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..a35725e89e663adad54293bad17dba7ae672ab9c 100644 |
| --- a/media/renderers/skcanvas_video_renderer.cc |
| +++ b/media/renderers/skcanvas_video_renderer.cc |
| @@ -160,6 +160,34 @@ sk_sp<SkImage> NewSkImageFromVideoFrameYUVTextures( |
| return img; |
| } |
| +gfx::Size MinVideoFrameSize(const VideoFrame* video_frame) { |
| + // On some platforms, and in some situations, 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. |
| + // |
| + // In other situations, the natural size has been seen to be _larger_ |
| + // than the coded size -- despite the fact that this means that there are |
| + // regions not actually covered by decoded video data! This appears to |
| + // happen if the Sample Aspect Ratio in the video's metadata is slightly |
| + // 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
|
| + // |
| + // Callers of some of the APIs in this file are responsible for |
| + // allocating the textures into which the video data goes. The only |
| + // sizing information these callers have are the width and height of the |
| + // video -- which are inevitably the natural width and height, since |
| + // that's all that's reliably available in the PipelineMetadata. The |
| + // destination textures are therefore allocated at this size. |
| + // |
| + // To avoid putting garbage into the bottom of the destination frame for |
| + // the first case, and to avoid mismatches between the source and |
| + // destination textures in CopySubTextureCHROMIUM operations for the |
| + // second case, we report the minimum video frame size as the |
| + // intersection of the coded size and the natural size. |
| + 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 +212,9 @@ 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::SingleFrameCopyTexture, |
| + source_texture, GL_RGBA, GL_UNSIGNED_BYTE, true, false); |
| } else { |
| gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); |
| source_texture = gl->CreateAndConsumeTextureCHROMIUM( |
| @@ -753,7 +778,10 @@ void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( |
| void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
| gpu::gles2::GLES2Interface* gl, |
| VideoFrame* video_frame, |
| + SingleFrameCopyMode mode, |
| unsigned int texture, |
| + unsigned int internal_format, |
| + unsigned int type, |
| bool premultiply_alpha, |
| bool flip_y) { |
| DCHECK(video_frame); |
| @@ -776,14 +804,29 @@ 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); |
| + switch (mode) { |
| + case SingleFrameCopyTexture: { |
| + // Assume that the caller is responsible for clipping the source |
| + // texture during rendering to the video's natural width and |
| + // height. This is done for example during rendering of the actual |
| + // video element. |
| + gl->CopyTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, |
| + internal_format, type, flip_y, premultiply_alpha, |
| + false); |
| + break; |
| + } |
| + case SingleFrameCopySubTexture: { |
| + // Use the minimum of the coded size and natural size to copy only |
| + // the good portion of the video frame. |
| + gfx::Size copy_size = MinVideoFrameSize(video_frame); |
| + gl->CopySubTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, |
| + 0, 0, 0, 0, copy_size.width(), |
| + copy_size.height(), flip_y, premultiply_alpha, |
| + false); |
| + break; |
| + } |
| + } |
| + |
| gl->DeleteTextures(1, &source_texture); |
| gl->Flush(); |
| @@ -832,14 +875,12 @@ 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(); |
| + // Use the minimum of the coded size and natural size to copy only the |
| + // good portion of the video frame. |
| + gfx::Size copy_size = MinVideoFrameSize(video_frame.get()); |
| 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, |
| + copy_size.width(), copy_size.height(), flip_y, premultiply_alpha, |
| false); |
| destination_gl->DeleteTextures(1, &intermediate_texture); |
| @@ -855,8 +896,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(), SingleFrameCopySubTexture, texture, |
| + 0 /* internal_format */, 0 /* type */, premultiply_alpha, flip_y); |
| } |
| return true; |