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

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: Fix per review feedback from sandersd@. 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 VideoTextureNeedsClipping(const VideoFrame* video_frame) {
164 // There are multiple reasons that the size of the video frame's
165 // visible rectangle may differ from the coded size, including the
166 // encoder rounding up to the size of a macroblock, or use of
167 // non-square pixels.
168 //
169 // Some callers of these APIs (HTMLVideoElement and the 2D canvas
170 // context) already clip to the video frame's visible rectangle.
171 // WebGL on the other hand assumes that only the valid pixels are
172 // contained in the destination texture. This helper function
173 // determines whether this slower path is needed.
174 return video_frame->visible_rect().size() != video_frame->coded_size();
sandersd (OOO until July 31) 2017/04/07 23:40:59 Might be more clear as Rect(coded_size() == visibl
Ken Russell (switch to Gerrit) 2017/04/07 23:48:18 WebGL's the only consumer of the code paths where
sandersd (OOO until July 31) 2017/04/07 23:51:53 My question is about the source texture though. Wh
Ken Russell (switch to Gerrit) 2017/04/07 23:54:51 Yes, that's my assumption. It appeared to be the c
sandersd (OOO until July 31) 2017/04/08 00:01:25 I'm not sure. I believe it is true when we create
sandersd (OOO until July 31) 2017/04/08 00:05:04 Upon reflection, I think Android is the only worry
sandersd (OOO until July 31) 2017/04/08 00:07:14 Relevant Android code is here: https://cs.chromium
175 }
176
177 gfx::Size AdjustedVideoTextureSize(const VideoFrame* video_frame) {
sandersd (OOO until July 31) 2017/04/07 23:40:59 Unused?
Ken Russell (switch to Gerrit) 2017/04/07 23:48:18 Fixed in next (current) patch set. I was still in
178 gfx::Size result = video_frame->natural_size();
179 result.SetToMin(video_frame->coded_size());
180 return result;
181 }
182
163 // Creates a SkImage from a |video_frame| backed by native resources. 183 // Creates a SkImage from a |video_frame| backed by native resources.
164 // The SkImage will take ownership of the underlying resource. 184 // The SkImage will take ownership of the underlying resource.
165 sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame, 185 sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame,
166 const Context3D& context_3d) { 186 const Context3D& context_3d) {
167 DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() || 187 DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() ||
168 PIXEL_FORMAT_XRGB == video_frame->format() || 188 PIXEL_FORMAT_XRGB == video_frame->format() ||
169 PIXEL_FORMAT_NV12 == video_frame->format() || 189 PIXEL_FORMAT_NV12 == video_frame->format() ||
170 PIXEL_FORMAT_UYVY == video_frame->format()); 190 PIXEL_FORMAT_UYVY == video_frame->format());
171 191
172 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); 192 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
173 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || 193 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
174 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || 194 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
175 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) 195 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
176 << mailbox_holder.texture_target; 196 << mailbox_holder.texture_target;
177 197
178 gpu::gles2::GLES2Interface* gl = context_3d.gl; 198 gpu::gles2::GLES2Interface* gl = context_3d.gl;
179 unsigned source_texture = 0; 199 unsigned source_texture = 0;
180 if (mailbox_holder.texture_target != GL_TEXTURE_2D) { 200 if (mailbox_holder.texture_target != GL_TEXTURE_2D) {
181 // TODO(dcastagna): At the moment Skia doesn't support targets different 201 // TODO(dcastagna): At the moment Skia doesn't support targets different
182 // than GL_TEXTURE_2D. Avoid this copy once 202 // than GL_TEXTURE_2D. Avoid this copy once
183 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed. 203 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed.
184 gl->GenTextures(1, &source_texture); 204 gl->GenTextures(1, &source_texture);
185 DCHECK(source_texture); 205 DCHECK(source_texture);
186 gl->BindTexture(GL_TEXTURE_2D, source_texture); 206 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( 207 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
192 gl, video_frame, source_texture, true, false); 208 gl, video_frame,
209 SkCanvasVideoRenderer::SingleFrameForVideoElementOrCanvas,
210 source_texture, GL_RGBA, GL_UNSIGNED_BYTE, true, false);
193 } else { 211 } else {
194 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); 212 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData());
195 source_texture = gl->CreateAndConsumeTextureCHROMIUM( 213 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
196 mailbox_holder.texture_target, mailbox_holder.mailbox.name); 214 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
197 } 215 }
198 GrBackendTextureDesc desc; 216 GrBackendTextureDesc desc;
199 desc.fFlags = kRenderTarget_GrBackendTextureFlag; 217 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
200 desc.fOrigin = kTopLeft_GrSurfaceOrigin; 218 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
201 desc.fWidth = video_frame->coded_size().width(); 219 desc.fWidth = video_frame->coded_size().width();
202 desc.fHeight = video_frame->coded_size().height(); 220 desc.fHeight = video_frame->coded_size().height();
(...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 case PIXEL_FORMAT_Y8: 764 case PIXEL_FORMAT_Y8:
747 case PIXEL_FORMAT_UNKNOWN: 765 case PIXEL_FORMAT_UNKNOWN:
748 NOTREACHED() << "Only YUV formats and Y16 are supported."; 766 NOTREACHED() << "Only YUV formats and Y16 are supported.";
749 } 767 }
750 } 768 }
751 769
752 // static 770 // static
753 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( 771 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
754 gpu::gles2::GLES2Interface* gl, 772 gpu::gles2::GLES2Interface* gl,
755 VideoFrame* video_frame, 773 VideoFrame* video_frame,
774 SingleFrameCopyMode copy_mode,
756 unsigned int texture, 775 unsigned int texture,
776 unsigned int internal_format,
777 unsigned int type,
757 bool premultiply_alpha, 778 bool premultiply_alpha,
758 bool flip_y) { 779 bool flip_y) {
759 DCHECK(video_frame); 780 DCHECK(video_frame);
760 DCHECK(video_frame->HasTextures()); 781 DCHECK(video_frame->HasTextures());
761 782
762 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); 783 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
763 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || 784 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
764 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || 785 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
765 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) 786 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
766 << mailbox_holder.texture_target; 787 << mailbox_holder.texture_target;
767 788
768 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); 789 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData());
769 uint32_t source_texture = gl->CreateAndConsumeTextureCHROMIUM( 790 uint32_t source_texture = gl->CreateAndConsumeTextureCHROMIUM(
770 mailbox_holder.texture_target, mailbox_holder.mailbox.name); 791 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
771 792
772 // The video is stored in a unmultiplied format, so premultiply 793 // The video is stored in a unmultiplied format, so premultiply
773 // if necessary. 794 // if necessary.
774 // Application itself needs to take care of setting the right |flip_y| 795 // Application itself needs to take care of setting the right |flip_y|
775 // value down to get the expected result. 796 // value down to get the expected result.
776 // "flip_y == true" means to reverse the video orientation while 797 // "flip_y == true" means to reverse the video orientation while
777 // "flip_y == false" means to keep the intrinsic orientation. 798 // "flip_y == false" means to keep the intrinsic orientation.
778 799
779 // The video's texture might be larger than the natural size because 800 if (copy_mode == SingleFrameForVideoElementOrCanvas ||
780 // the encoder might have had to round up to the size of a macroblock. 801 !VideoTextureNeedsClipping(video_frame)) {
781 // Make sure to only copy the natural size to avoid putting garbage 802 // No need to clip the source video texture.
782 // into the bottom of the destination texture. 803 gl->CopyTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0,
783 const gfx::Size& natural_size = video_frame->natural_size(); 804 internal_format, type, flip_y, premultiply_alpha,
784 gl->CopySubTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, 805 false);
785 0, 0, natural_size.width(), natural_size.height(), 806 } else {
786 flip_y, premultiply_alpha, false); 807 // Must reallocate the destination texture and copy only a sub-portion.
808 gfx::Rect dest_rect = video_frame->visible_rect();
809 #if DCHECK_IS_ON()
810 // The caller should have bound _texture_ to the GL_TEXTURE_2D
811 // binding point already.
812 GLuint current_texture = 0;
813 gl->GetIntegerv(GL_TEXTURE_BINDING_2D,
814 reinterpret_cast<GLint*>(&current_texture));
815 DCHECK_EQ(current_texture, texture);
816 // There should always be enough data in the source texture to
817 // cover this copy.
818 DCHECK_LE(dest_rect.width(), video_frame->coded_size().width());
819 DCHECK_LE(dest_rect.height(), video_frame->coded_size().height());
sandersd (OOO until July 31) 2017/04/07 23:40:59 Perhaps better written as Rect(coded_size()).Conta
820 #endif
821 gl->TexImage2D(GL_TEXTURE_2D, 0, internal_format, dest_rect.width(),
822 dest_rect.height(), 0, internal_format, type, nullptr);
823 gl->CopySubTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, 0,
824 0, dest_rect.x(), dest_rect.y(),
825 dest_rect.width(), dest_rect.height(), flip_y,
826 premultiply_alpha, false);
827 }
828
787 gl->DeleteTextures(1, &source_texture); 829 gl->DeleteTextures(1, &source_texture);
788 gl->Flush(); 830 gl->Flush();
789 831
790 SyncTokenClientImpl client(gl); 832 SyncTokenClientImpl client(gl);
791 video_frame->UpdateReleaseSyncToken(&client); 833 video_frame->UpdateReleaseSyncToken(&client);
792 } 834 }
793 835
794 bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( 836 bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture(
795 const Context3D& context_3d, 837 const Context3D& context_3d,
796 gpu::gles2::GLES2Interface* destination_gl, 838 gpu::gles2::GLES2Interface* destination_gl,
797 const scoped_refptr<VideoFrame>& video_frame, 839 const scoped_refptr<VideoFrame>& video_frame,
798 unsigned int texture, 840 unsigned int texture,
841 unsigned int internal_format,
842 unsigned int type,
799 bool premultiply_alpha, 843 bool premultiply_alpha,
800 bool flip_y) { 844 bool flip_y) {
801 DCHECK(thread_checker_.CalledOnValidThread()); 845 DCHECK(thread_checker_.CalledOnValidThread());
802 DCHECK(video_frame); 846 DCHECK(video_frame);
803 DCHECK(video_frame->HasTextures()); 847 DCHECK(video_frame->HasTextures());
804 if (media::VideoFrame::NumPlanes(video_frame->format()) > 1) { 848 if (media::VideoFrame::NumPlanes(video_frame->format()) > 1) {
805 if (!context_3d.gr_context) 849 if (!context_3d.gr_context)
806 return false; 850 return false;
807 if (!UpdateLastImage(video_frame, context_3d)) 851 if (!UpdateLastImage(video_frame, context_3d))
808 return false; 852 return false;
(...skipping 16 matching lines...) Expand all
825 canvas_gl->ShallowFlushCHROMIUM(); 869 canvas_gl->ShallowFlushCHROMIUM();
826 canvas_gl->GenSyncTokenCHROMIUM(fence_sync, 870 canvas_gl->GenSyncTokenCHROMIUM(fence_sync,
827 mailbox_holder.sync_token.GetData()); 871 mailbox_holder.sync_token.GetData());
828 872
829 destination_gl->WaitSyncTokenCHROMIUM( 873 destination_gl->WaitSyncTokenCHROMIUM(
830 mailbox_holder.sync_token.GetConstData()); 874 mailbox_holder.sync_token.GetConstData());
831 uint32_t intermediate_texture = 875 uint32_t intermediate_texture =
832 destination_gl->CreateAndConsumeTextureCHROMIUM( 876 destination_gl->CreateAndConsumeTextureCHROMIUM(
833 mailbox_holder.texture_target, mailbox_holder.mailbox.name); 877 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
834 878
835 // The video's texture might be larger than the natural size because 879 // See whether the source video texture must be clipped.
836 // the encoder might have had to round up to the size of a macroblock. 880 if (VideoTextureNeedsClipping(video_frame.get())) {
837 // Make sure to only copy the natural size to avoid putting garbage 881 // Reallocate destination texture and copy only valid region.
838 // into the bottom of the destination texture. 882 gfx::Size dest_rect = video_frame->visible_rect();
839 const gfx::Size& natural_size = video_frame->natural_size(); 883 #if DCHECK_IS_ON()
840 destination_gl->CopySubTextureCHROMIUM( 884 // The caller should have bound _texture_ to the GL_TEXTURE_2D
841 intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, 0, 0, 885 // binding point already.
842 natural_size.width(), natural_size.height(), flip_y, premultiply_alpha, 886 GLuint current_texture = 0;
843 false); 887 destination_gl->GetIntegerv(GL_TEXTURE_BINDING_2D,
888 reinterpret_cast<GLint*>(&current_texture));
889 DCHECK_EQ(current_texture, texture);
890 // There should always be enough data in the source texture to
891 // cover this copy.
892 DCHECK_LE(dest_rect.width(), video_frame->coded_size().width());
893 DCHECK_LE(dest_rect.height(), video_frame->coded_size().height());
894 #endif
895 destination_gl->TexImage2D(GL_TEXTURE_2D, 0, internal_format,
896 dest_rect.width(), dest_rect.height(), 0,
897 internal_format, type, nullptr);
898 destination_gl->CopySubTextureCHROMIUM(
899 intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0,
900 dest_rect.x(), dest_rect.y(), dest_rect.width(), dest_rect.height(),
901 flip_y, premultiply_alpha, false);
902 } else {
903 destination_gl->CopyTextureCHROMIUM(
904 intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, internal_format,
905 type, flip_y, premultiply_alpha, false);
906 }
907
844 destination_gl->DeleteTextures(1, &intermediate_texture); 908 destination_gl->DeleteTextures(1, &intermediate_texture);
845 909
846 // Wait for destination context to consume mailbox before deleting it in 910 // Wait for destination context to consume mailbox before deleting it in
847 // canvas context. 911 // canvas context.
848 const GLuint64 dest_fence_sync = destination_gl->InsertFenceSyncCHROMIUM(); 912 const GLuint64 dest_fence_sync = destination_gl->InsertFenceSyncCHROMIUM();
849 destination_gl->ShallowFlushCHROMIUM(); 913 destination_gl->ShallowFlushCHROMIUM();
850 gpu::SyncToken dest_sync_token; 914 gpu::SyncToken dest_sync_token;
851 destination_gl->GenSyncTokenCHROMIUM(dest_fence_sync, 915 destination_gl->GenSyncTokenCHROMIUM(dest_fence_sync,
852 dest_sync_token.GetData()); 916 dest_sync_token.GetData());
853 canvas_gl->WaitSyncTokenCHROMIUM(dest_sync_token.GetConstData()); 917 canvas_gl->WaitSyncTokenCHROMIUM(dest_sync_token.GetConstData());
854 918
855 SyncTokenClientImpl client(canvas_gl); 919 SyncTokenClientImpl client(canvas_gl);
856 video_frame->UpdateReleaseSyncToken(&client); 920 video_frame->UpdateReleaseSyncToken(&client);
857 } else { 921 } else {
858 CopyVideoFrameSingleTextureToGLTexture(destination_gl, video_frame.get(), 922 CopyVideoFrameSingleTextureToGLTexture(
859 texture, premultiply_alpha, flip_y); 923 destination_gl, video_frame.get(), SingleFrameForWebGL, texture,
924 internal_format, type, premultiply_alpha, flip_y);
860 } 925 }
861 926
862 return true; 927 return true;
863 } 928 }
864 929
865 bool SkCanvasVideoRenderer::TexImage2D(unsigned target, 930 bool SkCanvasVideoRenderer::TexImage2D(unsigned target,
866 gpu::gles2::GLES2Interface* gl, 931 gpu::gles2::GLES2Interface* gl,
867 VideoFrame* frame, 932 VideoFrame* frame,
868 int level, 933 int level,
869 int internalformat, 934 int internalformat,
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
957 last_image_->bounds().contains(visible_rect)) { 1022 last_image_->bounds().contains(visible_rect)) {
958 last_image_ = last_image_->makeSubset(visible_rect); 1023 last_image_ = last_image_->makeSubset(visible_rect);
959 } 1024 }
960 } 1025 }
961 1026
962 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() { 1027 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() {
963 return last_image_dimensions_for_testing_; 1028 return last_image_dimensions_for_testing_;
964 } 1029 }
965 1030
966 } // namespace media 1031 } // 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