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) |
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 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 |