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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 switch (video_frame->mailbox_holder(0).texture_target) { | 62 switch (video_frame->mailbox_holder(0).texture_target) { |
63 case GL_TEXTURE_EXTERNAL_OES: | 63 case GL_TEXTURE_EXTERNAL_OES: |
64 return VideoFrameExternalResources::YUV_RESOURCE; | 64 return VideoFrameExternalResources::YUV_RESOURCE; |
65 case GL_TEXTURE_RECTANGLE_ARB: | 65 case GL_TEXTURE_RECTANGLE_ARB: |
66 return VideoFrameExternalResources::RGB_RESOURCE; | 66 return VideoFrameExternalResources::RGB_RESOURCE; |
67 default: | 67 default: |
68 NOTREACHED(); | 68 NOTREACHED(); |
69 break; | 69 break; |
70 } | 70 } |
71 break; | 71 break; |
| 72 case media::PIXEL_FORMAT_Y16: |
| 73 return VideoFrameExternalResources::Y_RESOURCE; |
| 74 break; |
72 case media::PIXEL_FORMAT_YV12: | 75 case media::PIXEL_FORMAT_YV12: |
73 case media::PIXEL_FORMAT_YV16: | 76 case media::PIXEL_FORMAT_YV16: |
74 case media::PIXEL_FORMAT_YV24: | 77 case media::PIXEL_FORMAT_YV24: |
75 case media::PIXEL_FORMAT_YV12A: | 78 case media::PIXEL_FORMAT_YV12A: |
76 case media::PIXEL_FORMAT_NV21: | 79 case media::PIXEL_FORMAT_NV21: |
77 case media::PIXEL_FORMAT_YUY2: | 80 case media::PIXEL_FORMAT_YUY2: |
78 case media::PIXEL_FORMAT_RGB24: | 81 case media::PIXEL_FORMAT_RGB24: |
79 case media::PIXEL_FORMAT_RGB32: | 82 case media::PIXEL_FORMAT_RGB32: |
80 case media::PIXEL_FORMAT_MJPEG: | 83 case media::PIXEL_FORMAT_MJPEG: |
81 case media::PIXEL_FORMAT_MT21: | 84 case media::PIXEL_FORMAT_MT21: |
82 case media::PIXEL_FORMAT_YUV420P9: | 85 case media::PIXEL_FORMAT_YUV420P9: |
83 case media::PIXEL_FORMAT_YUV422P9: | 86 case media::PIXEL_FORMAT_YUV422P9: |
84 case media::PIXEL_FORMAT_YUV444P9: | 87 case media::PIXEL_FORMAT_YUV444P9: |
85 case media::PIXEL_FORMAT_YUV420P10: | 88 case media::PIXEL_FORMAT_YUV420P10: |
86 case media::PIXEL_FORMAT_YUV422P10: | 89 case media::PIXEL_FORMAT_YUV422P10: |
87 case media::PIXEL_FORMAT_YUV444P10: | 90 case media::PIXEL_FORMAT_YUV444P10: |
88 case media::PIXEL_FORMAT_YUV420P12: | 91 case media::PIXEL_FORMAT_YUV420P12: |
89 case media::PIXEL_FORMAT_YUV422P12: | 92 case media::PIXEL_FORMAT_YUV422P12: |
90 case media::PIXEL_FORMAT_YUV444P12: | 93 case media::PIXEL_FORMAT_YUV444P12: |
91 case media::PIXEL_FORMAT_Y8: | 94 case media::PIXEL_FORMAT_Y8: |
92 case media::PIXEL_FORMAT_Y16: | |
93 case media::PIXEL_FORMAT_UNKNOWN: | 95 case media::PIXEL_FORMAT_UNKNOWN: |
94 break; | 96 break; |
95 } | 97 } |
96 return VideoFrameExternalResources::NONE; | 98 return VideoFrameExternalResources::NONE; |
97 } | 99 } |
98 | 100 |
99 class SyncTokenClientImpl : public media::VideoFrame::SyncTokenClient { | 101 class SyncTokenClientImpl : public media::VideoFrame::SyncTokenClient { |
100 public: | 102 public: |
101 SyncTokenClientImpl(gpu::gles2::GLES2Interface* gl, | 103 SyncTokenClientImpl(gpu::gles2::GLES2Interface* gl, |
102 const gpu::SyncToken& sync_token) | 104 const gpu::SyncToken& sync_token) |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 // Maximum value used in |src|. | 307 // Maximum value used in |src|. |
306 int max_value = (1 << bits_per_channel) - 1; | 308 int max_value = (1 << bits_per_channel) - 1; |
307 int rows = 1; | 309 int rows = 1; |
308 libyuv::HalfFloatPlane(src, stride, dst, stride, 1.0f / max_value, num, rows); | 310 libyuv::HalfFloatPlane(src, stride, dst, stride, 1.0f / max_value, num, rows); |
309 } | 311 } |
310 | 312 |
311 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( | 313 VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( |
312 scoped_refptr<media::VideoFrame> video_frame) { | 314 scoped_refptr<media::VideoFrame> video_frame) { |
313 TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes"); | 315 TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes"); |
314 const media::VideoPixelFormat input_frame_format = video_frame->format(); | 316 const media::VideoPixelFormat input_frame_format = video_frame->format(); |
315 | |
316 // TODO(hubbe): Make this a video frame method. | 317 // TODO(hubbe): Make this a video frame method. |
317 int bits_per_channel = 0; | 318 int bits_per_channel = 0; |
318 switch (input_frame_format) { | 319 switch (input_frame_format) { |
319 case media::PIXEL_FORMAT_UNKNOWN: | 320 case media::PIXEL_FORMAT_UNKNOWN: |
320 NOTREACHED(); | 321 NOTREACHED(); |
321 // Fall through! | 322 // Fall through! |
322 case media::PIXEL_FORMAT_I420: | 323 case media::PIXEL_FORMAT_I420: |
323 case media::PIXEL_FORMAT_YV12: | 324 case media::PIXEL_FORMAT_YV12: |
324 case media::PIXEL_FORMAT_YV16: | 325 case media::PIXEL_FORMAT_YV16: |
325 case media::PIXEL_FORMAT_YV12A: | 326 case media::PIXEL_FORMAT_YV12A: |
(...skipping 24 matching lines...) Expand all Loading... |
350 case media::PIXEL_FORMAT_YUV420P12: | 351 case media::PIXEL_FORMAT_YUV420P12: |
351 case media::PIXEL_FORMAT_YUV422P12: | 352 case media::PIXEL_FORMAT_YUV422P12: |
352 case media::PIXEL_FORMAT_YUV444P12: | 353 case media::PIXEL_FORMAT_YUV444P12: |
353 bits_per_channel = 12; | 354 bits_per_channel = 12; |
354 break; | 355 break; |
355 case media::PIXEL_FORMAT_Y16: | 356 case media::PIXEL_FORMAT_Y16: |
356 bits_per_channel = 16; | 357 bits_per_channel = 16; |
357 break; | 358 break; |
358 } | 359 } |
359 | 360 |
360 // TODO(dshwang): support PIXEL_FORMAT_Y16. crbug.com/624436 | 361 // Only YUV and Y16 software video frames are supported. |
361 DCHECK_NE(bits_per_channel, 16); | 362 const bool isYuvPlanar = media::IsYuvPlanar(input_frame_format); |
362 | 363 if (!(isYuvPlanar || input_frame_format == media::PIXEL_FORMAT_Y16)) { |
363 // Only YUV software video frames are supported. | |
364 if (!media::IsYuvPlanar(input_frame_format)) { | |
365 NOTREACHED() << media::VideoPixelFormatToString(input_frame_format); | 364 NOTREACHED() << media::VideoPixelFormatToString(input_frame_format); |
366 return VideoFrameExternalResources(); | 365 return VideoFrameExternalResources(); |
367 } | 366 } |
368 | 367 |
369 const bool software_compositor = context_provider_ == NULL; | 368 const bool software_compositor = context_provider_ == NULL; |
370 | 369 |
371 ResourceFormat output_resource_format = | 370 ResourceFormat output_resource_format = |
372 resource_provider_->YuvResourceFormat(bits_per_channel); | 371 (input_frame_format == media::PIXEL_FORMAT_Y16) |
| 372 ? resource_provider_->Y16ResourceFormat() |
| 373 : resource_provider_->YuvResourceFormat(bits_per_channel); |
373 | 374 |
374 // If GPU compositing is enabled, but the output resource format | 375 // If GPU compositing is enabled, but the output resource format |
375 // returned by the resource provider is RGBA_8888, then a GPU driver | 376 // returned by the resource provider is RGBA_8888, then a GPU driver |
376 // bug workaround requires that YUV frames must be converted to RGB | 377 // bug workaround requires that YUV frames must be converted to RGB |
377 // before texture upload. | 378 // before texture upload. |
378 bool texture_needs_rgb_conversion = | 379 bool texture_needs_rgb_conversion = |
379 !software_compositor && | 380 !software_compositor && |
380 output_resource_format == ResourceFormat::RGBA_8888; | 381 output_resource_format == ResourceFormat::RGBA_8888 && |
| 382 input_frame_format != media::PIXEL_FORMAT_Y16; |
381 size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format); | 383 size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format); |
382 | 384 |
383 // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB | 385 // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB |
384 // conversion here. That involves an extra copy of each frame to a bitmap. | 386 // conversion here. That involves an extra copy of each frame to a bitmap. |
385 // Obviously, this is suboptimal and should be addressed once ubercompositor | 387 // Obviously, this is suboptimal and should be addressed once ubercompositor |
386 // starts shaping up. | 388 // starts shaping up. |
387 if (software_compositor || texture_needs_rgb_conversion) { | 389 if (software_compositor || texture_needs_rgb_conversion) { |
388 output_resource_format = kRGBResourceFormat; | 390 output_resource_format = kRGBResourceFormat; |
389 output_plane_count = 1; | 391 output_plane_count = 1; |
390 bits_per_channel = 8; | 392 bits_per_channel = 8; |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 external_resources.release_callbacks.push_back(base::Bind( | 481 external_resources.release_callbacks.push_back(base::Bind( |
480 &RecycleResource, AsWeakPtr(), plane_resource.resource_id())); | 482 &RecycleResource, AsWeakPtr(), plane_resource.resource_id())); |
481 external_resources.type = VideoFrameExternalResources::RGBA_RESOURCE; | 483 external_resources.type = VideoFrameExternalResources::RGBA_RESOURCE; |
482 } | 484 } |
483 return external_resources; | 485 return external_resources; |
484 } | 486 } |
485 | 487 |
486 for (size_t i = 0; i < plane_resources.size(); ++i) { | 488 for (size_t i = 0; i < plane_resources.size(); ++i) { |
487 PlaneResource& plane_resource = *plane_resources[i]; | 489 PlaneResource& plane_resource = *plane_resources[i]; |
488 // Update each plane's resource id with its content. | 490 // Update each plane's resource id with its content. |
489 DCHECK_EQ(plane_resource.resource_format(), | 491 DCHECK_EQ(plane_resource.resource_format(), output_resource_format); |
490 resource_provider_->YuvResourceFormat(bits_per_channel)); | |
491 | 492 |
492 if (!plane_resource.Matches(video_frame->unique_id(), i)) { | 493 if (!plane_resource.Matches(video_frame->unique_id(), i)) { |
493 // TODO(hubbe): Move all conversion (and upload?) code to media/. | 494 // TODO(hubbe): Move all conversion (and upload?) code to media/. |
494 // We need to transfer data from |video_frame| to the plane resource. | 495 // We need to transfer data from |video_frame| to the plane resource. |
495 // TODO(reveman): Can use GpuMemoryBuffers here to improve performance. | 496 // TODO(reveman): Can use GpuMemoryBuffers here to improve performance. |
496 | 497 |
497 // The |resource_size_pixels| is the size of the resource we want to | 498 // The |resource_size_pixels| is the size of the resource we want to |
498 // upload to. | 499 // upload to. |
499 gfx::Size resource_size_pixels = plane_resource.resource_size(); | 500 gfx::Size resource_size_pixels = plane_resource.resource_size(); |
500 // The |video_stride_bytes| is the width of the video frame we are | 501 // The |video_stride_bytes| is the width of the video frame we are |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
535 // https://en.wikipedia.org/wiki/Half-precision_floating-point_format | 536 // https://en.wikipedia.org/wiki/Half-precision_floating-point_format |
536 // | 537 // |
537 // PLEASE NOTE: | 538 // PLEASE NOTE: |
538 // All planes are assumed to use the same multiplier/offset. | 539 // All planes are assumed to use the same multiplier/offset. |
539 external_resources.offset = 0.5f; | 540 external_resources.offset = 0.5f; |
540 // Max value from input data. | 541 // Max value from input data. |
541 int max_input_value = (1 << bits_per_channel) - 1; | 542 int max_input_value = (1 << bits_per_channel) - 1; |
542 // 2 << 11 = 2048 would be 1.0 with our exponent. | 543 // 2 << 11 = 2048 would be 1.0 with our exponent. |
543 external_resources.multiplier = 2048.0 / max_input_value; | 544 external_resources.multiplier = 2048.0 / max_input_value; |
544 } | 545 } |
| 546 } else if (input_frame_format == media::PIXEL_FORMAT_Y16) { |
| 547 if (plane_resource.resource_format() == RGBA_8888) |
| 548 needs_conversion = true; |
545 } else if (bits_per_channel > 8) { | 549 } else if (bits_per_channel > 8) { |
546 // If bits_per_channel > 8 and we can't use LUMINANCE_F16, we need to | 550 // If bits_per_channel > 8 and we can't use LUMINANCE_F16, we need to |
547 // shift the data down and create an 8-bit texture. | 551 // shift the data down and create an 8-bit texture. |
548 needs_conversion = true; | 552 needs_conversion = true; |
549 shift = bits_per_channel - 8; | 553 shift = bits_per_channel - 8; |
550 } | 554 } |
551 const uint8_t* pixels; | 555 const uint8_t* pixels; |
552 if (static_cast<int>(upload_image_stride) == video_stride_bytes && | 556 if (static_cast<int>(upload_image_stride) == video_stride_bytes && |
553 !needs_conversion) { | 557 !needs_conversion) { |
554 pixels = video_frame->data(i); | 558 pixels = video_frame->data(i); |
(...skipping 22 matching lines...) Expand all Loading... |
577 MakeHalfFloats(src, bits_per_channel, bytes_per_row / 2, dst); | 581 MakeHalfFloats(src, bits_per_channel, bytes_per_row / 2, dst); |
578 } | 582 } |
579 } else if (shift != 0) { | 583 } else if (shift != 0) { |
580 // We have more-than-8-bit input which we need to shift | 584 // We have more-than-8-bit input which we need to shift |
581 // down to fit it into an 8-bit texture. | 585 // down to fit it into an 8-bit texture. |
582 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; | 586 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; |
583 const uint16_t* src = reinterpret_cast<uint16_t*>( | 587 const uint16_t* src = reinterpret_cast<uint16_t*>( |
584 video_frame->data(i) + (video_stride_bytes * row)); | 588 video_frame->data(i) + (video_stride_bytes * row)); |
585 for (size_t i = 0; i < bytes_per_row; i++) | 589 for (size_t i = 0; i < bytes_per_row; i++) |
586 dst[i] = src[i] >> shift; | 590 dst[i] = src[i] >> shift; |
| 591 } else if (input_frame_format == media::PIXEL_FORMAT_Y16 && |
| 592 plane_resource.resource_format() == RGBA_8888) { |
| 593 uint32_t* dst = reinterpret_cast<uint32_t*>( |
| 594 &upload_pixels_[upload_image_stride * row]); |
| 595 const uint16_t* src = reinterpret_cast<uint16_t*>( |
| 596 video_frame->data(i) + (video_stride_bytes * row)); |
| 597 for (size_t i = 0; i < bytes_per_row / 4; ++i) |
| 598 *dst++ = *src++; |
587 } else { | 599 } else { |
588 // Input and output are the same size and format, but | 600 // Input and output are the same size and format, but |
589 // differ in stride, copy one row at a time. | 601 // differ in stride, copy one row at a time. |
590 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; | 602 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; |
591 const uint8_t* src = | 603 const uint8_t* src = |
592 video_frame->data(i) + (video_stride_bytes * row); | 604 video_frame->data(i) + (video_stride_bytes * row); |
593 memcpy(dst, src, bytes_per_row); | 605 memcpy(dst, src, bytes_per_row); |
594 } | 606 } |
595 } | 607 } |
596 pixels = &upload_pixels_[0]; | 608 pixels = &upload_pixels_[0]; |
597 } | 609 } |
598 | 610 |
599 resource_provider_->CopyToResource(plane_resource.resource_id(), pixels, | 611 resource_provider_->CopyToResource(plane_resource.resource_id(), pixels, |
600 resource_size_pixels); | 612 resource_size_pixels); |
601 plane_resource.SetUniqueId(video_frame->unique_id(), i); | 613 plane_resource.SetUniqueId(video_frame->unique_id(), i); |
602 } | 614 } |
603 | 615 |
604 | 616 |
605 // VideoResourceUpdater shares a context with the compositor so a | 617 // VideoResourceUpdater shares a context with the compositor so a |
606 // sync token is not required. | 618 // sync token is not required. |
607 TextureMailbox mailbox(plane_resource.mailbox(), gpu::SyncToken(), | 619 TextureMailbox mailbox(plane_resource.mailbox(), gpu::SyncToken(), |
608 resource_provider_->GetResourceTextureTarget( | 620 resource_provider_->GetResourceTextureTarget( |
609 plane_resource.resource_id())); | 621 plane_resource.resource_id())); |
610 mailbox.set_color_space(video_frame->ColorSpace()); | 622 mailbox.set_color_space(video_frame->ColorSpace()); |
611 external_resources.mailboxes.push_back(mailbox); | 623 external_resources.mailboxes.push_back(mailbox); |
612 external_resources.release_callbacks.push_back(base::Bind( | 624 external_resources.release_callbacks.push_back(base::Bind( |
613 &RecycleResource, AsWeakPtr(), plane_resource.resource_id())); | 625 &RecycleResource, AsWeakPtr(), plane_resource.resource_id())); |
614 } | 626 } |
615 | 627 |
616 external_resources.type = VideoFrameExternalResources::YUV_RESOURCE; | 628 external_resources.type = (input_frame_format == media::PIXEL_FORMAT_Y16) |
| 629 ? VideoFrameExternalResources::Y_RESOURCE |
| 630 : VideoFrameExternalResources::YUV_RESOURCE; |
617 return external_resources; | 631 return external_resources; |
618 } | 632 } |
619 | 633 |
620 // static | 634 // static |
621 void VideoResourceUpdater::ReturnTexture( | 635 void VideoResourceUpdater::ReturnTexture( |
622 base::WeakPtr<VideoResourceUpdater> updater, | 636 base::WeakPtr<VideoResourceUpdater> updater, |
623 const scoped_refptr<media::VideoFrame>& video_frame, | 637 const scoped_refptr<media::VideoFrame>& video_frame, |
624 const gpu::SyncToken& sync_token, | 638 const gpu::SyncToken& sync_token, |
625 bool lost_resource, | 639 bool lost_resource, |
626 BlockingTaskRunner* main_thread_task_runner) { | 640 BlockingTaskRunner* main_thread_task_runner) { |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
723 video_frame->coded_size(), | 737 video_frame->coded_size(), |
724 video_frame->metadata()->IsTrue( | 738 video_frame->metadata()->IsTrue( |
725 media::VideoFrameMetadata::ALLOW_OVERLAY), | 739 media::VideoFrameMetadata::ALLOW_OVERLAY), |
726 false); | 740 false); |
727 mailbox.set_color_space(video_frame->ColorSpace()); | 741 mailbox.set_color_space(video_frame->ColorSpace()); |
728 external_resources.mailboxes.push_back(mailbox); | 742 external_resources.mailboxes.push_back(mailbox); |
729 external_resources.release_callbacks.push_back( | 743 external_resources.release_callbacks.push_back( |
730 base::Bind(&ReturnTexture, AsWeakPtr(), video_frame)); | 744 base::Bind(&ReturnTexture, AsWeakPtr(), video_frame)); |
731 } | 745 } |
732 } | 746 } |
| 747 |
| 748 external_resources.bits_per_channel = |
| 749 (video_frame->format() == media::PIXEL_FORMAT_Y16) ? 16 : 8; |
733 return external_resources; | 750 return external_resources; |
734 } | 751 } |
735 | 752 |
736 // static | 753 // static |
737 void VideoResourceUpdater::RecycleResource( | 754 void VideoResourceUpdater::RecycleResource( |
738 base::WeakPtr<VideoResourceUpdater> updater, | 755 base::WeakPtr<VideoResourceUpdater> updater, |
739 ResourceId resource_id, | 756 ResourceId resource_id, |
740 const gpu::SyncToken& sync_token, | 757 const gpu::SyncToken& sync_token, |
741 bool lost_resource, | 758 bool lost_resource, |
742 BlockingTaskRunner* main_thread_task_runner) { | 759 BlockingTaskRunner* main_thread_task_runner) { |
(...skipping 18 matching lines...) Expand all Loading... |
761 if (lost_resource) { | 778 if (lost_resource) { |
762 resource_it->clear_refs(); | 779 resource_it->clear_refs(); |
763 updater->DeleteResource(resource_it); | 780 updater->DeleteResource(resource_it); |
764 return; | 781 return; |
765 } | 782 } |
766 | 783 |
767 resource_it->remove_ref(); | 784 resource_it->remove_ref(); |
768 } | 785 } |
769 | 786 |
770 } // namespace cc | 787 } // namespace cc |
OLD | NEW |