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 |