diff options
author | Piotr Srebrny <piotr.srebrny@qt.io> | 2022-05-16 21:04:38 +0200 |
---|---|---|
committer | Piotr Srebrny <piotr.srebrny@qt.io> | 2022-05-24 12:05:53 +0200 |
commit | 8131af7dea6f0e4f55fb6af1457b64dde567c69a (patch) | |
tree | cf703732dcf2227a41570d6266550d3d9b58d961 | |
parent | 98e9c47020183b79c64dd30b1481c92c2e5dc01c (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>
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" |