| 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 <GLES3/gl3.h> |
| 8 #include <limits> | 8 #include <limits> |
| 9 | 9 |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 gl->TexParameteri(source_textures[i].fTarget, GL_TEXTURE_MIN_FILTER, | 169 gl->TexParameteri(source_textures[i].fTarget, GL_TEXTURE_MIN_FILTER, |
| 170 min_mag_filter[i][0]); | 170 min_mag_filter[i][0]); |
| 171 gl->TexParameteri(source_textures[i].fTarget, GL_TEXTURE_MAG_FILTER, | 171 gl->TexParameteri(source_textures[i].fTarget, GL_TEXTURE_MAG_FILTER, |
| 172 min_mag_filter[i][1]); | 172 min_mag_filter[i][1]); |
| 173 | 173 |
| 174 gl->DeleteTextures(1, &source_textures[i].fID); | 174 gl->DeleteTextures(1, &source_textures[i].fID); |
| 175 } | 175 } |
| 176 return img; | 176 return img; |
| 177 } | 177 } |
| 178 | 178 |
| 179 bool VideoTextureNeedsClipping(const VideoFrame* video_frame) { | |
| 180 // There are multiple reasons that the size of the video frame's | |
| 181 // visible rectangle may differ from the coded size, including the | |
| 182 // encoder rounding up to the size of a macroblock, or use of | |
| 183 // non-square pixels. | |
| 184 // | |
| 185 // Some callers of these APIs (HTMLVideoElement and the 2D canvas | |
| 186 // context) already clip to the video frame's visible rectangle. | |
| 187 // WebGL on the other hand assumes that only the valid pixels are | |
| 188 // contained in the destination texture. This helper function | |
| 189 // determines whether this slower path is needed. | |
| 190 return video_frame->visible_rect().size() != video_frame->coded_size(); | |
| 191 } | |
| 192 | |
| 193 // Creates a SkImage from a |video_frame| backed by native resources. | 179 // Creates a SkImage from a |video_frame| backed by native resources. |
| 194 // The SkImage will take ownership of the underlying resource. | 180 // The SkImage will take ownership of the underlying resource. |
| 195 sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame, | 181 sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame, |
| 196 const Context3D& context_3d) { | 182 const Context3D& context_3d) { |
| 197 DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() || | 183 DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() || |
| 198 PIXEL_FORMAT_XRGB == video_frame->format() || | 184 PIXEL_FORMAT_XRGB == video_frame->format() || |
| 199 PIXEL_FORMAT_NV12 == video_frame->format() || | 185 PIXEL_FORMAT_NV12 == video_frame->format() || |
| 200 PIXEL_FORMAT_UYVY == video_frame->format()); | 186 PIXEL_FORMAT_UYVY == video_frame->format()); |
| 201 | 187 |
| 202 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); | 188 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); |
| 203 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || | 189 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || |
| 204 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || | 190 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || |
| 205 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) | 191 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) |
| 206 << mailbox_holder.texture_target; | 192 << mailbox_holder.texture_target; |
| 207 | 193 |
| 208 gpu::gles2::GLES2Interface* gl = context_3d.gl; | 194 gpu::gles2::GLES2Interface* gl = context_3d.gl; |
| 209 unsigned source_texture = 0; | 195 unsigned source_texture = 0; |
| 210 if (mailbox_holder.texture_target != GL_TEXTURE_2D) { | 196 if (mailbox_holder.texture_target != GL_TEXTURE_2D) { |
| 211 // TODO(dcastagna): At the moment Skia doesn't support targets different | 197 // TODO(dcastagna): At the moment Skia doesn't support targets different |
| 212 // than GL_TEXTURE_2D. Avoid this copy once | 198 // than GL_TEXTURE_2D. Avoid this copy once |
| 213 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed. | 199 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed. |
| 214 gl->GenTextures(1, &source_texture); | 200 gl->GenTextures(1, &source_texture); |
| 215 DCHECK(source_texture); | 201 DCHECK(source_texture); |
| 216 gl->BindTexture(GL_TEXTURE_2D, source_texture); | 202 gl->BindTexture(GL_TEXTURE_2D, source_texture); |
| 217 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( | 203 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
| 218 gl, video_frame, | 204 gl, video_frame, |
| 219 SkCanvasVideoRenderer::SingleFrameForVideoElementOrCanvas, | |
| 220 GL_TEXTURE_2D, source_texture, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 0, | 205 GL_TEXTURE_2D, source_texture, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 0, |
| 221 true, false); | 206 true, false); |
| 222 context_3d.gr_context->resetContext(kTextureBinding_GrGLBackendState); | 207 context_3d.gr_context->resetContext(kTextureBinding_GrGLBackendState); |
| 223 } else { | 208 } else { |
| 224 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); | 209 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); |
| 225 source_texture = gl->CreateAndConsumeTextureCHROMIUM( | 210 source_texture = gl->CreateAndConsumeTextureCHROMIUM( |
| 226 mailbox_holder.texture_target, mailbox_holder.mailbox.name); | 211 mailbox_holder.texture_target, mailbox_holder.mailbox.name); |
| 227 } | 212 } |
| 228 GrGLTextureInfo source_texture_info; | 213 GrGLTextureInfo source_texture_info; |
| 229 source_texture_info.fID = source_texture; | 214 source_texture_info.fID = source_texture; |
| (...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 807 case PIXEL_FORMAT_Y8: | 792 case PIXEL_FORMAT_Y8: |
| 808 case PIXEL_FORMAT_UNKNOWN: | 793 case PIXEL_FORMAT_UNKNOWN: |
| 809 NOTREACHED() << "Only YUV formats and Y16 are supported."; | 794 NOTREACHED() << "Only YUV formats and Y16 are supported."; |
| 810 } | 795 } |
| 811 } | 796 } |
| 812 | 797 |
| 813 // static | 798 // static |
| 814 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( | 799 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
| 815 gpu::gles2::GLES2Interface* gl, | 800 gpu::gles2::GLES2Interface* gl, |
| 816 VideoFrame* video_frame, | 801 VideoFrame* video_frame, |
| 817 SingleFrameCopyMode copy_mode, | |
| 818 unsigned int target, | 802 unsigned int target, |
| 819 unsigned int texture, | 803 unsigned int texture, |
| 820 unsigned int internal_format, | 804 unsigned int internal_format, |
| 821 unsigned int format, | 805 unsigned int format, |
| 822 unsigned int type, | 806 unsigned int type, |
| 823 int level, | 807 int level, |
| 824 bool premultiply_alpha, | 808 bool premultiply_alpha, |
| 825 bool flip_y) { | 809 bool flip_y) { |
| 826 DCHECK(video_frame); | 810 DCHECK(video_frame); |
| 827 DCHECK(video_frame->HasTextures()); | 811 DCHECK(video_frame->HasTextures()); |
| 828 | 812 |
| 829 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); | 813 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); |
| 830 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || | 814 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || |
| 831 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || | 815 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || |
| 832 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) | 816 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) |
| 833 << mailbox_holder.texture_target; | 817 << mailbox_holder.texture_target; |
| 834 | 818 |
| 835 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); | 819 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); |
| 836 uint32_t source_texture = gl->CreateAndConsumeTextureCHROMIUM( | 820 uint32_t source_texture = gl->CreateAndConsumeTextureCHROMIUM( |
| 837 mailbox_holder.texture_target, mailbox_holder.mailbox.name); | 821 mailbox_holder.texture_target, mailbox_holder.mailbox.name); |
| 838 | 822 |
| 839 // The video is stored in a unmultiplied format, so premultiply | 823 // The video is stored in a unmultiplied format, so premultiply |
| 840 // if necessary. | 824 // if necessary. |
| 841 // Application itself needs to take care of setting the right |flip_y| | 825 // Application itself needs to take care of setting the right |flip_y| |
| 842 // value down to get the expected result. | 826 // value down to get the expected result. |
| 843 // "flip_y == true" means to reverse the video orientation while | 827 // "flip_y == true" means to reverse the video orientation while |
| 844 // "flip_y == false" means to keep the intrinsic orientation. | 828 // "flip_y == false" means to keep the intrinsic orientation. |
| 845 | 829 |
| 846 if (copy_mode == SingleFrameForVideoElementOrCanvas || | 830 // Must reallocate the destination texture and copy only a sub-portion. |
| 847 !VideoTextureNeedsClipping(video_frame)) { | 831 gfx::Rect dest_rect = video_frame->visible_rect(); |
| 848 // No need to clip the source video texture. | |
| 849 gl->CopyTextureCHROMIUM(source_texture, 0, target, texture, level, | |
| 850 internal_format, type, flip_y, premultiply_alpha, | |
| 851 false); | |
| 852 } else { | |
| 853 // Must reallocate the destination texture and copy only a sub-portion. | |
| 854 gfx::Rect dest_rect = video_frame->visible_rect(); | |
| 855 #if DCHECK_IS_ON() | 832 #if DCHECK_IS_ON() |
| 856 // The caller should have bound _texture_ to the GL_TEXTURE_2D | 833 // There should always be enough data in the source texture to |
| 857 // binding point already. | 834 // cover this copy. |
| 858 GLuint current_texture = 0; | 835 DCHECK_LE(dest_rect.width(), video_frame->coded_size().width()); |
| 859 gl->GetIntegerv(GL_TEXTURE_BINDING_2D, | 836 DCHECK_LE(dest_rect.height(), video_frame->coded_size().height()); |
| 860 reinterpret_cast<GLint*>(¤t_texture)); | |
| 861 DCHECK_EQ(current_texture, texture); | |
| 862 // There should always be enough data in the source texture to | |
| 863 // cover this copy. | |
| 864 DCHECK_LE(dest_rect.width(), video_frame->coded_size().width()); | |
| 865 DCHECK_LE(dest_rect.height(), video_frame->coded_size().height()); | |
| 866 #endif | 837 #endif |
| 867 gl->TexImage2D(target, level, internal_format, dest_rect.width(), | 838 gl->TexImage2D(target, level, internal_format, dest_rect.width(), |
| 868 dest_rect.height(), 0, format, type, nullptr); | 839 dest_rect.height(), 0, format, type, nullptr); |
| 869 gl->CopySubTextureCHROMIUM(source_texture, 0, target, texture, level, 0, 0, | 840 gl->CopySubTextureCHROMIUM(source_texture, 0, target, texture, level, 0, 0, |
| 870 dest_rect.x(), dest_rect.y(), dest_rect.width(), | 841 dest_rect.x(), dest_rect.y(), dest_rect.width(), |
| 871 dest_rect.height(), flip_y, premultiply_alpha, | 842 dest_rect.height(), flip_y, premultiply_alpha, |
| 872 false); | 843 false); |
| 873 } | |
| 874 | 844 |
| 875 gl->DeleteTextures(1, &source_texture); | 845 gl->DeleteTextures(1, &source_texture); |
| 876 gl->Flush(); | 846 gl->Flush(); |
| 877 | 847 |
| 878 SyncTokenClientImpl client(gl); | 848 SyncTokenClientImpl client(gl); |
| 879 video_frame->UpdateReleaseSyncToken(&client); | 849 video_frame->UpdateReleaseSyncToken(&client); |
| 880 } | 850 } |
| 881 | 851 |
| 882 bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( | 852 bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( |
| 883 const Context3D& context_3d, | 853 const Context3D& context_3d, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 918 canvas_gl->ShallowFlushCHROMIUM(); | 888 canvas_gl->ShallowFlushCHROMIUM(); |
| 919 canvas_gl->GenSyncTokenCHROMIUM(fence_sync, | 889 canvas_gl->GenSyncTokenCHROMIUM(fence_sync, |
| 920 mailbox_holder.sync_token.GetData()); | 890 mailbox_holder.sync_token.GetData()); |
| 921 | 891 |
| 922 destination_gl->WaitSyncTokenCHROMIUM( | 892 destination_gl->WaitSyncTokenCHROMIUM( |
| 923 mailbox_holder.sync_token.GetConstData()); | 893 mailbox_holder.sync_token.GetConstData()); |
| 924 uint32_t intermediate_texture = | 894 uint32_t intermediate_texture = |
| 925 destination_gl->CreateAndConsumeTextureCHROMIUM( | 895 destination_gl->CreateAndConsumeTextureCHROMIUM( |
| 926 mailbox_holder.texture_target, mailbox_holder.mailbox.name); | 896 mailbox_holder.texture_target, mailbox_holder.mailbox.name); |
| 927 | 897 |
| 928 // See whether the source video texture must be clipped. | 898 // Reallocate destination texture and copy only valid region. |
| 929 if (VideoTextureNeedsClipping(video_frame.get())) { | 899 gfx::Rect dest_rect = video_frame->visible_rect(); |
| 930 // Reallocate destination texture and copy only valid region. | |
| 931 gfx::Rect dest_rect = video_frame->visible_rect(); | |
| 932 #if DCHECK_IS_ON() | 900 #if DCHECK_IS_ON() |
| 933 // The caller should have bound _texture_ to the GL_TEXTURE_2D | 901 // There should always be enough data in the source texture to |
| 934 // binding point already. | 902 // cover this copy. |
| 935 GLuint current_texture = 0; | 903 DCHECK_LE(dest_rect.width(), video_frame->coded_size().width()); |
| 936 destination_gl->GetIntegerv(GL_TEXTURE_BINDING_2D, | 904 DCHECK_LE(dest_rect.height(), video_frame->coded_size().height()); |
| 937 reinterpret_cast<GLint*>(¤t_texture)); | |
| 938 DCHECK_EQ(current_texture, texture); | |
| 939 // There should always be enough data in the source texture to | |
| 940 // cover this copy. | |
| 941 DCHECK_LE(dest_rect.width(), video_frame->coded_size().width()); | |
| 942 DCHECK_LE(dest_rect.height(), video_frame->coded_size().height()); | |
| 943 #endif | 905 #endif |
| 944 destination_gl->TexImage2D(target, level, internal_format, | 906 destination_gl->TexImage2D(target, level, internal_format, |
| 945 dest_rect.width(), dest_rect.height(), 0, | 907 dest_rect.width(), dest_rect.height(), 0, format, |
| 946 format, type, nullptr); | 908 type, nullptr); |
| 947 destination_gl->CopySubTextureCHROMIUM( | 909 destination_gl->CopySubTextureCHROMIUM( |
| 948 intermediate_texture, 0, target, texture, level, 0, 0, dest_rect.x(), | 910 intermediate_texture, 0, target, texture, level, 0, 0, dest_rect.x(), |
| 949 dest_rect.y(), dest_rect.width(), dest_rect.height(), flip_y, | 911 dest_rect.y(), dest_rect.width(), dest_rect.height(), flip_y, |
| 950 premultiply_alpha, false); | 912 premultiply_alpha, false); |
| 951 } else { | |
| 952 destination_gl->CopyTextureCHROMIUM(intermediate_texture, 0, target, | |
| 953 texture, level, internal_format, type, | |
| 954 flip_y, premultiply_alpha, false); | |
| 955 } | |
| 956 | 913 |
| 957 destination_gl->DeleteTextures(1, &intermediate_texture); | 914 destination_gl->DeleteTextures(1, &intermediate_texture); |
| 958 | 915 |
| 959 // Wait for destination context to consume mailbox before deleting it in | 916 // Wait for destination context to consume mailbox before deleting it in |
| 960 // canvas context. | 917 // canvas context. |
| 961 const GLuint64 dest_fence_sync = destination_gl->InsertFenceSyncCHROMIUM(); | 918 const GLuint64 dest_fence_sync = destination_gl->InsertFenceSyncCHROMIUM(); |
| 962 destination_gl->ShallowFlushCHROMIUM(); | 919 destination_gl->ShallowFlushCHROMIUM(); |
| 963 gpu::SyncToken dest_sync_token; | 920 gpu::SyncToken dest_sync_token; |
| 964 destination_gl->GenSyncTokenCHROMIUM(dest_fence_sync, | 921 destination_gl->GenSyncTokenCHROMIUM(dest_fence_sync, |
| 965 dest_sync_token.GetData()); | 922 dest_sync_token.GetData()); |
| 966 canvas_gl->WaitSyncTokenCHROMIUM(dest_sync_token.GetConstData()); | 923 canvas_gl->WaitSyncTokenCHROMIUM(dest_sync_token.GetConstData()); |
| 967 | 924 |
| 968 SyncTokenClientImpl client(canvas_gl); | 925 SyncTokenClientImpl client(canvas_gl); |
| 969 video_frame->UpdateReleaseSyncToken(&client); | 926 video_frame->UpdateReleaseSyncToken(&client); |
| 970 } else { | 927 } else { |
| 971 CopyVideoFrameSingleTextureToGLTexture( | 928 CopyVideoFrameSingleTextureToGLTexture( |
| 972 destination_gl, video_frame.get(), SingleFrameForWebGL, target, texture, | 929 destination_gl, video_frame.get(), target, texture, internal_format, |
| 973 internal_format, format, type, level, premultiply_alpha, flip_y); | 930 format, type, level, premultiply_alpha, flip_y); |
| 974 } | 931 } |
| 975 | 932 |
| 976 return true; | 933 return true; |
| 977 } | 934 } |
| 978 | 935 |
| 979 bool SkCanvasVideoRenderer::TexImage2D( | 936 bool SkCanvasVideoRenderer::TexImage2D( |
| 980 unsigned target, | 937 unsigned target, |
| 981 unsigned texture, | 938 unsigned texture, |
| 982 gpu::gles2::GLES2Interface* gl, | 939 gpu::gles2::GLES2Interface* gl, |
| 983 const gpu::Capabilities& gpu_capabilities, | 940 const gpu::Capabilities& gpu_capabilities, |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1098 last_image_->bounds().contains(visible_rect)) { | 1055 last_image_->bounds().contains(visible_rect)) { |
| 1099 last_image_ = last_image_->makeSubset(visible_rect); | 1056 last_image_ = last_image_->makeSubset(visible_rect); |
| 1100 } | 1057 } |
| 1101 } | 1058 } |
| 1102 | 1059 |
| 1103 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() { | 1060 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() { |
| 1104 return last_image_dimensions_for_testing_; | 1061 return last_image_dimensions_for_testing_; |
| 1105 } | 1062 } |
| 1106 | 1063 |
| 1107 } // namespace media | 1064 } // namespace media |
| OLD | NEW |