diff options
41 files changed, 572 insertions, 282 deletions
diff --git a/cc/draw_quad_unittest.cc b/cc/draw_quad_unittest.cc index 2d7055e..a73bbec 100644 --- a/cc/draw_quad_unittest.cc +++ b/cc/draw_quad_unittest.cc @@ -278,36 +278,32 @@ TEST(DrawQuadTest, copyTileDrawQuad) TEST(DrawQuadTest, copyYUVVideoDrawQuad) { + gfx::SizeF texScale(0.75, 0.5); VideoLayerImpl::FramePlane yPlane; yPlane.resourceId = 45; yPlane.size = gfx::Size(34, 23); yPlane.format = 8; - yPlane.visibleSize = gfx::Size(623, 235); VideoLayerImpl::FramePlane uPlane; uPlane.resourceId = 532; uPlane.size = gfx::Size(134, 16); uPlane.format = 2; - uPlane.visibleSize = gfx::Size(126, 27); VideoLayerImpl::FramePlane vPlane; vPlane.resourceId = 4; vPlane.size = gfx::Size(456, 486); vPlane.format = 46; - vPlane.visibleSize = gfx::Size(19, 45); CREATE_SHARED_STATE(); - CREATE_QUAD_3(YUVVideoDrawQuad, yPlane, uPlane, vPlane); + CREATE_QUAD_4(YUVVideoDrawQuad, texScale, yPlane, uPlane, vPlane); + EXPECT_EQ(texScale, copyQuad->texScale()); EXPECT_EQ(yPlane.resourceId, copyQuad->yPlane().resourceId); EXPECT_EQ(yPlane.size, copyQuad->yPlane().size); EXPECT_EQ(yPlane.format, copyQuad->yPlane().format); - EXPECT_EQ(yPlane.visibleSize, copyQuad->yPlane().visibleSize); EXPECT_EQ(uPlane.resourceId, copyQuad->uPlane().resourceId); EXPECT_EQ(uPlane.size, copyQuad->uPlane().size); EXPECT_EQ(uPlane.format, copyQuad->uPlane().format); - EXPECT_EQ(uPlane.visibleSize, copyQuad->uPlane().visibleSize); EXPECT_EQ(vPlane.resourceId, copyQuad->vPlane().resourceId); EXPECT_EQ(vPlane.size, copyQuad->vPlane().size); EXPECT_EQ(vPlane.format, copyQuad->vPlane().format); - EXPECT_EQ(vPlane.visibleSize, copyQuad->vPlane().visibleSize); } } // anonymous namespace diff --git a/cc/gl_renderer.cc b/cc/gl_renderer.cc index e5e4347..55e2846 100644 --- a/cc/gl_renderer.cc +++ b/cc/gl_renderer.cc @@ -879,12 +879,7 @@ void GLRenderer::drawYUVVideoQuad(const DrawingFrame& frame, const YUVVideoDrawQ GLC(context(), context()->useProgram(program->program())); - float yWidthScaleFactor = static_cast<float>(yPlane.visibleSize.width()) / yPlane.size.width(); - // Arbitrarily take the u sizes because u and v dimensions are identical. - float uvWidthScaleFactor = static_cast<float>(uPlane.visibleSize.width()) / uPlane.size.width(); - GLC(context(), context()->uniform1f(program->vertexShader().yWidthScaleFactorLocation(), yWidthScaleFactor)); - GLC(context(), context()->uniform1f(program->vertexShader().uvWidthScaleFactorLocation(), uvWidthScaleFactor)); - + GLC(context(), context()->uniform2f(program->vertexShader().texScaleLocation(), quad->texScale().width(), quad->texScale().height())); GLC(context(), context()->uniform1i(program->fragmentShader().yTextureLocation(), 1)); GLC(context(), context()->uniform1i(program->fragmentShader().uTextureLocation(), 2)); GLC(context(), context()->uniform1i(program->fragmentShader().vTextureLocation(), 3)); diff --git a/cc/layer_tree_host_impl_unittest.cc b/cc/layer_tree_host_impl_unittest.cc index ed7ef13..723fcbdc 100644 --- a/cc/layer_tree_host_impl_unittest.cc +++ b/cc/layer_tree_host_impl_unittest.cc @@ -2565,6 +2565,8 @@ public: virtual const void* data(unsigned plane) const { NOTREACHED(); return NULL; } virtual unsigned textureId() const { NOTREACHED(); return 0; } virtual unsigned textureTarget() const { NOTREACHED(); return 0; } + virtual WebKit::WebRect visibleRect() const { NOTREACHED(); return WebKit::WebRect(0, 0, 0, 0); } + virtual WebKit::WebSize textureSize() const { NOTREACHED(); return WebKit::WebSize(4, 4); } static VideoFrame* toVideoFrame(WebVideoFrame* web_video_frame) { FakeVideoFrame* wrapped_frame = @@ -2735,6 +2737,15 @@ TEST_P(LayerTreeHostImplTest, dontUseOldResourcesAfterLostContext) videoLayer->setLayerTreeHostImpl(m_hostImpl.get()); rootLayer->addChild(videoLayer.PassAs<LayerImpl>()); + FakeVideoFrameProvider providerScaled; + scoped_ptr<VideoLayerImpl> videoLayerScaled = VideoLayerImpl::create(layerId++, &providerScaled, unwrapper); + videoLayerScaled->setBounds(gfx::Size(10, 10)); + videoLayerScaled->setAnchorPoint(gfx::PointF(0, 0)); + videoLayerScaled->setContentBounds(gfx::Size(10, 10)); + videoLayerScaled->setDrawsContent(true); + videoLayerScaled->setLayerTreeHostImpl(m_hostImpl.get()); + rootLayer->addChild(videoLayerScaled.PassAs<LayerImpl>()); + FakeVideoFrameProvider hwProvider; scoped_ptr<VideoLayerImpl> hwVideoLayer = VideoLayerImpl::create(layerId++, &hwProvider, unwrapper); hwVideoLayer->setBounds(gfx::Size(10, 10)); @@ -2787,10 +2798,18 @@ TEST_P(LayerTreeHostImplTest, dontUseOldResourcesAfterLostContext) VideoFrame::WrapNativeTexture( m_hostImpl->resourceProvider()->graphicsContext3D()->createTexture(), GL_TEXTURE_2D, - gfx::Size(4, 4), gfx::Size(4, 4), base::TimeDelta(), + gfx::Size(4, 4), gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta(), VideoFrame::ReadPixelsCB(), base::Closure())); hwProvider.setFrame(&hwVideoFrame); + FakeVideoFrame videoFrameScaled( + VideoFrame::WrapNativeTexture( + m_hostImpl->resourceProvider()->graphicsContext3D()->createTexture(), + GL_TEXTURE_2D, + gfx::Size(4, 4), gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), base::TimeDelta(), + VideoFrame::ReadPixelsCB(), base::Closure())); + providerScaled.setFrame(&videoFrameScaled); + m_hostImpl->setRootLayer(rootLayer.Pass()); LayerTreeHostImpl::FrameData frame; @@ -2813,6 +2832,7 @@ TEST_P(LayerTreeHostImplTest, dontUseOldResourcesAfterLostContext) // The WebVideoFrameProvider is expected to recreate its textures after a // lost context (or not serve a frame). hwProvider.setFrame(0); + providerScaled.setFrame(0); EXPECT_TRUE(m_hostImpl->prepareToDraw(frame)); m_hostImpl->drawLayers(frame); @@ -2823,7 +2843,7 @@ TEST_P(LayerTreeHostImplTest, dontUseOldResourcesAfterLostContext) VideoFrame::WrapNativeTexture( m_hostImpl->resourceProvider()->graphicsContext3D()->createTexture(), GL_TEXTURE_2D, - gfx::Size(4, 4), gfx::Size(4, 4), base::TimeDelta(), + gfx::Size(4, 4), gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta(), VideoFrame::ReadPixelsCB(), base::Closure())); hwProvider.setFrame(&hwVideoFrame2); diff --git a/cc/resource_provider.cc b/cc/resource_provider.cc index ec88bb7..3c134ef 100644 --- a/cc/resource_provider.cc +++ b/cc/resource_provider.cc @@ -283,6 +283,7 @@ void ResourceProvider::setPixels(ResourceId id, const uint8_t* image, const gfx: } if (resource->pixels) { + DCHECK(resource->format == GL_RGBA); SkBitmap srcFull; srcFull.setConfig(SkBitmap::kARGB_8888_Config, imageRect.width(), imageRect.height()); srcFull.setPixels(const_cast<uint8_t*>(image)); diff --git a/cc/shader.cc b/cc/shader.cc index 4bed89e..567d56c 100644 --- a/cc/shader.cc +++ b/cc/shader.cc @@ -69,8 +69,7 @@ std::string VertexShaderPosTex::getShaderString() const VertexShaderPosTexYUVStretch::VertexShaderPosTexYUVStretch() : m_matrixLocation(-1) - , m_yWidthScaleFactorLocation(-1) - , m_uvWidthScaleFactorLocation(-1) + , m_texScaleLocation(-1) { } @@ -78,17 +77,15 @@ void VertexShaderPosTexYUVStretch::init(WebGraphicsContext3D* context, unsigned { static const char* shaderUniforms[] = { "matrix", - "y_widthScaleFactor", - "uv_widthScaleFactor", + "texScale", }; - int locations[3]; + int locations[2]; getProgramUniformLocations(context, program, shaderUniforms, arraysize(shaderUniforms), arraysize(locations), locations, usingBindUniform, baseUniformIndex); m_matrixLocation = locations[0]; - m_yWidthScaleFactorLocation = locations[1]; - m_uvWidthScaleFactorLocation = locations[2]; - DCHECK(m_matrixLocation != -1 && m_yWidthScaleFactorLocation != -1 && m_uvWidthScaleFactorLocation != -1); + m_texScaleLocation = locations[1]; + DCHECK(m_matrixLocation != -1 && m_texScaleLocation != -1); } std::string VertexShaderPosTexYUVStretch::getShaderString() const @@ -98,15 +95,12 @@ std::string VertexShaderPosTexYUVStretch::getShaderString() const attribute vec4 a_position; attribute vec2 a_texCoord; uniform mat4 matrix; - varying vec2 y_texCoord; - varying vec2 uv_texCoord; - uniform float y_widthScaleFactor; - uniform float uv_widthScaleFactor; + varying vec2 v_texCoord; + uniform vec2 texScale; void main() { gl_Position = matrix * a_position; - y_texCoord = vec2(y_widthScaleFactor * a_texCoord.x, a_texCoord.y); - uv_texCoord = vec2(uv_widthScaleFactor * a_texCoord.x, a_texCoord.y); + v_texCoord = a_texCoord * texScale; } ); } @@ -782,8 +776,7 @@ std::string FragmentShaderYUVVideo::getShaderString() const return SHADER( precision mediump float; precision mediump int; - varying vec2 y_texCoord; - varying vec2 uv_texCoord; + varying vec2 v_texCoord; uniform sampler2D y_texture; uniform sampler2D u_texture; uniform sampler2D v_texture; @@ -792,9 +785,9 @@ std::string FragmentShaderYUVVideo::getShaderString() const uniform mat3 yuv_matrix; void main() { - float y_raw = texture2D(y_texture, y_texCoord).x; - float u_unsigned = texture2D(u_texture, uv_texCoord).x; - float v_unsigned = texture2D(v_texture, uv_texCoord).x; + float y_raw = texture2D(y_texture, v_texCoord).x; + float u_unsigned = texture2D(u_texture, v_texCoord).x; + float v_unsigned = texture2D(v_texture, v_texCoord).x; vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj; vec3 rgb = yuv_matrix * yuv; gl_FragColor = vec4(rgb, float(1)) * alpha; diff --git a/cc/shader.h b/cc/shader.h index a691712..67e93cb 100644 --- a/cc/shader.h +++ b/cc/shader.h @@ -35,13 +35,11 @@ public: std::string getShaderString() const; int matrixLocation() const { return m_matrixLocation; } - int yWidthScaleFactorLocation() const { return m_yWidthScaleFactorLocation; } - int uvWidthScaleFactorLocation() const { return m_uvWidthScaleFactorLocation; } + int texScaleLocation() const { return m_texScaleLocation; } private: int m_matrixLocation; - int m_yWidthScaleFactorLocation; - int m_uvWidthScaleFactorLocation; + int m_texScaleLocation; }; class VertexShaderPos { diff --git a/cc/video_layer_impl.cc b/cc/video_layer_impl.cc index c23225e..3b2e3a9 100644 --- a/cc/video_layer_impl.cc +++ b/cc/video_layer_impl.cc @@ -151,6 +151,12 @@ void VideoLayerImpl::willDrawInternal(ResourceProvider* resourceProvider) m_format = convertVFCFormatToGLenum(*m_frame); + // If these fail, we'll have to add draw logic that handles offset bitmap/ + // texture UVs. For now, just expect (0, 0) offset, since all our decoders + // so far don't offset. + DCHECK_EQ(m_frame->visible_rect().x(), 0); + DCHECK_EQ(m_frame->visible_rect().y(), 0); + if (m_format == GL_INVALID_VALUE) { m_provider->putCurrentFrame(m_webFrame); m_frame = 0; @@ -196,6 +202,14 @@ void VideoLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQuad // otherwise synchonize use of all textures in the quad. gfx::Rect quadRect(gfx::Point(), contentBounds()); + gfx::Rect visibleRect = m_frame->visible_rect(); + gfx::Size codedSize = m_frame->coded_size(); + + // pixels for macroblocked formats. + const float texWidthScale = + static_cast<float>(visibleRect.width()) / codedSize.width(); + const float texHeightScale = + static_cast<float>(visibleRect.height()) / codedSize.height(); switch (m_format) { case GL_LUMINANCE: { @@ -203,7 +217,9 @@ void VideoLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQuad const FramePlane& yPlane = m_framePlanes[media::VideoFrame::kYPlane]; const FramePlane& uPlane = m_framePlanes[media::VideoFrame::kUPlane]; const FramePlane& vPlane = m_framePlanes[media::VideoFrame::kVPlane]; - scoped_ptr<YUVVideoDrawQuad> yuvVideoQuad = YUVVideoDrawQuad::create(sharedQuadState, quadRect, yPlane, uPlane, vPlane); + gfx::SizeF texScale(texWidthScale, texHeightScale); + scoped_ptr<YUVVideoDrawQuad> yuvVideoQuad = YUVVideoDrawQuad::create( + sharedQuadState, quadRect, texScale, yPlane, uPlane, vPlane); quadSink.append(yuvVideoQuad.PassAs<DrawQuad>(), appendQuadsData); break; } @@ -211,8 +227,7 @@ void VideoLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQuad // RGBA software decoder. const FramePlane& plane = m_framePlanes[media::VideoFrame::kRGBPlane]; bool premultipliedAlpha = true; - float widthScaleFactor = static_cast<float>(plane.visibleSize.width()) / plane.size.width(); - gfx::RectF uvRect(widthScaleFactor, 1); + gfx::RectF uvRect(0, 0, texWidthScale, texHeightScale); bool flipped = false; scoped_ptr<TextureDrawQuad> textureQuad = TextureDrawQuad::create(sharedQuadState, quadRect, plane.resourceId, premultipliedAlpha, uvRect, flipped); quadSink.append(textureQuad.PassAs<DrawQuad>(), appendQuadsData); @@ -221,20 +236,26 @@ void VideoLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQuad case GL_TEXTURE_2D: { // NativeTexture hardware decoder. bool premultipliedAlpha = true; - gfx::RectF uvRect(1, 1); + gfx::RectF uvRect(0, 0, texWidthScale, texHeightScale); bool flipped = false; scoped_ptr<TextureDrawQuad> textureQuad = TextureDrawQuad::create(sharedQuadState, quadRect, m_externalTextureResource, premultipliedAlpha, uvRect, flipped); quadSink.append(textureQuad.PassAs<DrawQuad>(), appendQuadsData); break; } case GL_TEXTURE_RECTANGLE_ARB: { - scoped_ptr<IOSurfaceDrawQuad> ioSurfaceQuad = IOSurfaceDrawQuad::create(sharedQuadState, quadRect, m_frame->data_size(), m_frame->texture_id(), IOSurfaceDrawQuad::Unflipped); + gfx::Size visibleSize(visibleRect.width(), visibleRect.height()); + scoped_ptr<IOSurfaceDrawQuad> ioSurfaceQuad = IOSurfaceDrawQuad::create(sharedQuadState, quadRect, visibleSize, m_frame->texture_id(), IOSurfaceDrawQuad::Unflipped); quadSink.append(ioSurfaceQuad.PassAs<DrawQuad>(), appendQuadsData); break; } case GL_TEXTURE_EXTERNAL_OES: { // StreamTexture hardware decoder. - scoped_ptr<StreamVideoDrawQuad> streamVideoQuad = StreamVideoDrawQuad::create(sharedQuadState, quadRect, m_frame->texture_id(), m_streamTextureMatrix); + WebKit::WebTransformationMatrix transform(m_streamTextureMatrix); + transform.scaleNonUniform(texWidthScale, texHeightScale); + scoped_ptr<StreamVideoDrawQuad> streamVideoQuad = + StreamVideoDrawQuad::create(sharedQuadState, quadRect, + m_frame->texture_id(), + transform); quadSink.append(streamVideoQuad.PassAs<DrawQuad>(), appendQuadsData); break; } @@ -267,43 +288,28 @@ void VideoLayerImpl::didDraw(ResourceProvider* resourceProvider) m_providerLock.Release(); } -static int videoFrameDimension(int originalDimension, size_t plane, int format) -{ - if (format == media::VideoFrame::YV12 && plane != media::VideoFrame::kYPlane) - return originalDimension / 2; - return originalDimension; -} - -static bool hasPaddingBytes(const media::VideoFrame& frame, size_t plane) -{ - return frame.stride(plane) > videoFrameDimension(frame.data_size().width(), plane, frame.format()); -} - -gfx::Size computeVisibleSize(const media::VideoFrame& frame, size_t plane) -{ - int visibleWidth = videoFrameDimension(frame.data_size().width(), plane, frame.format()); - int originalWidth = visibleWidth; - int visibleHeight = videoFrameDimension(frame.data_size().height(), plane, frame.format()); - - // When there are dead pixels at the edge of the texture, decrease - // the frame width by 1 to prevent the rightmost pixels from - // interpolating with the dead pixels. - if (hasPaddingBytes(frame, plane)) - --visibleWidth; - - // In YV12, every 2x2 square of Y values corresponds to one U and - // one V value. If we decrease the width of the UV plane, we must decrease the - // width of the Y texture by 2 for proper alignment. This must happen - // always, even if Y's texture does not have padding bytes. - if (plane == media::VideoFrame::kYPlane && frame.format() == media::VideoFrame::YV12) { - if (hasPaddingBytes(frame, media::VideoFrame::kUPlane)) - visibleWidth = originalWidth - 2; +static gfx::Size videoFrameDimension(media::VideoFrame* frame, int plane) { + gfx::Size dimensions = frame->coded_size(); + switch (frame->format()) { + case media::VideoFrame::YV12: + if (plane != media::VideoFrame::kYPlane) { + dimensions.set_width(dimensions.width() / 2); + dimensions.set_height(dimensions.height() / 2); + } + break; + case media::VideoFrame::YV16: + if (plane != media::VideoFrame::kYPlane) { + dimensions.set_width(dimensions.width() / 2); + } + break; + default: + break; } - - return gfx::Size(visibleWidth, visibleHeight); + return dimensions; } -bool VideoLayerImpl::FramePlane::allocateData(ResourceProvider* resourceProvider) +bool VideoLayerImpl::FramePlane::allocateData( + ResourceProvider* resourceProvider) { if (resourceId) return true; @@ -325,12 +331,15 @@ bool VideoLayerImpl::allocatePlaneData(ResourceProvider* resourceProvider) { const int maxTextureSize = resourceProvider->maxTextureSize(); const size_t planeCount = numPlanes(); - for (size_t planeIndex = 0; planeIndex < planeCount; ++planeIndex) { - VideoLayerImpl::FramePlane& plane = m_framePlanes[planeIndex]; - - gfx::Size requiredTextureSize(m_frame->stride(planeIndex), videoFrameDimension(m_frame->data_size().height(), planeIndex, m_frame->format())); - // FIXME: Remove the test against maxTextureSize when tiled layers are implemented. - if (requiredTextureSize.IsEmpty() || requiredTextureSize.width() > maxTextureSize || requiredTextureSize.height() > maxTextureSize) + for (unsigned planeIdx = 0; planeIdx < planeCount; ++planeIdx) { + VideoLayerImpl::FramePlane& plane = m_framePlanes[planeIdx]; + + gfx::Size requiredTextureSize = videoFrameDimension(m_frame, planeIdx); + // FIXME: Remove the test against maxTextureSize when tiled layers are + // implemented. + if (requiredTextureSize.IsEmpty() || + requiredTextureSize.width() > maxTextureSize || + requiredTextureSize.height() > maxTextureSize) return false; if (plane.size != requiredTextureSize || plane.format != m_format) { @@ -339,11 +348,8 @@ bool VideoLayerImpl::allocatePlaneData(ResourceProvider* resourceProvider) plane.format = m_format; } - if (!plane.resourceId) { - if (!plane.allocateData(resourceProvider)) - return false; - plane.visibleSize = computeVisibleSize(*m_frame, planeIndex); - } + if (!plane.allocateData(resourceProvider)) + return false; } return true; } @@ -359,12 +365,14 @@ bool VideoLayerImpl::copyPlaneData(ResourceProvider* resourceProvider) m_videoRenderer.reset(new media::SkCanvasVideoRenderer); VideoLayerImpl::FramePlane& plane = m_framePlanes[media::VideoFrame::kRGBPlane]; ResourceProvider::ScopedWriteLockSoftware lock(resourceProvider, plane.resourceId); - m_videoRenderer->Paint(m_frame, lock.skCanvas(), gfx::Rect(plane.size), 0xFF); + m_videoRenderer->Paint(m_frame, lock.skCanvas(), m_frame->visible_rect(), 0xFF); return true; } for (size_t planeIndex = 0; planeIndex < planeCount; ++planeIndex) { VideoLayerImpl::FramePlane& plane = m_framePlanes[planeIndex]; + // Only non-FormatNativeTexture planes should need upload. + DCHECK_EQ(plane.format, GL_LUMINANCE); const uint8_t* softwarePlanePixels = m_frame->data(planeIndex); gfx::Rect planeRect(gfx::Point(), plane.size); resourceProvider->setPixels(plane.resourceId, softwarePlanePixels, planeRect, planeRect, gfx::Vector2d()); diff --git a/cc/video_layer_impl.h b/cc/video_layer_impl.h index 85e6f37..6291ae1 100644 --- a/cc/video_layer_impl.h +++ b/cc/video_layer_impl.h @@ -57,7 +57,6 @@ public: ResourceProvider::ResourceId resourceId; gfx::Size size; GLenum format; - gfx::Size visibleSize; FramePlane() : resourceId(0) { } diff --git a/cc/yuv_video_draw_quad.cc b/cc/yuv_video_draw_quad.cc index 38ba85f..ff60e1e 100644 --- a/cc/yuv_video_draw_quad.cc +++ b/cc/yuv_video_draw_quad.cc @@ -10,19 +10,38 @@ namespace cc { -scoped_ptr<YUVVideoDrawQuad> YUVVideoDrawQuad::create(const SharedQuadState* sharedQuadState, const gfx::Rect& quadRect, const VideoLayerImpl::FramePlane& yPlane, const VideoLayerImpl::FramePlane& uPlane, const VideoLayerImpl::FramePlane& vPlane) +scoped_ptr<YUVVideoDrawQuad> YUVVideoDrawQuad::create( + const SharedQuadState* sharedQuadState, + const gfx::Rect& quadRect, + const gfx::SizeF& texScale, + const VideoLayerImpl::FramePlane& yPlane, + const VideoLayerImpl::FramePlane& uPlane, + const VideoLayerImpl::FramePlane& vPlane) { - return make_scoped_ptr(new YUVVideoDrawQuad(sharedQuadState, quadRect, yPlane, uPlane, vPlane)); + return make_scoped_ptr(new YUVVideoDrawQuad(sharedQuadState, + quadRect, texScale, + yPlane, uPlane, vPlane)); } -YUVVideoDrawQuad::YUVVideoDrawQuad(const SharedQuadState* sharedQuadState, const gfx::Rect& quadRect, const VideoLayerImpl::FramePlane& yPlane, const VideoLayerImpl::FramePlane& uPlane, const VideoLayerImpl::FramePlane& vPlane) +YUVVideoDrawQuad::YUVVideoDrawQuad( + const SharedQuadState* sharedQuadState, + const gfx::Rect& quadRect, + const gfx::SizeF& texScale, + const VideoLayerImpl::FramePlane& yPlane, + const VideoLayerImpl::FramePlane& uPlane, + const VideoLayerImpl::FramePlane& vPlane) : DrawQuad(sharedQuadState, DrawQuad::YUVVideoContent, quadRect) + , m_texScale(texScale) , m_yPlane(yPlane) , m_uPlane(uPlane) , m_vPlane(vPlane) { } +YUVVideoDrawQuad::~YUVVideoDrawQuad() +{ +} + const YUVVideoDrawQuad* YUVVideoDrawQuad::materialCast(const DrawQuad* quad) { DCHECK(quad->material() == DrawQuad::YUVVideoContent); diff --git a/cc/yuv_video_draw_quad.h b/cc/yuv_video_draw_quad.h index 6894c95..8b1ac63 100644 --- a/cc/yuv_video_draw_quad.h +++ b/cc/yuv_video_draw_quad.h @@ -15,7 +15,17 @@ namespace cc { class CC_EXPORT YUVVideoDrawQuad : public DrawQuad { public: - static scoped_ptr<YUVVideoDrawQuad> create(const SharedQuadState*, const gfx::Rect&, const VideoLayerImpl::FramePlane& yPlane, const VideoLayerImpl::FramePlane& uPlane, const VideoLayerImpl::FramePlane& vPlane); + static scoped_ptr<YUVVideoDrawQuad> create( + const SharedQuadState* sharedQuadState, + const gfx::Rect& quadRect, + const gfx::SizeF& texScale, + const VideoLayerImpl::FramePlane& yPlane, + const VideoLayerImpl::FramePlane& uPlane, + const VideoLayerImpl::FramePlane& vPlane); + + ~YUVVideoDrawQuad(); + + const gfx::SizeF& texScale() const { return m_texScale; } const VideoLayerImpl::FramePlane& yPlane() const { return m_yPlane; } const VideoLayerImpl::FramePlane& uPlane() const { return m_uPlane; } @@ -23,8 +33,15 @@ public: static const YUVVideoDrawQuad* materialCast(const DrawQuad*); private: - YUVVideoDrawQuad(const SharedQuadState*, const gfx::Rect&, const VideoLayerImpl::FramePlane& yPlane, const VideoLayerImpl::FramePlane& uPlane, const VideoLayerImpl::FramePlane& vPlane); - + YUVVideoDrawQuad( + const SharedQuadState* sharedQuadState, + const gfx::Rect& quadRect, + const gfx::SizeF& texScale, + const VideoLayerImpl::FramePlane& yPlane, + const VideoLayerImpl::FramePlane& uPlane, + const VideoLayerImpl::FramePlane& vPlane); + + gfx::SizeF m_texScale; VideoLayerImpl::FramePlane m_yPlane; VideoLayerImpl::FramePlane m_uPlane; VideoLayerImpl::FramePlane m_vPlane; diff --git a/content/renderer/media/local_video_capture.cc b/content/renderer/media/local_video_capture.cc index b08f221..f4bc376 100644 --- a/content/renderer/media/local_video_capture.cc +++ b/content/renderer/media/local_video_capture.cc @@ -128,8 +128,8 @@ void LocalVideoCapture::OnBufferReady( gfx::Size natural_size(buf->width, buf->height); scoped_refptr<media::VideoFrame> current_frame = - media::VideoFrame::CreateFrame(media::VideoFrame::YV12, - natural_size, natural_size, + media::VideoFrame::CreateFrame(media::VideoFrame::YV12, natural_size, + gfx::Rect(natural_size), natural_size, buf->timestamp - base::Time()); uint8* buffer = buf->memory_pointer; diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc index 2ca2379..d795daf 100644 --- a/content/renderer/media/rtc_video_decoder.cc +++ b/content/renderer/media/rtc_video_decoder.cc @@ -147,6 +147,7 @@ void RTCVideoDecoder::RenderFrame(const cricket::VideoFrame* frame) { scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(media::VideoFrame::YV12, visible_size_, + gfx::Rect(visible_size_), visible_size_, timestamp - start_time_); last_frame_timestamp_ = timestamp; diff --git a/content/renderer/media/rtc_video_decoder_unittest.cc b/content/renderer/media/rtc_video_decoder_unittest.cc index c13b255..ab54037 100644 --- a/content/renderer/media/rtc_video_decoder_unittest.cc +++ b/content/renderer/media/rtc_video_decoder_unittest.cc @@ -251,12 +251,20 @@ const int RTCVideoDecoderTest::kHeight = 480; const PipelineStatistics RTCVideoDecoderTest::kStatistics; MATCHER_P2(HasSize, width, height, "") { - EXPECT_EQ(arg->data_size().width(), width); - EXPECT_EQ(arg->data_size().height(), height); + EXPECT_EQ(arg->coded_size().width(), width); + EXPECT_EQ(arg->coded_size().height(), height); + EXPECT_EQ(arg->visible_rect().x(), 0); + EXPECT_EQ(arg->visible_rect().y(), 0); + EXPECT_EQ(arg->visible_rect().width(), width); + EXPECT_EQ(arg->visible_rect().height(), height); EXPECT_EQ(arg->natural_size().width(), width); EXPECT_EQ(arg->natural_size().height(), height); - return (arg->data_size().width() == width) && - (arg->data_size().height() == height) && + return (arg->coded_size().width() == width) && + (arg->coded_size().height() == height) && + (arg->visible_rect().x() == 0) && + (arg->visible_rect().y() == 0) && + (arg->visible_rect().width() == width) && + (arg->visible_rect().height() == height) && (arg->natural_size().width() == width) && (arg->natural_size().height() == height); } diff --git a/content/renderer/media/rtc_video_renderer.cc b/content/renderer/media/rtc_video_renderer.cc index 14444fa..68d1c97 100644 --- a/content/renderer/media/rtc_video_renderer.cc +++ b/content/renderer/media/rtc_video_renderer.cc @@ -75,6 +75,7 @@ void RTCVideoRenderer::RenderFrame(const cricket::VideoFrame* frame) { scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size, + gfx::Rect(size), size, timestamp); diff --git a/media/base/video_decoder_config.cc b/media/base/video_decoder_config.cc index a42808fc..93f05b7 100644 --- a/media/base/video_decoder_config.cc +++ b/media/base/video_decoder_config.cc @@ -114,7 +114,8 @@ bool VideoDecoderConfig::IsValidConfig() const { return codec_ != kUnknownVideoCodec && natural_size_.width() > 0 && natural_size_.height() > 0 && - VideoFrame::IsValidConfig(format_, visible_rect().size(), natural_size_); + VideoFrame::IsValidConfig(format_, coded_size_, visible_rect_, + natural_size_); } bool VideoDecoderConfig::Matches(const VideoDecoderConfig& config) const { diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc index 6303f09b..3d76410 100644 --- a/media/base/video_frame.cc +++ b/media/base/video_frame.cc @@ -19,12 +19,13 @@ namespace media { // static scoped_refptr<VideoFrame> VideoFrame::CreateFrame( VideoFrame::Format format, - const gfx::Size& data_size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size, base::TimeDelta timestamp) { - DCHECK(IsValidConfig(format, data_size, natural_size)); + DCHECK(IsValidConfig(format, coded_size, visible_rect, natural_size)); scoped_refptr<VideoFrame> frame(new VideoFrame( - format, data_size, natural_size, timestamp)); + format, coded_size, visible_rect, natural_size, timestamp)); switch (format) { case VideoFrame::RGB32: frame->AllocateRGB(4u); @@ -41,30 +42,37 @@ scoped_refptr<VideoFrame> VideoFrame::CreateFrame( // static bool VideoFrame::IsValidConfig(VideoFrame::Format format, - const gfx::Size& data_size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size) { return (format != VideoFrame::INVALID && - data_size.width() > 0 && data_size.height() > 0 && - data_size.width() <= limits::kMaxDimension && - data_size.height() <= limits::kMaxDimension && - data_size.width() * data_size.height() <= limits::kMaxCanvas && - natural_size.width() > 0 && natural_size.height() > 0 && + !coded_size.IsEmpty() && + coded_size.GetArea() <= limits::kMaxCanvas && + coded_size.width() <= limits::kMaxDimension && + coded_size.height() <= limits::kMaxDimension && + !visible_rect.IsEmpty() && + visible_rect.x() >= 0 && visible_rect.y() >= 0 && + visible_rect.right() <= coded_size.width() && + visible_rect.bottom() <= coded_size.height() && + !natural_size.IsEmpty() && + natural_size.GetArea() <= limits::kMaxCanvas && natural_size.width() <= limits::kMaxDimension && - natural_size.height() <= limits::kMaxDimension && - natural_size.width() * natural_size.height() <= limits::kMaxCanvas); + natural_size.height() <= limits::kMaxDimension); } // static scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture( uint32 texture_id, uint32 texture_target, - const gfx::Size& data_size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size, base::TimeDelta timestamp, const ReadPixelsCB& read_pixels_cb, const base::Closure& no_longer_needed) { scoped_refptr<VideoFrame> frame( - new VideoFrame(NATIVE_TEXTURE, data_size, natural_size, timestamp)); + new VideoFrame(NATIVE_TEXTURE, coded_size, visible_rect, natural_size, + timestamp)); frame->texture_id_ = texture_id; frame->texture_target_ = texture_target; frame->read_pixels_cb_ = read_pixels_cb; @@ -81,7 +89,8 @@ void VideoFrame::ReadPixelsFromNativeTexture(void* pixels) { // static scoped_refptr<VideoFrame> VideoFrame::CreateEmptyFrame() { return new VideoFrame( - VideoFrame::EMPTY, gfx::Size(), gfx::Size(), base::TimeDelta()); + VideoFrame::EMPTY, gfx::Size(), gfx::Rect(), gfx::Size(), + base::TimeDelta()); } // static @@ -89,9 +98,9 @@ scoped_refptr<VideoFrame> VideoFrame::CreateColorFrame( const gfx::Size& size, uint8 y, uint8 u, uint8 v, base::TimeDelta timestamp) { - DCHECK(IsValidConfig(VideoFrame::YV12, size, size)); + DCHECK(IsValidConfig(VideoFrame::YV12, size, gfx::Rect(size), size)); scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame( - VideoFrame::YV12, size, size, timestamp); + VideoFrame::YV12, size, gfx::Rect(size), size, timestamp); FillYUV(frame, y, u, v); return frame; } @@ -117,9 +126,9 @@ static const int kFramePadBytes = 15; void VideoFrame::AllocateRGB(size_t bytes_per_pixel) { // Round up to align at least at a 16-byte boundary for each row. // This is sufficient for MMX and SSE2 reads (movq/movdqa). - size_t bytes_per_row = RoundUp(data_size_.width(), + size_t bytes_per_row = RoundUp(coded_size_.width(), kFrameSizeAlignment) * bytes_per_pixel; - size_t aligned_height = RoundUp(data_size_.height(), kFrameSizeAlignment); + size_t aligned_height = RoundUp(coded_size_.height(), kFrameSizeAlignment); strides_[VideoFrame::kRGBPlane] = bytes_per_row; #if !defined(OS_ANDROID) // TODO(dalecurtis): use DataAligned or so, so this #ifdef hackery @@ -151,7 +160,7 @@ void VideoFrame::AllocateYUV() { // The *2 here is because some formats (e.g. h264) allow interlaced coding, // and then the size needs to be a multiple of two macroblocks (vertically). // See libavcodec/utils.c:avcodec_align_dimensions2(). - size_t y_height = RoundUp(data_size_.height(), kFrameSizeAlignment * 2); + size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2); size_t uv_height = format_ == VideoFrame::YV12 ? y_height / 2 : y_height; size_t y_bytes = y_height * y_stride; size_t uv_bytes = uv_height * uv_stride; @@ -178,11 +187,13 @@ void VideoFrame::AllocateYUV() { } VideoFrame::VideoFrame(VideoFrame::Format format, - const gfx::Size& data_size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size, base::TimeDelta timestamp) : format_(format), - data_size_(data_size), + coded_size_(coded_size), + visible_rect_(visible_rect), natural_size_(natural_size), texture_id_(0), texture_target_(0), @@ -238,7 +249,7 @@ int VideoFrame::stride(size_t plane) const { int VideoFrame::row_bytes(size_t plane) const { DCHECK(IsValidPlane(plane)); - int width = data_size_.width(); + int width = coded_size_.width(); switch (format_) { // 32bpp. case RGB32: @@ -262,7 +273,7 @@ int VideoFrame::row_bytes(size_t plane) const { int VideoFrame::rows(size_t plane) const { DCHECK(IsValidPlane(plane)); - int height = data_size_.height(); + int height = coded_size_.height(); switch (format_) { case RGB32: case YV16: diff --git a/media/base/video_frame.h b/media/base/video_frame.h index 0840839..effdafd 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h @@ -8,6 +8,7 @@ #include "base/callback.h" #include "base/md5.h" #include "media/base/buffers.h" +#include "ui/gfx/rect.h" #include "ui/gfx/size.h" namespace media { @@ -40,19 +41,23 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // Creates a new frame in system memory with given parameters. Buffers for // the frame are allocated but not initialized. - // |data_size| is the width and height of the frame data in pixels. + // |coded_size| is the width and height of the frame data in pixels. + // |visible_rect| is the visible portion of |coded_size|, after cropping (if + // any) is applied. // |natural_size| is the width and height of the frame when the frame's aspect - // ratio is applied to |data_size|. + // ratio is applied to |visible_rect|. static scoped_refptr<VideoFrame> CreateFrame( Format format, - const gfx::Size& data_size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size, base::TimeDelta timestamp); // Call prior to CreateFrame to ensure validity of frame configuration. Called // automatically by VideoDecoderConfig::IsValidConfig(). // TODO(scherkus): VideoDecoderConfig shouldn't call this method - static bool IsValidConfig(Format format, const gfx::Size& data_size, + static bool IsValidConfig(Format format, const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size); // CB to write pixels from the texture backing this frame into the @@ -61,15 +66,18 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // Wraps a native texture of the given parameters with a VideoFrame. When the // frame is destroyed |no_longer_needed.Run()| will be called. - // |data_size| is the width and height of the frame data in pixels. + // |coded_size| is the width and height of the frame data in pixels. + // |visible_rect| is the visible portion of |coded_size|, after cropping (if + // any) is applied. // |natural_size| is the width and height of the frame when the frame's aspect - // ratio is applied to |size|. + // ratio is applied to |visible_rect|. // |read_pixels_cb| may be used to do (slow!) readbacks from the // texture to main memory. static scoped_refptr<VideoFrame> WrapNativeTexture( uint32 texture_id, uint32 texture_target, - const gfx::Size& data_size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size, base::TimeDelta timestamp, const ReadPixelsCB& read_pixels_cb, @@ -77,7 +85,7 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // Read pixels from the native texture backing |*this| and write // them to |*pixels| as BGRA. |pixels| must point to a buffer at - // least as large as 4*data_size().width()*data_size().height(). + // least as large as 4*visible_rect().width()*visible_rect().height(). void ReadPixelsFromNativeTexture(void* pixels); // Creates a frame with format equals to VideoFrame::EMPTY, width, height, @@ -86,7 +94,7 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // Allocates YV12 frame based on |size|, and sets its data to the YUV(y,u,v). static scoped_refptr<VideoFrame> CreateColorFrame( - const gfx::Size& data_size, + const gfx::Size& size, uint8 y, uint8 u, uint8 v, base::TimeDelta timestamp); @@ -96,7 +104,8 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { Format format() const { return format_; } - const gfx::Size& data_size() const { return data_size_; } + const gfx::Size& coded_size() const { return coded_size_; } + const gfx::Rect& visible_rect() const { return visible_rect_; } const gfx::Size& natural_size() const { return natural_size_; } int stride(size_t plane) const; @@ -104,7 +113,7 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // Returns the number of bytes per row and number of rows for a given plane. // // As opposed to stride(), row_bytes() refers to the bytes representing - // visible pixels. + // frame data scanlines (coded_size.width() pixels, without stride padding). int row_bytes(size_t plane) const; int rows(size_t plane) const; @@ -137,7 +146,8 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { friend class base::RefCountedThreadSafe<VideoFrame>; // Clients must use the static CreateFrame() method to create a new frame. VideoFrame(Format format, - const gfx::Size& size, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, const gfx::Size& natural_size, base::TimeDelta timestamp); virtual ~VideoFrame(); @@ -153,10 +163,13 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { Format format_; // Width and height of the video frame. - gfx::Size data_size_; + gfx::Size coded_size_; - // Width and height of the video frame with aspect ratio taken - // into account. + // Width, height, and offsets of the visible portion of the video frame. + gfx::Rect visible_rect_; + + // Width and height of the visible portion of the video frame with aspect + // ratio taken into account. gfx::Size natural_size_; // Array of strides for each plane, typically greater or equal to the width diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc index ebbf92b..18cc1d3 100644 --- a/media/base/video_frame_unittest.cc +++ b/media/base/video_frame_unittest.cc @@ -20,19 +20,19 @@ using base::MD5DigestToBase16; // frame will be black, if 1 then the entire frame will be white. void InitializeYV12Frame(VideoFrame* frame, double white_to_black) { EXPECT_EQ(VideoFrame::YV12, frame->format()); - int first_black_row = static_cast<int>(frame->data_size().height() * + int first_black_row = static_cast<int>(frame->coded_size().height() * white_to_black); uint8* y_plane = frame->data(VideoFrame::kYPlane); - for (int row = 0; row < frame->data_size().height(); ++row) { + for (int row = 0; row < frame->coded_size().height(); ++row) { int color = (row < first_black_row) ? 0xFF : 0x00; - memset(y_plane, color, frame->data_size().width()); + memset(y_plane, color, frame->stride(VideoFrame::kYPlane)); y_plane += frame->stride(VideoFrame::kYPlane); } uint8* u_plane = frame->data(VideoFrame::kUPlane); uint8* v_plane = frame->data(VideoFrame::kVPlane); - for (int row = 0; row < frame->data_size().height(); row += 2) { - memset(u_plane, 0x80, frame->data_size().width() / 2); - memset(v_plane, 0x80, frame->data_size().width() / 2); + for (int row = 0; row < frame->coded_size().height(); row += 2) { + memset(u_plane, 0x80, frame->stride(VideoFrame::kUPlane)); + memset(v_plane, 0x80, frame->stride(VideoFrame::kVPlane)); u_plane += frame->stride(VideoFrame::kUPlane); v_plane += frame->stride(VideoFrame::kVPlane); } @@ -47,29 +47,32 @@ void ExpectFrameColor(media::VideoFrame* yv12_frame, uint32 expect_rgb_color) { scoped_refptr<media::VideoFrame> rgb_frame; rgb_frame = media::VideoFrame::CreateFrame(VideoFrame::RGB32, - yv12_frame->data_size(), + yv12_frame->coded_size(), + yv12_frame->visible_rect(), yv12_frame->natural_size(), yv12_frame->GetTimestamp()); - ASSERT_EQ(yv12_frame->data_size().width(), rgb_frame->data_size().width()); - ASSERT_EQ(yv12_frame->data_size().height(), rgb_frame->data_size().height()); + ASSERT_EQ(yv12_frame->coded_size().width(), + rgb_frame->coded_size().width()); + ASSERT_EQ(yv12_frame->coded_size().height(), + rgb_frame->coded_size().height()); media::ConvertYUVToRGB32(yv12_frame->data(VideoFrame::kYPlane), yv12_frame->data(VideoFrame::kUPlane), yv12_frame->data(VideoFrame::kVPlane), rgb_frame->data(VideoFrame::kRGBPlane), - rgb_frame->data_size().width(), - rgb_frame->data_size().height(), + rgb_frame->coded_size().width(), + rgb_frame->coded_size().height(), yv12_frame->stride(VideoFrame::kYPlane), yv12_frame->stride(VideoFrame::kUPlane), rgb_frame->stride(VideoFrame::kRGBPlane), media::YV12); - for (int row = 0; row < rgb_frame->data_size().height(); ++row) { + for (int row = 0; row < rgb_frame->coded_size().height(); ++row) { uint32* rgb_row_data = reinterpret_cast<uint32*>( rgb_frame->data(VideoFrame::kRGBPlane) + (rgb_frame->stride(VideoFrame::kRGBPlane) * row)); - for (int col = 0; col < rgb_frame->data_size().width(); ++col) { + for (int col = 0; col < rgb_frame->coded_size().width(); ++col) { SCOPED_TRACE( base::StringPrintf("Checking (%d, %d)", row, col)); EXPECT_EQ(expect_rgb_color, rgb_row_data[col]); @@ -89,7 +92,7 @@ void ExpectFrameExtents(VideoFrame::Format format, int planes, gfx::Size size(kWidth, kHeight); scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame( - format, size, size, kTimestamp); + format, size, gfx::Rect(size), size, kTimestamp); ASSERT_TRUE(frame); for(int plane = 0; plane < planes; plane++) { @@ -124,7 +127,8 @@ TEST(VideoFrame, CreateFrame) { // Create a YV12 Video Frame. gfx::Size size(kWidth, kHeight); scoped_refptr<media::VideoFrame> frame = - VideoFrame::CreateFrame(media::VideoFrame::YV12, size, size, kTimestamp); + VideoFrame::CreateFrame(media::VideoFrame::YV12, size, gfx::Rect(size), + size, kTimestamp); ASSERT_TRUE(frame); // Test VideoFrame implementation. @@ -171,19 +175,19 @@ TEST(VideoFrame, CreateBlackFrame) { // Test |frame| properties. EXPECT_EQ(VideoFrame::YV12, frame->format()); - EXPECT_EQ(kWidth, frame->data_size().width()); - EXPECT_EQ(kHeight, frame->data_size().height()); + EXPECT_EQ(kWidth, frame->coded_size().width()); + EXPECT_EQ(kHeight, frame->coded_size().height()); // Test frames themselves. uint8* y_plane = frame->data(VideoFrame::kYPlane); - for (int y = 0; y < frame->data_size().height(); ++y) { + for (int y = 0; y < frame->coded_size().height(); ++y) { EXPECT_EQ(0, memcmp(kExpectedYRow, y_plane, arraysize(kExpectedYRow))); y_plane += frame->stride(VideoFrame::kYPlane); } uint8* u_plane = frame->data(VideoFrame::kUPlane); uint8* v_plane = frame->data(VideoFrame::kVPlane); - for (int y = 0; y < frame->data_size().height() / 2; ++y) { + for (int y = 0; y < frame->coded_size().height() / 2; ++y) { EXPECT_EQ(0, memcmp(kExpectedUVRow, u_plane, arraysize(kExpectedUVRow))); EXPECT_EQ(0, memcmp(kExpectedUVRow, v_plane, arraysize(kExpectedUVRow))); u_plane += frame->stride(VideoFrame::kUPlane); diff --git a/media/base/video_util_unittest.cc b/media/base/video_util_unittest.cc index 326907d..d4f2e29 100644 --- a/media/base/video_util_unittest.cc +++ b/media/base/video_util_unittest.cc @@ -39,7 +39,7 @@ class VideoUtilTest : public testing::Test { void CreateDestinationFrame(int width, int height) { gfx::Size size(width, height); destination_frame_ = - VideoFrame::CreateFrame(VideoFrame::YV12, size, size, + VideoFrame::CreateFrame(VideoFrame::YV12, size, gfx::Rect(size), size, base::TimeDelta()); } diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc index aaf7bd7..d75782f 100644 --- a/media/filters/ffmpeg_video_decoder.cc +++ b/media/filters/ffmpeg_video_decoder.cc @@ -91,11 +91,12 @@ int FFmpegVideoDecoder::GetVideoBuffer(AVCodecContext* codec_context, natural_size = demuxer_stream_->video_decoder_config().natural_size(); } - if (!VideoFrame::IsValidConfig(format, size, natural_size)) + if (!VideoFrame::IsValidConfig(format, size, gfx::Rect(size), natural_size)) return AVERROR(EINVAL); scoped_refptr<VideoFrame> video_frame = - VideoFrame::CreateFrame(format, size, natural_size, kNoTimestamp()); + VideoFrame::CreateFrame(format, size, gfx::Rect(size), natural_size, + kNoTimestamp()); for (int i = 0; i < 3; i++) { frame->base[i] = video_frame->data(i); diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc index 9d9c24d..52e02d2 100644 --- a/media/filters/ffmpeg_video_decoder_unittest.cc +++ b/media/filters/ffmpeg_video_decoder_unittest.cc @@ -218,10 +218,12 @@ class FFmpegVideoDecoderTest : public testing::Test { EXPECT_EQ(VideoDecoder::kOk, status_b); ASSERT_TRUE(video_frame_a); ASSERT_TRUE(video_frame_b); - EXPECT_EQ(original_size.width(), video_frame_a->data_size().width()); - EXPECT_EQ(original_size.height(), video_frame_a->data_size().height()); - EXPECT_EQ(expected_width, video_frame_b->data_size().width()); - EXPECT_EQ(expected_height, video_frame_b->data_size().height()); + EXPECT_EQ(original_size.width(), + video_frame_a->visible_rect().size().width()); + EXPECT_EQ(original_size.height(), + video_frame_a->visible_rect().size().height()); + EXPECT_EQ(expected_width, video_frame_b->visible_rect().size().width()); + EXPECT_EQ(expected_height, video_frame_b->visible_rect().size().height()); } void Read(VideoDecoder::Status* status, diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc index 092e127..d59364b 100644 --- a/media/filters/gpu_video_decoder.cc +++ b/media/filters/gpu_video_decoder.cc @@ -42,8 +42,9 @@ GpuVideoDecoder::BufferPair::BufferPair( GpuVideoDecoder::BufferPair::~BufferPair() {} GpuVideoDecoder::BufferData::BufferData( - int32 bbid, base::TimeDelta ts, const gfx::Size& ns) - : bitstream_buffer_id(bbid), timestamp(ts), natural_size(ns) { + int32 bbid, base::TimeDelta ts, const gfx::Rect& vr, const gfx::Size& ns) + : bitstream_buffer_id(bbid), timestamp(ts), visible_rect(vr), + natural_size(ns) { } GpuVideoDecoder::BufferData::~BufferData() {} @@ -325,6 +326,7 @@ void GpuVideoDecoder::RecordBufferData( const BitstreamBuffer& bitstream_buffer, const Buffer& buffer) { input_buffer_data_.push_front(BufferData( bitstream_buffer.id(), buffer.GetTimestamp(), + demuxer_stream_->video_decoder_config().visible_rect(), demuxer_stream_->video_decoder_config().natural_size())); // Why this value? Because why not. avformat.h:MAX_REORDER_DELAY is 16, but // that's too small for some pathological B-frame test videos. The cost of @@ -337,6 +339,7 @@ void GpuVideoDecoder::RecordBufferData( } void GpuVideoDecoder::GetBufferData(int32 id, base::TimeDelta* timestamp, + gfx::Rect* visible_rect, gfx::Size* natural_size) { for (std::list<BufferData>::const_iterator it = input_buffer_data_.begin(); it != input_buffer_data_.end(); @@ -344,6 +347,7 @@ void GpuVideoDecoder::GetBufferData(int32 id, base::TimeDelta* timestamp, if (it->bitstream_buffer_id != id) continue; *timestamp = it->timestamp; + *visible_rect = it->visible_rect; *natural_size = it->natural_size; return; } @@ -425,16 +429,19 @@ void GpuVideoDecoder::PictureReady(const media::Picture& picture) { // Update frame's timestamp. base::TimeDelta timestamp; + gfx::Rect visible_rect; gfx::Size natural_size; - GetBufferData(picture.bitstream_buffer_id(), ×tamp, &natural_size); + GetBufferData(picture.bitstream_buffer_id(), ×tamp, &visible_rect, + &natural_size); DCHECK(decoder_texture_target_); - scoped_refptr<VideoFrame> frame(VideoFrame::WrapNativeTexture( - pb.texture_id(), decoder_texture_target_, pb.size(), natural_size, - timestamp, - base::Bind(&Factories::ReadPixels, factories_, pb.texture_id(), - decoder_texture_target_, pb.size()), - base::Bind(&GpuVideoDecoder::ReusePictureBuffer, this, - picture.picture_buffer_id()))); + scoped_refptr<VideoFrame> frame( + VideoFrame::WrapNativeTexture( + pb.texture_id(), decoder_texture_target_, pb.size(), visible_rect, + natural_size, timestamp, + base::Bind(&Factories::ReadPixels, factories_, pb.texture_id(), + decoder_texture_target_, pb.size()), + base::Bind(&GpuVideoDecoder::ReusePictureBuffer, this, + picture.picture_buffer_id()))); EnqueueFrameAndTriggerFrameDelivery(frame); } diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h index 745505f..da3248c 100644 --- a/media/filters/gpu_video_decoder.h +++ b/media/filters/gpu_video_decoder.h @@ -127,7 +127,7 @@ class MEDIA_EXPORT GpuVideoDecoder void RecordBufferData( const BitstreamBuffer& bitstream_buffer, const Buffer& buffer); void GetBufferData(int32 id, base::TimeDelta* timetamp, - gfx::Size* natural_size); + gfx::Rect* visible_rect, gfx::Size* natural_size); // Set |vda_| and |weak_vda_| on the VDA thread (in practice the render // thread). @@ -208,11 +208,12 @@ class MEDIA_EXPORT GpuVideoDecoder uint32 decoder_texture_target_; struct BufferData { - BufferData(int32 bbid, base::TimeDelta ts, + BufferData(int32 bbid, base::TimeDelta ts, const gfx::Rect& visible_rect, const gfx::Size& natural_size); ~BufferData(); int32 bitstream_buffer_id; base::TimeDelta timestamp; + gfx::Rect visible_rect; gfx::Size natural_size; }; std::list<BufferData> input_buffer_data_; diff --git a/media/filters/skcanvas_video_renderer.cc b/media/filters/skcanvas_video_renderer.cc index bef015e..53b5b2d 100644 --- a/media/filters/skcanvas_video_renderer.cc +++ b/media/filters/skcanvas_video_renderer.cc @@ -68,9 +68,12 @@ static void FastPaint( video_frame->stride(media::VideoFrame::kVPlane)); const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true); - media::YUVType yuv_type = (video_frame->format() == media::VideoFrame::YV12) ? - media::YV12 : media::YV16; - int y_shift = yuv_type; // 1 for YV12, 0 for YV16. + media::YUVType yuv_type = media::YV16; + int y_shift = 0; + if (video_frame->format() == media::VideoFrame::YV12) { + yuv_type = media::YV12; + y_shift = 1; + } // Transform the destination rectangle to local coordinates. const SkMatrix& local_matrix = canvas->getTotalMatrix(); @@ -109,27 +112,29 @@ static void FastPaint( DCHECK_NE(0, dest_rect.width()); DCHECK_NE(0, dest_rect.height()); size_t frame_clip_width = local_dest_irect.width() * - video_frame->data_size().width() / local_dest_irect_saved.width(); + video_frame->visible_rect().width() / local_dest_irect_saved.width(); size_t frame_clip_height = local_dest_irect.height() * - video_frame->data_size().height() / local_dest_irect_saved.height(); + video_frame->visible_rect().height() / local_dest_irect_saved.height(); // Project the "left" and "top" of the final destination rect to local // coordinates of the video frame, use these values to find the offsets // in the video frame to start reading. size_t frame_clip_left = + video_frame->visible_rect().x() + (local_dest_irect.fLeft - local_dest_irect_saved.fLeft) * - video_frame->data_size().width() / local_dest_irect_saved.width(); + video_frame->visible_rect().width() / local_dest_irect_saved.width(); size_t frame_clip_top = + video_frame->visible_rect().y() + (local_dest_irect.fTop - local_dest_irect_saved.fTop) * - video_frame->data_size().height() / local_dest_irect_saved.height(); + video_frame->visible_rect().height() / local_dest_irect_saved.height(); // Use the "left" and "top" of the destination rect to locate the offset // in Y, U and V planes. - size_t y_offset = video_frame->stride(media::VideoFrame::kYPlane) * - frame_clip_top + frame_clip_left; + size_t y_offset = (video_frame->stride(media::VideoFrame::kYPlane) * + frame_clip_top) + frame_clip_left; // For format YV12, there is one U, V value per 2x2 block. - // For format YV16, there is one u, V value per 2x1 block. + // For format YV16, there is one U, V value per 2x1 block. size_t uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * (frame_clip_top >> y_shift)) + (frame_clip_left >> 1); uint8* frame_clip_y = @@ -174,26 +179,48 @@ static void ConvertVideoFrameToBitmap( // Check if |bitmap| needs to be (re)allocated. if (bitmap->isNull() || - bitmap->width() != video_frame->data_size().width() || - bitmap->height() != video_frame->data_size().height()) { + bitmap->width() != video_frame->visible_rect().width() || + bitmap->height() != video_frame->visible_rect().height()) { bitmap->setConfig(SkBitmap::kARGB_8888_Config, - video_frame->data_size().width(), - video_frame->data_size().height()); + video_frame->visible_rect().width(), + video_frame->visible_rect().height()); bitmap->allocPixels(); bitmap->setIsVolatile(true); } bitmap->lockPixels(); if (IsEitherYV12OrYV16(video_frame->format())) { - media::YUVType yuv_type = - (video_frame->format() == media::VideoFrame::YV12) ? - media::YV12 : media::YV16; - media::ConvertYUVToRGB32(video_frame->data(media::VideoFrame::kYPlane), - video_frame->data(media::VideoFrame::kUPlane), - video_frame->data(media::VideoFrame::kVPlane), + media::YUVType yuv_type = media::YV16; + int y_shift = 0; + if (video_frame->format() == media::VideoFrame::YV12) { + yuv_type = media::YV12; + y_shift = 1; + } + + // Use the "left" and "top" of the destination rect to locate the offset + // in Y, U and V planes. + size_t y_offset = (video_frame->stride(media::VideoFrame::kYPlane) * + video_frame->visible_rect().y()) + + video_frame->visible_rect().x(); + + // For format YV12, there is one U, V value per 2x2 block. + // For format YV16, there is one U, V value per 2x1 block. + size_t uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * + (video_frame->visible_rect().y() >> y_shift)) + + (video_frame->visible_rect().x() >> 1); + uint8* frame_clip_y = + video_frame->data(media::VideoFrame::kYPlane) + y_offset; + uint8* frame_clip_u = + video_frame->data(media::VideoFrame::kUPlane) + uv_offset; + uint8* frame_clip_v = + video_frame->data(media::VideoFrame::kVPlane) + uv_offset; + + media::ConvertYUVToRGB32(frame_clip_y, + frame_clip_u, + frame_clip_v, static_cast<uint8*>(bitmap->getPixels()), - video_frame->data_size().width(), - video_frame->data_size().height(), + video_frame->visible_rect().width(), + video_frame->visible_rect().height(), video_frame->stride(media::VideoFrame::kYPlane), video_frame->stride(media::VideoFrame::kUPlane), bitmap->rowBytes(), diff --git a/media/filters/skcanvas_video_renderer_unittest.cc b/media/filters/skcanvas_video_renderer_unittest.cc index a7ac30c..a50f266 100644 --- a/media/filters/skcanvas_video_renderer_unittest.cc +++ b/media/filters/skcanvas_video_renderer_unittest.cc @@ -26,18 +26,24 @@ void FillCanvas(SkCanvas* canvas, SkColor color) { } // Helper for returning the color of a solid |canvas|. -SkColor GetColor(SkCanvas* canvas) { +SkColor GetColorAt(SkCanvas* canvas, int x, int y) { const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); bitmap.lockPixels(); - SkColor c = bitmap.getColor(0, 0); + SkColor c = bitmap.getColor(x, y); bitmap.unlockPixels(); return c; } +SkColor GetColor(SkCanvas* canvas) { + return GetColorAt(canvas, 0, 0); +} + class SkCanvasVideoRendererTest : public testing::Test { public: enum Color { + kNone, kRed, + kGreen, kBlue, }; @@ -55,6 +61,7 @@ class SkCanvasVideoRendererTest : public testing::Test { VideoFrame* natural_frame() { return natural_frame_; } VideoFrame* larger_frame() { return larger_frame_; } VideoFrame* smaller_frame() { return smaller_frame_; } + VideoFrame* cropped_frame() { return cropped_frame_; } // Getters for canvases that trigger the various painting paths. SkCanvas* fast_path_canvas() { return &fast_path_canvas_; } @@ -66,6 +73,7 @@ class SkCanvasVideoRendererTest : public testing::Test { scoped_refptr<VideoFrame> natural_frame_; scoped_refptr<VideoFrame> larger_frame_; scoped_refptr<VideoFrame> smaller_frame_; + scoped_refptr<VideoFrame> cropped_frame_; SkDevice fast_path_device_; SkCanvas fast_path_canvas_; @@ -81,6 +89,12 @@ SkCanvasVideoRendererTest::SkCanvasVideoRendererTest() gfx::Size(kWidth * 2, kHeight * 2))), smaller_frame_(VideoFrame::CreateBlackFrame( gfx::Size(kWidth / 2, kHeight / 2))), + cropped_frame_(VideoFrame::CreateFrame( + VideoFrame::YV12, + gfx::Size(16, 16), + gfx::Rect(6, 6, 8, 6), + gfx::Size(8, 6), + base::TimeDelta::FromMilliseconds(4))), fast_path_device_(SkBitmap::kARGB_8888_Config, kWidth, kHeight, true), fast_path_canvas_(&fast_path_device_), slow_path_device_(SkBitmap::kARGB_8888_Config, kWidth, kHeight, false), @@ -89,6 +103,86 @@ SkCanvasVideoRendererTest::SkCanvasVideoRendererTest() natural_frame_->SetTimestamp(base::TimeDelta::FromMilliseconds(1)); larger_frame_->SetTimestamp(base::TimeDelta::FromMilliseconds(2)); smaller_frame_->SetTimestamp(base::TimeDelta::FromMilliseconds(3)); + + // Make sure the cropped video frame's aspect ratio matches the output device. + // Update cropped_frame_'s crop dimensions if this is not the case. + EXPECT_EQ(cropped_frame()->natural_size().width() * kHeight, + cropped_frame()->natural_size().height() * kWidth); + + // Fill in the cropped frame's entire data with colors: + // + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // Bl Bl Bl Bl Bl Bl Bl Bl R R R R R R R R + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // G G G G G G G G B B B B B B B B + // + // The visible crop of the frame (as set by its visible_rect_) has contents: + // + // Bl Bl R R R R R R + // Bl Bl R R R R R R + // G G B B B B B B + // G G B B B B B B + // G G B B B B B B + // G G B B B B B B + // + // Each color region in the cropped frame is on a 2x2 block granularity, to + // avoid sharing UV samples between regions. + + static const uint8 cropped_y_plane[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 76, 76, 76, 76, 76, 76, 76, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + 149, 149, 149, 149, 149, 149, 149, 149, 29, 29, 29, 29, 29, 29, 29, 29, + }; + + static const uint8 cropped_u_plane[] = { + 128, 128, 128, 128, 84, 84, 84, 84, + 128, 128, 128, 128, 84, 84, 84, 84, + 128, 128, 128, 128, 84, 84, 84, 84, + 128, 128, 128, 128, 84, 84, 84, 84, + 43, 43, 43, 43, 255, 255, 255, 255, + 43, 43, 43, 43, 255, 255, 255, 255, + 43, 43, 43, 43, 255, 255, 255, 255, + 43, 43, 43, 43, 255, 255, 255, 255, + }; + static const uint8 cropped_v_plane[] = { + 128, 128, 128, 128, 255, 255, 255, 255, + 128, 128, 128, 128, 255, 255, 255, 255, + 128, 128, 128, 128, 255, 255, 255, 255, + 128, 128, 128, 128, 255, 255, 255, 255, + 21, 21, 21, 21, 107, 107, 107, 107, + 21, 21, 21, 21, 107, 107, 107, 107, + 21, 21, 21, 21, 107, 107, 107, 107, + 21, 21, 21, 21, 107, 107, 107, 107, + }; + + media::CopyYPlane(cropped_y_plane, 16, 16, cropped_frame()); + media::CopyUPlane(cropped_u_plane, 8, 8, cropped_frame()); + media::CopyVPlane(cropped_v_plane, 8, 8, cropped_frame()); } SkCanvasVideoRendererTest::~SkCanvasVideoRendererTest() {} @@ -101,9 +195,14 @@ void SkCanvasVideoRendererTest::Paint(VideoFrame* video_frame, SkCanvas* canvas, Color color) { switch (color) { + case kNone: + break; case kRed: media::FillYUV(video_frame, 76, 84, 255); break; + case kGreen: + media::FillYUV(video_frame, 149, 43, 21); + break; case kBlue: media::FillYUV(video_frame, 29, 255, 107); break; @@ -199,4 +298,51 @@ TEST_F(SkCanvasVideoRendererTest, SlowPaint_SameVideoFrame) { EXPECT_EQ(SK_ColorRED, GetColor(slow_path_canvas())); } +TEST_F(SkCanvasVideoRendererTest, FastPaint_CroppedFrame) { + Paint(cropped_frame(), fast_path_canvas(), kNone); + // Check the corners. + EXPECT_EQ(SK_ColorBLACK, GetColorAt(fast_path_canvas(), 0, 0)); + EXPECT_EQ(SK_ColorRED, GetColorAt(fast_path_canvas(), kWidth - 1, 0)); + EXPECT_EQ(SK_ColorGREEN, GetColorAt(fast_path_canvas(), 0, kHeight - 1)); + EXPECT_EQ(SK_ColorBLUE, GetColorAt(fast_path_canvas(), kWidth - 1, + kHeight - 1)); + // Check the interior along the border between color regions. Note that we're + // bilinearly upscaling, so we'll need to take care to pick sample points that + // are just outside the "zone of resampling". + // TODO(sheu): commenting out two checks due to http://crbug.com/158462. +#if 0 + EXPECT_EQ(SK_ColorBLACK, GetColorAt(fast_path_canvas(), kWidth * 1 / 8 - 1, + kHeight * 1 / 6 - 1)); +#endif + EXPECT_EQ(SK_ColorRED, GetColorAt(fast_path_canvas(), kWidth * 3 / 8, + kHeight * 1 / 6 - 1)); +#if 0 + EXPECT_EQ(SK_ColorGREEN, GetColorAt(fast_path_canvas(), kWidth * 1 / 8 - 1, + kHeight * 3 / 6)); +#endif + EXPECT_EQ(SK_ColorBLUE, GetColorAt(fast_path_canvas(), kWidth * 3 / 8, + kHeight * 3 / 6)); +} + +TEST_F(SkCanvasVideoRendererTest, SlowPaint_CroppedFrame) { + Paint(cropped_frame(), slow_path_canvas(), kNone); + // Check the corners. + EXPECT_EQ(SK_ColorBLACK, GetColorAt(slow_path_canvas(), 0, 0)); + EXPECT_EQ(SK_ColorRED, GetColorAt(slow_path_canvas(), kWidth - 1, 0)); + EXPECT_EQ(SK_ColorGREEN, GetColorAt(slow_path_canvas(), 0, kHeight - 1)); + EXPECT_EQ(SK_ColorBLUE, GetColorAt(slow_path_canvas(), kWidth - 1, + kHeight - 1)); + // Check the interior along the border between color regions. Note that we're + // bilinearly upscaling, so we'll need to take care to pick sample points that + // are just outside the "zone of resampling". + EXPECT_EQ(SK_ColorBLACK, GetColorAt(slow_path_canvas(), kWidth * 1 / 8 - 1, + kHeight * 1 / 6 - 1)); + EXPECT_EQ(SK_ColorRED, GetColorAt(slow_path_canvas(), kWidth * 3 / 8, + kHeight * 1 / 6 - 1)); + EXPECT_EQ(SK_ColorGREEN, GetColorAt(slow_path_canvas(), kWidth * 1 / 8 - 1, + kHeight * 3 / 6)); + EXPECT_EQ(SK_ColorBLUE, GetColorAt(slow_path_canvas(), kWidth * 3 / 8, + kHeight * 3 / 6)); +} + } // namespace media diff --git a/media/filters/video_frame_generator.cc b/media/filters/video_frame_generator.cc index 4429c19..c72fe13 100644 --- a/media/filters/video_frame_generator.cc +++ b/media/filters/video_frame_generator.cc @@ -72,7 +72,8 @@ void VideoFrameGenerator::ReadOnDecoderThread(const ReadCB& read_cb) { // // TODO(scherkus): migrate this to proper buffer recycling. scoped_refptr<VideoFrame> video_frame = - VideoFrame::CreateFrame(VideoFrame::YV12, size_, size_, current_time_); + VideoFrame::CreateFrame(VideoFrame::YV12, size_, gfx::Rect(size_), size_, + current_time_); current_time_ += frame_duration_; // TODO(wjia): set pixel data to pre-defined patterns if it's desired to diff --git a/media/filters/video_renderer_base_unittest.cc b/media/filters/video_renderer_base_unittest.cc index b81c40d..9ce8a9c 100644 --- a/media/filters/video_renderer_base_unittest.cc +++ b/media/filters/video_renderer_base_unittest.cc @@ -287,7 +287,8 @@ class VideoRendererBaseTest : public ::testing::Test { // Creates a frame with given timestamp. scoped_refptr<VideoFrame> CreateFrame(int timestamp) { scoped_refptr<VideoFrame> frame = - VideoFrame::CreateFrame(VideoFrame::RGB32, kNaturalSize, kNaturalSize, + VideoFrame::CreateFrame(VideoFrame::RGB32, kNaturalSize, + gfx::Rect(kNaturalSize), kNaturalSize, base::TimeDelta::FromMilliseconds(timestamp)); return frame; } diff --git a/media/tools/player_wtl/view.h b/media/tools/player_wtl/view.h index b0e4737..cc34aa8 100644 --- a/media/tools/player_wtl/view.h +++ b/media/tools/player_wtl/view.h @@ -144,11 +144,12 @@ class WtlVideoWindow : public CScrollWindowImpl<WtlVideoWindow> { uint8 *movie_dib_bits = reinterpret_cast<uint8 *>(bm.bmBits) + bm.bmWidthBytes * (bm.bmHeight - 1); int dibrowbytes = -bm.bmWidthBytes; - int clipped_width = video_frame->data_size().width(); + // Not accounting for cropping presently. + int clipped_width = video_frame->coded_size().width(); if (dibwidth < clipped_width) { clipped_width = dibwidth; } - int clipped_height = video_frame->data_size().height(); + int clipped_height = video_frame->coded_size().height(); if (dibheight < clipped_height) { clipped_height = dibheight; } @@ -243,7 +244,7 @@ class WtlVideoWindow : public CScrollWindowImpl<WtlVideoWindow> { if (frame) { // Size the window the first time we get a frame. if (!last_frame_) - SetSize(frame->data_size().width(), frame->data_size().height()); + SetSize(frame->coded_size().width(), frame->coded_size().height()); base::TimeDelta frame_timestamp = frame->GetTimestamp(); if (frame != last_frame_ || frame_timestamp != last_timestamp_) { @@ -436,24 +437,24 @@ class WtlVideoWindow : public CScrollWindowImpl<WtlVideoWindow> { if (file_yuv != NULL) { fseek(file_yuv, 0, SEEK_END); const int frame_size = - video_frame->data_size().width() * video_frame->data_size().height(); - for (int y = 0; y < video_frame->data_size().height(); ++y) + video_frame->coded_size().width() * video_frame->coded_size().height(); + for (int y = 0; y < video_frame->coded_size().height(); ++y) fwrite(video_frame->data(0) + video_frame->stride(0)*y, - video_frame->data_size().width(), sizeof(uint8), file_yuv); - for (int y = 0; y < video_frame->data_size().height()/2; ++y) + video_frame->coded_size().width(), sizeof(uint8), file_yuv); + for (int y = 0; y < video_frame->coded_size().height()/2; ++y) fwrite(video_frame->data(1) + video_frame->stride(1)*y, - video_frame->data_size().width() / 2, sizeof(uint8), file_yuv); - for (int y = 0; y < video_frame->data_size().height()/2; ++y) + video_frame->coded_size().width() / 2, sizeof(uint8), file_yuv); + for (int y = 0; y < video_frame->coded_size().height()/2; ++y) fwrite(video_frame->data(2) + video_frame->stride(2)*y, - video_frame->data_size().width() / 2, sizeof(uint8), file_yuv); + video_frame->coded_size().width() / 2, sizeof(uint8), file_yuv); fclose(file_yuv); #if TESTING static int frame_dump_count = 0; char outputbuf[512]; _snprintf_s(outputbuf, sizeof(outputbuf), "yuvdump %4d %dx%d stride %d\n", - frame_dump_count, video_frame->data_size().width(), - video_frame->data_size().height(), + frame_dump_count, video_frame->coded_size().width(), + video_frame->coded_size().height(), video_frame->stride(0)); OutputDebugStringA(outputbuf); ++frame_dump_count; diff --git a/media/tools/player_x11/gl_video_renderer.cc b/media/tools/player_x11/gl_video_renderer.cc index 50abdd9..334dfad 100644 --- a/media/tools/player_x11/gl_video_renderer.cc +++ b/media/tools/player_x11/gl_video_renderer.cc @@ -121,8 +121,7 @@ GlVideoRenderer::~GlVideoRenderer() { void GlVideoRenderer::Paint(media::VideoFrame* video_frame) { if (!gl_context_) - Initialize(video_frame->data_size().width(), - video_frame->data_size().height()); + Initialize(video_frame->coded_size(), video_frame->visible_rect()); // Convert YUV frame to RGB. DCHECK(video_frame->format() == media::VideoFrame::YV12 || @@ -147,12 +146,12 @@ void GlVideoRenderer::Paint(media::VideoFrame* video_frame) { glXSwapBuffers(display_, window_); } -void GlVideoRenderer::Initialize(int width, int height) { +void GlVideoRenderer::Initialize(gfx::Size coded_size, gfx::Rect visible_rect) { CHECK(!gl_context_); LOG(INFO) << "Initializing GL Renderer..."; // Resize the window to fit that of the video. - XResizeWindow(display_, window_, width, height); + XResizeWindow(display_, window_, visible_rect.width(), visible_rect.height()); gl_context_ = InitGLContext(display_, window_); CHECK(gl_context_) << "Failed to initialize GL context"; @@ -241,8 +240,16 @@ void GlVideoRenderer::Initialize(int width, int height) { int tc_location = glGetAttribLocation(program, "in_tc"); glEnableVertexAttribArray(tc_location); - glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, - kTextureCoords); + float verts[8]; + float x0 = static_cast<float>(visible_rect.x()) / coded_size.width(); + float y0 = static_cast<float>(visible_rect.y()) / coded_size.height(); + float x1 = static_cast<float>(visible_rect.right()) / coded_size.width(); + float y1 = static_cast<float>(visible_rect.bottom()) / coded_size.height(); + verts[0] = x0; verts[1] = y0; + verts[2] = x0; verts[3] = y1; + verts[4] = x1; verts[5] = y0; + verts[6] = x1; verts[7] = y1; + glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, verts); // We are getting called on a thread. Release the context so that it can be // made current on the main thread. diff --git a/media/tools/player_x11/gl_video_renderer.h b/media/tools/player_x11/gl_video_renderer.h index 28d3ffb..b8818a1 100644 --- a/media/tools/player_x11/gl_video_renderer.h +++ b/media/tools/player_x11/gl_video_renderer.h @@ -7,6 +7,8 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size.h" #include "ui/gl/gl_bindings.h" class MessageLoop; @@ -27,7 +29,7 @@ class GlVideoRenderer : public base::RefCountedThreadSafe<GlVideoRenderer> { private: // Initializes GL rendering for the given dimensions. - void Initialize(int width, int height); + void Initialize(gfx::Size coded_size, gfx::Rect visible_rect); Display* display_; Window window_; diff --git a/media/tools/player_x11/x11_video_renderer.cc b/media/tools/player_x11/x11_video_renderer.cc index d259d6b..43a18cd 100644 --- a/media/tools/player_x11/x11_video_renderer.cc +++ b/media/tools/player_x11/x11_video_renderer.cc @@ -84,16 +84,18 @@ X11VideoRenderer::~X11VideoRenderer() { } void X11VideoRenderer::Paint(media::VideoFrame* video_frame) { - int width = video_frame->data_size().width(); - int height = video_frame->data_size().height(); - if (!image_) - Initialize(width, height); + Initialize(video_frame->coded_size(), video_frame->visible_rect()); + + const int coded_width = video_frame->coded_size().width(); + const int coded_height = video_frame->coded_size().height(); + const int visible_width = video_frame->visible_rect().width(); + const int visible_height = video_frame->visible_rect().height(); // Check if we need to reallocate our XImage. - if (image_->width != width || image_->height != height) { + if (image_->width != coded_width || image_->height != coded_height) { XDestroyImage(image_); - image_ = CreateImage(display_, width, height); + image_ = CreateImage(display_, coded_width, coded_height); } // Convert YUV frame to RGB. @@ -109,9 +111,7 @@ void X11VideoRenderer::Paint(media::VideoFrame* video_frame) { media::ConvertYUVToRGB32(video_frame->data(media::VideoFrame::kYPlane), video_frame->data(media::VideoFrame::kUPlane), video_frame->data(media::VideoFrame::kVPlane), - (uint8*)image_->data, - video_frame->data_size().width(), - video_frame->data_size().height(), + (uint8*)image_->data, coded_width, coded_height, video_frame->stride(media::VideoFrame::kYPlane), video_frame->stride(media::VideoFrame::kUPlane), image_->bytes_per_line, @@ -125,8 +125,8 @@ void X11VideoRenderer::Paint(media::VideoFrame* video_frame) { // Creates a XImage. XImage image; memset(&image, 0, sizeof(image)); - image.width = width; - image.height = height; + image.width = coded_width; + image.height = coded_height; image.depth = 32; image.bits_per_pixel = 32; image.format = ZPixmap; @@ -140,15 +140,15 @@ void X11VideoRenderer::Paint(media::VideoFrame* video_frame) { image.data = image_->data; // Creates a pixmap and uploads from the XImage. - unsigned long pixmap = XCreatePixmap(display_, - window_, - width, - height, + unsigned long pixmap = XCreatePixmap(display_, window_, + visible_width, visible_height, 32); GC gc = XCreateGC(display_, pixmap, 0, NULL); XPutImage(display_, pixmap, gc, &image, - 0, 0, 0, 0, - width, height); + video_frame->visible_rect().x(), + video_frame->visible_rect().y(), + 0, 0, + visible_width, visible_height); XFreeGC(display_, gc); // Creates the picture representing the pixmap. @@ -158,7 +158,7 @@ void X11VideoRenderer::Paint(media::VideoFrame* video_frame) { // Composite the picture over the picture representing the window. XRenderComposite(display_, PictOpSrc, picture, 0, picture_, 0, 0, 0, 0, 0, 0, - width, height); + visible_width, visible_height); XRenderFreePicture(display_, picture); XFreePixmap(display_, pixmap); @@ -171,18 +171,21 @@ void X11VideoRenderer::Paint(media::VideoFrame* video_frame) { // to the window. GC gc = XCreateGC(display_, window_, 0, NULL); XPutImage(display_, window_, gc, image_, - 0, 0, 0, 0, width, height); + video_frame->visible_rect().x(), + video_frame->visible_rect().y(), + 0, 0, visible_width, visible_height); XFlush(display_); XFreeGC(display_, gc); } -void X11VideoRenderer::Initialize(int width, int height) { +void X11VideoRenderer::Initialize(gfx::Size coded_size, + gfx::Rect visible_rect) { CHECK(!image_); LOG(INFO) << "Initializing X11 Renderer..."; // Resize the window to fit that of the video. - XResizeWindow(display_, window_, width, height); - image_ = CreateImage(display_, width, height); + XResizeWindow(display_, window_, visible_rect.width(), visible_rect.height()); + image_ = CreateImage(display_, coded_size.width(), coded_size.height()); // Testing XRender support. We'll use the very basic of XRender // so if it presents it is already good enough. We don't need diff --git a/media/tools/player_x11/x11_video_renderer.h b/media/tools/player_x11/x11_video_renderer.h index b91c565..05c624c 100644 --- a/media/tools/player_x11/x11_video_renderer.h +++ b/media/tools/player_x11/x11_video_renderer.h @@ -9,6 +9,8 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size.h" class MessageLoop; @@ -28,7 +30,7 @@ class X11VideoRenderer : public base::RefCountedThreadSafe<X11VideoRenderer> { private: // Initializes X11 rendering for the given dimensions. - void Initialize(int width, int height); + void Initialize(gfx::Size coded_size, gfx::Rect visible_rect); Display* display_; Window window_; diff --git a/media/tools/scaler_bench/scaler_bench.cc b/media/tools/scaler_bench/scaler_bench.cc index d8525d1..18c4ca1 100644 --- a/media/tools/scaler_bench/scaler_bench.cc +++ b/media/tools/scaler_bench/scaler_bench.cc @@ -122,7 +122,8 @@ static double BenchmarkFilter(media::ScaleFilter filter) { gfx::Size dest_size(dest_width, dest_height); dest_frames.push_back( - VideoFrame::CreateFrame(VideoFrame::RGB32, dest_size, dest_size, + VideoFrame::CreateFrame(VideoFrame::RGB32, dest_size, + gfx::Rect(dest_size), dest_size, TimeDelta::FromSeconds(0))); } @@ -160,7 +161,8 @@ static double BenchmarkScaleWithRect() { gfx::Size dest_size(dest_width, dest_height); dest_frames.push_back( - VideoFrame::CreateFrame(VideoFrame::RGB32, dest_size, dest_size, + VideoFrame::CreateFrame(VideoFrame::RGB32, dest_size, + gfx::Rect(dest_size), dest_size, TimeDelta::FromSeconds(0))); } diff --git a/media/tools/shader_bench/cpu_color_painter.cc b/media/tools/shader_bench/cpu_color_painter.cc index b99b803..a7cb570 100644 --- a/media/tools/shader_bench/cpu_color_painter.cc +++ b/media/tools/shader_bench/cpu_color_painter.cc @@ -67,7 +67,8 @@ void CPUColorPainter::Paint(scoped_refptr<media::VideoFrame> video_frame) { // Convert to RGB32 frame. scoped_refptr<media::VideoFrame> rgba_frame = media::VideoFrame::CreateFrame(media::VideoFrame::RGB32, - video_frame->data_size(), + video_frame->coded_size(), + video_frame->visible_rect(), video_frame->natural_size(), base::TimeDelta()); @@ -75,16 +76,19 @@ void CPUColorPainter::Paint(scoped_refptr<media::VideoFrame> video_frame) { video_frame->data(media::VideoFrame::kUPlane), video_frame->data(media::VideoFrame::kVPlane), rgba_frame->data(0), - video_frame->data_size().width(), - video_frame->data_size().height(), + video_frame->coded_size().width(), + video_frame->coded_size().height(), video_frame->stride(media::VideoFrame::kYPlane), video_frame->stride(media::VideoFrame::kUPlane), rgba_frame->stride(0), media::YV12); glBindTexture(GL_TEXTURE_2D, textures_[0]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rgba_frame->data_size().width(), - rgba_frame->data_size().height(), GL_RGBA, GL_UNSIGNED_BYTE, + // Not accounting for x/y offset presently. + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, + rgba_frame->visible_rect().width(), + rgba_frame->visible_rect().height(), + GL_RGBA, GL_UNSIGNED_BYTE, rgba_frame->data(0)); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); diff --git a/media/tools/shader_bench/gpu_color_painter.cc b/media/tools/shader_bench/gpu_color_painter.cc index a408de2..17155ee 100644 --- a/media/tools/shader_bench/gpu_color_painter.cc +++ b/media/tools/shader_bench/gpu_color_painter.cc @@ -104,8 +104,9 @@ void GPUColorWithLuminancePainter::Initialize(int width, int height) { void GPUColorWithLuminancePainter::Paint( scoped_refptr<media::VideoFrame> video_frame) { - int width = video_frame->data_size().width(); - int height = video_frame->data_size().height(); + // Not accounting for x/y offset presently. + int width = video_frame->visible_rect().width(); + int height = video_frame->visible_rect().height(); for (unsigned int i = 0; i < kNumYUVPlanes; ++i) { unsigned int plane_width = (i == media::VideoFrame::kYPlane) ? width : width / 2; diff --git a/media/tools/shader_bench/shader_bench.cc b/media/tools/shader_bench/shader_bench.cc index 17a45a4..897e588 100644 --- a/media/tools/shader_bench/shader_bench.cc +++ b/media/tools/shader_bench/shader_bench.cc @@ -53,7 +53,8 @@ void GetFrames(std::string file_name, gfx::Size size(width, height); for (int i = 0; i < num_frames; i++) { scoped_refptr<media::VideoFrame> video_frame = - media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size, size, + media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size, + gfx::Rect(size), size, base::TimeDelta()); long bytes_read = fread(video_frame->data(0), 1, frame_size, file_handle); diff --git a/webkit/media/android/webmediaplayer_android.cc b/webkit/media/android/webmediaplayer_android.cc index 468e180..6c0722c 100644 --- a/webkit/media/android/webmediaplayer_android.cc +++ b/webkit/media/android/webmediaplayer_android.cc @@ -376,8 +376,8 @@ void WebMediaPlayerAndroid::WillDestroyCurrentMessageLoop() { void WebMediaPlayerAndroid::ReallocateVideoFrame() { if (texture_id_) { video_frame_.reset(new WebVideoFrameImpl(VideoFrame::WrapNativeTexture( - texture_id_, kGLTextureExternalOES, natural_size_, natural_size_, - base::TimeDelta(), + texture_id_, kGLTextureExternalOES, natural_size_, + gfx::Rect(natural_size_), natural_size_, base::TimeDelta(), VideoFrame::ReadPixelsCB(), base::Closure()))); } diff --git a/webkit/media/simple_video_frame_provider.cc b/webkit/media/simple_video_frame_provider.cc index afdf3f8..8cffc03 100644 --- a/webkit/media/simple_video_frame_provider.cc +++ b/webkit/media/simple_video_frame_provider.cc @@ -66,6 +66,7 @@ void SimpleVideoFrameProvider::GenerateFrame() { scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size_, + gfx::Rect(size_), size_, current_time_); diff --git a/webkit/media/webvideoframe_impl.cc b/webkit/media/webvideoframe_impl.cc index 6d26ac6..16e04fa 100644 --- a/webkit/media/webvideoframe_impl.cc +++ b/webkit/media/webvideoframe_impl.cc @@ -37,18 +37,6 @@ WebVideoFrame::Format WebVideoFrameImpl::format() const { return WebVideoFrame::FormatInvalid; } -unsigned WebVideoFrameImpl::width() const { - if (video_frame_.get()) - return video_frame_->data_size().width(); - return 0; -} - -unsigned WebVideoFrameImpl::height() const { - if (video_frame_.get()) - return video_frame_->data_size().height(); - return 0; -} - unsigned WebVideoFrameImpl::planes() const { if (!video_frame_.get()) return 0; @@ -69,12 +57,6 @@ unsigned WebVideoFrameImpl::planes() const { return 0; } -int WebVideoFrameImpl::stride(unsigned plane) const { - if (video_frame_.get()) - return static_cast<int>(video_frame_->stride(plane)); - return 0; -} - const void* WebVideoFrameImpl::data(unsigned plane) const { if (!video_frame_.get() || format() == FormatNativeTexture) return NULL; @@ -93,4 +75,16 @@ unsigned WebVideoFrameImpl::textureTarget() const { return video_frame_->texture_target(); } +WebKit::WebRect WebVideoFrameImpl::visibleRect() const { + if (!video_frame_.get()) + return WebKit::WebRect(0, 0, 0, 0); + return WebKit::WebRect(video_frame_->visible_rect()); +} + +WebKit::WebSize WebVideoFrameImpl::textureSize() const { + if (!video_frame_.get() || format() != FormatNativeTexture) + return WebKit::WebSize(0, 0); + return WebKit::WebSize(video_frame_->coded_size()); +} + } // namespace webkit_media diff --git a/webkit/media/webvideoframe_impl.h b/webkit/media/webvideoframe_impl.h index 5125112..b2eed0c 100644 --- a/webkit/media/webvideoframe_impl.h +++ b/webkit/media/webvideoframe_impl.h @@ -7,6 +7,8 @@ #include "base/compiler_specific.h" #include "media/base/video_frame.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebVideoFrame.h" namespace webkit_media { @@ -20,13 +22,12 @@ class WebVideoFrameImpl : public WebKit::WebVideoFrame { WebVideoFrameImpl(scoped_refptr<media::VideoFrame> video_frame); virtual ~WebVideoFrameImpl(); virtual WebVideoFrame::Format format() const; - virtual unsigned width() const; - virtual unsigned height() const; virtual unsigned planes() const; - virtual int stride(unsigned plane) const; virtual const void* data(unsigned plane) const; virtual unsigned textureId() const; virtual unsigned textureTarget() const; + virtual WebKit::WebRect visibleRect() const; + virtual WebKit::WebSize textureSize() const; private: scoped_refptr<media::VideoFrame> video_frame_; diff --git a/webkit/plugins/ppapi/content_decryptor_delegate.cc b/webkit/plugins/ppapi/content_decryptor_delegate.cc index 3c55b6c..9b350ab 100644 --- a/webkit/plugins/ppapi/content_decryptor_delegate.cc +++ b/webkit/plugins/ppapi/content_decryptor_delegate.cc @@ -785,7 +785,7 @@ void ContentDecryptorDelegate::DeliverFrame( // managed by the PPB_Buffer_Dev, and avoid the extra copy. scoped_refptr<media::VideoFrame> decoded_frame( media::VideoFrame::CreateFrame( - format, frame_size, frame_size, + format, frame_size, gfx::Rect(frame_size), frame_size, base::TimeDelta::FromMicroseconds( frame_info->tracking_info.timestamp))); |