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

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

Issue 2476693002: WebGL & 16-bit video stream: upload to FLOAT texture. (Closed)
Patch Set: Nits. Created 4 years 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 <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
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)
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) {
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,
605 flip_y, 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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698