// Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QVIDEOTEXTUREHELPER_H #define QVIDEOTEXTUREHELPER_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 #include #include QT_BEGIN_NAMESPACE class QVideoFrame; class QTextLayout; class QVideoFrameTextures; using QVideoFrameTexturesUPtr = std::unique_ptr; class QVideoFrameTexturesHandles; using QVideoFrameTexturesHandlesUPtr = std::unique_ptr; namespace QVideoTextureHelper { struct Q_MULTIMEDIA_EXPORT TextureDescription { static constexpr int maxPlanes = 3; struct SizeScale { int x; int y; }; using BytesRequired = int(*)(int stride, int height); enum TextureFormat { UnknownFormat, Red_8, RG_8, RGBA_8, BGRA_8, Red_16, RG_16, }; QRhiTexture::Format rhiTextureFormat(int plane, QRhi *rhi) const; inline int strideForWidth(int width) const { return (width*strideFactor + 15) & ~15; } inline int bytesForSize(QSize s) const { return bytesRequired(strideForWidth(s.width()), s.height()); } int widthForPlane(int width, int plane) const { if (plane > nplanes) return 0; return (width + sizeScale[plane].x - 1)/sizeScale[plane].x; } int heightForPlane(int height, int plane) const { if (plane > nplanes) return 0; return (height + sizeScale[plane].y - 1)/sizeScale[plane].y; } /** * \returns Plane scaling factors taking into account possible workarounds due to QRhi backend * capabilities. */ SizeScale rhiSizeScale(int plane, QRhi *rhi) const { if (!rhi) return sizeScale[plane]; // NOTE: We need to handle sizing difference when packing two-component textures to RGBA8, // where width gets cut in half. // Another option would be to compare QRhiImplementation::TextureFormatInfo to expected // based on TextureDescription::Format. if ((textureFormat[plane] == TextureDescription::RG_8 || textureFormat[plane] == TextureDescription::Red_16) && rhiTextureFormat(plane, rhi) == QRhiTexture::RGBA8) return { sizeScale[plane].x * 2, sizeScale[plane].y }; return sizeScale[plane]; } QSize rhiPlaneSize(QSize frameSize, int plane, QRhi *rhi) const { SizeScale scale = rhiSizeScale(plane, rhi); return QSize(frameSize.width() / scale.x, frameSize.height() / scale.y); } bool hasTextureFormat(TextureFormat format) const { return std::any_of(textureFormat, textureFormat + nplanes, [format](TextureFormat f) { return f == format; }); } int nplanes; int strideFactor; BytesRequired bytesRequired; TextureFormat textureFormat[maxPlanes]; SizeScale sizeScale[maxPlanes]; }; Q_MULTIMEDIA_EXPORT const TextureDescription *textureDescription(QVideoFrameFormat::PixelFormat format); Q_MULTIMEDIA_EXPORT QString vertexShaderFileName(const QVideoFrameFormat &format); Q_MULTIMEDIA_EXPORT QString fragmentShaderFileName(const QVideoFrameFormat &format, QRhi *rhi, QRhiSwapChain::Format surfaceFormat = QRhiSwapChain::SDR); Q_MULTIMEDIA_EXPORT void updateUniformData(QByteArray *dst, QRhi *rhi, const QVideoFrameFormat &format, const QVideoFrame &frame, const QMatrix4x4 &transform, float opacity, float maxNits = 100); /** * @brief Creates plane textures from texture handles set by the specified rhi. * The result owns the specified handles set; the QRhiTexture(s), exposed by the result * refer to the owned handles set. * If the specified size is empty or pixelFormat is invalid, null is returned. */ Q_MULTIMEDIA_EXPORT QVideoFrameTexturesUPtr createTexturesFromHandles(QVideoFrameTexturesHandlesUPtr handles, QRhi &rhi, QVideoFrameFormat::PixelFormat pixelFormat, QSize size); /** * @brief Creates plane textures from a video frame by the specified rhi. If possible, the function modifies 'oldTextures', which is the texture from the pool, and returns the specified one or a new one with any taken data. */ Q_MULTIMEDIA_EXPORT QVideoFrameTexturesUPtr createTextures(const QVideoFrame &frame, QRhi &rhi, QRhiResourceUpdateBatch &rub, QVideoFrameTexturesUPtr oldTextures); /** * @brief Returns a QRhiTexture::Format taking into account rhi capabilities and explicitly excluded * formats using a chain of pre-defined fallback texture formats. If no valid fallback is * determined, will return the format argument. */ Q_MULTIMEDIA_EXPORT QRhiTexture::Format resolvedRhiTextureFormat(QRhiTexture::Format format, QRhi *rhi); Q_MULTIMEDIA_EXPORT void setExcludedRhiTextureFormats(QList formats); // for tests only struct UniformData { float transformMatrix[4][4]; float colorMatrix[4][4]; float opacity; float width; float masteringWhite; float maxLum; int redOrAlphaIndex; int planeFormats[TextureDescription::maxPlanes]; }; struct Q_MULTIMEDIA_EXPORT SubtitleLayout { QSize videoSize; QRectF bounds; QTextLayout layout; bool update(const QSize &frameSize, QString text); void draw(QPainter *painter, const QPointF &translate) const; QImage toImage() const; }; } QT_END_NAMESPACE #endif