summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPiotr Srebrny <piotr.srebrny@qt.io>2022-05-16 21:04:38 +0200
committerPiotr Srebrny <piotr.srebrny@qt.io>2022-05-24 12:05:53 +0200
commit8131af7dea6f0e4f55fb6af1457b64dde567c69a (patch)
treecf703732dcf2227a41570d6266550d3d9b58d961
parent98e9c47020183b79c64dd30b1481c92c2e5dc01c (diff)
Extend fraction computation algorithm to numbers above 1 and below 0
This patch extends the algorithm for finding a real number numerator and denominator to numbers below 0 and above 1. It also improves interface by returning a pair of number. Additionally, it adds some basic test cases. Change-Id: I70f23a06a1cd2451242a53ec7c5e2fb90b9586bb Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r--src/multimedia/qmultimediautils.cpp35
-rw-r--r--src/multimedia/qmultimediautils_p.h8
-rw-r--r--src/plugins/multimedia/darwin/camera/avfcamerautility.mm14
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp3
-rw-r--r--src/plugins/multimedia/ffmpeg/qv4l2camera.cpp3
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstutils.cpp9
-rw-r--r--tests/auto/unit/multimedia/CMakeLists.txt1
-rw-r--r--tests/auto/unit/multimedia/qmultimediautils/CMakeLists.txt6
-rw-r--r--tests/auto/unit/multimedia/qmultimediautils/tst_qmultimediautils.cpp100
9 files changed, 136 insertions, 43 deletions
diff --git a/src/multimedia/qmultimediautils.cpp b/src/multimedia/qmultimediautils.cpp
index 54653751b..f8dc8e25e 100644
--- a/src/multimedia/qmultimediautils.cpp
+++ b/src/multimedia/qmultimediautils.cpp
@@ -41,10 +41,12 @@
QT_BEGIN_NAMESPACE
-void qt_real_to_fraction(qreal value, int *numerator, int *denominator)
+Fraction qRealToFraction(qreal value)
{
- if (!numerator || !denominator)
- return;
+ int integral = int(floor(value));
+ value -= qreal(integral);
+ if (value == 0.)
+ return {integral, 1};
const int dMax = 1000;
int n1 = 0, d1 = 1, n2 = 1, d2 = 1;
@@ -53,19 +55,7 @@ void qt_real_to_fraction(qreal value, int *numerator, int *denominator)
mid = qreal(n1 + n2) / (d1 + d2);
if (qAbs(value - mid) < 0.000001) {
- if (d1 + d2 <= dMax) {
- *numerator = n1 + n2;
- *denominator = d1 + d2;
- return;
- } else if (d2 > d1) {
- *numerator = n2;
- *denominator = d2;
- return;
- } else {
- *numerator = n1;
- *denominator = d1;
- return;
- }
+ break;
} else if (value > mid) {
n1 = n1 + n2;
d1 = d1 + d2;
@@ -75,13 +65,12 @@ void qt_real_to_fraction(qreal value, int *numerator, int *denominator)
}
}
- if (d1 > dMax) {
- *numerator = n2;
- *denominator = d2;
- } else {
- *numerator = n1;
- *denominator = d1;
- }
+ if (d1 + d2 <= dMax)
+ return {n1 + n2 + integral * (d1 + d2), d1 + d2};
+ else if (d2 < d1)
+ return { n2 + integral * d2, d2 };
+ else
+ return { n1 + integral * d1, d1 };
}
QT_END_NAMESPACE
diff --git a/src/multimedia/qmultimediautils_p.h b/src/multimedia/qmultimediautils_p.h
index 3b1def5d6..a0df4b635 100644
--- a/src/multimedia/qmultimediautils_p.h
+++ b/src/multimedia/qmultimediautils_p.h
@@ -53,10 +53,16 @@
#include <QtMultimedia/qtmultimediaglobal.h>
#include <QtCore/private/qglobal_p.h>
+#include <utility>
QT_BEGIN_NAMESPACE
-Q_MULTIMEDIA_EXPORT void qt_real_to_fraction(qreal value, int *numerator, int *denominator);
+struct Fraction {
+ int numerator;
+ int denominator;
+};
+
+Q_MULTIMEDIA_EXPORT Fraction qRealToFraction(qreal value);
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/darwin/camera/avfcamerautility.mm b/src/plugins/multimedia/darwin/camera/avfcamerautility.mm
index 614b99e06..9ac291f72 100644
--- a/src/plugins/multimedia/darwin/camera/avfcamerautility.mm
+++ b/src/plugins/multimedia/darwin/camera/avfcamerautility.mm
@@ -258,13 +258,10 @@ QSize qt_device_format_pixel_aspect_ratio(AVCaptureDeviceFormat *format)
if (!res.width || !resPAR.width)
return QSize();
- int n, d;
- qt_real_to_fraction(resPAR.width > res.width
- ? res.width / qreal(resPAR.width)
- : resPAR.width / qreal(res.width),
- &n, &d);
+ auto frac = qRealToFraction(resPAR.width > res.width ? res.width / qreal(resPAR.width)
+ : resPAR.width / qreal(res.width));
- return QSize(n, d);
+ return QSize(frac.numerator, frac.denominator);
}
AVCaptureDeviceFormat *qt_find_best_resolution_match(AVCaptureDevice *captureDevice,
@@ -520,9 +517,8 @@ CMTime qt_adjusted_frame_duration(AVFrameRateRange *range, qreal fps)
if (fps >= range.maxFrameRate)
return range.minFrameDuration;
- int n, d;
- qt_real_to_fraction(1. / fps, &n, &d);
- return CMTimeMake(n, d);
+ auto frac = qRealToFraction(1. / fps);
+ return CMTimeMake(frac.numerator, frac.denominator);
}
void qt_set_framerate_limits(AVCaptureDevice *captureDevice, qreal minFPS, qreal maxFPS)
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp b/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp
index 4b576c441..ab12fda20 100644
--- a/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp
+++ b/src/plugins/multimedia/ffmpeg/qffmpegvideoframeencoder.cpp
@@ -290,8 +290,7 @@ void QFFmpeg::VideoFrameEncoder::initWithFormatContext(AVFormatContext *formatCo
avcodec_parameters_to_context(d->codecContext, d->stream->codecpar);
d->codecContext->time_base = d->stream->time_base;
qCDebug(qLcVideoFrameEncoder) << "requesting time base" << d->codecContext->time_base.num << d->codecContext->time_base.den;
- int num, den;
- qt_real_to_fraction(requestedRate, &num, &den);
+ auto [num, den] = qRealToFraction(requestedRate);
d->codecContext->framerate = { num, den };
auto deviceContext = d->accel.hwDeviceContextAsBuffer();
if (deviceContext)
diff --git a/src/plugins/multimedia/ffmpeg/qv4l2camera.cpp b/src/plugins/multimedia/ffmpeg/qv4l2camera.cpp
index 36ef020db..268674ce7 100644
--- a/src/plugins/multimedia/ffmpeg/qv4l2camera.cpp
+++ b/src/plugins/multimedia/ffmpeg/qv4l2camera.cpp
@@ -867,8 +867,7 @@ void QV4L2Camera::setV4L2CameraFormat()
streamParam.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
streamParam.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- int num, den;
- qt_real_to_fraction(1./m_cameraFormat.maxFrameRate(), &num, &den);
+ auto [num, den] = qRealToFraction(1./m_cameraFormat.maxFrameRate());
streamParam.parm.capture.timeperframe = { (uint)num, (uint)den };
ioctl(d->v4l2FileDescriptor, VIDIOC_S_PARM, &streamParam);
diff --git a/src/plugins/multimedia/gstreamer/common/qgstutils.cpp b/src/plugins/multimedia/gstreamer/common/qgstutils.cpp
index 21173a5cd..92fc31aa9 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstutils.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgstutils.cpp
@@ -357,17 +357,14 @@ QGstMutableCaps QGstMutableCaps::fromCameraFormat(const QCameraFormat &format)
QSize size = format.resolution();
GstStructure *structure = nullptr;
-// int num = 0;
-// int den = 1;
-// if (format.maxFrameRate() > 0)
-// qt_real_to_fraction(1. / format.maxFrameRate(), &num, &den);
+// auto [num, den] = qRealToFraction(format.maxFrameRate());
// qDebug() << "fromCameraFormat" << format.maxFrameRate() << num << den;
if (format.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
structure = gst_structure_new("image/jpeg",
"width" , G_TYPE_INT, size.width(),
"height" , G_TYPE_INT, size.height(),
-// "framerate", GST_TYPE_FRACTION, den, num,
+// "framerate", GST_TYPE_FRACTION, num, den,
nullptr);
} else {
int index = indexOfVideoFormat(format.pixelFormat());
@@ -378,7 +375,7 @@ QGstMutableCaps QGstMutableCaps::fromCameraFormat(const QCameraFormat &format)
"format" , G_TYPE_STRING, gst_video_format_to_string(gstFormat),
"width" , G_TYPE_INT, size.width(),
"height" , G_TYPE_INT, size.height(),
-// "framerate", GST_TYPE_FRACTION, den, num,
+// "framerate", GST_TYPE_FRACTION, num, den,
nullptr);
}
gst_caps_append_structure(caps.caps, structure);
diff --git a/tests/auto/unit/multimedia/CMakeLists.txt b/tests/auto/unit/multimedia/CMakeLists.txt
index d95cab75a..bf1169e58 100644
--- a/tests/auto/unit/multimedia/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/CMakeLists.txt
@@ -12,6 +12,7 @@ add_subdirectory(qmediaplayer)
#add_subdirectory(qmediaplaylist)
add_subdirectory(qmediarecorder)
add_subdirectory(qmediatimerange)
+add_subdirectory(qmultimediautils)
add_subdirectory(qvideoframe)
add_subdirectory(qvideoframeformat)
add_subdirectory(qaudiobuffer)
diff --git a/tests/auto/unit/multimedia/qmultimediautils/CMakeLists.txt b/tests/auto/unit/multimedia/qmultimediautils/CMakeLists.txt
new file mode 100644
index 000000000..5c522a5c6
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmultimediautils/CMakeLists.txt
@@ -0,0 +1,6 @@
+qt_internal_add_test(tst_qmultimediautils
+ SOURCES
+ tst_qmultimediautils.cpp
+ PUBLIC_LIBRARIES
+ Qt::MultimediaPrivate
+)
diff --git a/tests/auto/unit/multimedia/qmultimediautils/tst_qmultimediautils.cpp b/tests/auto/unit/multimedia/qmultimediautils/tst_qmultimediautils.cpp
new file mode 100644
index 000000000..37766843c
--- /dev/null
+++ b/tests/auto/unit/multimedia/qmultimediautils/tst_qmultimediautils.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QDebug>
+#include <private/qmultimediautils_p.h>
+
+class tst_QMultimediaUtils : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void fraction_of_0();
+ void fraction_of_negative_1_5();
+ void fraction_of_1_5();
+ void fraction_of_30();
+ void fraction_of_29_97();
+ void fraction_of_lower_boundary();
+ void fraction_of_upper_boundary();
+};
+
+void tst_QMultimediaUtils::fraction_of_0()
+{
+ auto [n, d] = qRealToFraction(0.);
+ QCOMPARE(n, 0);
+ QCOMPARE(d, 1);
+}
+
+void tst_QMultimediaUtils::fraction_of_negative_1_5()
+{
+ auto [n, d] = qRealToFraction(-1.5);
+ QCOMPARE(double(n) / double(d), -1.5);
+ QCOMPARE(n, -3);
+ QCOMPARE(d, 2);
+}
+
+void tst_QMultimediaUtils::fraction_of_1_5()
+{
+ auto [n, d] = qRealToFraction(1.5);
+ QCOMPARE(double(n) / double(d), 1.5);
+ QCOMPARE(n, 3);
+ QCOMPARE(d, 2);
+}
+
+void tst_QMultimediaUtils::fraction_of_30()
+{
+ auto [n, d] = qRealToFraction(30.);
+ QCOMPARE(double(n) / double(d), 30.);
+ QCOMPARE(d, 1);
+}
+
+void tst_QMultimediaUtils::fraction_of_29_97()
+{
+ auto [n, d] = qRealToFraction(29.97);
+ QCOMPARE(double(n) / double(d), 29.97);
+}
+
+void tst_QMultimediaUtils::fraction_of_lower_boundary()
+{
+ double f = 0.000001;
+ auto [n, d] = qRealToFraction(f);
+ QVERIFY(double(n) / double(d) < f);
+ QVERIFY(double(n) / double(d) >= 0.);
+}
+
+void tst_QMultimediaUtils::fraction_of_upper_boundary()
+{
+ double f = 0.999999;
+ auto [n, d] = qRealToFraction(f);
+ QVERIFY(double(n) / double(d) <= 1.);
+ QVERIFY(double(n) / double(d) > f);
+}
+
+QTEST_MAIN(tst_QMultimediaUtils)
+#include "tst_qmultimediautils.moc"