diff options
author | Pavel Dubsky <pavel.dubsky@qt.io> | 2024-04-11 13:55:32 +0200 |
---|---|---|
committer | Pavel Dubsky <pavel.dubsky@qt.io> | 2024-04-17 12:56:53 +0200 |
commit | 38c85f0fb274f9dd989bd7601791209589fab94a (patch) | |
tree | d2c2765878790c5f3c6cdad13350cae304bbee66 | |
parent | f1e64525961e56424651b44c34355518e80af537 (diff) |
Enable HDR based on video frame format for QtWidgets
Currently swap chain is configured for SDR or HDR only on creation and
there is no support for dynamic change when video is played using
QVideoWindow. This change adds check that determines whether video frame
contains SDR or HDR content and reconfigures swap chain (and
subsequently shaders) if needed.
Fixes: QTBUG-120963
Pick-to: 6.7 6.6 6.5
Change-Id: I8eef9b46b3999e00427cc50f82486cea7cd80e09
Reviewed-by: Artem Dyomin <artem.dyomin@qt.io>
-rw-r--r-- | src/multimedia/qmultimediautils.cpp | 27 | ||||
-rw-r--r-- | src/multimedia/qmultimediautils_p.h | 12 | ||||
-rw-r--r-- | src/multimedia/video/qvideowindow.cpp | 11 | ||||
-rw-r--r-- | tests/auto/unit/multimedia/qmultimediautils/tst_qmultimediautils.cpp | 71 |
4 files changed, 119 insertions, 2 deletions
diff --git a/src/multimedia/qmultimediautils.cpp b/src/multimedia/qmultimediautils.cpp index b08875592..9740b6d60 100644 --- a/src/multimedia/qmultimediautils.cpp +++ b/src/multimedia/qmultimediautils.cpp @@ -3,6 +3,7 @@ #include "qmultimediautils_p.h" #include "qvideoframe.h" +#include "qvideoframeformat.h" #include <QtCore/qdir.h> @@ -70,4 +71,30 @@ QUrl qMediaFromUserInput(QUrl url) return url; } +bool qIsAutoHdrEnabled() +{ + static const bool autoHdrEnabled = qEnvironmentVariableIntValue("QT_MEDIA_AUTO_HDR"); + + return autoHdrEnabled; +} + +QRhiSwapChain::Format qGetRequiredSwapChainFormat(const QVideoFrameFormat &format) +{ + constexpr auto sdrMaxLuminance = 100.0f; + const auto formatMaxLuminance = format.maxLuminance(); + + return formatMaxLuminance > sdrMaxLuminance ? QRhiSwapChain::HDRExtendedSrgbLinear + : QRhiSwapChain::SDR; +} + +bool qShouldUpdateSwapChainFormat(QRhiSwapChain *swapChain, + QRhiSwapChain::Format requiredSwapChainFormat) +{ + if (!swapChain) + return false; + + return qIsAutoHdrEnabled() && swapChain->format() != requiredSwapChainFormat + && swapChain->isFormatSupported(requiredSwapChainFormat); +} + QT_END_NAMESPACE diff --git a/src/multimedia/qmultimediautils_p.h b/src/multimedia/qmultimediautils_p.h index d95bb9e4b..a5d60e066 100644 --- a/src/multimedia/qmultimediautils_p.h +++ b/src/multimedia/qmultimediautils_p.h @@ -20,10 +20,13 @@ #include <QtMultimedia/private/qmaybe_p.h> #include <QtCore/qsize.h> #include <QtCore/qurl.h> +#include <QtGui/rhi/qrhi.h> QT_BEGIN_NAMESPACE +class QRhiSwapChain; class QVideoFrame; +class QVideoFrameFormat; struct Fraction { int numerator; @@ -47,6 +50,15 @@ Q_MULTIMEDIA_EXPORT QSize qRotatedFrameSize(const QVideoFrame &frame); Q_MULTIMEDIA_EXPORT QUrl qMediaFromUserInput(QUrl fileName); +Q_MULTIMEDIA_EXPORT bool qIsAutoHdrEnabled(); + +Q_MULTIMEDIA_EXPORT QRhiSwapChain::Format +qGetRequiredSwapChainFormat(const QVideoFrameFormat &format); + +Q_MULTIMEDIA_EXPORT bool +qShouldUpdateSwapChainFormat(QRhiSwapChain *swapChain, + QRhiSwapChain::Format requiredSwapChainFormat); + QT_END_NAMESPACE #endif // QMULTIMEDIAUTILS_P_H diff --git a/src/multimedia/video/qvideowindow.cpp b/src/multimedia/video/qvideowindow.cpp index c5afdaa7d..9cab23f5f 100644 --- a/src/multimedia/video/qvideowindow.cpp +++ b/src/multimedia/video/qvideowindow.cpp @@ -7,6 +7,7 @@ #include <qpainter.h> #include <private/qguiapplication_p.h> #include <private/qmemoryvideobuffer_p.h> +#include <private/qmultimediautils_p.h> #include <qpa/qplatformintegration.h> QT_BEGIN_NAMESPACE @@ -153,8 +154,6 @@ void QVideoWindowPrivate::initRhi() m_swapChain.reset(m_rhi->newSwapChain()); m_swapChain->setWindow(q); - if (m_swapChain->isFormatSupported(QRhiSwapChain::HDRExtendedSrgbLinear)) - m_swapChain->setFormat(QRhiSwapChain::HDRExtendedSrgbLinear); m_renderPass.reset(m_swapChain->newCompatibleRenderPassDescriptor()); m_swapChain->setRenderPassDescriptor(m_renderPass.get()); @@ -344,6 +343,14 @@ void QVideoWindowPrivate::render() if (!m_hasSwapChain || (m_swapChain->currentPixelSize() != m_swapChain->surfacePixelSize())) resizeSwapChain(); + const auto requiredSwapChainFormat = + qGetRequiredSwapChainFormat(m_currentFrame.surfaceFormat()); + if (qShouldUpdateSwapChainFormat(m_swapChain.get(), requiredSwapChainFormat)) { + releaseSwapChain(); + m_swapChain->setFormat(requiredSwapChainFormat); + resizeSwapChain(); + } + if (!m_hasSwapChain) return; diff --git a/tests/auto/unit/multimedia/qmultimediautils/tst_qmultimediautils.cpp b/tests/auto/unit/multimedia/qmultimediautils/tst_qmultimediautils.cpp index 0acd41696..8ed54ac64 100644 --- a/tests/auto/unit/multimedia/qmultimediautils/tst_qmultimediautils.cpp +++ b/tests/auto/unit/multimedia/qmultimediautils/tst_qmultimediautils.cpp @@ -4,6 +4,7 @@ #include <QtTest/QtTest> #include <QDebug> #include <private/qmultimediautils_p.h> +#include <qvideoframeformat.h> class tst_QMultimediaUtils : public QObject { @@ -21,6 +22,13 @@ private slots: void qRotatedFrameSize_returnsSizeAccordinglyToRotation(); void qMediaFromUserInput_addsFilePrefix_whenCalledWithLocalFile(); + + void qGetRequiredSwapChainFormat_returnsSdr_whenMaxLuminanceIsBelowSdrThreshold_data(); + void qGetRequiredSwapChainFormat_returnsSdr_whenMaxLuminanceIsBelowSdrThreshold(); + void qGetRequiredSwapChainFormat_returnsHdr_whenMaxLuminanceIsBelowHdrThreshold_data(); + void qGetRequiredSwapChainFormat_returnsHdr_whenMaxLuminanceIsBelowHdrThreshold(); + + void qShouldUpdateSwapChainFormat_returnsFalse_whenSwapChainIsNullPointer(); }; void tst_QMultimediaUtils::fraction_of_0() @@ -109,5 +117,68 @@ void tst_QMultimediaUtils::qMediaFromUserInput_addsFilePrefix_whenCalledWithLoca QUrl::fromLocalFile(QDir::currentPath() + u"/foo/bar/baz"_s)); } +void tst_QMultimediaUtils:: + qGetRequiredSwapChainFormat_returnsSdr_whenMaxLuminanceIsBelowSdrThreshold_data() +{ + QTest::addColumn<float>("maxLuminance"); + + QTest::newRow("0") << 0.0f; + QTest::newRow("80") << 80.0f; + QTest::newRow("100") << 100.0f; +} + +void tst_QMultimediaUtils:: + qGetRequiredSwapChainFormat_returnsSdr_whenMaxLuminanceIsBelowSdrThreshold() +{ + // Arrange + QFETCH(float, maxLuminance); + + QVideoFrameFormat format; + format.setMaxLuminance(maxLuminance); + + // Act + QRhiSwapChain::Format requiredSwapChainFormat = qGetRequiredSwapChainFormat(format); + + // Assert + QCOMPARE(requiredSwapChainFormat, QRhiSwapChain::Format::SDR); +} + +void tst_QMultimediaUtils:: + qGetRequiredSwapChainFormat_returnsHdr_whenMaxLuminanceIsBelowHdrThreshold_data() +{ + QTest::addColumn<float>("maxLuminance"); + + QTest::newRow("101") << 101.0f; + QTest::newRow("300") << 300.0f; + QTest::newRow("1600") << 1600.0f; +} + +void tst_QMultimediaUtils:: + qGetRequiredSwapChainFormat_returnsHdr_whenMaxLuminanceIsBelowHdrThreshold() +{ + // Arrange + QVideoFrameFormat format; + format.setMaxLuminance(300.0f); + + // Act + QRhiSwapChain::Format requiredSwapChainFormat = qGetRequiredSwapChainFormat(format); + + // Assert + QCOMPARE(requiredSwapChainFormat, QRhiSwapChain::Format::HDRExtendedSrgbLinear); +} + +void tst_QMultimediaUtils::qShouldUpdateSwapChainFormat_returnsFalse_whenSwapChainIsNullPointer() +{ + // Arrange + QRhiSwapChain *swapChain = nullptr; + QRhiSwapChain::Format requiredSwapChainFormat = QRhiSwapChain::Format::SDR; + + // Act + bool shouldUpdate = qShouldUpdateSwapChainFormat(swapChain, requiredSwapChainFormat); + + // Assert + QCOMPARE(shouldUpdate, false); +} + QTEST_MAIN(tst_QMultimediaUtils) #include "tst_qmultimediautils.moc" |