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