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 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
153 handles, yuvSizes, | 153 handles, yuvSizes, |
154 kTopLeft_GrSurfaceOrigin); | 154 kTopLeft_GrSurfaceOrigin); |
155 } | 155 } |
156 for (size_t i = 0; i < media::VideoFrame::NumPlanes(video_frame->format()); | 156 for (size_t i = 0; i < media::VideoFrame::NumPlanes(video_frame->format()); |
157 ++i) { | 157 ++i) { |
158 gl->DeleteTextures(1, &source_textures[i].fID); | 158 gl->DeleteTextures(1, &source_textures[i].fID); |
159 } | 159 } |
160 return img; | 160 return img; |
161 } | 161 } |
162 | 162 |
163 gfx::Size MinVideoFrameSize(const VideoFrame* video_frame) { | |
164 // On some platforms, and in some situations, the video's texture might | |
165 // be larger than the natural size because the encoder might have had to | |
166 // round up to the size of a macroblock. | |
167 // | |
168 // In other situations, the natural size has been seen to be _larger_ | |
169 // than the coded size -- despite the fact that this means that there are | |
170 // regions not actually covered by decoded video data! This appears to | |
171 // happen if the Sample Aspect Ratio in the video's metadata is slightly | |
172 // incorrect. | |
sandersd (OOO until July 31)
2017/04/03 18:56:21
This wording is misleading; it implies that normal
Ken Russell (switch to Gerrit)
2017/04/03 20:43:32
Thanks for these clarifications. Sorry for the mis
sandersd (OOO until July 31)
2017/04/03 21:19:10
Reading the WebGL spec, I'm not certain what it ac
Ken Russell (switch to Gerrit)
2017/04/07 07:16:00
Agreed that the spec needs to be clarified. There
| |
173 // | |
174 // Callers of some of the APIs in this file are responsible for | |
175 // allocating the textures into which the video data goes. The only | |
176 // sizing information these callers have are the width and height of the | |
177 // video -- which are inevitably the natural width and height, since | |
178 // that's all that's reliably available in the PipelineMetadata. The | |
179 // destination textures are therefore allocated at this size. | |
180 // | |
181 // To avoid putting garbage into the bottom of the destination frame for | |
182 // the first case, and to avoid mismatches between the source and | |
183 // destination textures in CopySubTextureCHROMIUM operations for the | |
184 // second case, we report the minimum video frame size as the | |
185 // intersection of the coded size and the natural size. | |
186 gfx::Size result = video_frame->natural_size(); | |
187 result.SetToMin(video_frame->coded_size()); | |
188 return result; | |
189 } | |
190 | |
163 // Creates a SkImage from a |video_frame| backed by native resources. | 191 // Creates a SkImage from a |video_frame| backed by native resources. |
164 // The SkImage will take ownership of the underlying resource. | 192 // The SkImage will take ownership of the underlying resource. |
165 sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame, | 193 sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame, |
166 const Context3D& context_3d) { | 194 const Context3D& context_3d) { |
167 DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() || | 195 DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() || |
168 PIXEL_FORMAT_XRGB == video_frame->format() || | 196 PIXEL_FORMAT_XRGB == video_frame->format() || |
169 PIXEL_FORMAT_NV12 == video_frame->format() || | 197 PIXEL_FORMAT_NV12 == video_frame->format() || |
170 PIXEL_FORMAT_UYVY == video_frame->format()); | 198 PIXEL_FORMAT_UYVY == video_frame->format()); |
171 | 199 |
172 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); | 200 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); |
173 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || | 201 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || |
174 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || | 202 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || |
175 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) | 203 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) |
176 << mailbox_holder.texture_target; | 204 << mailbox_holder.texture_target; |
177 | 205 |
178 gpu::gles2::GLES2Interface* gl = context_3d.gl; | 206 gpu::gles2::GLES2Interface* gl = context_3d.gl; |
179 unsigned source_texture = 0; | 207 unsigned source_texture = 0; |
180 if (mailbox_holder.texture_target != GL_TEXTURE_2D) { | 208 if (mailbox_holder.texture_target != GL_TEXTURE_2D) { |
181 // TODO(dcastagna): At the moment Skia doesn't support targets different | 209 // TODO(dcastagna): At the moment Skia doesn't support targets different |
182 // than GL_TEXTURE_2D. Avoid this copy once | 210 // than GL_TEXTURE_2D. Avoid this copy once |
183 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed. | 211 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed. |
184 gl->GenTextures(1, &source_texture); | 212 gl->GenTextures(1, &source_texture); |
185 DCHECK(source_texture); | 213 DCHECK(source_texture); |
186 gl->BindTexture(GL_TEXTURE_2D, source_texture); | 214 gl->BindTexture(GL_TEXTURE_2D, source_texture); |
187 const gfx::Size& natural_size = video_frame->natural_size(); | |
188 gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, natural_size.width(), | |
189 natural_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, | |
190 nullptr); | |
191 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( | 215 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
192 gl, video_frame, source_texture, true, false); | 216 gl, video_frame, SkCanvasVideoRenderer::SingleFrameCopyTexture, |
217 source_texture, GL_RGBA, GL_UNSIGNED_BYTE, true, false); | |
193 } else { | 218 } else { |
194 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); | 219 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); |
195 source_texture = gl->CreateAndConsumeTextureCHROMIUM( | 220 source_texture = gl->CreateAndConsumeTextureCHROMIUM( |
196 mailbox_holder.texture_target, mailbox_holder.mailbox.name); | 221 mailbox_holder.texture_target, mailbox_holder.mailbox.name); |
197 } | 222 } |
198 GrBackendTextureDesc desc; | 223 GrBackendTextureDesc desc; |
199 desc.fFlags = kRenderTarget_GrBackendTextureFlag; | 224 desc.fFlags = kRenderTarget_GrBackendTextureFlag; |
200 desc.fOrigin = kTopLeft_GrSurfaceOrigin; | 225 desc.fOrigin = kTopLeft_GrSurfaceOrigin; |
201 desc.fWidth = video_frame->coded_size().width(); | 226 desc.fWidth = video_frame->coded_size().width(); |
202 desc.fHeight = video_frame->coded_size().height(); | 227 desc.fHeight = video_frame->coded_size().height(); |
(...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
746 case PIXEL_FORMAT_Y8: | 771 case PIXEL_FORMAT_Y8: |
747 case PIXEL_FORMAT_UNKNOWN: | 772 case PIXEL_FORMAT_UNKNOWN: |
748 NOTREACHED() << "Only YUV formats and Y16 are supported."; | 773 NOTREACHED() << "Only YUV formats and Y16 are supported."; |
749 } | 774 } |
750 } | 775 } |
751 | 776 |
752 // static | 777 // static |
753 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( | 778 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
754 gpu::gles2::GLES2Interface* gl, | 779 gpu::gles2::GLES2Interface* gl, |
755 VideoFrame* video_frame, | 780 VideoFrame* video_frame, |
781 SingleFrameCopyMode mode, | |
756 unsigned int texture, | 782 unsigned int texture, |
783 unsigned int internal_format, | |
784 unsigned int type, | |
757 bool premultiply_alpha, | 785 bool premultiply_alpha, |
758 bool flip_y) { | 786 bool flip_y) { |
759 DCHECK(video_frame); | 787 DCHECK(video_frame); |
760 DCHECK(video_frame->HasTextures()); | 788 DCHECK(video_frame->HasTextures()); |
761 | 789 |
762 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); | 790 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); |
763 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || | 791 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || |
764 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || | 792 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || |
765 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) | 793 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) |
766 << mailbox_holder.texture_target; | 794 << mailbox_holder.texture_target; |
767 | 795 |
768 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); | 796 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); |
769 uint32_t source_texture = gl->CreateAndConsumeTextureCHROMIUM( | 797 uint32_t source_texture = gl->CreateAndConsumeTextureCHROMIUM( |
770 mailbox_holder.texture_target, mailbox_holder.mailbox.name); | 798 mailbox_holder.texture_target, mailbox_holder.mailbox.name); |
771 | 799 |
772 // The video is stored in a unmultiplied format, so premultiply | 800 // The video is stored in a unmultiplied format, so premultiply |
773 // if necessary. | 801 // if necessary. |
774 // Application itself needs to take care of setting the right |flip_y| | 802 // Application itself needs to take care of setting the right |flip_y| |
775 // value down to get the expected result. | 803 // value down to get the expected result. |
776 // "flip_y == true" means to reverse the video orientation while | 804 // "flip_y == true" means to reverse the video orientation while |
777 // "flip_y == false" means to keep the intrinsic orientation. | 805 // "flip_y == false" means to keep the intrinsic orientation. |
778 | 806 |
779 // The video's texture might be larger than the natural size because | 807 switch (mode) { |
780 // the encoder might have had to round up to the size of a macroblock. | 808 case SingleFrameCopyTexture: { |
781 // Make sure to only copy the natural size to avoid putting garbage | 809 // Assume that the caller is responsible for clipping the source |
782 // into the bottom of the destination texture. | 810 // texture during rendering to the video's natural width and |
783 const gfx::Size& natural_size = video_frame->natural_size(); | 811 // height. This is done for example during rendering of the actual |
784 gl->CopySubTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, | 812 // video element. |
785 0, 0, natural_size.width(), natural_size.height(), | 813 gl->CopyTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, |
786 flip_y, premultiply_alpha, false); | 814 internal_format, type, flip_y, premultiply_alpha, |
815 false); | |
816 break; | |
817 } | |
818 case SingleFrameCopySubTexture: { | |
819 // Use the minimum of the coded size and natural size to copy only | |
820 // the good portion of the video frame. | |
821 gfx::Size copy_size = MinVideoFrameSize(video_frame); | |
822 gl->CopySubTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, | |
823 0, 0, 0, 0, copy_size.width(), | |
824 copy_size.height(), flip_y, premultiply_alpha, | |
825 false); | |
826 break; | |
827 } | |
828 } | |
829 | |
787 gl->DeleteTextures(1, &source_texture); | 830 gl->DeleteTextures(1, &source_texture); |
788 gl->Flush(); | 831 gl->Flush(); |
789 | 832 |
790 SyncTokenClientImpl client(gl); | 833 SyncTokenClientImpl client(gl); |
791 video_frame->UpdateReleaseSyncToken(&client); | 834 video_frame->UpdateReleaseSyncToken(&client); |
792 } | 835 } |
793 | 836 |
794 bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( | 837 bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( |
795 const Context3D& context_3d, | 838 const Context3D& context_3d, |
796 gpu::gles2::GLES2Interface* destination_gl, | 839 gpu::gles2::GLES2Interface* destination_gl, |
(...skipping 28 matching lines...) Expand all Loading... | |
825 canvas_gl->ShallowFlushCHROMIUM(); | 868 canvas_gl->ShallowFlushCHROMIUM(); |
826 canvas_gl->GenSyncTokenCHROMIUM(fence_sync, | 869 canvas_gl->GenSyncTokenCHROMIUM(fence_sync, |
827 mailbox_holder.sync_token.GetData()); | 870 mailbox_holder.sync_token.GetData()); |
828 | 871 |
829 destination_gl->WaitSyncTokenCHROMIUM( | 872 destination_gl->WaitSyncTokenCHROMIUM( |
830 mailbox_holder.sync_token.GetConstData()); | 873 mailbox_holder.sync_token.GetConstData()); |
831 uint32_t intermediate_texture = | 874 uint32_t intermediate_texture = |
832 destination_gl->CreateAndConsumeTextureCHROMIUM( | 875 destination_gl->CreateAndConsumeTextureCHROMIUM( |
833 mailbox_holder.texture_target, mailbox_holder.mailbox.name); | 876 mailbox_holder.texture_target, mailbox_holder.mailbox.name); |
834 | 877 |
835 // The video's texture might be larger than the natural size because | 878 // Use the minimum of the coded size and natural size to copy only the |
836 // the encoder might have had to round up to the size of a macroblock. | 879 // good portion of the video frame. |
837 // Make sure to only copy the natural size to avoid putting garbage | 880 gfx::Size copy_size = MinVideoFrameSize(video_frame.get()); |
838 // into the bottom of the destination texture. | |
839 const gfx::Size& natural_size = video_frame->natural_size(); | |
840 destination_gl->CopySubTextureCHROMIUM( | 881 destination_gl->CopySubTextureCHROMIUM( |
841 intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, 0, 0, | 882 intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, 0, 0, |
842 natural_size.width(), natural_size.height(), flip_y, premultiply_alpha, | 883 copy_size.width(), copy_size.height(), flip_y, premultiply_alpha, |
843 false); | 884 false); |
844 destination_gl->DeleteTextures(1, &intermediate_texture); | 885 destination_gl->DeleteTextures(1, &intermediate_texture); |
845 | 886 |
846 // Wait for destination context to consume mailbox before deleting it in | 887 // Wait for destination context to consume mailbox before deleting it in |
847 // canvas context. | 888 // canvas context. |
848 const GLuint64 dest_fence_sync = destination_gl->InsertFenceSyncCHROMIUM(); | 889 const GLuint64 dest_fence_sync = destination_gl->InsertFenceSyncCHROMIUM(); |
849 destination_gl->ShallowFlushCHROMIUM(); | 890 destination_gl->ShallowFlushCHROMIUM(); |
850 gpu::SyncToken dest_sync_token; | 891 gpu::SyncToken dest_sync_token; |
851 destination_gl->GenSyncTokenCHROMIUM(dest_fence_sync, | 892 destination_gl->GenSyncTokenCHROMIUM(dest_fence_sync, |
852 dest_sync_token.GetData()); | 893 dest_sync_token.GetData()); |
853 canvas_gl->WaitSyncTokenCHROMIUM(dest_sync_token.GetConstData()); | 894 canvas_gl->WaitSyncTokenCHROMIUM(dest_sync_token.GetConstData()); |
854 | 895 |
855 SyncTokenClientImpl client(canvas_gl); | 896 SyncTokenClientImpl client(canvas_gl); |
856 video_frame->UpdateReleaseSyncToken(&client); | 897 video_frame->UpdateReleaseSyncToken(&client); |
857 } else { | 898 } else { |
858 CopyVideoFrameSingleTextureToGLTexture(destination_gl, video_frame.get(), | 899 CopyVideoFrameSingleTextureToGLTexture( |
859 texture, premultiply_alpha, flip_y); | 900 destination_gl, video_frame.get(), SingleFrameCopySubTexture, texture, |
901 0 /* internal_format */, 0 /* type */, premultiply_alpha, flip_y); | |
860 } | 902 } |
861 | 903 |
862 return true; | 904 return true; |
863 } | 905 } |
864 | 906 |
865 bool SkCanvasVideoRenderer::TexImage2D(unsigned target, | 907 bool SkCanvasVideoRenderer::TexImage2D(unsigned target, |
866 gpu::gles2::GLES2Interface* gl, | 908 gpu::gles2::GLES2Interface* gl, |
867 VideoFrame* frame, | 909 VideoFrame* frame, |
868 int level, | 910 int level, |
869 int internalformat, | 911 int internalformat, |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
957 last_image_->bounds().contains(visible_rect)) { | 999 last_image_->bounds().contains(visible_rect)) { |
958 last_image_ = last_image_->makeSubset(visible_rect); | 1000 last_image_ = last_image_->makeSubset(visible_rect); |
959 } | 1001 } |
960 } | 1002 } |
961 | 1003 |
962 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() { | 1004 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() { |
963 return last_image_dimensions_for_testing_; | 1005 return last_image_dimensions_for_testing_; |
964 } | 1006 } |
965 | 1007 |
966 } // namespace media | 1008 } // namespace media |
OLD | NEW |