From: Matthew Waters Date: Tue, 4 Feb 2020 08:43:52 +0000 (+1100) Subject: test/qml: add an dynamically adding qmlglsink element X-Git-Tag: 1.19.3~509^2~680 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=73cd4477af279ded0aa3f91bfdcbf9a9b59a6c08;p=platform%2Fupstream%2Fgstreamer.git test/qml: add an dynamically adding qmlglsink element The example shows how to add qmlglsink to an already running pipeline with pre-existing OpenGL elements. --- diff --git a/tests/examples/qt/meson.build b/tests/examples/qt/meson.build index 3fa08cf..650216c 100644 --- a/tests/examples/qt/meson.build +++ b/tests/examples/qt/meson.build @@ -1,2 +1,3 @@ subdir('qmlsink') +subdir('qmlsink-dynamically-added') subdir('qmlsrc') diff --git a/tests/examples/qt/qmlsink-dynamically-added/.gitignore b/tests/examples/qt/qmlsink-dynamically-added/.gitignore new file mode 100644 index 0000000..9bbbbc9 --- /dev/null +++ b/tests/examples/qt/qmlsink-dynamically-added/.gitignore @@ -0,0 +1,4 @@ +deployment.pri +play +qrc_qmlsink.cpp +*.o diff --git a/tests/examples/qt/qmlsink-dynamically-added/main.cpp b/tests/examples/qt/qmlsink-dynamically-added/main.cpp new file mode 100644 index 0000000..dede86d --- /dev/null +++ b/tests/examples/qt/qmlsink-dynamically-added/main.cpp @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static GstBusSyncReply +on_sync_bus_message (GstBus * bus, GstMessage * msg, gpointer data) +{ + GstElement *pipeline = (GstElement *) data; + + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_HAVE_CONTEXT: { + GstContext *context; + + gst_message_parse_have_context (msg, &context); + + /* if you need specific behviour or a context from a specific element, + * you need to be selective about which context's you set on the + * pipeline */ + if (gst_context_has_context_type (context, GST_GL_DISPLAY_CONTEXT_TYPE)) { + gst_println ("got have-context %p", context); + gst_element_set_context (pipeline, context); + } + + if (context) + gst_context_unref (context); + gst_message_unref (msg); + return GST_BUS_DROP; + } + default: + break; + } + + return GST_BUS_PASS; +} + +static void +connect_tee (GstElement * tee, GstElement * queue) +{ + gst_println ("attaching tee/queue %p %p", tee, queue); + gst_element_link (tee, queue); +} + +static void +connect_qmlglsink (GstElement * pipeline, GstElement * tee, QQuickWindow * rootObject) +{ + GstElement *queue = gst_element_factory_make ("queue", NULL); + GstElement *qmlglsink = gst_element_factory_make ("qmlglsink", NULL); + QQuickItem *videoItem; + + gst_println ("attaching qmlglsink %s at %p", GST_OBJECT_NAME (qmlglsink), qmlglsink); + + gst_bin_add (GST_BIN (pipeline), queue); + gst_bin_add (GST_BIN (pipeline), qmlglsink); + gst_element_link (queue, qmlglsink); + gst_element_set_state (queue, GST_STATE_PLAYING); + + videoItem = rootObject->findChild ("videoItem"); + g_assert (videoItem); + g_object_set (qmlglsink, "widget", videoItem, NULL); + + gst_element_set_state (qmlglsink, GST_STATE_PAUSED); + connect_tee (tee, queue); + gst_element_set_state (qmlglsink, GST_STATE_PLAYING); +} + +int main(int argc, char *argv[]) +{ + int ret; + + gst_init (&argc, &argv); + + { + QGuiApplication app(argc, argv); + + /* test a whole bunch of elements respect the change in display + * and therefore OpenGL context */ + GstElement *pipeline = gst_parse_launch ("gltestsrc ! " + "capsfilter caps=video/x-raw(ANY),framerate=10/1 ! glupload ! " + "glcolorconvert ! glalpha noise-level=16 method=green angle=40 ! " + "glcolorbalance hue=0.25 ! gltransformation rotation-x=30 ! " + "glvideomixerelement ! glviewconvert output-mode-override=side-by-side ! " + "glstereosplit name=s " + "glstereomix name=m ! tee name=t ! queue ! fakesink sync=true " + "s.left ! queue ! m.sink_0 " + "s.right ! queue ! m.sink_1", NULL); + GstBus *bus = gst_element_get_bus (pipeline); + gst_bus_set_sync_handler (bus, on_sync_bus_message, pipeline, NULL); + gst_object_unref (bus); + /* the plugin must be loaded before loading the qml file to register the + * GstGLVideoItem qml item */ + GstElement *sink = gst_element_factory_make ("qmlglsink", NULL); + + g_assert (pipeline && sink); + gst_object_unref (sink); + + QQuickWindow *rootObject; + + /* The Qml scene starts out with the widget not connected to any qmlglsink + * element */ + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + /* find and set the videoItem on the sink */ + rootObject = static_cast (engine.rootObjects().first()); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + GstElement *t = gst_bin_get_by_name (GST_BIN (pipeline), "t"); + gst_object_unref (t); /* ref held by pipeline */ + /* add the qmlglsink element */ + QTimer::singleShot(5000, [pipeline, t, rootObject]() { connect_qmlglsink (pipeline, t, rootObject); } ); + + ret = app.exec(); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + } + + gst_deinit (); + + return ret; +} diff --git a/tests/examples/qt/qmlsink-dynamically-added/main.qml b/tests/examples/qt/qmlsink-dynamically-added/main.qml new file mode 100644 index 0000000..ffd3cd1 --- /dev/null +++ b/tests/examples/qt/qmlsink-dynamically-added/main.qml @@ -0,0 +1,60 @@ +import QtQuick 2.4 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.3 +import QtQuick.Dialogs 1.2 +import QtQuick.Window 2.1 + +import org.freedesktop.gstreamer.GLVideoItem 1.0 + +ApplicationWindow { + id: window + visible: true + width: 640 + height: 480 + x: 30 + y: 30 + color: "black" + + Item { + anchors.fill: parent + + GstGLVideoItem { + id: video + objectName: "videoItem" + anchors.centerIn: parent + width: parent.width + height: parent.height + } + + Rectangle { + color: Qt.rgba(1, 1, 1, 0.7) + border.width: 1 + border.color: "white" + anchors.bottom: video.bottom + anchors.bottomMargin: 15 + anchors.horizontalCenter: parent.horizontalCenter + width : parent.width - 30 + height: parent.height - 30 + radius: 8 + + MouseArea { + id: mousearea + anchors.fill: parent + hoverEnabled: true + onEntered: { + parent.opacity = 1.0 + hidetimer.start() + } + } + + Timer { + id: hidetimer + interval: 5000 + onTriggered: { + parent.opacity = 0.0 + stop() + } + } + } + } +} diff --git a/tests/examples/qt/qmlsink-dynamically-added/meson.build b/tests/examples/qt/qmlsink-dynamically-added/meson.build new file mode 100644 index 0000000..ebee3b0 --- /dev/null +++ b/tests/examples/qt/qmlsink-dynamically-added/meson.build @@ -0,0 +1,20 @@ +sources = [ + 'main.cpp', +] + +if have_cxx and build_gstgl and gstgl_dep.found() + qt5_mod = import('qt5') + qt5qml_deps = dependency('qt5', modules : ['Core', 'Gui', 'Widgets', 'Qml', 'Quick'], + required: get_option('examples')) + + # FIXME Add a way to get that information out of the qt5 module + moc = find_program('moc-qt5', 'moc', required : get_option('examples')) + if qt5qml_deps.found() and moc.found() + qt_preprocessed = qt5_mod.preprocess(qresources : 'qmlsink.qrc') + executable('qmlsink-dynamically-added', sources, qt_preprocessed, + dependencies : [gst_dep, gstgl_dep, qt5qml_deps], + c_args : gst_plugins_good_args, + include_directories : [configinc], + install: false) + endif +endif diff --git a/tests/examples/qt/qmlsink-dynamically-added/play.pro b/tests/examples/qt/qmlsink-dynamically-added/play.pro new file mode 100644 index 0000000..9ecaf87 --- /dev/null +++ b/tests/examples/qt/qmlsink-dynamically-added/play.pro @@ -0,0 +1,20 @@ +TEMPLATE = app + +QT += qml quick widgets + +QT_CONFIG -= no-pkg-config +CONFIG += link_pkgconfig debug +PKGCONFIG = \ + gstreamer-1.0 \ + gstreamer-video-1.0 + +DEFINES += GST_USE_UNSTABLE_API + +INCLUDEPATH += ../lib + +SOURCES += main.cpp + +RESOURCES += qmlsink.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = diff --git a/tests/examples/qt/qmlsink-dynamically-added/qmlsink.qrc b/tests/examples/qt/qmlsink-dynamically-added/qmlsink.qrc new file mode 100644 index 0000000..5f6483a --- /dev/null +++ b/tests/examples/qt/qmlsink-dynamically-added/qmlsink.qrc @@ -0,0 +1,5 @@ + + + main.qml + +