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 <GLES3/gl3.h> | |
7 #include <limits> | 8 #include <limits> |
8 | 9 |
9 #include "base/macros.h" | 10 #include "base/macros.h" |
10 #include "gpu/GLES2/gl2extchromium.h" | 11 #include "gpu/GLES2/gl2extchromium.h" |
11 #include "gpu/command_buffer/client/gles2_interface.h" | 12 #include "gpu/command_buffer/client/gles2_interface.h" |
12 #include "gpu/command_buffer/common/mailbox_holder.h" | 13 #include "gpu/command_buffer/common/mailbox_holder.h" |
14 #include "media/base/data_buffer.h" | |
13 #include "media/base/video_frame.h" | 15 #include "media/base/video_frame.h" |
14 #include "media/base/yuv_convert.h" | 16 #include "media/base/yuv_convert.h" |
15 #include "skia/ext/texture_handle.h" | 17 #include "skia/ext/texture_handle.h" |
16 #include "third_party/libyuv/include/libyuv.h" | 18 #include "third_party/libyuv/include/libyuv.h" |
17 #include "third_party/skia/include/core/SkCanvas.h" | 19 #include "third_party/skia/include/core/SkCanvas.h" |
18 #include "third_party/skia/include/core/SkImage.h" | 20 #include "third_party/skia/include/core/SkImage.h" |
19 #include "third_party/skia/include/core/SkImageGenerator.h" | 21 #include "third_party/skia/include/core/SkImageGenerator.h" |
20 #include "third_party/skia/include/gpu/GrContext.h" | 22 #include "third_party/skia/include/gpu/GrContext.h" |
21 #include "third_party/skia/include/gpu/GrPaint.h" | 23 #include "third_party/skia/include/gpu/GrPaint.h" |
22 #include "third_party/skia/include/gpu/GrTexture.h" | 24 #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++) { | 517 for (int x = 0; x < width; x++) { |
516 dst[x] = src[x] >> shift; | 518 dst[x] = src[x] >> shift; |
517 } | 519 } |
518 src += video_frame->stride(plane) / 2; | 520 src += video_frame->stride(plane) / 2; |
519 dst += ret->stride(plane); | 521 dst += ret->stride(plane); |
520 } | 522 } |
521 } | 523 } |
522 return ret; | 524 return ret; |
523 } | 525 } |
524 | 526 |
525 // We take the upper 8 bits of 16-bit data and convert it as luminance to ARGB. | 527 void FlipAndConvertY16(const VideoFrame* video_frame, |
hubbe
2016/11/07 22:16:55
Add comment.
aleksandar.stojiljkovic
2016/11/16 20:01:24
Done.
| |
526 // We loose the precision here, but it is important not to render Y16 as RG_88. | 528 uint8_t* out, |
527 // To get the full precision use float textures with WebGL1 and e.g. R16UI or | 529 unsigned format, |
528 // R32F textures with WebGL2. | 530 unsigned type, |
529 void ConvertY16ToARGB(const VideoFrame* video_frame, | 531 bool flip_y, |
530 void* argb_pixels, | 532 size_t output_row_bytes) { |
531 size_t argb_row_bytes) { | |
532 const uint8_t* row_head = video_frame->visible_data(0); | 533 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); | 534 const size_t stride = video_frame->stride(0); |
535 for (int i = 0; i < video_frame->visible_rect().height(); ++i) { | 535 const int height = video_frame->visible_rect().height(); |
536 uint32_t* rgba = reinterpret_cast<uint32_t*>(out); | 536 for (int i = 0; i < height; ++i) { |
537 const uint8_t* row_end = row_head + video_frame->visible_rect().width() * 2; | 537 uint8_t* out_row_head = flip_y ? out + output_row_bytes * (height - i - 1) |
538 for (const uint8_t* row = row_head; row < row_end; ++row) { | 538 : out + output_row_bytes * i; |
539 uint32_t gray_value = *++row; | 539 const uint16_t* row = reinterpret_cast<const uint16_t*>(row_head); |
540 *rgba++ = SkColorSetRGB(gray_value, gray_value, gray_value); | 540 const uint16_t* row_end = row + video_frame->visible_rect().width(); |
541 if (type == GL_FLOAT && format == GL_RGBA) { | |
542 float* out_row = reinterpret_cast<float*>(out_row_head); | |
543 while (row < row_end) { | |
544 float gray_value = *row++ / 65535.f; | |
545 *out_row++ = gray_value; | |
546 *out_row++ = gray_value; | |
547 *out_row++ = gray_value; | |
548 *out_row++ = 1.0f; | |
549 } | |
550 } else if (type == GL_UNSIGNED_BYTE) { | |
551 // We take the upper 8 bits of 16-bit data and convert it as luminance to | |
552 // ARGB. We loose the precision here, but it is important not to render | |
553 // Y16 as RG_88. To get the full precision use float textures with WebGL1 | |
554 // and e.g. R16UI or R32F textures with WebGL2. | |
555 DCHECK(format == GL_RGBA) << "Unsupported Y16 conversion for format: 0x" | |
556 << std::hex << format << " and type: 0x" | |
557 << std::hex << type; | |
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 |
547 } // anonymous namespace | 571 } // anonymous namespace |
548 | 572 |
549 // static | 573 // static |
550 void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( | 574 void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( |
551 const VideoFrame* video_frame, | 575 const VideoFrame* video_frame, |
552 void* rgb_pixels, | 576 void* rgb_pixels, |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
641 case PIXEL_FORMAT_YUV422P12: | 665 case PIXEL_FORMAT_YUV422P12: |
642 case PIXEL_FORMAT_YUV444P12: { | 666 case PIXEL_FORMAT_YUV444P12: { |
643 scoped_refptr<VideoFrame> temporary_frame = | 667 scoped_refptr<VideoFrame> temporary_frame = |
644 DownShiftHighbitVideoFrame(video_frame); | 668 DownShiftHighbitVideoFrame(video_frame); |
645 ConvertVideoFrameToRGBPixels(temporary_frame.get(), rgb_pixels, | 669 ConvertVideoFrameToRGBPixels(temporary_frame.get(), rgb_pixels, |
646 row_bytes); | 670 row_bytes); |
647 break; | 671 break; |
648 } | 672 } |
649 | 673 |
650 case PIXEL_FORMAT_Y16: | 674 case PIXEL_FORMAT_Y16: |
651 ConvertY16ToARGB(video_frame, rgb_pixels, row_bytes); | 675 // Since it is grayscale conversion, we disregard SK_PMCOLOR_BYTE_ORDER |
676 // and always use GL_RGBA. | |
677 FlipAndConvertY16(video_frame, static_cast<uint8_t*>(rgb_pixels), GL_RGBA, | |
678 GL_UNSIGNED_BYTE, false /*flip_y*/, row_bytes); | |
652 break; | 679 break; |
653 | 680 |
654 case PIXEL_FORMAT_NV12: | 681 case PIXEL_FORMAT_NV12: |
655 case PIXEL_FORMAT_NV21: | 682 case PIXEL_FORMAT_NV21: |
656 case PIXEL_FORMAT_UYVY: | 683 case PIXEL_FORMAT_UYVY: |
657 case PIXEL_FORMAT_YUY2: | 684 case PIXEL_FORMAT_YUY2: |
658 case PIXEL_FORMAT_ARGB: | 685 case PIXEL_FORMAT_ARGB: |
659 case PIXEL_FORMAT_XRGB: | 686 case PIXEL_FORMAT_XRGB: |
660 case PIXEL_FORMAT_RGB24: | 687 case PIXEL_FORMAT_RGB24: |
661 case PIXEL_FORMAT_RGB32: | 688 case PIXEL_FORMAT_RGB32: |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
765 video_frame->UpdateReleaseSyncToken(&client); | 792 video_frame->UpdateReleaseSyncToken(&client); |
766 } else { | 793 } else { |
767 CopyVideoFrameSingleTextureToGLTexture(destination_gl, video_frame.get(), | 794 CopyVideoFrameSingleTextureToGLTexture(destination_gl, video_frame.get(), |
768 texture, internal_format, type, | 795 texture, internal_format, type, |
769 premultiply_alpha, flip_y); | 796 premultiply_alpha, flip_y); |
770 } | 797 } |
771 | 798 |
772 return true; | 799 return true; |
773 } | 800 } |
774 | 801 |
802 bool SkCanvasVideoRenderer::TexImageImpl(const char* functionID, | |
803 unsigned target, | |
804 gpu::gles2::GLES2Interface* gl, | |
805 VideoFrame* frame, | |
806 int level, | |
807 int internalformat, | |
808 unsigned format, | |
809 unsigned type, | |
810 int xoffset, | |
811 int yoffset, | |
812 int zoffset, | |
813 bool flip_y, | |
814 bool premultiplyAlpha) { | |
815 DCHECK(frame); | |
816 DCHECK(!frame->HasTextures()); | |
817 | |
818 bool has_alpha = false; | |
819 unsigned output_bytes_per_pixel; | |
hubbe
2016/11/07 22:16:55
Please initialize to something.
aleksandar.stojiljkovic
2016/11/16 20:01:24
Done.
| |
820 switch (frame->format()) { | |
821 case PIXEL_FORMAT_Y16: | |
822 // Converting single component unsigned short here to FLOAT luminance. | |
823 switch (format) { | |
824 case GL_RGBA: | |
825 if (type == GL_FLOAT) { | |
826 output_bytes_per_pixel = 4 * sizeof(GLfloat); | |
827 break; | |
828 } | |
829 // Pass through. | |
830 default: | |
831 return false; | |
832 } | |
833 break; | |
834 default: | |
835 return false; | |
836 } | |
837 | |
838 if (has_alpha && premultiplyAlpha) { | |
839 NOTREACHED() << "Premultiply alpha is not supported."; | |
840 return false; | |
841 } | |
842 if (xoffset || yoffset || zoffset) { | |
843 NOTREACHED() << "Offsets are not supported."; | |
hubbe
2016/11/07 22:16:55
If they are not supported, why even have those arg
aleksandar.stojiljkovic
2016/11/16 20:01:24
Done. Split the method and now supported in texSub
| |
844 return false; | |
845 } | |
846 | |
847 const size_t width = frame->visible_rect().width(); | |
848 const size_t height = frame->visible_rect().height(); | |
849 size_t output_row_bytes = width * output_bytes_per_pixel; | |
850 scoped_refptr<DataBuffer> temp_buffer = | |
851 new DataBuffer(output_row_bytes * height); | |
852 uint8_t* data = temp_buffer->writable_data(); | |
853 | |
854 FlipAndConvertY16(frame, data, format, type, flip_y, output_row_bytes); | |
855 | |
856 if (!strcmp(functionID, "texImage2D")) { | |
857 gl->TexImage2D(target, level, internalformat, width, height, 0, format, | |
858 type, data); | |
859 } else if (!strcmp(functionID, "texSubImage2D")) { | |
860 gl->TexSubImage2D(target, level, xoffset, yoffset, width, height, format, | |
861 type, data); | |
862 } else { | |
863 DCHECK(false) << functionID << " isn't implemented for format: " | |
864 << VideoPixelFormatToString(frame->format()); | |
865 } | |
866 return true; | |
867 } | |
868 | |
775 void SkCanvasVideoRenderer::ResetCache() { | 869 void SkCanvasVideoRenderer::ResetCache() { |
776 DCHECK(thread_checker_.CalledOnValidThread()); | 870 DCHECK(thread_checker_.CalledOnValidThread()); |
777 // Clear cached values. | 871 // Clear cached values. |
778 last_image_ = nullptr; | 872 last_image_ = nullptr; |
779 last_timestamp_ = kNoTimestamp; | 873 last_timestamp_ = kNoTimestamp; |
780 } | 874 } |
781 | 875 |
782 bool SkCanvasVideoRenderer::UpdateLastImage( | 876 bool SkCanvasVideoRenderer::UpdateLastImage( |
783 const scoped_refptr<VideoFrame>& video_frame, | 877 const scoped_refptr<VideoFrame>& video_frame, |
784 const Context3D& context_3d) { | 878 const Context3D& context_3d) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
822 last_image_->bounds().contains(visible_rect)) { | 916 last_image_->bounds().contains(visible_rect)) { |
823 last_image_ = last_image_->makeSubset(visible_rect); | 917 last_image_ = last_image_->makeSubset(visible_rect); |
824 } | 918 } |
825 } | 919 } |
826 | 920 |
827 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() { | 921 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() { |
828 return last_image_dimensions_for_testing_; | 922 return last_image_dimensions_for_testing_; |
829 } | 923 } |
830 | 924 |
831 } // namespace media | 925 } // namespace media |
OLD | NEW |