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 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 return img; | 160 return img; |
159 } | 161 } |
160 | 162 |
161 // Creates a SkImage from a |video_frame| backed by native resources. | 163 // Creates a SkImage from a |video_frame| backed by native resources. |
162 // The SkImage will take ownership of the underlying resource. | 164 // The SkImage will take ownership of the underlying resource. |
163 sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame, | 165 sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame, |
164 const Context3D& context_3d) { | 166 const Context3D& context_3d) { |
165 DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() || | 167 DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() || |
166 PIXEL_FORMAT_XRGB == video_frame->format() || | 168 PIXEL_FORMAT_XRGB == video_frame->format() || |
167 PIXEL_FORMAT_NV12 == video_frame->format() || | 169 PIXEL_FORMAT_NV12 == video_frame->format() || |
168 PIXEL_FORMAT_UYVY == video_frame->format()); | 170 PIXEL_FORMAT_UYVY == video_frame->format() || |
| 171 PIXEL_FORMAT_Y16 == video_frame->format()); |
169 | 172 |
170 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); | 173 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); |
171 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || | 174 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || |
172 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || | 175 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || |
173 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) | 176 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) |
174 << mailbox_holder.texture_target; | 177 << mailbox_holder.texture_target; |
175 | 178 |
176 gpu::gles2::GLES2Interface* gl = context_3d.gl; | 179 gpu::gles2::GLES2Interface* gl = context_3d.gl; |
177 unsigned source_texture = 0; | 180 unsigned source_texture = 0; |
178 if (mailbox_holder.texture_target != GL_TEXTURE_2D) { | 181 if (mailbox_holder.texture_target != GL_TEXTURE_2D) { |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 return; | 343 return; |
341 } | 344 } |
342 | 345 |
343 SkRect dest; | 346 SkRect dest; |
344 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); | 347 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); |
345 | 348 |
346 // Paint black rectangle if there isn't a frame available or the | 349 // Paint black rectangle if there isn't a frame available or the |
347 // frame has an unexpected format. | 350 // frame has an unexpected format. |
348 if (!video_frame.get() || video_frame->natural_size().IsEmpty() || | 351 if (!video_frame.get() || video_frame->natural_size().IsEmpty() || |
349 !(media::IsYuvPlanar(video_frame->format()) || | 352 !(media::IsYuvPlanar(video_frame->format()) || |
| 353 video_frame->format() == media::PIXEL_FORMAT_Y16 || |
350 video_frame->HasTextures())) { | 354 video_frame->HasTextures())) { |
351 SkPaint blackWithAlphaPaint; | 355 SkPaint blackWithAlphaPaint; |
352 blackWithAlphaPaint.setAlpha(paint.getAlpha()); | 356 blackWithAlphaPaint.setAlpha(paint.getAlpha()); |
353 canvas->drawRect(dest, blackWithAlphaPaint); | 357 canvas->drawRect(dest, blackWithAlphaPaint); |
354 canvas->flush(); | 358 canvas->flush(); |
355 return; | 359 return; |
356 } | 360 } |
357 | 361 |
358 gpu::gles2::GLES2Interface* gl = context_3d.gl; | 362 gpu::gles2::GLES2Interface* gl = context_3d.gl; |
359 if (!UpdateLastImage(video_frame, context_3d)) | 363 if (!UpdateLastImage(video_frame, context_3d)) |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 for (int row = 0; row < video_frame->rows(plane); row++) { | 520 for (int row = 0; row < video_frame->rows(plane); row++) { |
517 for (int x = 0; x < width; x++) { | 521 for (int x = 0; x < width; x++) { |
518 dst[x] = src[x] >> shift; | 522 dst[x] = src[x] >> shift; |
519 } | 523 } |
520 src += video_frame->stride(plane) / 2; | 524 src += video_frame->stride(plane) / 2; |
521 dst += ret->stride(plane); | 525 dst += ret->stride(plane); |
522 } | 526 } |
523 } | 527 } |
524 return ret; | 528 return ret; |
525 } | 529 } |
| 530 |
| 531 void ConvertY16ToARGB(const VideoFrame* video_frame, |
| 532 void* argb_pixels, |
| 533 size_t argb_row_bytes) { |
| 534 const uint8_t* source = |
| 535 reinterpret_cast<const uint8_t*>(video_frame->visible_data(0)); |
| 536 uint8_t* out = reinterpret_cast<uint8_t*>(argb_pixels); |
| 537 const size_t stride = video_frame->stride(0); |
| 538 for (int i = 0; i < video_frame->visible_rect().height(); ++i) { |
| 539 const uint8_t* row = source; |
| 540 uint32_t* rgba = reinterpret_cast<uint32_t*>(out); |
| 541 for (const uint8_t* row_end = row + video_frame->row_bytes(0); |
| 542 row < row_end; ++row) { |
| 543 // We loose the precision here and take only upper 8 bits of 16 bit data. |
| 544 // It is important not to render Y16 as RG_88. To get the full precision |
| 545 // use float textures with WebGL1 and e.g. R16UI or R32F textures with |
| 546 // WebGL2. |
| 547 uint32_t green = *++row; |
| 548 *rgba++ = SkColorSetARGB(0xFF, green, green, green); |
| 549 } |
| 550 out += argb_row_bytes; |
| 551 source += stride; |
| 552 } |
| 553 } |
| 554 |
| 555 void FlipAndConvertY16(const uint8_t* input, |
| 556 uint8_t* output, |
| 557 unsigned format, |
| 558 unsigned type, |
| 559 bool flip_y, |
| 560 size_t row_bytes, |
| 561 size_t stride, |
| 562 size_t output_row_bytes, |
| 563 size_t height) { |
| 564 DCHECK(input != output); |
| 565 for (size_t i = 0; i < height; ++i) { |
| 566 const uint16_t* in = reinterpret_cast<const uint16_t*>(input + i * stride); |
| 567 uint8_t* out = flip_y ? output + output_row_bytes * (height - i - 1) |
| 568 : output + output_row_bytes * i; |
| 569 if (type == GL_FLOAT) { |
| 570 float* out_row = reinterpret_cast<float*>(out); |
| 571 const uint16_t* in_end = in + row_bytes / 2; |
| 572 if (format == GL_RGBA) { |
| 573 while (in < in_end) { |
| 574 float red = *in++ / 65536.f; |
| 575 *out_row++ = red; |
| 576 *out_row++ = red; |
| 577 *out_row++ = red; |
| 578 *out_row++ = 1.0f; |
| 579 } |
| 580 } else if (format == GL_RGB) { |
| 581 while (in < in_end) { |
| 582 float red = *in++ / 65536.f; |
| 583 *out_row++ = red; |
| 584 *out_row++ = red; |
| 585 *out_row++ = red; |
| 586 } |
| 587 } else if (type == GL_RED) { |
| 588 while (in < in_end) |
| 589 *out_row++ = *in++ / 65536.f; |
| 590 } else { |
| 591 NOTREACHED(); |
| 592 } |
| 593 } else if ((format == GL_RG && type == GL_UNSIGNED_BYTE) || |
| 594 (format == GL_RED_INTEGER && type == GL_UNSIGNED_SHORT)) { |
| 595 memcpy(out, input + i * stride, row_bytes); |
| 596 } else { |
| 597 NOTREACHED(); |
| 598 } |
| 599 } |
| 600 } |
526 } | 601 } |
527 | 602 |
528 // static | 603 // static |
529 void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( | 604 void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( |
530 const VideoFrame* video_frame, | 605 const VideoFrame* video_frame, |
531 void* rgb_pixels, | 606 void* rgb_pixels, |
532 size_t row_bytes) { | 607 size_t row_bytes) { |
533 if (!video_frame->IsMappable()) { | 608 if (!video_frame->IsMappable()) { |
534 NOTREACHED() << "Cannot extract pixels from non-CPU frame formats."; | 609 NOTREACHED() << "Cannot extract pixels from non-CPU frame formats."; |
535 return; | 610 return; |
536 } | 611 } |
537 if (!media::IsYuvPlanar(video_frame->format())) { | |
538 NOTREACHED() << "Non YUV formats are not supported"; | |
539 return; | |
540 } | |
541 | 612 |
542 switch (video_frame->format()) { | 613 switch (video_frame->format()) { |
543 case PIXEL_FORMAT_YV12: | 614 case PIXEL_FORMAT_YV12: |
544 case PIXEL_FORMAT_I420: | 615 case PIXEL_FORMAT_I420: |
545 if (CheckColorSpace(video_frame, COLOR_SPACE_JPEG)) { | 616 if (CheckColorSpace(video_frame, COLOR_SPACE_JPEG)) { |
546 LIBYUV_J420_TO_ARGB(video_frame->visible_data(VideoFrame::kYPlane), | 617 LIBYUV_J420_TO_ARGB(video_frame->visible_data(VideoFrame::kYPlane), |
547 video_frame->stride(VideoFrame::kYPlane), | 618 video_frame->stride(VideoFrame::kYPlane), |
548 video_frame->visible_data(VideoFrame::kUPlane), | 619 video_frame->visible_data(VideoFrame::kUPlane), |
549 video_frame->stride(VideoFrame::kUPlane), | 620 video_frame->stride(VideoFrame::kUPlane), |
550 video_frame->visible_data(VideoFrame::kVPlane), | 621 video_frame->visible_data(VideoFrame::kVPlane), |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
623 case PIXEL_FORMAT_YUV420P12: | 694 case PIXEL_FORMAT_YUV420P12: |
624 case PIXEL_FORMAT_YUV422P12: | 695 case PIXEL_FORMAT_YUV422P12: |
625 case PIXEL_FORMAT_YUV444P12: { | 696 case PIXEL_FORMAT_YUV444P12: { |
626 scoped_refptr<VideoFrame> temporary_frame = | 697 scoped_refptr<VideoFrame> temporary_frame = |
627 DownShiftHighbitVideoFrame(video_frame); | 698 DownShiftHighbitVideoFrame(video_frame); |
628 ConvertVideoFrameToRGBPixels(temporary_frame.get(), rgb_pixels, | 699 ConvertVideoFrameToRGBPixels(temporary_frame.get(), rgb_pixels, |
629 row_bytes); | 700 row_bytes); |
630 break; | 701 break; |
631 } | 702 } |
632 | 703 |
| 704 case PIXEL_FORMAT_Y16: |
| 705 ConvertY16ToARGB(video_frame, rgb_pixels, row_bytes); |
| 706 break; |
| 707 |
633 case PIXEL_FORMAT_NV12: | 708 case PIXEL_FORMAT_NV12: |
634 case PIXEL_FORMAT_NV21: | 709 case PIXEL_FORMAT_NV21: |
635 case PIXEL_FORMAT_UYVY: | 710 case PIXEL_FORMAT_UYVY: |
636 case PIXEL_FORMAT_YUY2: | 711 case PIXEL_FORMAT_YUY2: |
637 case PIXEL_FORMAT_ARGB: | 712 case PIXEL_FORMAT_ARGB: |
638 case PIXEL_FORMAT_XRGB: | 713 case PIXEL_FORMAT_XRGB: |
639 case PIXEL_FORMAT_RGB24: | 714 case PIXEL_FORMAT_RGB24: |
640 case PIXEL_FORMAT_RGB32: | 715 case PIXEL_FORMAT_RGB32: |
641 case PIXEL_FORMAT_MJPEG: | 716 case PIXEL_FORMAT_MJPEG: |
642 case PIXEL_FORMAT_MT21: | 717 case PIXEL_FORMAT_MT21: |
643 // TODO(dshwang): Use either I400ToARGB or J400ToARGB depending if we want | |
644 // BT.601 constrained range of 16 to 240, or JPEG full range BT.601 | |
645 // coefficients. Implement it when Y8/16 foramt is supported. | |
646 // crbug.com/624436 | |
647 case PIXEL_FORMAT_Y8: | 718 case PIXEL_FORMAT_Y8: |
648 case PIXEL_FORMAT_Y16: | |
649 case PIXEL_FORMAT_UNKNOWN: | 719 case PIXEL_FORMAT_UNKNOWN: |
650 NOTREACHED(); | 720 NOTREACHED() << "Only YUV formats and Y16 are supported."; |
651 } | 721 } |
652 } | 722 } |
653 | 723 |
654 // static | 724 // static |
655 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( | 725 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
656 gpu::gles2::GLES2Interface* gl, | 726 gpu::gles2::GLES2Interface* gl, |
657 VideoFrame* video_frame, | 727 VideoFrame* video_frame, |
658 unsigned int texture, | 728 unsigned int texture, |
659 unsigned int internal_format, | 729 unsigned int internal_format, |
660 unsigned int type, | 730 unsigned int type, |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
740 // canvas context. | 810 // canvas context. |
741 const GLuint64 dest_fence_sync = destination_gl->InsertFenceSyncCHROMIUM(); | 811 const GLuint64 dest_fence_sync = destination_gl->InsertFenceSyncCHROMIUM(); |
742 destination_gl->ShallowFlushCHROMIUM(); | 812 destination_gl->ShallowFlushCHROMIUM(); |
743 gpu::SyncToken dest_sync_token; | 813 gpu::SyncToken dest_sync_token; |
744 destination_gl->GenSyncTokenCHROMIUM(dest_fence_sync, | 814 destination_gl->GenSyncTokenCHROMIUM(dest_fence_sync, |
745 dest_sync_token.GetData()); | 815 dest_sync_token.GetData()); |
746 canvas_gl->WaitSyncTokenCHROMIUM(dest_sync_token.GetConstData()); | 816 canvas_gl->WaitSyncTokenCHROMIUM(dest_sync_token.GetConstData()); |
747 | 817 |
748 SyncTokenClientImpl client(canvas_gl); | 818 SyncTokenClientImpl client(canvas_gl); |
749 video_frame->UpdateReleaseSyncToken(&client); | 819 video_frame->UpdateReleaseSyncToken(&client); |
| 820 } else if (video_frame->format() == PIXEL_FORMAT_Y16) { |
| 821 CopyRG8ToTexture(context_3d, destination_gl, video_frame.get(), texture, |
| 822 internal_format, type, flip_y); |
750 } else { | 823 } else { |
751 CopyVideoFrameSingleTextureToGLTexture(destination_gl, video_frame.get(), | 824 CopyVideoFrameSingleTextureToGLTexture(destination_gl, video_frame.get(), |
752 texture, internal_format, type, | 825 texture, internal_format, type, |
753 premultiply_alpha, flip_y); | 826 premultiply_alpha, flip_y); |
754 } | 827 } |
755 | |
756 return true; | 828 return true; |
757 } | 829 } |
758 | 830 |
| 831 bool SkCanvasVideoRenderer::TexImageImpl(const char* functionID, |
| 832 unsigned target, |
| 833 gpu::gles2::GLES2Interface* gl, |
| 834 VideoFrame* frame, |
| 835 int level, |
| 836 int internalformat, |
| 837 unsigned format, |
| 838 unsigned type, |
| 839 int xoffset, |
| 840 int yoffset, |
| 841 int zoffset, |
| 842 bool flip_y, |
| 843 bool premultiplyAlpha) { |
| 844 DCHECK(frame); |
| 845 DCHECK(!frame->HasTextures()); |
| 846 |
| 847 bool has_alpha = false; |
| 848 unsigned output_bytes_per_pixel; |
| 849 switch (frame->format()) { |
| 850 case PIXEL_FORMAT_Y16: |
| 851 // Allow reinterpreting RG8 buffer here as R component in FLOAT. |
| 852 switch (format) { |
| 853 case GL_RGBA: |
| 854 if (type == GL_FLOAT) { |
| 855 output_bytes_per_pixel = 4 * sizeof(GLfloat); |
| 856 break; |
| 857 } |
| 858 // Pass through. |
| 859 case GL_RGB: |
| 860 if (type == GL_FLOAT) { |
| 861 output_bytes_per_pixel = 3 * sizeof(GLfloat); |
| 862 break; |
| 863 } |
| 864 // Pass through. |
| 865 default: |
| 866 return false; |
| 867 } |
| 868 break; |
| 869 default: |
| 870 return false; |
| 871 } |
| 872 unsigned source_bytes_per_pixel = |
| 873 VideoFrame::PlaneBitsPerPixel(frame->format(), 0) / 8; |
| 874 DCHECK_EQ(VideoFrame::PlaneBitsPerPixel(frame->format(), 0) % 8, 0); |
| 875 |
| 876 if (has_alpha && premultiplyAlpha) { |
| 877 NOTREACHED() << "Premultiply alpha is not supported."; |
| 878 return false; |
| 879 } |
| 880 if (xoffset || yoffset || zoffset) { |
| 881 NOTREACHED() << "Offsets are not supported."; |
| 882 return false; |
| 883 } |
| 884 |
| 885 uint8_t* data; |
| 886 scoped_refptr<DataBuffer> temp_buffer; |
| 887 size_t width = frame->visible_rect().width(); |
| 888 size_t height = frame->visible_rect().height(); |
| 889 size_t output_row_bytes = |
| 890 frame->row_bytes(0) * output_bytes_per_pixel / source_bytes_per_pixel; |
| 891 temp_buffer = new DataBuffer(output_row_bytes * height); |
| 892 data = temp_buffer->writable_data(); |
| 893 DCHECK_EQ(frame->format(), PIXEL_FORMAT_Y16); |
| 894 FlipAndConvertY16(frame->visible_data(0), data, format, type, flip_y, |
| 895 frame->row_bytes(0), frame->stride(0), output_row_bytes, |
| 896 height); |
| 897 |
| 898 if (!strcmp(functionID, "texImage2D")) { |
| 899 gl->TexImage2D(target, level, internalformat, width, height, 0, format, |
| 900 type, data); |
| 901 } else if (!strcmp(functionID, "texSubImage2D")) { |
| 902 gl->TexSubImage2D(target, level, xoffset, yoffset, width, height, format, |
| 903 type, data); |
| 904 } else { |
| 905 DCHECK(!strcmp(functionID, "texSubImage3D")); |
| 906 gl->TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, |
| 907 1, format, type, data); |
| 908 } |
| 909 return true; |
| 910 } |
| 911 |
| 912 void SkCanvasVideoRenderer::CopyRG8ToTexture( |
| 913 const Context3D& context_3d, |
| 914 gpu::gles2::GLES2Interface* target_gl, |
| 915 VideoFrame* frame, |
| 916 unsigned texture, |
| 917 unsigned internal_format, |
| 918 unsigned type, |
| 919 bool flip_y) { |
| 920 // TODO(astojilj): After GLES 3.2, use glCopyImageSubData for RG8 to R16UI |
| 921 // conversion. glCopyImageSubData is already available as extension on some of |
| 922 // the Android devices (GL_EXT_COPY_IMAGE). |
| 923 gpu::gles2::GLES2Interface* local_gl = context_3d.gl; |
| 924 |
| 925 // Get source texture on local_gl. |
| 926 unsigned source_texture; |
| 927 { |
| 928 const gpu::MailboxHolder& mailbox_holder = frame->mailbox_holder(0); |
| 929 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D) |
| 930 << mailbox_holder.texture_target; |
| 931 |
| 932 local_gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); |
| 933 source_texture = local_gl->CreateAndConsumeTextureCHROMIUM( |
| 934 mailbox_holder.texture_target, mailbox_holder.mailbox.name); |
| 935 } |
| 936 |
| 937 // Reinterpret RG8 as 16 bit normalized and then to luminance in RGBA on |
| 938 // local_gl. Later, do the copy on target_gl. |
| 939 unsigned intermediate_texture; |
| 940 local_gl->GenTextures(1, &intermediate_texture); |
| 941 DoCopyRG8ToTexture(context_3d, source_texture, intermediate_texture, GL_RGBA, |
| 942 GL_RGBA, GL_FLOAT, frame->visible_rect().width(), |
| 943 frame->visible_rect().height(), flip_y); |
| 944 local_gl->DeleteTextures(1, &source_texture); |
| 945 |
| 946 // Get intermediate_texture to target_gl. |
| 947 { |
| 948 gpu::MailboxHolder mailbox_holder; |
| 949 mailbox_holder.texture_target = GL_TEXTURE_2D; |
| 950 local_gl->GenMailboxCHROMIUM(mailbox_holder.mailbox.name); |
| 951 local_gl->ProduceTextureDirectCHROMIUM(intermediate_texture, |
| 952 mailbox_holder.texture_target, |
| 953 mailbox_holder.mailbox.name); |
| 954 // Wait for mailbox creation on local context before consuming it and |
| 955 // copying from it on the consumer context. |
| 956 const GLuint64 fence_sync = local_gl->InsertFenceSyncCHROMIUM(); |
| 957 local_gl->ShallowFlushCHROMIUM(); |
| 958 local_gl->GenSyncTokenCHROMIUM(fence_sync, |
| 959 mailbox_holder.sync_token.GetData()); |
| 960 |
| 961 target_gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); |
| 962 uint32_t target_intermediate_texture = |
| 963 target_gl->CreateAndConsumeTextureCHROMIUM( |
| 964 mailbox_holder.texture_target, mailbox_holder.mailbox.name); |
| 965 |
| 966 local_gl->DeleteTextures(1, &intermediate_texture); |
| 967 intermediate_texture = target_intermediate_texture; |
| 968 } |
| 969 |
| 970 // Copy intermediate_texture to texture. |
| 971 target_gl->CopyTextureCHROMIUM(intermediate_texture, texture, internal_format, |
| 972 type, false, false, false); |
| 973 target_gl->DeleteTextures(1, &intermediate_texture); |
| 974 |
| 975 // Undo gr_context state changes introduced in this function. |
| 976 context_3d.gr_context->resetContext( |
| 977 kMisc_GrGLBackendState | kBlend_GrGLBackendState | |
| 978 kView_GrGLBackendState | kStencil_GrGLBackendState | |
| 979 kVertex_GrGLBackendState | kProgram_GrGLBackendState | |
| 980 kTextureBinding_GrGLBackendState); |
| 981 SyncTokenClientImpl client(target_gl); |
| 982 frame->UpdateReleaseSyncToken(&client); |
| 983 } |
| 984 |
| 985 void SkCanvasVideoRenderer::DoCopyRG8ToTexture(const Context3D& context_3d, |
| 986 unsigned source_texture, |
| 987 unsigned texture, |
| 988 unsigned format, |
| 989 unsigned internal_format, |
| 990 unsigned type, |
| 991 unsigned width, |
| 992 unsigned height, |
| 993 bool flip_y) { |
| 994 gpu::gles2::GLES2Interface* gl = context_3d.gl; |
| 995 |
| 996 if (cached_gl_resources_gr_context_id_ != context_3d.gr_context->uniqueID()) { |
| 997 rg8_to_texture_program_ = 0; |
| 998 rg8_to_texture_vertices_buffer_ = 0; |
| 999 cached_gl_resources_gr_context_id_ = context_3d.gr_context->uniqueID(); |
| 1000 } |
| 1001 |
| 1002 gl->EnableVertexAttribArray(0); |
| 1003 if (!rg8_to_texture_vertices_buffer_) { |
| 1004 gl->GenBuffers(1, &rg8_to_texture_vertices_buffer_); |
| 1005 gl->BindBuffer(GL_ARRAY_BUFFER, rg8_to_texture_vertices_buffer_); |
| 1006 const GLfloat vertices[] = {-1.f, -1.f, 1.f, -1.f, -1.0f, 1.f, 1.f, 1.f}; |
| 1007 gl->BufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); |
| 1008 gl->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); |
| 1009 } |
| 1010 |
| 1011 if (!rg8_to_texture_program_) { |
| 1012 rg8_to_texture_program_ = gl->CreateProgram(); |
| 1013 GLuint vertex_shader = gl->CreateShader(GL_VERTEX_SHADER); |
| 1014 std::string source = std::string( |
| 1015 "\ |
| 1016 #ifdef GL_ES\n\ |
| 1017 precision mediump float;\n\ |
| 1018 #define TexCoordPrecision mediump\n\ |
| 1019 #else\n\ |
| 1020 #define TexCoordPrecision\n\ |
| 1021 #endif\n\ |
| 1022 uniform vec2 coord_transform;\n\ |
| 1023 attribute vec2 a_pos;\n\ |
| 1024 varying TexCoordPrecision vec2 v_uv;\n\ |
| 1025 void main(void) {\n\ |
| 1026 gl_Position = vec4(a_pos, 0, 1.0);\n\ |
| 1027 v_uv = (a_pos * coord_transform) + 0.5;\n\ |
| 1028 }\n"); |
| 1029 const char* vertex_source = source.c_str(); |
| 1030 gl->ShaderSource(vertex_shader, 1, &vertex_source, 0); |
| 1031 gl->CompileShader(vertex_shader); |
| 1032 gl->AttachShader(rg8_to_texture_program_, vertex_shader); |
| 1033 |
| 1034 GLuint fragment_shader = gl->CreateShader(GL_FRAGMENT_SHADER); |
| 1035 source = std::string( |
| 1036 "\ |
| 1037 #ifdef GL_ES\n\ |
| 1038 precision mediump float;\n\ |
| 1039 #define TexCoordPrecision mediump\n\ |
| 1040 #else\n\ |
| 1041 #define TexCoordPrecision\n\ |
| 1042 #endif\n\ |
| 1043 uniform sampler2D u_sampler;\n\ |
| 1044 varying TexCoordPrecision vec2 v_uv;\n\ |
| 1045 void main(void) {\n\ |
| 1046 vec4 color = texture2D(u_sampler, v_uv);\n\ |
| 1047 gl_FragColor.rgb = vec3((color.r * 0.00390625) + color.g);\n\ |
| 1048 }\n"); |
| 1049 const char* fragment_source = source.c_str(); |
| 1050 gl->ShaderSource(fragment_shader, 1, &fragment_source, 0); |
| 1051 gl->CompileShader(fragment_shader); |
| 1052 |
| 1053 gl->AttachShader(rg8_to_texture_program_, fragment_shader); |
| 1054 |
| 1055 gl->BindAttribLocation(rg8_to_texture_program_, 0, "a_pos"); |
| 1056 gl->LinkProgram(rg8_to_texture_program_); |
| 1057 } |
| 1058 |
| 1059 gl->UseProgram(rg8_to_texture_program_); |
| 1060 gl->Uniform1i(gl->GetUniformLocation(rg8_to_texture_program_, "u_sampler"), |
| 1061 0); |
| 1062 gl->Uniform2f( |
| 1063 gl->GetUniformLocation(rg8_to_texture_program_, "coord_transform"), 0.5, |
| 1064 flip_y ? -0.5 : 0.5); |
| 1065 |
| 1066 GLuint fbo; |
| 1067 gl->GenFramebuffers(1, &fbo); |
| 1068 gl->ActiveTexture(GL_TEXTURE0); |
| 1069 unsigned target = GL_TEXTURE_2D; |
| 1070 gl->BindTexture(target, texture); |
| 1071 gl->TexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, |
| 1072 type, 0); |
| 1073 |
| 1074 gl->TexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 1075 gl->TexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 1076 gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| 1077 gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 1078 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo); |
| 1079 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, |
| 1080 texture, 0); |
| 1081 |
| 1082 gl->BindTexture(target, source_texture); |
| 1083 gl->TexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 1084 gl->TexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 1085 gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| 1086 gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 1087 |
| 1088 gl->Disable(GL_DEPTH_TEST); |
| 1089 gl->Disable(GL_STENCIL_TEST); |
| 1090 gl->Disable(GL_CULL_FACE); |
| 1091 gl->ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| 1092 gl->DepthMask(GL_FALSE); |
| 1093 gl->Disable(GL_BLEND); |
| 1094 gl->Disable(GL_SCISSOR_TEST); |
| 1095 gl->Viewport(0, 0, width, height); |
| 1096 gl->DrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| 1097 gl->Flush(); |
| 1098 gl->BindFramebuffer(GL_FRAMEBUFFER, 0); |
| 1099 gl->DeleteFramebuffers(1, &fbo); |
| 1100 } |
| 1101 |
759 void SkCanvasVideoRenderer::ResetCache() { | 1102 void SkCanvasVideoRenderer::ResetCache() { |
760 DCHECK(thread_checker_.CalledOnValidThread()); | 1103 DCHECK(thread_checker_.CalledOnValidThread()); |
761 // Clear cached values. | 1104 // Clear cached values. |
762 last_image_ = nullptr; | 1105 last_image_ = nullptr; |
763 last_timestamp_ = kNoTimestamp; | 1106 last_timestamp_ = kNoTimestamp; |
764 } | 1107 } |
765 | 1108 |
766 bool SkCanvasVideoRenderer::UpdateLastImage( | 1109 bool SkCanvasVideoRenderer::UpdateLastImage( |
767 const scoped_refptr<VideoFrame>& video_frame, | 1110 const scoped_refptr<VideoFrame>& video_frame, |
768 const Context3D& context_3d) { | 1111 const Context3D& context_3d) { |
769 if (!last_image_ || video_frame->timestamp() != last_timestamp_) { | 1112 if (!last_image_ || video_frame->timestamp() != last_timestamp_) { |
770 ResetCache(); | 1113 ResetCache(); |
771 // Generate a new image. | 1114 // Generate a new image. |
772 // Note: Skia will hold onto |video_frame| via |video_generator| only when | 1115 // Note: Skia will hold onto |video_frame| via |video_generator| only when |
773 // |video_frame| is software. | 1116 // |video_frame| is software. |
774 // Holding |video_frame| longer than this call when using GPUVideoDecoder | 1117 // Holding |video_frame| longer than this call when using GPUVideoDecoder |
775 // could cause problems since the pool of VideoFrames has a fixed size. | 1118 // could cause problems since the pool of VideoFrames has a fixed size. |
776 if (video_frame->HasTextures()) { | 1119 if (video_frame->HasTextures()) { |
777 DCHECK(context_3d.gr_context); | 1120 DCHECK(context_3d.gr_context); |
778 DCHECK(context_3d.gl); | 1121 DCHECK(context_3d.gl); |
779 if (media::VideoFrame::NumPlanes(video_frame->format()) > 1) { | 1122 if (media::VideoFrame::NumPlanes(video_frame->format()) > 1) { |
780 last_image_ = | 1123 last_image_ = |
781 NewSkImageFromVideoFrameYUVTextures(video_frame.get(), context_3d); | 1124 NewSkImageFromVideoFrameYUVTextures(video_frame.get(), context_3d); |
782 } else { | 1125 } else { |
| 1126 // TODO(astojilj): For Y16 on RG textures we don't want to paint 16 bit |
| 1127 // split to 8 bit R & G. Implement using CopyRG8ToTexture. |
783 last_image_ = | 1128 last_image_ = |
784 NewSkImageFromVideoFrameNative(video_frame.get(), context_3d); | 1129 NewSkImageFromVideoFrameNative(video_frame.get(), context_3d); |
785 } | 1130 } |
786 } else { | 1131 } else { |
787 auto* video_generator = new VideoImageGenerator(video_frame); | 1132 auto* video_generator = new VideoImageGenerator(video_frame); |
788 last_image_ = SkImage::MakeFromGenerator(video_generator); | 1133 last_image_ = SkImage::MakeFromGenerator(video_generator); |
789 } | 1134 } |
790 if (!last_image_) // Couldn't create the SkImage. | 1135 if (!last_image_) // Couldn't create the SkImage. |
791 return false; | 1136 return false; |
792 last_timestamp_ = video_frame->timestamp(); | 1137 last_timestamp_ = video_frame->timestamp(); |
793 } | 1138 } |
794 last_image_deleting_timer_.Reset(); | 1139 last_image_deleting_timer_.Reset(); |
795 DCHECK(!!last_image_); | 1140 DCHECK(!!last_image_); |
796 return true; | 1141 return true; |
797 } | 1142 } |
798 | 1143 |
799 } // namespace media | 1144 } // namespace media |
OLD | NEW |