From 200f6d9c0db2af9166cea44cb1cdc48a85d0150e Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Fri, 5 Apr 2024 18:37:02 +0800 Subject: GStreamer: add createFromPipelineDescription MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Helper functions to run `gst_parse_launch` and friends. Pick-to: 6.5 6.7 Change-Id: Iaa45fe97778ebea82cde155f925b309fa8ec8561 Reviewed-by: Jøger Hansegård Reviewed-by: Artem Dyomin --- src/plugins/multimedia/gstreamer/common/qgst.cpp | 54 ++++++++++++++++++++++ src/plugins/multimedia/gstreamer/common/qgst_p.h | 9 ++++ .../gstreamer_backend/tst_gstreamer_backend.cpp | 47 ++++++++++++++++++- .../gstreamer_backend/tst_gstreamer_backend.h | 4 ++ 4 files changed, 113 insertions(+), 1 deletion(-) diff --git a/src/plugins/multimedia/gstreamer/common/qgst.cpp b/src/plugins/multimedia/gstreamer/common/qgst.cpp index 8a77533a6..6f1a291a1 100644 --- a/src/plugins/multimedia/gstreamer/common/qgst.cpp +++ b/src/plugins/multimedia/gstreamer/common/qgst.cpp @@ -656,6 +656,11 @@ GType QGstObject::type() const return G_OBJECT_TYPE(get()); } +const char *QGstObject::typeName() const +{ + return g_type_name(type()); +} + GstObject *QGstObject::object() const { return get(); @@ -858,6 +863,25 @@ QGstElement QGstElement::createFromDevice(GstDevice *device, const char *name) }; } +QGstElement QGstElement::createFromPipelineDescription(const char *str) +{ + QUniqueGErrorHandle error; + QGstElement element{ + gst_parse_launch(str, &error), + QGstElement::NeedsRef, + }; + + if (error) // error does not mean that the element could not be constructed + qWarning() << "gst_parse_launch error:" << error; + + return element; +} + +QGstElement QGstElement::createFromPipelineDescription(const QByteArray &str) +{ + return createFromPipelineDescription(str.constData()); +} + QGstPad QGstElement::staticPad(const char *name) const { return QGstPad(gst_element_get_static_pad(element(), name), HasRef); @@ -1016,6 +1040,36 @@ QGstBin QGstBin::createFromFactory(const char *factory, const char *name) }; } +QGstBin QGstBin::createFromPipelineDescription(const QByteArray &pipelineDescription, + const char *name, bool ghostUnlinkedPads) +{ + return createFromPipelineDescription(pipelineDescription.constData(), name, ghostUnlinkedPads); +} + +QGstBin QGstBin::createFromPipelineDescription(const char *pipelineDescription, const char *name, + bool ghostUnlinkedPads) +{ + QUniqueGErrorHandle error; + + GstElement *element = + gst_parse_bin_from_description_full(pipelineDescription, ghostUnlinkedPads, + /*context=*/nullptr, GST_PARSE_FLAG_NONE, &error); + + if (!element) { + qWarning() << "Failed to make element from pipeline description" << pipelineDescription + << error; + return QGstBin{}; + } + + if (name) + gst_element_set_name(element, name); + + return QGstBin{ + element, + NeedsRef, + }; +} + QGstBin::QGstBin(GstBin *bin, RefMode mode) : QGstElement{ qGstCheckedCast(bin), diff --git a/src/plugins/multimedia/gstreamer/common/qgst_p.h b/src/plugins/multimedia/gstreamer/common/qgst_p.h index ec41b508d..34b7e7e22 100644 --- a/src/plugins/multimedia/gstreamer/common/qgst_p.h +++ b/src/plugins/multimedia/gstreamer/common/qgst_p.h @@ -408,6 +408,7 @@ public: void disconnect(gulong handlerId); GType type() const; + const char *typeName() const; GstObject *object() const; const char *name() const; }; @@ -558,6 +559,8 @@ public: const char *name = nullptr); static QGstElement createFromDevice(const QGstDeviceHandle &, const char *name = nullptr); static QGstElement createFromDevice(GstDevice *, const char *name = nullptr); + static QGstElement createFromPipelineDescription(const char *); + static QGstElement createFromPipelineDescription(const QByteArray &); QGstPad staticPad(const char *name) const; QGstPad src() const; @@ -669,6 +672,12 @@ public: explicit QGstBin(GstBin *bin, RefMode mode = NeedsRef); static QGstBin create(const char *name); static QGstBin createFromFactory(const char *factory, const char *name); + static QGstBin createFromPipelineDescription(const QByteArray &pipelineDescription, + const char *name = nullptr, + bool ghostUnlinkedPads = false); + static QGstBin createFromPipelineDescription(const char *pipelineDescription, + const char *name = nullptr, + bool ghostUnlinkedPads = false); template std::enable_if_t<(std::is_base_of_v && ...), void> add(const Ts &...ts) diff --git a/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp index b0d814dfd..763ff01bf 100644 --- a/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp +++ b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp @@ -4,8 +4,10 @@ #include "tst_gstreamer_backend.h" #include -#include + #include +#include +#include QT_USE_NAMESPACE @@ -73,6 +75,49 @@ void tst_GStreamer::metadata_taglistToMetaData_extractsDuration() QCOMPARE(parsed[QMediaMetaData::Duration].value(), 400); } +void tst_GStreamer::QGstBin_createFromPipelineDescription() +{ + QGstBin bin = QGstBin::createFromPipelineDescription("identity name=foo ! identity name=bar"); + + QVERIFY(bin); + QVERIFY(bin.findByName("foo")); + QCOMPARE_EQ(bin.findByName("foo").getParent(), bin); + QVERIFY(bin.findByName("bar")); + QVERIFY(!bin.findByName("baz")); + bin.dumpGraph("QGstBin_createFromPipelineDescription"); +} + +void tst_GStreamer::QGstElement_createFromPipelineDescription() +{ + using namespace std::string_view_literals; + QGstElement element = QGstElement::createFromPipelineDescription("identity name=foo"); + QCOMPARE_EQ(element.name(), "foo"sv); + QCOMPARE_EQ(element.typeName(), "GstIdentity"sv); +} + +void tst_GStreamer::QGstElement_createFromPipelineDescription_multipleElementsCreatesBin() +{ + using namespace std::string_view_literals; + QGstElement element = + QGstElement::createFromPipelineDescription("identity name=foo ! identity name=bar"); + + QVERIFY(element); + QCOMPARE_EQ(element.typeName(), "GstPipeline"sv); + + QGstBin bin{ + qGstSafeCast(element.element()), + QGstBin::NeedsRef, + }; + + QVERIFY(bin); + QVERIFY(bin.findByName("foo")); + QCOMPARE_EQ(bin.findByName("foo").getParent(), bin); + QVERIFY(bin.findByName("bar")); + QVERIFY(!bin.findByName("baz")); + + bin.dumpGraph("QGstElement_createFromPipelineDescription_multipleElements"); +} + QTEST_GUILESS_MAIN(tst_GStreamer) #include "moc_tst_gstreamer_backend.cpp" diff --git a/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h index e84e3f7cd..0a1628031 100644 --- a/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h +++ b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h @@ -24,6 +24,10 @@ private slots: void metadata_taglistToMetaData_extractsOrientation_data(); void metadata_taglistToMetaData_extractsDuration(); + void QGstBin_createFromPipelineDescription(); + void QGstElement_createFromPipelineDescription(); + void QGstElement_createFromPipelineDescription_multipleElementsCreatesBin(); + private: QGstreamerIntegration integration; }; -- cgit v1.2.3