summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Blechmann <tim@klingt.org>2024-03-05 10:06:15 +0800
committerArtem Dyomin <artem.dyomin@qt.io>2024-03-12 12:40:01 +0000
commit5a6f60417b827a9ffa14146567ce5a09ad84342a (patch)
tree42210a1e6a944a4132724b9abf2a6f6f64328562
parent582ad5aa6cd650d90d3e3d74a882e3b5bb2c8ff2 (diff)
GStreamer: cleanups - move implementations into cpp file
Some implementations of qgst_p.h were located in qgstutils.cpp. This patch performs some cleanups: * move all functionality related to `qgst_p.h` into `qgst.cpp` * move all inline functions from `qgst_p.h` into `qgst.cpp` * header streamlining Pick-to: 6.5 Change-Id: I22b0ba4f23ad2f7f8579d7f61040b58a91c5cf43 Reviewed-by: Artem Dyomin <artem.dyomin@qt.io> Reviewed-by: Jøger Hansegård <joger.hansegard@qt.io> (cherry picked from commit 2e47c94382b174f30c3ec14de245fbb320b7a393)
-rw-r--r--src/plugins/multimedia/gstreamer/CMakeLists.txt2
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgst.cpp876
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgst_p.h411
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstutils.cpp374
4 files changed, 983 insertions, 680 deletions
diff --git a/src/plugins/multimedia/gstreamer/CMakeLists.txt b/src/plugins/multimedia/gstreamer/CMakeLists.txt
index 8945d253e..d2205ad85 100644
--- a/src/plugins/multimedia/gstreamer/CMakeLists.txt
+++ b/src/plugins/multimedia/gstreamer/CMakeLists.txt
@@ -11,7 +11,7 @@ qt_internal_add_plugin(QGstreamerMediaPlugin
audio/qgstreameraudiosource.cpp audio/qgstreameraudiosource_p.h
audio/qgstreameraudiosink.cpp audio/qgstreameraudiosink_p.h
audio/qgstreameraudiodecoder.cpp audio/qgstreameraudiodecoder_p.h
- common/qgst_p.h
+ common/qgst.cpp common/qgst_p.h
common/qgst_debug.cpp common/qgst_debug_p.h
common/qgst_handle_types_p.h
common/qgstappsrc.cpp common/qgstappsrc_p.h
diff --git a/src/plugins/multimedia/gstreamer/common/qgst.cpp b/src/plugins/multimedia/gstreamer/common/qgst.cpp
new file mode 100644
index 000000000..002d5aaf7
--- /dev/null
+++ b/src/plugins/multimedia/gstreamer/common/qgst.cpp
@@ -0,0 +1,876 @@
+// Copyright (C) 2024 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
+
+#include <common/qgst_p.h>
+#include <common/qgst_debug_p.h>
+#include <common/qgstreamermessage_p.h>
+
+#include <QtCore/qdebug.h>
+#include <QtMultimedia/qcameradevice.h>
+
+#include <array>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+struct VideoFormat
+{
+ QVideoFrameFormat::PixelFormat pixelFormat;
+ GstVideoFormat gstFormat;
+};
+
+constexpr std::array<VideoFormat, 19> qt_videoFormatLookup{ {
+ { QVideoFrameFormat::Format_YUV420P, GST_VIDEO_FORMAT_I420 },
+ { QVideoFrameFormat::Format_YUV422P, GST_VIDEO_FORMAT_Y42B },
+ { QVideoFrameFormat::Format_YV12, GST_VIDEO_FORMAT_YV12 },
+ { QVideoFrameFormat::Format_UYVY, GST_VIDEO_FORMAT_UYVY },
+ { QVideoFrameFormat::Format_YUYV, GST_VIDEO_FORMAT_YUY2 },
+ { QVideoFrameFormat::Format_NV12, GST_VIDEO_FORMAT_NV12 },
+ { QVideoFrameFormat::Format_NV21, GST_VIDEO_FORMAT_NV21 },
+ { QVideoFrameFormat::Format_AYUV, GST_VIDEO_FORMAT_AYUV },
+ { QVideoFrameFormat::Format_Y8, GST_VIDEO_FORMAT_GRAY8 },
+ { QVideoFrameFormat::Format_XRGB8888, GST_VIDEO_FORMAT_xRGB },
+ { QVideoFrameFormat::Format_XBGR8888, GST_VIDEO_FORMAT_xBGR },
+ { QVideoFrameFormat::Format_RGBX8888, GST_VIDEO_FORMAT_RGBx },
+ { QVideoFrameFormat::Format_BGRX8888, GST_VIDEO_FORMAT_BGRx },
+ { QVideoFrameFormat::Format_ARGB8888, GST_VIDEO_FORMAT_ARGB },
+ { QVideoFrameFormat::Format_ABGR8888, GST_VIDEO_FORMAT_ABGR },
+ { QVideoFrameFormat::Format_RGBA8888, GST_VIDEO_FORMAT_RGBA },
+ { QVideoFrameFormat::Format_BGRA8888, GST_VIDEO_FORMAT_BGRA },
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ { QVideoFrameFormat::Format_Y16, GST_VIDEO_FORMAT_GRAY16_LE },
+ { QVideoFrameFormat::Format_P010, GST_VIDEO_FORMAT_P010_10LE },
+#else
+ { QVideoFrameFormat::Format_Y16, GST_VIDEO_FORMAT_GRAY16_BE },
+ { QVideoFrameFormat::Format_P010, GST_VIDEO_FORMAT_P010_10BE },
+#endif
+} };
+
+int indexOfVideoFormat(QVideoFrameFormat::PixelFormat format)
+{
+ for (size_t i = 0; i < qt_videoFormatLookup.size(); ++i)
+ if (qt_videoFormatLookup[i].pixelFormat == format)
+ return int(i);
+
+ return -1;
+}
+
+int indexOfVideoFormat(GstVideoFormat format)
+{
+ for (size_t i = 0; i < qt_videoFormatLookup.size(); ++i)
+ if (qt_videoFormatLookup[i].gstFormat == format)
+ return int(i);
+
+ return -1;
+}
+
+} // namespace
+
+// QGValue
+
+QGValue::QGValue(const GValue *v) : value(v) { }
+
+bool QGValue::isNull() const
+{
+ return !value;
+}
+
+std::optional<bool> QGValue::toBool() const
+{
+ if (!G_VALUE_HOLDS_BOOLEAN(value))
+ return std::nullopt;
+ return g_value_get_boolean(value);
+}
+
+std::optional<int> QGValue::toInt() const
+{
+ if (!G_VALUE_HOLDS_INT(value))
+ return std::nullopt;
+ return g_value_get_int(value);
+}
+
+std::optional<int> QGValue::toInt64() const
+{
+ if (!G_VALUE_HOLDS_INT64(value))
+ return std::nullopt;
+ return g_value_get_int64(value);
+}
+
+const char *QGValue::toString() const
+{
+ return value ? g_value_get_string(value) : nullptr;
+}
+
+std::optional<float> QGValue::getFraction() const
+{
+ if (!GST_VALUE_HOLDS_FRACTION(value))
+ return std::nullopt;
+ return (float)gst_value_get_fraction_numerator(value)
+ / (float)gst_value_get_fraction_denominator(value);
+}
+
+std::optional<QGRange<float>> QGValue::getFractionRange() const
+{
+ if (!GST_VALUE_HOLDS_FRACTION_RANGE(value))
+ return std::nullopt;
+ QGValue min = QGValue{ gst_value_get_fraction_range_min(value) };
+ QGValue max = QGValue{ gst_value_get_fraction_range_max(value) };
+ return QGRange<float>{ *min.getFraction(), *max.getFraction() };
+}
+
+std::optional<QGRange<int>> QGValue::toIntRange() const
+{
+ if (!GST_VALUE_HOLDS_INT_RANGE(value))
+ return std::nullopt;
+ return QGRange<int>{ gst_value_get_int_range_min(value), gst_value_get_int_range_max(value) };
+}
+
+QGstStructure QGValue::toStructure() const
+{
+ if (!value || !GST_VALUE_HOLDS_STRUCTURE(value))
+ return QGstStructure();
+ return QGstStructure(gst_value_get_structure(value));
+}
+
+QGstCaps QGValue::toCaps() const
+{
+ if (!value || !GST_VALUE_HOLDS_CAPS(value))
+ return {};
+ return QGstCaps(gst_caps_copy(gst_value_get_caps(value)), QGstCaps::HasRef);
+}
+
+bool QGValue::isList() const
+{
+ return value && GST_VALUE_HOLDS_LIST(value);
+}
+
+int QGValue::listSize() const
+{
+ return gst_value_list_get_size(value);
+}
+
+QGValue QGValue::at(int index) const
+{
+ return QGValue{ gst_value_list_get_value(value, index) };
+}
+
+// QGstStructure
+
+QGstStructure::QGstStructure(const GstStructure *s) : structure(s) { }
+
+void QGstStructure::free()
+{
+ if (structure)
+ gst_structure_free(const_cast<GstStructure *>(structure));
+ structure = nullptr;
+}
+
+bool QGstStructure::isNull() const
+{
+ return !structure;
+}
+
+QByteArrayView QGstStructure::name() const
+{
+ return gst_structure_get_name(structure);
+}
+
+QGValue QGstStructure::operator[](const char *name) const
+{
+ return QGValue{ gst_structure_get_value(structure, name) };
+}
+
+QGstStructure QGstStructure::copy() const
+{
+ return gst_structure_copy(structure);
+}
+
+QSize QGstStructure::resolution() const
+{
+ QSize size;
+
+ int w, h;
+ if (structure && gst_structure_get_int(structure, "width", &w)
+ && gst_structure_get_int(structure, "height", &h)) {
+ size.rwidth() = w;
+ size.rheight() = h;
+ }
+
+ return size;
+}
+
+QVideoFrameFormat::PixelFormat QGstStructure::pixelFormat() const
+{
+ QVideoFrameFormat::PixelFormat pixelFormat = QVideoFrameFormat::Format_Invalid;
+
+ if (!structure)
+ return pixelFormat;
+
+ if (gst_structure_has_name(structure, "video/x-raw")) {
+ const gchar *s = gst_structure_get_string(structure, "format");
+ if (s) {
+ GstVideoFormat format = gst_video_format_from_string(s);
+ int index = indexOfVideoFormat(format);
+
+ if (index != -1)
+ pixelFormat = qt_videoFormatLookup[index].pixelFormat;
+ }
+ } else if (gst_structure_has_name(structure, "image/jpeg")) {
+ pixelFormat = QVideoFrameFormat::Format_Jpeg;
+ }
+
+ return pixelFormat;
+}
+
+QGRange<float> QGstStructure::frameRateRange() const
+{
+ float minRate = 0.;
+ float maxRate = 0.;
+
+ if (!structure)
+ return { 0.f, 0.f };
+
+ auto extractFraction = [](const GValue *v) -> float {
+ return (float)gst_value_get_fraction_numerator(v)
+ / (float)gst_value_get_fraction_denominator(v);
+ };
+ auto extractFrameRate = [&](const GValue *v) {
+ auto insert = [&](float min, float max) {
+ if (max > maxRate)
+ maxRate = max;
+ if (min < minRate)
+ minRate = min;
+ };
+
+ if (GST_VALUE_HOLDS_FRACTION(v)) {
+ float rate = extractFraction(v);
+ insert(rate, rate);
+ } else if (GST_VALUE_HOLDS_FRACTION_RANGE(v)) {
+ auto *min = gst_value_get_fraction_range_max(v);
+ auto *max = gst_value_get_fraction_range_max(v);
+ insert(extractFraction(min), extractFraction(max));
+ }
+ };
+
+ const GValue *gstFrameRates = gst_structure_get_value(structure, "framerate");
+ if (gstFrameRates) {
+ if (GST_VALUE_HOLDS_LIST(gstFrameRates)) {
+ guint nFrameRates = gst_value_list_get_size(gstFrameRates);
+ for (guint f = 0; f < nFrameRates; ++f) {
+ extractFrameRate(gst_value_list_get_value(gstFrameRates, f));
+ }
+ } else {
+ extractFrameRate(gstFrameRates);
+ }
+ } else {
+ const GValue *min = gst_structure_get_value(structure, "min-framerate");
+ const GValue *max = gst_structure_get_value(structure, "max-framerate");
+ if (min && max) {
+ minRate = extractFraction(min);
+ maxRate = extractFraction(max);
+ }
+ }
+
+ return { minRate, maxRate };
+}
+
+QGstreamerMessage QGstStructure::getMessage()
+{
+ GstMessage *message = nullptr;
+ gst_structure_get(structure, "message", GST_TYPE_MESSAGE, &message, nullptr);
+ return QGstreamerMessage(message, QGstreamerMessage::HasRef);
+}
+
+std::optional<Fraction> QGstStructure::pixelAspectRatio() const
+{
+ gint numerator;
+ gint denominator;
+ if (gst_structure_get_fraction(structure, "pixel-aspect-ratio", &numerator, &denominator)) {
+ return Fraction{
+ numerator,
+ denominator,
+ };
+ }
+
+ return std::nullopt;
+}
+
+QSize QGstStructure::nativeSize() const
+{
+ QSize size = resolution();
+ if (!size.isValid()) {
+ qWarning() << Q_FUNC_INFO << "invalid resolution when querying nativeSize";
+ return size;
+ }
+
+ std::optional<Fraction> par = pixelAspectRatio();
+ if (par)
+ size = qCalculateFrameSize(size, *par);
+ return size;
+}
+
+// QGstCaps
+
+std::optional<std::pair<QVideoFrameFormat, GstVideoInfo>> QGstCaps::formatAndVideoInfo() const
+{
+ GstVideoInfo vidInfo;
+
+ bool success = gst_video_info_from_caps(&vidInfo, get());
+ if (!success)
+ return std::nullopt;
+
+ int index = indexOfVideoFormat(vidInfo.finfo->format);
+ if (index == -1)
+ return std::nullopt;
+
+ QVideoFrameFormat format(QSize(vidInfo.width, vidInfo.height),
+ qt_videoFormatLookup[index].pixelFormat);
+
+ if (vidInfo.fps_d > 0)
+ format.setFrameRate(qreal(vidInfo.fps_n) / vidInfo.fps_d);
+
+ QVideoFrameFormat::ColorRange range = QVideoFrameFormat::ColorRange_Unknown;
+ switch (vidInfo.colorimetry.range) {
+ case GST_VIDEO_COLOR_RANGE_UNKNOWN:
+ break;
+ case GST_VIDEO_COLOR_RANGE_0_255:
+ range = QVideoFrameFormat::ColorRange_Full;
+ break;
+ case GST_VIDEO_COLOR_RANGE_16_235:
+ range = QVideoFrameFormat::ColorRange_Video;
+ break;
+ }
+ format.setColorRange(range);
+
+ QVideoFrameFormat::ColorSpace colorSpace = QVideoFrameFormat::ColorSpace_Undefined;
+ switch (vidInfo.colorimetry.matrix) {
+ case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
+ case GST_VIDEO_COLOR_MATRIX_RGB:
+ case GST_VIDEO_COLOR_MATRIX_FCC:
+ break;
+ case GST_VIDEO_COLOR_MATRIX_BT709:
+ colorSpace = QVideoFrameFormat::ColorSpace_BT709;
+ break;
+ case GST_VIDEO_COLOR_MATRIX_BT601:
+ colorSpace = QVideoFrameFormat::ColorSpace_BT601;
+ break;
+ case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
+ colorSpace = QVideoFrameFormat::ColorSpace_AdobeRgb;
+ break;
+ case GST_VIDEO_COLOR_MATRIX_BT2020:
+ colorSpace = QVideoFrameFormat::ColorSpace_BT2020;
+ break;
+ }
+ format.setColorSpace(colorSpace);
+
+ QVideoFrameFormat::ColorTransfer transfer = QVideoFrameFormat::ColorTransfer_Unknown;
+ switch (vidInfo.colorimetry.transfer) {
+ case GST_VIDEO_TRANSFER_UNKNOWN:
+ break;
+ case GST_VIDEO_TRANSFER_GAMMA10:
+ transfer = QVideoFrameFormat::ColorTransfer_Linear;
+ break;
+ case GST_VIDEO_TRANSFER_GAMMA22:
+ case GST_VIDEO_TRANSFER_SMPTE240M:
+ case GST_VIDEO_TRANSFER_SRGB:
+ case GST_VIDEO_TRANSFER_ADOBERGB:
+ transfer = QVideoFrameFormat::ColorTransfer_Gamma22;
+ break;
+ case GST_VIDEO_TRANSFER_GAMMA18:
+ case GST_VIDEO_TRANSFER_GAMMA20:
+ // not quite, but best fit
+ case GST_VIDEO_TRANSFER_BT709:
+ case GST_VIDEO_TRANSFER_BT2020_12:
+ transfer = QVideoFrameFormat::ColorTransfer_BT709;
+ break;
+ case GST_VIDEO_TRANSFER_GAMMA28:
+ transfer = QVideoFrameFormat::ColorTransfer_Gamma28;
+ break;
+ case GST_VIDEO_TRANSFER_LOG100:
+ case GST_VIDEO_TRANSFER_LOG316:
+ break;
+#if GST_CHECK_VERSION(1, 18, 0)
+ case GST_VIDEO_TRANSFER_SMPTE2084:
+ transfer = QVideoFrameFormat::ColorTransfer_ST2084;
+ break;
+ case GST_VIDEO_TRANSFER_ARIB_STD_B67:
+ transfer = QVideoFrameFormat::ColorTransfer_STD_B67;
+ break;
+ case GST_VIDEO_TRANSFER_BT2020_10:
+ transfer = QVideoFrameFormat::ColorTransfer_BT709;
+ break;
+ case GST_VIDEO_TRANSFER_BT601:
+ transfer = QVideoFrameFormat::ColorTransfer_BT601;
+ break;
+#endif
+ }
+ format.setColorTransfer(transfer);
+
+ return std::pair{
+ std::move(format),
+ vidInfo,
+ };
+}
+
+void QGstCaps::addPixelFormats(const QList<QVideoFrameFormat::PixelFormat> &formats,
+ const char *modifier)
+{
+ if (!gst_caps_is_writable(get()))
+ *this = QGstCaps(gst_caps_make_writable(release()), QGstCaps::RefMode::HasRef);
+
+ GValue list = {};
+ g_value_init(&list, GST_TYPE_LIST);
+
+ for (QVideoFrameFormat::PixelFormat format : formats) {
+ int index = indexOfVideoFormat(format);
+ if (index == -1)
+ continue;
+ GValue item = {};
+
+ g_value_init(&item, G_TYPE_STRING);
+ g_value_set_string(&item,
+ gst_video_format_to_string(qt_videoFormatLookup[index].gstFormat));
+ gst_value_list_append_value(&list, &item);
+ g_value_unset(&item);
+ }
+
+ auto *structure = gst_structure_new("video/x-raw", "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
+ INT_MAX, 1, "width", GST_TYPE_INT_RANGE, 1, INT_MAX,
+ "height", GST_TYPE_INT_RANGE, 1, INT_MAX, nullptr);
+ gst_structure_set_value(structure, "format", &list);
+ gst_caps_append_structure(get(), structure);
+ g_value_unset(&list);
+
+ if (modifier)
+ gst_caps_set_features(get(), size() - 1, gst_caps_features_from_string(modifier));
+}
+
+QGstCaps QGstCaps::fromCameraFormat(const QCameraFormat &format)
+{
+ QSize size = format.resolution();
+ GstStructure *structure = nullptr;
+ if (format.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
+ structure = gst_structure_new("image/jpeg", "width", G_TYPE_INT, size.width(), "height",
+ G_TYPE_INT, size.height(), nullptr);
+ } else {
+ int index = indexOfVideoFormat(format.pixelFormat());
+ if (index < 0)
+ return {};
+ auto gstFormat = qt_videoFormatLookup[index].gstFormat;
+ structure = gst_structure_new("video/x-raw", "format", G_TYPE_STRING,
+ gst_video_format_to_string(gstFormat), "width", G_TYPE_INT,
+ size.width(), "height", G_TYPE_INT, size.height(), nullptr);
+ }
+ auto caps = QGstCaps::create();
+ gst_caps_append_structure(caps.get(), structure);
+ return caps;
+}
+
+QGstCaps::MemoryFormat QGstCaps::memoryFormat() const
+{
+ auto *features = gst_caps_get_features(get(), 0);
+ if (gst_caps_features_contains(features, "memory:GLMemory"))
+ return GLTexture;
+ if (gst_caps_features_contains(features, "memory:DMABuf"))
+ return DMABuf;
+ return CpuMemory;
+}
+
+int QGstCaps::size() const
+{
+ return int(gst_caps_get_size(get()));
+}
+
+QGstStructure QGstCaps::at(int index) const
+{
+ return gst_caps_get_structure(get(), index);
+}
+
+GstCaps *QGstCaps::caps() const
+{
+ return get();
+}
+
+QGstCaps QGstCaps::create()
+{
+ return QGstCaps(gst_caps_new_empty(), HasRef);
+}
+
+// QGstObject
+
+void QGstObject::set(const char *property, const char *str)
+{
+ g_object_set(get(), property, str, nullptr);
+}
+
+void QGstObject::set(const char *property, bool b)
+{
+ g_object_set(get(), property, gboolean(b), nullptr);
+}
+
+void QGstObject::set(const char *property, uint i)
+{
+ g_object_set(get(), property, guint(i), nullptr);
+}
+
+void QGstObject::set(const char *property, int i)
+{
+ g_object_set(get(), property, gint(i), nullptr);
+}
+
+void QGstObject::set(const char *property, qint64 i)
+{
+ g_object_set(get(), property, gint64(i), nullptr);
+}
+
+void QGstObject::set(const char *property, quint64 i)
+{
+ g_object_set(get(), property, guint64(i), nullptr);
+}
+
+void QGstObject::set(const char *property, double d)
+{
+ g_object_set(get(), property, gdouble(d), nullptr);
+}
+
+void QGstObject::set(const char *property, const QGstObject &o)
+{
+ g_object_set(get(), property, o.object(), nullptr);
+}
+
+void QGstObject::set(const char *property, const QGstCaps &c)
+{
+ g_object_set(get(), property, c.caps(), nullptr);
+}
+
+QGString QGstObject::getString(const char *property) const
+{
+ char *s = nullptr;
+ g_object_get(get(), property, &s, nullptr);
+ return QGString(s);
+}
+
+QGstStructure QGstObject::getStructure(const char *property) const
+{
+ GstStructure *s = nullptr;
+ g_object_get(get(), property, &s, nullptr);
+ return QGstStructure(s);
+}
+
+bool QGstObject::getBool(const char *property) const
+{
+ gboolean b = false;
+ g_object_get(get(), property, &b, nullptr);
+ return b;
+}
+
+uint QGstObject::getUInt(const char *property) const
+{
+ guint i = 0;
+ g_object_get(get(), property, &i, nullptr);
+ return i;
+}
+
+int QGstObject::getInt(const char *property) const
+{
+ gint i = 0;
+ g_object_get(get(), property, &i, nullptr);
+ return i;
+}
+
+quint64 QGstObject::getUInt64(const char *property) const
+{
+ guint64 i = 0;
+ g_object_get(get(), property, &i, nullptr);
+ return i;
+}
+
+qint64 QGstObject::getInt64(const char *property) const
+{
+ gint64 i = 0;
+ g_object_get(get(), property, &i, nullptr);
+ return i;
+}
+
+float QGstObject::getFloat(const char *property) const
+{
+ gfloat d = 0;
+ g_object_get(get(), property, &d, nullptr);
+ return d;
+}
+
+double QGstObject::getDouble(const char *property) const
+{
+ gdouble d = 0;
+ g_object_get(get(), property, &d, nullptr);
+ return d;
+}
+
+QGstObject QGstObject::getObject(const char *property) const
+{
+ GstObject *o = nullptr;
+ g_object_get(get(), property, &o, nullptr);
+ return QGstObject(o, HasRef);
+}
+
+void QGstObject::connect(const char *name, GCallback callback, gpointer userData)
+{
+ g_signal_connect(get(), name, callback, userData);
+}
+
+GstObject *QGstObject::object() const
+{
+ return get();
+}
+
+const char *QGstObject::name() const
+{
+ return get() ? GST_OBJECT_NAME(get()) : "(null)";
+}
+
+// QGstPad
+
+QGstPad::QGstPad(const QGstObject &o) : QGstPad(GST_PAD(o.object()), NeedsRef) { }
+
+QGstPad::QGstPad(GstPad *pad, RefMode mode) : QGstObject(&pad->object, mode) { }
+
+QGstCaps QGstPad::currentCaps() const
+{
+ return QGstCaps(gst_pad_get_current_caps(pad()), QGstCaps::HasRef);
+}
+
+QGstCaps QGstPad::queryCaps() const
+{
+ return QGstCaps(gst_pad_query_caps(pad(), nullptr), QGstCaps::HasRef);
+}
+
+bool QGstPad::isLinked() const
+{
+ return gst_pad_is_linked(pad());
+}
+
+bool QGstPad::link(const QGstPad &sink) const
+{
+ return gst_pad_link(pad(), sink.pad()) == GST_PAD_LINK_OK;
+}
+
+bool QGstPad::unlink(const QGstPad &sink) const
+{
+ return gst_pad_unlink(pad(), sink.pad());
+}
+
+bool QGstPad::unlinkPeer() const
+{
+ return unlink(peer());
+}
+
+QGstPad QGstPad::peer() const
+{
+ return QGstPad(gst_pad_get_peer(pad()), HasRef);
+}
+
+QGstElement QGstPad::parent() const
+{
+ return QGstElement(gst_pad_get_parent_element(pad()), HasRef);
+}
+
+GstPad *QGstPad::pad() const
+{
+ return GST_PAD_CAST(object());
+}
+
+GstEvent *QGstPad::stickyEvent(GstEventType type)
+{
+ return gst_pad_get_sticky_event(pad(), type, 0);
+}
+
+bool QGstPad::sendEvent(GstEvent *event)
+{
+ return gst_pad_send_event(pad(), event);
+}
+
+// QGstClock
+
+QGstClock::QGstClock(const QGstObject &o) : QGstClock(GST_CLOCK(o.object())) { }
+
+QGstClock::QGstClock(GstClock *clock, RefMode mode) : QGstObject(&clock->object, mode) { }
+
+GstClock *QGstClock::clock() const
+{
+ return GST_CLOCK_CAST(object());
+}
+
+GstClockTime QGstClock::time() const
+{
+ return gst_clock_get_time(clock());
+}
+
+// QGstElement
+
+QGstElement::QGstElement(GstElement *element, RefMode mode) : QGstObject(&element->object, mode) { }
+
+QGstElement QGstElement::createFromFactory(const char *factory, const char *name)
+{
+ GstElement *element = gst_element_factory_make(factory, name);
+
+#ifndef QT_NO_DEBUG
+ if (!element) {
+ qWarning() << "Failed to make element" << name << "from factory" << factory;
+ return QGstElement{};
+ }
+#endif
+
+ return QGstElement{
+ element,
+ NeedsRef,
+ };
+}
+
+QGstPad QGstElement::staticPad(const char *name) const
+{
+ return QGstPad(gst_element_get_static_pad(element(), name), HasRef);
+}
+
+QGstPad QGstElement::src() const
+{
+ return staticPad("src");
+}
+
+QGstPad QGstElement::sink() const
+{
+ return staticPad("sink");
+}
+
+QGstPad QGstElement::getRequestPad(const char *name) const
+{
+#if GST_CHECK_VERSION(1, 19, 1)
+ return QGstPad(gst_element_request_pad_simple(element(), name), HasRef);
+#else
+ return QGstPad(gst_element_get_request_pad(element(), name), HasRef);
+#endif
+}
+
+void QGstElement::releaseRequestPad(const QGstPad &pad) const
+{
+ return gst_element_release_request_pad(element(), pad.pad());
+}
+
+GstState QGstElement::state() const
+{
+ GstState state;
+ gst_element_get_state(element(), &state, nullptr, 0);
+ return state;
+}
+
+GstStateChangeReturn QGstElement::setState(GstState state)
+{
+ return gst_element_set_state(element(), state);
+}
+
+bool QGstElement::setStateSync(GstState state, std::chrono::nanoseconds timeout)
+{
+ GstStateChangeReturn change = gst_element_set_state(element(), state);
+ if (change == GST_STATE_CHANGE_ASYNC) {
+ change = gst_element_get_state(element(), nullptr, &state, timeout.count());
+ }
+#ifndef QT_NO_DEBUG
+ if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL)
+ qWarning() << "Could not change state of" << name() << "to" << state << change;
+#endif
+ return change == GST_STATE_CHANGE_SUCCESS;
+}
+
+bool QGstElement::syncStateWithParent()
+{
+ return gst_element_sync_state_with_parent(element()) == TRUE;
+}
+
+bool QGstElement::finishStateChange(std::chrono::nanoseconds timeout)
+{
+ GstState state, pending;
+ GstStateChangeReturn change =
+ gst_element_get_state(element(), &state, &pending, timeout.count());
+
+#ifndef QT_NO_DEBUG
+ if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL)
+ qWarning() << "Could not finish change state of" << name() << change << state << pending;
+#endif
+ return change == GST_STATE_CHANGE_SUCCESS;
+}
+
+void QGstElement::lockState(bool locked)
+{
+ gst_element_set_locked_state(element(), locked);
+}
+
+bool QGstElement::isStateLocked() const
+{
+ return gst_element_is_locked_state(element());
+}
+
+void QGstElement::sendEvent(GstEvent *event) const
+{
+ gst_element_send_event(element(), event);
+}
+
+void QGstElement::sendEos() const
+{
+ sendEvent(gst_event_new_eos());
+}
+
+GstClockTime QGstElement::baseTime() const
+{
+ return gst_element_get_base_time(element());
+}
+
+void QGstElement::setBaseTime(GstClockTime time) const
+{
+ gst_element_set_base_time(element(), time);
+}
+
+GstElement *QGstElement::element() const
+{
+ return GST_ELEMENT_CAST(get());
+}
+
+// QGstBin
+
+QGstBin QGstBin::create(const char *name)
+{
+ return QGstBin(gst_bin_new(name), NeedsRef);
+}
+
+QGstBin QGstBin::createFromFactory(const char *factory, const char *name)
+{
+ QGstElement element = QGstElement::createFromFactory(factory, name);
+ Q_ASSERT(GST_IS_BIN(element.element()));
+ return QGstBin{
+ GST_BIN(element.release()),
+ RefMode::HasRef,
+ };
+}
+
+QGstBin::QGstBin(GstBin *bin, RefMode mode) : QGstElement(&bin->element, mode) { }
+
+GstBin *QGstBin::bin() const
+{
+ return GST_BIN_CAST(get());
+}
+
+void QGstBin::addGhostPad(const QGstElement &child, const char *name)
+{
+ addGhostPad(name, child.staticPad(name));
+}
+
+void QGstBin::addGhostPad(const char *name, const QGstPad &pad)
+{
+ gst_element_add_pad(element(), gst_ghost_pad_new(name, pad.pad()));
+}
+
+bool QGstBin::syncChildrenState()
+{
+ return gst_bin_sync_children_states(bin());
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/common/qgst_p.h b/src/plugins/multimedia/gstreamer/common/qgst_p.h
index 40a7ab2c2..95a1f6b5f 100644
--- a/src/plugins/multimedia/gstreamer/common/qgst_p.h
+++ b/src/plugins/multimedia/gstreamer/common/qgst_p.h
@@ -15,23 +15,22 @@
// We mean it.
//
+#include "qgst_handle_types_p.h"
+
#include <private/qtmultimediaglobal_p.h>
#include <private/qmultimediautils_p.h>
-#include <QtCore/qsemaphore.h>
-#include <QtCore/qlist.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qsemaphore.h>
#include <QtMultimedia/qaudioformat.h>
#include <QtMultimedia/qvideoframe.h>
-#include "qgst_handle_types_p.h"
-
#include <gst/gst.h>
#include <gst/video/video-info.h>
#include <type_traits>
-#include <functional>
#if QT_CONFIG(gstreamer_photography)
#define GST_USE_UNSTABLE_API
@@ -64,70 +63,33 @@ struct QGString : QUniqueGStringHandle
class QGValue
{
public:
- explicit QGValue(const GValue *v) : value(v) { }
+ explicit QGValue(const GValue *v);
const GValue *value;
- bool isNull() const { return !value; }
+ bool isNull() const;
- std::optional<bool> toBool() const
- {
- if (!G_VALUE_HOLDS_BOOLEAN(value))
- return std::nullopt;
- return g_value_get_boolean(value);
- }
- std::optional<int> toInt() const
- {
- if (!G_VALUE_HOLDS_INT(value))
- return std::nullopt;
- return g_value_get_int(value);
- }
- std::optional<int> toInt64() const
- {
- if (!G_VALUE_HOLDS_INT64(value))
- return std::nullopt;
- return g_value_get_int64(value);
- }
+ std::optional<bool> toBool() const;
+ std::optional<int> toInt() const;
+ std::optional<int> toInt64() const;
template<typename T>
T *getPointer() const
{
return value ? static_cast<T *>(g_value_get_pointer(value)) : nullptr;
}
- const char *toString() const
- {
- return value ? g_value_get_string(value) : nullptr;
- }
- std::optional<float> getFraction() const
- {
- if (!GST_VALUE_HOLDS_FRACTION(value))
- return std::nullopt;
- return (float)gst_value_get_fraction_numerator(value)/(float)gst_value_get_fraction_denominator(value);
- }
+ const char *toString() const;
+ std::optional<float> getFraction() const;
+ std::optional<QGRange<float>> getFractionRange() const;
+ std::optional<QGRange<int>> toIntRange() const;
- std::optional<QGRange<float>> getFractionRange() const
- {
- if (!GST_VALUE_HOLDS_FRACTION_RANGE(value))
- return std::nullopt;
- QGValue min = QGValue{ gst_value_get_fraction_range_min(value) };
- QGValue max = QGValue{ gst_value_get_fraction_range_max(value) };
- return QGRange<float>{ *min.getFraction(), *max.getFraction() };
- }
+ QGstStructure toStructure() const;
+ QGstCaps toCaps() const;
- std::optional<QGRange<int>> toIntRange() const
- {
- if (!GST_VALUE_HOLDS_INT_RANGE(value))
- return std::nullopt;
- return QGRange<int>{ gst_value_get_int_range_min(value), gst_value_get_int_range_max(value) };
- }
-
- inline QGstStructure toStructure() const;
- inline QGstCaps toCaps() const;
-
- inline bool isList() const { return value && GST_VALUE_HOLDS_LIST(value); }
- inline int listSize() const { return gst_value_list_get_size(value); }
- inline QGValue at(int index) const { return QGValue{ gst_value_list_get_value(value, index) }; }
+ bool isList() const;
+ int listSize() const;
+ QGValue at(int index) const;
- Q_MULTIMEDIA_EXPORT QList<QAudioFormat::SampleFormat> getSampleFormats() const;
+ QList<QAudioFormat::SampleFormat> getSampleFormats() const;
};
namespace QGstPointerImpl {
@@ -218,30 +180,27 @@ protected:
class QGstreamerMessage;
-class QGstStructure {
+class QGstStructure
+{
public:
const GstStructure *structure = nullptr;
QGstStructure() = default;
- QGstStructure(const GstStructure *s) : structure(s) {}
- void free() { if (structure) gst_structure_free(const_cast<GstStructure *>(structure)); structure = nullptr; }
-
- bool isNull() const { return !structure; }
+ QGstStructure(const GstStructure *s);
+ void free();
- QByteArrayView name() const { return gst_structure_get_name(structure); }
+ bool isNull() const;
- QGValue operator[](const char *name) const
- {
- return QGValue{ gst_structure_get_value(structure, name) };
- }
+ QByteArrayView name() const;
+ QGValue operator[](const char *name) const;
- Q_MULTIMEDIA_EXPORT QSize resolution() const;
- Q_MULTIMEDIA_EXPORT QVideoFrameFormat::PixelFormat pixelFormat() const;
- Q_MULTIMEDIA_EXPORT QGRange<float> frameRateRange() const;
- Q_MULTIMEDIA_EXPORT QGstreamerMessage getMessage();
- Q_MULTIMEDIA_EXPORT std::optional<Fraction> pixelAspectRatio() const;
- Q_MULTIMEDIA_EXPORT QSize nativeSize() const;
+ QSize resolution() const;
+ QVideoFrameFormat::PixelFormat pixelFormat() const;
+ QGRange<float> frameRateRange() const;
+ QGstreamerMessage getMessage();
+ std::optional<Fraction> pixelAspectRatio() const;
+ QSize nativeSize() const;
- QGstStructure copy() const { return gst_structure_copy(structure); }
+ QGstStructure copy() const;
};
template <>
@@ -264,18 +223,16 @@ public:
enum MemoryFormat { CpuMemory, GLTexture, DMABuf };
- int size() const { return int(gst_caps_get_size(get())); }
- QGstStructure at(int index) const { return gst_caps_get_structure(get(), index); }
- GstCaps *caps() const { return get(); }
+ int size() const;
+ QGstStructure at(int index) const;
+ GstCaps *caps() const;
MemoryFormat memoryFormat() const;
std::optional<std::pair<QVideoFrameFormat, GstVideoInfo>> formatAndVideoInfo() const;
void addPixelFormats(const QList<QVideoFrameFormat::PixelFormat> &formats, const char *modifier = nullptr);
- static QGstCaps create() {
- return QGstCaps(gst_caps_new_empty(), HasRef);
- }
+ static QGstCaps create();
static QGstCaps fromCameraFormat(const QCameraFormat &format);
};
@@ -301,94 +258,31 @@ public:
QGstObject &operator=(const QGstObject &) = default;
QGstObject &operator=(QGstObject &&) noexcept = default;
- void set(const char *property, const char *str) { g_object_set(get(), property, str, nullptr); }
- void set(const char *property, bool b) { g_object_set(get(), property, gboolean(b), nullptr); }
- void set(const char *property, uint i) { g_object_set(get(), property, guint(i), nullptr); }
- void set(const char *property, int i) { g_object_set(get(), property, gint(i), nullptr); }
- void set(const char *property, qint64 i) { g_object_set(get(), property, gint64(i), nullptr); }
- void set(const char *property, quint64 i)
- {
- g_object_set(get(), property, guint64(i), nullptr);
- }
- void set(const char *property, double d) { g_object_set(get(), property, gdouble(d), nullptr); }
- void set(const char *property, const QGstObject &o)
- {
- g_object_set(get(), property, o.object(), nullptr);
- }
- void set(const char *property, const QGstCaps &c)
- {
- g_object_set(get(), property, c.caps(), nullptr);
- }
-
- QGString getString(const char *property) const
- {
- char *s = nullptr;
- g_object_get(get(), property, &s, nullptr);
- return QGString(s);
- }
-
- QGstStructure getStructure(const char *property) const
- {
- GstStructure *s = nullptr;
- g_object_get(get(), property, &s, nullptr);
- return QGstStructure(s);
- }
- bool getBool(const char *property) const
- {
- gboolean b = false;
- g_object_get(get(), property, &b, nullptr);
- return b;
- }
- uint getUInt(const char *property) const
- {
- guint i = 0;
- g_object_get(get(), property, &i, nullptr);
- return i;
- }
- int getInt(const char *property) const
- {
- gint i = 0;
- g_object_get(get(), property, &i, nullptr);
- return i;
- }
- quint64 getUInt64(const char *property) const
- {
- guint64 i = 0;
- g_object_get(get(), property, &i, nullptr);
- return i;
- }
- qint64 getInt64(const char *property) const
- {
- gint64 i = 0;
- g_object_get(get(), property, &i, nullptr);
- return i;
- }
- float getFloat(const char *property) const
- {
- gfloat d = 0;
- g_object_get(get(), property, &d, nullptr);
- return d;
- }
- double getDouble(const char *property) const
- {
- gdouble d = 0;
- g_object_get(get(), property, &d, nullptr);
- return d;
- }
- QGstObject getObject(const char *property) const
- {
- GstObject *o = nullptr;
- g_object_get(get(), property, &o, nullptr);
- return QGstObject(o, HasRef);
- }
-
- void connect(const char *name, GCallback callback, gpointer userData)
- {
- g_signal_connect(get(), name, callback, userData);
- }
-
- GstObject *object() const { return get(); }
- const char *name() const { return get() ? GST_OBJECT_NAME(get()) : "(null)"; }
+ void set(const char *property, const char *str);
+ void set(const char *property, bool b);
+ void set(const char *property, uint i);
+ void set(const char *property, int i);
+ void set(const char *property, qint64 i);
+ void set(const char *property, quint64 i);
+ void set(const char *property, double d);
+ void set(const char *property, const QGstObject &o);
+ void set(const char *property, const QGstCaps &c);
+
+ QGString getString(const char *property) const;
+ QGstStructure getStructure(const char *property) const;
+ bool getBool(const char *property) const;
+ uint getUInt(const char *property) const;
+ int getInt(const char *property) const;
+ quint64 getUInt64(const char *property) const;
+ qint64 getInt64(const char *property) const;
+ float getFloat(const char *property) const;
+ double getDouble(const char *property) const;
+ QGstObject getObject(const char *property) const;
+
+ void connect(const char *name, GCallback callback, gpointer userData);
+
+ GstObject *object() const;
+ const char *name() const;
};
class QGstElement;
@@ -400,35 +294,26 @@ public:
QGstPad(const QGstPad &) = default;
QGstPad(QGstPad &&) noexcept = default;
- explicit QGstPad(const QGstObject &o) : QGstPad(GST_PAD(o.object()), NeedsRef) { }
- explicit QGstPad(GstPad *pad, RefMode mode = NeedsRef) : QGstObject(&pad->object, mode) { }
+ explicit QGstPad(const QGstObject &o);
+ explicit QGstPad(GstPad *pad, RefMode mode = NeedsRef);
QGstPad &operator=(const QGstPad &) = default;
QGstPad &operator=(QGstPad &&) noexcept = default;
- QGstCaps currentCaps() const
- {
- return QGstCaps(gst_pad_get_current_caps(pad()), QGstCaps::HasRef);
- }
- QGstCaps queryCaps() const
- {
- return QGstCaps(gst_pad_query_caps(pad(), nullptr), QGstCaps::HasRef);
- }
+ QGstCaps currentCaps() const;
+ QGstCaps queryCaps() const;
- bool isLinked() const { return gst_pad_is_linked(pad()); }
- bool link(const QGstPad &sink) const
- {
- return gst_pad_link(pad(), sink.pad()) == GST_PAD_LINK_OK;
- }
- bool unlink(const QGstPad &sink) const { return gst_pad_unlink(pad(), sink.pad()); }
- bool unlinkPeer() const { return unlink(peer()); }
- QGstPad peer() const { return QGstPad(gst_pad_get_peer(pad()), HasRef); }
- inline QGstElement parent() const;
+ bool isLinked() const;
+ bool link(const QGstPad &sink) const;
+ bool unlink(const QGstPad &sink) const;
+ bool unlinkPeer() const;
+ QGstPad peer() const;
+ QGstElement parent() const;
- GstPad *pad() const { return GST_PAD_CAST(object()); }
+ GstPad *pad() const;
- GstEvent *stickyEvent(GstEventType type) { return gst_pad_get_sticky_event(pad(), type, 0); }
- bool sendEvent(GstEvent *event) { return gst_pad_send_event (pad(), event); }
+ GstEvent *stickyEvent(GstEventType type);
+ bool sendEvent(GstEvent *event);
template<auto Member, typename T>
void addProbe(T *instance, GstPadProbeType type) {
@@ -480,14 +365,11 @@ class QGstClock : public QGstObject
{
public:
QGstClock() = default;
- explicit QGstClock(const QGstObject &o) : QGstClock(GST_CLOCK(o.object())) { }
- explicit QGstClock(GstClock *clock, RefMode mode = NeedsRef) : QGstObject(&clock->object, mode)
- {
- }
-
- GstClock *clock() const { return GST_CLOCK_CAST(object()); }
+ explicit QGstClock(const QGstObject &o);
+ explicit QGstClock(GstClock *clock, RefMode mode = NeedsRef);
- GstClockTime time() const { return gst_clock_get_time(clock()); }
+ GstClock *clock() const;
+ GstClockTime time() const;
};
class QGstElement : public QGstObject
@@ -500,76 +382,26 @@ public:
QGstElement &operator=(const QGstElement &) = default;
QGstElement &operator=(QGstElement &&) noexcept = default;
- explicit QGstElement(GstElement *element, RefMode mode = NeedsRef)
- : QGstObject(&element->object, mode)
- {
- }
+ explicit QGstElement(GstElement *element, RefMode mode = NeedsRef);
+ static QGstElement createFromFactory(const char *factory, const char *name = nullptr);
- static QGstElement createFromFactory(const char *factory, const char *name = nullptr)
- {
- GstElement *element = gst_element_factory_make(factory, name);
-
-#ifndef QT_NO_DEBUG
- if (!element) {
- qWarning() << "Failed to make element" << name << "from factory" << factory;
- return QGstElement{};
- }
-#endif
-
- return QGstElement{
- element,
- NeedsRef,
- };
- }
-
- QGstPad staticPad(const char *name) const { return QGstPad(gst_element_get_static_pad(element(), name), HasRef); }
- QGstPad src() const { return staticPad("src"); }
- QGstPad sink() const { return staticPad("sink"); }
- QGstPad getRequestPad(const char *name) const
- {
-#if GST_CHECK_VERSION(1,19,1)
- return QGstPad(gst_element_request_pad_simple(element(), name), HasRef);
-#else
- return QGstPad(gst_element_get_request_pad(element(), name), HasRef);
-#endif
- }
- void releaseRequestPad(const QGstPad &pad) const { return gst_element_release_request_pad(element(), pad.pad()); }
+ QGstPad staticPad(const char *name) const;
+ QGstPad src() const;
+ QGstPad sink() const;
+ QGstPad getRequestPad(const char *name) const;
+ void releaseRequestPad(const QGstPad &pad) const;
- GstState state() const
- {
- GstState state;
- gst_element_get_state(element(), &state, nullptr, 0);
- return state;
- }
- GstStateChangeReturn setState(GstState state) { return gst_element_set_state(element(), state); }
- bool setStateSync(GstState state)
- {
- auto change = gst_element_set_state(element(), state);
- if (change == GST_STATE_CHANGE_ASYNC) {
- change = gst_element_get_state(element(), nullptr, &state, 1000*1e6 /*nano seconds*/);
- }
-#ifndef QT_NO_DEBUG
- if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL)
- qWarning() << "Could not change state of" << name() << "to" << state << change;
-#endif
- return change == GST_STATE_CHANGE_SUCCESS;
- }
- bool syncStateWithParent() { return gst_element_sync_state_with_parent(element()) == TRUE; }
- bool finishStateChange()
- {
- auto change = gst_element_get_state(element(), nullptr, nullptr, 1000*1e6 /*nano seconds*/);
-#ifndef QT_NO_DEBUG
- if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL)
- qWarning() << "Could finish change state of" << name();
-#endif
- return change == GST_STATE_CHANGE_SUCCESS;
- }
+ GstState state() const;
+ GstStateChangeReturn setState(GstState state);
+ bool setStateSync(GstState state, std::chrono::nanoseconds timeout = std::chrono::seconds(1));
+ bool syncStateWithParent();
+ bool finishStateChange(std::chrono::nanoseconds timeout = std::chrono::seconds(5));
- void lockState(bool locked) { gst_element_set_locked_state(element(), locked); }
- bool isStateLocked() const { return gst_element_is_locked_state(element()); }
+ void lockState(bool locked);
+ bool isStateLocked() const;
- void sendEvent(GstEvent *event) const { gst_element_send_event(element(), event); }
- void sendEos() const { sendEvent(gst_event_new_eos()); }
+ void sendEvent(GstEvent *event) const;
+ void sendEos() const;
template<auto Member, typename T>
void onPadAdded(T *instance) {
@@ -602,10 +434,10 @@ public:
connect("no-more-pads", G_CALLBACK(Impl::callback), instance);
}
- GstClockTime baseTime() const { return gst_element_get_base_time(element()); }
- void setBaseTime(GstClockTime time) const { gst_element_set_base_time(element(), time); }
+ GstClockTime baseTime() const;
+ void setBaseTime(GstClockTime time) const;
- GstElement *element() const { return GST_ELEMENT_CAST(get()); }
+ GstElement *element() const;
};
template <typename... Ts>
@@ -637,11 +469,6 @@ qUnlinkGstElements(const Ts &...ts)
gst_element_unlink_many(ts.element()..., nullptr);
}
-inline QGstElement QGstPad::parent() const
-{
- return QGstElement(gst_pad_get_parent_element(pad()), HasRef);
-}
-
class QGstBin : public QGstElement
{
public:
@@ -651,18 +478,9 @@ public:
QGstBin &operator=(const QGstBin &) = default;
QGstBin &operator=(QGstBin &&) noexcept = default;
- static QGstBin create(const char *name) { return QGstBin(gst_bin_new(name), NeedsRef); }
- static QGstBin createFromFactory(const char *factory, const char *name)
- {
- QGstElement element = QGstElement::createFromFactory(factory, name);
- Q_ASSERT(GST_IS_BIN(element.element()));
- return QGstBin{
- GST_BIN(element.release()),
- RefMode::HasRef,
- };
- }
-
- explicit QGstBin(GstBin *bin, RefMode mode = NeedsRef) : QGstElement(&bin->element, mode) { }
+ explicit QGstBin(GstBin *bin, RefMode mode = NeedsRef);
+ static QGstBin create(const char *name);
+ static QGstBin createFromFactory(const char *factory, const char *name);
template <typename... Ts>
std::enable_if_t<(std::is_base_of_v<QGstElement, Ts> && ...), void> add(const Ts &...ts)
@@ -691,33 +509,14 @@ public:
remove(ts...);
}
- GstBin *bin() const { return GST_BIN_CAST(get()); }
+ GstBin *bin() const;
- void addGhostPad(const QGstElement &child, const char *name)
- {
- addGhostPad(name, child.staticPad(name));
- }
- void addGhostPad(const char *name, const QGstPad &pad)
- {
- gst_element_add_pad(element(), gst_ghost_pad_new(name, pad.pad()));
- }
+ void addGhostPad(const QGstElement &child, const char *name);
+ void addGhostPad(const char *name, const QGstPad &pad);
- bool syncChildrenState() { return gst_bin_sync_children_states(bin()); }
+ bool syncChildrenState();
};
-inline QGstStructure QGValue::toStructure() const
-{
- if (!value || !GST_VALUE_HOLDS_STRUCTURE(value))
- return QGstStructure();
- return QGstStructure(gst_value_get_structure(value));
-}
-
-inline QGstCaps QGValue::toCaps() const
-{
- if (!value || !GST_VALUE_HOLDS_CAPS(value))
- return {};
- return QGstCaps(gst_caps_copy(gst_value_get_caps(value)), QGstCaps::HasRef);
-}
inline QString errorMessageCannotFindElement(std::string_view element)
{
diff --git a/src/plugins/multimedia/gstreamer/common/qgstutils.cpp b/src/plugins/multimedia/gstreamer/common/qgstutils.cpp
index dfbe241d4..ca3047b81 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstutils.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgstutils.cpp
@@ -1,37 +1,14 @@
// Copyright (C) 2016 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
-#include <QtMultimedia/private/qtmultimediaglobal_p.h>
#include "qgstutils_p.h"
-#include "qgstreamermessage_p.h"
-
-#include <QtCore/qdatetime.h>
-#include <QtCore/qdir.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qregularexpression.h>
-#include <QtCore/qsize.h>
-#include <QtCore/qset.h>
-#include <QtCore/qstringlist.h>
-#include <QtGui/qimage.h>
-#include <qaudioformat.h>
-#include <QtCore/qelapsedtimer.h>
-#include <QtMultimedia/qvideoframeformat.h>
-#include <private/qmultimediautils_p.h>
-#include <gst/audio/audio.h>
-#include <gst/video/video.h>
+#include <QtMultimedia/private/qtmultimediaglobal_p.h>
QT_BEGIN_NAMESPACE
namespace {
-template <typename T, int N>
-constexpr int lengthOf(const T (&)[N])
-{
- return N;
-}
-
const char *audioSampleFormatNames[QAudioFormat::NSampleFormats] = {
nullptr,
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
@@ -135,230 +112,6 @@ QList<QAudioFormat::SampleFormat> QGValue::getSampleFormats() const
return formats;
}
-namespace {
-
-struct VideoFormat
-{
- QVideoFrameFormat::PixelFormat pixelFormat;
- GstVideoFormat gstFormat;
-};
-
-const VideoFormat qt_videoFormatLookup[] = {
- { QVideoFrameFormat::Format_YUV420P, GST_VIDEO_FORMAT_I420 },
- { QVideoFrameFormat::Format_YUV422P, GST_VIDEO_FORMAT_Y42B },
- { QVideoFrameFormat::Format_YV12 , GST_VIDEO_FORMAT_YV12 },
- { QVideoFrameFormat::Format_UYVY , GST_VIDEO_FORMAT_UYVY },
- { QVideoFrameFormat::Format_YUYV , GST_VIDEO_FORMAT_YUY2 },
- { QVideoFrameFormat::Format_NV12 , GST_VIDEO_FORMAT_NV12 },
- { QVideoFrameFormat::Format_NV21 , GST_VIDEO_FORMAT_NV21 },
- { QVideoFrameFormat::Format_AYUV , GST_VIDEO_FORMAT_AYUV },
- { QVideoFrameFormat::Format_Y8 , GST_VIDEO_FORMAT_GRAY8 },
- { QVideoFrameFormat::Format_XRGB8888 , GST_VIDEO_FORMAT_xRGB },
- { QVideoFrameFormat::Format_XBGR8888 , GST_VIDEO_FORMAT_xBGR },
- { QVideoFrameFormat::Format_RGBX8888 , GST_VIDEO_FORMAT_RGBx },
- { QVideoFrameFormat::Format_BGRX8888 , GST_VIDEO_FORMAT_BGRx },
- { QVideoFrameFormat::Format_ARGB8888, GST_VIDEO_FORMAT_ARGB },
- { QVideoFrameFormat::Format_ABGR8888, GST_VIDEO_FORMAT_ABGR },
- { QVideoFrameFormat::Format_RGBA8888, GST_VIDEO_FORMAT_RGBA },
- { QVideoFrameFormat::Format_BGRA8888, GST_VIDEO_FORMAT_BGRA },
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- { QVideoFrameFormat::Format_Y16 , GST_VIDEO_FORMAT_GRAY16_LE },
- { QVideoFrameFormat::Format_P010 , GST_VIDEO_FORMAT_P010_10LE },
-#else
- { QVideoFrameFormat::Format_Y16 , GST_VIDEO_FORMAT_GRAY16_BE },
- { QVideoFrameFormat::Format_P010 , GST_VIDEO_FORMAT_P010_10BE },
-#endif
-};
-
-int indexOfVideoFormat(QVideoFrameFormat::PixelFormat format)
-{
- for (int i = 0; i < lengthOf(qt_videoFormatLookup); ++i)
- if (qt_videoFormatLookup[i].pixelFormat == format)
- return i;
-
- return -1;
-}
-
-int indexOfVideoFormat(GstVideoFormat format)
-{
- for (int i = 0; i < lengthOf(qt_videoFormatLookup); ++i)
- if (qt_videoFormatLookup[i].gstFormat == format)
- return i;
-
- return -1;
-}
-
-} // namespace
-
-QGstCaps::MemoryFormat QGstCaps::memoryFormat() const
-{
- auto *features = gst_caps_get_features(get(), 0);
- if (gst_caps_features_contains(features, "memory:GLMemory"))
- return GLTexture;
- if (gst_caps_features_contains(features, "memory:DMABuf"))
- return DMABuf;
- return CpuMemory;
-}
-
-std::optional<std::pair<QVideoFrameFormat, GstVideoInfo>> QGstCaps::formatAndVideoInfo() const
-{
- GstVideoInfo vidInfo;
-
- bool success = gst_video_info_from_caps(&vidInfo, get());
- if (!success)
- return std::nullopt;
-
- int index = indexOfVideoFormat(vidInfo.finfo->format);
- if (index == -1)
- return std::nullopt;
-
- QVideoFrameFormat format(QSize(vidInfo.width, vidInfo.height),
- qt_videoFormatLookup[index].pixelFormat);
-
- if (vidInfo.fps_d > 0)
- format.setFrameRate(qreal(vidInfo.fps_n) / vidInfo.fps_d);
-
- QVideoFrameFormat::ColorRange range = QVideoFrameFormat::ColorRange_Unknown;
- switch (vidInfo.colorimetry.range) {
- case GST_VIDEO_COLOR_RANGE_UNKNOWN:
- break;
- case GST_VIDEO_COLOR_RANGE_0_255:
- range = QVideoFrameFormat::ColorRange_Full;
- break;
- case GST_VIDEO_COLOR_RANGE_16_235:
- range = QVideoFrameFormat::ColorRange_Video;
- break;
- }
- format.setColorRange(range);
-
- QVideoFrameFormat::ColorSpace colorSpace = QVideoFrameFormat::ColorSpace_Undefined;
- switch (vidInfo.colorimetry.matrix) {
- case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
- case GST_VIDEO_COLOR_MATRIX_RGB:
- case GST_VIDEO_COLOR_MATRIX_FCC:
- break;
- case GST_VIDEO_COLOR_MATRIX_BT709:
- colorSpace = QVideoFrameFormat::ColorSpace_BT709;
- break;
- case GST_VIDEO_COLOR_MATRIX_BT601:
- colorSpace = QVideoFrameFormat::ColorSpace_BT601;
- break;
- case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
- colorSpace = QVideoFrameFormat::ColorSpace_AdobeRgb;
- break;
- case GST_VIDEO_COLOR_MATRIX_BT2020:
- colorSpace = QVideoFrameFormat::ColorSpace_BT2020;
- break;
- }
- format.setColorSpace(colorSpace);
-
- QVideoFrameFormat::ColorTransfer transfer = QVideoFrameFormat::ColorTransfer_Unknown;
- switch (vidInfo.colorimetry.transfer) {
- case GST_VIDEO_TRANSFER_UNKNOWN:
- break;
- case GST_VIDEO_TRANSFER_GAMMA10:
- transfer = QVideoFrameFormat::ColorTransfer_Linear;
- break;
- case GST_VIDEO_TRANSFER_GAMMA22:
- case GST_VIDEO_TRANSFER_SMPTE240M:
- case GST_VIDEO_TRANSFER_SRGB:
- case GST_VIDEO_TRANSFER_ADOBERGB:
- transfer = QVideoFrameFormat::ColorTransfer_Gamma22;
- break;
- case GST_VIDEO_TRANSFER_GAMMA18:
- case GST_VIDEO_TRANSFER_GAMMA20:
- // not quite, but best fit
- case GST_VIDEO_TRANSFER_BT709:
- case GST_VIDEO_TRANSFER_BT2020_12:
- transfer = QVideoFrameFormat::ColorTransfer_BT709;
- break;
- case GST_VIDEO_TRANSFER_GAMMA28:
- transfer = QVideoFrameFormat::ColorTransfer_Gamma28;
- break;
- case GST_VIDEO_TRANSFER_LOG100:
- case GST_VIDEO_TRANSFER_LOG316:
- break;
-#if GST_CHECK_VERSION(1, 18, 0)
- case GST_VIDEO_TRANSFER_SMPTE2084:
- transfer = QVideoFrameFormat::ColorTransfer_ST2084;
- break;
- case GST_VIDEO_TRANSFER_ARIB_STD_B67:
- transfer = QVideoFrameFormat::ColorTransfer_STD_B67;
- break;
- case GST_VIDEO_TRANSFER_BT2020_10:
- transfer = QVideoFrameFormat::ColorTransfer_BT709;
- break;
- case GST_VIDEO_TRANSFER_BT601:
- transfer = QVideoFrameFormat::ColorTransfer_BT601;
- break;
-#endif
- }
- format.setColorTransfer(transfer);
-
- return std::pair{
- std::move(format),
- vidInfo,
- };
-}
-
-void QGstCaps::addPixelFormats(const QList<QVideoFrameFormat::PixelFormat> &formats, const char *modifier)
-{
- if (!gst_caps_is_writable(get()))
- *this = QGstCaps(gst_caps_make_writable(release()), QGstCaps::RefMode::HasRef);
-
- GValue list = {};
- g_value_init(&list, GST_TYPE_LIST);
-
- for (QVideoFrameFormat::PixelFormat format : formats) {
- int index = indexOfVideoFormat(format);
- if (index == -1)
- continue;
- GValue item = {};
-
- g_value_init(&item, G_TYPE_STRING);
- g_value_set_string(&item, gst_video_format_to_string(qt_videoFormatLookup[index].gstFormat));
- gst_value_list_append_value(&list, &item);
- g_value_unset(&item);
- }
-
- auto *structure = gst_structure_new("video/x-raw",
- "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, INT_MAX, 1,
- "width" , GST_TYPE_INT_RANGE, 1, INT_MAX,
- "height" , GST_TYPE_INT_RANGE, 1, INT_MAX,
- nullptr);
- gst_structure_set_value(structure, "format", &list);
- gst_caps_append_structure(get(), structure);
- g_value_unset(&list);
-
- if (modifier)
- gst_caps_set_features(get(), size() - 1, gst_caps_features_from_string(modifier));
-}
-
-QGstCaps QGstCaps::fromCameraFormat(const QCameraFormat &format)
-{
- QSize size = format.resolution();
- GstStructure *structure = nullptr;
- if (format.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
- structure = gst_structure_new("image/jpeg",
- "width" , G_TYPE_INT, size.width(),
- "height" , G_TYPE_INT, size.height(),
- nullptr);
- } else {
- int index = indexOfVideoFormat(format.pixelFormat());
- if (index < 0)
- return {};
- auto gstFormat = qt_videoFormatLookup[index].gstFormat;
- structure = gst_structure_new("video/x-raw",
- "format" , G_TYPE_STRING, gst_video_format_to_string(gstFormat),
- "width" , G_TYPE_INT, size.width(),
- "height" , G_TYPE_INT, size.height(),
- nullptr);
- }
- auto caps = QGstCaps::create();
- gst_caps_append_structure(caps.get(), structure);
- return caps;
-}
-
void QGstUtils::setFrameTimeStamps(QVideoFrame *frame, GstBuffer *buffer)
{
// GStreamer uses nanoseconds, Qt uses microseconds
@@ -371,131 +124,6 @@ void QGstUtils::setFrameTimeStamps(QVideoFrame *frame, GstBuffer *buffer)
frame->setEndTime((startTime + duration)/G_GINT64_CONSTANT (1000));
}
}
-
-QSize QGstStructure::resolution() const
-{
- QSize size;
-
- int w, h;
- if (structure &&
- gst_structure_get_int(structure, "width", &w) &&
- gst_structure_get_int(structure, "height", &h)) {
- size.rwidth() = w;
- size.rheight() = h;
- }
-
- return size;
-}
-
-QVideoFrameFormat::PixelFormat QGstStructure::pixelFormat() const
-{
- QVideoFrameFormat::PixelFormat pixelFormat = QVideoFrameFormat::Format_Invalid;
-
- if (!structure)
- return pixelFormat;
-
- if (gst_structure_has_name(structure, "video/x-raw")) {
- const gchar *s = gst_structure_get_string(structure, "format");
- if (s) {
- GstVideoFormat format = gst_video_format_from_string(s);
- int index = indexOfVideoFormat(format);
-
- if (index != -1)
- pixelFormat = qt_videoFormatLookup[index].pixelFormat;
- }
- } else if (gst_structure_has_name(structure, "image/jpeg")) {
- pixelFormat = QVideoFrameFormat::Format_Jpeg;
- }
-
- return pixelFormat;
-}
-
-QGRange<float> QGstStructure::frameRateRange() const
-{
- float minRate = 0.;
- float maxRate = 0.;
-
- if (!structure)
- return {0.f, 0.f};
-
- auto extractFraction = [] (const GValue *v) -> float {
- return (float)gst_value_get_fraction_numerator(v)/(float)gst_value_get_fraction_denominator(v);
- };
- auto extractFrameRate = [&] (const GValue *v) {
- auto insert = [&] (float min, float max) {
- if (max > maxRate)
- maxRate = max;
- if (min < minRate)
- minRate = min;
- };
-
- if (GST_VALUE_HOLDS_FRACTION(v)) {
- float rate = extractFraction(v);
- insert(rate, rate);
- } else if (GST_VALUE_HOLDS_FRACTION_RANGE(v)) {
- auto *min = gst_value_get_fraction_range_max(v);
- auto *max = gst_value_get_fraction_range_max(v);
- insert(extractFraction(min), extractFraction(max));
- }
- };
-
- const GValue *gstFrameRates = gst_structure_get_value(structure, "framerate");
- if (gstFrameRates) {
- if (GST_VALUE_HOLDS_LIST(gstFrameRates)) {
- guint nFrameRates = gst_value_list_get_size(gstFrameRates);
- for (guint f = 0; f < nFrameRates; ++f) {
- extractFrameRate(gst_value_list_get_value(gstFrameRates, f));
- }
- } else {
- extractFrameRate(gstFrameRates);
- }
- } else {
- const GValue *min = gst_structure_get_value(structure, "min-framerate");
- const GValue *max = gst_structure_get_value(structure, "max-framerate");
- if (min && max) {
- minRate = extractFraction(min);
- maxRate = extractFraction(max);
- }
- }
-
- return {minRate, maxRate};
-}
-
-QGstreamerMessage QGstStructure::getMessage()
-{
- GstMessage *message = nullptr;
- gst_structure_get(structure, "message", GST_TYPE_MESSAGE, &message, nullptr);
- return QGstreamerMessage(message, QGstreamerMessage::HasRef);
-}
-
-std::optional<Fraction> QGstStructure::pixelAspectRatio() const
-{
- gint numerator;
- gint denominator;
- if (gst_structure_get_fraction(structure, "pixel-aspect-ratio", &numerator, &denominator)) {
- return Fraction{
- numerator,
- denominator,
- };
- }
-
- return std::nullopt;
-}
-
-QSize QGstStructure::nativeSize() const
-{
- QSize size = resolution();
- if (!size.isValid()) {
- qWarning() << Q_FUNC_INFO << "invalid resolution when querying nativeSize";
- return size;
- }
-
- std::optional<Fraction> par = pixelAspectRatio();
- if (par)
- size = qCalculateFrameSize(size, *par);
- return size;
-}
-
GList *qt_gst_video_sinks()
{
return gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_SINK