diff options
author | VaL Doroshchuk <valentyn.doroshchuk@qt.io> | 2020-05-21 15:17:07 +0200 |
---|---|---|
committer | Val Doroshchuk <valentyn.doroshchuk@qt.io> | 2020-05-29 16:46:42 +0200 |
commit | f60c028d522ce3e4ed01cf00e6601956a1f0ed01 (patch) | |
tree | 82e33543e766cdf1dc95d4a1cfad596f479b7a47 /src | |
parent | 5238ce8fdc5dd357dc96e351ba8baea73ce9fb55 (diff) |
Quick: Add support of RHI for video frames
Added RHI shaders for RGB*, YUV* and opengl texture video frames.
Task-number: QTBUG-78678
Change-Id: I045d6a806fea059a80b8e5d9817b6997af8d0f41
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src')
26 files changed, 899 insertions, 4 deletions
diff --git a/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp index 4fb62921e..5746a644a 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp @@ -37,6 +37,7 @@ ** ****************************************************************************/ #include "qsgvideonode_rgb_p.h" +#include "qsgvideotexture_p.h" #include <QtQuick/qsgtexturematerial.h> #include <QtQuick/qsgmaterial.h> #include <QtCore/qmutex.h> @@ -128,6 +129,21 @@ protected: bool m_hasAlpha; }; +class QSGVideoMaterialRhiShader_RGB : public QSGMaterialRhiShader +{ +public: + QSGVideoMaterialRhiShader_RGB() + { + setShaderFileName(VertexStage, QStringLiteral(":/qtmultimediaquicktools/shaders_ng/rgba.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/qtmultimediaquicktools/shaders_ng/rgba.frag.qsb")); + } + + bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, + QSGMaterial *oldMaterial) override; + + void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; +}; class QSGVideoMaterial_RGB : public QSGMaterial { @@ -139,6 +155,7 @@ public: m_width(1.0) { setFlag(Blending, false); + setFlag(SupportsRhiShader, true); } ~QSGVideoMaterial_RGB() @@ -153,6 +170,9 @@ public: } QSGMaterialShader *createShader() const override { + if (flags().testFlag(RhiShaderWanted)) + return new QSGVideoMaterialRhiShader_RGB; + const bool hasAlpha = m_format.pixelFormat() == QVideoFrame::Format_ARGB32; return needsSwizzling() ? new QSGVideoMaterialShader_RGB_swizzle(hasAlpha) : new QSGVideoMaterialShader_RGB; @@ -245,6 +265,7 @@ public: GLuint m_textureId; qreal m_opacity; GLfloat m_width; + QScopedPointer<QSGVideoTexture> m_texture; private: bool needsSwizzling() const { @@ -253,6 +274,63 @@ private: } }; +bool QSGVideoMaterialRhiShader_RGB::updateUniformData(RenderState &state, QSGMaterial *newMaterial, + QSGMaterial *oldMaterial) +{ + Q_UNUSED(newMaterial); + Q_UNUSED(oldMaterial); + + bool changed = false; + QByteArray *buf = state.uniformData(); + + if (state.isMatrixDirty()) { + memcpy(buf->data(), state.combinedMatrix().constData(), 64); + changed = true; + } + + if (state.isOpacityDirty()) { + const float opacity = state.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + changed = true; + } + + return changed; +} + +void QSGVideoMaterialRhiShader_RGB::updateSampledImage(RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) +{ + Q_UNUSED(oldMaterial); + + if (binding < 1) + return; + + auto m = static_cast<QSGVideoMaterial_RGB *>(newMaterial); + if (!m->m_texture) + m->m_texture.reset(new QSGVideoTexture); + + m->m_frameMutex.lock(); + auto frame = m->m_frame; + m->m_frameMutex.unlock(); + + if (frame.pixelFormat() == QVideoFrame::Format_RGB565) // Format_RGB565 requires GL_UNSIGNED_SHORT_5_6_5 + frame = frame.image().convertToFormat(QImage::Format_RGBA8888_Premultiplied); + + auto format = QRhiTexture::RGBA8; + if (frame.pixelFormat() == QVideoFrame::Format_RGB32 + || frame.pixelFormat() == QVideoFrame::Format_ARGB32) + { + format = QRhiTexture::BGRA8; + } + + if (frame.isValid() && frame.map(QAbstractVideoBuffer::ReadOnly)) { + m->m_texture->setData(format, frame.size(), frame.bits(), frame.bytesPerLine() * frame.height()); + frame.unmap(); + } + + m->m_texture->commitTextureOperations(state.rhi(), state.resourceUpdateBatch()); + *texture = m->m_texture.data(); +} QSGVideoNode_RGB::QSGVideoNode_RGB(const QVideoSurfaceFormat &format) : m_format(format) diff --git a/src/qtmultimediaquicktools/qsgvideonode_texture.cpp b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp index d89a36ee8..a5206eefb 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_texture.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp @@ -37,6 +37,7 @@ ** ****************************************************************************/ #include "qsgvideonode_texture_p.h" +#include "qsgvideotexture_p.h" #include <QtQuick/qsgtexturematerial.h> #include <QtQuick/qsgmaterial.h> #include <QtCore/qmutex.h> @@ -126,6 +127,30 @@ protected: int m_hasAlpha; }; +class QSGVideoMaterialRhiShader_Texture : public QSGMaterialRhiShader +{ +public: + QSGVideoMaterialRhiShader_Texture() + { + setShaderFileName(VertexStage, QStringLiteral(":/qtmultimediaquicktools/shaders_ng/rgba.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/qtmultimediaquicktools/shaders_ng/rgba.frag.qsb")); + } + + bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, + QSGMaterial *oldMaterial) override; + + void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; +}; + +class QSGVideoMaterialRhiShader_Texture_swizzle : public QSGVideoMaterialRhiShader_Texture +{ +public: + QSGVideoMaterialRhiShader_Texture_swizzle() + { + setShaderFileName(FragmentStage, QStringLiteral(":/qtmultimediaquicktools/shaders_ng/bgra.frag.qsb")); + } +}; class QSGVideoMaterial_Texture : public QSGMaterial { @@ -136,6 +161,7 @@ public: m_opacity(1.0) { setFlag(Blending, false); + setFlag(SupportsRhiShader, true); } ~QSGVideoMaterial_Texture() @@ -149,6 +175,10 @@ public: } QSGMaterialShader *createShader() const override { + if (flags().testFlag(RhiShaderWanted)) + return needsSwizzling() ? new QSGVideoMaterialRhiShader_Texture_swizzle + : new QSGVideoMaterialRhiShader_Texture; + const bool hasAlpha = m_format.pixelFormat() == QVideoFrame::Format_ARGB32; return needsSwizzling() ? new QSGVideoMaterialShader_Texture_swizzle(hasAlpha) : new QSGVideoMaterialShader_Texture; @@ -201,8 +231,9 @@ public: QMutex m_frameMutex; QSize m_textureSize; QVideoSurfaceFormat m_format; - GLuint m_textureId; + quint64 m_textureId; qreal m_opacity; + QScopedPointer<QSGVideoTexture> m_texture; private: bool needsSwizzling() const { @@ -211,6 +242,51 @@ private: } }; +bool QSGVideoMaterialRhiShader_Texture::updateUniformData(RenderState &state, QSGMaterial *newMaterial, + QSGMaterial *oldMaterial) +{ + Q_UNUSED(newMaterial); + Q_UNUSED(oldMaterial); + + bool changed = false; + QByteArray *buf = state.uniformData(); + + if (state.isMatrixDirty()) { + memcpy(buf->data(), state.combinedMatrix().constData(), 64); + changed = true; + } + + if (state.isOpacityDirty()) { + const float opacity = state.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + changed = true; + } + + return changed; +} + +void QSGVideoMaterialRhiShader_Texture::updateSampledImage(RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) +{ + Q_UNUSED(oldMaterial); + + if (binding < 1) + return; + + auto m = static_cast<QSGVideoMaterial_Texture *>(newMaterial); + if (!m->m_texture) + m->m_texture.reset(new QSGVideoTexture); + + m->m_frameMutex.lock(); + auto size = m->m_frame.size(); + if (m->m_frame.isValid()) + m->m_textureId = m->m_frame.handle().toULongLong(); + m->m_frameMutex.unlock(); + + m->m_texture->setNativeObject(m->m_textureId, size); + m->m_texture->commitTextureOperations(state.rhi(), state.resourceUpdateBatch()); + *texture = m->m_texture.data(); +} QSGVideoNode_Texture::QSGVideoNode_Texture(const QVideoSurfaceFormat &format) : m_format(format) diff --git a/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp b/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp index 2b50e9cb0..006704a23 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp @@ -37,6 +37,7 @@ ** ****************************************************************************/ #include "qsgvideonode_yuv_p.h" +#include "qsgvideotexture_p.h" #include <QtCore/qmutex.h> #include <QtQuick/qsgtexturematerial.h> #include <QtQuick/qsgmaterial.h> @@ -181,7 +182,6 @@ public: } }; - class QSGVideoMaterialShader_YUV_BiPlanar_swizzle : public QSGVideoMaterialShader_YUV_BiPlanar { public: @@ -192,7 +192,6 @@ public: } }; - class QSGVideoMaterialShader_YUV_TriPlanar : public QSGVideoMaterialShader_YUV_BiPlanar { public: @@ -216,6 +215,77 @@ protected: int m_id_plane3Texture; }; +class QSGVideoMaterialRhiShader_YUV : public QSGMaterialRhiShader +{ +public: + QSGVideoMaterialRhiShader_YUV() + { + setShaderFileName(VertexStage, QStringLiteral(":/qtmultimediaquicktools/shaders_ng/yuv.vert.qsb")); + } + + bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, + QSGMaterial *oldMaterial) override; + + void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; + + virtual void mapFrame(QSGVideoMaterial_YUV *) = 0; + +protected: + GLfloat m_planeWidth[3] = {0, 0, 0}; + QMatrix4x4 m_colorMatrix; +}; + +class QSGVideoMaterialRhiShader_UYVY : public QSGVideoMaterialRhiShader_YUV +{ +public: + QSGVideoMaterialRhiShader_UYVY() + { + setShaderFileName(FragmentStage, QStringLiteral(":/qtmultimediaquicktools/shaders_ng/uyvy.frag.qsb")); + } + + void mapFrame(QSGVideoMaterial_YUV *m) override; +}; + +class QSGVideoMaterialRhiShader_YUYV : public QSGVideoMaterialRhiShader_UYVY +{ +public: + QSGVideoMaterialRhiShader_YUYV() + { + setShaderFileName(FragmentStage, QStringLiteral(":/qtmultimediaquicktools/shaders_ng/yuyv.frag.qsb")); + } +}; + +class QSGVideoMaterialRhiShader_YUV_YV : public QSGVideoMaterialRhiShader_YUV +{ +public: + QSGVideoMaterialRhiShader_YUV_YV() + { + setShaderFileName(FragmentStage, QStringLiteral(":/qtmultimediaquicktools/shaders_ng/yuv_yv.frag.qsb")); + } + + void mapFrame(QSGVideoMaterial_YUV *m) override; +}; + +class QSGVideoMaterialRhiShader_NV12 : public QSGVideoMaterialRhiShader_YUV +{ +public: + QSGVideoMaterialRhiShader_NV12() + { + setShaderFileName(FragmentStage, QStringLiteral(":/qtmultimediaquicktools/shaders_ng/nv12.frag.qsb")); + } + + void mapFrame(QSGVideoMaterial_YUV *m) override; +}; + +class QSGVideoMaterialRhiShader_NV21 : public QSGVideoMaterialRhiShader_NV12 +{ +public: + QSGVideoMaterialRhiShader_NV21() + { + setShaderFileName(FragmentStage, QStringLiteral(":/qtmultimediaquicktools/shaders_ng/nv21.frag.qsb")); + } +}; class QSGVideoMaterial_YUV : public QSGMaterial { @@ -241,6 +311,21 @@ public: } QSGMaterialShader *createShader() const override { + if (flags().testFlag(RhiShaderWanted)) { + switch (m_format.pixelFormat()) { + case QVideoFrame::Format_NV12: + return new QSGVideoMaterialRhiShader_NV12; + case QVideoFrame::Format_NV21: + return new QSGVideoMaterialRhiShader_NV21; + case QVideoFrame::Format_UYVY: + return new QSGVideoMaterialRhiShader_UYVY; + case QVideoFrame::Format_YUYV: + return new QSGVideoMaterialRhiShader_YUYV; + default: // Currently: YUV420P, YUV422P and YV12 + return new QSGVideoMaterialRhiShader_YUV_YV; + } + } + switch (m_format.pixelFormat()) { case QVideoFrame::Format_NV12: return new QSGVideoMaterialShader_YUV_BiPlanar; @@ -293,12 +378,145 @@ public: QVideoFrame m_frame; QMutex m_frameMutex; + + QScopedPointer<QSGVideoTexture> m_textures[3]; }; +bool QSGVideoMaterialRhiShader_YUV::updateUniformData(RenderState &state, QSGMaterial *newMaterial, + QSGMaterial *oldMaterial) +{ + Q_UNUSED(oldMaterial); + + auto m = static_cast<QSGVideoMaterial_YUV *>(newMaterial); + bool changed = false; + QByteArray *buf = state.uniformData(); + + if (state.isMatrixDirty()) { + memcpy(buf->data(), state.combinedMatrix().constData(), 64); + changed = true; + } + + if (m->m_colorMatrix != m_colorMatrix) { + memcpy(buf->data() + 64, m->m_colorMatrix.constData(), 64); + changed = true; + } + m_colorMatrix = m->m_colorMatrix; + + if (state.isOpacityDirty()) { + const float opacity = state.opacity(); + memcpy(buf->data() + 64 + 64, &opacity, 4); + changed = true; + } + + if (!m->m_textures[0]) { + m->m_textures[0].reset(new QSGVideoTexture); + m->m_textures[1].reset(new QSGVideoTexture); + } + + mapFrame(m); + + if (m->m_planeWidth[0] != m_planeWidth[0] + || m->m_planeWidth[1] != m_planeWidth[1] + || m->m_planeWidth[2] != m_planeWidth[2]) + { + memcpy(buf->data() + 64 + 64 + 4, &m->m_planeWidth[0], 4); + memcpy(buf->data() + 64 + 64 + 4 + 4, &m->m_planeWidth[1], 4); + memcpy(buf->data() + 64 + 64 + 4 + 4 + 4, &m->m_planeWidth[2], 4); + changed = true; + } + m_planeWidth[0] = m->m_planeWidth[0]; + m_planeWidth[1] = m->m_planeWidth[1]; + m_planeWidth[2] = m->m_planeWidth[2]; + + return changed; +} + +void QSGVideoMaterialRhiShader_YUV::updateSampledImage(RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) +{ + Q_UNUSED(oldMaterial); + if (binding < 1 || binding > 3) + return; + + auto m = static_cast<QSGVideoMaterial_YUV *>(newMaterial); + *texture = m->m_textures[binding - 1].data(); + (*texture)->commitTextureOperations(state.rhi(), state.resourceUpdateBatch()); +} + +void QSGVideoMaterialRhiShader_UYVY::mapFrame(QSGVideoMaterial_YUV *m) +{ + if (!m->m_frame.isValid() || !m->m_frame.map(QAbstractVideoBuffer::ReadOnly)) + return; + + int fw = m->m_frame.width(); + int fh = m->m_frame.height(); + + m->m_planeWidth[0] = 1; + m->m_planeWidth[1] = 1; + + // Either r,b (YUYV) or g,a (UYVY) values are used as source of UV. + // Additionally U and V are set per 2 pixels hence only 1/2 of image width is used. + m->m_textures[0]->setData(QRhiTexture::RG8, m->m_frame.size(), + m->m_frame.bits(), m->m_frame.bytesPerLine() * fh); + m->m_textures[1]->setData(QRhiTexture::RGBA8, QSize(fw / 2, fh), + m->m_frame.bits(), m->m_frame.bytesPerLine() * fh); + + m->m_frame.unmap(); +} + +void QSGVideoMaterialRhiShader_YUV_YV::mapFrame(QSGVideoMaterial_YUV *m) +{ + if (!m->m_frame.isValid() || !m->m_frame.map(QAbstractVideoBuffer::ReadOnly)) + return; + + if (!m->m_textures[2]) + m->m_textures[2].reset(new QSGVideoTexture); + + int y = 0; + int u = m->m_frame.pixelFormat() == QVideoFrame::Format_YV12 ? 2 : 1; + int v = m->m_frame.pixelFormat() == QVideoFrame::Format_YV12 ? 1 : 2; + int fw = m->m_frame.width(); + int fh = m->m_frame.height(); + int uvHeight = m->m_frame.pixelFormat() == QVideoFrame::Format_YUV422P ? fh : fh / 2; + + m->m_planeWidth[0] = qreal(fw) / m->m_frame.bytesPerLine(y); + m->m_planeWidth[1] = m->m_planeWidth[2] = qreal(fw) / (2 * m->m_frame.bytesPerLine(u)); + + m->m_textures[0]->setData(QRhiTexture::R8, m->m_frame.size(), + m->m_frame.bits(y), m->m_frame.bytesPerLine(y) * fh); + m->m_textures[1]->setData(QRhiTexture::R8, QSize(m->m_frame.bytesPerLine(u), uvHeight), + m->m_frame.bits(u), m->m_frame.bytesPerLine(u) * uvHeight); + m->m_textures[2]->setData(QRhiTexture::R8, QSize(m->m_frame.bytesPerLine(v), uvHeight), + m->m_frame.bits(v), m->m_frame.bytesPerLine(v) * uvHeight); + + m->m_frame.unmap(); +} + +void QSGVideoMaterialRhiShader_NV12::mapFrame(QSGVideoMaterial_YUV *m) +{ + if (!m->m_frame.isValid() || !m->m_frame.map(QAbstractVideoBuffer::ReadOnly)) + return; + + int y = 0; + int uv = 1; + int fw = m->m_frame.width(); + int fh = m->m_frame.height(); + + m->m_planeWidth[0] = m->m_planeWidth[1] = qreal(fw) / m->m_frame.bytesPerLine(y); + + m->m_textures[0]->setData(QRhiTexture::R8, m->m_frame.size(), + m->m_frame.bits(y), m->m_frame.bytesPerLine(y) * fh); + m->m_textures[1]->setData(QRhiTexture::RG8, QSize(m->m_frame.bytesPerLine(uv) / 2 , fh / 2), + m->m_frame.bits(uv), m->m_frame.bytesPerLine(uv) * fh / 2); + + m->m_frame.unmap(); +} + QSGVideoMaterial_YUV::QSGVideoMaterial_YUV(const QVideoSurfaceFormat &format) : m_format(format), m_opacity(1.0) { + setFlag(SupportsRhiShader, true); memset(m_textureIds, 0, sizeof(m_textureIds)); switch (format.pixelFormat()) { diff --git a/src/qtmultimediaquicktools/qsgvideotexture.cpp b/src/qtmultimediaquicktools/qsgvideotexture.cpp new file mode 100644 index 000000000..dd31695ef --- /dev/null +++ b/src/qtmultimediaquicktools/qsgvideotexture.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgvideotexture_p.h" +#include <QtQuick/qsgtexturematerial.h> +#include <QtQuick/qsgmaterial.h> + +QT_BEGIN_NAMESPACE + +class QSGVideoTexturePrivate +{ + Q_DECLARE_PUBLIC(QSGVideoTexture) +public: + void updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates); + +private: + QSGVideoTexture *q_ptr = nullptr; + QRhiTexture::Format m_format; + QSize m_size; + const uchar *m_data = nullptr; + qsizetype m_bytes = 0; + + QScopedPointer<QRhiTexture> m_texture; + quint64 m_nativeObject = 0; +}; + +QSGVideoTexture::QSGVideoTexture() + : d_ptr(new QSGVideoTexturePrivate) +{ + d_ptr->q_ptr = this; +} + +QSGVideoTexture::~QSGVideoTexture() +{ +} + +qint64 QSGVideoTexture::comparisonKey() const +{ + Q_D(const QSGVideoTexture); + if (d->m_nativeObject) + return d->m_nativeObject; + + if (d->m_texture) + return qint64(qintptr(d->m_texture.data())); + + // two textures (and so materials) with not-yet-created texture underneath are never equal + return qint64(qintptr(this)); +} + +int QSGVideoTexture::textureId() const // legacy +{ + return 0; +} + +QRhiTexture *QSGVideoTexture::rhiTexture() const +{ + return d_func()->m_texture.data(); +} + +QSize QSGVideoTexture::textureSize() const +{ + return d_func()->m_size; +} + +bool QSGVideoTexture::hasAlphaChannel() const +{ + Q_D(const QSGVideoTexture); + return d->m_format == QRhiTexture::RGBA8 || d->m_format == QRhiTexture::BGRA8; +} + +bool QSGVideoTexture::hasMipmaps() const +{ + return mipmapFiltering() != QSGTexture::None; +} + +void QSGVideoTexture::bind() +{ +} + +void QSGVideoTexture::setData(QRhiTexture::Format f, const QSize &s, const uchar *data, qsizetype bytes) +{ + Q_D(QSGVideoTexture); + d->m_size = s; + d->m_format = f; + d->m_data = data; + d->m_bytes = bytes; +} + +void QSGVideoTexture::setNativeObject(quint64 obj, const QSize &s) +{ + Q_D(QSGVideoTexture); + setData(QRhiTexture::RGBA8, s, nullptr, 0); + if (d->m_nativeObject != obj) { + d->m_nativeObject = obj; + d->m_texture.reset(); + } +} + +void QSGVideoTexturePrivate::updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates) +{ + Q_Q(QSGVideoTexture); + + bool needsRebuild = m_texture && m_texture->pixelSize() != m_size; + if (!m_texture) { + QRhiTexture::Flags flags; + if (q->hasMipmaps()) + flags |= QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips; + + m_texture.reset(rhi->newTexture(m_format, m_size, 1, flags)); + needsRebuild = true; + } + + if (needsRebuild) { + m_texture->setPixelSize(m_size); + bool created = m_nativeObject + ? m_texture->buildFrom({m_nativeObject, 0}) + : m_texture->build(); + if (!created) { + qWarning("Failed to build texture (size %dx%d)", + m_size.width(), m_size.height()); + return; + } + } + + if (m_bytes) { + QRhiTextureSubresourceUploadDescription subresDesc(m_data, m_bytes); + subresDesc.setSourceSize(m_size); + subresDesc.setDestinationTopLeft(QPoint(0, 0)); + QRhiTextureUploadEntry entry(0, 0, subresDesc); + QRhiTextureUploadDescription desc({ entry }); + resourceUpdates->uploadTexture(m_texture.data(), desc); + } +} + +void QSGVideoTexture::commitTextureOperations(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates) +{ + d_func()->updateRhiTexture(rhi, resourceUpdates); +} + +QT_END_NAMESPACE diff --git a/src/qtmultimediaquicktools/qsgvideotexture_p.h b/src/qtmultimediaquicktools/qsgvideotexture_p.h new file mode 100644 index 000000000..6201264b6 --- /dev/null +++ b/src/qtmultimediaquicktools/qsgvideotexture_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGVIDEOTEXTURE_H +#define QSGVIDEOTEXTURE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtQuick/QSGTexture> +#include <QImage> +#include <private/qrhi_p.h> + +QT_BEGIN_NAMESPACE + +class QSGVideoTexturePrivate; +class QSGVideoTexture : public QSGTexture +{ + Q_DECLARE_PRIVATE(QSGVideoTexture) +public: + QSGVideoTexture(); + ~QSGVideoTexture(); + + qint64 comparisonKey() const override; + int textureId() const override; + QRhiTexture *rhiTexture() const override; + QSize textureSize() const override; + bool hasAlphaChannel() const override; + bool hasMipmaps() const override; + void bind() override; + void commitTextureOperations(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates) override; + void setData(QRhiTexture::Format f, const QSize &s, const uchar *data, qsizetype bytes); + void setNativeObject(quint64 obj, const QSize &s); + +protected: + QScopedPointer<QSGVideoTexturePrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QSGVIDEOTEXTURE_H diff --git a/src/qtmultimediaquicktools/qtmultimediaquicktools.pro b/src/qtmultimediaquicktools/qtmultimediaquicktools.pro index 4f3908f6a..fefb8dec5 100644 --- a/src/qtmultimediaquicktools/qtmultimediaquicktools.pro +++ b/src/qtmultimediaquicktools/qtmultimediaquicktools.pro @@ -1,12 +1,13 @@ TARGET = QtMultimediaQuick -QT = core opengl quick multimedia-private +QT = core quick multimedia-private CONFIG += internal_module PRIVATE_HEADERS += \ qdeclarativevideooutput_p.h \ qdeclarativevideooutput_backend_p.h \ qsgvideonode_p.h \ + qsgvideotexture_p.h \ qtmultimediaquickdefs_p.h HEADERS += \ @@ -15,6 +16,7 @@ HEADERS += \ SOURCES += \ qsgvideonode_p.cpp \ + qsgvideotexture.cpp \ qdeclarativevideooutput.cpp \ qdeclarativevideooutput_window.cpp diff --git a/src/qtmultimediaquicktools/qtmultimediaquicktools.qrc b/src/qtmultimediaquicktools/qtmultimediaquicktools.qrc index b8180e31f..1c0e29c04 100644 --- a/src/qtmultimediaquicktools/qtmultimediaquicktools.qrc +++ b/src/qtmultimediaquicktools/qtmultimediaquicktools.qrc @@ -23,5 +23,15 @@ <file>shaders/triplanaryuvvideo_core.vert</file> <file>shaders/uyvyvideo_core.frag</file> <file>shaders/yuyvvideo_core.frag</file> + + <file>shaders_ng/rgba.vert.qsb</file> + <file>shaders_ng/rgba.frag.qsb</file> + <file>shaders_ng/bgra.frag.qsb</file> + <file>shaders_ng/yuv.vert.qsb</file> + <file>shaders_ng/yuv_yv.frag.qsb</file> + <file>shaders_ng/nv12.frag.qsb</file> + <file>shaders_ng/nv21.frag.qsb</file> + <file>shaders_ng/uyvy.frag.qsb</file> + <file>shaders_ng/yuyv.frag.qsb</file> </qresource> </RCC> diff --git a/src/qtmultimediaquicktools/shaders_ng/bgra.frag b/src/qtmultimediaquicktools/shaders_ng/bgra.frag new file mode 100644 index 000000000..f04e3e721 --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/bgra.frag @@ -0,0 +1,16 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + float opacity; +} ubuf; + +layout(binding = 1) uniform sampler2D rgbTexture; + +void main() +{ + fragColor = texture(rgbTexture, qt_TexCoord).bgra * ubuf.opacity; +} diff --git a/src/qtmultimediaquicktools/shaders_ng/bgra.frag.qsb b/src/qtmultimediaquicktools/shaders_ng/bgra.frag.qsb Binary files differnew file mode 100644 index 000000000..20c61e92f --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/bgra.frag.qsb diff --git a/src/qtmultimediaquicktools/shaders_ng/compile.bat b/src/qtmultimediaquicktools/shaders_ng/compile.bat new file mode 100755 index 000000000..682cc71b8 --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/compile.bat @@ -0,0 +1,50 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: Copyright (C) 2019 The Qt Company Ltd. +:: Contact: https://www.qt.io/licensing/ +:: +:: This file is part of the QtQuick module 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 The Qt Company. For licensing terms +:: and conditions see https://www.qt.io/terms-conditions. For further +:: information use the contact form at https://www.qt.io/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 3 as published by the Free Software +:: Foundation and appearing in the file LICENSE.LGPL3 included in the +:: packaging of this file. Please review the following information to +:: ensure the GNU Lesser General Public License version 3 requirements +:: will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +:: +:: GNU General Public License Usage +:: Alternatively, this file may be used under the terms of the GNU +:: General Public License version 2.0 or (at your option) the GNU General +:: Public license version 3 or any later version approved by the KDE Free +:: Qt Foundation. The licenses are as published by the Free Software +:: Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +:: included in the packaging of this file. Please review the following +:: information to ensure the GNU General Public License requirements will +:: be met: https://www.gnu.org/licenses/gpl-2.0.html and +:: https://www.gnu.org/licenses/gpl-3.0.html. +:: +:: $QT_END_LICENSE$ +:: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o rgba.vert.qsb rgba.vert +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o rgba.frag.qsb rgba.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o bgra.frag.qsb bgra.frag + +qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o yuv.vert.qsb yuv.vert +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o yuv_yv.frag.qsb yuv_yv.frag + +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o nv12.frag.qsb nv12.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o nv21.frag.qsb nv21.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o uyvy.frag.qsb uyvy.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o yuyv.frag.qsb yuyv.frag diff --git a/src/qtmultimediaquicktools/shaders_ng/nv12.frag b/src/qtmultimediaquicktools/shaders_ng/nv12.frag new file mode 100644 index 000000000..9ef6bd648 --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/nv12.frag @@ -0,0 +1,25 @@ +#version 440 + +layout(location = 0) in vec2 plane1TexCoord; +layout(location = 1) in vec2 plane2TexCoord; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + mat4 colorMatrix; + float opacity; + float plane1Width; + float plane2Width; + float plane3Width; +} ubuf; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; + +void main() +{ + float Y = texture(plane1Texture, plane1TexCoord).r; + vec2 UV = texture(plane2Texture, plane2TexCoord).rg; + vec4 color = vec4(Y, UV.x, UV.y, 1.); + fragColor = ubuf.colorMatrix * color * ubuf.opacity; +} diff --git a/src/qtmultimediaquicktools/shaders_ng/nv12.frag.qsb b/src/qtmultimediaquicktools/shaders_ng/nv12.frag.qsb Binary files differnew file mode 100644 index 000000000..f3402d460 --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/nv12.frag.qsb diff --git a/src/qtmultimediaquicktools/shaders_ng/nv21.frag b/src/qtmultimediaquicktools/shaders_ng/nv21.frag new file mode 100644 index 000000000..636294048 --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/nv21.frag @@ -0,0 +1,25 @@ +#version 440 + +layout(location = 0) in vec2 plane1TexCoord; +layout(location = 1) in vec2 plane2TexCoord; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + mat4 colorMatrix; + float opacity; + float plane1Width; + float plane2Width; + float plane3Width; +} ubuf; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; + +void main() +{ + float Y = texture(plane1Texture, plane1TexCoord).r; + vec2 UV = texture(plane2Texture, plane2TexCoord).gr; + vec4 color = vec4(Y, UV.x, UV.y, 1.); + fragColor = ubuf.colorMatrix * color * ubuf.opacity; +} diff --git a/src/qtmultimediaquicktools/shaders_ng/nv21.frag.qsb b/src/qtmultimediaquicktools/shaders_ng/nv21.frag.qsb Binary files differnew file mode 100644 index 000000000..b90af8c53 --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/nv21.frag.qsb diff --git a/src/qtmultimediaquicktools/shaders_ng/rgba.frag b/src/qtmultimediaquicktools/shaders_ng/rgba.frag new file mode 100644 index 000000000..1623c2cc7 --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/rgba.frag @@ -0,0 +1,16 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + float opacity; +} ubuf; + +layout(binding = 1) uniform sampler2D rgbTexture; + +void main() +{ + fragColor = texture(rgbTexture, qt_TexCoord) * ubuf.opacity; +} diff --git a/src/qtmultimediaquicktools/shaders_ng/rgba.frag.qsb b/src/qtmultimediaquicktools/shaders_ng/rgba.frag.qsb Binary files differnew file mode 100644 index 000000000..c1ecaa7bf --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/rgba.frag.qsb diff --git a/src/qtmultimediaquicktools/shaders_ng/rgba.vert b/src/qtmultimediaquicktools/shaders_ng/rgba.vert new file mode 100644 index 000000000..ebc53a65f --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/rgba.vert @@ -0,0 +1,18 @@ +#version 440 + +layout(location = 0) in vec4 qt_VertexPosition; +layout(location = 1) in vec2 qt_VertexTexCoord; + +layout(location = 0) out vec2 qt_TexCoord; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + float opacity; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() { + qt_TexCoord = qt_VertexTexCoord; + gl_Position = ubuf.matrix * qt_VertexPosition; +} diff --git a/src/qtmultimediaquicktools/shaders_ng/rgba.vert.qsb b/src/qtmultimediaquicktools/shaders_ng/rgba.vert.qsb Binary files differnew file mode 100644 index 000000000..f655df0db --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/rgba.vert.qsb diff --git a/src/qtmultimediaquicktools/shaders_ng/uyvy.frag b/src/qtmultimediaquicktools/shaders_ng/uyvy.frag new file mode 100644 index 000000000..f1c7c1aec --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/uyvy.frag @@ -0,0 +1,23 @@ +#version 440 + +layout(location = 0) in vec2 plane1TexCoord; +layout(location = 1) in vec2 plane2TexCoord; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + mat4 colorMatrix; + float opacity; + float plane1Width; + float plane2Width; + float plane3Width; +} ubuf; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; + +void main() +{ + vec3 YUV = vec3(texture(plane1Texture, plane1TexCoord).g, texture(plane2Texture, plane2TexCoord).rb); + fragColor = ubuf.colorMatrix * vec4(YUV, 1.0) * ubuf.opacity; +} diff --git a/src/qtmultimediaquicktools/shaders_ng/uyvy.frag.qsb b/src/qtmultimediaquicktools/shaders_ng/uyvy.frag.qsb Binary files differnew file mode 100644 index 000000000..902821fd3 --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/uyvy.frag.qsb diff --git a/src/qtmultimediaquicktools/shaders_ng/yuv.vert b/src/qtmultimediaquicktools/shaders_ng/yuv.vert new file mode 100644 index 000000000..6f103372f --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/yuv.vert @@ -0,0 +1,26 @@ +#version 440 + +layout(location = 0) in vec4 qt_VertexPosition; +layout(location = 1) in vec2 qt_VertexTexCoord; + +layout(location = 0) out vec2 plane1TexCoord; +layout(location = 1) out vec2 plane2TexCoord; +layout(location = 2) out vec2 plane3TexCoord; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + mat4 colorMatrix; + float opacity; + float plane1Width; + float plane2Width; + float plane3Width; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() { + plane1TexCoord = qt_VertexTexCoord * vec2(ubuf.plane1Width, 1); + plane2TexCoord = qt_VertexTexCoord * vec2(ubuf.plane2Width, 1); + plane3TexCoord = qt_VertexTexCoord * vec2(ubuf.plane3Width, 1); + gl_Position = ubuf.matrix * qt_VertexPosition; +} diff --git a/src/qtmultimediaquicktools/shaders_ng/yuv.vert.qsb b/src/qtmultimediaquicktools/shaders_ng/yuv.vert.qsb Binary files differnew file mode 100644 index 000000000..0cde24cf6 --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/yuv.vert.qsb diff --git a/src/qtmultimediaquicktools/shaders_ng/yuv_yv.frag b/src/qtmultimediaquicktools/shaders_ng/yuv_yv.frag new file mode 100644 index 000000000..07ea52aab --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/yuv_yv.frag @@ -0,0 +1,28 @@ +#version 440 + +layout(location = 0) in vec2 plane1TexCoord; +layout(location = 1) in vec2 plane2TexCoord; +layout(location = 2) in vec2 plane3TexCoord; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + mat4 colorMatrix; + float opacity; + float plane1Width; + float plane2Width; + float plane3Width; +} ubuf; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; +layout(binding = 3) uniform sampler2D plane3Texture; + +void main() +{ + float Y = texture(plane1Texture, plane1TexCoord).r; + float U = texture(plane2Texture, plane2TexCoord).r; + float V = texture(plane3Texture, plane3TexCoord).r; + vec4 color = vec4(Y, U, V, 1.); + fragColor = ubuf.colorMatrix * color * ubuf.opacity; +} diff --git a/src/qtmultimediaquicktools/shaders_ng/yuv_yv.frag.qsb b/src/qtmultimediaquicktools/shaders_ng/yuv_yv.frag.qsb Binary files differnew file mode 100644 index 000000000..b6e3fe366 --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/yuv_yv.frag.qsb diff --git a/src/qtmultimediaquicktools/shaders_ng/yuyv.frag b/src/qtmultimediaquicktools/shaders_ng/yuyv.frag new file mode 100644 index 000000000..454fdc21e --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/yuyv.frag @@ -0,0 +1,23 @@ +#version 440 + +layout(location = 0) in vec2 plane1TexCoord; +layout(location = 1) in vec2 plane2TexCoord; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + mat4 colorMatrix; + float opacity; + float plane1Width; + float plane2Width; + float plane3Width; +} ubuf; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; + +void main() +{ + vec3 YUV = vec3(texture(plane1Texture, plane1TexCoord).r, texture(plane2Texture, plane2TexCoord).ga); + fragColor = ubuf.colorMatrix * vec4(YUV, 1.0) * ubuf.opacity; +} diff --git a/src/qtmultimediaquicktools/shaders_ng/yuyv.frag.qsb b/src/qtmultimediaquicktools/shaders_ng/yuyv.frag.qsb Binary files differnew file mode 100644 index 000000000..543361af6 --- /dev/null +++ b/src/qtmultimediaquicktools/shaders_ng/yuyv.frag.qsb |