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 #include <stddef.h> | 9 #include <stddef.h> |
10 #include <stdint.h> | 10 #include <stdint.h> |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
79 struct PlaneResource { | 79 struct PlaneResource { |
80 gfx::Size size; | 80 gfx::Size size; |
81 std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; | 81 std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; |
82 unsigned texture_id = 0u; | 82 unsigned texture_id = 0u; |
83 unsigned image_id = 0u; | 83 unsigned image_id = 0u; |
84 gpu::Mailbox mailbox; | 84 gpu::Mailbox mailbox; |
85 }; | 85 }; |
86 | 86 |
87 // All the resources needed to compose a frame. | 87 // All the resources needed to compose a frame. |
88 struct FrameResources { | 88 struct FrameResources { |
89 explicit FrameResources(const gfx::Size& size) : size(size) {} | 89 explicit FrameResources(const gfx::Size& size, VideoPixelFormat format) |
90 : size(size), format(format) {} | |
90 void SetIsInUse(bool in_use) { in_use_ = in_use; } | 91 void SetIsInUse(bool in_use) { in_use_ = in_use; } |
91 bool IsInUse() const { return in_use_; } | 92 bool IsInUse() const { return in_use_; } |
92 | 93 |
93 const gfx::Size size; | 94 const gfx::Size size; |
95 VideoPixelFormat format; | |
94 PlaneResource plane_resources[VideoFrame::kMaxPlanes]; | 96 PlaneResource plane_resources[VideoFrame::kMaxPlanes]; |
95 | 97 |
96 private: | 98 private: |
97 bool in_use_ = true; | 99 bool in_use_ = true; |
98 }; | 100 }; |
99 | 101 |
100 // Copy |video_frame| data into |frame_resouces| | 102 // Copy |video_frame| data into |frame_resouces| |
101 // and calls |done| when done. | 103 // and calls |done| when done. |
102 void CopyVideoFrameToGpuMemoryBuffers( | 104 void CopyVideoFrameToGpuMemoryBuffers( |
103 const scoped_refptr<VideoFrame>& video_frame, | 105 const scoped_refptr<VideoFrame>& video_frame, |
(...skipping 10 matching lines...) Expand all Loading... | |
114 // This has to be run on |media_task_runner_| where |frame_ready_cb| will also | 116 // This has to be run on |media_task_runner_| where |frame_ready_cb| will also |
115 // be run. | 117 // be run. |
116 void BindAndCreateMailboxesHardwareFrameResources( | 118 void BindAndCreateMailboxesHardwareFrameResources( |
117 const scoped_refptr<VideoFrame>& video_frame, | 119 const scoped_refptr<VideoFrame>& video_frame, |
118 FrameResources* frame_resources, | 120 FrameResources* frame_resources, |
119 const FrameReadyCB& frame_ready_cb); | 121 const FrameReadyCB& frame_ready_cb); |
120 | 122 |
121 // Return true if |resources| can be used to represent a frame for | 123 // Return true if |resources| can be used to represent a frame for |
122 // specific |format| and |size|. | 124 // specific |format| and |size|. |
123 static bool AreFrameResourcesCompatible(const FrameResources* resources, | 125 static bool AreFrameResourcesCompatible(const FrameResources* resources, |
124 const gfx::Size& size) { | 126 const gfx::Size& size, |
125 return size == resources->size; | 127 VideoPixelFormat format) { |
128 return size == resources->size && format == resources->format; | |
126 } | 129 } |
127 | 130 |
128 // Get the resources needed for a frame out of the pool, or create them if | 131 // Get the resources needed for a frame out of the pool, or create them if |
129 // necessary. | 132 // necessary. |
130 // This also drops the LRU resources that can't be reuse for this frame. | 133 // This also drops the LRU resources that can't be reuse for this frame. |
131 FrameResources* GetOrCreateFrameResources(const gfx::Size& size, | 134 FrameResources* GetOrCreateFrameResources(const gfx::Size& size, |
132 VideoPixelFormat format); | 135 VideoPixelFormat format); |
133 | 136 |
134 // Callback called when a VideoFrame generated with GetFrameResources is no | 137 // Callback called when a VideoFrame generated with GetFrameResources is no |
135 // longer referenced. | 138 // longer referenced. |
(...skipping 12 matching lines...) Expand all Loading... | |
148 scoped_refptr<base::TaskRunner> worker_task_runner_; | 151 scoped_refptr<base::TaskRunner> worker_task_runner_; |
149 | 152 |
150 // Interface to GPU related operations. | 153 // Interface to GPU related operations. |
151 GpuVideoAcceleratorFactories* gpu_factories_; | 154 GpuVideoAcceleratorFactories* gpu_factories_; |
152 | 155 |
153 // Pool of resources. | 156 // Pool of resources. |
154 std::list<FrameResources*> resources_pool_; | 157 std::list<FrameResources*> resources_pool_; |
155 | 158 |
156 // TODO(dcastagna): change the following type from VideoPixelFormat to | 159 // TODO(dcastagna): change the following type from VideoPixelFormat to |
157 // BufferFormat. | 160 // BufferFormat. |
161 // Pixel format of the hardware video frames for I420 and YV12 video. | |
158 VideoPixelFormat output_format_; | 162 VideoPixelFormat output_format_; |
Daniele Castagna
2016/10/10 18:42:31
This is changing slightly with crrev.com/238244300
aleksandar.stojiljkovic
2016/10/11 18:29:54
Done.
CL split to:
crrev.com/2410923002: GpuMemory
| |
159 | 163 |
164 // If texture_rg is supported, gpu memory buffers can be used for R8 and RG8. | |
165 bool texture_rg_available_ = false; | |
166 bool texture_rg_available_initialized_ = false; | |
167 | |
160 DISALLOW_COPY_AND_ASSIGN(PoolImpl); | 168 DISALLOW_COPY_AND_ASSIGN(PoolImpl); |
161 }; | 169 }; |
162 | 170 |
163 namespace { | 171 namespace { |
164 | 172 |
165 // VideoFrame copies to GpuMemoryBuffers will be split in copies where the | 173 // VideoFrame copies to GpuMemoryBuffers will be split in copies where the |
166 // output size is |kBytesPerCopyTarget| bytes and run in parallel. | 174 // output size is |kBytesPerCopyTarget| bytes and run in parallel. |
167 const size_t kBytesPerCopyTarget = 1024 * 1024; // 1MB | 175 const size_t kBytesPerCopyTarget = 1024 * 1024; // 1MB |
168 | 176 |
169 // Return the GpuMemoryBuffer format to use for a specific VideoPixelFormat | |
170 // and plane. | |
171 gfx::BufferFormat GpuMemoryBufferFormat(VideoPixelFormat format, size_t plane) { | |
172 switch (format) { | |
173 case PIXEL_FORMAT_I420: | |
174 DCHECK_LE(plane, 2u); | |
175 return gfx::BufferFormat::R_8; | |
176 case PIXEL_FORMAT_NV12: | |
177 DCHECK_LE(plane, 1u); | |
178 return gfx::BufferFormat::YUV_420_BIPLANAR; | |
179 case PIXEL_FORMAT_UYVY: | |
180 DCHECK_EQ(0u, plane); | |
181 return gfx::BufferFormat::UYVY_422; | |
182 default: | |
183 NOTREACHED(); | |
184 return gfx::BufferFormat::BGRA_8888; | |
185 } | |
186 } | |
187 | |
188 unsigned ImageInternalFormat(VideoPixelFormat format, size_t plane) { | 177 unsigned ImageInternalFormat(VideoPixelFormat format, size_t plane) { |
189 switch (format) { | 178 switch (format) { |
190 case PIXEL_FORMAT_I420: | 179 case PIXEL_FORMAT_I420: |
191 DCHECK_LE(plane, 2u); | 180 DCHECK_LE(plane, 2u); |
192 return GL_RED_EXT; | 181 return GL_RED_EXT; |
193 case PIXEL_FORMAT_NV12: | 182 case PIXEL_FORMAT_NV12: |
194 DCHECK_LE(plane, 1u); | 183 DCHECK_LE(plane, 1u); |
195 return GL_RGB_YCBCR_420V_CHROMIUM; | 184 return GL_RGB_YCBCR_420V_CHROMIUM; |
196 case PIXEL_FORMAT_UYVY: | 185 case PIXEL_FORMAT_UYVY: |
197 DCHECK_EQ(0u, plane); | 186 DCHECK_EQ(0u, plane); |
198 return GL_RGB_YCBCR_422_CHROMIUM; | 187 return GL_RGB_YCBCR_422_CHROMIUM; |
188 case PIXEL_FORMAT_Y16: | |
189 DCHECK_EQ(0u, plane); | |
190 return GL_RG_EXT; | |
199 default: | 191 default: |
200 NOTREACHED(); | 192 NOTREACHED(); |
201 return 0; | 193 return 0; |
202 } | 194 } |
203 } | 195 } |
204 | 196 |
205 // The number of output planes to be copied in each iteration. | 197 // The number of output planes to be copied in each iteration. |
206 size_t PlanesPerCopy(VideoPixelFormat format) { | 198 size_t PlanesPerCopy(VideoPixelFormat format) { |
207 switch (format) { | 199 switch (format) { |
208 case PIXEL_FORMAT_I420: | 200 case PIXEL_FORMAT_I420: |
209 case PIXEL_FORMAT_UYVY: | 201 case PIXEL_FORMAT_UYVY: |
202 case PIXEL_FORMAT_Y16: | |
210 return 1; | 203 return 1; |
211 case PIXEL_FORMAT_NV12: | 204 case PIXEL_FORMAT_NV12: |
212 return 2; | 205 return 2; |
213 default: | 206 default: |
214 NOTREACHED(); | 207 NOTREACHED(); |
215 return 0; | 208 return 0; |
216 } | 209 } |
217 } | 210 } |
218 | 211 |
219 // The number of output rows to be copied in each iteration. | 212 // The number of output rows to be copied in each iteration. |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
305 first_row / 2 * source_frame->stride(VideoFrame::kUPlane), | 298 first_row / 2 * source_frame->stride(VideoFrame::kUPlane), |
306 source_frame->stride(VideoFrame::kUPlane), | 299 source_frame->stride(VideoFrame::kUPlane), |
307 source_frame->visible_data(VideoFrame::kVPlane) + | 300 source_frame->visible_data(VideoFrame::kVPlane) + |
308 first_row / 2 * source_frame->stride(VideoFrame::kVPlane), | 301 first_row / 2 * source_frame->stride(VideoFrame::kVPlane), |
309 source_frame->stride(VideoFrame::kVPlane), | 302 source_frame->stride(VideoFrame::kVPlane), |
310 output + first_row * dest_stride, dest_stride, width, rows); | 303 output + first_row * dest_stride, dest_stride, width, rows); |
311 } | 304 } |
312 done.Run(); | 305 done.Run(); |
313 } | 306 } |
314 | 307 |
308 void CopyRowsToGPUBuffer(int first_row, | |
309 int rows, | |
310 int width, | |
311 const scoped_refptr<VideoFrame>& source_frame, | |
312 uint8_t* output, | |
313 int dest_stride, | |
314 const base::Closure& done) { | |
315 int row_bytes = VideoFrame::RowBytes(0, source_frame->format(), width); | |
316 TRACE_EVENT2("media", "CopyRowsToGPUBuffer", "bytes_per_row", row_bytes, | |
317 "rows", rows); | |
318 if (output) { | |
319 DCHECK_NE(dest_stride, 0); | |
320 DCHECK_LE(row_bytes, std::abs(dest_stride)); | |
321 const int source_stride = source_frame->stride(0); | |
322 const uint8_t* source = | |
323 source_frame->visible_data(0) + first_row * source_stride; | |
324 uint8_t* dest = output + first_row * dest_stride; | |
325 for (int i = 0; i < rows; ++i) | |
326 memcpy(dest + i * dest_stride, source + i * source_stride, row_bytes); | |
327 } | |
328 done.Run(); | |
329 } | |
330 | |
315 gfx::Size CodedSize(const scoped_refptr<VideoFrame>& video_frame, | 331 gfx::Size CodedSize(const scoped_refptr<VideoFrame>& video_frame, |
316 VideoPixelFormat output_format) { | 332 VideoPixelFormat output_format) { |
317 DCHECK(gfx::Rect(video_frame->coded_size()) | 333 DCHECK(gfx::Rect(video_frame->coded_size()) |
318 .Contains(video_frame->visible_rect())); | 334 .Contains(video_frame->visible_rect())); |
319 DCHECK((video_frame->visible_rect().x() & 1) == 0); | 335 DCHECK((video_frame->visible_rect().x() & 1) == 0); |
320 gfx::Size output; | 336 gfx::Size output; |
321 switch (output_format) { | 337 switch (output_format) { |
322 case PIXEL_FORMAT_I420: | 338 case PIXEL_FORMAT_I420: |
323 case PIXEL_FORMAT_NV12: | 339 case PIXEL_FORMAT_NV12: |
324 DCHECK((video_frame->visible_rect().y() & 1) == 0); | 340 DCHECK((video_frame->visible_rect().y() & 1) == 0); |
325 output = gfx::Size((video_frame->visible_rect().width() + 1) & ~1, | 341 output = gfx::Size((video_frame->visible_rect().width() + 1) & ~1, |
326 (video_frame->visible_rect().height() + 1) & ~1); | 342 (video_frame->visible_rect().height() + 1) & ~1); |
327 break; | 343 break; |
328 case PIXEL_FORMAT_UYVY: | 344 case PIXEL_FORMAT_UYVY: |
329 output = gfx::Size((video_frame->visible_rect().width() + 1) & ~1, | 345 output = gfx::Size((video_frame->visible_rect().width() + 1) & ~1, |
330 video_frame->visible_rect().height()); | 346 video_frame->visible_rect().height()); |
331 break; | 347 break; |
348 case PIXEL_FORMAT_Y16: | |
349 output = video_frame->visible_rect().size(); | |
350 break; | |
332 default: | 351 default: |
333 NOTREACHED(); | 352 NOTREACHED(); |
334 } | 353 } |
335 DCHECK(gfx::Rect(video_frame->coded_size()).Contains(gfx::Rect(output))); | 354 DCHECK(gfx::Rect(video_frame->coded_size()).Contains(gfx::Rect(output))); |
336 return output; | 355 return output; |
337 } | 356 } |
338 } // unnamed namespace | 357 } // unnamed namespace |
339 | 358 |
340 // Creates a VideoFrame backed by native textures starting from a software | 359 // Creates a VideoFrame backed by native textures starting from a software |
341 // VideoFrame. | 360 // VideoFrame. |
342 // The data contained in |video_frame| is copied into the VideoFrame passed to | 361 // The data contained in |video_frame| is copied into the VideoFrame passed to |
343 // |frame_ready_cb|. | 362 // |frame_ready_cb|. |
344 // This has to be called on the thread where |media_task_runner_| is current. | 363 // This has to be called on the thread where |media_task_runner_| is current. |
345 void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame( | 364 void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame( |
346 const scoped_refptr<VideoFrame>& video_frame, | 365 const scoped_refptr<VideoFrame>& video_frame, |
347 const FrameReadyCB& frame_ready_cb) { | 366 const FrameReadyCB& frame_ready_cb) { |
348 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 367 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
349 // Lazily initialize output_format_ since VideoFrameOutputFormat() has to be | 368 media::VideoPixelFormat output_format = PIXEL_FORMAT_UNKNOWN; |
350 // called on the media_thread while this object might be instantiated on any. | |
351 if (output_format_ == PIXEL_FORMAT_UNKNOWN) | |
352 output_format_ = gpu_factories_->VideoFrameOutputFormat(); | |
353 | |
354 if (output_format_ == PIXEL_FORMAT_UNKNOWN) { | |
355 frame_ready_cb.Run(video_frame); | |
356 return; | |
357 } | |
358 switch (video_frame->format()) { | 369 switch (video_frame->format()) { |
359 // Supported cases. | 370 // Supported cases. |
360 case PIXEL_FORMAT_YV12: | 371 case PIXEL_FORMAT_YV12: |
361 case PIXEL_FORMAT_I420: | 372 case PIXEL_FORMAT_I420: { |
373 // Lazily initialize output_format_ since VideoFrameOutputFormat() has to | |
374 // be called on the media_thread while this object might be instantiated | |
375 // on any. | |
376 if (output_format_ == PIXEL_FORMAT_UNKNOWN) { | |
377 output_format_ = | |
378 gpu_factories_->VideoFrameOutputFormat(PIXEL_FORMAT_I420); | |
379 } | |
380 output_format = output_format_; | |
381 break; | |
382 } | |
383 case PIXEL_FORMAT_Y16: | |
384 // Lazily initialize texture_rg_available_. | |
385 if (!texture_rg_available_initialized_) { | |
386 texture_rg_available_initialized_ = true; | |
387 texture_rg_available_ = gpu_factories_->VideoFrameOutputFormat( | |
388 PIXEL_FORMAT_Y16) == PIXEL_FORMAT_Y16; | |
389 } | |
390 output_format = | |
391 texture_rg_available_ ? video_frame->format() : PIXEL_FORMAT_UNKNOWN; | |
362 break; | 392 break; |
363 // Unsupported cases. | 393 // Unsupported cases. |
364 case PIXEL_FORMAT_YV12A: | 394 case PIXEL_FORMAT_YV12A: |
365 case PIXEL_FORMAT_YV16: | 395 case PIXEL_FORMAT_YV16: |
366 case PIXEL_FORMAT_YV24: | 396 case PIXEL_FORMAT_YV24: |
367 case PIXEL_FORMAT_NV12: | 397 case PIXEL_FORMAT_NV12: |
368 case PIXEL_FORMAT_NV21: | 398 case PIXEL_FORMAT_NV21: |
369 case PIXEL_FORMAT_UYVY: | 399 case PIXEL_FORMAT_UYVY: |
370 case PIXEL_FORMAT_YUY2: | 400 case PIXEL_FORMAT_YUY2: |
371 case PIXEL_FORMAT_ARGB: | 401 case PIXEL_FORMAT_ARGB: |
372 case PIXEL_FORMAT_XRGB: | 402 case PIXEL_FORMAT_XRGB: |
373 case PIXEL_FORMAT_RGB24: | 403 case PIXEL_FORMAT_RGB24: |
374 case PIXEL_FORMAT_RGB32: | 404 case PIXEL_FORMAT_RGB32: |
375 case PIXEL_FORMAT_MJPEG: | 405 case PIXEL_FORMAT_MJPEG: |
376 case PIXEL_FORMAT_MT21: | 406 case PIXEL_FORMAT_MT21: |
377 case PIXEL_FORMAT_YUV420P9: | 407 case PIXEL_FORMAT_YUV420P9: |
378 case PIXEL_FORMAT_YUV422P9: | 408 case PIXEL_FORMAT_YUV422P9: |
379 case PIXEL_FORMAT_YUV444P9: | 409 case PIXEL_FORMAT_YUV444P9: |
380 case PIXEL_FORMAT_YUV420P10: | 410 case PIXEL_FORMAT_YUV420P10: |
381 case PIXEL_FORMAT_YUV422P10: | 411 case PIXEL_FORMAT_YUV422P10: |
382 case PIXEL_FORMAT_YUV444P10: | 412 case PIXEL_FORMAT_YUV444P10: |
383 case PIXEL_FORMAT_YUV420P12: | 413 case PIXEL_FORMAT_YUV420P12: |
384 case PIXEL_FORMAT_YUV422P12: | 414 case PIXEL_FORMAT_YUV422P12: |
385 case PIXEL_FORMAT_YUV444P12: | 415 case PIXEL_FORMAT_YUV444P12: |
386 case PIXEL_FORMAT_Y8: | 416 case PIXEL_FORMAT_Y8: |
387 case PIXEL_FORMAT_Y16: | |
388 case PIXEL_FORMAT_UNKNOWN: | 417 case PIXEL_FORMAT_UNKNOWN: |
389 frame_ready_cb.Run(video_frame); | 418 break; |
390 return; | 419 } |
420 if (output_format == PIXEL_FORMAT_UNKNOWN) { | |
421 frame_ready_cb.Run(video_frame); | |
422 return; | |
391 } | 423 } |
392 | 424 |
393 const gfx::Size coded_size = CodedSize(video_frame, output_format_); | 425 const gfx::Size coded_size = CodedSize(video_frame, output_format); |
394 // Acquire resources. Incompatible ones will be dropped from the pool. | 426 // Acquire resources. Incompatible ones will be dropped from the pool. |
395 FrameResources* frame_resources = | 427 FrameResources* frame_resources = |
396 GetOrCreateFrameResources(coded_size, output_format_); | 428 GetOrCreateFrameResources(coded_size, output_format); |
397 if (!frame_resources) { | 429 if (!frame_resources) { |
398 frame_ready_cb.Run(video_frame); | 430 frame_ready_cb.Run(video_frame); |
399 return; | 431 return; |
400 } | 432 } |
401 | 433 |
402 worker_task_runner_->PostTask( | 434 worker_task_runner_->PostTask( |
403 FROM_HERE, base::Bind(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers, this, | 435 FROM_HERE, base::Bind(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers, this, |
404 video_frame, frame_resources, frame_ready_cb)); | 436 video_frame, frame_resources, frame_ready_cb)); |
405 } | 437 } |
406 | 438 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
459 } | 491 } |
460 | 492 |
461 // Copies |video_frame| into |frame_resources| asynchronously, posting n tasks | 493 // Copies |video_frame| into |frame_resources| asynchronously, posting n tasks |
462 // that will be synchronized by a barrier. | 494 // that will be synchronized by a barrier. |
463 // After the barrier is passed OnCopiesDone will be called. | 495 // After the barrier is passed OnCopiesDone will be called. |
464 void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( | 496 void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( |
465 const scoped_refptr<VideoFrame>& video_frame, | 497 const scoped_refptr<VideoFrame>& video_frame, |
466 FrameResources* frame_resources, | 498 FrameResources* frame_resources, |
467 const FrameReadyCB& frame_ready_cb) { | 499 const FrameReadyCB& frame_ready_cb) { |
468 // Compute the number of tasks to post and create the barrier. | 500 // Compute the number of tasks to post and create the barrier. |
469 const size_t num_planes = VideoFrame::NumPlanes(output_format_); | 501 const size_t num_planes = VideoFrame::NumPlanes(frame_resources->format); |
470 const size_t planes_per_copy = PlanesPerCopy(output_format_); | 502 const size_t planes_per_copy = PlanesPerCopy(frame_resources->format); |
471 const gfx::Size coded_size = CodedSize(video_frame, output_format_); | 503 const gfx::Size coded_size = CodedSize(video_frame, frame_resources->format); |
472 size_t copies = 0; | 504 size_t copies = 0; |
473 for (size_t i = 0; i < num_planes; i += planes_per_copy) { | 505 for (size_t i = 0; i < num_planes; i += planes_per_copy) { |
474 const int rows = VideoFrame::Rows(i, output_format_, coded_size.height()); | 506 const int rows = |
507 VideoFrame::Rows(i, frame_resources->format, coded_size.height()); | |
475 const int rows_per_copy = | 508 const int rows_per_copy = |
476 RowsPerCopy(i, output_format_, coded_size.width()); | 509 RowsPerCopy(i, frame_resources->format, coded_size.width()); |
477 copies += rows / rows_per_copy; | 510 copies += rows / rows_per_copy; |
478 if (rows % rows_per_copy) | 511 if (rows % rows_per_copy) |
479 ++copies; | 512 ++copies; |
480 } | 513 } |
481 const base::Closure copies_done = | 514 const base::Closure copies_done = |
482 base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources, | 515 base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources, |
483 frame_ready_cb); | 516 frame_ready_cb); |
484 const base::Closure barrier = base::BarrierClosure(copies, copies_done); | 517 const base::Closure barrier = base::BarrierClosure(copies, copies_done); |
485 | 518 |
486 // Post all the async tasks. | 519 // Post all the async tasks. |
487 for (size_t i = 0; i < num_planes; i += planes_per_copy) { | 520 for (size_t i = 0; i < num_planes; i += planes_per_copy) { |
488 gfx::GpuMemoryBuffer* buffer = | 521 gfx::GpuMemoryBuffer* buffer = |
489 frame_resources->plane_resources[i].gpu_memory_buffer.get(); | 522 frame_resources->plane_resources[i].gpu_memory_buffer.get(); |
490 | 523 |
491 if (!buffer || !buffer->Map()) { | 524 if (!buffer || !buffer->Map()) { |
492 DLOG(ERROR) << "Could not get or Map() buffer"; | 525 DLOG(ERROR) << "Could not get or Map() buffer"; |
493 return; | 526 return; |
494 } | 527 } |
495 DCHECK_EQ(planes_per_copy, | 528 DCHECK_EQ(planes_per_copy, |
496 gfx::NumberOfPlanesForBufferFormat(buffer->GetFormat())); | 529 gfx::NumberOfPlanesForBufferFormat(buffer->GetFormat())); |
497 | 530 |
498 const int rows = VideoFrame::Rows(i, output_format_, coded_size.height()); | 531 const int rows = |
532 VideoFrame::Rows(i, frame_resources->format, coded_size.height()); | |
499 const int rows_per_copy = | 533 const int rows_per_copy = |
500 RowsPerCopy(i, output_format_, coded_size.width()); | 534 RowsPerCopy(i, frame_resources->format, coded_size.width()); |
501 | 535 |
502 for (int row = 0; row < rows; row += rows_per_copy) { | 536 for (int row = 0; row < rows; row += rows_per_copy) { |
503 const int rows_to_copy = std::min(rows_per_copy, rows - row); | 537 const int rows_to_copy = std::min(rows_per_copy, rows - row); |
504 switch (output_format_) { | 538 switch (frame_resources->format) { |
505 case PIXEL_FORMAT_I420: { | 539 case PIXEL_FORMAT_I420: { |
506 const int bytes_per_row = | 540 const int bytes_per_row = VideoFrame::RowBytes( |
507 VideoFrame::RowBytes(i, output_format_, coded_size.width()); | 541 i, frame_resources->format, coded_size.width()); |
508 worker_task_runner_->PostTask( | 542 worker_task_runner_->PostTask( |
509 FROM_HERE, base::Bind(&CopyRowsToI420Buffer, row, rows_to_copy, | 543 FROM_HERE, base::Bind(&CopyRowsToI420Buffer, row, rows_to_copy, |
510 bytes_per_row, video_frame->visible_data(i), | 544 bytes_per_row, video_frame->visible_data(i), |
511 video_frame->stride(i), | 545 video_frame->stride(i), |
512 static_cast<uint8_t*>(buffer->memory(0)), | 546 static_cast<uint8_t*>(buffer->memory(0)), |
513 buffer->stride(0), barrier)); | 547 buffer->stride(0), barrier)); |
514 break; | 548 break; |
515 } | 549 } |
516 case PIXEL_FORMAT_NV12: | 550 case PIXEL_FORMAT_NV12: |
517 worker_task_runner_->PostTask( | 551 worker_task_runner_->PostTask( |
518 FROM_HERE, base::Bind(&CopyRowsToNV12Buffer, row, rows_to_copy, | 552 FROM_HERE, base::Bind(&CopyRowsToNV12Buffer, row, rows_to_copy, |
519 coded_size.width(), video_frame, | 553 coded_size.width(), video_frame, |
520 static_cast<uint8_t*>(buffer->memory(0)), | 554 static_cast<uint8_t*>(buffer->memory(0)), |
521 buffer->stride(0), | 555 buffer->stride(0), |
522 static_cast<uint8_t*>(buffer->memory(1)), | 556 static_cast<uint8_t*>(buffer->memory(1)), |
523 buffer->stride(1), barrier)); | 557 buffer->stride(1), barrier)); |
524 break; | 558 break; |
525 case PIXEL_FORMAT_UYVY: | 559 case PIXEL_FORMAT_UYVY: |
526 worker_task_runner_->PostTask( | 560 worker_task_runner_->PostTask( |
527 FROM_HERE, base::Bind(&CopyRowsToUYVYBuffer, row, rows_to_copy, | 561 FROM_HERE, base::Bind(&CopyRowsToUYVYBuffer, row, rows_to_copy, |
528 coded_size.width(), video_frame, | 562 coded_size.width(), video_frame, |
529 static_cast<uint8_t*>(buffer->memory(0)), | 563 static_cast<uint8_t*>(buffer->memory(0)), |
530 buffer->stride(0), barrier)); | 564 buffer->stride(0), barrier)); |
531 break; | 565 break; |
566 case PIXEL_FORMAT_Y16: | |
567 worker_task_runner_->PostTask( | |
568 FROM_HERE, base::Bind(&CopyRowsToGPUBuffer, row, rows_to_copy, | |
569 coded_size.width(), video_frame, | |
570 static_cast<uint8_t*>(buffer->memory(0)), | |
571 buffer->stride(0), barrier)); | |
572 break; | |
532 default: | 573 default: |
533 NOTREACHED(); | 574 NOTREACHED(); |
534 } | 575 } |
535 } | 576 } |
536 } | 577 } |
537 } | 578 } |
538 | 579 |
539 void GpuMemoryBufferVideoFramePool::PoolImpl:: | 580 void GpuMemoryBufferVideoFramePool::PoolImpl:: |
540 BindAndCreateMailboxesHardwareFrameResources( | 581 BindAndCreateMailboxesHardwareFrameResources( |
541 const scoped_refptr<VideoFrame>& video_frame, | 582 const scoped_refptr<VideoFrame>& video_frame, |
542 FrameResources* frame_resources, | 583 FrameResources* frame_resources, |
543 const FrameReadyCB& frame_ready_cb) { | 584 const FrameReadyCB& frame_ready_cb) { |
544 std::unique_ptr<GpuVideoAcceleratorFactories::ScopedGLContextLock> lock( | 585 std::unique_ptr<GpuVideoAcceleratorFactories::ScopedGLContextLock> lock( |
545 gpu_factories_->GetGLContextLock()); | 586 gpu_factories_->GetGLContextLock()); |
546 if (!lock) { | 587 if (!lock) { |
547 frame_ready_cb.Run(video_frame); | 588 frame_ready_cb.Run(video_frame); |
548 return; | 589 return; |
549 } | 590 } |
550 gpu::gles2::GLES2Interface* gles2 = lock->ContextGL(); | 591 gpu::gles2::GLES2Interface* gles2 = lock->ContextGL(); |
551 | 592 |
552 const size_t num_planes = VideoFrame::NumPlanes(output_format_); | 593 const size_t num_planes = VideoFrame::NumPlanes(frame_resources->format); |
553 const size_t planes_per_copy = PlanesPerCopy(output_format_); | 594 const size_t planes_per_copy = PlanesPerCopy(frame_resources->format); |
554 const gfx::Size coded_size = CodedSize(video_frame, output_format_); | 595 const gfx::Size coded_size = CodedSize(video_frame, frame_resources->format); |
555 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; | 596 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; |
556 // Set up the planes creating the mailboxes needed to refer to the textures. | 597 // Set up the planes creating the mailboxes needed to refer to the textures. |
557 for (size_t i = 0; i < num_planes; i += planes_per_copy) { | 598 for (size_t i = 0; i < num_planes; i += planes_per_copy) { |
558 PlaneResource& plane_resource = frame_resources->plane_resources[i]; | 599 PlaneResource& plane_resource = frame_resources->plane_resources[i]; |
559 const gfx::BufferFormat buffer_format = | 600 const gfx::BufferFormat buffer_format = |
560 GpuMemoryBufferFormat(output_format_, i); | 601 VideoFrame::BufferFormat(frame_resources->format); |
561 unsigned texture_target = gpu_factories_->ImageTextureTarget(buffer_format); | 602 unsigned texture_target = gpu_factories_->ImageTextureTarget(buffer_format); |
562 // Bind the texture and create or rebind the image. | 603 // Bind the texture and create or rebind the image. |
563 gles2->BindTexture(texture_target, plane_resource.texture_id); | 604 gles2->BindTexture(texture_target, plane_resource.texture_id); |
564 | 605 |
565 if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) { | 606 if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) { |
566 const size_t width = | 607 const size_t width = |
567 VideoFrame::Columns(i, output_format_, coded_size.width()); | 608 VideoFrame::Columns(i, frame_resources->format, coded_size.width()); |
568 const size_t height = | 609 const size_t height = |
569 VideoFrame::Rows(i, output_format_, coded_size.height()); | 610 VideoFrame::Rows(i, frame_resources->format, coded_size.height()); |
570 plane_resource.image_id = gles2->CreateImageCHROMIUM( | 611 plane_resource.image_id = gles2->CreateImageCHROMIUM( |
571 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height, | 612 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height, |
572 ImageInternalFormat(output_format_, i)); | 613 ImageInternalFormat(frame_resources->format, i)); |
573 } else if (plane_resource.image_id) { | 614 } else if (plane_resource.image_id) { |
574 gles2->ReleaseTexImage2DCHROMIUM(texture_target, plane_resource.image_id); | 615 gles2->ReleaseTexImage2DCHROMIUM(texture_target, plane_resource.image_id); |
575 } | 616 } |
576 if (plane_resource.image_id) | 617 if (plane_resource.image_id) |
577 gles2->BindTexImage2DCHROMIUM(texture_target, plane_resource.image_id); | 618 gles2->BindTexImage2DCHROMIUM(texture_target, plane_resource.image_id); |
578 mailbox_holders[i] = gpu::MailboxHolder(plane_resource.mailbox, | 619 mailbox_holders[i] = gpu::MailboxHolder(plane_resource.mailbox, |
579 gpu::SyncToken(), texture_target); | 620 gpu::SyncToken(), texture_target); |
580 } | 621 } |
581 | 622 |
582 // Insert a sync_token, this is needed to make sure that the textures the | 623 // Insert a sync_token, this is needed to make sure that the textures the |
583 // mailboxes refer to will be used only after all the previous commands posted | 624 // mailboxes refer to will be used only after all the previous commands posted |
584 // in the command buffer have been processed. | 625 // in the command buffer have been processed. |
585 const GLuint64 fence_sync = gles2->InsertFenceSyncCHROMIUM(); | 626 const GLuint64 fence_sync = gles2->InsertFenceSyncCHROMIUM(); |
586 gles2->OrderingBarrierCHROMIUM(); | 627 gles2->OrderingBarrierCHROMIUM(); |
587 | 628 |
588 gpu::SyncToken sync_token; | 629 gpu::SyncToken sync_token; |
589 gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); | 630 gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); |
590 for (size_t i = 0; i < num_planes; i += planes_per_copy) | 631 for (size_t i = 0; i < num_planes; i += planes_per_copy) |
591 mailbox_holders[i].sync_token = sync_token; | 632 mailbox_holders[i].sync_token = sync_token; |
592 | 633 |
593 | 634 |
594 auto release_mailbox_callback = BindToCurrentLoop( | 635 auto release_mailbox_callback = BindToCurrentLoop( |
595 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources)); | 636 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources)); |
596 | 637 |
597 // Consumers should sample from NV12 textures as if they're XRGB. | 638 // Consumers should sample from NV12 textures as if they're XRGB. |
598 VideoPixelFormat frame_format = | 639 VideoPixelFormat frame_format = (frame_resources->format == PIXEL_FORMAT_NV12) |
599 output_format_ == PIXEL_FORMAT_NV12 ? PIXEL_FORMAT_XRGB : output_format_; | 640 ? PIXEL_FORMAT_XRGB |
641 : frame_resources->format; | |
600 DCHECK_EQ(VideoFrame::NumPlanes(frame_format) * planes_per_copy, num_planes); | 642 DCHECK_EQ(VideoFrame::NumPlanes(frame_format) * planes_per_copy, num_planes); |
601 | 643 |
602 // Create the VideoFrame backed by native textures. | 644 // Create the VideoFrame backed by native textures. |
603 gfx::Size visible_size = video_frame->visible_rect().size(); | 645 gfx::Size visible_size = video_frame->visible_rect().size(); |
604 scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTextures( | 646 scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTextures( |
605 frame_format, mailbox_holders, release_mailbox_callback, coded_size, | 647 frame_format, mailbox_holders, release_mailbox_callback, coded_size, |
606 gfx::Rect(visible_size), video_frame->natural_size(), | 648 gfx::Rect(visible_size), video_frame->natural_size(), |
607 video_frame->timestamp()); | 649 video_frame->timestamp()); |
608 | 650 |
609 if (!frame) { | 651 if (!frame) { |
610 release_mailbox_callback.Run(gpu::SyncToken()); | 652 release_mailbox_callback.Run(gpu::SyncToken()); |
611 frame_ready_cb.Run(video_frame); | 653 frame_ready_cb.Run(video_frame); |
612 return; | 654 return; |
613 } | 655 } |
614 | 656 |
615 frame->set_color_space(video_frame->ColorSpace()); | 657 frame->set_color_space(video_frame->ColorSpace()); |
616 | 658 |
617 bool allow_overlay = false; | 659 bool allow_overlay = false; |
618 switch (output_format_) { | 660 switch (frame_resources->format) { |
619 case PIXEL_FORMAT_I420: | 661 case PIXEL_FORMAT_I420: |
620 allow_overlay = | 662 allow_overlay = |
621 video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY); | 663 video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY); |
622 break; | 664 break; |
623 case PIXEL_FORMAT_NV12: | 665 case PIXEL_FORMAT_NV12: |
624 case PIXEL_FORMAT_UYVY: | 666 case PIXEL_FORMAT_UYVY: |
667 case PIXEL_FORMAT_Y16: | |
625 allow_overlay = true; | 668 allow_overlay = true; |
626 break; | 669 break; |
627 default: | 670 default: |
628 break; | 671 break; |
629 } | 672 } |
630 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, | 673 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, |
631 allow_overlay); | 674 allow_overlay); |
632 | 675 |
633 base::TimeTicks render_time; | 676 base::TimeTicks render_time; |
634 if (video_frame->metadata()->GetTimeTicks(VideoFrameMetadata::REFERENCE_TIME, | 677 if (video_frame->metadata()->GetTimeTicks(VideoFrameMetadata::REFERENCE_TIME, |
(...skipping 24 matching lines...) Expand all Loading... | |
659 // Tries to find the resources in the pool or create them. | 702 // Tries to find the resources in the pool or create them. |
660 // Incompatible resources will be dropped. | 703 // Incompatible resources will be dropped. |
661 GpuMemoryBufferVideoFramePool::PoolImpl::FrameResources* | 704 GpuMemoryBufferVideoFramePool::PoolImpl::FrameResources* |
662 GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources( | 705 GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources( |
663 const gfx::Size& size, | 706 const gfx::Size& size, |
664 VideoPixelFormat format) { | 707 VideoPixelFormat format) { |
665 auto it = resources_pool_.begin(); | 708 auto it = resources_pool_.begin(); |
666 while (it != resources_pool_.end()) { | 709 while (it != resources_pool_.end()) { |
667 FrameResources* frame_resources = *it; | 710 FrameResources* frame_resources = *it; |
668 if (!frame_resources->IsInUse()) { | 711 if (!frame_resources->IsInUse()) { |
669 if (AreFrameResourcesCompatible(frame_resources, size)) { | 712 if (AreFrameResourcesCompatible(frame_resources, size, format)) { |
670 frame_resources->SetIsInUse(true); | 713 frame_resources->SetIsInUse(true); |
671 return frame_resources; | 714 return frame_resources; |
672 } else { | 715 } else { |
673 resources_pool_.erase(it++); | 716 resources_pool_.erase(it++); |
674 DeleteFrameResources(gpu_factories_, frame_resources); | 717 DeleteFrameResources(gpu_factories_, frame_resources); |
675 delete frame_resources; | 718 delete frame_resources; |
676 } | 719 } |
677 } else { | 720 } else { |
678 it++; | 721 it++; |
679 } | 722 } |
680 } | 723 } |
681 | 724 |
682 // Create the resources. | 725 // Create the resources. |
683 std::unique_ptr<GpuVideoAcceleratorFactories::ScopedGLContextLock> lock( | 726 std::unique_ptr<GpuVideoAcceleratorFactories::ScopedGLContextLock> lock( |
684 gpu_factories_->GetGLContextLock()); | 727 gpu_factories_->GetGLContextLock()); |
685 if (!lock) | 728 if (!lock) |
686 return nullptr; | 729 return nullptr; |
687 | 730 |
688 gpu::gles2::GLES2Interface* gles2 = lock->ContextGL(); | 731 gpu::gles2::GLES2Interface* gles2 = lock->ContextGL(); |
689 gles2->ActiveTexture(GL_TEXTURE0); | 732 gles2->ActiveTexture(GL_TEXTURE0); |
690 size_t num_planes = VideoFrame::NumPlanes(format); | 733 size_t num_planes = VideoFrame::NumPlanes(format); |
691 FrameResources* frame_resources = new FrameResources(size); | 734 FrameResources* frame_resources = new FrameResources(size, format); |
692 resources_pool_.push_back(frame_resources); | 735 resources_pool_.push_back(frame_resources); |
693 for (size_t i = 0; i < num_planes; i += PlanesPerCopy(format)) { | 736 for (size_t i = 0; i < num_planes; i += PlanesPerCopy(format)) { |
694 PlaneResource& plane_resource = frame_resources->plane_resources[i]; | 737 PlaneResource& plane_resource = frame_resources->plane_resources[i]; |
695 const size_t width = VideoFrame::Columns(i, format, size.width()); | 738 const size_t width = VideoFrame::Columns(i, format, size.width()); |
696 const size_t height = VideoFrame::Rows(i, format, size.height()); | 739 const size_t height = VideoFrame::Rows(i, format, size.height()); |
697 plane_resource.size = gfx::Size(width, height); | 740 plane_resource.size = gfx::Size(width, height); |
698 | 741 |
699 const gfx::BufferFormat buffer_format = GpuMemoryBufferFormat(format, i); | 742 const gfx::BufferFormat buffer_format = VideoFrame::BufferFormat(format); |
700 plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer( | 743 plane_resource.gpu_memory_buffer = gpu_factories_->AllocateGpuMemoryBuffer( |
701 plane_resource.size, buffer_format, | 744 plane_resource.size, buffer_format, |
702 gfx::BufferUsage::GPU_READ_CPU_READ_WRITE); | 745 gfx::BufferUsage::GPU_READ_CPU_READ_WRITE); |
703 | 746 |
704 unsigned texture_target = gpu_factories_->ImageTextureTarget(buffer_format); | 747 unsigned texture_target = gpu_factories_->ImageTextureTarget(buffer_format); |
705 gles2->GenTextures(1, &plane_resource.texture_id); | 748 gles2->GenTextures(1, &plane_resource.texture_id); |
706 gles2->BindTexture(texture_target, plane_resource.texture_id); | 749 gles2->BindTexture(texture_target, plane_resource.texture_id); |
707 gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 750 if (format == PIXEL_FORMAT_Y16) { |
708 gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 751 gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
752 gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
753 } else { | |
754 gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
755 gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
756 } | |
709 gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 757 gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
710 gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 758 gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
711 gles2->GenMailboxCHROMIUM(plane_resource.mailbox.name); | 759 gles2->GenMailboxCHROMIUM(plane_resource.mailbox.name); |
712 gles2->ProduceTextureCHROMIUM(texture_target, plane_resource.mailbox.name); | 760 gles2->ProduceTextureCHROMIUM(texture_target, plane_resource.mailbox.name); |
713 } | 761 } |
714 return frame_resources; | 762 return frame_resources; |
715 } | 763 } |
716 | 764 |
717 // static | 765 // static |
718 void GpuMemoryBufferVideoFramePool::PoolImpl::DeleteFrameResources( | 766 void GpuMemoryBufferVideoFramePool::PoolImpl::DeleteFrameResources( |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
770 } | 818 } |
771 | 819 |
772 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame( | 820 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame( |
773 const scoped_refptr<VideoFrame>& video_frame, | 821 const scoped_refptr<VideoFrame>& video_frame, |
774 const FrameReadyCB& frame_ready_cb) { | 822 const FrameReadyCB& frame_ready_cb) { |
775 DCHECK(video_frame); | 823 DCHECK(video_frame); |
776 pool_impl_->CreateHardwareFrame(video_frame, frame_ready_cb); | 824 pool_impl_->CreateHardwareFrame(video_frame, frame_ready_cb); |
777 } | 825 } |
778 | 826 |
779 } // namespace media | 827 } // namespace media |
OLD | NEW |