Index: cc/video_layer_impl.cc |
diff --git a/cc/video_layer_impl.cc b/cc/video_layer_impl.cc |
index 86cf037eb8baa87676451710629a73fdde0bc619..43e88646bd223d296eb23b8eaa249ff3b27af31f 100644 |
--- a/cc/video_layer_impl.cc |
+++ b/cc/video_layer_impl.cc |
@@ -6,7 +6,7 @@ |
#include "cc/video_layer_impl.h" |
-#include "NotImplemented.h" |
+#include "base/logging.h" |
#include "cc/io_surface_draw_quad.h" |
#include "cc/layer_tree_host_impl.h" |
#include "cc/proxy.h" |
@@ -15,16 +15,21 @@ |
#include "cc/stream_video_draw_quad.h" |
#include "cc/texture_draw_quad.h" |
#include "cc/yuv_video_draw_quad.h" |
+#include "media/filters/skcanvas_video_renderer.h" |
#include "third_party/khronos/GLES2/gl2.h" |
#include "third_party/khronos/GLES2/gl2ext.h" |
-#include <public/WebVideoFrame.h> |
namespace cc { |
-VideoLayerImpl::VideoLayerImpl(int id, WebKit::WebVideoFrameProvider* provider) |
+VideoLayerImpl::VideoLayerImpl(int id, WebKit::WebVideoFrameProvider* provider, |
+ const FrameUnwrapper& unwrapper) |
: LayerImpl(id) |
, m_provider(provider) |
+ , m_unwrapper(unwrapper) |
+ , m_webFrame(0) |
, m_frame(0) |
+ , m_format(GL_INVALID_VALUE) |
+ , m_convertYUV(false) |
, m_externalTextureResource(0) |
{ |
// This matrix is the default transformation for stream textures, and flips on the Y axis. |
@@ -53,8 +58,8 @@ VideoLayerImpl::~VideoLayerImpl() |
freePlaneData(layerTreeHostImpl()->resourceProvider()); |
#ifndef NDEBUG |
- for (unsigned i = 0; i < WebKit::WebVideoFrame::maxPlanes; ++i) |
- DCHECK(!m_framePlanes[i].resourceId); |
+ for (size_t i = 0; i < media::VideoFrame::kMaxPlanes; ++i) |
+ DCHECK(!m_framePlanes[i].resourceId); |
DCHECK(!m_externalTextureResource); |
#endif |
} |
@@ -68,24 +73,50 @@ void VideoLayerImpl::stopUsingProvider() |
m_provider = 0; |
} |
-// Convert WebKit::WebVideoFrame::Format to GraphicsContext3D's format enum values. |
-static GLenum convertVFCFormatToGC3DFormat(const WebKit::WebVideoFrame& frame) |
+// Convert media::VideoFrame::Format to OpenGL enum values. |
+static GLenum convertVFCFormatToGLenum(const media::VideoFrame& frame) |
{ |
switch (frame.format()) { |
- case WebKit::WebVideoFrame::FormatYV12: |
- case WebKit::WebVideoFrame::FormatYV16: |
+ case media::VideoFrame::YV12: |
+ case media::VideoFrame::YV16: |
return GL_LUMINANCE; |
- case WebKit::WebVideoFrame::FormatNativeTexture: |
- return frame.textureTarget(); |
- case WebKit::WebVideoFrame::FormatInvalid: |
- case WebKit::WebVideoFrame::FormatRGB32: |
- case WebKit::WebVideoFrame::FormatEmpty: |
- case WebKit::WebVideoFrame::FormatI420: |
- notImplemented(); |
+ case media::VideoFrame::NATIVE_TEXTURE: |
+ return frame.texture_target(); |
+ case media::VideoFrame::INVALID: |
+ case media::VideoFrame::RGB32: |
+ case media::VideoFrame::EMPTY: |
+ case media::VideoFrame::I420: |
+ NOTREACHED(); |
+ break; |
} |
return GL_INVALID_VALUE; |
} |
+size_t VideoLayerImpl::numPlanes() const |
+{ |
+ if (!m_frame) |
+ return 0; |
+ |
+ if (m_convertYUV) |
+ return 1; |
+ |
+ switch (m_frame->format()) { |
+ case media::VideoFrame::RGB32: |
+ return 1; |
+ case media::VideoFrame::YV12: |
+ case media::VideoFrame::YV16: |
+ return 3; |
+ case media::VideoFrame::INVALID: |
+ case media::VideoFrame::EMPTY: |
+ case media::VideoFrame::I420: |
+ break; |
+ case media::VideoFrame::NATIVE_TEXTURE: |
+ return 0; |
+ } |
+ NOTREACHED(); |
+ return 0; |
+} |
+ |
void VideoLayerImpl::willDraw(ResourceProvider* resourceProvider) |
{ |
DCHECK(Proxy::isImplThread()); |
@@ -117,39 +148,45 @@ void VideoLayerImpl::willDrawInternal(ResourceProvider* resourceProvider) |
return; |
} |
- m_frame = m_provider->getCurrentFrame(); |
+ m_webFrame = m_provider->getCurrentFrame(); |
+ m_frame = m_unwrapper.Run(m_webFrame); |
if (!m_frame) |
return; |
- m_format = convertVFCFormatToGC3DFormat(*m_frame); |
+ m_format = convertVFCFormatToGLenum(*m_frame); |
if (m_format == GL_INVALID_VALUE) { |
- m_provider->putCurrentFrame(m_frame); |
+ m_provider->putCurrentFrame(m_webFrame); |
m_frame = 0; |
return; |
} |
- if (m_frame->planes() > WebKit::WebVideoFrame::maxPlanes) { |
- m_provider->putCurrentFrame(m_frame); |
- m_frame = 0; |
- return; |
- } |
+ // FIXME: If we're in software compositing mode, we do the YUV -> RGB |
+ // conversion here. That involves an extra copy of each frame to a bitmap. |
+ // Obviously, this is suboptimal and should be addressed once ubercompositor |
+ // starts shaping up. |
+ m_convertYUV = resourceProvider->defaultResourceType() == ResourceProvider::Bitmap && |
+ (m_frame->format() == media::VideoFrame::YV12 || |
+ m_frame->format() == media::VideoFrame::YV16); |
+ |
+ if (m_convertYUV) |
+ m_format = GL_RGBA; |
if (!allocatePlaneData(resourceProvider)) { |
- m_provider->putCurrentFrame(m_frame); |
+ m_provider->putCurrentFrame(m_webFrame); |
m_frame = 0; |
return; |
} |
if (!copyPlaneData(resourceProvider)) { |
- m_provider->putCurrentFrame(m_frame); |
+ m_provider->putCurrentFrame(m_webFrame); |
m_frame = 0; |
return; |
} |
if (m_format == GL_TEXTURE_2D) |
- m_externalTextureResource = resourceProvider->createResourceFromExternalTexture(m_frame->textureId()); |
+ m_externalTextureResource = resourceProvider->createResourceFromExternalTexture(m_frame->texture_id()); |
} |
void VideoLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQuadsData) |
@@ -165,25 +202,24 @@ void VideoLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQuad |
// FIXME: When we pass quads out of process, we need to double-buffer, or |
// otherwise synchonize use of all textures in the quad. |
- IntRect quadRect(IntPoint(), contentBounds()); |
+ gfx::Rect quadRect(contentBounds()); |
switch (m_format) { |
case GL_LUMINANCE: { |
// YUV software decoder. |
- const FramePlane& yPlane = m_framePlanes[WebKit::WebVideoFrame::yPlane]; |
- const FramePlane& uPlane = m_framePlanes[WebKit::WebVideoFrame::uPlane]; |
- const FramePlane& vPlane = m_framePlanes[WebKit::WebVideoFrame::vPlane]; |
+ 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); |
quadSink.append(yuvVideoQuad.PassAs<DrawQuad>(), appendQuadsData); |
break; |
} |
case GL_RGBA: { |
// RGBA software decoder. |
- const FramePlane& plane = m_framePlanes[WebKit::WebVideoFrame::rgbPlane]; |
- float widthScaleFactor = static_cast<float>(plane.visibleSize.width()) / plane.size.width(); |
- |
+ const FramePlane& plane = m_framePlanes[media::VideoFrame::kRGBPlane]; |
bool premultipliedAlpha = true; |
- FloatRect uvRect(0, 0, widthScaleFactor, 1); |
+ float widthScaleFactor = static_cast<float>(plane.visibleSize.width()) / plane.size.width(); |
+ gfx::RectF uvRect(widthScaleFactor, 1); |
bool flipped = false; |
scoped_ptr<TextureDrawQuad> textureQuad = TextureDrawQuad::create(sharedQuadState, quadRect, plane.resourceId, premultipliedAlpha, uvRect, flipped); |
quadSink.append(textureQuad.PassAs<DrawQuad>(), appendQuadsData); |
@@ -192,26 +228,26 @@ void VideoLayerImpl::appendQuads(QuadSink& quadSink, AppendQuadsData& appendQuad |
case GL_TEXTURE_2D: { |
// NativeTexture hardware decoder. |
bool premultipliedAlpha = true; |
- FloatRect uvRect(0, 0, 1, 1); |
+ gfx::RectF uvRect(1, 1); |
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: { |
- IntSize textureSize(m_frame->width(), m_frame->height()); |
- scoped_ptr<IOSurfaceDrawQuad> ioSurfaceQuad = IOSurfaceDrawQuad::create(sharedQuadState, quadRect, textureSize, m_frame->textureId(), IOSurfaceDrawQuad::Unflipped); |
+ scoped_ptr<IOSurfaceDrawQuad> ioSurfaceQuad = IOSurfaceDrawQuad::create(sharedQuadState, quadRect, m_frame->data_size(), 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->textureId(), m_streamTextureMatrix); |
+ scoped_ptr<StreamVideoDrawQuad> streamVideoQuad = StreamVideoDrawQuad::create(sharedQuadState, quadRect, m_frame->texture_id(), m_streamTextureMatrix); |
quadSink.append(streamVideoQuad.PassAs<DrawQuad>(), appendQuadsData); |
break; |
} |
default: |
- CRASH(); // Someone updated convertVFCFormatToGC3DFormat above but update this! |
+ NOTREACHED(); // Someone updated convertVFCFormatToGLenum above but update this! |
+ break; |
} |
} |
@@ -233,29 +269,29 @@ void VideoLayerImpl::didDraw(ResourceProvider* resourceProvider) |
m_externalTextureResource = 0; |
} |
- m_provider->putCurrentFrame(m_frame); |
+ m_provider->putCurrentFrame(m_webFrame); |
m_frame = 0; |
m_providerLock.Release(); |
} |
-static int videoFrameDimension(int originalDimension, unsigned plane, int format) |
+static int videoFrameDimension(int originalDimension, size_t plane, int format) |
{ |
- if (format == WebKit::WebVideoFrame::FormatYV12 && plane != WebKit::WebVideoFrame::yPlane) |
+ if (format == media::VideoFrame::YV12 && plane != media::VideoFrame::kYPlane) |
return originalDimension / 2; |
return originalDimension; |
} |
-static bool hasPaddingBytes(const WebKit::WebVideoFrame& frame, unsigned plane) |
+static bool hasPaddingBytes(const media::VideoFrame& frame, size_t plane) |
{ |
- return frame.stride(plane) > videoFrameDimension(frame.width(), plane, frame.format()); |
+ return frame.stride(plane) > videoFrameDimension(frame.data_size().width(), plane, frame.format()); |
} |
-IntSize VideoLayerImpl::computeVisibleSize(const WebKit::WebVideoFrame& frame, unsigned plane) |
+IntSize computeVisibleSize(const media::VideoFrame& frame, size_t plane) |
{ |
- int visibleWidth = videoFrameDimension(frame.width(), plane, frame.format()); |
+ int visibleWidth = videoFrameDimension(frame.data_size().width(), plane, frame.format()); |
int originalWidth = visibleWidth; |
- int visibleHeight = videoFrameDimension(frame.height(), plane, frame.format()); |
+ 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 |
@@ -267,8 +303,8 @@ IntSize VideoLayerImpl::computeVisibleSize(const WebKit::WebVideoFrame& frame, u |
// 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 == WebKit::WebVideoFrame::yPlane && frame.format() == WebKit::WebVideoFrame::FormatYV12) { |
- if (hasPaddingBytes(frame, WebKit::WebVideoFrame::uPlane)) |
+ if (plane == media::VideoFrame::kYPlane && frame.format() == media::VideoFrame::YV12) { |
+ if (hasPaddingBytes(frame, media::VideoFrame::kUPlane)) |
visibleWidth = originalWidth - 2; |
} |
@@ -295,11 +331,12 @@ void VideoLayerImpl::FramePlane::freeData(ResourceProvider* resourceProvider) |
bool VideoLayerImpl::allocatePlaneData(ResourceProvider* resourceProvider) |
{ |
- int maxTextureSize = resourceProvider->maxTextureSize(); |
- for (unsigned planeIndex = 0; planeIndex < m_frame->planes(); ++planeIndex) { |
+ const int maxTextureSize = resourceProvider->maxTextureSize(); |
+ const size_t planeCount = numPlanes(); |
+ for (size_t planeIndex = 0; planeIndex < planeCount; ++planeIndex) { |
VideoLayerImpl::FramePlane& plane = m_framePlanes[planeIndex]; |
- IntSize requiredTextureSize(m_frame->stride(planeIndex), videoFrameDimension(m_frame->height(), planeIndex, m_frame->format())); |
+ IntSize 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.isZero() || requiredTextureSize.width() > maxTextureSize || requiredTextureSize.height() > maxTextureSize) |
return false; |
@@ -321,13 +358,22 @@ bool VideoLayerImpl::allocatePlaneData(ResourceProvider* resourceProvider) |
bool VideoLayerImpl::copyPlaneData(ResourceProvider* resourceProvider) |
{ |
- size_t softwarePlaneCount = m_frame->planes(); |
- if (!softwarePlaneCount) |
+ const size_t planeCount = numPlanes(); |
+ if (!planeCount) |
return true; |
- for (size_t softwarePlaneIndex = 0; softwarePlaneIndex < softwarePlaneCount; ++softwarePlaneIndex) { |
- VideoLayerImpl::FramePlane& plane = m_framePlanes[softwarePlaneIndex]; |
- const uint8_t* softwarePlanePixels = static_cast<const uint8_t*>(m_frame->data(softwarePlaneIndex)); |
+ if (m_convertYUV) { |
+ if (!m_videoRenderer) |
+ 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); |
+ return true; |
+ } |
+ |
+ for (size_t planeIndex = 0; planeIndex < planeCount; ++planeIndex) { |
+ VideoLayerImpl::FramePlane& plane = m_framePlanes[planeIndex]; |
+ const uint8_t* softwarePlanePixels = m_frame->data(planeIndex); |
IntRect planeRect(IntPoint(), plane.size); |
resourceProvider->upload(plane.resourceId, softwarePlanePixels, planeRect, planeRect, IntSize()); |
} |
@@ -336,14 +382,14 @@ bool VideoLayerImpl::copyPlaneData(ResourceProvider* resourceProvider) |
void VideoLayerImpl::freePlaneData(ResourceProvider* resourceProvider) |
{ |
- for (unsigned i = 0; i < WebKit::WebVideoFrame::maxPlanes; ++i) |
+ for (size_t i = 0; i < media::VideoFrame::kMaxPlanes; ++i) |
m_framePlanes[i].freeData(resourceProvider); |
} |
void VideoLayerImpl::freeUnusedPlaneData(ResourceProvider* resourceProvider) |
{ |
- unsigned firstUnusedPlane = m_frame ? m_frame->planes() : 0; |
- for (unsigned i = firstUnusedPlane; i < WebKit::WebVideoFrame::maxPlanes; ++i) |
+ size_t firstUnusedPlane = numPlanes(); |
+ for (size_t i = firstUnusedPlane; i < media::VideoFrame::kMaxPlanes; ++i) |
m_framePlanes[i].freeData(resourceProvider); |
} |