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..4131dac3b93f14353a96aaf9323a0f160ebd3e79 100644 |
| --- a/media/renderers/skcanvas_video_renderer.cc |
| +++ b/media/renderers/skcanvas_video_renderer.cc |
| @@ -160,6 +160,25 @@ sk_sp<SkImage> NewSkImageFromVideoFrameYUVTextures( |
| return img; |
| } |
| +bool VideoTextureSizeNeedsAdjustment(const VideoFrame* video_frame) { |
| + // There are multiple reasons that the video frame's natural size |
| + // 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->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
|
| +} |
| + |
| +gfx::Size AdjustedVideoTextureSize(const VideoFrame* video_frame) { |
| + 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 +203,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 +770,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 +796,30 @@ 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 || |
| + !VideoTextureSizeNeedsAdjustment(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::Size dest_size = AdjustedVideoTextureSize(video_frame); |
| +#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); |
| +#endif |
| + gl->TexImage2D(GL_TEXTURE_2D, 0, internal_format, dest_size.width(), |
| + dest_size.height(), 0, internal_format, type, nullptr); |
| + gl->CopySubTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, 0, |
| + 0, 0, 0, dest_size.width(), dest_size.height(), |
| + flip_y, premultiply_alpha, false); |
| + } |
| + |
| gl->DeleteTextures(1, &source_texture); |
| gl->Flush(); |
| @@ -796,6 +832,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 +870,31 @@ 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 (VideoTextureSizeNeedsAdjustment(video_frame.get())) { |
| + // Reallocate destination texture and copy only valid region. |
| + gfx::Size dest_size = AdjustedVideoTextureSize(video_frame.get()); |
| +#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); |
| +#endif |
| + destination_gl->TexImage2D(GL_TEXTURE_2D, 0, internal_format, |
| + dest_size.width(), dest_size.height(), 0, |
| + internal_format, type, nullptr); |
| + destination_gl->CopySubTextureCHROMIUM( |
| + intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, 0, 0, |
| + dest_size.width(), dest_size.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 +909,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; |