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