CCVideoLayerImpl.cpp [plain text]
#include "config.h"
#if USE(ACCELERATED_COMPOSITING)
#include "cc/CCVideoLayerImpl.h"
#include "Extensions3DChromium.h"
#include "GraphicsContext3D.h"
#include "LayerRendererChromium.h"
#include "NotImplemented.h"
#include "ProgramBinding.h"
#include "cc/CCLayerTreeHostImpl.h"
#include "cc/CCProxy.h"
#include "cc/CCQuadCuller.h"
#include "cc/CCVideoDrawQuad.h"
#include <public/WebVideoFrame.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
const float CCVideoLayerImpl::yuv2RGB[9] = {
1.164f, 1.164f, 1.164f,
0.f, -.391f, 2.018f,
1.596f, -.813f, 0.f,
};
const float CCVideoLayerImpl::yuvAdjust[3] = {
-0.0625f,
-0.5f,
-0.5f,
};
const float CCVideoLayerImpl::flipTransform[16] = {
1, 0, 0, 0,
0, -1, 0, 0,
0, 0, 1, 0,
0, 1, 0, 1,
};
CCVideoLayerImpl::CCVideoLayerImpl(int id, WebKit::WebVideoFrameProvider* provider)
: CCLayerImpl(id)
, m_provider(provider)
, m_layerTreeHostImpl(0)
, m_frame(0)
{
memcpy(m_streamTextureMatrix, flipTransform, sizeof(m_streamTextureMatrix));
provider->setVideoFrameProviderClient(this);
}
CCVideoLayerImpl::~CCVideoLayerImpl()
{
MutexLocker locker(m_providerMutex);
if (m_provider) {
m_provider->setVideoFrameProviderClient(0);
m_provider = 0;
}
for (unsigned i = 0; i < MaxPlanes; ++i)
m_textures[i].m_texture.clear();
}
void CCVideoLayerImpl::stopUsingProvider()
{
MutexLocker locker(m_providerMutex);
m_provider = 0;
}
static GC3Denum convertVFCFormatToGC3DFormat(const WebKit::WebVideoFrame& frame)
{
switch (frame.format()) {
case WebKit::WebVideoFrame::FormatYV12:
case WebKit::WebVideoFrame::FormatYV16:
return GraphicsContext3D::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();
}
return GraphicsContext3D::INVALID_VALUE;
}
void CCVideoLayerImpl::willDraw(LayerRendererChromium* layerRenderer)
{
ASSERT(CCProxy::isImplThread());
CCLayerImpl::willDraw(layerRenderer);
m_providerMutex.lock();
willDrawInternal(layerRenderer);
if (!m_frame)
m_providerMutex.unlock();
}
void CCVideoLayerImpl::willDrawInternal(LayerRendererChromium* layerRenderer)
{
ASSERT(CCProxy::isImplThread());
if (!m_provider) {
m_frame = 0;
return;
}
m_frame = m_provider->getCurrentFrame();
if (!m_frame)
return;
m_format = convertVFCFormatToGC3DFormat(*m_frame);
if (m_format == GraphicsContext3D::INVALID_VALUE) {
m_provider->putCurrentFrame(m_frame);
m_frame = 0;
return;
}
if (!reserveTextures(*m_frame, m_format, layerRenderer)) {
m_provider->putCurrentFrame(m_frame);
m_frame = 0;
}
}
void CCVideoLayerImpl::appendQuads(CCQuadCuller& quadList, const CCSharedQuadState* sharedQuadState, bool&)
{
ASSERT(CCProxy::isImplThread());
if (!m_frame)
return;
IntRect quadRect(IntPoint(), bounds());
OwnPtr<CCVideoDrawQuad> videoQuad = CCVideoDrawQuad::create(sharedQuadState, quadRect, m_textures, m_frame, m_format);
if (m_format == Extensions3DChromium::GL_TEXTURE_EXTERNAL_OES)
videoQuad->setMatrix(m_streamTextureMatrix);
quadList.append(videoQuad.release());
}
void CCVideoLayerImpl::didDraw()
{
ASSERT(CCProxy::isImplThread());
CCLayerImpl::didDraw();
if (!m_frame)
return;
for (unsigned plane = 0; plane < m_frame->planes(); ++plane)
m_textures[plane].m_texture->unreserve();
m_provider->putCurrentFrame(m_frame);
m_frame = 0;
m_providerMutex.unlock();
}
static int videoFrameDimension(int originalDimension, unsigned plane, int format)
{
if (format == WebKit::WebVideoFrame::FormatYV12 && plane != WebKit::WebVideoFrame::yPlane)
return originalDimension / 2;
return originalDimension;
}
static bool hasPaddingBytes(const WebKit::WebVideoFrame& frame, unsigned plane)
{
return frame.stride(plane) > videoFrameDimension(frame.width(), plane, frame.format());
}
IntSize CCVideoLayerImpl::computeVisibleSize(const WebKit::WebVideoFrame& frame, unsigned plane)
{
int visibleWidth = videoFrameDimension(frame.width(), plane, frame.format());
int originalWidth = visibleWidth;
int visibleHeight = videoFrameDimension(frame.height(), plane, frame.format());
if (hasPaddingBytes(frame, plane))
--visibleWidth;
if (plane == WebKit::WebVideoFrame::yPlane && frame.format() == WebKit::WebVideoFrame::FormatYV12) {
if (hasPaddingBytes(frame, WebKit::WebVideoFrame::uPlane))
visibleWidth = originalWidth - 2;
}
return IntSize(visibleWidth, visibleHeight);
}
bool CCVideoLayerImpl::reserveTextures(const WebKit::WebVideoFrame& frame, GC3Denum format, LayerRendererChromium* layerRenderer)
{
if (frame.planes() > MaxPlanes)
return false;
int maxTextureSize = layerRenderer->capabilities().maxTextureSize;
for (unsigned plane = 0; plane < frame.planes(); ++plane) {
IntSize requiredTextureSize(frame.stride(plane), videoFrameDimension(frame.height(), plane, frame.format()));
if (requiredTextureSize.isZero() || requiredTextureSize.width() > maxTextureSize || requiredTextureSize.height() > maxTextureSize)
return false;
if (!m_textures[plane].m_texture) {
m_textures[plane].m_texture = ManagedTexture::create(layerRenderer->renderSurfaceTextureManager());
if (!m_textures[plane].m_texture)
return false;
m_textures[plane].m_visibleSize = IntSize();
} else {
m_textures[plane].m_texture->setTextureManager(layerRenderer->renderSurfaceTextureManager());
}
if (m_textures[plane].m_texture->size() != requiredTextureSize)
m_textures[plane].m_visibleSize = computeVisibleSize(frame, plane);
if (!m_textures[plane].m_texture->reserve(requiredTextureSize, format))
return false;
}
return true;
}
void CCVideoLayerImpl::didReceiveFrame()
{
setNeedsRedraw();
}
void CCVideoLayerImpl::didUpdateMatrix(const float matrix[16])
{
memcpy(m_streamTextureMatrix, matrix, sizeof(m_streamTextureMatrix));
setNeedsRedraw();
}
void CCVideoLayerImpl::didLoseContext()
{
for (unsigned i = 0; i < MaxPlanes; ++i)
m_textures[i].m_texture.clear();
}
void CCVideoLayerImpl::setNeedsRedraw()
{
if (m_layerTreeHostImpl)
m_layerTreeHostImpl->setNeedsRedraw();
}
void CCVideoLayerImpl::dumpLayerProperties(TextStream& ts, int indent) const
{
writeIndent(ts, indent);
ts << "video layer\n";
CCLayerImpl::dumpLayerProperties(ts, indent);
}
}
#endif // USE(ACCELERATED_COMPOSITING)