diff options
-rw-r--r-- | lib/delegated_frame_node.cpp | 31 | ||||
-rw-r--r-- | lib/lib.pro | 6 | ||||
-rw-r--r-- | lib/type_conversion.h | 5 | ||||
-rw-r--r-- | lib/yuv_video_node.cpp | 274 | ||||
-rw-r--r-- | lib/yuv_video_node.h | 101 |
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 |