diff options
Diffstat (limited to 'src/multimedia')
-rw-r--r-- | src/multimedia/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/multimedia/video/qvideoframe.cpp | 3 | ||||
-rw-r--r-- | src/multimedia/video/qvideoframe.h | 5 | ||||
-rw-r--r-- | src/multimedia/video/qvideosurfaceformat.cpp | 245 | ||||
-rw-r--r-- | src/multimedia/video/qvideotexturehelper.cpp | 514 | ||||
-rw-r--r-- | src/multimedia/video/qvideotexturehelper_p.h | 78 |
6 files changed, 604 insertions, 242 deletions
diff --git a/src/multimedia/CMakeLists.txt b/src/multimedia/CMakeLists.txt index ce8f44f61..8a1010188 100644 --- a/src/multimedia/CMakeLists.txt +++ b/src/multimedia/CMakeLists.txt @@ -65,6 +65,7 @@ qt_internal_add_module(Multimedia video/qmemoryvideobuffer.cpp video/qmemoryvideobuffer_p.h video/qvideoframe.cpp video/qvideoframe.h video/qvideosink.cpp video/qvideosink.h + video/qvideotexturehelper.cpp video/qvideotexturehelper_p.h video/qvideoframeconversionhelper.cpp video/qvideoframeconversionhelper_p.h video/qvideooutputorientationhandler.cpp video/qvideooutputorientationhandler_p.h video/qvideosurfaceformat.cpp video/qvideosurfaceformat.h 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 |