Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/video/gpu_memory_buffer_video_frame_pool.h" | 5 #include "media/video/gpu_memory_buffer_video_frame_pool.h" |
| 6 | 6 |
| 7 #include <GLES2/gl2.h> | 7 #include <GLES2/gl2.h> |
| 8 #include <GLES2/gl2ext.h> | 8 #include <GLES2/gl2ext.h> |
| 9 | 9 |
| 10 #include <algorithm> | |
| 10 #include <list> | 11 #include <list> |
| 11 #include <utility> | 12 #include <utility> |
| 12 | 13 |
| 14 #include "base/barrier_closure.h" | |
| 13 #include "base/bind.h" | 15 #include "base/bind.h" |
| 14 #include "base/containers/stack_container.h" | 16 #include "base/containers/stack_container.h" |
| 15 #include "base/location.h" | 17 #include "base/location.h" |
| 16 #include "base/memory/linked_ptr.h" | 18 #include "base/memory/linked_ptr.h" |
| 17 #include "base/single_thread_task_runner.h" | |
| 18 #include "base/trace_event/trace_event.h" | 19 #include "base/trace_event/trace_event.h" |
| 19 #include "gpu/command_buffer/client/gles2_interface.h" | 20 #include "gpu/command_buffer/client/gles2_interface.h" |
| 20 #include "media/renderers/gpu_video_accelerator_factories.h" | 21 #include "media/renderers/gpu_video_accelerator_factories.h" |
| 21 | 22 |
| 22 namespace media { | 23 namespace media { |
| 23 | 24 |
| 24 // Implementation of a pool of GpuMemoryBuffers used to back VideoFrames. | 25 // Implementation of a pool of GpuMemoryBuffers used to back VideoFrames. |
| 25 class GpuMemoryBufferVideoFramePool::PoolImpl | 26 class GpuMemoryBufferVideoFramePool::PoolImpl |
| 26 : public base::RefCountedThreadSafe< | 27 : public base::RefCountedThreadSafe< |
| 27 GpuMemoryBufferVideoFramePool::PoolImpl> { | 28 GpuMemoryBufferVideoFramePool::PoolImpl> { |
| 28 public: | 29 public: |
| 29 // |task_runner| is associated to the thread where the context of | 30 // |media_task_runner| is the media task runner associated with the |
| 30 // GLES2Interface returned by |gpu_factories| lives. | 31 // GL context provided by |gpu_factories| |
| 32 // |worker_task_runner| is a task runner used to asynchronously copy | |
| 33 // video frame's planes. | |
| 31 // |gpu_factories| is an interface to GPU related operation and can be | 34 // |gpu_factories| is an interface to GPU related operation and can be |
| 32 // null. | 35 // null if a GL context is not available. |
| 33 PoolImpl(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 36 PoolImpl(const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, |
| 37 const scoped_refptr<base::TaskRunner>& worker_task_runner, | |
| 34 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories) | 38 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories) |
| 35 : task_runner_(task_runner), | 39 : media_task_runner_(media_task_runner), |
| 40 worker_task_runner_(worker_task_runner), | |
| 36 gpu_factories_(gpu_factories), | 41 gpu_factories_(gpu_factories), |
| 37 texture_target_(gpu_factories_ ? gpu_factories_->ImageTextureTarget() | 42 texture_target_(gpu_factories ? gpu_factories->ImageTextureTarget() |
| 38 : GL_TEXTURE_2D) {} | 43 : GL_TEXTURE_2D) { |
| 44 DCHECK(media_task_runner_); | |
| 45 DCHECK(worker_task_runner_); | |
| 46 } | |
| 39 | 47 |
| 40 // Takes a software VideoFrame and returns a VideoFrame backed by native | 48 // Takes a software VideoFrame and calls |cb| with a VideoFrame backed by |
| 41 // textures if possible. | 49 // native textures if possible. |
| 42 // The data contained in video_frame is copied into the returned frame. | 50 // The data contained in video_frame is copied into the returned frame |
| 43 scoped_refptr<VideoFrame> CreateHardwareFrame( | 51 // asynchronously posting tasks to |worker_task_runner_|, while |cb| will be |
| 44 const scoped_refptr<VideoFrame>& video_frame); | 52 // called on |media_task_runner_| once all the data has been copied. |
| 53 void CreateHardwareFrame(const scoped_refptr<VideoFrame>& video_frame, | |
| 54 const FrameReadyCB& cb); | |
| 45 | 55 |
| 46 private: | 56 private: |
| 47 friend class base::RefCountedThreadSafe< | 57 friend class base::RefCountedThreadSafe< |
| 48 GpuMemoryBufferVideoFramePool::PoolImpl>; | 58 GpuMemoryBufferVideoFramePool::PoolImpl>; |
| 49 ~PoolImpl(); | 59 ~PoolImpl(); |
| 50 | 60 |
| 51 // Resource to represent a plane. | 61 // Resource to represent a plane. |
| 52 struct PlaneResource { | 62 struct PlaneResource { |
| 53 gfx::Size size; | 63 gfx::Size size; |
| 54 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; | 64 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; |
| 55 unsigned texture_id = 0u; | 65 unsigned texture_id = 0u; |
| 56 unsigned image_id = 0u; | 66 unsigned image_id = 0u; |
| 57 gpu::Mailbox mailbox; | 67 gpu::Mailbox mailbox; |
| 58 }; | 68 }; |
| 59 | 69 |
| 60 // All the resources needed to compose a frame. | 70 // All the resources needed to compose a frame. |
| 61 struct FrameResources { | 71 struct FrameResources { |
| 62 FrameResources(VideoPixelFormat format, const gfx::Size& size) | 72 FrameResources(VideoPixelFormat format, const gfx::Size& size) |
| 63 : format(format), size(size) {} | 73 : format(format), size(size) {} |
| 64 bool in_use = true; | 74 bool in_use = true; |
| 65 VideoPixelFormat format; | 75 VideoPixelFormat format; |
| 66 gfx::Size size; | 76 gfx::Size size; |
| 67 PlaneResource plane_resources[VideoFrame::kMaxPlanes]; | 77 PlaneResource plane_resources[VideoFrame::kMaxPlanes]; |
| 68 }; | 78 }; |
| 69 | 79 |
| 80 // Copy |video_frame| data into |frame_resouces| | |
| 81 // and calls |done| when done. | |
| 82 void CopyVideoFrameToGpuMemoryBuffers( | |
| 83 const scoped_refptr<VideoFrame>& video_frame, | |
| 84 FrameResources* frame_resources, | |
| 85 const FrameReadyCB& cb); | |
|
DaleCurtis
2015/08/17 18:01:30
Please use something more descriptive than |cb|.
Daniele Castagna
2015/08/19 21:31:25
Done.
Change everywhere |cb| to |frame_ready_cb|
| |
| 86 | |
| 87 // Called when all the data has been copied. | |
| 88 void OnCopiesDone(const scoped_refptr<VideoFrame>& video_frame, | |
| 89 FrameResources* frame_resources, | |
| 90 const FrameReadyCB& cb); | |
| 91 | |
| 92 // Prepares GL resources, mailboxes and calls |cb| with the new VideoFrame. | |
| 93 // This has to be run on |media_task_runner_| where |cb| will also be run. | |
| 94 void BindAndCreateMailboxesHardwareFrameResources( | |
| 95 const scoped_refptr<VideoFrame>& video_frame, | |
| 96 FrameResources* frame_resources, | |
| 97 const FrameReadyCB& cb); | |
| 98 | |
| 70 // Return true if |resources| can be used to represent a frame for | 99 // Return true if |resources| can be used to represent a frame for |
| 71 // specific |format| and |size|. | 100 // specific |format| and |size|. |
| 72 static bool AreFrameResourcesCompatible(const FrameResources* resources, | 101 static bool AreFrameResourcesCompatible(const FrameResources* resources, |
| 73 const gfx::Size& size, | 102 const gfx::Size& size, |
| 74 VideoPixelFormat format) { | 103 VideoPixelFormat format) { |
| 75 return size == resources->size && format == resources->format; | 104 return size == resources->size && format == resources->format; |
| 76 } | 105 } |
| 77 | 106 |
| 78 // Get the resources needed for a frame out of the pool, or create them if | 107 // Get the resources needed for a frame out of the pool, or create them if |
| 79 // necessary. | 108 // necessary. |
| 80 // This also drops the LRU resources that can't be reuse for this frame. | 109 // This also drops the LRU resources that can't be reuse for this frame. |
| 81 FrameResources* GetOrCreateFrameResources(const gfx::Size& size, | 110 FrameResources* GetOrCreateFrameResources(const gfx::Size& size, |
| 82 VideoPixelFormat format); | 111 VideoPixelFormat format); |
| 83 | 112 |
| 84 // Callback called when a VideoFrame generated with GetFrameResources is no | 113 // Callback called when a VideoFrame generated with GetFrameResources is no |
| 85 // longer referenced. | 114 // longer referenced. |
| 86 // This could be called by any thread. | 115 // This could be called by any thread. |
| 87 void MailboxHoldersReleased(FrameResources* frame_resources, | 116 void MailboxHoldersReleased(FrameResources* frame_resources, |
| 88 uint32 sync_point); | 117 uint32 sync_point); |
| 89 | 118 |
| 90 // Return frame resources to the pool. This has to be called on the thread | 119 // Return frame resources to the pool. This has to be called on the thread |
| 91 // where |task_runner| is current. | 120 // where |media_task_runner_| is current. |
| 92 void ReturnFrameResources(FrameResources* frame_resources); | 121 void ReturnFrameResources(FrameResources* frame_resources); |
| 93 | 122 |
| 94 // Delete resources. This has to be called on the thread where |task_runner| | 123 // Delete resources. This has to be called on the thread where |task_runner| |
| 95 // is current. | 124 // is current. |
| 96 static void DeleteFrameResources( | 125 static void DeleteFrameResources( |
| 97 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories, | 126 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories, |
| 98 FrameResources* frame_resources); | 127 FrameResources* frame_resources); |
| 99 | 128 |
| 100 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 129 // Task runner associated to the GL context provided by |gpu_factories_|. |
| 130 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_; | |
| 131 // Task runner used to asynchronously copy planes. | |
| 132 scoped_refptr<base::TaskRunner> worker_task_runner_; | |
| 133 | |
| 134 // Interface to GPU related operations. | |
| 101 scoped_refptr<GpuVideoAcceleratorFactories> gpu_factories_; | 135 scoped_refptr<GpuVideoAcceleratorFactories> gpu_factories_; |
| 102 | 136 |
| 103 // Pool of resources. | 137 // Pool of resources. |
| 104 std::list<FrameResources*> resources_pool_; | 138 std::list<FrameResources*> resources_pool_; |
| 105 | 139 |
| 106 const unsigned texture_target_; | 140 const unsigned texture_target_; |
| 107 DISALLOW_COPY_AND_ASSIGN(PoolImpl); | 141 DISALLOW_COPY_AND_ASSIGN(PoolImpl); |
| 108 }; | 142 }; |
| 109 | 143 |
| 110 namespace { | 144 namespace { |
| 111 | 145 |
| 112 // Copy a buffer info a GpuMemoryBuffer. | 146 void CopyRowsToBuffer(int first_row, |
| 113 // |bytes_per_row| is expected to be less or equal than the strides of the two | 147 int rows, |
| 114 // buffers. | 148 int bytes_per_row, |
| 115 void CopyPlaneToGpuMemoryBuffer(int rows, | 149 const uint8* source, |
| 116 int bytes_per_row, | 150 int source_stride, |
| 117 const uint8* source, | 151 uint8* output, |
| 118 int source_stride, | 152 int dest_stride, |
| 119 gfx::GpuMemoryBuffer* buffer) { | 153 base::Closure done) { |
|
DaleCurtis
2015/08/17 18:01:30
const&
Daniele Castagna
2015/08/19 21:31:25
Done.
| |
| 120 TRACE_EVENT2("media", "CopyPlaneToGpuMemoryBuffer", "bytes_per_row", | 154 TRACE_EVENT2("media", "CopyRowsToBuffer", "bytes_per_row", bytes_per_row, |
| 121 bytes_per_row, "rows", rows); | 155 "rows", rows); |
| 122 | |
| 123 DCHECK(buffer); | |
| 124 DCHECK(source); | |
| 125 void* data = nullptr; | |
| 126 CHECK(buffer->Map(&data)); | |
| 127 uint8* mapped_buffer = static_cast<uint8*>(data); | |
| 128 int dest_stride = 0; | |
| 129 buffer->GetStride(&dest_stride); | |
| 130 DCHECK_NE(dest_stride, 0); | 156 DCHECK_NE(dest_stride, 0); |
| 131 DCHECK_LE(bytes_per_row, std::abs(dest_stride)); | 157 DCHECK_LE(bytes_per_row, std::abs(dest_stride)); |
| 132 DCHECK_LE(bytes_per_row, source_stride); | 158 DCHECK_LE(bytes_per_row, source_stride); |
| 133 for (int row = 0; row < rows; ++row) { | 159 for (int row = first_row; row < first_row + rows; ++row) { |
| 134 memcpy(mapped_buffer + dest_stride * row, source + source_stride * row, | 160 memcpy(output + dest_stride * row, source + source_stride * row, |
| 135 bytes_per_row); | 161 bytes_per_row); |
| 136 } | 162 } |
| 137 buffer->Unmap(); | 163 done.Run(); |
| 138 } | 164 } |
| 139 | 165 |
| 140 } // unnamed namespace | 166 } // unnamed namespace |
| 141 | 167 |
| 142 // Creates a VideoFrame backed by native textures starting from a software | 168 // Creates a VideoFrame backed by native textures starting from a software |
| 143 // VideoFrame. | 169 // VideoFrame. |
| 144 // The data contained in video_frame is copied into the returned VideoFrame. | 170 // The data contained in |video_frame| is copied into the VideoFrame passed to |
| 145 scoped_refptr<VideoFrame> | 171 // |cb|. |
| 146 GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame( | 172 // This has to be called on the thread where |media_task_runner_| is current. |
| 147 const scoped_refptr<VideoFrame>& video_frame) { | 173 void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame( |
| 148 if (!gpu_factories_) | 174 const scoped_refptr<VideoFrame>& video_frame, |
| 149 return video_frame; | 175 const FrameReadyCB& cb) { |
| 150 | 176 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 151 if (!gpu_factories_->IsTextureRGSupported()) | 177 if (!gpu_factories_ || !gpu_factories_->IsTextureRGSupported()) { |
| 152 return video_frame; | 178 cb.Run(video_frame); |
| 153 | 179 return; |
| 154 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); | 180 } |
| 155 if (!gles2) | 181 switch (video_frame->format()) { |
| 156 return video_frame; | 182 // Supported cases. |
| 183 case PIXEL_FORMAT_YV12: | |
| 184 case PIXEL_FORMAT_I420: | |
| 185 break; | |
| 186 // Unsupported cases. | |
| 187 case PIXEL_FORMAT_YV12A: | |
| 188 case PIXEL_FORMAT_YV16: | |
| 189 case PIXEL_FORMAT_YV24: | |
| 190 case PIXEL_FORMAT_NV12: | |
| 191 case PIXEL_FORMAT_ARGB: | |
| 192 case PIXEL_FORMAT_XRGB: | |
| 193 case PIXEL_FORMAT_UNKNOWN: | |
| 194 cb.Run(video_frame); | |
| 195 return; | |
| 196 } | |
| 157 | 197 |
| 158 VideoPixelFormat format = video_frame->format(); | 198 VideoPixelFormat format = video_frame->format(); |
| 159 size_t planes = VideoFrame::NumPlanes(format); | |
| 160 DCHECK(video_frame->visible_rect().origin().IsOrigin()); | 199 DCHECK(video_frame->visible_rect().origin().IsOrigin()); |
| 161 gfx::Size size = video_frame->visible_rect().size(); | 200 const gfx::Size size = video_frame->visible_rect().size(); |
| 162 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; | |
| 163 | 201 |
| 164 // Acquire resources. Incompatible ones will be dropped from the pool. | 202 // Acquire resources. Incompatible ones will be dropped from the pool. |
| 165 FrameResources* frame_resources = GetOrCreateFrameResources(size, format); | 203 FrameResources* frame_resources = GetOrCreateFrameResources(size, format); |
|
DaleCurtis
2015/08/17 18:01:30
How expensive is the create portion here? I.e. is
Daniele Castagna
2015/08/19 21:31:25
It should not be particularly expensive but it def
| |
| 204 if (!frame_resources) { | |
| 205 cb.Run(video_frame); | |
| 206 return; | |
| 207 } | |
| 166 | 208 |
| 167 // Set up the planes copying data into it and creating the mailboxes needed | 209 worker_task_runner_->PostTask( |
|
DaleCurtis
2015/08/17 18:01:30
WDYT about doing an inline copy (i.e. w/o post tas
Daniele Castagna
2015/08/19 21:31:25
Sounds like a good idea.
Is it OK if we do this af
| |
| 168 // to refer to the textures. | 210 FROM_HERE, base::Bind(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers, this, |
| 211 video_frame, frame_resources, cb)); | |
| 212 } | |
| 213 | |
| 214 void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone( | |
| 215 const scoped_refptr<VideoFrame>& video_frame, | |
| 216 FrameResources* frame_resources, | |
| 217 const FrameReadyCB& cb) { | |
| 218 const VideoPixelFormat format = video_frame->format(); | |
| 219 const size_t planes = VideoFrame::NumPlanes(format); | |
| 220 for (size_t i = 0; i < planes; ++i) { | |
| 221 frame_resources->plane_resources[i].gpu_memory_buffer->Unmap(); | |
| 222 } | |
| 223 | |
| 224 media_task_runner_->PostTask( | |
| 225 FROM_HERE, | |
| 226 base::Bind(&PoolImpl::BindAndCreateMailboxesHardwareFrameResources, this, | |
| 227 video_frame, frame_resources, cb)); | |
| 228 } | |
| 229 | |
| 230 // Copies |video_frame| into |frame_resources| asynchronously, posting n tasks | |
| 231 // that will be synchronized by a barrier. | |
| 232 // After the barrier is passed OnCopiesDone will be called. | |
| 233 void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( | |
| 234 const scoped_refptr<VideoFrame>& video_frame, | |
| 235 FrameResources* frame_resources, | |
| 236 const FrameReadyCB& cb) { | |
| 237 const size_t kBytesPerCopyTarget = 1 << 20; | |
|
reveman
2015/08/17 16:38:29
Can you add a comment that makes it clear exactly
Daniele Castagna
2015/08/19 21:31:25
Done.
| |
| 238 const VideoPixelFormat format = video_frame->format(); | |
| 239 const size_t planes = VideoFrame::NumPlanes(format); | |
| 240 gfx::Size size = video_frame->visible_rect().size(); | |
| 241 size_t copies = 0; | |
| 242 for (size_t i = 0; i < planes; ++i) { | |
| 243 int rows = VideoFrame::Rows(i, format, size.height()); | |
| 244 int bytes = VideoFrame::RowBytes(i, format, size.width()); | |
|
reveman
2015/08/17 16:38:29
nit: s/bytes/bytes_per_row/ or row_bytes
Daniele Castagna
2015/08/19 21:31:25
Done.
| |
| 245 int rows_per_copy = std::max<size_t>(kBytesPerCopyTarget / bytes, 1); | |
| 246 copies += rows / rows_per_copy; | |
| 247 if (rows % rows_per_copy) | |
| 248 ++copies; | |
| 249 } | |
| 250 | |
| 251 base::Closure copies_done = base::Bind(&PoolImpl::OnCopiesDone, this, | |
| 252 video_frame, frame_resources, cb); | |
| 253 base::Closure barrier = base::BarrierClosure(copies, copies_done); | |
| 254 | |
| 255 for (size_t i = 0; i < planes; ++i) { | |
| 256 int rows = VideoFrame::Rows(i, format, size.height()); | |
| 257 int bytes = VideoFrame::RowBytes(i, format, size.width()); | |
|
reveman
2015/08/17 16:38:29
nit: s/bytes/bytes_per_row/
Daniele Castagna
2015/08/19 21:31:25
Done.
| |
| 258 int rows_per_copy = std::max<size_t>(kBytesPerCopyTarget / bytes, 1); | |
| 259 | |
| 260 PlaneResource& plane_resource = frame_resources->plane_resources[i]; | |
| 261 void* data = nullptr; | |
| 262 CHECK(plane_resource.gpu_memory_buffer->Map(&data)); | |
| 263 uint8* mapped_buffer = static_cast<uint8*>(data); | |
| 264 int dest_stride = 0; | |
| 265 plane_resource.gpu_memory_buffer->GetStride(&dest_stride); | |
| 266 | |
| 267 for (int row = 0; row < rows; row += rows_per_copy) { | |
| 268 worker_task_runner_->PostTask( | |
|
DaleCurtis
2015/08/17 18:01:30
Hmm, did you change the worker task runner to run
Daniele Castagna
2015/08/19 21:31:25
Correct, the worker task runner execute tasks in p
| |
| 269 FROM_HERE, base::Bind(&CopyRowsToBuffer, row, | |
| 270 std::min(rows_per_copy, rows - row), bytes, | |
| 271 video_frame->data(i), video_frame->stride(i), | |
| 272 mapped_buffer, dest_stride, barrier)); | |
| 273 } | |
| 274 } | |
| 275 } | |
| 276 | |
| 277 void GpuMemoryBufferVideoFramePool::PoolImpl:: | |
| 278 BindAndCreateMailboxesHardwareFrameResources( | |
| 279 const scoped_refptr<VideoFrame>& video_frame, | |
| 280 FrameResources* frame_resources, | |
| 281 const FrameReadyCB& cb) { | |
| 282 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); | |
| 283 if (!gles2) { | |
| 284 cb.Run(video_frame); | |
| 285 return; | |
| 286 } | |
| 287 | |
| 288 const VideoPixelFormat format = video_frame->format(); | |
| 289 const size_t planes = VideoFrame::NumPlanes(format); | |
| 290 const gfx::Size size = video_frame->visible_rect().size(); | |
| 291 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; | |
| 292 // Set up the planes creating the mailboxes needed to refer to the textures. | |
| 169 for (size_t i = 0; i < planes; ++i) { | 293 for (size_t i = 0; i < planes; ++i) { |
| 170 PlaneResource& plane_resource = frame_resources->plane_resources[i]; | 294 PlaneResource& plane_resource = frame_resources->plane_resources[i]; |
| 171 CopyPlaneToGpuMemoryBuffer(VideoFrame::Rows(i, format, size.height()), | |
| 172 VideoFrame::RowBytes(i, format, size.width()), | |
| 173 video_frame->data(i), video_frame->stride(i), | |
| 174 plane_resource.gpu_memory_buffer.get()); | |
| 175 | |
| 176 // Bind the texture and create or rebind the image. | 295 // Bind the texture and create or rebind the image. |
| 177 gles2->BindTexture(texture_target_, plane_resource.texture_id); | 296 gles2->BindTexture(texture_target_, plane_resource.texture_id); |
| 178 | 297 |
| 179 if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) { | 298 if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) { |
| 180 const size_t width = VideoFrame::Columns(i, format, size.width()); | 299 const size_t width = VideoFrame::Columns(i, format, size.width()); |
| 181 const size_t height = VideoFrame::Rows(i, format, size.height()); | 300 const size_t height = VideoFrame::Rows(i, format, size.height()); |
| 182 plane_resource.image_id = gles2->CreateImageCHROMIUM( | 301 plane_resource.image_id = gles2->CreateImageCHROMIUM( |
| 183 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height, | 302 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height, |
| 184 GL_R8_EXT); | 303 GL_R8_EXT); |
| 185 } else { | 304 } else { |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 202 // Create the VideoFrame backed by native textures. | 321 // Create the VideoFrame backed by native textures. |
| 203 scoped_refptr<VideoFrame> frame = VideoFrame::WrapYUV420NativeTextures( | 322 scoped_refptr<VideoFrame> frame = VideoFrame::WrapYUV420NativeTextures( |
| 204 mailbox_holders[VideoFrame::kYPlane], | 323 mailbox_holders[VideoFrame::kYPlane], |
| 205 mailbox_holders[VideoFrame::kUPlane], | 324 mailbox_holders[VideoFrame::kUPlane], |
| 206 mailbox_holders[VideoFrame::kVPlane], | 325 mailbox_holders[VideoFrame::kVPlane], |
| 207 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources), | 326 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources), |
| 208 size, video_frame->visible_rect(), video_frame->natural_size(), | 327 size, video_frame->visible_rect(), video_frame->natural_size(), |
| 209 video_frame->timestamp()); | 328 video_frame->timestamp()); |
| 210 if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY)) | 329 if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY)) |
| 211 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); | 330 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); |
| 212 return frame; | 331 cb.Run(frame); |
| 213 } | 332 } |
| 214 | 333 |
| 215 // Destroy all the resources posting one task per FrameResources | 334 // Destroy all the resources posting one task per FrameResources |
| 216 // to the |task_runner_|. | 335 // to the |media_task_runner_|. |
| 217 GpuMemoryBufferVideoFramePool::PoolImpl::~PoolImpl() { | 336 GpuMemoryBufferVideoFramePool::PoolImpl::~PoolImpl() { |
| 218 // Delete all the resources on the media thread. | 337 // Delete all the resources on the media thread. |
| 219 while (!resources_pool_.empty()) { | 338 while (!resources_pool_.empty()) { |
| 220 FrameResources* frame_resources = resources_pool_.front(); | 339 FrameResources* frame_resources = resources_pool_.front(); |
| 221 resources_pool_.pop_front(); | 340 resources_pool_.pop_front(); |
| 222 task_runner_->PostTask( | 341 media_task_runner_->PostTask( |
| 223 FROM_HERE, base::Bind(&PoolImpl::DeleteFrameResources, gpu_factories_, | 342 FROM_HERE, base::Bind(&PoolImpl::DeleteFrameResources, gpu_factories_, |
| 224 base::Owned(frame_resources))); | 343 base::Owned(frame_resources))); |
| 225 } | 344 } |
| 226 } | 345 } |
| 227 | 346 |
| 228 // Tries to find the resources in the pool or create them. | 347 // Tries to find the resources in the pool or create them. |
| 229 // Incompatible resources will be dropped. | 348 // Incompatible resources will be dropped. |
| 230 GpuMemoryBufferVideoFramePool::PoolImpl::FrameResources* | 349 GpuMemoryBufferVideoFramePool::PoolImpl::FrameResources* |
| 231 GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources( | 350 GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources( |
| 232 const gfx::Size& size, | 351 const gfx::Size& size, |
| 233 VideoPixelFormat format) { | 352 VideoPixelFormat format) { |
| 234 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 235 | |
| 236 auto it = resources_pool_.begin(); | 353 auto it = resources_pool_.begin(); |
| 237 while (it != resources_pool_.end()) { | 354 while (it != resources_pool_.end()) { |
| 238 FrameResources* frame_resources = *it; | 355 FrameResources* frame_resources = *it; |
| 239 if (!frame_resources->in_use) { | 356 if (!frame_resources->in_use) { |
| 240 if (AreFrameResourcesCompatible(frame_resources, size, format)) { | 357 if (AreFrameResourcesCompatible(frame_resources, size, format)) { |
| 241 frame_resources->in_use = true; | 358 frame_resources->in_use = true; |
| 242 return frame_resources; | 359 return frame_resources; |
| 243 } else { | 360 } else { |
| 244 resources_pool_.erase(it++); | 361 resources_pool_.erase(it++); |
| 245 DeleteFrameResources(gpu_factories_, frame_resources); | 362 DeleteFrameResources(gpu_factories_, frame_resources); |
| 246 delete frame_resources; | 363 delete frame_resources; |
| 247 } | 364 } |
| 248 } else { | 365 } else { |
| 249 it++; | 366 it++; |
| 250 } | 367 } |
| 251 } | 368 } |
| 252 | 369 |
| 253 // Create the resources. | 370 // Create the resources. |
| 254 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); | 371 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); |
| 255 DCHECK(gles2); | 372 if (!gles2) |
| 373 return nullptr; | |
| 256 gles2->ActiveTexture(GL_TEXTURE0); | 374 gles2->ActiveTexture(GL_TEXTURE0); |
| 257 size_t planes = VideoFrame::NumPlanes(format); | 375 size_t planes = VideoFrame::NumPlanes(format); |
| 258 FrameResources* frame_resources = new FrameResources(format, size); | 376 FrameResources* frame_resources = new FrameResources(format, size); |
| 259 resources_pool_.push_back(frame_resources); | 377 resources_pool_.push_back(frame_resources); |
| 260 for (size_t i = 0; i < planes; ++i) { | 378 for (size_t i = 0; i < planes; ++i) { |
| 261 PlaneResource& plane_resource = frame_resources->plane_resources[i]; | 379 PlaneResource& plane_resource = frame_resources->plane_resources[i]; |
| 262 const size_t width = VideoFrame::Columns(i, format, size.width()); | 380 const size_t width = VideoFrame::Columns(i, format, size.width()); |
| 263 const size_t height = VideoFrame::Rows(i, format, size.height()); | 381 const size_t height = VideoFrame::Rows(i, format, size.height()); |
| 264 const gfx::Size plane_size(width, height); | 382 const gfx::Size plane_size(width, height); |
| 265 plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer( | 383 plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer( |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 294 if (plane_resource.texture_id) | 412 if (plane_resource.texture_id) |
| 295 gles2->DeleteTextures(1, &plane_resource.texture_id); | 413 gles2->DeleteTextures(1, &plane_resource.texture_id); |
| 296 } | 414 } |
| 297 } | 415 } |
| 298 | 416 |
| 299 // Called when a VideoFrame is no longer references. | 417 // Called when a VideoFrame is no longer references. |
| 300 void GpuMemoryBufferVideoFramePool::PoolImpl::MailboxHoldersReleased( | 418 void GpuMemoryBufferVideoFramePool::PoolImpl::MailboxHoldersReleased( |
| 301 FrameResources* frame_resources, | 419 FrameResources* frame_resources, |
| 302 uint32 sync_point) { | 420 uint32 sync_point) { |
| 303 // Return the resource on the media thread. | 421 // Return the resource on the media thread. |
| 304 task_runner_->PostTask(FROM_HERE, base::Bind(&PoolImpl::ReturnFrameResources, | 422 media_task_runner_->PostTask( |
| 305 this, frame_resources)); | 423 FROM_HERE, |
| 424 base::Bind(&PoolImpl::ReturnFrameResources, this, frame_resources)); | |
| 306 } | 425 } |
| 307 | 426 |
| 308 // Put back the resoruces in the pool. | 427 // Put back the resoruces in the pool. |
| 309 void GpuMemoryBufferVideoFramePool::PoolImpl::ReturnFrameResources( | 428 void GpuMemoryBufferVideoFramePool::PoolImpl::ReturnFrameResources( |
| 310 FrameResources* frame_resources) { | 429 FrameResources* frame_resources) { |
| 311 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 312 | 430 |
| 313 auto it = std::find(resources_pool_.begin(), resources_pool_.end(), | 431 auto it = std::find(resources_pool_.begin(), resources_pool_.end(), |
| 314 frame_resources); | 432 frame_resources); |
| 315 DCHECK(it != resources_pool_.end()); | 433 DCHECK(it != resources_pool_.end()); |
| 316 // We want the pool to behave in a FIFO way. | 434 // We want the pool to behave in a FIFO way. |
| 317 // This minimizes the chances of locking the buffer that might be | 435 // This minimizes the chances of locking the buffer that might be |
| 318 // still needed for drawing. | 436 // still needed for drawing. |
| 319 std::swap(*it, resources_pool_.back()); | 437 std::swap(*it, resources_pool_.back()); |
| 320 frame_resources->in_use = false; | 438 frame_resources->in_use = false; |
| 321 } | 439 } |
| 322 | 440 |
| 323 GpuMemoryBufferVideoFramePool::GpuMemoryBufferVideoFramePool( | 441 GpuMemoryBufferVideoFramePool::GpuMemoryBufferVideoFramePool( |
| 324 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 442 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, |
| 443 const scoped_refptr<base::TaskRunner>& worker_task_runner, | |
| 325 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories) | 444 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories) |
| 326 : pool_impl_(new PoolImpl(task_runner, gpu_factories)) { | 445 : pool_impl_( |
| 327 } | 446 new PoolImpl(media_task_runner, worker_task_runner, gpu_factories)) {} |
| 328 | 447 |
| 329 GpuMemoryBufferVideoFramePool::~GpuMemoryBufferVideoFramePool() { | 448 GpuMemoryBufferVideoFramePool::~GpuMemoryBufferVideoFramePool() { |
| 330 } | 449 } |
| 331 | 450 |
| 332 scoped_refptr<VideoFrame> | 451 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame( |
| 333 GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame( | 452 const scoped_refptr<VideoFrame>& video_frame, |
| 334 const scoped_refptr<VideoFrame>& video_frame) { | 453 const FrameReadyCB& cb) { |
| 335 switch (video_frame->format()) { | 454 DCHECK(video_frame); |
| 336 // Supported cases. | 455 pool_impl_->CreateHardwareFrame(video_frame, cb); |
| 337 case PIXEL_FORMAT_YV12: | |
| 338 case PIXEL_FORMAT_I420: | |
| 339 return pool_impl_->CreateHardwareFrame(video_frame); | |
| 340 // Unsupported cases. | |
| 341 case PIXEL_FORMAT_YV12A: | |
| 342 case PIXEL_FORMAT_YV16: | |
| 343 case PIXEL_FORMAT_YV24: | |
| 344 case PIXEL_FORMAT_NV12: | |
| 345 case PIXEL_FORMAT_ARGB: | |
| 346 case PIXEL_FORMAT_XRGB: | |
| 347 case PIXEL_FORMAT_UNKNOWN: | |
| 348 break; | |
| 349 } | |
| 350 return video_frame; | |
| 351 } | 456 } |
| 352 | 457 |
| 353 } // namespace media | 458 } // namespace media |
| OLD | NEW |