Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qmultimediautils.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "qvideoframe.h"
7
8#include <QtCore/qdir.h>
9#include <QtCore/qloggingcategory.h>
10
11#include <cmath>
12
14
15Q_STATIC_LOGGING_CATEGORY(qLcMultimediaUtils, "qt.multimedia.utils");
16
18{
19 int integral = int(floor(value));
20 value -= qreal(integral);
21 if (value == 0.)
22 return {integral, 1};
23
24 const int dMax = 1000;
25 int n1 = 0, d1 = 1, n2 = 1, d2 = 1;
26 qreal mid = 0.;
27 while (d1 <= dMax && d2 <= dMax) {
28 mid = qreal(n1 + n2) / (d1 + d2);
29
30 if (qAbs(value - mid) < 0.000001) {
31 break;
32 } else if (value > mid) {
33 n1 = n1 + n2;
34 d1 = d1 + d2;
35 } else {
36 n2 = n1 + n2;
37 d2 = d1 + d2;
38 }
39 }
40
41 if (d1 + d2 <= dMax)
42 return {n1 + n2 + integral * (d1 + d2), d1 + d2};
43 else if (d2 < d1)
44 return { n2 + integral * d2, d2 };
45 else
46 return { n1 + integral * d1, d1 };
47}
48
49QSize qCalculateFrameSize(QSize resolution, Fraction par)
50{
51 if (par.numerator == par.denominator || par.numerator < 1 || par.denominator < 1)
52 return resolution;
53
54 if (par.numerator > par.denominator)
55 return { resolution.width() * par.numerator / par.denominator, resolution.height() };
56
57 return { resolution.width(), resolution.height() * par.denominator / par.numerator };
58}
59
60QSize qRotatedFrameSize(QSize size, int rotation)
61{
62 Q_ASSERT(rotation % 90 == 0);
63 return rotation % 180 ? size.transposed() : size;
64}
65
66QSize qRotatedFramePresentationSize(const QVideoFrame &frame)
67{
68 // For mirrored frames the rotation can be +/- 180 degrees,
69 // but this inaccuracy doesn't impact on the result.
70 const int rotation = qToUnderlying(frame.rotation()) + qToUnderlying(frame.surfaceFormat().rotation());
71 return qRotatedFrameSize(frame.size(), rotation);
72}
73
75{
76 return QUrl::fromUserInput(url.toString(), QDir::currentPath(), QUrl::AssumeLocalFile);
77}
78
80{
81 static const bool autoHdrEnabled = qEnvironmentVariableIntValue("QT_MEDIA_AUTO_HDR");
82
83 return autoHdrEnabled;
84}
85
86QRhiSwapChain::Format qGetRequiredSwapChainFormat(const QVideoFrameFormat &format)
87{
88 constexpr auto sdrMaxLuminance = 100.0f;
89 const auto formatMaxLuminance = format.maxLuminance();
90
91 return formatMaxLuminance > sdrMaxLuminance ? QRhiSwapChain::HDRExtendedSrgbLinear
92 : QRhiSwapChain::SDR;
93}
94
95bool qShouldUpdateSwapChainFormat(QRhiSwapChain *swapChain,
96 QRhiSwapChain::Format requiredSwapChainFormat)
97{
98 if (!swapChain)
99 return false;
100
101 return qIsAutoHdrEnabled() && swapChain->format() != requiredSwapChainFormat
102 && swapChain->isFormatSupported(requiredSwapChainFormat);
103}
104
105Q_MULTIMEDIA_EXPORT VideoTransformation
106qNormalizedSurfaceTransformation(const QVideoFrameFormat &format)
107{
108 VideoTransformation result;
109 result.mirrorVertically(format.scanLineDirection() == QVideoFrameFormat::BottomToTop);
110 result.rotate(format.rotation());
111 result.mirrorHorizontally(format.isMirrored());
112 return result;
113}
114
116 VideoTransformation videoOutputTransformation)
117{
118 VideoTransformation result = qNormalizedSurfaceTransformation(frame.surfaceFormat());
119 result.rotate(frame.rotation());
120 result.mirrorHorizontally(frame.mirrored());
121 result.rotate(videoOutputTransformation.rotation);
122 result.mirrorHorizontally(videoOutputTransformation.mirroredHorizontallyAfterRotation);
123 return result;
124}
125
126// Only accepts inputs divisible by 90.
127// Invalid input returns no rotation.
129{
130 if (clockwiseDegrees % 90 != 0) {
131 qCWarning(qLcMultimediaUtils) << "qVideoRotationFromAngle(int) received "
132 "input not divisible by 90. Input was: "
133 << clockwiseDegrees;
134 return QtVideo::Rotation::None;
135 }
136
137 int newDegrees = clockwiseDegrees % 360;
138 // Adjust negative rotations into positive ones.
139 if (newDegrees < 0)
140 newDegrees += 360;
141 return static_cast<QtVideo::Rotation>(newDegrees);
142}
143
145{
146 const qreal absScaleX = std::hypot(matrix.m11(), matrix.m12());
147 const qreal absScaleY = std::hypot(matrix.m21(), matrix.m22());
148
149 if (qFuzzyIsNull(absScaleX) || qFuzzyIsNull(absScaleY))
150 return {}; // the matrix is malformed
151
152 qreal cos1 = matrix.m11() / absScaleX;
153 qreal sin1 = matrix.m12() / absScaleX;
154
155 // const: consider yScale > 0, as negative yScale can be compensated via negative xScale
156 const qreal sin2 = -matrix.m21() / absScaleY;
157 const qreal cos2 = matrix.m22() / absScaleY;
158
159 VideoTransformation result;
160
161 // try detecting the best pair option to detect mirroring
162
163 if (std::abs(cos1) + std::abs(cos2) > std::abs(sin1) + std::abs(sin2))
164 result.mirroredHorizontallyAfterRotation = std::signbit(cos1) != std::signbit(cos2);
165 else
166 result.mirroredHorizontallyAfterRotation = std::signbit(sin1) != std::signbit(sin2);
167
168 if (result.mirroredHorizontallyAfterRotation) {
169 cos1 *= -1;
170 sin1 *= -1;
171 }
172
173 const qreal maxDiscrepancy = 0.2;
174
175 if (std::abs(cos1 - cos2) > maxDiscrepancy || std::abs(sin1 - sin2) > maxDiscrepancy)
176 return {}; // the matrix is sheared too much, this is not supported currently
177
178 const qreal angle = atan2(sin1 + sin2, cos1 + cos2);
179 Q_ASSERT(!std::isnan(angle)); // checked upon scale validation
180
181 result.rotation = qVideoRotationFromDegrees(qRound(angle / M_PI_2) * 90);
182 return result;
183}
184
185QT_END_NAMESPACE
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
#define M_PI_2
Definition qmath.h:204
QRhiSwapChain::Format qGetRequiredSwapChainFormat(const QVideoFrameFormat &format)
QUrl qMediaFromUserInput(QUrl url)
Fraction qRealToFraction(qreal value)
QSize qRotatedFramePresentationSize(const QVideoFrame &frame)
QtVideo::Rotation qVideoRotationFromDegrees(int clockwiseDegrees)
VideoTransformationOpt qVideoTransformationFromMatrix(const QTransform &matrix)
QSize qCalculateFrameSize(QSize resolution, Fraction par)
VideoTransformation qNormalizedFrameTransformation(const QVideoFrame &frame, int videoOutputRotation)
Q_MULTIMEDIA_EXPORT bool qIsAutoHdrEnabled()
QSize qRotatedFrameSize(QSize size, QtVideo::Rotation rotation)
Q_MULTIMEDIA_EXPORT bool qShouldUpdateSwapChainFormat(QRhiSwapChain *swapChain, QRhiSwapChain::Format requiredSwapChainFormat)