summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2013-11-06 16:13:18 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-11-13 11:51:12 +0100
commit47d56fd2c2404f709a943be93b754b3d3cf49fa8 (patch)
tree6a967f20afbbd5e85e2c1a2f6bd414c019e4db69
parentf14eeffc576dd766909b1e9ad0fa22ec63a1c649 (diff)
Delegated renderer: Add YUV video support.
This basically reimplements GLRenderer::DrawYUVVideoQuad. Change-Id: I990e224d69b372c76e2174c174c9b82678e25b86 Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
-rw-r--r--lib/delegated_frame_node.cpp31
-rw-r--r--lib/lib.pro6
-rw-r--r--lib/type_conversion.h5
-rw-r--r--lib/yuv_video_node.cpp274
-rw-r--r--lib/yuv_video_node.h101
5 files changed, 415 insertions, 2 deletions
diff --git a/lib/delegated_frame_node.cpp b/lib/delegated_frame_node.cpp
index 0e3f34fff..c75256542 100644
--- a/lib/delegated_frame_node.cpp
+++ b/lib/delegated_frame_node.cpp
@@ -54,6 +54,7 @@
#include "chromium_gpu_helper.h"
#include "type_conversion.h"
+#include "yuv_video_node.h"
#include "base/message_loop/message_loop.h"
#include "base/bind.h"
@@ -62,6 +63,7 @@
#include "cc/quads/render_pass_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
+#include "cc/quads/yuv_video_draw_quad.h"
#include <QOpenGLFramebufferObject>
#include <QSGSimpleTextureNode>
#include <QSGTexture>
@@ -436,7 +438,36 @@ void DelegatedFrameNode::commit(cc::DelegatedFrameData *frameData)
// This has to be done at the end since many QSGSimpleTextureNode methods would overwrite this.
QSGGeometry::updateTexturedRectGeometry(textureNode->geometry(), textureNode->rect(), textureNode->texture()->convertToNormalizedSourceRect(toQt(tquad->tex_coord_rect)));
currentLayerChain->appendChildNode(textureNode);
+ break;
+ } case cc::DrawQuad::YUV_VIDEO_CONTENT: {
+ const cc::YUVVideoDrawQuad *vquad = cc::YUVVideoDrawQuad::MaterialCast(quad);
+ const cc::TransferableResource *yRes = findResource(frameData->resource_list, vquad->y_plane_resource_id);
+ const cc::TransferableResource *uRes = findResource(frameData->resource_list, vquad->u_plane_resource_id);
+ const cc::TransferableResource *vRes = findResource(frameData->resource_list, vquad->v_plane_resource_id);
+ const cc::TransferableResource *aRes = findResource(frameData->resource_list, vquad->a_plane_resource_id);
+
+ QSharedPointer<MailboxTexture> &yTexture = m_mailboxTextures[yRes->id] = oldMailboxTextures.value(yRes->id);
+ QSharedPointer<MailboxTexture> &uTexture = m_mailboxTextures[uRes->id] = oldMailboxTextures.value(uRes->id);
+ QSharedPointer<MailboxTexture> &vTexture = m_mailboxTextures[vRes->id] = oldMailboxTextures.value(vRes->id);
+ if (!yTexture) {
+ yTexture = QSharedPointer<MailboxTexture>(new MailboxTexture(yRes, /* hasAlpha */ false));
+ uTexture = QSharedPointer<MailboxTexture>(new MailboxTexture(uRes, /* hasAlpha */ false));
+ vTexture = QSharedPointer<MailboxTexture>(new MailboxTexture(vRes, /* hasAlpha */ false));
+ }
+
+ // Do not use a reference for aTexture since we don't necessarily want an entry for it in m_mailboxTextures.
+ QSharedPointer<MailboxTexture> aTexture;
+ // This currently requires --enable-vp8-alpha-playback to apply.
+ if (aRes) {
+ aTexture = oldMailboxTextures.value(aRes->id);
+ if (!aTexture)
+ aTexture = QSharedPointer<MailboxTexture>(new MailboxTexture(aRes, /* hasAlpha */ false));
+ m_mailboxTextures[aRes->id] = aTexture;
+ }
+ YUVVideoNode *videoNode = new YUVVideoNode(yTexture.data(), uTexture.data(), vTexture.data(), aTexture.data(), toQt(vquad->tex_scale));
+ videoNode->setRect(toQt(quad->rect));
+ currentLayerChain->appendChildNode(videoNode);
break;
} default:
qWarning("Unimplemented quad material: %d", quad->material);
diff --git a/lib/lib.pro b/lib/lib.pro
index 32af217b6..4eb076467 100644
--- a/lib/lib.pro
+++ b/lib/lib.pro
@@ -49,7 +49,8 @@ SOURCES = \
web_contents_delegate_qt.cpp \
web_contents_view_qt.cpp \
web_engine_context.cpp \
- web_event_factory.cpp
+ web_event_factory.cpp \
+ yuv_video_node.cpp
HEADERS = \
backing_store_qt.h \
@@ -70,5 +71,6 @@ HEADERS = \
web_contents_delegate_qt.h \
web_contents_view_qt.h \
web_engine_context.h \
- web_event_factory.h
+ web_event_factory.h \
+ yuv_video_node.h
diff --git a/lib/type_conversion.h b/lib/type_conversion.h
index b2e29685d..ce3423e63 100644
--- a/lib/type_conversion.h
+++ b/lib/type_conversion.h
@@ -91,6 +91,11 @@ inline QSize toQt(const gfx::Size &size)
return QSize(size.width(), size.height());
}
+inline QSizeF toQt(const gfx::SizeF &size)
+{
+ return QSizeF(size.width(), size.height());
+}
+
inline QMatrix4x4 toQt(const SkMatrix44 &m)
{
return QMatrix4x4(
diff --git a/lib/yuv_video_node.cpp b/lib/yuv_video_node.cpp
new file mode 100644
index 000000000..869630f67
--- /dev/null
+++ b/lib/yuv_video_node.cpp
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "yuv_video_node.h"
+
+#include <QtQuick/qsgtexture.h>
+
+class YUVVideoMaterialShader : public QSGMaterialShader
+{
+public:
+ virtual void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
+
+ virtual char const *const *attributeNames() const {
+ static const char *names[] = {
+ "a_position",
+ "a_texCoord",
+ 0
+ };
+ return names;
+ }
+
+protected:
+ virtual const char *vertexShader() const {
+ // Keep in sync with cc::VertexShaderPosTexYUVStretch
+ const char *shader =
+ "attribute highp vec4 a_position;\n"
+ "attribute mediump vec2 a_texCoord;\n"
+ "uniform highp mat4 matrix;\n"
+ "varying mediump vec2 v_texCoord;\n"
+ "uniform mediump vec2 texScale;\n"
+ "void main() {\n"
+ " gl_Position = matrix * a_position;\n"
+ " v_texCoord = a_texCoord * texScale;\n"
+ "}";
+ return shader;
+ }
+
+ virtual const char *fragmentShader() const {
+ // Keep in sync with cc::FragmentShaderYUVVideo
+ static const char *shader =
+ "varying mediump vec2 v_texCoord;\n"
+ "uniform sampler2D y_texture;\n"
+ "uniform sampler2D u_texture;\n"
+ "uniform sampler2D v_texture;\n"
+ "uniform lowp float alpha;\n"
+ "uniform lowp vec3 yuv_adj;\n"
+ "uniform lowp mat3 yuv_matrix;\n"
+ "void main() {\n"
+ " lowp float y_raw = texture2D(y_texture, v_texCoord).x;\n"
+ " lowp float u_unsigned = texture2D(u_texture, v_texCoord).x;\n"
+ " lowp float v_unsigned = texture2D(v_texture, v_texCoord).x;\n"
+ " lowp vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;\n"
+ " lowp vec3 rgb = yuv_matrix * yuv;\n"
+ " gl_FragColor = vec4(rgb, 1.0) * alpha;\n"
+ "}";
+ return shader;
+ }
+
+ virtual void initialize() {
+ m_id_matrix = program()->uniformLocation("matrix");
+ m_id_texScale = program()->uniformLocation("texScale");
+ m_id_yTexture = program()->uniformLocation("y_texture");
+ m_id_uTexture = program()->uniformLocation("u_texture");
+ m_id_vTexture = program()->uniformLocation("v_texture");
+ m_id_yuvMatrix = program()->uniformLocation("yuv_matrix");
+ m_id_yuvAdjust = program()->uniformLocation("yuv_adj");
+ m_id_opacity = program()->uniformLocation("alpha");
+ }
+
+ int m_id_matrix;
+ int m_id_texScale;
+ int m_id_yTexture;
+ int m_id_uTexture;
+ int m_id_vTexture;
+ int m_id_yuvMatrix;
+ int m_id_yuvAdjust;
+ int m_id_opacity;
+};
+
+class YUVAVideoMaterialShader : public YUVVideoMaterialShader
+{
+ virtual void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
+
+protected:
+ virtual const char *fragmentShader() const {
+ // Keep in sync with cc::FragmentShaderYUVAVideo
+ static const char *shader =
+ // "precision mediump float;\n"
+ // "precision mediump int;\n"
+ "varying mediump vec2 v_texCoord;\n"
+ "uniform sampler2D y_texture;\n"
+ "uniform sampler2D u_texture;\n"
+ "uniform sampler2D v_texture;\n"
+ "uniform sampler2D a_texture;\n"
+ "uniform lowp float alpha;\n"
+ "uniform lowp vec3 yuv_adj;\n"
+ "uniform lowp mat3 yuv_matrix;\n"
+ "void main() {\n"
+ " lowp float y_raw = texture2D(y_texture, v_texCoord).x;\n"
+ " lowp float u_unsigned = texture2D(u_texture, v_texCoord).x;\n"
+ " lowp float v_unsigned = texture2D(v_texture, v_texCoord).x;\n"
+ " lowp float a_raw = texture2D(a_texture, v_texCoord).x;\n"
+ " lowp vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;\n"
+ " lowp vec3 rgb = yuv_matrix * yuv;\n"
+ " gl_FragColor = vec4(rgb, 1.0) * (alpha * a_raw);\n"
+ "}";
+ return shader;
+ }
+
+ virtual void initialize() {
+ // YUVVideoMaterialShader has a subset of the uniforms.
+ YUVVideoMaterialShader::initialize();
+ m_id_aTexture = program()->uniformLocation("a_texture");
+ }
+
+ int m_id_aTexture;
+};
+
+void YUVVideoMaterialShader::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
+{
+ Q_UNUSED(oldMaterial);
+
+ YUVVideoMaterial *mat = static_cast<YUVVideoMaterial *>(newMaterial);
+ program()->setUniformValue(m_id_yTexture, 0);
+ program()->setUniformValue(m_id_uTexture, 1);
+ program()->setUniformValue(m_id_vTexture, 2);
+
+ glActiveTexture(GL_TEXTURE1);
+ mat->m_uTexture->bind();
+ glActiveTexture(GL_TEXTURE2);
+ mat->m_vTexture->bind();
+ glActiveTexture(GL_TEXTURE0); // Finish with 0 as default texture unit
+ mat->m_yTexture->bind();
+
+ program()->setUniformValue(m_id_texScale, mat->m_texScale);
+
+ // These values are magic numbers that are used in the transformation from YUV
+ // to RGB color values. They are taken from the following webpage:
+ // http://www.fourcc.org/fccyvrgb.php
+ const float yuv_to_rgb[9] = {
+ 1.164f, 0.0f, 1.596f,
+ 1.164f, -.391f, -.813f,
+ 1.164f, 2.018f, 0.0f,
+ };
+ const QMatrix3x3 yuvMatrix(yuv_to_rgb);
+
+ // These values map to 16, 128, and 128 respectively, and are computed
+ // as a fraction over 256 (e.g. 16 / 256 = 0.0625).
+ // They are used in the YUV to RGBA conversion formula:
+ // Y - 16 : Gives 16 values of head and footroom for overshooting
+ // U - 128 : Turns unsigned U into signed U [-128,127]
+ // V - 128 : Turns unsigned V into signed V [-128,127]
+ const QVector3D yuvAdjust(-0.0625f, -0.5f, -0.5f);
+ program()->setUniformValue(m_id_yuvMatrix, yuvMatrix);
+ program()->setUniformValue(m_id_yuvAdjust, yuvAdjust);
+
+ if (state.isOpacityDirty())
+ program()->setUniformValue(m_id_opacity, state.opacity());
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_id_matrix, state.combinedMatrix());
+}
+
+void YUVAVideoMaterialShader::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
+{
+ YUVVideoMaterialShader::updateState(state, newMaterial, oldMaterial);
+
+ YUVAVideoMaterial *mat = static_cast<YUVAVideoMaterial *>(newMaterial);
+ program()->setUniformValue(m_id_aTexture, 3);
+
+ glActiveTexture(GL_TEXTURE3);
+ mat->m_aTexture->bind();
+
+ // Reset the default texture unit.
+ glActiveTexture(GL_TEXTURE0);
+}
+
+
+YUVVideoMaterial::YUVVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, const QSizeF &texScale)
+ : m_yTexture(yTexture)
+ , m_uTexture(uTexture)
+ , m_vTexture(vTexture)
+ , m_texScale(texScale)
+{
+}
+
+QSGMaterialShader *YUVVideoMaterial::createShader() const
+{
+ return new YUVVideoMaterialShader;
+}
+
+int YUVVideoMaterial::compare(const QSGMaterial *other) const
+{
+ const YUVVideoMaterial *m = static_cast<const YUVVideoMaterial *>(other);
+ if (int diff = m_yTexture->textureId() - m->m_yTexture->textureId())
+ return diff;
+ if (int diff = m_uTexture->textureId() - m->m_uTexture->textureId())
+ return diff;
+ return m_vTexture->textureId() - m->m_vTexture->textureId();
+}
+
+YUVAVideoMaterial::YUVAVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, const QSizeF &texScale)
+ : YUVVideoMaterial(yTexture, uTexture, vTexture, texScale)
+ , m_aTexture(aTexture)
+{
+ setFlag(Blending, aTexture);
+}
+
+QSGMaterialShader *YUVAVideoMaterial::createShader() const
+{
+ return new YUVAVideoMaterialShader;
+}
+
+int YUVAVideoMaterial::compare(const QSGMaterial *other) const
+{
+ if (int diff = YUVVideoMaterial::compare(other))
+ return diff;
+ const YUVAVideoMaterial *m = static_cast<const YUVAVideoMaterial *>(other);
+ return (m_aTexture ? m_aTexture->textureId() : 0) - (m->m_aTexture ? m->m_aTexture->textureId() : 0);
+}
+
+YUVVideoNode::YUVVideoNode(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, const QSizeF &texScale)
+ : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+{
+ setGeometry(&m_geometry);
+ setFlag(QSGNode::OwnsMaterial);
+ if (aTexture)
+ m_material = new YUVAVideoMaterial(yTexture, uTexture, vTexture, aTexture, texScale);
+ else
+ m_material = new YUVVideoMaterial(yTexture, uTexture, vTexture, texScale);
+ setMaterial(m_material);
+}
+
+void YUVVideoNode::setRect(const QRectF &rect)
+{
+ QSGGeometry::updateTexturedRectGeometry(geometry(), rect, QRectF(0, 0, 1, 1));
+}
diff --git a/lib/yuv_video_node.h b/lib/yuv_video_node.h
new file mode 100644
index 000000000..73e267d92
--- /dev/null
+++ b/lib/yuv_video_node.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef YUV_VIDEO_NODE_H
+#define YUV_VIDEO_NODE_H
+
+#include <QtQuick/qsgmaterial.h>
+#include <QtQuick/qsgnode.h>
+
+QT_BEGIN_NAMESPACE
+class QSGTexture;
+QT_END_NAMESPACE
+
+// These classes duplicate, QtQuick style, the logic of GLRenderer::DrawYUVVideoQuad.
+// Their behavior should stay as close as possible to GLRenderer.
+
+class YUVVideoMaterial : public QSGMaterial
+{
+public:
+ YUVVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, const QSizeF &texScale);
+
+ virtual QSGMaterialType *type() const {
+ static QSGMaterialType theType;
+ return &theType;
+ }
+
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
+
+ QSGTexture *m_yTexture;
+ QSGTexture *m_uTexture;
+ QSGTexture *m_vTexture;
+ QSizeF m_texScale;
+};
+
+class YUVAVideoMaterial : public YUVVideoMaterial
+{
+public:
+ YUVAVideoMaterial(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, const QSizeF &texScale);
+
+ virtual QSGMaterialType *type() const {
+ static QSGMaterialType theType;
+ return &theType;
+ }
+
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
+
+ QSGTexture *m_aTexture;
+};
+
+class YUVVideoNode : public QSGGeometryNode
+{
+public:
+ YUVVideoNode(QSGTexture *yTexture, QSGTexture *uTexture, QSGTexture *vTexture, QSGTexture *aTexture, const QSizeF &texScale);
+ void setRect(const QRectF &rect);
+
+private:
+ QSGGeometry m_geometry;
+ YUVVideoMaterial *m_material;
+};
+
+#endif // YUV_VIDEO_NODE_H