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

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: Rebased. 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
« no previous file with comments | « media/renderers/skcanvas_video_renderer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 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
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
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
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
OLDNEW
« no previous file with comments | « media/renderers/skcanvas_video_renderer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698