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; |