Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(475)

Side by Side Diff: media/renderers/skcanvas_video_renderer.cc

Issue 2791813003: Fix broken draw/upload paths from videos to 2D canvas and WebGL. (Closed)
Patch Set: Fixed bug in error checking code. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 bool VideoTextureSizeNeedsAdjustment(const VideoFrame* video_frame) {
164 // There are multiple reasons that the video frame's natural size
165 // may differ from the coded size, including the encoder rounding up
166 // to the size of a macroblock, or use of non-square pixels.
167 //
168 // Some callers of these APIs (HTMLVideoElement and the 2D canvas
169 // context) already clip to the video frame's visible rectangle.
170 // WebGL on the other hand assumes that only the valid pixels are
171 // contained in the destination texture. This helper function
172 // determines whether this slower path is needed.
173 return video_frame->natural_size() != video_frame->coded_size();
sandersd (OOO until July 31) 2017/04/07 19:07:13 I'm not sure which check you are intending here. T
Ken Russell (switch to Gerrit) 2017/04/07 19:27:23 Thanks for the info. The reason I didn't look at
sandersd (OOO until July 31) 2017/04/07 20:58:06 If we don't have the option of scaling, then the o
Ken Russell (switch to Gerrit) 2017/04/07 21:15:27 Can the coded size or natural size be smaller (in
sandersd (OOO until July 31) 2017/04/07 21:41:57 Strict rules: - Visible rect must be a subset of
Ken Russell (switch to Gerrit) 2017/04/07 23:22:09 OK. Thanks for your feedback. I've revised the fix
174 }
175
176 gfx::Size AdjustedVideoTextureSize(const VideoFrame* video_frame) {
177 gfx::Size result = video_frame->natural_size();
178 result.SetToMin(video_frame->coded_size());
179 return result;
180 }
181
163 // Creates a SkImage from a |video_frame| backed by native resources. 182 // Creates a SkImage from a |video_frame| backed by native resources.
164 // The SkImage will take ownership of the underlying resource. 183 // The SkImage will take ownership of the underlying resource.
165 sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame, 184 sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame,
166 const Context3D& context_3d) { 185 const Context3D& context_3d) {
167 DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() || 186 DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() ||
168 PIXEL_FORMAT_XRGB == video_frame->format() || 187 PIXEL_FORMAT_XRGB == video_frame->format() ||
169 PIXEL_FORMAT_NV12 == video_frame->format() || 188 PIXEL_FORMAT_NV12 == video_frame->format() ||
170 PIXEL_FORMAT_UYVY == video_frame->format()); 189 PIXEL_FORMAT_UYVY == video_frame->format());
171 190
172 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); 191 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
173 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || 192 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
174 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || 193 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
175 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) 194 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
176 << mailbox_holder.texture_target; 195 << mailbox_holder.texture_target;
177 196
178 gpu::gles2::GLES2Interface* gl = context_3d.gl; 197 gpu::gles2::GLES2Interface* gl = context_3d.gl;
179 unsigned source_texture = 0; 198 unsigned source_texture = 0;
180 if (mailbox_holder.texture_target != GL_TEXTURE_2D) { 199 if (mailbox_holder.texture_target != GL_TEXTURE_2D) {
181 // TODO(dcastagna): At the moment Skia doesn't support targets different 200 // TODO(dcastagna): At the moment Skia doesn't support targets different
182 // than GL_TEXTURE_2D. Avoid this copy once 201 // than GL_TEXTURE_2D. Avoid this copy once
183 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed. 202 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed.
184 gl->GenTextures(1, &source_texture); 203 gl->GenTextures(1, &source_texture);
185 DCHECK(source_texture); 204 DCHECK(source_texture);
186 gl->BindTexture(GL_TEXTURE_2D, source_texture); 205 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( 206 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
192 gl, video_frame, source_texture, true, false); 207 gl, video_frame,
208 SkCanvasVideoRenderer::SingleFrameForVideoElementOrCanvas,
209 source_texture, GL_RGBA, GL_UNSIGNED_BYTE, true, false);
193 } else { 210 } else {
194 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); 211 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData());
195 source_texture = gl->CreateAndConsumeTextureCHROMIUM( 212 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
196 mailbox_holder.texture_target, mailbox_holder.mailbox.name); 213 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
197 } 214 }
198 GrBackendTextureDesc desc; 215 GrBackendTextureDesc desc;
199 desc.fFlags = kRenderTarget_GrBackendTextureFlag; 216 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
200 desc.fOrigin = kTopLeft_GrSurfaceOrigin; 217 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
201 desc.fWidth = video_frame->coded_size().width(); 218 desc.fWidth = video_frame->coded_size().width();
202 desc.fHeight = video_frame->coded_size().height(); 219 desc.fHeight = video_frame->coded_size().height();
(...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 case PIXEL_FORMAT_Y8: 763 case PIXEL_FORMAT_Y8:
747 case PIXEL_FORMAT_UNKNOWN: 764 case PIXEL_FORMAT_UNKNOWN:
748 NOTREACHED() << "Only YUV formats and Y16 are supported."; 765 NOTREACHED() << "Only YUV formats and Y16 are supported.";
749 } 766 }
750 } 767 }
751 768
752 // static 769 // static
753 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( 770 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
754 gpu::gles2::GLES2Interface* gl, 771 gpu::gles2::GLES2Interface* gl,
755 VideoFrame* video_frame, 772 VideoFrame* video_frame,
773 SingleFrameCopyMode copy_mode,
756 unsigned int texture, 774 unsigned int texture,
775 unsigned int internal_format,
776 unsigned int type,
757 bool premultiply_alpha, 777 bool premultiply_alpha,
758 bool flip_y) { 778 bool flip_y) {
759 DCHECK(video_frame); 779 DCHECK(video_frame);
760 DCHECK(video_frame->HasTextures()); 780 DCHECK(video_frame->HasTextures());
761 781
762 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); 782 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
763 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || 783 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
764 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || 784 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
765 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) 785 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
766 << mailbox_holder.texture_target; 786 << mailbox_holder.texture_target;
767 787
768 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); 788 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData());
769 uint32_t source_texture = gl->CreateAndConsumeTextureCHROMIUM( 789 uint32_t source_texture = gl->CreateAndConsumeTextureCHROMIUM(
770 mailbox_holder.texture_target, mailbox_holder.mailbox.name); 790 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
771 791
772 // The video is stored in a unmultiplied format, so premultiply 792 // The video is stored in a unmultiplied format, so premultiply
773 // if necessary. 793 // if necessary.
774 // Application itself needs to take care of setting the right |flip_y| 794 // Application itself needs to take care of setting the right |flip_y|
775 // value down to get the expected result. 795 // value down to get the expected result.
776 // "flip_y == true" means to reverse the video orientation while 796 // "flip_y == true" means to reverse the video orientation while
777 // "flip_y == false" means to keep the intrinsic orientation. 797 // "flip_y == false" means to keep the intrinsic orientation.
778 798
779 // The video's texture might be larger than the natural size because 799 if (copy_mode == SingleFrameForVideoElementOrCanvas ||
780 // the encoder might have had to round up to the size of a macroblock. 800 !VideoTextureSizeNeedsAdjustment(video_frame)) {
781 // Make sure to only copy the natural size to avoid putting garbage 801 // No need to clip the source video texture.
782 // into the bottom of the destination texture. 802 gl->CopyTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0,
783 const gfx::Size& natural_size = video_frame->natural_size(); 803 internal_format, type, flip_y, premultiply_alpha,
784 gl->CopySubTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, 804 false);
785 0, 0, natural_size.width(), natural_size.height(), 805 } else {
786 flip_y, premultiply_alpha, false); 806 // Must reallocate the destination texture and copy only a sub-portion.
807 gfx::Size dest_size = AdjustedVideoTextureSize(video_frame);
808 #if DCHECK_IS_ON()
809 // The caller should have bound _texture_ to the GL_TEXTURE_2D
810 // binding point already.
811 GLuint current_texture = 0;
812 gl->GetIntegerv(GL_TEXTURE_BINDING_2D,
813 reinterpret_cast<GLint*>(&current_texture));
814 DCHECK_EQ(current_texture, texture);
815 #endif
816 gl->TexImage2D(GL_TEXTURE_2D, 0, internal_format, dest_size.width(),
817 dest_size.height(), 0, internal_format, type, nullptr);
818 gl->CopySubTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, 0,
819 0, 0, 0, dest_size.width(), dest_size.height(),
820 flip_y, premultiply_alpha, false);
821 }
822
787 gl->DeleteTextures(1, &source_texture); 823 gl->DeleteTextures(1, &source_texture);
788 gl->Flush(); 824 gl->Flush();
789 825
790 SyncTokenClientImpl client(gl); 826 SyncTokenClientImpl client(gl);
791 video_frame->UpdateReleaseSyncToken(&client); 827 video_frame->UpdateReleaseSyncToken(&client);
792 } 828 }
793 829
794 bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( 830 bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture(
795 const Context3D& context_3d, 831 const Context3D& context_3d,
796 gpu::gles2::GLES2Interface* destination_gl, 832 gpu::gles2::GLES2Interface* destination_gl,
797 const scoped_refptr<VideoFrame>& video_frame, 833 const scoped_refptr<VideoFrame>& video_frame,
798 unsigned int texture, 834 unsigned int texture,
835 unsigned int internal_format,
836 unsigned int type,
799 bool premultiply_alpha, 837 bool premultiply_alpha,
800 bool flip_y) { 838 bool flip_y) {
801 DCHECK(thread_checker_.CalledOnValidThread()); 839 DCHECK(thread_checker_.CalledOnValidThread());
802 DCHECK(video_frame); 840 DCHECK(video_frame);
803 DCHECK(video_frame->HasTextures()); 841 DCHECK(video_frame->HasTextures());
804 if (media::VideoFrame::NumPlanes(video_frame->format()) > 1) { 842 if (media::VideoFrame::NumPlanes(video_frame->format()) > 1) {
805 if (!context_3d.gr_context) 843 if (!context_3d.gr_context)
806 return false; 844 return false;
807 if (!UpdateLastImage(video_frame, context_3d)) 845 if (!UpdateLastImage(video_frame, context_3d))
808 return false; 846 return false;
(...skipping 16 matching lines...) Expand all
825 canvas_gl->ShallowFlushCHROMIUM(); 863 canvas_gl->ShallowFlushCHROMIUM();
826 canvas_gl->GenSyncTokenCHROMIUM(fence_sync, 864 canvas_gl->GenSyncTokenCHROMIUM(fence_sync,
827 mailbox_holder.sync_token.GetData()); 865 mailbox_holder.sync_token.GetData());
828 866
829 destination_gl->WaitSyncTokenCHROMIUM( 867 destination_gl->WaitSyncTokenCHROMIUM(
830 mailbox_holder.sync_token.GetConstData()); 868 mailbox_holder.sync_token.GetConstData());
831 uint32_t intermediate_texture = 869 uint32_t intermediate_texture =
832 destination_gl->CreateAndConsumeTextureCHROMIUM( 870 destination_gl->CreateAndConsumeTextureCHROMIUM(
833 mailbox_holder.texture_target, mailbox_holder.mailbox.name); 871 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
834 872
835 // The video's texture might be larger than the natural size because 873 // See whether the source video texture must be clipped.
836 // the encoder might have had to round up to the size of a macroblock. 874 if (VideoTextureSizeNeedsAdjustment(video_frame.get())) {
837 // Make sure to only copy the natural size to avoid putting garbage 875 // Reallocate destination texture and copy only valid region.
838 // into the bottom of the destination texture. 876 gfx::Size dest_size = AdjustedVideoTextureSize(video_frame.get());
839 const gfx::Size& natural_size = video_frame->natural_size(); 877 #if DCHECK_IS_ON()
840 destination_gl->CopySubTextureCHROMIUM( 878 // The caller should have bound _texture_ to the GL_TEXTURE_2D
841 intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, 0, 0, 879 // binding point already.
842 natural_size.width(), natural_size.height(), flip_y, premultiply_alpha, 880 GLuint current_texture = 0;
843 false); 881 destination_gl->GetIntegerv(GL_TEXTURE_BINDING_2D,
882 reinterpret_cast<GLint*>(&current_texture));
883 DCHECK_EQ(current_texture, texture);
884 #endif
885 destination_gl->TexImage2D(GL_TEXTURE_2D, 0, internal_format,
886 dest_size.width(), dest_size.height(), 0,
887 internal_format, type, nullptr);
888 destination_gl->CopySubTextureCHROMIUM(
889 intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, 0, 0,
890 dest_size.width(), dest_size.height(), flip_y, premultiply_alpha,
891 false);
892 } else {
893 destination_gl->CopyTextureCHROMIUM(
894 intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, internal_format,
895 type, flip_y, premultiply_alpha, false);
896 }
897
844 destination_gl->DeleteTextures(1, &intermediate_texture); 898 destination_gl->DeleteTextures(1, &intermediate_texture);
845 899
846 // Wait for destination context to consume mailbox before deleting it in 900 // Wait for destination context to consume mailbox before deleting it in
847 // canvas context. 901 // canvas context.
848 const GLuint64 dest_fence_sync = destination_gl->InsertFenceSyncCHROMIUM(); 902 const GLuint64 dest_fence_sync = destination_gl->InsertFenceSyncCHROMIUM();
849 destination_gl->ShallowFlushCHROMIUM(); 903 destination_gl->ShallowFlushCHROMIUM();
850 gpu::SyncToken dest_sync_token; 904 gpu::SyncToken dest_sync_token;
851 destination_gl->GenSyncTokenCHROMIUM(dest_fence_sync, 905 destination_gl->GenSyncTokenCHROMIUM(dest_fence_sync,
852 dest_sync_token.GetData()); 906 dest_sync_token.GetData());
853 canvas_gl->WaitSyncTokenCHROMIUM(dest_sync_token.GetConstData()); 907 canvas_gl->WaitSyncTokenCHROMIUM(dest_sync_token.GetConstData());
854 908
855 SyncTokenClientImpl client(canvas_gl); 909 SyncTokenClientImpl client(canvas_gl);
856 video_frame->UpdateReleaseSyncToken(&client); 910 video_frame->UpdateReleaseSyncToken(&client);
857 } else { 911 } else {
858 CopyVideoFrameSingleTextureToGLTexture(destination_gl, video_frame.get(), 912 CopyVideoFrameSingleTextureToGLTexture(
859 texture, premultiply_alpha, flip_y); 913 destination_gl, video_frame.get(), SingleFrameForWebGL, texture,
914 internal_format, type, premultiply_alpha, flip_y);
860 } 915 }
861 916
862 return true; 917 return true;
863 } 918 }
864 919
865 bool SkCanvasVideoRenderer::TexImage2D(unsigned target, 920 bool SkCanvasVideoRenderer::TexImage2D(unsigned target,
866 gpu::gles2::GLES2Interface* gl, 921 gpu::gles2::GLES2Interface* gl,
867 VideoFrame* frame, 922 VideoFrame* frame,
868 int level, 923 int level,
869 int internalformat, 924 int internalformat,
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
957 last_image_->bounds().contains(visible_rect)) { 1012 last_image_->bounds().contains(visible_rect)) {
958 last_image_ = last_image_->makeSubset(visible_rect); 1013 last_image_ = last_image_->makeSubset(visible_rect);
959 } 1014 }
960 } 1015 }
961 1016
962 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() { 1017 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() {
963 return last_image_dimensions_for_testing_; 1018 return last_image_dimensions_for_testing_;
964 } 1019 }
965 1020
966 } // namespace media 1021 } // namespace media
OLDNEW
« no previous file with comments | « media/renderers/skcanvas_video_renderer.h ('k') | third_party/WebKit/Source/core/html/HTMLVideoElement.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698