Chromium Code Reviews| Index: media/renderers/skcanvas_video_renderer.cc |
| diff --git a/media/renderers/skcanvas_video_renderer.cc b/media/renderers/skcanvas_video_renderer.cc |
| index 1e2e9b21ab1a7e25977f25aeb0a8452a56a533ca..6f9cb7c815b75af4782708c97fbfb6b31430e8f2 100644 |
| --- a/media/renderers/skcanvas_video_renderer.cc |
| +++ b/media/renderers/skcanvas_video_renderer.cc |
| @@ -160,6 +160,26 @@ sk_sp<SkImage> NewSkImageFromVideoFrameYUVTextures( |
| return img; |
| } |
| +bool VideoTextureNeedsClipping(const VideoFrame* video_frame) { |
| + // There are multiple reasons that the size of the video frame's |
| + // visible rectangle may differ from the coded size, including the |
| + // encoder rounding up to the size of a macroblock, or use of |
| + // non-square pixels. |
| + // |
| + // Some callers of these APIs (HTMLVideoElement and the 2D canvas |
| + // context) already clip to the video frame's visible rectangle. |
| + // WebGL on the other hand assumes that only the valid pixels are |
| + // contained in the destination texture. This helper function |
| + // determines whether this slower path is needed. |
| + 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
|
| +} |
| + |
| +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
|
| + gfx::Size result = video_frame->natural_size(); |
| + result.SetToMin(video_frame->coded_size()); |
| + return result; |
| +} |
| + |
| // Creates a SkImage from a |video_frame| backed by native resources. |
| // The SkImage will take ownership of the underlying resource. |
| sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame, |
| @@ -184,12 +204,10 @@ sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame, |
| gl->GenTextures(1, &source_texture); |
| DCHECK(source_texture); |
| gl->BindTexture(GL_TEXTURE_2D, source_texture); |
| - const gfx::Size& natural_size = video_frame->natural_size(); |
| - gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, natural_size.width(), |
| - natural_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| - nullptr); |
| SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
| - gl, video_frame, source_texture, true, false); |
| + gl, video_frame, |
| + SkCanvasVideoRenderer::SingleFrameForVideoElementOrCanvas, |
| + source_texture, GL_RGBA, GL_UNSIGNED_BYTE, true, false); |
| } else { |
| gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); |
| source_texture = gl->CreateAndConsumeTextureCHROMIUM( |
| @@ -753,7 +771,10 @@ void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( |
| void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
| gpu::gles2::GLES2Interface* gl, |
| VideoFrame* video_frame, |
| + SingleFrameCopyMode copy_mode, |
| unsigned int texture, |
| + unsigned int internal_format, |
| + unsigned int type, |
| bool premultiply_alpha, |
| bool flip_y) { |
| DCHECK(video_frame); |
| @@ -776,14 +797,35 @@ void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
| // "flip_y == true" means to reverse the video orientation while |
| // "flip_y == false" means to keep the intrinsic orientation. |
| - // The video's texture might be larger than the natural size because |
| - // the encoder might have had to round up to the size of a macroblock. |
| - // Make sure to only copy the natural size to avoid putting garbage |
| - // into the bottom of the destination texture. |
| - const gfx::Size& natural_size = video_frame->natural_size(); |
| - gl->CopySubTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, |
| - 0, 0, natural_size.width(), natural_size.height(), |
| - flip_y, premultiply_alpha, false); |
| + if (copy_mode == SingleFrameForVideoElementOrCanvas || |
| + !VideoTextureNeedsClipping(video_frame)) { |
| + // No need to clip the source video texture. |
| + gl->CopyTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, |
| + internal_format, type, flip_y, premultiply_alpha, |
| + false); |
| + } else { |
| + // Must reallocate the destination texture and copy only a sub-portion. |
| + gfx::Rect dest_rect = video_frame->visible_rect(); |
| +#if DCHECK_IS_ON() |
| + // The caller should have bound _texture_ to the GL_TEXTURE_2D |
| + // binding point already. |
| + GLuint current_texture = 0; |
| + gl->GetIntegerv(GL_TEXTURE_BINDING_2D, |
| + reinterpret_cast<GLint*>(¤t_texture)); |
| + DCHECK_EQ(current_texture, texture); |
| + // There should always be enough data in the source texture to |
| + // cover this copy. |
| + DCHECK_LE(dest_rect.width(), video_frame->coded_size().width()); |
| + 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
|
| +#endif |
| + gl->TexImage2D(GL_TEXTURE_2D, 0, internal_format, dest_rect.width(), |
| + dest_rect.height(), 0, internal_format, type, nullptr); |
| + gl->CopySubTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, 0, |
| + 0, dest_rect.x(), dest_rect.y(), |
| + dest_rect.width(), dest_rect.height(), flip_y, |
| + premultiply_alpha, false); |
| + } |
| + |
| gl->DeleteTextures(1, &source_texture); |
| gl->Flush(); |
| @@ -796,6 +838,8 @@ bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( |
| gpu::gles2::GLES2Interface* destination_gl, |
| const scoped_refptr<VideoFrame>& video_frame, |
| unsigned int texture, |
| + unsigned int internal_format, |
| + unsigned int type, |
| bool premultiply_alpha, |
| bool flip_y) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| @@ -832,15 +876,35 @@ bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( |
| destination_gl->CreateAndConsumeTextureCHROMIUM( |
| mailbox_holder.texture_target, mailbox_holder.mailbox.name); |
| - // The video's texture might be larger than the natural size because |
| - // the encoder might have had to round up to the size of a macroblock. |
| - // Make sure to only copy the natural size to avoid putting garbage |
| - // into the bottom of the destination texture. |
| - const gfx::Size& natural_size = video_frame->natural_size(); |
| - destination_gl->CopySubTextureCHROMIUM( |
| - intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, 0, 0, |
| - natural_size.width(), natural_size.height(), flip_y, premultiply_alpha, |
| - false); |
| + // See whether the source video texture must be clipped. |
| + if (VideoTextureNeedsClipping(video_frame.get())) { |
| + // Reallocate destination texture and copy only valid region. |
| + gfx::Size dest_rect = video_frame->visible_rect(); |
| +#if DCHECK_IS_ON() |
| + // The caller should have bound _texture_ to the GL_TEXTURE_2D |
| + // binding point already. |
| + GLuint current_texture = 0; |
| + destination_gl->GetIntegerv(GL_TEXTURE_BINDING_2D, |
| + reinterpret_cast<GLint*>(¤t_texture)); |
| + DCHECK_EQ(current_texture, texture); |
| + // There should always be enough data in the source texture to |
| + // cover this copy. |
| + DCHECK_LE(dest_rect.width(), video_frame->coded_size().width()); |
| + DCHECK_LE(dest_rect.height(), video_frame->coded_size().height()); |
| +#endif |
| + destination_gl->TexImage2D(GL_TEXTURE_2D, 0, internal_format, |
| + dest_rect.width(), dest_rect.height(), 0, |
| + internal_format, type, nullptr); |
| + destination_gl->CopySubTextureCHROMIUM( |
| + intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, |
| + dest_rect.x(), dest_rect.y(), dest_rect.width(), dest_rect.height(), |
| + flip_y, premultiply_alpha, false); |
| + } else { |
| + destination_gl->CopyTextureCHROMIUM( |
| + intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, internal_format, |
| + type, flip_y, premultiply_alpha, false); |
| + } |
| + |
| destination_gl->DeleteTextures(1, &intermediate_texture); |
| // Wait for destination context to consume mailbox before deleting it in |
| @@ -855,8 +919,9 @@ bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( |
| SyncTokenClientImpl client(canvas_gl); |
| video_frame->UpdateReleaseSyncToken(&client); |
| } else { |
| - CopyVideoFrameSingleTextureToGLTexture(destination_gl, video_frame.get(), |
| - texture, premultiply_alpha, flip_y); |
| + CopyVideoFrameSingleTextureToGLTexture( |
| + destination_gl, video_frame.get(), SingleFrameForWebGL, texture, |
| + internal_format, type, premultiply_alpha, flip_y); |
| } |
| return true; |