| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "cc/resources/video_resource_updater.h" | 5 #include "cc/resources/video_resource_updater.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 case GL_TEXTURE_EXTERNAL_OES: | 63 case GL_TEXTURE_EXTERNAL_OES: |
| 64 case GL_TEXTURE_2D: | 64 case GL_TEXTURE_2D: |
| 65 return VideoFrameExternalResources::YUV_RESOURCE; | 65 return VideoFrameExternalResources::YUV_RESOURCE; |
| 66 case GL_TEXTURE_RECTANGLE_ARB: | 66 case GL_TEXTURE_RECTANGLE_ARB: |
| 67 return VideoFrameExternalResources::RGB_RESOURCE; | 67 return VideoFrameExternalResources::RGB_RESOURCE; |
| 68 default: | 68 default: |
| 69 NOTREACHED(); | 69 NOTREACHED(); |
| 70 break; | 70 break; |
| 71 } | 71 } |
| 72 break; | 72 break; |
| 73 case media::PIXEL_FORMAT_Y16: |
| 74 return VideoFrameExternalResources::Y_RESOURCE; |
| 75 break; |
| 73 case media::PIXEL_FORMAT_YV12: | 76 case media::PIXEL_FORMAT_YV12: |
| 74 case media::PIXEL_FORMAT_YV16: | 77 case media::PIXEL_FORMAT_YV16: |
| 75 case media::PIXEL_FORMAT_YV24: | 78 case media::PIXEL_FORMAT_YV24: |
| 76 case media::PIXEL_FORMAT_YV12A: | 79 case media::PIXEL_FORMAT_YV12A: |
| 77 case media::PIXEL_FORMAT_NV21: | 80 case media::PIXEL_FORMAT_NV21: |
| 78 case media::PIXEL_FORMAT_YUY2: | 81 case media::PIXEL_FORMAT_YUY2: |
| 79 case media::PIXEL_FORMAT_RGB24: | 82 case media::PIXEL_FORMAT_RGB24: |
| 80 case media::PIXEL_FORMAT_RGB32: | 83 case media::PIXEL_FORMAT_RGB32: |
| 81 case media::PIXEL_FORMAT_MJPEG: | 84 case media::PIXEL_FORMAT_MJPEG: |
| 82 case media::PIXEL_FORMAT_MT21: | 85 case media::PIXEL_FORMAT_MT21: |
| 83 case media::PIXEL_FORMAT_YUV420P9: | 86 case media::PIXEL_FORMAT_YUV420P9: |
| 84 case media::PIXEL_FORMAT_YUV422P9: | 87 case media::PIXEL_FORMAT_YUV422P9: |
| 85 case media::PIXEL_FORMAT_YUV444P9: | 88 case media::PIXEL_FORMAT_YUV444P9: |
| 86 case media::PIXEL_FORMAT_YUV420P10: | 89 case media::PIXEL_FORMAT_YUV420P10: |
| 87 case media::PIXEL_FORMAT_YUV422P10: | 90 case media::PIXEL_FORMAT_YUV422P10: |
| 88 case media::PIXEL_FORMAT_YUV444P10: | 91 case media::PIXEL_FORMAT_YUV444P10: |
| 89 case media::PIXEL_FORMAT_YUV420P12: | 92 case media::PIXEL_FORMAT_YUV420P12: |
| 90 case media::PIXEL_FORMAT_YUV422P12: | 93 case media::PIXEL_FORMAT_YUV422P12: |
| 91 case media::PIXEL_FORMAT_YUV444P12: | 94 case media::PIXEL_FORMAT_YUV444P12: |
| 92 case media::PIXEL_FORMAT_Y8: | 95 case media::PIXEL_FORMAT_Y8: |
| 93 case media::PIXEL_FORMAT_Y16: | |
| 94 case media::PIXEL_FORMAT_UNKNOWN: | 96 case media::PIXEL_FORMAT_UNKNOWN: |
| 95 break; | 97 break; |
| 96 } | 98 } |
| 97 return VideoFrameExternalResources::NONE; | 99 return VideoFrameExternalResources::NONE; |
| 98 } | 100 } |
| 99 | 101 |
| 100 class SyncTokenClientImpl : public media::VideoFrame::SyncTokenClient { | 102 class SyncTokenClientImpl : public media::VideoFrame::SyncTokenClient { |
| 101 public: | 103 public: |
| 102 SyncTokenClientImpl(gpu::gles2::GLES2Interface* gl, | 104 SyncTokenClientImpl(gpu::gles2::GLES2Interface* gl, |
| 103 const gpu::SyncToken& sync_token) | 105 const gpu::SyncToken& sync_token) |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 // Maximum value used in |src|. | 308 // Maximum value used in |src|. |
| 307 int max_value = (1 << bits_per_channel) - 1; | 309 int max_value = (1 << bits_per_channel) - 1; |
| 308 int rows = 1; | 310 int rows = 1; |
| 309 libyuv::HalfFloatPlane(src, stride, dst, stride, 1.0f / max_value, num, rows); | 311 libyuv::HalfFloatPlane(src, stride, dst, stride, 1.0f / max_value, num, rows); |
| 310 } | 312 } |
| 311 | 313 |
| 312 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( | 314 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( |
| 313 scoped_refptr<media::VideoFrame> video_frame) { | 315 scoped_refptr<media::VideoFrame> video_frame) { |
| 314 TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes"); | 316 TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes"); |
| 315 const media::VideoPixelFormat input_frame_format = video_frame->format(); | 317 const media::VideoPixelFormat input_frame_format = video_frame->format(); |
| 316 | |
| 317 // TODO(hubbe): Make this a video frame method. | 318 // TODO(hubbe): Make this a video frame method. |
| 318 int bits_per_channel = 0; | 319 int bits_per_channel = 0; |
| 319 switch (input_frame_format) { | 320 switch (input_frame_format) { |
| 320 case media::PIXEL_FORMAT_UNKNOWN: | 321 case media::PIXEL_FORMAT_UNKNOWN: |
| 321 NOTREACHED(); | 322 NOTREACHED(); |
| 322 // Fall through! | 323 // Fall through! |
| 323 case media::PIXEL_FORMAT_I420: | 324 case media::PIXEL_FORMAT_I420: |
| 324 case media::PIXEL_FORMAT_YV12: | 325 case media::PIXEL_FORMAT_YV12: |
| 325 case media::PIXEL_FORMAT_YV16: | 326 case media::PIXEL_FORMAT_YV16: |
| 326 case media::PIXEL_FORMAT_YV12A: | 327 case media::PIXEL_FORMAT_YV12A: |
| (...skipping 24 matching lines...) Expand all Loading... |
| 351 case media::PIXEL_FORMAT_YUV420P12: | 352 case media::PIXEL_FORMAT_YUV420P12: |
| 352 case media::PIXEL_FORMAT_YUV422P12: | 353 case media::PIXEL_FORMAT_YUV422P12: |
| 353 case media::PIXEL_FORMAT_YUV444P12: | 354 case media::PIXEL_FORMAT_YUV444P12: |
| 354 bits_per_channel = 12; | 355 bits_per_channel = 12; |
| 355 break; | 356 break; |
| 356 case media::PIXEL_FORMAT_Y16: | 357 case media::PIXEL_FORMAT_Y16: |
| 357 bits_per_channel = 16; | 358 bits_per_channel = 16; |
| 358 break; | 359 break; |
| 359 } | 360 } |
| 360 | 361 |
| 361 // TODO(dshwang): support PIXEL_FORMAT_Y16. crbug.com/624436 | 362 // Only YUV and Y16 software video frames are supported. |
| 362 DCHECK_NE(bits_per_channel, 16); | 363 const bool isYuvPlanar = media::IsYuvPlanar(input_frame_format); |
| 363 | 364 if (!(isYuvPlanar || input_frame_format == media::PIXEL_FORMAT_Y16)) { |
| 364 // Only YUV software video frames are supported. | |
| 365 if (!media::IsYuvPlanar(input_frame_format)) { | |
| 366 NOTREACHED() << media::VideoPixelFormatToString(input_frame_format); | 365 NOTREACHED() << media::VideoPixelFormatToString(input_frame_format); |
| 367 return VideoFrameExternalResources(); | 366 return VideoFrameExternalResources(); |
| 368 } | 367 } |
| 369 | 368 |
| 370 const bool software_compositor = context_provider_ == NULL; | 369 const bool software_compositor = context_provider_ == NULL; |
| 371 | 370 |
| 372 ResourceFormat output_resource_format = | 371 ResourceFormat output_resource_format = |
| 373 resource_provider_->YuvResourceFormat(bits_per_channel); | 372 (input_frame_format == media::PIXEL_FORMAT_Y16) |
| 373 ? resource_provider_->Y16ResourceFormat() |
| 374 : resource_provider_->YuvResourceFormat(bits_per_channel); |
| 374 | 375 |
| 375 // If GPU compositing is enabled, but the output resource format | 376 // If GPU compositing is enabled, but the output resource format |
| 376 // returned by the resource provider is RGBA_8888, then a GPU driver | 377 // returned by the resource provider is RGBA_8888, then a GPU driver |
| 377 // bug workaround requires that YUV frames must be converted to RGB | 378 // bug workaround requires that YUV frames must be converted to RGB |
| 378 // before texture upload. | 379 // before texture upload. |
| 379 bool texture_needs_rgb_conversion = | 380 bool texture_needs_rgb_conversion = |
| 380 !software_compositor && | 381 !software_compositor && |
| 381 output_resource_format == ResourceFormat::RGBA_8888; | 382 output_resource_format == ResourceFormat::RGBA_8888 && |
| 383 input_frame_format != media::PIXEL_FORMAT_Y16; |
| 382 size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format); | 384 size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format); |
| 383 | 385 |
| 384 // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB | 386 // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB |
| 385 // conversion here. That involves an extra copy of each frame to a bitmap. | 387 // conversion here. That involves an extra copy of each frame to a bitmap. |
| 386 // Obviously, this is suboptimal and should be addressed once ubercompositor | 388 // Obviously, this is suboptimal and should be addressed once ubercompositor |
| 387 // starts shaping up. | 389 // starts shaping up. |
| 388 if (software_compositor || texture_needs_rgb_conversion) { | 390 if (software_compositor || texture_needs_rgb_conversion) { |
| 389 output_resource_format = kRGBResourceFormat; | 391 output_resource_format = kRGBResourceFormat; |
| 390 output_plane_count = 1; | 392 output_plane_count = 1; |
| 391 bits_per_channel = 8; | 393 bits_per_channel = 8; |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 external_resources.release_callbacks.push_back(base::Bind( | 482 external_resources.release_callbacks.push_back(base::Bind( |
| 481 &RecycleResource, AsWeakPtr(), plane_resource.resource_id())); | 483 &RecycleResource, AsWeakPtr(), plane_resource.resource_id())); |
| 482 external_resources.type = VideoFrameExternalResources::RGBA_RESOURCE; | 484 external_resources.type = VideoFrameExternalResources::RGBA_RESOURCE; |
| 483 } | 485 } |
| 484 return external_resources; | 486 return external_resources; |
| 485 } | 487 } |
| 486 | 488 |
| 487 for (size_t i = 0; i < plane_resources.size(); ++i) { | 489 for (size_t i = 0; i < plane_resources.size(); ++i) { |
| 488 PlaneResource& plane_resource = *plane_resources[i]; | 490 PlaneResource& plane_resource = *plane_resources[i]; |
| 489 // Update each plane's resource id with its content. | 491 // Update each plane's resource id with its content. |
| 490 DCHECK_EQ(plane_resource.resource_format(), | 492 DCHECK_EQ(plane_resource.resource_format(), output_resource_format); |
| 491 resource_provider_->YuvResourceFormat(bits_per_channel)); | |
| 492 | 493 |
| 493 if (!plane_resource.Matches(video_frame->unique_id(), i)) { | 494 if (!plane_resource.Matches(video_frame->unique_id(), i)) { |
| 494 // TODO(hubbe): Move all conversion (and upload?) code to media/. | 495 // TODO(hubbe): Move all conversion (and upload?) code to media/. |
| 495 // We need to transfer data from |video_frame| to the plane resource. | 496 // We need to transfer data from |video_frame| to the plane resource. |
| 496 // TODO(reveman): Can use GpuMemoryBuffers here to improve performance. | 497 // TODO(reveman): Can use GpuMemoryBuffers here to improve performance. |
| 497 | 498 |
| 498 // The |resource_size_pixels| is the size of the resource we want to | 499 // The |resource_size_pixels| is the size of the resource we want to |
| 499 // upload to. | 500 // upload to. |
| 500 gfx::Size resource_size_pixels = plane_resource.resource_size(); | 501 gfx::Size resource_size_pixels = plane_resource.resource_size(); |
| 501 // The |video_stride_bytes| is the width of the video frame we are | 502 // The |video_stride_bytes| is the width of the video frame we are |
| 502 // uploading (including non-frame data to fill in the stride). | 503 // uploading (including non-frame data to fill in the stride). |
| 503 int video_stride_bytes = video_frame->stride(i); | 504 int video_stride_bytes = video_frame->stride(i); |
| 504 | 505 |
| 505 size_t bytes_per_row = ResourceUtil::CheckedWidthInBytes<size_t>( | 506 size_t bytes_per_row = ResourceUtil::CheckedWidthInBytes<size_t>( |
| 506 resource_size_pixels.width(), plane_resource.resource_format()); | 507 resource_size_pixels.width(), plane_resource.resource_format()); |
| 507 // Use 4-byte row alignment (OpenGL default) for upload performance. | 508 // Use 4-byte row alignment (OpenGL default) for upload performance. |
| 508 // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. | 509 // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. |
| 509 size_t upload_image_stride = | 510 size_t upload_image_stride = |
| 510 MathUtil::CheckedRoundUp<size_t>(bytes_per_row, 4u); | 511 MathUtil::CheckedRoundUp<size_t>(bytes_per_row, 4u); |
| 511 | 512 |
| 512 bool needs_conversion = false; | 513 bool needs_conversion = false; |
| 513 int shift = 0; | 514 int shift = 0; |
| 514 | 515 |
| 515 // LUMINANCE_F16 uses half-floats, so we always need a conversion step. | 516 // LUMINANCE_F16 uses half-floats, so we always need a conversion step. |
| 516 if (plane_resource.resource_format() == LUMINANCE_F16) { | 517 if (plane_resource.resource_format() == LUMINANCE_F16) { |
| 517 needs_conversion = true; | 518 needs_conversion = true; |
| 519 } else if (input_frame_format == media::PIXEL_FORMAT_Y16) { |
| 520 if (plane_resource.resource_format() == RGBA_8888) |
| 521 needs_conversion = true; |
| 518 } else if (bits_per_channel > 8) { | 522 } else if (bits_per_channel > 8) { |
| 519 // If bits_per_channel > 8 and we can't use LUMINANCE_F16, we need to | 523 // If bits_per_channel > 8 and we can't use LUMINANCE_F16, we need to |
| 520 // shift the data down and create an 8-bit texture. | 524 // shift the data down and create an 8-bit texture. |
| 521 needs_conversion = true; | 525 needs_conversion = true; |
| 522 shift = bits_per_channel - 8; | 526 shift = bits_per_channel - 8; |
| 523 } | 527 } |
| 524 const uint8_t* pixels; | 528 const uint8_t* pixels; |
| 525 if (static_cast<int>(upload_image_stride) == video_stride_bytes && | 529 if (static_cast<int>(upload_image_stride) == video_stride_bytes && |
| 526 !needs_conversion) { | 530 !needs_conversion) { |
| 527 pixels = video_frame->data(i); | 531 pixels = video_frame->data(i); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 550 MakeHalfFloats(src, bits_per_channel, bytes_per_row / 2, dst); | 554 MakeHalfFloats(src, bits_per_channel, bytes_per_row / 2, dst); |
| 551 } | 555 } |
| 552 } else if (shift != 0) { | 556 } else if (shift != 0) { |
| 553 // We have more-than-8-bit input which we need to shift | 557 // We have more-than-8-bit input which we need to shift |
| 554 // down to fit it into an 8-bit texture. | 558 // down to fit it into an 8-bit texture. |
| 555 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; | 559 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; |
| 556 const uint16_t* src = reinterpret_cast<uint16_t*>( | 560 const uint16_t* src = reinterpret_cast<uint16_t*>( |
| 557 video_frame->data(i) + (video_stride_bytes * row)); | 561 video_frame->data(i) + (video_stride_bytes * row)); |
| 558 for (size_t i = 0; i < bytes_per_row; i++) | 562 for (size_t i = 0; i < bytes_per_row; i++) |
| 559 dst[i] = src[i] >> shift; | 563 dst[i] = src[i] >> shift; |
| 564 } else if (input_frame_format == media::PIXEL_FORMAT_Y16 && |
| 565 plane_resource.resource_format() == RGBA_8888) { |
| 566 uint32_t* dst = reinterpret_cast<uint32_t*>( |
| 567 &upload_pixels_[upload_image_stride * row]); |
| 568 const uint16_t* src = reinterpret_cast<uint16_t*>( |
| 569 video_frame->data(i) + (video_stride_bytes * row)); |
| 570 for (size_t i = 0; i < bytes_per_row / 4; ++i) |
| 571 *dst++ = *src++; |
| 560 } else { | 572 } else { |
| 561 // Input and output are the same size and format, but | 573 // Input and output are the same size and format, but |
| 562 // differ in stride, copy one row at a time. | 574 // differ in stride, copy one row at a time. |
| 563 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; | 575 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; |
| 564 const uint8_t* src = | 576 const uint8_t* src = |
| 565 video_frame->data(i) + (video_stride_bytes * row); | 577 video_frame->data(i) + (video_stride_bytes * row); |
| 566 memcpy(dst, src, bytes_per_row); | 578 memcpy(dst, src, bytes_per_row); |
| 567 } | 579 } |
| 568 } | 580 } |
| 569 pixels = &upload_pixels_[0]; | 581 pixels = &upload_pixels_[0]; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 608 // sync token is not required. | 620 // sync token is not required. |
| 609 TextureMailbox mailbox(plane_resource.mailbox(), gpu::SyncToken(), | 621 TextureMailbox mailbox(plane_resource.mailbox(), gpu::SyncToken(), |
| 610 resource_provider_->GetResourceTextureTarget( | 622 resource_provider_->GetResourceTextureTarget( |
| 611 plane_resource.resource_id())); | 623 plane_resource.resource_id())); |
| 612 mailbox.set_color_space(video_frame->ColorSpace()); | 624 mailbox.set_color_space(video_frame->ColorSpace()); |
| 613 external_resources.mailboxes.push_back(mailbox); | 625 external_resources.mailboxes.push_back(mailbox); |
| 614 external_resources.release_callbacks.push_back(base::Bind( | 626 external_resources.release_callbacks.push_back(base::Bind( |
| 615 &RecycleResource, AsWeakPtr(), plane_resource.resource_id())); | 627 &RecycleResource, AsWeakPtr(), plane_resource.resource_id())); |
| 616 } | 628 } |
| 617 | 629 |
| 618 external_resources.type = VideoFrameExternalResources::YUV_RESOURCE; | 630 external_resources.type = (input_frame_format == media::PIXEL_FORMAT_Y16) |
| 631 ? VideoFrameExternalResources::Y_RESOURCE |
| 632 : VideoFrameExternalResources::YUV_RESOURCE; |
| 619 return external_resources; | 633 return external_resources; |
| 620 } | 634 } |
| 621 | 635 |
| 622 // static | 636 // static |
| 623 void VideoResourceUpdater::ReturnTexture( | 637 void VideoResourceUpdater::ReturnTexture( |
| 624 base::WeakPtr<VideoResourceUpdater> updater, | 638 base::WeakPtr<VideoResourceUpdater> updater, |
| 625 const scoped_refptr<media::VideoFrame>& video_frame, | 639 const scoped_refptr<media::VideoFrame>& video_frame, |
| 626 const gpu::SyncToken& sync_token, | 640 const gpu::SyncToken& sync_token, |
| 627 bool lost_resource, | 641 bool lost_resource, |
| 628 BlockingTaskRunner* main_thread_task_runner) { | 642 BlockingTaskRunner* main_thread_task_runner) { |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 725 video_frame->coded_size(), | 739 video_frame->coded_size(), |
| 726 video_frame->metadata()->IsTrue( | 740 video_frame->metadata()->IsTrue( |
| 727 media::VideoFrameMetadata::ALLOW_OVERLAY), | 741 media::VideoFrameMetadata::ALLOW_OVERLAY), |
| 728 false); | 742 false); |
| 729 mailbox.set_color_space(video_frame->ColorSpace()); | 743 mailbox.set_color_space(video_frame->ColorSpace()); |
| 730 external_resources.mailboxes.push_back(mailbox); | 744 external_resources.mailboxes.push_back(mailbox); |
| 731 external_resources.release_callbacks.push_back( | 745 external_resources.release_callbacks.push_back( |
| 732 base::Bind(&ReturnTexture, AsWeakPtr(), video_frame)); | 746 base::Bind(&ReturnTexture, AsWeakPtr(), video_frame)); |
| 733 } | 747 } |
| 734 } | 748 } |
| 749 |
| 750 external_resources.bits_per_channel = |
| 751 (video_frame->format() == media::PIXEL_FORMAT_Y16) ? 16 : 8; |
| 735 return external_resources; | 752 return external_resources; |
| 736 } | 753 } |
| 737 | 754 |
| 738 // static | 755 // static |
| 739 void VideoResourceUpdater::RecycleResource( | 756 void VideoResourceUpdater::RecycleResource( |
| 740 base::WeakPtr<VideoResourceUpdater> updater, | 757 base::WeakPtr<VideoResourceUpdater> updater, |
| 741 ResourceId resource_id, | 758 ResourceId resource_id, |
| 742 const gpu::SyncToken& sync_token, | 759 const gpu::SyncToken& sync_token, |
| 743 bool lost_resource, | 760 bool lost_resource, |
| 744 BlockingTaskRunner* main_thread_task_runner) { | 761 BlockingTaskRunner* main_thread_task_runner) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 763 if (lost_resource) { | 780 if (lost_resource) { |
| 764 resource_it->clear_refs(); | 781 resource_it->clear_refs(); |
| 765 updater->DeleteResource(resource_it); | 782 updater->DeleteResource(resource_it); |
| 766 return; | 783 return; |
| 767 } | 784 } |
| 768 | 785 |
| 769 resource_it->remove_ref(); | 786 resource_it->remove_ref(); |
| 770 } | 787 } |
| 771 | 788 |
| 772 } // namespace cc | 789 } // namespace cc |
| OLD | NEW |