| 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 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 first_row / 2 * source_frame->stride(VideoFrame::kUPlane), | 300 first_row / 2 * source_frame->stride(VideoFrame::kUPlane), |
| 301 source_frame->stride(VideoFrame::kUPlane), | 301 source_frame->stride(VideoFrame::kUPlane), |
| 302 source_frame->visible_data(VideoFrame::kVPlane) + | 302 source_frame->visible_data(VideoFrame::kVPlane) + |
| 303 first_row / 2 * source_frame->stride(VideoFrame::kVPlane), | 303 first_row / 2 * source_frame->stride(VideoFrame::kVPlane), |
| 304 source_frame->stride(VideoFrame::kVPlane), | 304 source_frame->stride(VideoFrame::kVPlane), |
| 305 output + first_row * dest_stride, dest_stride, width, rows); | 305 output + first_row * dest_stride, dest_stride, width, rows); |
| 306 } | 306 } |
| 307 done.Run(); | 307 done.Run(); |
| 308 } | 308 } |
| 309 | 309 |
| 310 gfx::Size CodedSize(const scoped_refptr<VideoFrame>& video_frame, |
| 311 VideoPixelFormat output_format) { |
| 312 DCHECK(gfx::Rect(video_frame->coded_size()) |
| 313 .Contains(video_frame->visible_rect())); |
| 314 DCHECK((video_frame->visible_rect().x() & 1) == 0); |
| 315 gfx::Size output; |
| 316 switch (output_format) { |
| 317 case PIXEL_FORMAT_I420: |
| 318 case PIXEL_FORMAT_NV12: |
| 319 DCHECK((video_frame->visible_rect().y() & 1) == 0); |
| 320 output = gfx::Size((video_frame->visible_rect().width() + 1) & ~1, |
| 321 (video_frame->visible_rect().height() + 1) & ~1); |
| 322 break; |
| 323 case PIXEL_FORMAT_UYVY: |
| 324 output = gfx::Size((video_frame->visible_rect().width() + 1) & ~1, |
| 325 video_frame->visible_rect().height()); |
| 326 break; |
| 327 default: |
| 328 NOTREACHED(); |
| 329 } |
| 330 DCHECK(gfx::Rect(video_frame->coded_size()).Contains(gfx::Rect(output))); |
| 331 return output; |
| 332 } |
| 310 } // unnamed namespace | 333 } // unnamed namespace |
| 311 | 334 |
| 312 // Creates a VideoFrame backed by native textures starting from a software | 335 // Creates a VideoFrame backed by native textures starting from a software |
| 313 // VideoFrame. | 336 // VideoFrame. |
| 314 // The data contained in |video_frame| is copied into the VideoFrame passed to | 337 // The data contained in |video_frame| is copied into the VideoFrame passed to |
| 315 // |frame_ready_cb|. | 338 // |frame_ready_cb|. |
| 316 // This has to be called on the thread where |media_task_runner_| is current. | 339 // This has to be called on the thread where |media_task_runner_| is current. |
| 317 void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame( | 340 void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame( |
| 318 const scoped_refptr<VideoFrame>& video_frame, | 341 const scoped_refptr<VideoFrame>& video_frame, |
| 319 const FrameReadyCB& frame_ready_cb) { | 342 const FrameReadyCB& frame_ready_cb) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 344 case PIXEL_FORMAT_XRGB: | 367 case PIXEL_FORMAT_XRGB: |
| 345 case PIXEL_FORMAT_RGB24: | 368 case PIXEL_FORMAT_RGB24: |
| 346 case PIXEL_FORMAT_RGB32: | 369 case PIXEL_FORMAT_RGB32: |
| 347 case PIXEL_FORMAT_MJPEG: | 370 case PIXEL_FORMAT_MJPEG: |
| 348 case PIXEL_FORMAT_MT21: | 371 case PIXEL_FORMAT_MT21: |
| 349 case PIXEL_FORMAT_UNKNOWN: | 372 case PIXEL_FORMAT_UNKNOWN: |
| 350 frame_ready_cb.Run(video_frame); | 373 frame_ready_cb.Run(video_frame); |
| 351 return; | 374 return; |
| 352 } | 375 } |
| 353 | 376 |
| 354 const gfx::Size size = video_frame->visible_rect().size(); | 377 const gfx::Size coded_size = CodedSize(video_frame, output_format_); |
| 355 | |
| 356 // Acquire resources. Incompatible ones will be dropped from the pool. | 378 // Acquire resources. Incompatible ones will be dropped from the pool. |
| 357 FrameResources* frame_resources = | 379 FrameResources* frame_resources = |
| 358 GetOrCreateFrameResources(size, output_format_); | 380 GetOrCreateFrameResources(coded_size, output_format_); |
| 359 if (!frame_resources) { | 381 if (!frame_resources) { |
| 360 frame_ready_cb.Run(video_frame); | 382 frame_ready_cb.Run(video_frame); |
| 361 return; | 383 return; |
| 362 } | 384 } |
| 363 | 385 |
| 364 worker_task_runner_->PostTask( | 386 worker_task_runner_->PostTask( |
| 365 FROM_HERE, base::Bind(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers, this, | 387 FROM_HERE, base::Bind(&PoolImpl::CopyVideoFrameToGpuMemoryBuffers, this, |
| 366 video_frame, frame_resources, frame_ready_cb)); | 388 video_frame, frame_resources, frame_ready_cb)); |
| 367 } | 389 } |
| 368 | 390 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 // Copies |video_frame| into |frame_resources| asynchronously, posting n tasks | 442 // Copies |video_frame| into |frame_resources| asynchronously, posting n tasks |
| 421 // that will be synchronized by a barrier. | 443 // that will be synchronized by a barrier. |
| 422 // After the barrier is passed OnCopiesDone will be called. | 444 // After the barrier is passed OnCopiesDone will be called. |
| 423 void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( | 445 void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers( |
| 424 const scoped_refptr<VideoFrame>& video_frame, | 446 const scoped_refptr<VideoFrame>& video_frame, |
| 425 FrameResources* frame_resources, | 447 FrameResources* frame_resources, |
| 426 const FrameReadyCB& frame_ready_cb) { | 448 const FrameReadyCB& frame_ready_cb) { |
| 427 // Compute the number of tasks to post and create the barrier. | 449 // Compute the number of tasks to post and create the barrier. |
| 428 const size_t num_planes = VideoFrame::NumPlanes(output_format_); | 450 const size_t num_planes = VideoFrame::NumPlanes(output_format_); |
| 429 const size_t planes_per_copy = PlanesPerCopy(output_format_); | 451 const size_t planes_per_copy = PlanesPerCopy(output_format_); |
| 430 const gfx::Size size = video_frame->visible_rect().size(); | 452 const gfx::Size coded_size = CodedSize(video_frame, output_format_); |
| 431 size_t copies = 0; | 453 size_t copies = 0; |
| 432 for (size_t i = 0; i < num_planes; i += planes_per_copy) { | 454 for (size_t i = 0; i < num_planes; i += planes_per_copy) { |
| 433 const int rows = VideoFrame::Rows(i, output_format_, size.height()); | 455 const int rows = VideoFrame::Rows(i, output_format_, coded_size.height()); |
| 434 const int rows_per_copy = RowsPerCopy(i, output_format_, size.width()); | 456 const int rows_per_copy = |
| 457 RowsPerCopy(i, output_format_, coded_size.width()); |
| 435 copies += rows / rows_per_copy; | 458 copies += rows / rows_per_copy; |
| 436 if (rows % rows_per_copy) | 459 if (rows % rows_per_copy) |
| 437 ++copies; | 460 ++copies; |
| 438 } | 461 } |
| 439 const base::Closure copies_done = | 462 const base::Closure copies_done = |
| 440 base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources, | 463 base::Bind(&PoolImpl::OnCopiesDone, this, video_frame, frame_resources, |
| 441 frame_ready_cb); | 464 frame_ready_cb); |
| 442 const base::Closure barrier = base::BarrierClosure(copies, copies_done); | 465 const base::Closure barrier = base::BarrierClosure(copies, copies_done); |
| 443 | 466 |
| 444 // Post all the async tasks. | 467 // Post all the async tasks. |
| 445 for (size_t i = 0; i < num_planes; i += planes_per_copy) { | 468 for (size_t i = 0; i < num_planes; i += planes_per_copy) { |
| 446 gfx::GpuMemoryBuffer* buffer = | 469 gfx::GpuMemoryBuffer* buffer = |
| 447 frame_resources->plane_resources[i].gpu_memory_buffer.get(); | 470 frame_resources->plane_resources[i].gpu_memory_buffer.get(); |
| 448 | 471 |
| 449 if (!buffer || !buffer->Map()) { | 472 if (!buffer || !buffer->Map()) { |
| 450 DLOG(ERROR) << "Could not get or Map() buffer"; | 473 DLOG(ERROR) << "Could not get or Map() buffer"; |
| 451 return; | 474 return; |
| 452 } | 475 } |
| 453 DCHECK_EQ(planes_per_copy, | 476 DCHECK_EQ(planes_per_copy, |
| 454 gfx::NumberOfPlanesForBufferFormat(buffer->GetFormat())); | 477 gfx::NumberOfPlanesForBufferFormat(buffer->GetFormat())); |
| 455 | 478 |
| 456 const int rows = VideoFrame::Rows(i, output_format_, size.height()); | 479 const int rows = VideoFrame::Rows(i, output_format_, coded_size.height()); |
| 457 const int rows_per_copy = RowsPerCopy(i, output_format_, size.width()); | 480 const int rows_per_copy = |
| 481 RowsPerCopy(i, output_format_, coded_size.width()); |
| 458 | 482 |
| 459 for (int row = 0; row < rows; row += rows_per_copy) { | 483 for (int row = 0; row < rows; row += rows_per_copy) { |
| 460 const int rows_to_copy = std::min(rows_per_copy, rows - row); | 484 const int rows_to_copy = std::min(rows_per_copy, rows - row); |
| 461 switch (output_format_) { | 485 switch (output_format_) { |
| 462 case PIXEL_FORMAT_I420: { | 486 case PIXEL_FORMAT_I420: { |
| 463 const int bytes_per_row = | 487 const int bytes_per_row = |
| 464 VideoFrame::RowBytes(i, output_format_, size.width()); | 488 VideoFrame::RowBytes(i, output_format_, coded_size.width()); |
| 465 worker_task_runner_->PostTask( | 489 worker_task_runner_->PostTask( |
| 466 FROM_HERE, base::Bind(&CopyRowsToI420Buffer, row, rows_to_copy, | 490 FROM_HERE, base::Bind(&CopyRowsToI420Buffer, row, rows_to_copy, |
| 467 bytes_per_row, video_frame->visible_data(i), | 491 bytes_per_row, video_frame->visible_data(i), |
| 468 video_frame->stride(i), | 492 video_frame->stride(i), |
| 469 static_cast<uint8_t*>(buffer->memory(0)), | 493 static_cast<uint8_t*>(buffer->memory(0)), |
| 470 buffer->stride(0), barrier)); | 494 buffer->stride(0), barrier)); |
| 471 break; | 495 break; |
| 472 } | 496 } |
| 473 case PIXEL_FORMAT_NV12: | 497 case PIXEL_FORMAT_NV12: |
| 474 worker_task_runner_->PostTask( | 498 worker_task_runner_->PostTask( |
| 475 FROM_HERE, | 499 FROM_HERE, base::Bind(&CopyRowsToNV12Buffer, row, rows_to_copy, |
| 476 base::Bind(&CopyRowsToNV12Buffer, row, rows_to_copy, size.width(), | 500 coded_size.width(), video_frame, |
| 477 video_frame, static_cast<uint8_t*>(buffer->memory(0)), | 501 static_cast<uint8_t*>(buffer->memory(0)), |
| 478 buffer->stride(0), | 502 buffer->stride(0), |
| 479 static_cast<uint8_t*>(buffer->memory(1)), | 503 static_cast<uint8_t*>(buffer->memory(1)), |
| 480 buffer->stride(1), barrier)); | 504 buffer->stride(1), barrier)); |
| 481 break; | 505 break; |
| 482 case PIXEL_FORMAT_UYVY: | 506 case PIXEL_FORMAT_UYVY: |
| 483 worker_task_runner_->PostTask( | 507 worker_task_runner_->PostTask( |
| 484 FROM_HERE, | 508 FROM_HERE, base::Bind(&CopyRowsToUYVYBuffer, row, rows_to_copy, |
| 485 base::Bind(&CopyRowsToUYVYBuffer, row, rows_to_copy, size.width(), | 509 coded_size.width(), video_frame, |
| 486 video_frame, static_cast<uint8_t*>(buffer->memory(0)), | 510 static_cast<uint8_t*>(buffer->memory(0)), |
| 487 buffer->stride(0), barrier)); | 511 buffer->stride(0), barrier)); |
| 488 break; | 512 break; |
| 489 default: | 513 default: |
| 490 NOTREACHED(); | 514 NOTREACHED(); |
| 491 } | 515 } |
| 492 } | 516 } |
| 493 } | 517 } |
| 494 } | 518 } |
| 495 | 519 |
| 496 void GpuMemoryBufferVideoFramePool::PoolImpl:: | 520 void GpuMemoryBufferVideoFramePool::PoolImpl:: |
| 497 BindAndCreateMailboxesHardwareFrameResources( | 521 BindAndCreateMailboxesHardwareFrameResources( |
| 498 const scoped_refptr<VideoFrame>& video_frame, | 522 const scoped_refptr<VideoFrame>& video_frame, |
| 499 FrameResources* frame_resources, | 523 FrameResources* frame_resources, |
| 500 const FrameReadyCB& frame_ready_cb) { | 524 const FrameReadyCB& frame_ready_cb) { |
| 501 scoped_ptr<GpuVideoAcceleratorFactories::ScopedGLContextLock> lock( | 525 scoped_ptr<GpuVideoAcceleratorFactories::ScopedGLContextLock> lock( |
| 502 gpu_factories_->GetGLContextLock()); | 526 gpu_factories_->GetGLContextLock()); |
| 503 if (!lock) { | 527 if (!lock) { |
| 504 frame_ready_cb.Run(video_frame); | 528 frame_ready_cb.Run(video_frame); |
| 505 return; | 529 return; |
| 506 } | 530 } |
| 507 gpu::gles2::GLES2Interface* gles2 = lock->ContextGL(); | 531 gpu::gles2::GLES2Interface* gles2 = lock->ContextGL(); |
| 508 | 532 |
| 509 const size_t num_planes = VideoFrame::NumPlanes(output_format_); | 533 const size_t num_planes = VideoFrame::NumPlanes(output_format_); |
| 510 const size_t planes_per_copy = PlanesPerCopy(output_format_); | 534 const size_t planes_per_copy = PlanesPerCopy(output_format_); |
| 511 const gfx::Size size = video_frame->visible_rect().size(); | 535 const gfx::Size coded_size = CodedSize(video_frame, output_format_); |
| 512 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; | 536 gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; |
| 513 // Set up the planes creating the mailboxes needed to refer to the textures. | 537 // Set up the planes creating the mailboxes needed to refer to the textures. |
| 514 for (size_t i = 0; i < num_planes; i += planes_per_copy) { | 538 for (size_t i = 0; i < num_planes; i += planes_per_copy) { |
| 515 PlaneResource& plane_resource = frame_resources->plane_resources[i]; | 539 PlaneResource& plane_resource = frame_resources->plane_resources[i]; |
| 516 // Bind the texture and create or rebind the image. | 540 // Bind the texture and create or rebind the image. |
| 517 gles2->BindTexture(texture_target_, plane_resource.texture_id); | 541 gles2->BindTexture(texture_target_, plane_resource.texture_id); |
| 518 | 542 |
| 519 if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) { | 543 if (plane_resource.gpu_memory_buffer && !plane_resource.image_id) { |
| 520 const size_t width = VideoFrame::Columns(i, output_format_, size.width()); | 544 const size_t width = |
| 521 const size_t height = VideoFrame::Rows(i, output_format_, size.height()); | 545 VideoFrame::Columns(i, output_format_, coded_size.width()); |
| 546 const size_t height = |
| 547 VideoFrame::Rows(i, output_format_, coded_size.height()); |
| 522 plane_resource.image_id = gles2->CreateImageCHROMIUM( | 548 plane_resource.image_id = gles2->CreateImageCHROMIUM( |
| 523 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height, | 549 plane_resource.gpu_memory_buffer->AsClientBuffer(), width, height, |
| 524 ImageInternalFormat(output_format_, i)); | 550 ImageInternalFormat(output_format_, i)); |
| 525 } else if (plane_resource.image_id) { | 551 } else if (plane_resource.image_id) { |
| 526 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, | 552 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, |
| 527 plane_resource.image_id); | 553 plane_resource.image_id); |
| 528 } | 554 } |
| 529 if (plane_resource.image_id) | 555 if (plane_resource.image_id) |
| 530 gles2->BindTexImage2DCHROMIUM(texture_target_, plane_resource.image_id); | 556 gles2->BindTexImage2DCHROMIUM(texture_target_, plane_resource.image_id); |
| 531 mailbox_holders[i] = | 557 mailbox_holders[i] = |
| 532 gpu::MailboxHolder(plane_resource.mailbox, texture_target_, 0); | 558 gpu::MailboxHolder(plane_resource.mailbox, texture_target_, 0); |
| 533 } | 559 } |
| 534 | 560 |
| 535 // Insert a sync_point, this is needed to make sure that the textures the | 561 // Insert a sync_point, this is needed to make sure that the textures the |
| 536 // mailboxes refer to will be used only after all the previous commands posted | 562 // mailboxes refer to will be used only after all the previous commands posted |
| 537 // in the command buffer have been processed. | 563 // in the command buffer have been processed. |
| 538 unsigned sync_point = gles2->InsertSyncPointCHROMIUM(); | 564 unsigned sync_point = gles2->InsertSyncPointCHROMIUM(); |
| 539 for (size_t i = 0; i < num_planes; i += planes_per_copy) | 565 for (size_t i = 0; i < num_planes; i += planes_per_copy) |
| 540 mailbox_holders[i].sync_point = sync_point; | 566 mailbox_holders[i].sync_point = sync_point; |
| 541 | 567 |
| 542 scoped_refptr<VideoFrame> frame; | 568 scoped_refptr<VideoFrame> frame; |
| 543 | 569 |
| 544 auto release_mailbox_callback = | 570 auto release_mailbox_callback = |
| 545 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources); | 571 base::Bind(&PoolImpl::MailboxHoldersReleased, this, frame_resources); |
| 546 | 572 |
| 547 // Create the VideoFrame backed by native textures. | 573 // Create the VideoFrame backed by native textures. |
| 574 gfx::Size visible_size = video_frame->visible_rect().size(); |
| 548 switch (output_format_) { | 575 switch (output_format_) { |
| 549 case PIXEL_FORMAT_I420: | 576 case PIXEL_FORMAT_I420: |
| 550 frame = VideoFrame::WrapYUV420NativeTextures( | 577 frame = VideoFrame::WrapYUV420NativeTextures( |
| 551 mailbox_holders[VideoFrame::kYPlane], | 578 mailbox_holders[VideoFrame::kYPlane], |
| 552 mailbox_holders[VideoFrame::kUPlane], | 579 mailbox_holders[VideoFrame::kUPlane], |
| 553 mailbox_holders[VideoFrame::kVPlane], release_mailbox_callback, size, | 580 mailbox_holders[VideoFrame::kVPlane], release_mailbox_callback, |
| 554 gfx::Rect(size), video_frame->natural_size(), | 581 coded_size, gfx::Rect(visible_size), video_frame->natural_size(), |
| 555 video_frame->timestamp()); | 582 video_frame->timestamp()); |
| 556 if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY)) | 583 if (video_frame->metadata()->IsTrue(VideoFrameMetadata::ALLOW_OVERLAY)) |
| 557 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); | 584 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); |
| 558 break; | 585 break; |
| 559 case PIXEL_FORMAT_NV12: | 586 case PIXEL_FORMAT_NV12: |
| 560 case PIXEL_FORMAT_UYVY: | 587 case PIXEL_FORMAT_UYVY: |
| 561 frame = VideoFrame::WrapNativeTexture( | 588 frame = VideoFrame::WrapNativeTexture( |
| 562 output_format_, mailbox_holders[VideoFrame::kYPlane], | 589 output_format_, mailbox_holders[VideoFrame::kYPlane], |
| 563 release_mailbox_callback, size, gfx::Rect(size), | 590 release_mailbox_callback, coded_size, gfx::Rect(visible_size), |
| 564 video_frame->natural_size(), video_frame->timestamp()); | 591 video_frame->natural_size(), video_frame->timestamp()); |
| 565 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); | 592 frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true); |
| 566 break; | 593 break; |
| 567 default: | 594 default: |
| 568 NOTREACHED(); | 595 NOTREACHED(); |
| 569 } | 596 } |
| 570 frame_ready_cb.Run(frame); | 597 frame_ready_cb.Run(frame); |
| 571 } | 598 } |
| 572 | 599 |
| 573 // Destroy all the resources posting one task per FrameResources | 600 // Destroy all the resources posting one task per FrameResources |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 702 } | 729 } |
| 703 | 730 |
| 704 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame( | 731 void GpuMemoryBufferVideoFramePool::MaybeCreateHardwareFrame( |
| 705 const scoped_refptr<VideoFrame>& video_frame, | 732 const scoped_refptr<VideoFrame>& video_frame, |
| 706 const FrameReadyCB& frame_ready_cb) { | 733 const FrameReadyCB& frame_ready_cb) { |
| 707 DCHECK(video_frame); | 734 DCHECK(video_frame); |
| 708 pool_impl_->CreateHardwareFrame(video_frame, frame_ready_cb); | 735 pool_impl_->CreateHardwareFrame(video_frame, frame_ready_cb); |
| 709 } | 736 } |
| 710 | 737 |
| 711 } // namespace media | 738 } // namespace media |
| OLD | NEW |