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 |frame_ready_cb| with a VideoFrame |
41 // textures if possible. | 49 // backed by 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 |
44 const scoped_refptr<VideoFrame>& video_frame); | 52 // |frame_ready_cb| will be called on |media_task_runner_| once all the data |
| 53 // has been copied. |
| 54 void CreateHardwareFrame(const scoped_refptr<VideoFrame>& video_frame, |
| 55 const FrameReadyCB& cb); |
45 | 56 |
46 private: | 57 private: |
47 friend class base::RefCountedThreadSafe< | 58 friend class base::RefCountedThreadSafe< |
48 GpuMemoryBufferVideoFramePool::PoolImpl>; | 59 GpuMemoryBufferVideoFramePool::PoolImpl>; |
49 ~PoolImpl(); | 60 ~PoolImpl(); |
50 | 61 |
51 // Resource to represent a plane. | 62 // Resource to represent a plane. |
52 struct PlaneResource { | 63 struct PlaneResource { |
53 gfx::Size size; | 64 gfx::Size size; |
54 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; | 65 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; |
55 unsigned texture_id = 0u; | 66 unsigned texture_id = 0u; |
56 unsigned image_id = 0u; | 67 unsigned image_id = 0u; |
57 gpu::Mailbox mailbox; | 68 gpu::Mailbox mailbox; |
58 }; | 69 }; |
59 | 70 |
60 // All the resources needed to compose a frame. | 71 // All the resources needed to compose a frame. |
61 struct FrameResources { | 72 struct FrameResources { |
62 FrameResources(VideoPixelFormat format, const gfx::Size& size) | 73 FrameResources(VideoPixelFormat format, const gfx::Size& size) |
63 : format(format), size(size) {} | 74 : format(format), size(size) {} |
64 bool in_use = true; | 75 bool in_use = true; |
65 VideoPixelFormat format; | 76 VideoPixelFormat format; |
66 gfx::Size size; | 77 gfx::Size size; |
67 PlaneResource plane_resources[VideoFrame::kMaxPlanes]; | 78 PlaneResource plane_resources[VideoFrame::kMaxPlanes]; |
68 }; | 79 }; |
69 | 80 |
| 81 // Copy |video_frame| data into |frame_resouces| |
| 82 // and calls |done| when done. |
| 83 void CopyVideoFrameToGpuMemoryBuffers( |
| 84 const scoped_refptr<VideoFrame>& video_frame, |
| 85 FrameResources* frame_resources, |
| 86 const FrameReadyCB& frame_ready_cb); |
| 87 |
| 88 // Called when all the data has been copied. |
| 89 void OnCopiesDone(const scoped_refptr<VideoFrame>& video_frame, |
| 90 FrameResources* frame_resources, |
| 91 const FrameReadyCB& frame_ready_cb); |
| 92 |
| 93 // Prepares GL resources, mailboxes and calls |frame_ready_cb| with the new |
| 94 // VideoFrame. |
| 95 // This has to be run on |media_task_runner_| where |frame_ready_cb| will also |
| 96 // be run. |
| 97 void BindAndCreateMailboxesHardwareFrameResources( |
| 98 const scoped_refptr<VideoFrame>& video_frame, |
| 99 FrameResources* frame_resources, |
| 100 const FrameReadyCB& frame_ready_cb); |
| 101 |
70 // Return true if |resources| can be used to represent a frame for | 102 // Return true if |resources| can be used to represent a frame for |
71 // specific |format| and |size|. | 103 // specific |format| and |size|. |
72 static bool AreFrameResourcesCompatible(const FrameResources* resources, | 104 static bool AreFrameResourcesCompatible(const FrameResources* resources, |
73 const gfx::Size& size, | 105 const gfx::Size& size, |
74 VideoPixelFormat format) { | 106 VideoPixelFormat format) { |
75 return size == resources->size && format == resources->format; | 107 return size == resources->size && format == resources->format; |
76 } | 108 } |
77 | 109 |
78 // Get the resources needed for a frame out of the pool, or create them if | 110 // Get the resources needed for a frame out of the pool, or create them if |
79 // necessary. | 111 // necessary. |
80 // This also drops the LRU resources that can't be reuse for this frame. | 112 // This also drops the LRU resources that can't be reuse for this frame. |
81 FrameResources* GetOrCreateFrameResources(const gfx::Size& size, | 113 FrameResources* GetOrCreateFrameResources(const gfx::Size& size, |
82 VideoPixelFormat format); | 114 VideoPixelFormat format); |
83 | 115 |
84 // Callback called when a VideoFrame generated with GetFrameResources is no | 116 // Callback called when a VideoFrame generated with GetFrameResources is no |
85 // longer referenced. | 117 // longer referenced. |
86 // This could be called by any thread. | 118 // This could be called by any thread. |
87 void MailboxHoldersReleased(FrameResources* frame_resources, | 119 void MailboxHoldersReleased(FrameResources* frame_resources, |
88 uint32 sync_point); | 120 uint32 sync_point); |
89 | 121 |
90 // Return frame resources to the pool. This has to be called on the thread | 122 // Return frame resources to the pool. This has to be called on the thread |
91 // where |task_runner| is current. | 123 // where |media_task_runner_| is current. |
92 void ReturnFrameResources(FrameResources* frame_resources); | 124 void ReturnFrameResources(FrameResources* frame_resources); |
93 | 125 |
94 // Delete resources. This has to be called on the thread where |task_runner| | 126 // Delete resources. This has to be called on the thread where |task_runner| |
95 // is current. | 127 // is current. |
96 static void DeleteFrameResources( | 128 static void DeleteFrameResources( |
97 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories, | 129 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories, |
98 FrameResources* frame_resources); | 130 FrameResources* frame_resources); |
99 | 131 |
100 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 132 // Task runner associated to the GL context provided by |gpu_factories_|. |
| 133 scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_; |
| 134 // Task runner used to asynchronously copy planes. |
| 135 scoped_refptr<base::TaskRunner> worker_task_runner_; |
| 136 |
| 137 // Interface to GPU related operations. |
101 scoped_refptr<GpuVideoAcceleratorFactories> gpu_factories_; | 138 scoped_refptr<GpuVideoAcceleratorFactories> gpu_factories_; |
102 | 139 |
103 // Pool of resources. | 140 // Pool of resources. |
104 std::list<FrameResources*> resources_pool_; | 141 std::list<FrameResources*> resources_pool_; |
105 | 142 |
106 const unsigned texture_target_; | 143 const unsigned texture_target_; |
107 DISALLOW_COPY_AND_ASSIGN(PoolImpl); | 144 DISALLOW_COPY_AND_ASSIGN(PoolImpl); |
108 }; | 145 }; |
109 | 146 |
110 namespace { | 147 namespace { |
111 | 148 |
112 // Copy a buffer info a GpuMemoryBuffer. | 149 // VideoFrame copies to GpuMemoryBuffers will be split in |kBytesPerCopyTarget| |
113 // |bytes_per_row| is expected to be less or equal than the strides of the two | 150 // bytes copies and run in parallel. |
114 // buffers. | 151 const size_t kBytesPerCopyTarget = 1024 * 1024; // 1MB |
115 void CopyPlaneToGpuMemoryBuffer(int rows, | |
116 int bytes_per_row, | |
117 const uint8* source, | |
118 int source_stride, | |
119 gfx::GpuMemoryBuffer* buffer) { | |
120 TRACE_EVENT2("media", "CopyPlaneToGpuMemoryBuffer", "bytes_per_row", | |
121 bytes_per_row, "rows", rows); | |
122 | 152 |
123 DCHECK(buffer); | 153 void CopyRowsToBuffer(int first_row, |
124 DCHECK(source); | 154 int rows, |
125 void* data = nullptr; | 155 int bytes_per_row, |
126 CHECK(buffer->Map(&data)); | 156 const uint8* source, |
127 uint8* mapped_buffer = static_cast<uint8*>(data); | 157 int source_stride, |
128 int dest_stride = 0; | 158 uint8* output, |
129 buffer->GetStride(&dest_stride); | 159 int dest_stride, |
| 160 const base::Closure& done) { |
| 161 TRACE_EVENT2("media", "CopyRowsToBuffer", "bytes_per_row", bytes_per_row, |
| 162 "rows", rows); |
130 DCHECK_NE(dest_stride, 0); | 163 DCHECK_NE(dest_stride, 0); |
131 DCHECK_LE(bytes_per_row, std::abs(dest_stride)); | 164 DCHECK_LE(bytes_per_row, std::abs(dest_stride)); |
132 DCHECK_LE(bytes_per_row, source_stride); | 165 DCHECK_LE(bytes_per_row, source_stride); |
133 for (int row = 0; row < rows; ++row) { | 166 for (int row = first_row; row < first_row + rows; ++row) { |
134 memcpy(mapped_buffer + dest_stride * row, source + source_stride * row, | 167 memcpy(output + dest_stride * row, source + source_stride * row, |
135 bytes_per_row); | 168 bytes_per_row); |
136 } | 169 } |
137 buffer->Unmap(); | 170 done.Run(); |
138 } | 171 } |
139 | 172 |
140 } // unnamed namespace | 173 } // unnamed namespace |
141 | 174 |
142 // Creates a VideoFrame backed by native textures starting from a software | 175 // Creates a VideoFrame backed by native textures starting from a software |
143 // VideoFrame. | 176 // VideoFrame. |
144 // The data contained in video_frame is copied into the returned VideoFrame. | 177 // The data contained in |video_frame| is copied into the VideoFrame passed to |
145 scoped_refptr<VideoFrame> | 178 // |frame_ready_cb|. |
146 GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame( | 179 // This has to be called on the thread where |media_task_runner_| is current. |
147 const scoped_refptr<VideoFrame>& video_frame) { | 180 void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame( |
148 if (!gpu_factories_) | 181 const scoped_refptr<VideoFrame>& video_frame, |
149 return video_frame; | 182 const FrameReadyCB& frame_ready_cb) { |
150 | 183 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
151 if (!gpu_factories_->IsTextureRGSupported()) | 184 if (!gpu_factories_ || !gpu_factories_->IsTextureRGSupported()) { |
152 return video_frame; | 185 frame_ready_cb.Run(video_frame); |
153 | 186 return; |
154 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); | 187 } |
155 if (!gles2) | 188 switch (video_frame->format()) { |
156 return video_frame; | 189 // Supported cases. |
| 190 case PIXEL_FORMAT_YV12: |
| 191 case PIXEL_FORMAT_I420: |
| 192 break; |
| 193 // Unsupported cases. |
| 194 case PIXEL_FORMAT_YV12A: |
| 195 case PIXEL_FORMAT_YV16: |
| 196 case PIXEL_FORMAT_YV24: |
| 197 case PIXEL_FORMAT_NV12: |
| 198 case PIXEL_FORMAT_ARGB: |
| 199 case PIXEL_FORMAT_XRGB: |
| 200 case PIXEL_FORMAT_UNKNOWN: |
| 201 frame_ready_cb.Run(video_frame); |
| 202 return; |
| 203 } |
157 | 204 |
158 VideoPixelFormat format = video_frame->format(); | 205 VideoPixelFormat format = video_frame->format(); |
159 size_t planes = VideoFrame::NumPlanes(format); | |
160 DCHECK(video_frame->visible_rect().origin().IsOrigin()); | 206 DCHECK(video_frame->visible_rect().origin().IsOrigin()); |
161 gfx::Size size = video_frame->visible_rect().size(); | 207 const gfx::Size size = video_frame->visible_rect().size(); |
162 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; | |
163 | 208 |
164 // Acquire resources. Incompatible ones will be dropped from the pool. | 209 // Acquire resources. Incompatible ones will be dropped from the pool. |
165 FrameResources* frame_resources = GetOrCreateFrameResources(size, format); | 210 FrameResources* frame_resources = GetOrCreateFrameResources(size, format); |
| 211 if (!frame_resources) { |
| 212 frame_ready_cb.Run(video_frame); |
| 213 return; |
| 214 } |
166 | 215 |
167 // Set up the planes copying data into it and creating the mailboxes needed | 216 worker_task_runner_->PostTask( |
168 // to refer to the textures. | 217 FROM_HERE, base::Bind(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers, this, |
| 218 video_frame, frame_resources, frame_ready_cb)); |
| 219 } |
| 220 |
| 221 void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone( |
| 222 const scoped_refptr<VideoFrame>& video_frame, |
| 223 FrameResources* frame_resources, |
| 224 const FrameReadyCB& frame_ready_cb) { |
| 225 const VideoPixelFormat format = video_frame->format(); |
| 226 const size_t planes = VideoFrame::NumPlanes(format); |
| 227 for (size_t i = 0; i < planes; ++i) { |
| 228 frame_resources->plane_resources[i].gpu_memory_buffer->Unmap(); |
| 229 } |
| 230 |
| 231 media_task_runner_->PostTask( |
| 232 FROM_HERE, |
| 233 base::Bind(&PoolImpl::BindAndCreateMailboxesHardwareFrameResources, this, |
| 234 video_frame, frame_resources, frame_ready_cb)); |
| 235 } |
| 236 |
| 237 // Copies |video_frame| into |frame_resources| asynchronously, posting n tasks |
| 238 // that will be synchronized by a barrier. |
| 239 // After the barrier is passed OnCopiesDone will be called. |
| 240 void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( |
| 241 const scoped_refptr<VideoFrame>& video_frame, |
| 242 FrameResources* frame_resources, |
| 243 const FrameReadyCB& frame_ready_cb) { |
| 244 const VideoPixelFormat format = video_frame->format(); |
| 245 const size_t planes = VideoFrame::NumPlanes(format); |
| 246 gfx::Size size = video_frame->visible_rect().size(); |
| 247 size_t copies = 0; |
| 248 for (size_t i = 0; i < planes; ++i) { |
| 249 int rows = VideoFrame::Rows(i, format, size.height()); |
| 250 int bytes_per_row = VideoFrame::RowBytes(i, format, size.width()); |
| 251 int rows_per_copy = |
| 252 std::max<size_t>(kBytesPerCopyTarget / bytes_per_row, 1); |
| 253 copies += rows / rows_per_copy; |
| 254 if (rows % rows_per_copy) |
| 255 ++copies; |
| 256 } |
| 257 |
| 258 base::Closure copies_done = |
| 259 base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources, |
| 260 frame_ready_cb); |
| 261 base::Closure barrier = base::BarrierClosure(copies, copies_done); |
| 262 |
| 263 for (size_t i = 0; i < planes; ++i) { |
| 264 int rows = VideoFrame::Rows(i, format, size.height()); |
| 265 int bytes_per_row = VideoFrame::RowBytes(i, format, size.width()); |
| 266 int rows_per_copy = |
| 267 std::max<size_t>(kBytesPerCopyTarget / bytes_per_row, 1); |
| 268 |
| 269 PlaneResource& plane_resource = frame_resources->plane_resources[i]; |
| 270 void* data = nullptr; |
| 271 CHECK(plane_resource.gpu_memory_buffer->Map(&data)); |
| 272 uint8* mapped_buffer = static_cast<uint8*>(data); |
| 273 int dest_stride = 0; |
| 274 plane_resource.gpu_memory_buffer->GetStride(&dest_stride); |
| 275 |
| 276 for (int row = 0; row < rows; row += rows_per_copy) { |
| 277 worker_task_runner_->PostTask( |
| 278 FROM_HERE, |
| 279 base::Bind(&CopyRowsToBuffer, row, |
| 280 std::min(rows_per_copy, rows - row), bytes_per_row, |
| 281 video_frame->data(i), video_frame->stride(i), |
| 282 mapped_buffer, dest_stride, barrier)); |
| 283 } |
| 284 } |
| 285 } |
| 286 |
| 287 void GpuMemoryBufferVideoFramePool::PoolImpl:: |
| 288 BindAndCreateMailboxesHardwareFrameResources( |
| 289 const scoped_refptr<VideoFrame>& video_frame, |
| 290 FrameResources* frame_resources, |
| 291 const FrameReadyCB& frame_ready_cb) { |
| 292 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); |
| 293 if (!gles2) { |
| 294 frame_ready_cb.Run(video_frame); |
| 295 return; |
| 296 } |
| 297 |
| 298 const VideoPixelFormat format = video_frame->format(); |
| 299 const size_t planes = VideoFrame::NumPlanes(format); |
| 300 const gfx::Size size = video_frame->visible_rect().size(); |
| 301 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; |
| 302 // Set up the planes creating the mailboxes needed to refer to the textures. |
169 for (size_t i = 0; i < planes; ++i) { | 303 for (size_t i = 0; i < planes; ++i) { |
170 PlaneResource& plane_resource = frame_resources->plane_resources[i]; | 304 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. | 305 // Bind the texture and create or rebind the image. |
177 gles2->BindTexture(texture_target_, plane_resource.texture_id); | 306 gles2->BindTexture(texture_target_, plane_resource.texture_id); |
178 | 307 |
179 if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) { | 308 if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) { |
180 const size_t width = VideoFrame::Columns(i, format, size.width()); | 309 const size_t width = VideoFrame::Columns(i, format, size.width()); |
181 const size_t height = VideoFrame::Rows(i, format, size.height()); | 310 const size_t height = VideoFrame::Rows(i, format, size.height()); |
182 plane_resource.image_id = gles2->CreateImageCHROMIUM( | 311 plane_resource.image_id = gles2->CreateImageCHROMIUM( |
183 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height, | 312 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height, |
184 GL_R8_EXT); | 313 GL_R8_EXT); |
185 } else { | 314 } else { |
(...skipping 16 matching lines...) Expand all Loading... |
202 // Create the VideoFrame backed by native textures. | 331 // Create the VideoFrame backed by native textures. |
203 scoped_refptr<VideoFrame> frame = VideoFrame::WrapYUV420NativeTextures( | 332 scoped_refptr<VideoFrame> frame = VideoFrame::WrapYUV420NativeTextures( |
204 mailbox_holders[VideoFrame::kYPlane], | 333 mailbox_holders[VideoFrame::kYPlane], |
205 mailbox_holders[VideoFrame::kUPlane], | 334 mailbox_holders[VideoFrame::kUPlane], |
206 mailbox_holders[VideoFrame::kVPlane], | 335 mailbox_holders[VideoFrame::kVPlane], |
207 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources), | 336 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources), |
208 size, video_frame->visible_rect(), video_frame->natural_size(), | 337 size, video_frame->visible_rect(), video_frame->natural_size(), |
209 video_frame->timestamp()); | 338 video_frame->timestamp()); |
210 if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY)) | 339 if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY)) |
211 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); | 340 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); |
212 return frame; | 341 frame_ready_cb.Run(frame); |
213 } | 342 } |
214 | 343 |
215 // Destroy all the resources posting one task per FrameResources | 344 // Destroy all the resources posting one task per FrameResources |
216 // to the |task_runner_|. | 345 // to the |media_task_runner_|. |
217 GpuMemoryBufferVideoFramePool::PoolImpl::~PoolImpl() { | 346 GpuMemoryBufferVideoFramePool::PoolImpl::~PoolImpl() { |
218 // Delete all the resources on the media thread. | 347 // Delete all the resources on the media thread. |
219 while (!resources_pool_.empty()) { | 348 while (!resources_pool_.empty()) { |
220 FrameResources* frame_resources = resources_pool_.front(); | 349 FrameResources* frame_resources = resources_pool_.front(); |
221 resources_pool_.pop_front(); | 350 resources_pool_.pop_front(); |
222 task_runner_->PostTask( | 351 media_task_runner_->PostTask( |
223 FROM_HERE, base::Bind(&PoolImpl::DeleteFrameResources, gpu_factories_, | 352 FROM_HERE, base::Bind(&PoolImpl::DeleteFrameResources, gpu_factories_, |
224 base::Owned(frame_resources))); | 353 base::Owned(frame_resources))); |
225 } | 354 } |
226 } | 355 } |
227 | 356 |
228 // Tries to find the resources in the pool or create them. | 357 // Tries to find the resources in the pool or create them. |
229 // Incompatible resources will be dropped. | 358 // Incompatible resources will be dropped. |
230 GpuMemoryBufferVideoFramePool::PoolImpl::FrameResources* | 359 GpuMemoryBufferVideoFramePool::PoolImpl::FrameResources* |
231 GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources( | 360 GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources( |
232 const gfx::Size& size, | 361 const gfx::Size& size, |
233 VideoPixelFormat format) { | 362 VideoPixelFormat format) { |
234 DCHECK(task_runner_->BelongsToCurrentThread()); | |
235 | |
236 auto it = resources_pool_.begin(); | 363 auto it = resources_pool_.begin(); |
237 while (it != resources_pool_.end()) { | 364 while (it != resources_pool_.end()) { |
238 FrameResources* frame_resources = *it; | 365 FrameResources* frame_resources = *it; |
239 if (!frame_resources->in_use) { | 366 if (!frame_resources->in_use) { |
240 if (AreFrameResourcesCompatible(frame_resources, size, format)) { | 367 if (AreFrameResourcesCompatible(frame_resources, size, format)) { |
241 frame_resources->in_use = true; | 368 frame_resources->in_use = true; |
242 return frame_resources; | 369 return frame_resources; |
243 } else { | 370 } else { |
244 resources_pool_.erase(it++); | 371 resources_pool_.erase(it++); |
245 DeleteFrameResources(gpu_factories_, frame_resources); | 372 DeleteFrameResources(gpu_factories_, frame_resources); |
246 delete frame_resources; | 373 delete frame_resources; |
247 } | 374 } |
248 } else { | 375 } else { |
249 it++; | 376 it++; |
250 } | 377 } |
251 } | 378 } |
252 | 379 |
253 // Create the resources. | 380 // Create the resources. |
254 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); | 381 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); |
255 DCHECK(gles2); | 382 if (!gles2) |
| 383 return nullptr; |
256 gles2->ActiveTexture(GL_TEXTURE0); | 384 gles2->ActiveTexture(GL_TEXTURE0); |
257 size_t planes = VideoFrame::NumPlanes(format); | 385 size_t planes = VideoFrame::NumPlanes(format); |
258 FrameResources* frame_resources = new FrameResources(format, size); | 386 FrameResources* frame_resources = new FrameResources(format, size); |
259 resources_pool_.push_back(frame_resources); | 387 resources_pool_.push_back(frame_resources); |
260 for (size_t i = 0; i < planes; ++i) { | 388 for (size_t i = 0; i < planes; ++i) { |
261 PlaneResource& plane_resource = frame_resources->plane_resources[i]; | 389 PlaneResource& plane_resource = frame_resources->plane_resources[i]; |
262 const size_t width = VideoFrame::Columns(i, format, size.width()); | 390 const size_t width = VideoFrame::Columns(i, format, size.width()); |
263 const size_t height = VideoFrame::Rows(i, format, size.height()); | 391 const size_t height = VideoFrame::Rows(i, format, size.height()); |
264 const gfx::Size plane_size(width, height); | 392 const gfx::Size plane_size(width, height); |
265 plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer( | 393 plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer( |
(...skipping 28 matching lines...) Expand all Loading... |
294 if (plane_resource.texture_id) | 422 if (plane_resource.texture_id) |
295 gles2->DeleteTextures(1, &plane_resource.texture_id); | 423 gles2->DeleteTextures(1, &plane_resource.texture_id); |
296 } | 424 } |
297 } | 425 } |
298 | 426 |
299 // Called when a VideoFrame is no longer references. | 427 // Called when a VideoFrame is no longer references. |
300 void GpuMemoryBufferVideoFramePool::PoolImpl::MailboxHoldersReleased( | 428 void GpuMemoryBufferVideoFramePool::PoolImpl::MailboxHoldersReleased( |
301 FrameResources* frame_resources, | 429 FrameResources* frame_resources, |
302 uint32 sync_point) { | 430 uint32 sync_point) { |
303 // Return the resource on the media thread. | 431 // Return the resource on the media thread. |
304 task_runner_->PostTask(FROM_HERE, base::Bind(&PoolImpl::ReturnFrameResources, | 432 media_task_runner_->PostTask( |
305 this, frame_resources)); | 433 FROM_HERE, |
| 434 base::Bind(&PoolImpl::ReturnFrameResources, this, frame_resources)); |
306 } | 435 } |
307 | 436 |
308 // Put back the resoruces in the pool. | 437 // Put back the resoruces in the pool. |
309 void GpuMemoryBufferVideoFramePool::PoolImpl::ReturnFrameResources( | 438 void GpuMemoryBufferVideoFramePool::PoolImpl::ReturnFrameResources( |
310 FrameResources* frame_resources) { | 439 FrameResources* frame_resources) { |
311 DCHECK(task_runner_->BelongsToCurrentThread()); | |
312 | 440 |
313 auto it = std::find(resources_pool_.begin(), resources_pool_.end(), | 441 auto it = std::find(resources_pool_.begin(), resources_pool_.end(), |
314 frame_resources); | 442 frame_resources); |
315 DCHECK(it != resources_pool_.end()); | 443 DCHECK(it != resources_pool_.end()); |
316 // We want the pool to behave in a FIFO way. | 444 // We want the pool to behave in a FIFO way. |
317 // This minimizes the chances of locking the buffer that might be | 445 // This minimizes the chances of locking the buffer that might be |
318 // still needed for drawing. | 446 // still needed for drawing. |
319 std::swap(*it, resources_pool_.back()); | 447 std::swap(*it, resources_pool_.back()); |
320 frame_resources->in_use = false; | 448 frame_resources->in_use = false; |
321 } | 449 } |
322 | 450 |
323 GpuMemoryBufferVideoFramePool::GpuMemoryBufferVideoFramePool( | 451 GpuMemoryBufferVideoFramePool::GpuMemoryBufferVideoFramePool( |
324 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 452 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, |
| 453 const scoped_refptr<base::TaskRunner>& worker_task_runner, |
325 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories) | 454 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories) |
326 : pool_impl_(new PoolImpl(task_runner, gpu_factories)) { | 455 : pool_impl_( |
327 } | 456 new PoolImpl(media_task_runner, worker_task_runner, gpu_factories)) {} |
328 | 457 |
329 GpuMemoryBufferVideoFramePool::~GpuMemoryBufferVideoFramePool() { | 458 GpuMemoryBufferVideoFramePool::~GpuMemoryBufferVideoFramePool() { |
330 } | 459 } |
331 | 460 |
332 scoped_refptr<VideoFrame> | 461 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame( |
333 GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame( | 462 const scoped_refptr<VideoFrame>& video_frame, |
334 const scoped_refptr<VideoFrame>& video_frame) { | 463 const FrameReadyCB& frame_ready_cb) { |
335 switch (video_frame->format()) { | 464 DCHECK(video_frame); |
336 // Supported cases. | 465 pool_impl_->CreateHardwareFrame(video_frame, frame_ready_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 } | 466 } |
352 | 467 |
353 } // namespace media | 468 } // namespace media |
OLD | NEW |