Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(366)

Side by Side Diff: media/renderers/skcanvas_video_renderer.cc

Issue 2476693002: WebGL & 16-bit video stream: upload to FLOAT texture. (Closed)
Patch Set: Lossless access to 16-bit video stream using WebGL GL_FLOAT texture. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698