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 <algorithm> |
11 #include <list> | 11 #include <list> |
12 #include <utility> | 12 #include <utility> |
13 | 13 |
14 #include "base/barrier_closure.h" | 14 #include "base/barrier_closure.h" |
15 #include "base/bind.h" | 15 #include "base/bind.h" |
16 #include "base/containers/stack_container.h" | 16 #include "base/containers/stack_container.h" |
17 #include "base/location.h" | 17 #include "base/location.h" |
18 #include "base/memory/linked_ptr.h" | 18 #include "base/memory/linked_ptr.h" |
19 #include "base/trace_event/trace_event.h" | 19 #include "base/trace_event/trace_event.h" |
20 #include "gpu/command_buffer/client/gles2_interface.h" | 20 #include "gpu/command_buffer/client/gles2_interface.h" |
21 #include "media/renderers/gpu_video_accelerator_factories.h" | 21 #include "media/renderers/gpu_video_accelerator_factories.h" |
22 #include "third_party/libyuv/include/libyuv.h" | |
23 #include "ui/gfx/buffer_format_util.h" | |
22 | 24 |
23 namespace media { | 25 namespace media { |
24 | 26 |
25 // Implementation of a pool of GpuMemoryBuffers used to back VideoFrames. | 27 // Implementation of a pool of GpuMemoryBuffers used to back VideoFrames. |
26 class GpuMemoryBufferVideoFramePool::PoolImpl | 28 class GpuMemoryBufferVideoFramePool::PoolImpl |
27 : public base::RefCountedThreadSafe< | 29 : public base::RefCountedThreadSafe< |
28 GpuMemoryBufferVideoFramePool::PoolImpl> { | 30 GpuMemoryBufferVideoFramePool::PoolImpl> { |
29 public: | 31 public: |
30 // |media_task_runner| is the media task runner associated with the | 32 // |media_task_runner| is the media task runner associated with the |
31 // GL context provided by |gpu_factories| | 33 // GL context provided by |gpu_factories| |
32 // |worker_task_runner| is a task runner used to asynchronously copy | 34 // |worker_task_runner| is a task runner used to asynchronously copy |
33 // video frame's planes. | 35 // video frame's planes. |
34 // |gpu_factories| is an interface to GPU related operation and can be | 36 // |gpu_factories| is an interface to GPU related operation and can be |
35 // null if a GL context is not available. | 37 // null if a GL context is not available. |
36 PoolImpl(const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, | 38 PoolImpl(const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, |
37 const scoped_refptr<base::TaskRunner>& worker_task_runner, | 39 const scoped_refptr<base::TaskRunner>& worker_task_runner, |
38 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories) | 40 const scoped_refptr<GpuVideoAcceleratorFactories>& gpu_factories) |
39 : media_task_runner_(media_task_runner), | 41 : media_task_runner_(media_task_runner), |
40 worker_task_runner_(worker_task_runner), | 42 worker_task_runner_(worker_task_runner), |
41 gpu_factories_(gpu_factories), | 43 gpu_factories_(gpu_factories), |
42 texture_target_(gpu_factories ? gpu_factories->ImageTextureTarget() | 44 texture_target_(gpu_factories ? gpu_factories->ImageTextureTarget() |
43 : GL_TEXTURE_2D) { | 45 : GL_TEXTURE_2D), |
46 output_format_(gpu_factories ? gpu_factories->VideoFrameOutputFormat() | |
47 : PIXEL_FORMAT_I420) { | |
44 DCHECK(media_task_runner_); | 48 DCHECK(media_task_runner_); |
45 DCHECK(worker_task_runner_); | 49 DCHECK(worker_task_runner_); |
46 } | 50 } |
47 | 51 |
48 // Takes a software VideoFrame and calls |frame_ready_cb| with a VideoFrame | 52 // Takes a software VideoFrame and calls |frame_ready_cb| with a VideoFrame |
49 // backed by native textures if possible. | 53 // backed by native textures if possible. |
50 // The data contained in video_frame is copied into the returned frame | 54 // The data contained in video_frame is copied into the returned frame |
51 // asynchronously posting tasks to |worker_task_runner_|, while | 55 // asynchronously posting tasks to |worker_task_runner_|, while |
52 // |frame_ready_cb| will be called on |media_task_runner_| once all the data | 56 // |frame_ready_cb| will be called on |media_task_runner_| once all the data |
53 // has been copied. | 57 // has been copied. |
54 void CreateHardwareFrame(const scoped_refptr<VideoFrame>& video_frame, | 58 void CreateHardwareFrame(const scoped_refptr<VideoFrame>& video_frame, |
55 const FrameReadyCB& cb); | 59 const FrameReadyCB& cb); |
56 | 60 |
57 private: | 61 private: |
58 friend class base::RefCountedThreadSafe< | 62 friend class base::RefCountedThreadSafe< |
59 GpuMemoryBufferVideoFramePool::PoolImpl>; | 63 GpuMemoryBufferVideoFramePool::PoolImpl>; |
60 ~PoolImpl(); | 64 ~PoolImpl(); |
61 | 65 |
62 // Resource to represent a plane. | 66 // Resource to represent a plane. |
63 struct PlaneResource { | 67 struct PlaneResource { |
64 gfx::Size size; | 68 gfx::Size size; |
65 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; | 69 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; |
66 unsigned texture_id = 0u; | 70 unsigned texture_id = 0u; |
67 unsigned image_id = 0u; | 71 unsigned image_id = 0u; |
68 gpu::Mailbox mailbox; | 72 gpu::Mailbox mailbox; |
69 }; | 73 }; |
70 | 74 |
71 // All the resources needed to compose a frame. | 75 // All the resources needed to compose a frame. |
72 struct FrameResources { | 76 struct FrameResources { |
73 FrameResources(VideoPixelFormat format, const gfx::Size& size) | 77 explicit FrameResources(const gfx::Size& size) : size(size) {} |
74 : format(format), size(size) {} | |
75 bool in_use = true; | 78 bool in_use = true; |
76 VideoPixelFormat format; | |
77 gfx::Size size; | 79 gfx::Size size; |
78 PlaneResource plane_resources[VideoFrame::kMaxPlanes]; | 80 PlaneResource plane_resources[VideoFrame::kMaxPlanes]; |
79 }; | 81 }; |
80 | 82 |
81 // Copy |video_frame| data into |frame_resouces| | 83 // Copy |video_frame| data into |frame_resouces| |
82 // and calls |done| when done. | 84 // and calls |done| when done. |
83 void CopyVideoFrameToGpuMemoryBuffers( | 85 void CopyVideoFrameToGpuMemoryBuffers( |
84 const scoped_refptr<VideoFrame>& video_frame, | 86 const scoped_refptr<VideoFrame>& video_frame, |
85 FrameResources* frame_resources, | 87 FrameResources* frame_resources, |
86 const FrameReadyCB& frame_ready_cb); | 88 const FrameReadyCB& frame_ready_cb); |
87 | 89 |
88 // Called when all the data has been copied. | 90 // Called when all the data has been copied. |
89 void OnCopiesDone(const scoped_refptr<VideoFrame>& video_frame, | 91 void OnCopiesDone(const scoped_refptr<VideoFrame>& video_frame, |
90 FrameResources* frame_resources, | 92 FrameResources* frame_resources, |
91 const FrameReadyCB& frame_ready_cb); | 93 const FrameReadyCB& frame_ready_cb); |
92 | 94 |
93 // Prepares GL resources, mailboxes and calls |frame_ready_cb| with the new | 95 // Prepares GL resources, mailboxes and calls |frame_ready_cb| with the new |
94 // VideoFrame. | 96 // VideoFrame. |
95 // This has to be run on |media_task_runner_| where |frame_ready_cb| will also | 97 // This has to be run on |media_task_runner_| where |frame_ready_cb| will also |
96 // be run. | 98 // be run. |
97 void BindAndCreateMailboxesHardwareFrameResources( | 99 void BindAndCreateMailboxesHardwareFrameResources( |
98 const scoped_refptr<VideoFrame>& video_frame, | 100 const scoped_refptr<VideoFrame>& video_frame, |
99 FrameResources* frame_resources, | 101 FrameResources* frame_resources, |
100 const FrameReadyCB& frame_ready_cb); | 102 const FrameReadyCB& frame_ready_cb); |
101 | 103 |
102 // Return true if |resources| can be used to represent a frame for | 104 // Return true if |resources| can be used to represent a frame for |
103 // specific |format| and |size|. | 105 // specific |format| and |size|. |
104 static bool AreFrameResourcesCompatible(const FrameResources* resources, | 106 static bool AreFrameResourcesCompatible(const FrameResources* resources, |
105 const gfx::Size& size, | 107 const gfx::Size& size) { |
106 VideoPixelFormat format) { | 108 return size == resources->size; |
107 return size == resources->size && format == resources->format; | |
108 } | 109 } |
109 | 110 |
110 // Get the resources needed for a frame out of the pool, or create them if | 111 // Get the resources needed for a frame out of the pool, or create them if |
111 // necessary. | 112 // necessary. |
112 // This also drops the LRU resources that can't be reuse for this frame. | 113 // This also drops the LRU resources that can't be reuse for this frame. |
113 FrameResources* GetOrCreateFrameResources(const gfx::Size& size, | 114 FrameResources* GetOrCreateFrameResources(const gfx::Size& size, |
114 VideoPixelFormat format); | 115 VideoPixelFormat format); |
115 | 116 |
116 // Callback called when a VideoFrame generated with GetFrameResources is no | 117 // Callback called when a VideoFrame generated with GetFrameResources is no |
117 // longer referenced. | 118 // longer referenced. |
(...skipping 16 matching lines...) Expand all Loading... | |
134 // Task runner used to asynchronously copy planes. | 135 // Task runner used to asynchronously copy planes. |
135 scoped_refptr<base::TaskRunner> worker_task_runner_; | 136 scoped_refptr<base::TaskRunner> worker_task_runner_; |
136 | 137 |
137 // Interface to GPU related operations. | 138 // Interface to GPU related operations. |
138 scoped_refptr<GpuVideoAcceleratorFactories> gpu_factories_; | 139 scoped_refptr<GpuVideoAcceleratorFactories> gpu_factories_; |
139 | 140 |
140 // Pool of resources. | 141 // Pool of resources. |
141 std::list<FrameResources*> resources_pool_; | 142 std::list<FrameResources*> resources_pool_; |
142 | 143 |
143 const unsigned texture_target_; | 144 const unsigned texture_target_; |
145 const VideoPixelFormat output_format_; | |
146 | |
144 DISALLOW_COPY_AND_ASSIGN(PoolImpl); | 147 DISALLOW_COPY_AND_ASSIGN(PoolImpl); |
145 }; | 148 }; |
146 | 149 |
147 namespace { | 150 namespace { |
148 | 151 |
149 // VideoFrame copies to GpuMemoryBuffers will be split in |kBytesPerCopyTarget| | 152 // VideoFrame copies to GpuMemoryBuffers will be split in copies where the |
150 // bytes copies and run in parallel. | 153 // output size is |kBytesPerCopyTarget| bytes and run in parallel. |
151 const size_t kBytesPerCopyTarget = 1024 * 1024; // 1MB | 154 const size_t kBytesPerCopyTarget = 1024 * 1024; // 1MB |
152 | 155 |
153 void CopyRowsToBuffer(int first_row, | 156 // Return the GpuMemoryBuffer format to use for a specific VideoPixelFormat |
154 int rows, | 157 // and plane. |
155 int bytes_per_row, | 158 gfx::BufferFormat GpuMemoryBufferFormat(VideoPixelFormat format, size_t plane) { |
156 const uint8* source, | 159 switch (format) { |
157 int source_stride, | 160 case PIXEL_FORMAT_I420: |
158 uint8* output, | 161 DCHECK_LE(plane, 2u); |
159 int dest_stride, | 162 return gfx::BufferFormat::R_8; |
160 const base::Closure& done) { | 163 case PIXEL_FORMAT_UYVY: |
161 TRACE_EVENT2("media", "CopyRowsToBuffer", "bytes_per_row", bytes_per_row, | 164 DCHECK_EQ(0u, plane); |
165 return gfx::BufferFormat::UYVY_422; | |
166 default: | |
167 NOTREACHED(); | |
168 return gfx::BufferFormat::BGRA_8888; | |
169 } | |
170 } | |
171 | |
172 unsigned ImageInternalFormat(VideoPixelFormat format, size_t plane) { | |
173 switch (format) { | |
174 case PIXEL_FORMAT_I420: | |
175 DCHECK_LE(plane, 2u); | |
176 return GL_R8_EXT; | |
177 case PIXEL_FORMAT_UYVY: | |
178 DCHECK_EQ(0u, plane); | |
179 return GL_RGB; | |
180 default: | |
181 NOTREACHED(); | |
182 return 0; | |
183 } | |
184 } | |
185 | |
186 void CopyRowsToI420Buffer(int first_row, | |
187 int rows, | |
188 int bytes_per_row, | |
189 const uint8* source, | |
190 int source_stride, | |
191 uint8* output, | |
192 int dest_stride, | |
193 const base::Closure& done) { | |
194 TRACE_EVENT2("media", "CopyRowsToI420Buffer", "bytes_per_row", bytes_per_row, | |
162 "rows", rows); | 195 "rows", rows); |
163 DCHECK_NE(dest_stride, 0); | 196 DCHECK_NE(dest_stride, 0); |
164 DCHECK_LE(bytes_per_row, std::abs(dest_stride)); | 197 DCHECK_LE(bytes_per_row, std::abs(dest_stride)); |
165 DCHECK_LE(bytes_per_row, source_stride); | 198 DCHECK_LE(bytes_per_row, source_stride); |
166 for (int row = first_row; row < first_row + rows; ++row) { | 199 for (int row = first_row; row < first_row + rows; ++row) { |
167 memcpy(output + dest_stride * row, source + source_stride * row, | 200 memcpy(output + dest_stride * row, source + source_stride * row, |
168 bytes_per_row); | 201 bytes_per_row); |
169 } | 202 } |
170 done.Run(); | 203 done.Run(); |
171 } | 204 } |
172 | 205 |
206 void CopyRowsToUYVYBuffer(int first_row, | |
207 int rows, | |
208 int width, | |
209 const scoped_refptr<VideoFrame>& source_frame, | |
210 uint8* output, | |
211 int dest_stride, | |
212 const base::Closure& done) { | |
213 TRACE_EVENT2("media", "CopyRowsToUYVYBuffer", "bytes_per_row", width * 2, | |
214 "rows", rows); | |
215 DCHECK_NE(dest_stride, 0); | |
216 DCHECK_LE(width, std::abs(dest_stride / 2)); | |
217 DCHECK_EQ(0, first_row % 2); | |
218 libyuv::I420ToUYVY( | |
219 source_frame->data(VideoFrame::kYPlane) + | |
220 first_row * source_frame->stride(VideoFrame::kYPlane), | |
221 source_frame->stride(VideoFrame::kYPlane), | |
222 source_frame->data(VideoFrame::kUPlane) + | |
223 first_row / 2 * source_frame->stride(VideoFrame::kUPlane), | |
224 source_frame->stride(VideoFrame::kUPlane), | |
225 source_frame->data(VideoFrame::kVPlane) + | |
226 first_row / 2 * source_frame->stride(VideoFrame::kVPlane), | |
227 source_frame->stride(VideoFrame::kVPlane), | |
228 output + first_row * dest_stride, dest_stride, width, rows); | |
229 done.Run(); | |
230 } | |
231 | |
173 } // unnamed namespace | 232 } // unnamed namespace |
174 | 233 |
175 // Creates a VideoFrame backed by native textures starting from a software | 234 // Creates a VideoFrame backed by native textures starting from a software |
176 // VideoFrame. | 235 // VideoFrame. |
177 // The data contained in |video_frame| is copied into the VideoFrame passed to | 236 // The data contained in |video_frame| is copied into the VideoFrame passed to |
178 // |frame_ready_cb|. | 237 // |frame_ready_cb|. |
179 // This has to be called on the thread where |media_task_runner_| is current. | 238 // This has to be called on the thread where |media_task_runner_| is current. |
180 void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame( | 239 void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame( |
181 const scoped_refptr<VideoFrame>& video_frame, | 240 const scoped_refptr<VideoFrame>& video_frame, |
182 const FrameReadyCB& frame_ready_cb) { | 241 const FrameReadyCB& frame_ready_cb) { |
183 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 242 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
184 if (!gpu_factories_ || !gpu_factories_->IsTextureRGSupported()) { | 243 if (!gpu_factories_ || (output_format_ == PIXEL_FORMAT_I420 && |
244 !gpu_factories_->IsTextureRGSupported())) { | |
185 frame_ready_cb.Run(video_frame); | 245 frame_ready_cb.Run(video_frame); |
186 return; | 246 return; |
187 } | 247 } |
188 switch (video_frame->format()) { | 248 switch (video_frame->format()) { |
189 // Supported cases. | 249 // Supported cases. |
190 case PIXEL_FORMAT_YV12: | 250 case PIXEL_FORMAT_YV12: |
191 case PIXEL_FORMAT_I420: | 251 case PIXEL_FORMAT_I420: |
192 break; | 252 break; |
193 // Unsupported cases. | 253 // Unsupported cases. |
194 case PIXEL_FORMAT_YV12A: | 254 case PIXEL_FORMAT_YV12A: |
195 case PIXEL_FORMAT_YV16: | 255 case PIXEL_FORMAT_YV16: |
196 case PIXEL_FORMAT_YV24: | 256 case PIXEL_FORMAT_YV24: |
197 case PIXEL_FORMAT_NV12: | 257 case PIXEL_FORMAT_NV12: |
198 case PIXEL_FORMAT_ARGB: | 258 case PIXEL_FORMAT_ARGB: |
199 case PIXEL_FORMAT_XRGB: | 259 case PIXEL_FORMAT_XRGB: |
200 case PIXEL_FORMAT_UYVY: | 260 case PIXEL_FORMAT_UYVY: |
201 case PIXEL_FORMAT_UNKNOWN: | 261 case PIXEL_FORMAT_UNKNOWN: |
202 frame_ready_cb.Run(video_frame); | 262 frame_ready_cb.Run(video_frame); |
203 return; | 263 return; |
204 } | 264 } |
205 | 265 |
206 VideoPixelFormat format = video_frame->format(); | |
207 DCHECK(video_frame->visible_rect().origin().IsOrigin()); | 266 DCHECK(video_frame->visible_rect().origin().IsOrigin()); |
208 const gfx::Size size = video_frame->visible_rect().size(); | 267 const gfx::Size size = video_frame->visible_rect().size(); |
209 | 268 |
210 // Acquire resources. Incompatible ones will be dropped from the pool. | 269 // Acquire resources. Incompatible ones will be dropped from the pool. |
211 FrameResources* frame_resources = GetOrCreateFrameResources(size, format); | 270 FrameResources* frame_resources = |
271 GetOrCreateFrameResources(size, output_format_); | |
212 if (!frame_resources) { | 272 if (!frame_resources) { |
213 frame_ready_cb.Run(video_frame); | 273 frame_ready_cb.Run(video_frame); |
214 return; | 274 return; |
215 } | 275 } |
216 | 276 |
217 worker_task_runner_->PostTask( | 277 worker_task_runner_->PostTask( |
218 FROM_HERE, base::Bind(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers, this, | 278 FROM_HERE, base::Bind(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers, this, |
219 video_frame, frame_resources, frame_ready_cb)); | 279 video_frame, frame_resources, frame_ready_cb)); |
220 } | 280 } |
221 | 281 |
222 void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone( | 282 void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone( |
223 const scoped_refptr<VideoFrame>& video_frame, | 283 const scoped_refptr<VideoFrame>& video_frame, |
224 FrameResources* frame_resources, | 284 FrameResources* frame_resources, |
225 const FrameReadyCB& frame_ready_cb) { | 285 const FrameReadyCB& frame_ready_cb) { |
226 const VideoPixelFormat format = video_frame->format(); | 286 const size_t planes = VideoFrame::NumPlanes(output_format_); |
227 const size_t planes = VideoFrame::NumPlanes(format); | |
228 for (size_t i = 0; i < planes; ++i) { | 287 for (size_t i = 0; i < planes; ++i) { |
229 frame_resources->plane_resources[i].gpu_memory_buffer->Unmap(); | 288 frame_resources->plane_resources[i].gpu_memory_buffer->Unmap(); |
230 } | 289 } |
231 | 290 |
232 media_task_runner_->PostTask( | 291 media_task_runner_->PostTask( |
233 FROM_HERE, | 292 FROM_HERE, |
234 base::Bind(&PoolImpl::BindAndCreateMailboxesHardwareFrameResources, this, | 293 base::Bind(&PoolImpl::BindAndCreateMailboxesHardwareFrameResources, this, |
235 video_frame, frame_resources, frame_ready_cb)); | 294 video_frame, frame_resources, frame_ready_cb)); |
236 } | 295 } |
237 | 296 |
238 // Copies |video_frame| into |frame_resources| asynchronously, posting n tasks | 297 // Copies |video_frame| into |frame_resources| asynchronously, posting n tasks |
239 // that will be synchronized by a barrier. | 298 // that will be synchronized by a barrier. |
240 // After the barrier is passed OnCopiesDone will be called. | 299 // After the barrier is passed OnCopiesDone will be called. |
241 void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( | 300 void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( |
242 const scoped_refptr<VideoFrame>& video_frame, | 301 const scoped_refptr<VideoFrame>& video_frame, |
243 FrameResources* frame_resources, | 302 FrameResources* frame_resources, |
244 const FrameReadyCB& frame_ready_cb) { | 303 const FrameReadyCB& frame_ready_cb) { |
245 const VideoPixelFormat format = video_frame->format(); | 304 // Compute the number of tasks to post and create the barrier. |
246 const size_t planes = VideoFrame::NumPlanes(format); | 305 const size_t dest_planes = VideoFrame::NumPlanes(output_format_); |
247 gfx::Size size = video_frame->visible_rect().size(); | 306 gfx::Size size = video_frame->visible_rect().size(); |
248 size_t copies = 0; | 307 size_t copies = 0; |
249 for (size_t i = 0; i < planes; ++i) { | 308 for (size_t i = 0; i < dest_planes; ++i) { |
250 int rows = VideoFrame::Rows(i, format, size.height()); | 309 int rows = VideoFrame::Rows(i, output_format_, size.height()); |
251 int bytes_per_row = VideoFrame::RowBytes(i, format, size.width()); | 310 int bytes_per_row = VideoFrame::RowBytes(i, output_format_, size.width()); |
311 // Copy a even number of lines, and at least one. | |
252 int rows_per_copy = | 312 int rows_per_copy = |
253 std::max<size_t>(kBytesPerCopyTarget / bytes_per_row, 1); | 313 std::max<size_t>((kBytesPerCopyTarget / bytes_per_row) & ~1, 1); |
254 copies += rows / rows_per_copy; | 314 copies += rows / rows_per_copy; |
255 if (rows % rows_per_copy) | 315 if (rows % rows_per_copy) |
256 ++copies; | 316 ++copies; |
257 } | 317 } |
258 | |
259 base::Closure copies_done = | 318 base::Closure copies_done = |
260 base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources, | 319 base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources, |
261 frame_ready_cb); | 320 frame_ready_cb); |
262 base::Closure barrier = base::BarrierClosure(copies, copies_done); | 321 base::Closure barrier = base::BarrierClosure(copies, copies_done); |
322 // Post all the async tasks. | |
323 for (size_t i = 0; i < dest_planes; ++i) { | |
324 int rows = VideoFrame::Rows(i, output_format_, size.height()); | |
325 int bytes_per_row = VideoFrame::RowBytes(i, output_format_, size.width()); | |
326 int rows_per_copy = | |
327 std::max<size_t>((kBytesPerCopyTarget / bytes_per_row) & ~1, 1); | |
263 | 328 |
264 for (size_t i = 0; i < planes; ++i) { | 329 void* data = nullptr; |
265 int rows = VideoFrame::Rows(i, format, size.height()); | 330 CHECK_EQ(1u, gfx::NumberOfPlanesForBufferFormat( |
266 int bytes_per_row = VideoFrame::RowBytes(i, format, size.width()); | 331 GpuMemoryBufferFormat(output_format_, i))); |
Avi (use Gerrit)
2015/08/21 21:32:03
DCHECK here too
Daniele Castagna
2015/08/21 21:37:08
Done.
| |
267 int rows_per_copy = | 332 bool rv = frame_resources->plane_resources[i].gpu_memory_buffer->Map(&data); |
268 std::max<size_t>(kBytesPerCopyTarget / bytes_per_row, 1); | 333 DCHECK(rv); |
334 uint8* mapped_buffer = static_cast<uint8*>(data); | |
269 | 335 |
270 PlaneResource& plane_resource = frame_resources->plane_resources[i]; | |
271 void* data = nullptr; | |
272 CHECK(plane_resource.gpu_memory_buffer->Map(&data)); | |
273 uint8* mapped_buffer = static_cast<uint8*>(data); | |
274 int dest_stride = 0; | 336 int dest_stride = 0; |
275 plane_resource.gpu_memory_buffer->GetStride(&dest_stride); | 337 frame_resources->plane_resources[i].gpu_memory_buffer->GetStride( |
338 &dest_stride); | |
276 | 339 |
277 for (int row = 0; row < rows; row += rows_per_copy) { | 340 for (int row = 0; row < rows; row += rows_per_copy) { |
278 worker_task_runner_->PostTask( | 341 switch (output_format_) { |
279 FROM_HERE, | 342 case PIXEL_FORMAT_I420: |
280 base::Bind(&CopyRowsToBuffer, row, | 343 worker_task_runner_->PostTask( |
281 std::min(rows_per_copy, rows - row), bytes_per_row, | 344 FROM_HERE, |
282 video_frame->data(i), video_frame->stride(i), | 345 base::Bind(&CopyRowsToI420Buffer, row, |
283 mapped_buffer, dest_stride, barrier)); | 346 std::min(rows_per_copy, rows - row), bytes_per_row, |
347 video_frame->data(i), video_frame->stride(i), | |
348 mapped_buffer, dest_stride, barrier)); | |
349 break; | |
350 case PIXEL_FORMAT_UYVY: | |
351 worker_task_runner_->PostTask( | |
352 FROM_HERE, | |
353 base::Bind(&CopyRowsToUYVYBuffer, row, | |
354 std::min(rows_per_copy, rows - row), size.width(), | |
355 video_frame, mapped_buffer, dest_stride, barrier)); | |
356 break; | |
357 default: | |
358 NOTREACHED(); | |
359 } | |
284 } | 360 } |
285 } | 361 } |
286 } | 362 } |
287 | 363 |
288 void GpuMemoryBufferVideoFramePool::PoolImpl:: | 364 void GpuMemoryBufferVideoFramePool::PoolImpl:: |
289 BindAndCreateMailboxesHardwareFrameResources( | 365 BindAndCreateMailboxesHardwareFrameResources( |
290 const scoped_refptr<VideoFrame>& video_frame, | 366 const scoped_refptr<VideoFrame>& video_frame, |
291 FrameResources* frame_resources, | 367 FrameResources* frame_resources, |
292 const FrameReadyCB& frame_ready_cb) { | 368 const FrameReadyCB& frame_ready_cb) { |
293 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); | 369 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); |
294 if (!gles2) { | 370 if (!gles2) { |
295 frame_ready_cb.Run(video_frame); | 371 frame_ready_cb.Run(video_frame); |
296 return; | 372 return; |
297 } | 373 } |
298 | 374 |
299 const VideoPixelFormat format = video_frame->format(); | 375 const size_t planes = VideoFrame::NumPlanes(output_format_); |
300 const size_t planes = VideoFrame::NumPlanes(format); | |
301 const gfx::Size size = video_frame->visible_rect().size(); | 376 const gfx::Size size = video_frame->visible_rect().size(); |
302 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; | 377 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; |
303 // Set up the planes creating the mailboxes needed to refer to the textures. | 378 // Set up the planes creating the mailboxes needed to refer to the textures. |
304 for (size_t i = 0; i < planes; ++i) { | 379 for (size_t i = 0; i < planes; ++i) { |
305 PlaneResource& plane_resource = frame_resources->plane_resources[i]; | 380 PlaneResource& plane_resource = frame_resources->plane_resources[i]; |
306 // Bind the texture and create or rebind the image. | 381 // Bind the texture and create or rebind the image. |
307 gles2->BindTexture(texture_target_, plane_resource.texture_id); | 382 gles2->BindTexture(texture_target_, plane_resource.texture_id); |
308 | 383 |
309 if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) { | 384 if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) { |
310 const size_t width = VideoFrame::Columns(i, format, size.width()); | 385 const size_t width = VideoFrame::Columns(i, output_format_, size.width()); |
311 const size_t height = VideoFrame::Rows(i, format, size.height()); | 386 const size_t height = VideoFrame::Rows(i, output_format_, size.height()); |
312 plane_resource.image_id = gles2->CreateImageCHROMIUM( | 387 plane_resource.image_id = gles2->CreateImageCHROMIUM( |
313 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height, | 388 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height, |
314 GL_R8_EXT); | 389 ImageInternalFormat(output_format_, i)); |
315 } else { | 390 } else { |
316 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, | 391 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, |
317 plane_resource.image_id); | 392 plane_resource.image_id); |
318 } | 393 } |
319 gles2->BindTexImage2DCHROMIUM(texture_target_, plane_resource.image_id); | 394 gles2->BindTexImage2DCHROMIUM(texture_target_, plane_resource.image_id); |
320 mailbox_holders[i] = | 395 mailbox_holders[i] = |
321 gpu::MailboxHolder(plane_resource.mailbox, texture_target_, 0); | 396 gpu::MailboxHolder(plane_resource.mailbox, texture_target_, 0); |
322 } | 397 } |
323 | 398 |
324 // Insert a sync_point, this is needed to make sure that the textures the | 399 // Insert a sync_point, this is needed to make sure that the textures the |
325 // mailboxes refer to will be used only after all the previous commands posted | 400 // mailboxes refer to will be used only after all the previous commands posted |
326 // in the command buffer have been processed. | 401 // in the command buffer have been processed. |
327 unsigned sync_point = gles2->InsertSyncPointCHROMIUM(); | 402 unsigned sync_point = gles2->InsertSyncPointCHROMIUM(); |
328 for (size_t i = 0; i < planes; ++i) { | 403 for (size_t i = 0; i < planes; ++i) { |
329 mailbox_holders[i].sync_point = sync_point; | 404 mailbox_holders[i].sync_point = sync_point; |
330 } | 405 } |
331 | 406 |
407 scoped_refptr<VideoFrame> frame; | |
332 // Create the VideoFrame backed by native textures. | 408 // Create the VideoFrame backed by native textures. |
333 scoped_refptr<VideoFrame> frame = VideoFrame::WrapYUV420NativeTextures( | 409 switch (output_format_) { |
334 mailbox_holders[VideoFrame::kYPlane], | 410 case PIXEL_FORMAT_I420: |
335 mailbox_holders[VideoFrame::kUPlane], | 411 frame = VideoFrame::WrapYUV420NativeTextures( |
336 mailbox_holders[VideoFrame::kVPlane], | 412 mailbox_holders[VideoFrame::kYPlane], |
337 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources), | 413 mailbox_holders[VideoFrame::kUPlane], |
338 size, video_frame->visible_rect(), video_frame->natural_size(), | 414 mailbox_holders[VideoFrame::kVPlane], |
339 video_frame->timestamp()); | 415 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources), |
340 if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY)) | 416 size, video_frame->visible_rect(), video_frame->natural_size(), |
341 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); | 417 video_frame->timestamp()); |
418 if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY)) | |
419 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); | |
420 break; | |
421 case PIXEL_FORMAT_UYVY: | |
422 frame = VideoFrame::WrapNativeTexture( | |
423 PIXEL_FORMAT_UYVY, mailbox_holders[VideoFrame::kYPlane], | |
424 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources), | |
425 size, video_frame->visible_rect(), video_frame->natural_size(), | |
426 video_frame->timestamp()); | |
427 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); | |
428 break; | |
429 default: | |
430 NOTREACHED(); | |
431 } | |
342 frame_ready_cb.Run(frame); | 432 frame_ready_cb.Run(frame); |
343 } | 433 } |
344 | 434 |
345 // Destroy all the resources posting one task per FrameResources | 435 // Destroy all the resources posting one task per FrameResources |
346 // to the |media_task_runner_|. | 436 // to the |media_task_runner_|. |
347 GpuMemoryBufferVideoFramePool::PoolImpl::~PoolImpl() { | 437 GpuMemoryBufferVideoFramePool::PoolImpl::~PoolImpl() { |
348 // Delete all the resources on the media thread. | 438 // Delete all the resources on the media thread. |
349 while (!resources_pool_.empty()) { | 439 while (!resources_pool_.empty()) { |
350 FrameResources* frame_resources = resources_pool_.front(); | 440 FrameResources* frame_resources = resources_pool_.front(); |
351 resources_pool_.pop_front(); | 441 resources_pool_.pop_front(); |
352 media_task_runner_->PostTask( | 442 media_task_runner_->PostTask( |
353 FROM_HERE, base::Bind(&PoolImpl::DeleteFrameResources, gpu_factories_, | 443 FROM_HERE, base::Bind(&PoolImpl::DeleteFrameResources, gpu_factories_, |
354 base::Owned(frame_resources))); | 444 base::Owned(frame_resources))); |
355 } | 445 } |
356 } | 446 } |
357 | 447 |
358 // Tries to find the resources in the pool or create them. | 448 // Tries to find the resources in the pool or create them. |
359 // Incompatible resources will be dropped. | 449 // Incompatible resources will be dropped. |
360 GpuMemoryBufferVideoFramePool::PoolImpl::FrameResources* | 450 GpuMemoryBufferVideoFramePool::PoolImpl::FrameResources* |
361 GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources( | 451 GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources( |
362 const gfx::Size& size, | 452 const gfx::Size& size, |
363 VideoPixelFormat format) { | 453 VideoPixelFormat format) { |
364 auto it = resources_pool_.begin(); | 454 auto it = resources_pool_.begin(); |
365 while (it != resources_pool_.end()) { | 455 while (it != resources_pool_.end()) { |
366 FrameResources* frame_resources = *it; | 456 FrameResources* frame_resources = *it; |
367 if (!frame_resources->in_use) { | 457 if (!frame_resources->in_use) { |
368 if (AreFrameResourcesCompatible(frame_resources, size, format)) { | 458 if (AreFrameResourcesCompatible(frame_resources, size)) { |
369 frame_resources->in_use = true; | 459 frame_resources->in_use = true; |
370 return frame_resources; | 460 return frame_resources; |
371 } else { | 461 } else { |
372 resources_pool_.erase(it++); | 462 resources_pool_.erase(it++); |
373 DeleteFrameResources(gpu_factories_, frame_resources); | 463 DeleteFrameResources(gpu_factories_, frame_resources); |
374 delete frame_resources; | 464 delete frame_resources; |
375 } | 465 } |
376 } else { | 466 } else { |
377 it++; | 467 it++; |
378 } | 468 } |
379 } | 469 } |
380 | 470 |
381 // Create the resources. | 471 // Create the resources. |
382 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); | 472 gpu::gles2::GLES2Interface* gles2 = gpu_factories_->GetGLES2Interface(); |
383 if (!gles2) | 473 if (!gles2) |
384 return nullptr; | 474 return nullptr; |
385 gles2->ActiveTexture(GL_TEXTURE0); | 475 gles2->ActiveTexture(GL_TEXTURE0); |
386 size_t planes = VideoFrame::NumPlanes(format); | 476 size_t planes = VideoFrame::NumPlanes(format); |
387 FrameResources* frame_resources = new FrameResources(format, size); | 477 FrameResources* frame_resources = new FrameResources(size); |
388 resources_pool_.push_back(frame_resources); | 478 resources_pool_.push_back(frame_resources); |
389 for (size_t i = 0; i < planes; ++i) { | 479 for (size_t i = 0; i < planes; ++i) { |
390 PlaneResource& plane_resource = frame_resources->plane_resources[i]; | 480 PlaneResource& plane_resource = frame_resources->plane_resources[i]; |
391 const size_t width = VideoFrame::Columns(i, format, size.width()); | 481 const size_t width = VideoFrame::Columns(i, format, size.width()); |
392 const size_t height = VideoFrame::Rows(i, format, size.height()); | 482 const size_t height = VideoFrame::Rows(i, format, size.height()); |
393 const gfx::Size plane_size(width, height); | 483 const gfx::Size plane_size(width, height); |
484 | |
394 plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer( | 485 plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer( |
395 plane_size, gfx::BufferFormat::R_8, gfx::BufferUsage::MAP); | 486 plane_size, GpuMemoryBufferFormat(format, i), gfx::BufferUsage::MAP); |
396 | 487 |
397 gles2->GenTextures(1, &plane_resource.texture_id); | 488 gles2->GenTextures(1, &plane_resource.texture_id); |
398 gles2->BindTexture(texture_target_, plane_resource.texture_id); | 489 gles2->BindTexture(texture_target_, plane_resource.texture_id); |
399 gles2->TexParameteri(texture_target_, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 490 gles2->TexParameteri(texture_target_, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
400 gles2->TexParameteri(texture_target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 491 gles2->TexParameteri(texture_target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
401 gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 492 gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
402 gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 493 gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
403 gles2->GenMailboxCHROMIUM(plane_resource.mailbox.name); | 494 gles2->GenMailboxCHROMIUM(plane_resource.mailbox.name); |
404 gles2->ProduceTextureCHROMIUM(texture_target_, plane_resource.mailbox.name); | 495 gles2->ProduceTextureCHROMIUM(texture_target_, plane_resource.mailbox.name); |
405 } | 496 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
460 } | 551 } |
461 | 552 |
462 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame( | 553 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame( |
463 const scoped_refptr<VideoFrame>& video_frame, | 554 const scoped_refptr<VideoFrame>& video_frame, |
464 const FrameReadyCB& frame_ready_cb) { | 555 const FrameReadyCB& frame_ready_cb) { |
465 DCHECK(video_frame); | 556 DCHECK(video_frame); |
466 pool_impl_->CreateHardwareFrame(video_frame, frame_ready_cb); | 557 pool_impl_->CreateHardwareFrame(video_frame, frame_ready_cb); |
467 } | 558 } |
468 | 559 |
469 } // namespace media | 560 } // namespace media |
OLD | NEW |