OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/renderers/skcanvas_video_renderer.h" | 5 #include "media/renderers/skcanvas_video_renderer.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "base/macros.h" | 9 #include "base/macros.h" |
10 #include "gpu/GLES2/gl2extchromium.h" | 10 #include "gpu/GLES2/gl2extchromium.h" |
11 #include "gpu/command_buffer/client/gles2_interface.h" | 11 #include "gpu/command_buffer/client/gles2_interface.h" |
12 #include "gpu/command_buffer/common/mailbox_holder.h" | 12 #include "gpu/command_buffer/common/mailbox_holder.h" |
13 #include "media/base/data_buffer.h" | |
13 #include "media/base/video_frame.h" | 14 #include "media/base/video_frame.h" |
14 #include "media/base/yuv_convert.h" | 15 #include "media/base/yuv_convert.h" |
15 #include "skia/ext/texture_handle.h" | 16 #include "skia/ext/texture_handle.h" |
16 #include "third_party/libyuv/include/libyuv.h" | 17 #include "third_party/libyuv/include/libyuv.h" |
17 #include "third_party/skia/include/core/SkCanvas.h" | 18 #include "third_party/skia/include/core/SkCanvas.h" |
18 #include "third_party/skia/include/core/SkImage.h" | 19 #include "third_party/skia/include/core/SkImage.h" |
19 #include "third_party/skia/include/core/SkImageGenerator.h" | 20 #include "third_party/skia/include/core/SkImageGenerator.h" |
20 #include "third_party/skia/include/gpu/GrContext.h" | 21 #include "third_party/skia/include/gpu/GrContext.h" |
21 #include "third_party/skia/include/gpu/GrPaint.h" | 22 #include "third_party/skia/include/gpu/GrPaint.h" |
22 #include "third_party/skia/include/gpu/GrTexture.h" | 23 #include "third_party/skia/include/gpu/GrTexture.h" |
(...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
515 for (int x = 0; x < width; x++) { | 516 for (int x = 0; x < width; x++) { |
516 dst[x] = src[x] >> shift; | 517 dst[x] = src[x] >> shift; |
517 } | 518 } |
518 src += video_frame->stride(plane) / 2; | 519 src += video_frame->stride(plane) / 2; |
519 dst += ret->stride(plane); | 520 dst += ret->stride(plane); |
520 } | 521 } |
521 } | 522 } |
522 return ret; | 523 return ret; |
523 } | 524 } |
524 | 525 |
525 // We take the upper 8 bits of 16-bit data and convert it as luminance to ARGB. | 526 // Converts 16-bit data to |out| buffer of specified GL |type|. |
526 // We loose the precision here, but it is important not to render Y16 as RG_88. | 527 // When the |format| is RGBA, the converted value is fed as luminance. |
527 // To get the full precision use float textures with WebGL1 and e.g. R16UI or | 528 void FlipAndConvertY16(const VideoFrame* video_frame, |
528 // R32F textures with WebGL2. | 529 uint8_t* out, |
529 void ConvertY16ToARGB(const VideoFrame* video_frame, | 530 unsigned format, |
530 void* argb_pixels, | 531 unsigned type, |
531 size_t argb_row_bytes) { | 532 bool flip_y, |
533 size_t output_row_bytes) { | |
532 const uint8_t* row_head = video_frame->visible_data(0); | 534 const uint8_t* row_head = video_frame->visible_data(0); |
533 uint8_t* out = static_cast<uint8_t*>(argb_pixels); | |
534 const size_t stride = video_frame->stride(0); | 535 const size_t stride = video_frame->stride(0); |
535 for (int i = 0; i < video_frame->visible_rect().height(); ++i) { | 536 const int height = video_frame->visible_rect().height(); |
536 uint32_t* rgba = reinterpret_cast<uint32_t*>(out); | 537 for (int i = 0; i < height; ++i) { |
537 const uint8_t* row_end = row_head + video_frame->visible_rect().width() * 2; | 538 uint8_t* out_row_head = flip_y ? out + output_row_bytes * (height - i - 1) |
Ken Russell (switch to Gerrit)
2016/12/01 08:39:34
Perhaps add a TODO about adding SIMD or similar op
| |
538 for (const uint8_t* row = row_head; row < row_end; ++row) { | 539 : out + output_row_bytes * i; |
539 uint32_t gray_value = *++row; | 540 const uint16_t* row = reinterpret_cast<const uint16_t*>(row_head); |
540 *rgba++ = SkColorSetRGB(gray_value, gray_value, gray_value); | 541 const uint16_t* row_end = row + video_frame->visible_rect().width(); |
542 if (type == GL_FLOAT) { | |
543 DCHECK_EQ(static_cast<unsigned>(GL_RGBA), format); | |
544 float* out_row = reinterpret_cast<float*>(out_row_head); | |
545 while (row < row_end) { | |
546 float gray_value = *row++ / 65535.f; | |
547 *out_row++ = gray_value; | |
548 *out_row++ = gray_value; | |
549 *out_row++ = gray_value; | |
550 *out_row++ = 1.0f; | |
551 } | |
552 } else if (type == GL_UNSIGNED_BYTE) { | |
553 // We take the upper 8 bits of 16-bit data and convert it as luminance to | |
554 // ARGB. We loose the precision here, but it is important not to render | |
555 // Y16 as RG_88. To get the full precision use float textures with WebGL1 | |
556 // and e.g. R16UI or R32F textures with WebGL2. | |
557 DCHECK_EQ(static_cast<unsigned>(GL_RGBA), format); | |
558 uint32_t* rgba = reinterpret_cast<uint32_t*>(out_row_head); | |
559 while (row < row_end) { | |
560 uint32_t gray_value = *row++ >> 8; | |
561 *rgba++ = SkColorSetRGB(gray_value, gray_value, gray_value); | |
562 } | |
563 } else { | |
564 NOTREACHED() << "Unsupported Y16 conversion for format: 0x" << std::hex | |
565 << format << " and type: 0x" << std::hex << type; | |
541 } | 566 } |
542 out += argb_row_bytes; | |
543 row_head += stride; | 567 row_head += stride; |
544 } | 568 } |
545 } | 569 } |
546 | 570 |
571 // Common functionality of SkCanvasVideoRenderer's TexImage2D and TexSubImage2D. | |
572 // Allocates a buffer required for conversion and converts |frame| content to | |
573 // desired |format|. | |
574 // Returns true if calling glTex(Sub)Image is supported for provided |frame| | |
575 // format and parameters. | |
576 bool TexImageHelper(VideoFrame* frame, | |
577 unsigned format, | |
578 unsigned type, | |
579 bool flip_y, | |
580 scoped_refptr<DataBuffer>& temp_buffer) { | |
Ken Russell (switch to Gerrit)
2016/12/01 08:39:34
Mutable references are not allowed per the Google
aleksandar.stojiljkovic
2016/12/02 20:23:41
Done.
| |
581 unsigned output_bytes_per_pixel = 0; | |
582 switch (frame->format()) { | |
583 case PIXEL_FORMAT_Y16: | |
584 // Converting single component unsigned short here to FLOAT luminance. | |
585 switch (format) { | |
586 case GL_RGBA: | |
587 if (type == GL_FLOAT) { | |
588 output_bytes_per_pixel = 4 * sizeof(GLfloat); | |
589 break; | |
590 } | |
591 // Pass through. | |
592 default: | |
593 return false; | |
594 } | |
595 break; | |
596 default: | |
597 return false; | |
598 } | |
599 | |
600 size_t output_row_bytes = | |
601 frame->visible_rect().width() * output_bytes_per_pixel; | |
602 temp_buffer = | |
603 new DataBuffer(output_row_bytes * frame->visible_rect().height()); | |
604 FlipAndConvertY16(frame, temp_buffer->writable_data(), format, type, flip_y, | |
605 output_row_bytes); | |
606 return true; | |
607 } | |
608 | |
547 } // anonymous namespace | 609 } // anonymous namespace |
548 | 610 |
549 // static | 611 // static |
550 void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( | 612 void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( |
551 const VideoFrame* video_frame, | 613 const VideoFrame* video_frame, |
552 void* rgb_pixels, | 614 void* rgb_pixels, |
553 size_t row_bytes) { | 615 size_t row_bytes) { |
554 if (!video_frame->IsMappable()) { | 616 if (!video_frame->IsMappable()) { |
555 NOTREACHED() << "Cannot extract pixels from non-CPU frame formats."; | 617 NOTREACHED() << "Cannot extract pixels from non-CPU frame formats."; |
556 return; | 618 return; |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
641 case PIXEL_FORMAT_YUV422P12: | 703 case PIXEL_FORMAT_YUV422P12: |
642 case PIXEL_FORMAT_YUV444P12: { | 704 case PIXEL_FORMAT_YUV444P12: { |
643 scoped_refptr<VideoFrame> temporary_frame = | 705 scoped_refptr<VideoFrame> temporary_frame = |
644 DownShiftHighbitVideoFrame(video_frame); | 706 DownShiftHighbitVideoFrame(video_frame); |
645 ConvertVideoFrameToRGBPixels(temporary_frame.get(), rgb_pixels, | 707 ConvertVideoFrameToRGBPixels(temporary_frame.get(), rgb_pixels, |
646 row_bytes); | 708 row_bytes); |
647 break; | 709 break; |
648 } | 710 } |
649 | 711 |
650 case PIXEL_FORMAT_Y16: | 712 case PIXEL_FORMAT_Y16: |
651 ConvertY16ToARGB(video_frame, rgb_pixels, row_bytes); | 713 // Since it is grayscale conversion, we disregard SK_PMCOLOR_BYTE_ORDER |
714 // and always use GL_RGBA. | |
715 FlipAndConvertY16(video_frame, static_cast<uint8_t*>(rgb_pixels), GL_RGBA, | |
716 GL_UNSIGNED_BYTE, false /*flip_y*/, row_bytes); | |
652 break; | 717 break; |
653 | 718 |
654 case PIXEL_FORMAT_NV12: | 719 case PIXEL_FORMAT_NV12: |
655 case PIXEL_FORMAT_NV21: | 720 case PIXEL_FORMAT_NV21: |
656 case PIXEL_FORMAT_UYVY: | 721 case PIXEL_FORMAT_UYVY: |
657 case PIXEL_FORMAT_YUY2: | 722 case PIXEL_FORMAT_YUY2: |
658 case PIXEL_FORMAT_ARGB: | 723 case PIXEL_FORMAT_ARGB: |
659 case PIXEL_FORMAT_XRGB: | 724 case PIXEL_FORMAT_XRGB: |
660 case PIXEL_FORMAT_RGB24: | 725 case PIXEL_FORMAT_RGB24: |
661 case PIXEL_FORMAT_RGB32: | 726 case PIXEL_FORMAT_RGB32: |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
765 video_frame->UpdateReleaseSyncToken(&client); | 830 video_frame->UpdateReleaseSyncToken(&client); |
766 } else { | 831 } else { |
767 CopyVideoFrameSingleTextureToGLTexture(destination_gl, video_frame.get(), | 832 CopyVideoFrameSingleTextureToGLTexture(destination_gl, video_frame.get(), |
768 texture, internal_format, type, | 833 texture, internal_format, type, |
769 premultiply_alpha, flip_y); | 834 premultiply_alpha, flip_y); |
770 } | 835 } |
771 | 836 |
772 return true; | 837 return true; |
773 } | 838 } |
774 | 839 |
840 bool SkCanvasVideoRenderer::TexImage2D(unsigned target, | |
841 gpu::gles2::GLES2Interface* gl, | |
842 VideoFrame* frame, | |
843 int level, | |
844 int internalformat, | |
845 unsigned format, | |
846 unsigned type, | |
847 bool flip_y, | |
848 bool premultiply_alpha) { | |
849 DCHECK(frame); | |
850 DCHECK(!frame->HasTextures()); | |
851 | |
852 scoped_refptr<DataBuffer> temp_buffer; | |
853 if (!TexImageHelper(frame, format, type, flip_y, temp_buffer)) | |
854 return false; | |
855 | |
856 gl->TexImage2D(target, level, internalformat, frame->visible_rect().width(), | |
857 frame->visible_rect().height(), 0, format, type, | |
858 temp_buffer->data()); | |
859 return true; | |
860 } | |
861 | |
862 bool SkCanvasVideoRenderer::TexSubImage2D(unsigned target, | |
863 gpu::gles2::GLES2Interface* gl, | |
864 VideoFrame* frame, | |
865 int level, | |
866 unsigned format, | |
867 unsigned type, | |
868 int xoffset, | |
869 int yoffset, | |
870 bool flip_y, | |
871 bool premultiply_alpha) { | |
872 DCHECK(frame); | |
873 DCHECK(!frame->HasTextures()); | |
874 | |
875 scoped_refptr<DataBuffer> temp_buffer; | |
876 if (!TexImageHelper(frame, format, type, flip_y, temp_buffer)) | |
877 return false; | |
878 | |
879 gl->TexSubImage2D( | |
880 target, level, xoffset, yoffset, frame->visible_rect().width(), | |
881 frame->visible_rect().height(), format, type, temp_buffer->data()); | |
882 return true; | |
883 } | |
884 | |
775 void SkCanvasVideoRenderer::ResetCache() { | 885 void SkCanvasVideoRenderer::ResetCache() { |
776 DCHECK(thread_checker_.CalledOnValidThread()); | 886 DCHECK(thread_checker_.CalledOnValidThread()); |
777 // Clear cached values. | 887 // Clear cached values. |
778 last_image_ = nullptr; | 888 last_image_ = nullptr; |
779 last_timestamp_ = kNoTimestamp; | 889 last_timestamp_ = kNoTimestamp; |
780 } | 890 } |
781 | 891 |
782 bool SkCanvasVideoRenderer::UpdateLastImage( | 892 bool SkCanvasVideoRenderer::UpdateLastImage( |
783 const scoped_refptr<VideoFrame>& video_frame, | 893 const scoped_refptr<VideoFrame>& video_frame, |
784 const Context3D& context_3d) { | 894 const Context3D& context_3d) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
822 last_image_->bounds().contains(visible_rect)) { | 932 last_image_->bounds().contains(visible_rect)) { |
823 last_image_ = last_image_->makeSubset(visible_rect); | 933 last_image_ = last_image_->makeSubset(visible_rect); |
824 } | 934 } |
825 } | 935 } |
826 | 936 |
827 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() { | 937 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() { |
828 return last_image_dimensions_for_testing_; | 938 return last_image_dimensions_for_testing_; |
829 } | 939 } |
830 | 940 |
831 } // namespace media | 941 } // namespace media |
OLD | NEW |