Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/video/gpu_memory_buffer_video_frame_pool.h" | 5 #include "media/video/gpu_memory_buffer_video_frame_pool.h" |
| 6 | 6 |
| 7 #include <GLES2/gl2.h> | 7 #include <GLES2/gl2.h> |
| 8 #include <GLES2/gl2ext.h> | 8 #include <GLES2/gl2ext.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 97 // 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 |
| 98 // be run. | 98 // be run. |
| 99 void BindAndCreateMailboxesHardwareFrameResources( | 99 void BindAndCreateMailboxesHardwareFrameResources( |
| 100 const scoped_refptr<VideoFrame>& video_frame, | 100 const scoped_refptr<VideoFrame>& video_frame, |
| 101 FrameResources* frame_resources, | 101 FrameResources* frame_resources, |
| 102 const FrameReadyCB& frame_ready_cb); | 102 const FrameReadyCB& frame_ready_cb); |
| 103 | 103 |
| 104 // 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 |
| 105 // specific |format| and |size|. | 105 // specific |format| and |size|. |
| 106 static bool AreFrameResourcesCompatible(const FrameResources* resources, | 106 static bool AreFrameResourcesCompatible(const FrameResources* resources, |
| 107 const gfx::Size& size) { | 107 const gfx::Size& size); |
| 108 return size == resources->size; | |
| 109 } | |
| 110 | 108 |
| 111 // Get the resources needed for a frame out of the pool, or create them if | 109 // Get the resources needed for a frame out of the pool, or create them if |
| 112 // necessary. | 110 // necessary. |
| 113 // This also drops the LRU resources that can't be reuse for this frame. | 111 // This also drops the LRU resources that can't be reuse for this frame. |
| 114 FrameResources* GetOrCreateFrameResources(const gfx::Size& size, | 112 FrameResources* GetOrCreateFrameResources(const gfx::Size& size, |
| 115 VideoPixelFormat format); | 113 VideoPixelFormat format); |
| 116 | 114 |
| 117 // Callback called when a VideoFrame generated with GetFrameResources is no | 115 // Callback called when a VideoFrame generated with GetFrameResources is no |
| 118 // longer referenced. | 116 // longer referenced. |
| 119 // This could be called by any thread. | 117 // This could be called by any thread. |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 219 void CopyRowsToI420Buffer(int first_row, | 217 void CopyRowsToI420Buffer(int first_row, |
| 220 int rows, | 218 int rows, |
| 221 int bytes_per_row, | 219 int bytes_per_row, |
| 222 const uint8* source, | 220 const uint8* source, |
| 223 int source_stride, | 221 int source_stride, |
| 224 uint8* output, | 222 uint8* output, |
| 225 int dest_stride, | 223 int dest_stride, |
| 226 const base::Closure& done) { | 224 const base::Closure& done) { |
| 227 TRACE_EVENT2("media", "CopyRowsToI420Buffer", "bytes_per_row", bytes_per_row, | 225 TRACE_EVENT2("media", "CopyRowsToI420Buffer", "bytes_per_row", bytes_per_row, |
| 228 "rows", rows); | 226 "rows", rows); |
| 229 DCHECK_NE(dest_stride, 0); | 227 if (output) { |
| 230 DCHECK_LE(bytes_per_row, std::abs(dest_stride)); | 228 DCHECK_NE(dest_stride, 0); |
| 231 DCHECK_LE(bytes_per_row, source_stride); | 229 DCHECK_LE(bytes_per_row, std::abs(dest_stride)); |
| 232 for (int row = first_row; row < first_row + rows; ++row) { | 230 DCHECK_LE(bytes_per_row, source_stride); |
| 233 memcpy(output + dest_stride * row, source + source_stride * row, | 231 for (int row = first_row; row < first_row + rows; ++row) { |
| 234 bytes_per_row); | 232 memcpy(output + dest_stride * row, source + source_stride * row, |
| 233 bytes_per_row); | |
| 234 } | |
| 235 } | 235 } |
| 236 done.Run(); | 236 done.Run(); |
| 237 } | 237 } |
| 238 | 238 |
| 239 void CopyRowsToNV12Buffer(int first_row, | 239 void CopyRowsToNV12Buffer(int first_row, |
| 240 int rows, | 240 int rows, |
| 241 int bytes_per_row, | 241 int bytes_per_row, |
| 242 const scoped_refptr<VideoFrame>& source_frame, | 242 const scoped_refptr<VideoFrame>& source_frame, |
| 243 uint8* dest_y, | 243 uint8* dest_y, |
| 244 int dest_stride_y, | 244 int dest_stride_y, |
| 245 uint8* dest_uv, | 245 uint8* dest_uv, |
| 246 int dest_stride_uv, | 246 int dest_stride_uv, |
| 247 const base::Closure& done) { | 247 const base::Closure& done) { |
| 248 TRACE_EVENT2("media", "CopyRowsToNV12Buffer", "bytes_per_row", bytes_per_row, | 248 TRACE_EVENT2("media", "CopyRowsToNV12Buffer", "bytes_per_row", bytes_per_row, |
| 249 "rows", rows); | 249 "rows", rows); |
| 250 DCHECK_NE(dest_stride_y, 0); | 250 if (dest_y && dest_uv) { |
| 251 DCHECK_NE(dest_stride_uv, 0); | 251 DCHECK_NE(dest_stride_y, 0); |
| 252 DCHECK_LE(bytes_per_row, std::abs(dest_stride_y)); | 252 DCHECK_NE(dest_stride_uv, 0); |
| 253 DCHECK_LE(bytes_per_row, std::abs(dest_stride_uv)); | 253 DCHECK_LE(bytes_per_row, std::abs(dest_stride_y)); |
| 254 DCHECK_EQ(0, first_row % 2); | 254 DCHECK_LE(bytes_per_row, std::abs(dest_stride_uv)); |
| 255 libyuv::I420ToNV12( | 255 DCHECK_EQ(0, first_row % 2); |
| 256 source_frame->data(VideoFrame::kYPlane) + | 256 |
| 257 first_row * source_frame->stride(VideoFrame::kYPlane), | 257 libyuv::I420ToNV12( |
| 258 source_frame->stride(VideoFrame::kYPlane), | 258 source_frame->data(VideoFrame::kYPlane) + |
| 259 source_frame->data(VideoFrame::kUPlane) + | 259 first_row * source_frame->stride(VideoFrame::kYPlane), |
| 260 first_row / 2 * source_frame->stride(VideoFrame::kUPlane), | 260 source_frame->stride(VideoFrame::kYPlane), |
| 261 source_frame->stride(VideoFrame::kUPlane), | 261 source_frame->data(VideoFrame::kUPlane) + |
| 262 source_frame->data(VideoFrame::kVPlane) + | 262 first_row / 2 * source_frame->stride(VideoFrame::kUPlane), |
| 263 first_row / 2 * source_frame->stride(VideoFrame::kVPlane), | 263 source_frame->stride(VideoFrame::kUPlane), |
| 264 source_frame->stride(VideoFrame::kVPlane), | 264 source_frame->data(VideoFrame::kVPlane) + |
| 265 dest_y + first_row * dest_stride_y, dest_stride_y, | 265 first_row / 2 * source_frame->stride(VideoFrame::kVPlane), |
| 266 dest_uv + first_row / 2 * dest_stride_uv, dest_stride_uv, | 266 source_frame->stride(VideoFrame::kVPlane), |
| 267 bytes_per_row, rows); | 267 dest_y + first_row * dest_stride_y, dest_stride_y, |
| 268 dest_uv + first_row / 2 * dest_stride_uv, dest_stride_uv, bytes_per_row, | |
| 269 rows); | |
| 270 } | |
| 268 done.Run(); | 271 done.Run(); |
| 269 } | 272 } |
| 270 | 273 |
| 271 void CopyRowsToUYVYBuffer(int first_row, | 274 void CopyRowsToUYVYBuffer(int first_row, |
| 272 int rows, | 275 int rows, |
| 273 int width, | 276 int width, |
| 274 const scoped_refptr<VideoFrame>& source_frame, | 277 const scoped_refptr<VideoFrame>& source_frame, |
| 275 uint8* output, | 278 uint8* output, |
| 276 int dest_stride, | 279 int dest_stride, |
| 277 const base::Closure& done) { | 280 const base::Closure& done) { |
| 278 TRACE_EVENT2("media", "CopyRowsToUYVYBuffer", "bytes_per_row", width * 2, | 281 TRACE_EVENT2("media", "CopyRowsToUYVYBuffer", "bytes_per_row", width * 2, |
| 279 "rows", rows); | 282 "rows", rows); |
| 280 DCHECK_NE(dest_stride, 0); | 283 if (output) { |
| 281 DCHECK_LE(width, std::abs(dest_stride / 2)); | 284 DCHECK_NE(dest_stride, 0); |
| 282 DCHECK_EQ(0, first_row % 2); | 285 DCHECK_LE(width, std::abs(dest_stride / 2)); |
| 283 libyuv::I420ToUYVY( | 286 DCHECK_EQ(0, first_row % 2); |
| 284 source_frame->data(VideoFrame::kYPlane) + | 287 libyuv::I420ToUYVY( |
| 285 first_row * source_frame->stride(VideoFrame::kYPlane), | 288 source_frame->data(VideoFrame::kYPlane) + |
| 286 source_frame->stride(VideoFrame::kYPlane), | 289 first_row * source_frame->stride(VideoFrame::kYPlane), |
| 287 source_frame->data(VideoFrame::kUPlane) + | 290 source_frame->stride(VideoFrame::kYPlane), |
| 288 first_row / 2 * source_frame->stride(VideoFrame::kUPlane), | 291 source_frame->data(VideoFrame::kUPlane) + |
| 289 source_frame->stride(VideoFrame::kUPlane), | 292 first_row / 2 * source_frame->stride(VideoFrame::kUPlane), |
| 290 source_frame->data(VideoFrame::kVPlane) + | 293 source_frame->stride(VideoFrame::kUPlane), |
| 291 first_row / 2 * source_frame->stride(VideoFrame::kVPlane), | 294 source_frame->data(VideoFrame::kVPlane) + |
| 292 source_frame->stride(VideoFrame::kVPlane), | 295 first_row / 2 * source_frame->stride(VideoFrame::kVPlane), |
| 293 output + first_row * dest_stride, dest_stride, width, rows); | 296 source_frame->stride(VideoFrame::kVPlane), |
| 297 output + first_row * dest_stride, dest_stride, width, rows); | |
| 298 } | |
| 294 done.Run(); | 299 done.Run(); |
| 295 } | 300 } |
| 296 | 301 |
| 297 } // unnamed namespace | 302 } // unnamed namespace |
| 298 | 303 |
| 299 // Creates a VideoFrame backed by native textures starting from a software | 304 // Creates a VideoFrame backed by native textures starting from a software |
| 300 // VideoFrame. | 305 // VideoFrame. |
| 301 // The data contained in |video_frame| is copied into the VideoFrame passed to | 306 // The data contained in |video_frame| is copied into the VideoFrame passed to |
| 302 // |frame_ready_cb|. | 307 // |frame_ready_cb|. |
| 303 // This has to be called on the thread where |media_task_runner_| is current. | 308 // This has to be called on the thread where |media_task_runner_| is current. |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 394 } | 399 } |
| 395 base::Closure copies_done = | 400 base::Closure copies_done = |
| 396 base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources, | 401 base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources, |
| 397 frame_ready_cb); | 402 frame_ready_cb); |
| 398 base::Closure barrier = base::BarrierClosure(copies, copies_done); | 403 base::Closure barrier = base::BarrierClosure(copies, copies_done); |
| 399 | 404 |
| 400 // Post all the async tasks. | 405 // Post all the async tasks. |
| 401 for (size_t i = 0; i < num_planes; i += planes_per_copy) { | 406 for (size_t i = 0; i < num_planes; i += planes_per_copy) { |
| 402 gfx::GpuMemoryBuffer* buffer = | 407 gfx::GpuMemoryBuffer* buffer = |
| 403 frame_resources->plane_resources[i].gpu_memory_buffer.get(); | 408 frame_resources->plane_resources[i].gpu_memory_buffer.get(); |
| 404 DCHECK(buffer); | 409 uint8* dest_buffers[VideoFrame::kMaxPlanes] = {0}; |
| 405 DCHECK_EQ(planes_per_copy, | 410 int dest_strides[VideoFrame::kMaxPlanes] = {0}; |
| 406 gfx::NumberOfPlanesForBufferFormat(buffer->GetFormat())); | 411 if (buffer) { |
| 407 uint8* dest_buffers[VideoFrame::kMaxPlanes]; | 412 DCHECK_EQ(planes_per_copy, |
| 408 int dest_strides[VideoFrame::kMaxPlanes]; | 413 gfx::NumberOfPlanesForBufferFormat(buffer->GetFormat())); |
| 409 bool rv = buffer->Map(reinterpret_cast<void**>(dest_buffers)); | 414 bool rv = buffer->Map(reinterpret_cast<void**>(dest_buffers)); |
| 410 DCHECK(rv); | 415 DCHECK(rv); |
| 411 buffer->GetStride(dest_strides); | 416 buffer->GetStride(dest_strides); |
| 417 } | |
| 412 | 418 |
| 413 const int rows = VideoFrame::Rows(i, output_format_, size.height()); | 419 const int rows = VideoFrame::Rows(i, output_format_, size.height()); |
| 414 const int rows_per_copy = RowsPerCopy(i, output_format_, size.width()); | 420 const int rows_per_copy = RowsPerCopy(i, output_format_, size.width()); |
| 415 | 421 |
| 416 for (int row = 0; row < rows; row += rows_per_copy) { | 422 for (int row = 0; row < rows; row += rows_per_copy) { |
| 417 const int rows_to_copy = std::min(rows_per_copy, rows - row); | 423 const int rows_to_copy = std::min(rows_per_copy, rows - row); |
| 418 switch (output_format_) { | 424 switch (output_format_) { |
| 419 case PIXEL_FORMAT_I420: { | 425 case PIXEL_FORMAT_I420: { |
| 420 const int bytes_per_row = | 426 const int bytes_per_row = |
| 421 VideoFrame::RowBytes(i, output_format_, size.width()); | 427 VideoFrame::RowBytes(i, output_format_, size.width()); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 460 return; | 466 return; |
| 461 } | 467 } |
| 462 | 468 |
| 463 const size_t num_planes = VideoFrame::NumPlanes(output_format_); | 469 const size_t num_planes = VideoFrame::NumPlanes(output_format_); |
| 464 const size_t planes_per_copy = PlanesPerCopy(output_format_); | 470 const size_t planes_per_copy = PlanesPerCopy(output_format_); |
| 465 const gfx::Size size = video_frame->visible_rect().size(); | 471 const gfx::Size size = video_frame->visible_rect().size(); |
| 466 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; | 472 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; |
| 467 // Set up the planes creating the mailboxes needed to refer to the textures. | 473 // Set up the planes creating the mailboxes needed to refer to the textures. |
| 468 for (size_t i = 0; i < num_planes; i += planes_per_copy) { | 474 for (size_t i = 0; i < num_planes; i += planes_per_copy) { |
| 469 PlaneResource& plane_resource = frame_resources->plane_resources[i]; | 475 PlaneResource& plane_resource = frame_resources->plane_resources[i]; |
| 470 DCHECK(plane_resource.gpu_memory_buffer); | |
| 471 // Bind the texture and create or rebind the image. | 476 // Bind the texture and create or rebind the image. |
| 472 gles2->BindTexture(texture_target_, plane_resource.texture_id); | 477 gles2->BindTexture(texture_target_, plane_resource.texture_id); |
| 473 | 478 |
| 474 if (!plane_resource.image_id) { | 479 if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) { |
| 475 const size_t width = VideoFrame::Columns(i, output_format_, size.width()); | 480 const size_t width = VideoFrame::Columns(i, output_format_, size.width()); |
| 476 const size_t height = VideoFrame::Rows(i, output_format_, size.height()); | 481 const size_t height = VideoFrame::Rows(i, output_format_, size.height()); |
| 477 plane_resource.image_id = gles2->CreateImageCHROMIUM( | 482 plane_resource.image_id = gles2->CreateImageCHROMIUM( |
| 478 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height, | 483 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height, |
| 479 ImageInternalFormat(output_format_, i)); | 484 ImageInternalFormat(output_format_, i)); |
| 480 } else { | 485 } else if (plane_resource.image_id) { |
| 481 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, | 486 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, |
| 482 plane_resource.image_id); | 487 plane_resource.image_id); |
| 483 } | 488 } |
| 484 gles2->BindTexImage2DCHROMIUM(texture_target_, plane_resource.image_id); | 489 if (plane_resource.image_id) |
| 490 gles2->BindTexImage2DCHROMIUM(texture_target_, plane_resource.image_id); | |
| 485 mailbox_holders[i] = | 491 mailbox_holders[i] = |
| 486 gpu::MailboxHolder(plane_resource.mailbox, texture_target_, 0); | 492 gpu::MailboxHolder(plane_resource.mailbox, texture_target_, 0); |
| 487 } | 493 } |
| 488 | 494 |
| 489 // Insert a sync_point, this is needed to make sure that the textures the | 495 // Insert a sync_point, this is needed to make sure that the textures the |
| 490 // mailboxes refer to will be used only after all the previous commands posted | 496 // mailboxes refer to will be used only after all the previous commands posted |
| 491 // in the command buffer have been processed. | 497 // in the command buffer have been processed. |
| 492 unsigned sync_point = gles2->InsertSyncPointCHROMIUM(); | 498 unsigned sync_point = gles2->InsertSyncPointCHROMIUM(); |
| 493 for (size_t i = 0; i < num_planes; i += planes_per_copy) | 499 for (size_t i = 0; i < num_planes; i += planes_per_copy) |
| 494 mailbox_holders[i].sync_point = sync_point; | 500 mailbox_holders[i].sync_point = sync_point; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 515 size, video_frame->visible_rect(), video_frame->natural_size(), | 521 size, video_frame->visible_rect(), video_frame->natural_size(), |
| 516 video_frame->timestamp()); | 522 video_frame->timestamp()); |
| 517 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); | 523 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); |
| 518 break; | 524 break; |
| 519 default: | 525 default: |
| 520 NOTREACHED(); | 526 NOTREACHED(); |
| 521 } | 527 } |
| 522 frame_ready_cb.Run(frame); | 528 frame_ready_cb.Run(frame); |
| 523 } | 529 } |
| 524 | 530 |
| 531 // static | |
| 532 bool GpuMemoryBufferVideoFramePool::PoolImpl::AreFrameResourcesCompatible( | |
| 533 const FrameResources* resources, | |
| 534 const gfx::Size& size) { | |
| 535 if (size != resources->size) | |
| 536 return false; | |
| 537 for (const PlaneResource& plane : resources->plane_resources) { | |
| 538 if (!plane.gpu_memory_buffer && | |
| 539 plane.texture_id) // This happens if we failed to allocate a GMB | |
| 540 return false; | |
|
reveman
2015/09/09 22:45:28
Not needed as discussed.
Daniele Castagna
2015/09/10 00:04:20
Done. Also removed the second part of the test tha
| |
| 541 } | |
| 542 return true; | |
| 543 } | |
| 544 | |
| 525 // Destroy all the resources posting one task per FrameResources | 545 // Destroy all the resources posting one task per FrameResources |
| 526 // to the |media_task_runner_|. | 546 // to the |media_task_runner_|. |
| 527 GpuMemoryBufferVideoFramePool::PoolImpl::~PoolImpl() { | 547 GpuMemoryBufferVideoFramePool::PoolImpl::~PoolImpl() { |
| 528 // Delete all the resources on the media thread. | 548 // Delete all the resources on the media thread. |
| 529 while (!resources_pool_.empty()) { | 549 while (!resources_pool_.empty()) { |
| 530 FrameResources* frame_resources = resources_pool_.front(); | 550 FrameResources* frame_resources = resources_pool_.front(); |
| 531 resources_pool_.pop_front(); | 551 resources_pool_.pop_front(); |
| 532 media_task_runner_->PostTask( | 552 media_task_runner_->PostTask( |
| 533 FROM_HERE, base::Bind(&PoolImpl::DeleteFrameResources, gpu_factories_, | 553 FROM_HERE, base::Bind(&PoolImpl::DeleteFrameResources, gpu_factories_, |
| 534 base::Owned(frame_resources))); | 554 base::Owned(frame_resources))); |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 644 } | 664 } |
| 645 | 665 |
| 646 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame( | 666 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame( |
| 647 const scoped_refptr<VideoFrame>& video_frame, | 667 const scoped_refptr<VideoFrame>& video_frame, |
| 648 const FrameReadyCB& frame_ready_cb) { | 668 const FrameReadyCB& frame_ready_cb) { |
| 649 DCHECK(video_frame); | 669 DCHECK(video_frame); |
| 650 pool_impl_->CreateHardwareFrame(video_frame, frame_ready_cb); | 670 pool_impl_->CreateHardwareFrame(video_frame, frame_ready_cb); |
| 651 } | 671 } |
| 652 | 672 |
| 653 } // namespace media | 673 } // namespace media |
| OLD | NEW |