summaryrefslogtreecommitdiffstats
path: root/src/multimedia/video
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2021-03-26 10:24:57 +0100
committerLars Knoll <lars.knoll@qt.io>2021-04-07 14:51:23 +0000
commit0022bca8f430d7eea7a5f7e39a1cb3719118af2a (patch)
treeec32a61cfa5a1bf69404f124a786633a4c3a4d59 /src/multimedia/video
parentf66c18bc51989ae5388b333c2b2804dd7b6e3f1a (diff)
Move the texture uploading code into Qt Multimedia
Qt Multimedia has now some generic helper functions to upload the video data into textures. This way, we can greatly simplify the rendering code in qtmultimediaquicktools. Change-Id: I5b0e3eb96cbcf79fe5e9757697f11b0183132b17 Reviewed-by: Doris Verria <doris.verria@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/multimedia/video')
-rw-r--r--src/multimedia/video/qvideoframe.cpp3
-rw-r--r--src/multimedia/video/qvideoframe.h5
-rw-r--r--src/multimedia/video/qvideosurfaceformat.cpp245
-rw-r--r--src/multimedia/video/qvideotexturehelper.cpp514
-rw-r--r--src/multimedia/video/qvideotexturehelper_p.h78
5 files changed, 603 insertions, 242 deletions
diff --git a/src/multimedia/video/qvideoframe.cpp b/src/multimedia/video/qvideoframe.cpp
index 2fa5f9f88..a4a985a5f 100644
--- a/src/multimedia/video/qvideoframe.cpp
+++ b/src/multimedia/video/qvideoframe.cpp
@@ -49,6 +49,7 @@
#include <qpair.h>
#include <qsize.h>
#include <qvariant.h>
+#include <private/qrhi_p.h>
#include <QDebug>
@@ -812,7 +813,7 @@ int QVideoFrame::planeCount() const
\internal
Returns a texture id to the video frame's buffers.
*/
-quint64 QVideoFrame::textureHandle(int plane)
+quint64 QVideoFrame::textureHandle(int plane) const
{
return d->buffer->textureHandle(plane);
}
diff --git a/src/multimedia/video/qvideoframe.h b/src/multimedia/video/qvideoframe.h
index ea01ccb92..d2c371c3f 100644
--- a/src/multimedia/video/qvideoframe.h
+++ b/src/multimedia/video/qvideoframe.h
@@ -53,6 +53,9 @@ QT_BEGIN_NAMESPACE
class QSize;
class QVideoFramePrivate;
class QAbstractVideoBuffer;
+class QRhi;
+class QRhiResourceUpdateBatch;
+class QRhiTexture;
class Q_MULTIMEDIA_EXPORT QVideoFrame
{
@@ -113,7 +116,7 @@ public:
int mappedBytes() const;
int planeCount() const;
- quint64 textureHandle(int plane);
+ quint64 textureHandle(int plane) const;
qint64 startTime() const;
void setStartTime(qint64 time);
diff --git a/src/multimedia/video/qvideosurfaceformat.cpp b/src/multimedia/video/qvideosurfaceformat.cpp
index 5271a12db..745fe8b32 100644
--- a/src/multimedia/video/qvideosurfaceformat.cpp
+++ b/src/multimedia/video/qvideosurfaceformat.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qvideosurfaceformat.h"
+#include "qvideotexturehelper_p.h"
#include <qdebug.h>
#include <qlist.h>
@@ -259,49 +260,7 @@ int QVideoSurfaceFormat::frameHeight() const
int QVideoSurfaceFormat::nPlanes() const
{
- switch (d->pixelFormat) {
- case Format_Invalid:
- case Format_ARGB32:
- case Format_ARGB32_Premultiplied:
- case Format_RGB32:
- case Format_RGB24:
- case Format_RGB565:
- case Format_RGB555:
- case Format_ARGB8565_Premultiplied:
- case Format_BGRA32:
- case Format_BGRA32_Premultiplied:
- case Format_ABGR32:
- case Format_BGR32:
- case Format_BGR24:
- case Format_BGR565:
- case Format_BGR555:
- case Format_BGRA5658_Premultiplied:
- case Format_AYUV444:
- case Format_AYUV444_Premultiplied:
- case Format_YUV444:
- case Format_UYVY:
- case Format_YUYV:
- case Format_Y8:
- case Format_Y16:
- case Format_Jpeg:
- return 1;
- case Format_NV12:
- case Format_NV21:
- case Format_IMC2:
- case Format_IMC4:
- case Format_P010LE:
- case Format_P010BE:
- case Format_P016LE:
- case Format_P016BE:
- return 2;
- case Format_YUV420P:
- case Format_YUV422P:
- case Format_YV12:
- case Format_IMC1:
- case Format_IMC3:
- return 3;
- }
- return 0;
+ return QVideoTextureHelper::textureDescription(d->pixelFormat)->nplanes;
}
/*!
@@ -438,211 +397,17 @@ QSize QVideoSurfaceFormat::sizeHint() const
QString QVideoSurfaceFormat::vertexShaderFileName() const
{
- switch (d->pixelFormat) {
- case Format_Invalid:
- case Format_Jpeg:
-
- case Format_RGB24:
- case Format_RGB565:
- case Format_RGB555:
- case Format_ARGB8565_Premultiplied:
- case Format_BGR24:
- case Format_BGR565:
- case Format_BGR555:
- case Format_BGRA5658_Premultiplied:
-
- case Format_Y8:
- case Format_Y16:
-
- case Format_AYUV444:
- case Format_AYUV444_Premultiplied:
- case Format_YUV444:
-
- case Format_IMC1:
- case Format_IMC2:
- case Format_IMC3:
- case Format_IMC4:
- return QString();
- case Format_ARGB32:
- case Format_ARGB32_Premultiplied:
- case Format_RGB32:
- case Format_BGRA32:
- case Format_BGRA32_Premultiplied:
- case Format_ABGR32:
- case Format_BGR32:
- return QStringLiteral(":/qtmultimedia/shaders/rgba.vert.qsb");
- case Format_YUV420P:
- case Format_YUV422P:
- case Format_YV12:
- case Format_UYVY:
- case Format_YUYV:
- case Format_NV12:
- case Format_NV21:
- case Format_P010LE:
- case Format_P010BE:
- case Format_P016LE:
- case Format_P016BE:
- return QStringLiteral(":/qtmultimedia/shaders/yuv.vert.qsb");
- }
+ return QVideoTextureHelper::vertexShaderFileName(d->pixelFormat);
}
QString QVideoSurfaceFormat::fragmentShaderFileName() const
{
- switch (d->pixelFormat) {
- case Format_Invalid:
- case Format_Jpeg:
-
- case Format_RGB24:
- case Format_RGB565:
- case Format_RGB555:
- case Format_ARGB8565_Premultiplied:
- case Format_BGR24:
- case Format_BGR565:
- case Format_BGR555:
- case Format_BGRA5658_Premultiplied:
-
- case Format_Y8:
- case Format_Y16:
-
- case Format_AYUV444:
- case Format_AYUV444_Premultiplied:
- case Format_YUV444:
-
- case Format_IMC1:
- case Format_IMC2:
- case Format_IMC3:
- case Format_IMC4:
- return QString();
- case Format_ARGB32:
- case Format_ARGB32_Premultiplied:
- case Format_RGB32:
- case Format_BGRA32:
- case Format_BGRA32_Premultiplied:
- case Format_ABGR32:
- case Format_BGR32:
- return QStringLiteral(":/qtmultimedia/shaders/rgba.frag.qsb");
- case Format_YUV420P:
- case Format_YUV422P:
- case Format_YV12:
- return QStringLiteral(":/qtmultimedia/shaders/yuv_yv.frag.qsb");
- case Format_UYVY:
- return QStringLiteral(":/qtmultimedia/shaders/uyvy.frag.qsb");
- case Format_YUYV:
- return QStringLiteral(":/qtmultimedia/shaders/yuyv.frag.qsb");
- case Format_NV12:
- return QStringLiteral(":/qtmultimedia/shaders/nv12.frag.qsb");
- case Format_NV21:
- return QStringLiteral(":/qtmultimedia/shaders/nv21.frag.qsb");
- case Format_P010LE:
- case Format_P016LE:
- return QStringLiteral(":/qtmultimedia/shaders/p010le.frag.qsb");
- case Format_P010BE:
- case Format_P016BE:
- return QStringLiteral(":/qtmultimedia/shaders/p010be.frag.qsb");
- }
-}
-
-static QMatrix4x4 colorMatrix(QVideoSurfaceFormat::YCbCrColorSpace colorSpace)
-{
- switch (colorSpace) {
- case QVideoSurfaceFormat::YCbCr_JPEG:
- return QMatrix4x4(
- 1.0f, 0.000f, 1.402f, -0.701f,
- 1.0f, -0.344f, -0.714f, 0.529f,
- 1.0f, 1.772f, 0.000f, -0.886f,
- 0.0f, 0.000f, 0.000f, 1.0000f);
- case QVideoSurfaceFormat::YCbCr_BT709:
- case QVideoSurfaceFormat::YCbCr_xvYCC709:
- return QMatrix4x4(
- 1.164f, 0.000f, 1.793f, -0.5727f,
- 1.164f, -0.534f, -0.213f, 0.3007f,
- 1.164f, 2.115f, 0.000f, -1.1302f,
- 0.0f, 0.000f, 0.000f, 1.0000f);
- default: //BT 601:
- return QMatrix4x4(
- 1.164f, 0.000f, 1.596f, -0.8708f,
- 1.164f, -0.392f, -0.813f, 0.5296f,
- 1.164f, 2.017f, 0.000f, -1.081f,
- 0.0f, 0.000f, 0.000f, 1.0000f);
- }
+ return QVideoTextureHelper::fragmentShaderFileName(d->pixelFormat);
}
QByteArray QVideoSurfaceFormat::uniformData(const QMatrix4x4 &transform, float opacity) const
{
- static constexpr float pw[3] = {};
- const float *planeWidth = pw;
-
- switch (d->pixelFormat) {
- case Format_Invalid:
- case Format_Jpeg:
-
- case Format_RGB24:
- case Format_RGB565:
- case Format_RGB555:
- case Format_ARGB8565_Premultiplied:
- case Format_BGR24:
- case Format_BGR565:
- case Format_BGR555:
- case Format_BGRA5658_Premultiplied:
-
- case Format_Y8:
- case Format_Y16:
-
- case Format_AYUV444:
- case Format_AYUV444_Premultiplied:
- case Format_YUV444:
-
- case Format_IMC1:
- case Format_IMC2:
- case Format_IMC3:
- case Format_IMC4:
- return QByteArray();
- case Format_ARGB32:
- case Format_ARGB32_Premultiplied:
- case Format_RGB32:
- case Format_BGRA32:
- case Format_BGRA32_Premultiplied:
- case Format_ABGR32:
- case Format_BGR32: {
- // { matrix4x4, opacity }
- QByteArray buf(16*4 + 4, Qt::Uninitialized);
- char *data = buf.data();
- memcpy(data, transform.constData(), 64);
- memcpy(data + 64, &opacity, 4);
- return buf;
- }
- case Format_YUV420P:
- case Format_YUV422P:
- case Format_YV12: {
- static constexpr float pw[] = { 1, 1, 1 };
- planeWidth = pw;
- break;
- }
- case Format_UYVY:
- case Format_YUYV: {
- static constexpr float pw[] = { 1, 1, 0 };
- planeWidth = pw;
- break;
- }
- case Format_NV12:
- case Format_NV21:
- case Format_P010LE:
- case Format_P010BE:
- case Format_P016LE:
- case Format_P016BE: {
- static constexpr float pw[] = { 1, 1, 0 };
- planeWidth = pw;
- break;
- }
- }
- // { matrix4x4, colorMatrix, opacity, planeWidth[3] }
- QByteArray buf(64*2 + 4 + 3*4, Qt::Uninitialized);
- char *data = buf.data();
- memcpy(data, transform.constData(), 64);
- memcpy(data + 64, colorMatrix(d->ycbcrColorSpace).constData(), 64);
- memcpy(data + 64 + 64, &opacity, 4);
- memcpy(data + 64 + 64 + 4, planeWidth, 3*4);
- return buf;
+ return QVideoTextureHelper::uniformData(*this, transform, opacity);
}
diff --git a/src/multimedia/video/qvideotexturehelper.cpp b/src/multimedia/video/qvideotexturehelper.cpp
new file mode 100644
index 000000000..930456d7d
--- /dev/null
+++ b/src/multimedia/video/qvideotexturehelper.cpp
@@ -0,0 +1,514 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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 "qvideotexturehelper_p.h"
+#include "qvideoframe.h"
+
+namespace QVideoTextureHelper
+{
+
+static const TextureDescription descriptions[QVideoSurfaceFormat::NPixelFormats] = {
+ // Format_Invalid
+ { 0,
+ { QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat},
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_ARGB32
+ { 1,
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_ARGB32_Premultiplied
+ { 1,
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_RGB32
+ { 1,
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_RGB24
+ { 1,
+ { QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_RGB565
+ { 1,
+ { QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_RGB555
+ { 1,
+ { QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_ARGB8565_Premultiplied
+ { 1,
+ { QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_BGRA32
+ { 1,
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_BGRA32_Premultiplied
+ { 1,
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_ABGR32
+ { 1,
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_BGR32
+ { 1,
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_BGR24
+ { 1,
+ { QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_BGR565
+ { 1,
+ { QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_BGR555
+ { 1,
+ { QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_BGRA5658_Premultiplied
+ { 1,
+ { QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+
+ // Format_AYUV444
+ { 1,
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_AYUV444_Premultiplied
+ { 1,
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_YUV444
+ { 1,
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_YUV420P
+ { 3,
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::R8 },
+ { { 1, 1 }, { 2, 2 }, { 2, 2 } }
+ },
+ // Format_YUV422P
+ { 3,
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::R8 },
+ { { 1, 1 }, { 2, 1 }, { 2, 1 } }
+ },
+ // Format_YV12
+ { 3,
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::R8 },
+ { { 1, 1 }, { 2, 2 }, { 2, 2 } }
+ },
+ // Format_UYVY
+ { 1,
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_YUYV
+ { 1,
+ { QRhiTexture::BGRA8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_NV12
+ { 2,
+ { QRhiTexture::RG8, QRhiTexture::R8, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 2, 2 }, { 1, 1 } }
+ },
+ // Format_NV21
+ { 2,
+ { QRhiTexture::RG8, QRhiTexture::R8, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 2, 2 }, { 1, 1 } }
+ },
+ // Format_IMC1
+ { 3,
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::R8 },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_IMC2
+ { 2,
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_IMC3
+ { 3,
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::R8 },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_IMC4
+ { 2,
+ { QRhiTexture::R8, QRhiTexture::R8, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_Y8
+ { 1,
+ { QRhiTexture::R8, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+ // Format_Y16
+ { 1,
+ { QRhiTexture::R16, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ },
+
+ // Format_P010LE
+ { 2,
+ { QRhiTexture::RG8, QRhiTexture::BGRA8, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 2, 2 }, { 1, 1 } }
+ },
+ // Format_P010BE
+ { 2,
+ { QRhiTexture::RG8, QRhiTexture::BGRA8, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 2, 2 }, { 1, 1 } }
+ },
+ // Format_P016LE
+ { 2,
+ { QRhiTexture::RG8, QRhiTexture::BGRA8, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 2, 2 }, { 1, 1 } }
+ },
+ // Format_P016BE
+ { 2,
+ { QRhiTexture::RG8, QRhiTexture::BGRA8, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 2, 2 }, { 1, 1 } }
+ },
+
+ // Format_Jpeg
+ { 1,
+ { QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat, QRhiTexture::UnknownFormat },
+ { { 1, 1 }, { 1, 1 }, { 1, 1 } }
+ }
+};
+
+
+const TextureDescription *textureDescription(QVideoSurfaceFormat::PixelFormat format)
+{
+ return descriptions + format;
+}
+
+QString vertexShaderFileName(QVideoSurfaceFormat::PixelFormat format)
+{
+ switch (format) {
+ case QVideoSurfaceFormat::Format_Invalid:
+ case QVideoSurfaceFormat::Format_Jpeg:
+
+ case QVideoSurfaceFormat::Format_RGB24:
+ case QVideoSurfaceFormat::Format_RGB565:
+ case QVideoSurfaceFormat::Format_RGB555:
+ case QVideoSurfaceFormat::Format_ARGB8565_Premultiplied:
+ case QVideoSurfaceFormat::Format_BGR24:
+ case QVideoSurfaceFormat::Format_BGR565:
+ case QVideoSurfaceFormat::Format_BGR555:
+ case QVideoSurfaceFormat::Format_BGRA5658_Premultiplied:
+
+ case QVideoSurfaceFormat::Format_Y8:
+ case QVideoSurfaceFormat::Format_Y16:
+
+ case QVideoSurfaceFormat::Format_YUV444:
+
+ case QVideoSurfaceFormat::Format_IMC1:
+ case QVideoSurfaceFormat::Format_IMC2:
+ case QVideoSurfaceFormat::Format_IMC3:
+ case QVideoSurfaceFormat::Format_IMC4:
+ return QString();
+ case QVideoSurfaceFormat::Format_AYUV444:
+ case QVideoSurfaceFormat::Format_AYUV444_Premultiplied:
+ return QStringLiteral(":/qtmultimedia/shaders/yuv.vert.qsb");
+ case QVideoSurfaceFormat::Format_ARGB32:
+ case QVideoSurfaceFormat::Format_ARGB32_Premultiplied:
+ case QVideoSurfaceFormat::Format_RGB32:
+ case QVideoSurfaceFormat::Format_BGRA32:
+ case QVideoSurfaceFormat::Format_BGRA32_Premultiplied:
+ case QVideoSurfaceFormat::Format_ABGR32:
+ case QVideoSurfaceFormat::Format_BGR32:
+ return QStringLiteral(":/qtmultimedia/shaders/rgba.vert.qsb");
+ case QVideoSurfaceFormat::Format_YUV420P:
+ case QVideoSurfaceFormat::Format_YUV422P:
+ case QVideoSurfaceFormat::Format_YV12:
+ case QVideoSurfaceFormat::Format_UYVY:
+ case QVideoSurfaceFormat::Format_YUYV:
+ case QVideoSurfaceFormat::Format_NV12:
+ case QVideoSurfaceFormat::Format_NV21:
+ case QVideoSurfaceFormat::Format_P010LE:
+ case QVideoSurfaceFormat::Format_P010BE:
+ case QVideoSurfaceFormat::Format_P016LE:
+ case QVideoSurfaceFormat::Format_P016BE:
+ return QStringLiteral(":/qtmultimedia/shaders/yuv.vert.qsb");
+ }
+}
+
+QString fragmentShaderFileName(QVideoSurfaceFormat::PixelFormat format)
+{
+ switch (format) {
+ case QVideoSurfaceFormat::Format_Invalid:
+ case QVideoSurfaceFormat::Format_Jpeg:
+
+ case QVideoSurfaceFormat::Format_RGB24:
+ case QVideoSurfaceFormat::Format_RGB565:
+ case QVideoSurfaceFormat::Format_RGB555:
+ case QVideoSurfaceFormat::Format_ARGB8565_Premultiplied:
+ case QVideoSurfaceFormat::Format_BGR24:
+ case QVideoSurfaceFormat::Format_BGR565:
+ case QVideoSurfaceFormat::Format_BGR555:
+ case QVideoSurfaceFormat::Format_BGRA5658_Premultiplied:
+
+ case QVideoSurfaceFormat::Format_Y8:
+ case QVideoSurfaceFormat::Format_Y16:
+
+ case QVideoSurfaceFormat::Format_YUV444:
+
+ case QVideoSurfaceFormat::Format_IMC1:
+ case QVideoSurfaceFormat::Format_IMC2:
+ case QVideoSurfaceFormat::Format_IMC3:
+ case QVideoSurfaceFormat::Format_IMC4:
+ return QString();
+ case QVideoSurfaceFormat::Format_AYUV444:
+ case QVideoSurfaceFormat::Format_AYUV444_Premultiplied:
+ return QStringLiteral(":/qtmultimedia/shaders/ayuv.frag.qsb");
+ case QVideoSurfaceFormat::Format_ARGB32:
+ case QVideoSurfaceFormat::Format_ARGB32_Premultiplied:
+ case QVideoSurfaceFormat::Format_RGB32:
+ case QVideoSurfaceFormat::Format_BGRA32:
+ case QVideoSurfaceFormat::Format_BGRA32_Premultiplied:
+ case QVideoSurfaceFormat::Format_ABGR32:
+ case QVideoSurfaceFormat::Format_BGR32:
+ return QStringLiteral(":/qtmultimedia/shaders/rgba.frag.qsb");
+ case QVideoSurfaceFormat::Format_YUV420P:
+ case QVideoSurfaceFormat::Format_YUV422P:
+ case QVideoSurfaceFormat::Format_YV12:
+ return QStringLiteral(":/qtmultimedia/shaders/yuv_yv.frag.qsb");
+ case QVideoSurfaceFormat::Format_UYVY:
+ return QStringLiteral(":/qtmultimedia/shaders/uyvy.frag.qsb");
+ case QVideoSurfaceFormat::Format_YUYV:
+ return QStringLiteral(":/qtmultimedia/shaders/yuyv.frag.qsb");
+ case QVideoSurfaceFormat::Format_NV12:
+ return QStringLiteral(":/qtmultimedia/shaders/nv12.frag.qsb");
+ case QVideoSurfaceFormat::Format_NV21:
+ return QStringLiteral(":/qtmultimedia/shaders/nv21.frag.qsb");
+ case QVideoSurfaceFormat::Format_P010LE:
+ case QVideoSurfaceFormat::Format_P016LE:
+ return QStringLiteral(":/qtmultimedia/shaders/p010le.frag.qsb");
+ case QVideoSurfaceFormat::Format_P010BE:
+ case QVideoSurfaceFormat::Format_P016BE:
+ return QStringLiteral(":/qtmultimedia/shaders/p010be.frag.qsb");
+ }
+}
+
+
+static QMatrix4x4 colorMatrix(QVideoSurfaceFormat::YCbCrColorSpace colorSpace)
+{
+ switch (colorSpace) {
+ case QVideoSurfaceFormat::YCbCr_JPEG:
+ return QMatrix4x4(
+ 1.0f, 0.000f, 1.402f, -0.701f,
+ 1.0f, -0.344f, -0.714f, 0.529f,
+ 1.0f, 1.772f, 0.000f, -0.886f,
+ 0.0f, 0.000f, 0.000f, 1.0000f);
+ case QVideoSurfaceFormat::YCbCr_BT709:
+ case QVideoSurfaceFormat::YCbCr_xvYCC709:
+ return QMatrix4x4(
+ 1.164f, 0.000f, 1.793f, -0.5727f,
+ 1.164f, -0.534f, -0.213f, 0.3007f,
+ 1.164f, 2.115f, 0.000f, -1.1302f,
+ 0.0f, 0.000f, 0.000f, 1.0000f);
+ default: //BT 601:
+ return QMatrix4x4(
+ 1.164f, 0.000f, 1.596f, -0.8708f,
+ 1.164f, -0.392f, -0.813f, 0.5296f,
+ 1.164f, 2.017f, 0.000f, -1.081f,
+ 0.0f, 0.000f, 0.000f, 1.0000f);
+ }
+}
+
+QByteArray uniformData(const QVideoSurfaceFormat &format, const QMatrix4x4 &transform, float opacity)
+{
+ static constexpr float pw[3] = {};
+ const float *planeWidth = pw;
+
+ switch (format.pixelFormat()) {
+ case QVideoSurfaceFormat::Format_Invalid:
+ case QVideoSurfaceFormat::Format_Jpeg:
+
+ case QVideoSurfaceFormat::Format_RGB24:
+ case QVideoSurfaceFormat::Format_RGB565:
+ case QVideoSurfaceFormat::Format_RGB555:
+ case QVideoSurfaceFormat::Format_ARGB8565_Premultiplied:
+ case QVideoSurfaceFormat::Format_BGR24:
+ case QVideoSurfaceFormat::Format_BGR565:
+ case QVideoSurfaceFormat::Format_BGR555:
+ case QVideoSurfaceFormat::Format_BGRA5658_Premultiplied:
+
+ case QVideoSurfaceFormat::Format_Y8:
+ case QVideoSurfaceFormat::Format_Y16:
+
+ case QVideoSurfaceFormat::Format_YUV444:
+
+ case QVideoSurfaceFormat::Format_IMC1:
+ case QVideoSurfaceFormat::Format_IMC2:
+ case QVideoSurfaceFormat::Format_IMC3:
+ case QVideoSurfaceFormat::Format_IMC4:
+ return QByteArray();
+ case QVideoSurfaceFormat::Format_ARGB32:
+ case QVideoSurfaceFormat::Format_ARGB32_Premultiplied:
+ case QVideoSurfaceFormat::Format_RGB32:
+ case QVideoSurfaceFormat::Format_BGRA32:
+ case QVideoSurfaceFormat::Format_BGRA32_Premultiplied:
+ case QVideoSurfaceFormat::Format_ABGR32:
+ case QVideoSurfaceFormat::Format_BGR32: {
+ // { matrix4x4, opacity }
+ QByteArray buf(16*4 + 4, Qt::Uninitialized);
+ char *data = buf.data();
+ memcpy(data, transform.constData(), 64);
+ memcpy(data + 64, &opacity, 4);
+ return buf;
+ }
+ case QVideoSurfaceFormat::Format_AYUV444:
+ case QVideoSurfaceFormat::Format_AYUV444_Premultiplied: {
+ static constexpr float pw[] = { 1, 0, 0 };
+ planeWidth = pw;
+ break;
+ }
+ case QVideoSurfaceFormat::Format_YUV420P:
+ case QVideoSurfaceFormat::Format_YUV422P:
+ case QVideoSurfaceFormat::Format_YV12: {
+ static constexpr float pw[] = { 1, 1, 1 };
+ planeWidth = pw;
+ break;
+ }
+ case QVideoSurfaceFormat::Format_UYVY:
+ case QVideoSurfaceFormat::Format_YUYV: {
+ static constexpr float pw[] = { 1, 1, 0 };
+ planeWidth = pw;
+ break;
+ }
+ case QVideoSurfaceFormat::Format_NV12:
+ case QVideoSurfaceFormat::Format_NV21:
+ case QVideoSurfaceFormat::Format_P010LE:
+ case QVideoSurfaceFormat::Format_P010BE:
+ case QVideoSurfaceFormat::Format_P016LE:
+ case QVideoSurfaceFormat::Format_P016BE: {
+ static constexpr float pw[] = { 1, 1, 0 };
+ planeWidth = pw;
+ break;
+ }
+ }
+ // { matrix4x4, colorMatrix, opacity, planeWidth[3] }
+ QByteArray buf(64*2 + 4 + 3*4, Qt::Uninitialized);
+ char *data = buf.data();
+ memcpy(data, transform.constData(), 64);
+ memcpy(data + 64, colorMatrix(format.yCbCrColorSpace()).constData(), 64);
+ memcpy(data + 64 + 64, &opacity, 4);
+ memcpy(data + 64 + 64 + 4, planeWidth, 3*4);
+ return buf;
+}
+
+int updateRhiTextures(QVideoFrame frame, QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates, QRhiTexture **textures)
+{
+ QVideoSurfaceFormat fmt = frame.surfaceFormat();
+ QVideoSurfaceFormat::PixelFormat pixelFormat = fmt.pixelFormat();
+ QSize size = fmt.frameSize();
+
+ const TextureDescription *description = descriptions + pixelFormat;
+
+ QSize planeSizes[TextureDescription::maxPlanes];
+ for (int plane = 0; plane < description->nplanes; ++plane)
+ planeSizes[plane] = QSize(size.width()/description->sizeScale[plane].x, size.height()/description->sizeScale[plane].y);
+
+ if (frame.handleType() == QVideoFrame::RhiTextureHandle) {
+ for (int plane = 0; plane < description->nplanes; ++plane) {
+ quint64 nativeTexture = frame.textureHandle(plane);
+ Q_ASSERT(nativeTexture);
+ textures[plane] = rhi->newTexture(description->textureFormat[plane], planeSizes[plane], 1, {});
+ textures[plane]->createFrom({nativeTexture, 0});
+ }
+ return description->nplanes;
+ }
+
+ // need to upload textures
+ bool mapped = frame.map(QVideoFrame::ReadOnly);
+ if (!mapped) {
+ qWarning() << "could not map data of QVideoFrame for upload";
+ return 0;
+ }
+
+ Q_ASSERT(frame.planeCount() == description->nplanes);
+ for (int plane = 0; plane < description->nplanes; ++plane) {
+
+ bool needsRebuild = !textures[plane] || textures[plane]->pixelSize() != planeSizes[plane];
+ if (!textures[plane])
+ textures[plane] = rhi->newTexture(description->textureFormat[plane], planeSizes[plane], 1, {});
+
+ if (needsRebuild) {
+ textures[plane]->setPixelSize(planeSizes[plane]);
+ bool created = textures[plane]->create();
+ if (!created) {
+ qWarning("Failed to create texture (size %dx%d)", planeSizes[plane].width(), planeSizes[plane].height());
+ return 0;
+ }
+ }
+
+ QRhiTextureSubresourceUploadDescription subresDesc(frame.bits(plane), frame.bytesPerLine(plane)*planeSizes[plane].height());
+ subresDesc.setSourceSize(planeSizes[plane]);
+ subresDesc.setDestinationTopLeft(QPoint(0, 0));
+ QRhiTextureUploadEntry entry(0, 0, subresDesc);
+ QRhiTextureUploadDescription desc({ entry });
+ resourceUpdates->uploadTexture(textures[plane], desc);
+ }
+ return description->nplanes;
+}
+
+}
diff --git a/src/multimedia/video/qvideotexturehelper_p.h b/src/multimedia/video/qvideotexturehelper_p.h
new file mode 100644
index 000000000..4b369594a
--- /dev/null
+++ b/src/multimedia/video/qvideotexturehelper_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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 QVIDEOTEXTUREHELPER_H
+#define QVIDEOTEXTUREHELPER_H
+
+#include <qvideosurfaceformat.h>
+#include <private/qrhi_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVideoFrame;
+
+namespace QVideoTextureHelper
+{
+
+struct TextureDescription
+{
+ static constexpr int maxPlanes = 3;
+ struct SizeScale {
+ int x;
+ int y;
+ };
+
+ int nplanes;
+ QRhiTexture::Format textureFormat[maxPlanes];
+ SizeScale sizeScale[maxPlanes];
+};
+
+Q_MULTIMEDIA_EXPORT const TextureDescription *textureDescription(QVideoSurfaceFormat::PixelFormat format);
+
+Q_MULTIMEDIA_EXPORT QString vertexShaderFileName(QVideoSurfaceFormat::PixelFormat format);
+Q_MULTIMEDIA_EXPORT QString fragmentShaderFileName(QVideoSurfaceFormat::PixelFormat format);
+Q_MULTIMEDIA_EXPORT QByteArray uniformData(const QVideoSurfaceFormat &format, const QMatrix4x4 &transform, float opacity);
+Q_MULTIMEDIA_EXPORT int updateRhiTextures(QVideoFrame frame, QRhi *rhi,
+ QRhiResourceUpdateBatch *resourceUpdates, QRhiTexture **textures);
+
+}
+
+QT_END_NAMESPACE
+
+#endif