diff --git a/cmake/find-modules/FindGStreamer.cmake b/cmake/find-modules/FindGStreamer.cmake index a06e496285a..23f57af6a1e 100644 --- a/cmake/find-modules/FindGStreamer.cmake +++ b/cmake/find-modules/FindGStreamer.cmake @@ -200,7 +200,7 @@ elseif(GST_VERSION_MINOR EQUAL 20) elseif(GST_VERSION_MINOR EQUAL 22) set(GST_VERSION_PATCH 12) elseif(GST_VERSION_MINOR EQUAL 24) - set(GST_VERSION_PATCH 8) + set(GST_VERSION_PATCH 11) endif() set(GST_PLUGINS_VERSION ${GST_VERSION_MAJOR}.${GST_VERSION_MINOR}.${GST_VERSION_PATCH}) diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt index 817fc78349f..1339777b261 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt +++ b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/CMakeLists.txt @@ -106,7 +106,10 @@ endif() ################################################################################ -if(GStreamer_VERSION VERSION_GREATER_EQUAL 1.22) +if(GStreamer_VERSION VERSION_GREATER_EQUAL 1.20) + if(GStreamer_VERSION VERSION_EQUAL 1.20) + set(GStreamer_VERSION 1.22) + endif() FetchContent_Declare(gstreamer_good_plugins # URL https://gitlab.freedesktop.org/gstreamer/gstreamer/-/archive/${GST_PLUGINS_VERSION}/gstreamer-${GST_PLUGINS_VERSION}.zip?path=subprojects/gst-plugins-good/ext/qt6 URL https://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-${GST_PLUGINS_VERSION}.tar.xz @@ -114,10 +117,10 @@ if(GStreamer_VERSION VERSION_GREATER_EQUAL 1.22) ) FetchContent_MakeAvailable(gstreamer_good_plugins) set(QGC_GST_QT6_PLUGIN_PATH "${gstreamer_good_plugins_SOURCE_DIR}/ext/qt6") + cmake_print_variables(QGC_GST_QT6_PLUGIN_PATH) else() - set(QGC_GST_QT6_PLUGIN_PATH "${CMAKE_CURRENT_SOURCE_DIR}/qt6") + return() endif() -cmake_print_variables(QGC_GST_QT6_PLUGIN_PATH) ################################################################################ diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstplugin.cc b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstplugin.cc deleted file mode 100644 index f7c82f4e4d8..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstplugin.cc +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2024 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstqt6elements.h" -#include "qt6glitem.h" - -#include - -static gboolean -plugin_init (GstPlugin * plugin) -{ - gboolean ret = FALSE; -// TODO(zdanek) fix after switching to gstreamer 1.20.0+ -// original code from 1.20.0 -// ret |= GST_ELEMENT_REGISTER (qml6glsink, plugin); - ret |= gst_element_register_qml6glsink (plugin); - - return ret; -} - -static void registerMetatypes() -{ - qmlRegisterType ("org.freedesktop.gstreamer.Qt6GLVideoItem", 1, 0, "GstGLQt6VideoItem"); -} - -Q_CONSTRUCTOR_FUNCTION(registerMetatypes) - -#ifndef GST_PACKAGE_NAME -#define GST_PACKAGE_NAME "GStreamer Bad Plug-ins (qmake)" -#define GST_PACKAGE_ORIGIN "Unknown package origin" -#define GST_LICENSE "LGPL" -#define PACKAGE "gst-plugins-bad (qmake)" -#define PACKAGE_VERSION "1.21.0.1" -#endif - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - qml6, - "Qt6 Qml plugin", - plugin_init, PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, - GST_PACKAGE_ORIGIN) diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqml6glsink.cc b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqml6glsink.cc deleted file mode 100644 index 32dd6469312..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqml6glsink.cc +++ /dev/null @@ -1,585 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2024 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -/** - * SECTION:gstqml6glsink - * - * qml6glsink provides a way to render a video stream as a Qml object inside - * the Qml scene graph. This is achieved by providing the incoming OpenGL - * textures to Qt as a scene graph object. - * - * qml6glsink will attempt to retrieve the windowing system display connection - * that Qt is using (#GstGLDisplay). This may be different to any already - * existing window system display connection already in use in the pipeline for - * a number of reasons. A couple of examples of this are: - * - * 1. Adding qml6glsink to an already running pipeline - * 2. Not having any qml6glsink element start up before any - * other OpenGL-based element in the pipeline. - * - * If one of these scenarios occurs, then there will be multiple OpenGL contexts - * in use in the pipeline. This means that either the pipeline will fail to - * start up correctly, a downstream element may reject buffers, or a complete - * GPU->System memory->GPU transfer is performed for every buffer. - * - * The requirement to avoid this is that all elements share the same - * #GstGLDisplay object and as Qt cannot currently share an existing window - * system display connection, GStreamer must use the window system display - * connection provided by Qt. This window system display connection can be - * retrieved by either a qmlglsink element or a qmlgloverlay element. The - * recommended usage is to have either element (qmlglsink or qmlgloverlay) - * be the first to propagate the #GstGLDisplay for the entire pipeline to use by - * setting either element to the READY element state before any other OpenGL - * element in the pipeline. - * - * In a dynamically adding qmlglsink (or qmlgloverlay) to a pipeline case, - * there are some considerations for ensuring that the window system display - * and OpenGL contexts are compatible with Qt. When the qmlgloverlay (or - * qmlglsink) element is added and brought up to READY, it will propagate it's - * own #GstGLDisplay using the #GstContext mechanism regardless of any existing - * #GstGLDisplay used by the pipeline previously. In order for the new - * #GstGLDisplay to be used, the application must then set the provided - * #GstGLDisplay containing #GstContext on the pipeline. This may effectively - * cause each OpenGL element to replace the window system display and also the - * OpenGL context it is using. As such this process may take a significant - * amount of time and resources as objects are recreated in the new OpenGL - * context. - * - * All instances of qmlglsink and qmlgloverlay will return the exact same - * #GstGLDisplay object while the pipeline is running regardless of whether - * any qmlglsink or qmlgloverlay elements are added or removed from the - * pipeline. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstqt6elements.h" -#include "gstqml6glsink.h" -#include - -#include - -#define GST_CAT_DEFAULT gst_debug_qml6_gl_sink -GST_DEBUG_CATEGORY (GST_CAT_DEFAULT); - -static void gst_qml6_gl_sink_navigation_interface_init (GstNavigationInterface * iface); -static void gst_qml6_gl_sink_finalize (GObject * object); -static void gst_qml6_gl_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * param_spec); -static void gst_qml6_gl_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * param_spec); - -static gboolean gst_qml6_gl_sink_stop (GstBaseSink * bsink); - -static gboolean gst_qml6_gl_sink_query (GstBaseSink * bsink, GstQuery * query); - -static GstStateChangeReturn -gst_qml6_gl_sink_change_state (GstElement * element, GstStateChange transition); - -static void gst_qml6_gl_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, - GstClockTime * start, GstClockTime * end); -static gboolean gst_qml6_gl_sink_set_caps (GstBaseSink * bsink, GstCaps * caps); -static GstFlowReturn gst_qml6_gl_sink_show_frame (GstVideoSink * bsink, - GstBuffer * buf); -static gboolean gst_qml6_gl_sink_propose_allocation (GstBaseSink * bsink, - GstQuery * query); - -static GstStaticPadTemplate gst_qt_sink_template = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY "), " - "format = (string) { RGB, RGBA }, " - "width = " GST_VIDEO_SIZE_RANGE ", " - "height = " GST_VIDEO_SIZE_RANGE ", " - "framerate = " GST_VIDEO_FPS_RANGE ", " - "texture-target = (string) 2D")); - -#define DEFAULT_FORCE_ASPECT_RATIO TRUE -#define DEFAULT_PAR_N 0 -#define DEFAULT_PAR_D 1 - -enum -{ - ARG_0, - PROP_WIDGET, - PROP_FORCE_ASPECT_RATIO, - PROP_PIXEL_ASPECT_RATIO, -}; - -enum -{ - SIGNAL_0, - LAST_SIGNAL -}; - -#define gst_qml6_gl_sink_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstQml6GLSink, gst_qml6_gl_sink, - GST_TYPE_VIDEO_SINK, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, - "qtsink", 0, "Qt Video Sink"); - G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION, - gst_qml6_gl_sink_navigation_interface_init)); -G_BEGIN_DECLS gboolean G_PASTE(gst_element_register_, qml6glsink)(GstPlugin *plugin) -{ - { - { - qt6_element_init(plugin); - } - } - return gst_element_register(plugin, "qml6glsink", GST_RANK_NONE, (gst_qml6_gl_sink_get_type())); -} -G_END_DECLS; - -static void -gst_qml6_gl_sink_class_init (GstQml6GLSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - GstVideoSinkClass *gstvideosink_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - gstvideosink_class = (GstVideoSinkClass *) klass; - - gobject_class->set_property = gst_qml6_gl_sink_set_property; - gobject_class->get_property = gst_qml6_gl_sink_get_property; - - gst_element_class_set_metadata (gstelement_class, "Qt6 Video Sink", - "Sink/Video", "A video sink that renders to a QQuickItem for Qt6", - "Matthew Waters "); - - g_object_class_install_property (gobject_class, PROP_WIDGET, - g_param_spec_pointer ("widget", "QQuickItem", - "The QQuickItem to place in the object hierarchy", - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO, - g_param_spec_boolean ("force-aspect-ratio", - "Force aspect ratio", - "When enabled, scaling will respect original aspect ratio", - DEFAULT_FORCE_ASPECT_RATIO, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO, - gst_param_spec_fraction ("pixel-aspect-ratio", "Pixel Aspect Ratio", - "The pixel aspect ratio of the device", DEFAULT_PAR_N, DEFAULT_PAR_D, - G_MAXINT, 1, 1, 1, - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - - gst_element_class_add_static_pad_template (gstelement_class, &gst_qt_sink_template); - - gobject_class->finalize = gst_qml6_gl_sink_finalize; - - gstelement_class->change_state = gst_qml6_gl_sink_change_state; - gstbasesink_class->query = gst_qml6_gl_sink_query; - gstbasesink_class->set_caps = gst_qml6_gl_sink_set_caps; - gstbasesink_class->get_times = gst_qml6_gl_sink_get_times; - gstbasesink_class->propose_allocation = gst_qml6_gl_sink_propose_allocation; - gstbasesink_class->stop = gst_qml6_gl_sink_stop; - - gstvideosink_class->show_frame = gst_qml6_gl_sink_show_frame; -} - -static void -gst_qml6_gl_sink_init (GstQml6GLSink * qt_sink) -{ - qt_sink->widget = QSharedPointer(); - if (qt_sink->widget) - qt_sink->widget->setSink (GST_ELEMENT_CAST (qt_sink)); -} - -static void -gst_qml6_gl_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (object); - - switch (prop_id) { - case PROP_WIDGET: { - Qt6GLVideoItem *qt_item = static_cast (g_value_get_pointer (value)); - if (qt_item) { - qt_sink->widget = qt_item->getInterface(); - if (qt_sink->widget) { - qt_sink->widget->setSink (GST_ELEMENT_CAST (qt_sink)); - } - } else { - qt_sink->widget.clear(); - } - break; - } - case PROP_FORCE_ASPECT_RATIO: - g_return_if_fail (qt_sink->widget); - qt_sink->widget->setForceAspectRatio (g_value_get_boolean (value)); - break; - case PROP_PIXEL_ASPECT_RATIO: - g_return_if_fail (qt_sink->widget); - qt_sink->widget->setDAR (gst_value_get_fraction_numerator (value), - gst_value_get_fraction_denominator (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -_reset (GstQml6GLSink * qt_sink) -{ - if (qt_sink->display) { - gst_object_unref (qt_sink->display); - qt_sink->display = NULL; - } - - if (qt_sink->context) { - gst_object_unref (qt_sink->context); - qt_sink->context = NULL; - } - - if (qt_sink->qt_context) { - gst_object_unref (qt_sink->qt_context); - qt_sink->qt_context = NULL; - } -} - -static void -gst_qml6_gl_sink_finalize (GObject * object) -{ - GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (object); - - _reset (qt_sink); - - qt_sink->widget.clear(); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_qml6_gl_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (object); - - switch (prop_id) { - case PROP_WIDGET: - /* This is not really safe - the app needs to be - * sure the widget is going to be kept alive or - * this can crash */ - if (qt_sink->widget) - g_value_set_pointer (value, qt_sink->widget->videoItem()); - else - g_value_set_pointer (value, NULL); - break; - case PROP_FORCE_ASPECT_RATIO: - if (qt_sink->widget) - g_value_set_boolean (value, qt_sink->widget->getForceAspectRatio ()); - else - g_value_set_boolean (value, DEFAULT_FORCE_ASPECT_RATIO); - break; - case PROP_PIXEL_ASPECT_RATIO: - if (qt_sink->widget) { - gint num, den; - qt_sink->widget->getDAR (&num, &den); - gst_value_set_fraction (value, num, den); - } else { - gst_value_set_fraction (value, DEFAULT_PAR_N, DEFAULT_PAR_D); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gboolean -gst_qml6_gl_sink_query (GstBaseSink * bsink, GstQuery * query) -{ - GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (bsink); - gboolean res = FALSE; - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_CONTEXT: - { - if (gst_gl_handle_context_query ((GstElement *) qt_sink, query, - qt_sink->display, qt_sink->context, qt_sink->qt_context)) - return TRUE; - - /* fallthrough */ - } - default: - res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); - break; - } - - return res; -} - -static gboolean -gst_qml6_gl_sink_stop (GstBaseSink * bsink) -{ - return TRUE; -} - -static GstStateChangeReturn -gst_qml6_gl_sink_change_state (GstElement * element, GstStateChange transition) -{ - GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (element); - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - QGuiApplication *app; - - GST_DEBUG ("changing state: %s => %s", - gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)), - gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition))); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - app = static_cast (QCoreApplication::instance ()); - if (!app) { - GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, - ("%s", "Failed to connect to Qt"), - ("%s", "Could not retrieve QGuiApplication instance")); - return GST_STATE_CHANGE_FAILURE; - } - - if (!qt_sink->widget) { - GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, - ("%s", "Required property \'widget\' not set"), - (NULL)); - return GST_STATE_CHANGE_FAILURE; - } - - if (!qt_sink->widget->initWinSys()) { - GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, - ("%s", "Could not initialize window system"), - (NULL)); - return GST_STATE_CHANGE_FAILURE; - } - - qt_sink->display = qt_sink->widget->getDisplay(); - qt_sink->context = qt_sink->widget->getContext(); - qt_sink->qt_context = qt_sink->widget->getQtContext(); - - if (!qt_sink->display || !qt_sink->context || !qt_sink->qt_context) { - GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, - ("%s", "Could not retrieve window system OpenGL configuration"), - (NULL)); - return GST_STATE_CHANGE_FAILURE; - } - - GST_OBJECT_LOCK (qt_sink->display); - gst_gl_display_add_context (qt_sink->display, qt_sink->context); - GST_OBJECT_UNLOCK (qt_sink->display); - - gst_gl_element_propagate_display_context (GST_ELEMENT (qt_sink), qt_sink->display); - - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - if (qt_sink->widget) - qt_sink->widget->setBuffer(NULL); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; -} - -static void -gst_qml6_gl_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, - GstClockTime * start, GstClockTime * end) -{ - GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (bsink); - - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - *start = GST_BUFFER_TIMESTAMP (buf); - if (GST_BUFFER_DURATION_IS_VALID (buf)) - *end = *start + GST_BUFFER_DURATION (buf); - else { - if (GST_VIDEO_INFO_FPS_N (&qt_sink->v_info) > 0) { - *end = *start + - gst_util_uint64_scale_int (GST_SECOND, - GST_VIDEO_INFO_FPS_D (&qt_sink->v_info), - GST_VIDEO_INFO_FPS_N (&qt_sink->v_info)); - } - } - } -} - -gboolean -gst_qml6_gl_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) -{ - GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (bsink); - - GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps); - - if (!gst_video_info_from_caps (&qt_sink->v_info, caps)) - return FALSE; - - if (!qt_sink->widget) - return FALSE; - - return qt_sink->widget->setCaps(caps); -} - -static GstFlowReturn -gst_qml6_gl_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) -{ - GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (vsink); - - GST_TRACE ("rendering buffer:%p", buf); - - if (qt_sink->widget) - qt_sink->widget->setBuffer(buf); - - return GST_FLOW_OK; -} - -static gboolean -gst_qml6_gl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) -{ - GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (bsink); - GstBufferPool *pool; - GstStructure *config; - GstCaps *caps; - guint size; - gboolean need_pool; - - if (!qt_sink->display || !qt_sink->context) - return FALSE; - - gst_query_parse_allocation (query, &caps, &need_pool); - - if (caps == NULL) - goto no_caps; - - /* FIXME re-using buffer pool breaks renegotiation */ - if ((pool = qt_sink->pool)) - gst_object_ref (pool); - - if (pool != NULL) { - GstCaps *pcaps; - - /* we had a pool, check caps */ - GST_DEBUG_OBJECT (qt_sink, "check existing pool caps"); - config = gst_buffer_pool_get_config (pool); - gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL); - - if (!gst_caps_is_equal (caps, pcaps)) { - GST_DEBUG_OBJECT (qt_sink, "pool has different caps"); - /* different caps, we can't use this pool */ - gst_object_unref (pool); - pool = NULL; - } - gst_structure_free (config); - } else { - GstVideoInfo info; - - if (!gst_video_info_from_caps (&info, caps)) - goto invalid_caps; - - /* the normal size of a frame */ - size = info.size; - } - - if (pool == NULL && need_pool) { - - GST_DEBUG_OBJECT (qt_sink, "create new pool"); - pool = gst_gl_buffer_pool_new (qt_sink->context); - - config = gst_buffer_pool_get_config (pool); - gst_buffer_pool_config_set_params (config, caps, size, 0, 0); - if (!gst_buffer_pool_set_config (pool, config)) - goto config_failed; - } - - /* we need at least 2 buffer because we hold on to the last one */ - gst_query_add_allocation_pool (query, pool, size, 2, 0); - if (pool) - gst_object_unref (pool); - - /* we also support various metadata */ - gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0); - - if (qt_sink->context->gl_vtable->FenceSync) - gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0); - - return TRUE; - - /* ERRORS */ -no_caps: - { - GST_DEBUG_OBJECT (bsink, "no caps specified"); - return FALSE; - } -invalid_caps: - { - GST_DEBUG_OBJECT (bsink, "invalid caps specified"); - return FALSE; - } -config_failed: - { - GST_DEBUG_OBJECT (bsink, "failed setting config"); - return FALSE; - } -} - -static void -gst_qml6_gl_sink_navigation_send_event (GstNavigation * navigation, - GstStructure *structure) -{ - GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (navigation); - GST_TRACE_OBJECT (qt_sink, "navigation event %" GST_PTR_FORMAT, - structure); - // TODO(zdanek) this will be available from gstreamer 1.22 -} - -static void gst_qml6_gl_sink_navigation_interface_init (GstNavigationInterface * iface) -{ - iface->send_event = gst_qml6_gl_sink_navigation_send_event; -} diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqml6glsink.h b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqml6glsink.h deleted file mode 100644 index dbc409d860a..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqml6glsink.h +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2024 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __GST_QT6_SINK_H__ -#define __GST_QT6_SINK_H__ - -#include -#include -#include -#include -#include "qt6glitem.h" - -typedef struct _GstQml6GLSinkPrivate GstQml6GLSinkPrivate; - -G_BEGIN_DECLS - -#define GST_TYPE_QML6_GL_SINK (gst_qml6_gl_sink_get_type()) -G_DECLARE_FINAL_TYPE (GstQml6GLSink, gst_qml6_gl_sink, GST, QML6_GL_SINK, GstVideoSink) -#define GST_QML6_GL_SINK_CAST(obj) ((GstQml6GLSink*)(obj)) - -/** - * GstQml6GLSink: - * - * Opaque #GstQml6GLSink object - */ -struct _GstQml6GLSink -{ - /* */ - GstVideoSink parent; - - GstVideoInfo v_info; - GstBufferPool *pool; - - GstGLDisplay *display; - GstGLContext *context; - GstGLContext *qt_context; - - QSharedPointer widget; -}; - -GstQml6GLSink * gst_qml6_gl_sink_new (void); - -G_END_DECLS - -#endif /* __GST_QT6_SINK_H__ */ diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqsg6glnode.cc b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqsg6glnode.cc deleted file mode 100644 index fd1aac4a0e9..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqsg6glnode.cc +++ /dev/null @@ -1,197 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2024 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -/* - * GStreamer - * Copyright (C) 2022 Matthew Waters - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "gstqsg6glnode.h" - -#include -#include -#include -#include - -#define GST_CAT_DEFAULT gst_qsg_texture_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -GstQSG6OpenGLNode::GstQSG6OpenGLNode(QQuickItem * item) -{ - static gsize _debug; - - if (g_once_init_enter (&_debug)) { - GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "qtqsgtexture", 0, - "Qt Scenegraph Texture"); - g_once_init_leave (&_debug, 1); - } - - gst_video_info_init (&this->v_info); - - this->buffer_ = NULL; - this->sync_buffer_ = gst_buffer_new (); - this->dummy_tex_ = nullptr; - // TODO; handle windowChanged? - this->window_ = item->window(); -} - -GstQSG6OpenGLNode::~GstQSG6OpenGLNode() -{ - gst_buffer_replace (&this->buffer_, NULL); - gst_buffer_replace (&this->sync_buffer_, NULL); - this->buffer_was_bound = FALSE; - delete this->dummy_tex_; - this->dummy_tex_ = nullptr; -} - -QSGTexture * -GstQSG6OpenGLNode::texture() const -{ - return QSGSimpleTextureNode::texture(); -} - -/* only called from the streaming thread with scene graph thread blocked */ -void -GstQSG6OpenGLNode::setCaps (GstCaps * caps) -{ - GST_LOG ("%p setCaps %" GST_PTR_FORMAT, this, caps); - - if (caps) - gst_video_info_from_caps (&this->v_info, caps); - else - gst_video_info_init (&this->v_info); -} - -/* only called from the streaming thread with scene graph thread blocked */ -GstBuffer * -GstQSG6OpenGLNode::getBuffer () -{ - GstBuffer *buffer = NULL; - - if (this->buffer_) - buffer = gst_buffer_ref (this->buffer_); - - return buffer; -} - -/* only called from the streaming thread with scene graph thread blocked */ -void -GstQSG6OpenGLNode::setBuffer (GstBuffer * buffer) -{ - GstGLContext *qt_context = NULL; - gboolean buffer_changed; - - GST_LOG ("%p setBuffer %" GST_PTR_FORMAT, this, buffer); - /* FIXME: update more state here */ - buffer_changed = gst_buffer_replace (&this->buffer_, buffer); - - if (buffer_changed) { - GstGLContext *context; - GstGLSyncMeta *sync_meta; - GstMemory *mem; - guint tex_id; - QQuickWindow::CreateTextureOptions options = QQuickWindow::TextureHasAlphaChannel; - QSGTexture *texture = nullptr; - QSize texSize; - - qt_context = gst_gl_context_get_current(); - if (!qt_context) - goto use_dummy_tex; - - if (!this->buffer_) - goto use_dummy_tex; - if (GST_VIDEO_INFO_FORMAT (&this->v_info) == GST_VIDEO_FORMAT_UNKNOWN) - goto use_dummy_tex; - - this->mem_ = gst_buffer_peek_memory (this->buffer_, 0); - if (!this->mem_) - goto use_dummy_tex; - - /* FIXME: should really lock the memory to prevent write access */ - if (!gst_video_frame_map (&this->v_frame, &this->v_info, this->buffer_, - (GstMapFlags) (GST_MAP_READ | GST_MAP_GL))) { - // TODO(zdanek) - this happens when format of the video changes - //g_assert_not_reached (); - GST_ERROR ("Failed to map video frame"); - goto use_dummy_tex; - } - - mem = gst_buffer_peek_memory (this->buffer_, 0); - g_assert (gst_is_gl_memory (mem)); - - context = ((GstGLBaseMemory *)mem)->context; - - sync_meta = gst_buffer_get_gl_sync_meta (this->sync_buffer_); - if (!sync_meta) - sync_meta = gst_buffer_add_gl_sync_meta (context, this->sync_buffer_); - - gst_gl_sync_meta_set_sync_point (sync_meta, context); - - gst_gl_sync_meta_wait (sync_meta, qt_context); - - tex_id = *(guint *) this->v_frame.data[0]; - GST_LOG ("%p binding Qt texture %u", this, tex_id); - - texSize = QSize(GST_VIDEO_FRAME_WIDTH (&this->v_frame), GST_VIDEO_FRAME_HEIGHT (&this->v_frame)); - // XXX: ideally, we would like to subclass the relevant texture object - // ourselves but this is good enough for now - texture = QNativeInterface::QSGOpenGLTexture::fromNative(tex_id, this->window_, texSize, options); - - setTexture(texture); - setOwnsTexture(true); - markDirty(QSGNode::DirtyMaterial); - - gst_video_frame_unmap (&this->v_frame); - - /* Texture was successfully bound, so we do not need - * to use the dummy texture */ - } - - if (!texture()) { -use_dummy_tex: - /* Create dummy texture if not already present. */ - if (this->dummy_tex_ == nullptr) { - /* Make this a black 64x64 pixel RGBA texture. - * This size and format is supported pretty much everywhere, so these - * are a safe pick. (64 pixel sidelength must be supported according - * to the GLES2 spec, table 6.18.) - * Set min/mag filters to GL_LINEAR to make sure no mipmapping is used. */ - const int tex_sidelength = 64; - QImage image(tex_sidelength, tex_sidelength, QImage::Format_ARGB32); - image.fill(QColor(0, 0, 0, 255)); - - this->dummy_tex_ = this->window_->createTextureFromImage(image); - } - - g_assert (this->dummy_tex_ != nullptr); - - if (texture() != this->dummy_tex_) { - setTexture(this->dummy_tex_); - setOwnsTexture(false); - markDirty(QSGNode::DirtyMaterial); - } - - GST_LOG ("%p binding fallback dummy Qt texture %p", this, this->dummy_tex_); - } -} diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqsg6glnode.h b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqsg6glnode.h deleted file mode 100644 index a2d362d2306..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqsg6glnode.h +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2024 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -/* - * GStreamer - * Copyright (C) 2022 Matthew Waters - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#pragma once - -#include -#include - -#include "gstqt6gl.h" -#include -#include -#include -#include -#include - -class GstQSG6OpenGLNode : public QSGTextureProvider, public QSGSimpleTextureNode, protected QOpenGLFunctions -{ - Q_OBJECT - -public: - GstQSG6OpenGLNode(QQuickItem *item); - ~GstQSG6OpenGLNode(); - - QSGTexture *texture() const override; - - void setCaps(GstCaps *caps); - void setBuffer(GstBuffer *buffer); - GstBuffer *getBuffer(); - - void updateQSGTexture(); - -private: - QQuickWindow *window_; - GstBuffer * buffer_; - gboolean buffer_was_bound; - GstBuffer * sync_buffer_; - GstMemory * mem_; - QSGTexture *dummy_tex_; - GstVideoInfo v_info; - GstVideoFrame v_frame; -}; diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6element.cc b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6element.cc deleted file mode 100644 index e17eee3fa05..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6element.cc +++ /dev/null @@ -1,47 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2024 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstqt6elements.h" -#include "qt6glitem.h" -#include - -void -qt6_element_init (GstPlugin * plugin) -{ - static gsize res = FALSE; - if (g_once_init_enter (&res)) { - /* this means the plugin must be loaded before the qml engine is loaded */ - qmlRegisterType ("org.freedesktop.gstreamer.Qt6GLVideoItem", 1, 0, "GstGLQt6VideoItem"); - g_once_init_leave (&res, TRUE); - } -} diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6elements.h b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6elements.h deleted file mode 100644 index abbcf2083a1..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6elements.h +++ /dev/null @@ -1,46 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2024 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -/* - * Copyright (C) 2020 Huawei Technologies Co., Ltd. - * @Author: Julian Bouzas - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __GST_QT6_ELEMENTS_H__ -#define __GST_QT6_ELEMENTS_H__ - -#include - -G_BEGIN_DECLS - -void qt6_element_init (GstPlugin * plugin); - -// TODO(zdanek) fix after switching to gstreamer 1.20.0+ -// original code from 1.20.0 -// GST_ELEMENT_REGISTER_DECLARE (qml6glsink); -// backported to: -extern "C" { gboolean gst_element_register_qml6glsink (GstPlugin * plugin); }; - -G_END_DECLS - -#endif /* __GST_QT6_ELEMENTS_H__ */ diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6gl.h b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6gl.h deleted file mode 100644 index f7b3d658a97..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6gl.h +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2024 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#include -#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) -#include -#endif - -#include - -/* The glext.h guard was renamed in 2018, but some software which - * includes their own copy of the GL headers (such as qt) might have - * older version which use the old guard. This would result in the - * header being included again (and symbols redefined). - * - * To avoid this, we define the "old" guard if the "new" guard is - * defined.*/ -#if GST_GL_HAVE_OPENGL -#ifdef __gl_glext_h_ -#ifndef __glext_h_ -#define __glext_h_ 1 -#endif -#endif -#endif - -/* pulls in GLsync, see below */ -#include - -/* qt uses the same trick as us to typedef GLsync on GLES2 but to a different - * type which confuses the preprocessor. Instead of trying to reconcile the - * two, we instead use the GLsync definition from Qt from above, and ensure - * that we don't typedef GLsync in gstglfuncs.h */ -#undef GST_GL_HAVE_GLSYNC -#define GST_GL_HAVE_GLSYNC 1 -#include - -#if defined(QT_OPENGL_ES_2) -#include -#include -#endif /* defined(QT_OPENGL_ES_2) */ diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6glutility.cc b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6glutility.cc deleted file mode 100644 index 3367d65b29a..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6glutility.cc +++ /dev/null @@ -1,368 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2024 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -/* - * GStreamer - * Copyright (C) 2016 Freescale Semiconductor, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstqt6glutility.h" -#include -#if GST_GL_HAVE_WINDOW_X11 && defined (HAVE_QT_X11) -#include -//#include -#endif -#if GST_GL_HAVE_PLATFORM_EGL && (defined (HAVE_QT_WAYLAND) || defined (HAVE_QT_EGLFS) || defined (HAVE_QT_ANDROID)) -#include -#ifdef HAVE_QT_QPA_HEADER -#include -#endif -//#include -#include -#endif - -#if GST_GL_HAVE_WINDOW_WAYLAND && defined (HAVE_QT_WAYLAND) -#include -#endif -#if 0 -#if GST_GL_HAVE_WINDOW_VIV_FB -#include -#endif - -#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) -#include -#include -#endif -#endif -#include - -#define GST_CAT_DEFAULT qml6_gl_utils_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -G_LOCK_DEFINE_STATIC (display_lock); -static GWeakRef qt_display; -static gboolean sink_retrieved = FALSE; - -GstGLDisplay * -gst_qml6_get_gl_display (gboolean sink) -{ - GstGLDisplay *display = NULL; - QGuiApplication *app = static_cast (QCoreApplication::instance ()); - static gsize _debug; - - g_assert (app != NULL); - - if (g_once_init_enter (&_debug)) { - GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "qtglutility", 0, - "Qt gl utility functions"); - g_once_init_leave (&_debug, 1); - } - - G_LOCK (display_lock); - /* XXX: this assumes that only one display will ever be created by Qt */ - display = static_cast(g_weak_ref_get (&qt_display)); - if (display) { - if (sink_retrieved) { - GST_INFO ("returning previously created display"); - G_UNLOCK (display_lock); - return display; - } - gst_clear_object (&display); - } - if (sink) - sink_retrieved = sink; - - GST_INFO ("QGuiApplication::instance()->platformName() %s", app->platformName().toUtf8().data()); -#if GST_GL_HAVE_WINDOW_X11 && defined (HAVE_QT_X11) - if (QString::fromUtf8 ("xcb") == app->platformName()) { - auto x11_native = app->nativeInterface(); - if (x11_native) { - display = (GstGLDisplay *) - gst_gl_display_x11_new_with_display (x11_native->display()); - } - } -#endif -#if GST_GL_HAVE_WINDOW_WAYLAND && GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_WAYLAND) - if (QString::fromUtf8 ("wayland") == app->platformName() - || QString::fromUtf8 ("wayland-egl") == app->platformName()){ - struct wl_display * wayland_display; - QPlatformNativeInterface *native = - QGuiApplication::platformNativeInterface(); - wayland_display = (struct wl_display *) - native->nativeResourceForWindow("display", NULL); - display = (GstGLDisplay *) - gst_gl_display_wayland_new_with_display (wayland_display); - } -#endif -#if GST_GL_HAVE_PLATFORM_EGL && GST_GL_HAVE_WINDOW_ANDROID - if (QString::fromUtf8 ("android") == app->platformName()) { - EGLDisplay egl_display = (EGLDisplay) gst_gl_display_egl_get_from_native (GST_GL_DISPLAY_TYPE_ANY, 0); - display = (GstGLDisplay *) gst_gl_display_egl_new_with_egl_display (egl_display); - } -#elif GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_EGLFS) - if (QString::fromUtf8("eglfs") == app->platformName()) { -#if GST_GL_HAVE_WINDOW_VIV_FB - /* FIXME: Could get the display directly from Qt like this - * QPlatformNativeInterface *native = - * QGuiApplication::platformNativeInterface(); - * EGLDisplay egl_display = (EGLDisplay) - * native->nativeResourceForWindow("egldisplay", NULL); - * - * However we seem to have no way for getting the EGLNativeDisplayType, aka - * native_display, via public API. As such we have to assume that display 0 - * is always used. Only way around that is parsing the index the same way as - * Qt does in QEGLDeviceIntegration::fbDeviceName(), so let's do that. - */ - const gchar *fb_dev; - gint disp_idx = 0; - - fb_dev = g_getenv ("QT_QPA_EGLFS_FB"); - if (fb_dev) { - if (sscanf (fb_dev, "/dev/fb%d", &disp_idx) != 1) - disp_idx = 0; - } - - display = (GstGLDisplay *) gst_gl_display_viv_fb_new (disp_idx); -#elif defined(HAVE_QT_QPA_HEADER) - QPlatformNativeInterface *native = - QGuiApplication::platformNativeInterface(); - EGLDisplay egl_display = (EGLDisplay) - native->nativeResourceForWindow("egldisplay", NULL); - if (egl_display != EGL_NO_DISPLAY) - display = (GstGLDisplay *) gst_gl_display_egl_new_with_egl_display (egl_display); -#else - EGLDisplay egl_display = (EGLDisplay) gst_gl_display_egl_get_from_native (GST_GL_DISPLAY_TYPE_ANY, 0); - display = (GstGLDisplay *) gst_gl_display_egl_new_with_egl_display (egl_display); -#endif - } -#endif -#if GST_GL_HAVE_WINDOW_COCOA && GST_GL_HAVE_PLATFORM_CGL && defined (HAVE_QT_MAC) - if (QString::fromUtf8 ("cocoa") == app->platformName()) - display = (GstGLDisplay *) gst_gl_display_new (); -#endif -#if GST_GL_HAVE_WINDOW_EAGL && GST_GL_HAVE_PLATFORM_EAGL && defined (HAVE_QT_IOS) - if (QString::fromUtf8 ("ios") == app->platformName()) - display = gst_gl_display_new (); -#endif -#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) - if (QString::fromUtf8 ("windows") == app->platformName()) - display = gst_gl_display_new (); -#endif - - if (!display) - display = gst_gl_display_new (); - - g_weak_ref_set (&qt_display, display); - G_UNLOCK (display_lock); - - return display; -} - -gboolean -gst_qml6_get_gl_wrapcontext (GstGLDisplay * display, - GstGLContext **wrap_glcontext, GstGLContext **context) -{ - GstGLPlatform G_GNUC_UNUSED platform = (GstGLPlatform) 0; - GstGLAPI G_GNUC_UNUSED gl_api; - guintptr G_GNUC_UNUSED gl_handle; - GstGLContext *current; - GError *error = NULL; - - g_return_val_if_fail (display != NULL && wrap_glcontext != NULL, FALSE); -#if GST_GL_HAVE_WINDOW_X11 && defined (HAVE_QT_X11) - if (GST_IS_GL_DISPLAY_X11 (display)) { -#if GST_GL_HAVE_PLATFORM_GLX - platform = GST_GL_PLATFORM_GLX; -#elif GST_GL_HAVE_PLATFORM_EGL - platform = GST_GL_PLATFORM_EGL; -#endif - } -#endif -#if GST_GL_HAVE_WINDOW_WAYLAND && defined (HAVE_QT_WAYLAND) - if (GST_IS_GL_DISPLAY_WAYLAND (display)) { - platform = GST_GL_PLATFORM_EGL; - } -#endif -#if GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_EGLFS) -#if GST_GL_HAVE_WINDOW_VIV_FB - if (GST_IS_GL_DISPLAY_VIV_FB (display)) { -#else - if (GST_IS_GL_DISPLAY_EGL (display)) { -#endif - platform = GST_GL_PLATFORM_EGL; - } -#endif - if (platform == 0) { -#if GST_GL_HAVE_WINDOW_COCOA && GST_GL_HAVE_PLATFORM_CGL && defined (HAVE_QT_MAC) - platform = GST_GL_PLATFORM_CGL; -#elif GST_GL_HAVE_WINDOW_EAGL && GST_GL_HAVE_PLATFORM_EAGL && defined (HAVE_QT_IOS) - platform = GST_GL_PLATFORM_EAGL; -#elif GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) - platform = GST_GL_PLATFORM_WGL; -#elif GST_GL_HAVE_WINDOW_ANDROID && GST_GL_HAVE_PLATFORM_EGL && defined (HAVE_QT_ANDROID) - platform = GST_GL_PLATFORM_EGL; -#else - GST_ERROR ("Unknown platform"); - return FALSE; -#endif - } - - gl_api = gst_gl_context_get_current_gl_api (platform, NULL, NULL); - gl_handle = gst_gl_context_get_current_gl_context (platform); - - /* see if we already have a current GL context in GStreamer for this thread */ - current = gst_gl_context_get_current (); - if (current && current->display == display) { - /* just use current context we found */ - *wrap_glcontext = static_cast (gst_object_ref (current)); - } - else { - if (gl_handle) - *wrap_glcontext = - gst_gl_context_new_wrapped (display, gl_handle, - platform, gl_api); - - if (!*wrap_glcontext) { - GST_ERROR ("cannot wrap qt OpenGL context"); - return FALSE; - } - - gst_gl_context_activate(*wrap_glcontext, TRUE); - if (!gst_gl_context_fill_info (*wrap_glcontext, &error)) { - GST_ERROR ("failed to retrieve qt context info: %s", error->message); - gst_gl_context_activate(*wrap_glcontext, FALSE); - gst_clear_object (wrap_glcontext); - return FALSE; - } - - gst_gl_display_filter_gl_api (display, gst_gl_context_get_gl_api (*wrap_glcontext)); - gst_gl_context_activate (*wrap_glcontext, FALSE); - } -#if 0 -#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) - g_return_val_if_fail (context != NULL, FALSE); - - G_STMT_START { - /* If there's no wglCreateContextAttribsARB() support, then we would fallback to - * wglShareLists() which will fail with ERROR_BUSY (0xaa) if either of the GL - * contexts are current in any other thread. - * - * The workaround here is to temporarily disable Qt's GL context while we - * set up our own. - * - * Sometimes wglCreateContextAttribsARB() - * exists, but isn't functional (some Intel drivers), so it's easiest to do this - * unconditionally. - */ - - /* retrieve Qt's GL device context as current device context */ - HDC device = wglGetCurrentDC (); - - *context = gst_gl_context_new (display); - - wglMakeCurrent (NULL, NULL); - if (!gst_gl_context_create (*context, *wrap_glcontext, &error)) { - GST_ERROR ("failed to create shared GL context: %s", error->message); - gst_clear_object (wrap_glcontext); - gst_clear_object (context); - } - wglMakeCurrent (device, (HGLRC) gl_handle); - - if (!*context) - return FALSE; - - } G_STMT_END; -#endif -#endif - return TRUE; -} -#if 0 -QVariant -qt_opengl_native_context_from_gst_gl_context (GstGLContext * context) -{ - guintptr handle; - GstGLPlatform platform; - - handle = gst_gl_context_get_gl_context (context); - platform = gst_gl_context_get_gl_platform (context); - -#if GST_GL_HAVE_WINDOW_X11 && defined (HAVE_QT_X11) - if (platform == GST_GL_PLATFORM_GLX) { - GstGLDisplay *display = gst_gl_context_get_display (context); - GstGLWindow *window = gst_gl_context_get_window (context); - Display *xdisplay = (Display *) gst_gl_display_get_handle (display); - Window win = gst_gl_window_get_window_handle (window); - gst_object_unref (window); - gst_object_unref (display); - return QVariant::fromValue(QGLXNativeContext((GLXContext) handle, xdisplay, win)); - } -#endif -#if GST_GL_HAVE_PLATFORM_EGL && (defined (HAVE_QT_WAYLAND) || defined (HAVE_QT_EGLFS) || defined (HAVE_QT_ANDROID)) - if (platform == GST_GL_PLATFORM_EGL) { - EGLDisplay egl_display = EGL_DEFAULT_DISPLAY; - GstGLDisplay *display = gst_gl_context_get_display (context); - GstGLDisplayEGL *display_egl = gst_gl_display_egl_from_gl_display (display); -#if GST_GL_HAVE_WINDOW_WAYLAND && defined (HAVE_QT_WAYLAND) - if (gst_gl_display_get_handle_type (display) == GST_GL_DISPLAY_TYPE_WAYLAND) { -#if 1 - g_warning ("Qt does not support wrapping native OpenGL contexts " - "on wayland. See https://bugreports.qt.io/browse/QTBUG-82528"); - gst_object_unref (display_egl); - gst_object_unref (display); - return QVariant::fromValue(nullptr); -#else - if (display_egl) - egl_display = (EGLDisplay) gst_gl_display_get_handle ((GstGLDisplay *) display_egl); -#endif - } -#endif - gst_object_unref (display_egl); - gst_object_unref (display); - return QVariant::fromValue(QEGLNativeContext((EGLContext) handle, egl_display)); - } -#endif -#if GST_GL_HAVE_WINDOW_WIN32 && GST_GL_HAVE_PLATFORM_WGL && defined (HAVE_QT_WIN32) - if (platform == GST_GL_PLATFORM_WGL) { - GstGLWindow *window = gst_gl_context_get_window (context); - guintptr hwnd = gst_gl_window_get_window_handle (window); - gst_object_unref (window); - return QVariant::fromValue(QWGLNativeContext((HGLRC) handle, (HWND) hwnd)); - } -#endif - { - gchar *platform_s = gst_gl_platform_to_string (platform); - g_warning ("Unimplemented configuration! This means either:\n" - "1. The qmlgl plugin was built without support for your platform.\n" - "2. The necessary code to convert from a GstGLContext to Qt's " - "native context type for \'%s\' currently does not exist.", - platform_s); - g_free (platform_s); - } - return QVariant::fromValue(nullptr); -} -#endif diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6glutility.h b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6glutility.h deleted file mode 100644 index f607e55caa6..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/gstqt6glutility.h +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2024 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -/* - * GStreamer - * Copyright (C) 2016 Freescale Semiconductor, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __QML6_GL_UTILS_H__ -#define __QML6_GL_UTILS_H__ - -#include -#include - -#include -#include - -G_BEGIN_DECLS - -struct RenderJob : public QRunnable { - using Callable = std::function; - - explicit RenderJob(Callable c) : _c(c) { } - - void run() { _c(); } - -private: - Callable _c; -}; - -GstGLDisplay * gst_qml6_get_gl_display (gboolean sink); -gboolean gst_qml6_get_gl_wrapcontext (GstGLDisplay * display, - GstGLContext **wrap_glcontext, GstGLContext **context); - -G_END_DECLS - -#if 0 -#if defined(__cplusplus) -QVariant qt_opengl_native_context_from_gst_gl_context (GstGLContext * context); -#endif -#endif - -#endif /* __QML6_GL_UTILS_H__ */ diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/meson.build b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/meson.build deleted file mode 100644 index 150b0b9f222..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/meson.build +++ /dev/null @@ -1,145 +0,0 @@ -sources = [ - 'gstplugin.cc', - 'gstqt6element.cc', - 'gstqsg6glnode.cc', - 'gstqt6glutility.cc', - 'gstqml6glsink.cc', - 'qt6glitem.cc', -] - -moc_headers = [ - 'qt6glitem.h', - 'gstqsg6glnode.h', -] - -qt6qml_dep = dependency('', required: false) -qt6_option = get_option('qt6') -qt6_method = get_option('qt-method') - -if qt6_option.disabled() - subdir_done() -endif - -if not have_gstgl - if qt6_option.enabled() - error('qt6 qmlglsink plugin is enabled, but gstreamer-gl-1.0 was not found') - endif - subdir_done() -endif - -if not add_languages('cpp', native: false, required: qt6_option) - subdir_done() -endif - -qt6_mod = import('qt6') -if not qt6_mod.has_tools() - if qt6_option.enabled() - error('qt6 qmlglsink plugin is enabled, but qt specific tools were not found') - endif - subdir_done() -endif - -qt6qml_dep = dependency('qt6', modules : ['Core', 'Gui', 'Qml', 'Quick'], - method: qt6_method, required: qt6_option, static: host_system == 'ios') -if not qt6qml_dep.found() - subdir_done() -endif - -optional_deps = [] -qt_defines = [] -have_qpa_include = false -have_qt_windowing = false - -# Look for the QPA platform native interface header -qpa_header_path = join_paths(qt6qml_dep.version(), 'QtGui') -qpa_header = join_paths(qpa_header_path, 'qpa/qplatformnativeinterface.h') -if cxx.has_header(qpa_header, dependencies : qt6qml_dep) - qt_defines += '-DHAVE_QT_QPA_HEADER' - qt_defines += '-DQT_QPA_HEADER=' + '<@0@>'.format(qpa_header) - have_qpa_include = true - message('Found QtGui QPA header in ' + qpa_header_path) -endif - -# Try to come up with all the platform/winsys combinations that will work - -if gst_gl_have_window_x11 and gst_gl_have_platform_glx - # FIXME: automagic - qt_defines += ['-DHAVE_QT_X11'] - have_qt_windowing = true -endif - -if gst_gl_have_platform_egl - # Embedded linux (e.g. i.MX6) with or without windowing support - qt_defines += ['-DHAVE_QT_EGLFS'] - optional_deps += gstglegl_dep - have_qt_windowing = true - if have_qpa_include - # Wayland windowing - if gst_gl_have_window_wayland - # FIXME: automagic - qt6waylandextras = dependency('qt6', modules : ['WaylandClient'], method: qt6_method, required : false) - if qt6waylandextras.found() - optional_deps += [qt6waylandextras, gstglwayland_dep] - qt_defines += ['-DHAVE_QT_WAYLAND'] - have_qt_windowing = true - endif - endif - # Android windowing -# if gst_gl_have_window_android - # FIXME: automagic -# qt5androidextras = dependency('qt5', modules : ['AndroidExtras'], method: qt6_method, required : false) - # for gl functions in QtGui/qopenglfunctions.h - # FIXME: automagic -# glesv2_dep = cc.find_library('GLESv2', required : false) -# if glesv2_dep.found() and qt5androidextras.found() -# optional_deps += [qt5androidextras, glesv2_dep] -# qt_defines += ['-DHAVE_QT_ANDROID'] -# have_qt_windowing = true - # Needed for C++11 support in Cerbero. People building with Android - # in some other way need to add the necessary bits themselves. -# optional_deps += dependency('gnustl', required : false) -# endif -# endif - endif -endif - -#if gst_gl_have_platform_wgl and gst_gl_have_window_win32 - # for wglMakeCurrent() - # FIXME: automagic -# opengl32_dep = cc.find_library('opengl32', required : false) -# if opengl32_dep.found() -# qt_defines += ['-DHAVE_QT_WIN32'] -# optional_deps += opengl32_dep -# have_qt_windowing = true -# endif -#endif - -if gst_gl_have_window_cocoa and gst_gl_have_platform_cgl - # FIXME: automagic - if host_machine.system() == 'darwin' - qt_defines += ['-DHAVE_QT_MAC'] - have_qt_windowing = true - endif -endif - -if gst_gl_have_window_eagl and gst_gl_have_platform_eagl - if host_machine.system() == 'ios' - qt_defines += ['-DHAVE_QT_IOS'] - have_qt_windowing = true - endif -endif - -if have_qt_windowing - # Build it! - moc_files = qt6_mod.preprocess(moc_headers : moc_headers) - gstqml6gl = library('gstqml6', sources, moc_files, - cpp_args : gst_plugins_good_args + qt_defines, - link_args : noseh_link_args, - include_directories: [configinc, libsinc], - dependencies : [gst_dep, gstvideo_dep, gstgl_dep, gstglproto_dep, qt6qml_dep, optional_deps], - override_options : ['cpp_std=c++17'], - install: true, - install_dir : plugins_install_dir) - pkgconfig.generate(gstqml6gl, install_dir : plugins_pkgconfig_install_dir) - plugins += [gstqml6gl] -endif diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/qt6glitem.cc b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/qt6glitem.cc deleted file mode 100644 index cb01ca8b84e..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/qt6glitem.cc +++ /dev/null @@ -1,764 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2024 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include -#include "qt6glitem.h" -#include "gstqsg6glnode.h" -#include "gstqt6glutility.h" - -#include -#include -#include -#include -#include - -/** - * SECTION:Qt6GLVideoItem - * @short_description: a Qt5 QtQuick item that renders GStreamer video #GstBuffers - * - * #QtGLVideoItem is an #QQuickItem that renders GStreamer video buffers. - */ - -#define GST_CAT_DEFAULT qt_item_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -#define DEFAULT_FORCE_ASPECT_RATIO TRUE -#define DEFAULT_PAR_N 0 -#define DEFAULT_PAR_D 1 - -enum -{ - PROP_0, - PROP_FORCE_ASPECT_RATIO, - PROP_PIXEL_ASPECT_RATIO, -}; - -struct _Qt6GLVideoItemPrivate -{ - GMutex lock; - - /* properties */ - gboolean force_aspect_ratio; - gint par_n, par_d; - - GWeakRef sink; - - gint display_width; - gint display_height; - - GstBuffer *buffer; - GstCaps *new_caps; - GstCaps *caps; - GstVideoInfo new_v_info; - GstVideoInfo v_info; - - gboolean initted; - GstGLDisplay *display; - QOpenGLContext *qt_context; - GstGLContext *other_context; - GstGLContext *context; - - /* buffers with textures that were bound by QML */ - GQueue bound_buffers; - /* buffers that were previously bound but in the meantime a new one was - * bound so this one is most likely not used anymore - * FIXME: Ideally we would use fences for this but there seems to be no - * way to reliably "try wait" on a fence */ - GQueue potentially_unbound_buffers; - - GstQSG6OpenGLNode *m_node; -}; - -Qt6GLVideoItem::Qt6GLVideoItem() -{ - static gsize _debug; - - if (g_once_init_enter (&_debug)) { - GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "qtglwidget", 0, "Qt GL Widget"); - g_once_init_leave (&_debug, 1); - } - - this->setFlag (QQuickItem::ItemHasContents, true); - - this->priv = g_new0 (Qt6GLVideoItemPrivate, 1); - - this->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO; - this->priv->par_n = DEFAULT_PAR_N; - this->priv->par_d = DEFAULT_PAR_D; - - this->priv->initted = FALSE; - - g_mutex_init (&this->priv->lock); - - g_weak_ref_init (&priv->sink, NULL); - - this->priv->display = gst_qml6_get_gl_display(TRUE); - - connect(this, SIGNAL(windowChanged(QQuickWindow*)), this, - SLOT(handleWindowChanged(QQuickWindow*))); - - this->proxy = QSharedPointer(new Qt6GLVideoItemInterface(this)); - - setFlag(ItemHasContents, true); - setAcceptedMouseButtons(Qt::AllButtons); - setAcceptHoverEvents(true); - - setAcceptTouchEvents(true); - - GST_DEBUG ("%p init Qt6 Video Item", this); -} - -Qt6GLVideoItem::~Qt6GLVideoItem() -{ - GstBuffer *tmp_buffer; - - /* Before destroying the priv info, make sure - * no qmlglsink's will call in again, and that - * any ongoing calls are done by invalidating the proxy - * pointer */ - GST_INFO ("%p Destroying QtGLVideoItem and invalidating the proxy %p", this, proxy.data()); - proxy->invalidateRef(); - proxy.clear(); - - g_mutex_clear (&this->priv->lock); - if (this->priv->context) - gst_object_unref(this->priv->context); - if (this->priv->other_context) - gst_object_unref(this->priv->other_context); - if (this->priv->display) - gst_object_unref(this->priv->display); - - while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&this->priv->potentially_unbound_buffers))) { - GST_TRACE ("old buffer %p should be unbound now, unreffing", tmp_buffer); - gst_buffer_unref (tmp_buffer); - } - while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&this->priv->bound_buffers))) { - GST_TRACE ("old buffer %p should be unbound now, unreffing", tmp_buffer); - gst_buffer_unref (tmp_buffer); - } - - gst_buffer_replace (&this->priv->buffer, NULL); - - gst_caps_replace (&this->priv->caps, NULL); - gst_caps_replace (&this->priv->new_caps, NULL); - - g_weak_ref_clear (&this->priv->sink); - - g_free (this->priv); - this->priv = NULL; -} - -void -Qt6GLVideoItem::setDAR(gint num, gint den) -{ - this->priv->par_n = num; - this->priv->par_d = den; -} - -void -Qt6GLVideoItem::getDAR(gint * num, gint * den) -{ - if (num) - *num = this->priv->par_n; - if (den) - *den = this->priv->par_d; -} - -void -Qt6GLVideoItem::setForceAspectRatio(bool force_aspect_ratio) -{ - this->priv->force_aspect_ratio = !!force_aspect_ratio; - - emit forceAspectRatioChanged(force_aspect_ratio); -} - -bool -Qt6GLVideoItem::getForceAspectRatio() -{ - return this->priv->force_aspect_ratio; -} - -bool -Qt6GLVideoItem::itemInitialized() -{ - return this->priv->initted; -} - -static gboolean -_calculate_par (Qt6GLVideoItem * widget, GstVideoInfo * info) -{ - gboolean ok; - gint width, height; - gint par_n, par_d; - gint display_par_n, display_par_d; - guint display_ratio_num, display_ratio_den; - - width = GST_VIDEO_INFO_WIDTH (info); - height = GST_VIDEO_INFO_HEIGHT (info); - - par_n = GST_VIDEO_INFO_PAR_N (info); - par_d = GST_VIDEO_INFO_PAR_D (info); - - if (!par_n) - par_n = 1; - - /* get display's PAR */ - if (widget->priv->par_n != 0 && widget->priv->par_d != 0) { - display_par_n = widget->priv->par_n; - display_par_d = widget->priv->par_d; - } else { - display_par_n = 1; - display_par_d = 1; - } - - ok = gst_video_calculate_display_ratio (&display_ratio_num, - &display_ratio_den, width, height, par_n, par_d, display_par_n, - display_par_d); - - if (!ok) - return FALSE; - - widget->setImplicitWidth (width); - widget->setImplicitHeight (height); - - GST_LOG ("%p PAR: %u/%u DAR:%u/%u", widget, par_n, par_d, display_par_n, - display_par_d); - - if (height % display_ratio_den == 0) { - GST_DEBUG ("%p keeping video height", widget); - widget->priv->display_width = (guint) - gst_util_uint64_scale_int (height, display_ratio_num, - display_ratio_den); - widget->priv->display_height = height; - } else if (width % display_ratio_num == 0) { - GST_DEBUG ("%p keeping video width", widget); - widget->priv->display_width = width; - widget->priv->display_height = (guint) - gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num); - } else { - GST_DEBUG ("%p approximating while keeping video height", widget); - widget->priv->display_width = (guint) - gst_util_uint64_scale_int (height, display_ratio_num, - display_ratio_den); - widget->priv->display_height = height; - } - GST_DEBUG ("%p scaling to %dx%d", widget, widget->priv->display_width, - widget->priv->display_height); - - return TRUE; -} - -QSGNode * -Qt6GLVideoItem::updatePaintNode(QSGNode * oldNode, - UpdatePaintNodeData * updatePaintNodeData) -{ - GstBuffer *old_buffer; - - if (!this->priv->initted) - return oldNode; - - GstQSG6OpenGLNode *texNode = static_cast (oldNode); - GstVideoRectangle src, dst, result; - - g_mutex_lock (&this->priv->lock); - - GST_TRACE ("%p updatePaintNode", this); - - if (gst_gl_context_get_current() == NULL) - gst_gl_context_activate (this->priv->other_context, TRUE); - - if (!texNode) { - texNode = new GstQSG6OpenGLNode (this); - this->priv->m_node = texNode; - } - - if ((old_buffer = texNode->getBuffer())) { - if (old_buffer == this->priv->buffer) { - /* same buffer */ - gst_buffer_unref (old_buffer); - } else { - GstBuffer *tmp_buffer; - - GST_TRACE ("old buffer %p was bound, queueing up for later", old_buffer); - /* Unref all buffers that were previously not bound anymore. At least - * one more buffer was bound in the meantime so this one is most likely - * not in use anymore. */ - while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&this->priv->potentially_unbound_buffers))) { - GST_TRACE ("old buffer %p should be unbound now, unreffing", tmp_buffer); - gst_buffer_unref (tmp_buffer); - } - - /* Move previous bound buffers to the next queue. We now know that - * another buffer was bound in the meantime and will free them on - * the next iteration above. */ - while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&this->priv->bound_buffers))) { - GST_TRACE ("old buffer %p is potentially unbound now", tmp_buffer); - g_queue_push_tail (&this->priv->potentially_unbound_buffers, tmp_buffer); - } - g_queue_push_tail (&this->priv->bound_buffers, old_buffer); - } - old_buffer = NULL; - } - - texNode->setCaps (this->priv->caps); - texNode->setBuffer (this->priv->buffer); - - if (this->priv->force_aspect_ratio && this->priv->caps) { - src.w = this->priv->display_width; - src.h = this->priv->display_height; - - dst.x = boundingRect().x(); - dst.y = boundingRect().y(); - dst.w = boundingRect().width(); - dst.h = boundingRect().height(); - - gst_video_sink_center_rect (src, dst, &result, TRUE); - } else { - result.x = boundingRect().x(); - result.y = boundingRect().y(); - result.w = boundingRect().width(); - result.h = boundingRect().height(); - } - - texNode->setRect (QRectF (result.x, result.y, result.w, result.h)); - - g_mutex_unlock (&this->priv->lock); - - return texNode; -} - -/* This method has to be invoked with the the priv->lock taken */ -void -Qt6GLVideoItem::fitStreamToAllocatedSize(GstVideoRectangle * result) -{ - if (this->priv->force_aspect_ratio) { - GstVideoRectangle src, dst; - - src.x = 0; - src.y = 0; - src.w = this->priv->display_width; - src.h = this->priv->display_height; - - dst.x = 0; - dst.y = 0; - dst.w = width(); - dst.h = height(); - - gst_video_sink_center_rect (src, dst, result, TRUE); - } else { - result->x = 0; - result->y = 0; - result->w = width(); - result->h = height(); - } -} - -/* This method has to be invoked with the the priv->lock taken */ -QPointF -Qt6GLVideoItem::mapPointToStreamSize(QPointF pos) -{ - gdouble stream_width, stream_height; - GstVideoRectangle result; - double stream_x, stream_y; - double x, y; - - fitStreamToAllocatedSize(&result); - - stream_width = (gdouble) GST_VIDEO_INFO_WIDTH (&this->priv->v_info); - stream_height = (gdouble) GST_VIDEO_INFO_HEIGHT (&this->priv->v_info); - x = pos.x(); - y = pos.y(); - - /* from display coordinates to stream coordinates */ - if (result.w > 0) - stream_x = (x - result.x) / result.w * stream_width; - else - stream_x = 0.; - - /* clip to stream size */ - stream_x = CLAMP(stream_x, 0., stream_width); - - /* same for y-axis */ - if (result.h > 0) - stream_y = (y - result.y) / result.h * stream_height; - else - stream_y = 0.; - - stream_y = CLAMP(stream_y, 0., stream_height); - GST_TRACE ("transform %fx%f into %fx%f", x, y, stream_x, stream_y); - - return QPointF(stream_x, stream_y); -} - -void -Qt6GLVideoItem::wheelEvent(QWheelEvent * event) -{ - // noop -} - -void -Qt6GLVideoItem::hoverEnterEvent(QHoverEvent *) -{ - mouseHovering = true; -} - -void -Qt6GLVideoItem::hoverLeaveEvent(QHoverEvent *) -{ - mouseHovering = false; -} - -void -Qt6GLVideoItem::hoverMoveEvent(QHoverEvent * event) -{ - // noop -} - -void -Qt6GLVideoItem::touchEvent(QTouchEvent * event) -{ - // noop -} - -void -Qt6GLVideoItem::sendMouseEvent(QMouseEvent * event, gboolean is_press) -{ - // noop -} - -void -Qt6GLVideoItem::mousePressEvent(QMouseEvent * event) -{ - forceActiveFocus(); - sendMouseEvent(event, TRUE); -} - -void -Qt6GLVideoItem::mouseReleaseEvent(QMouseEvent * event) -{ - sendMouseEvent(event, FALSE); -} - -void -Qt6GLVideoItemInterface::setSink (GstElement * sink) -{ - QMutexLocker locker(&lock); - if (qt_item == NULL) - return; - - g_mutex_lock (&qt_item->priv->lock); - g_weak_ref_set (&qt_item->priv->sink, sink); - g_mutex_unlock (&qt_item->priv->lock); -} - -void -Qt6GLVideoItemInterface::setBuffer (GstBuffer * buffer) -{ - QMutexLocker locker(&lock); - - if (qt_item == NULL) { - GST_WARNING ("%p actual item is NULL. setBuffer call ignored", this); - return; - } - - if (!qt_item->priv->caps && !qt_item->priv->new_caps) { - GST_WARNING ("%p Got buffer on unnegotiated QtGLVideoItem. Dropping", this); - return; - } - - g_mutex_lock (&qt_item->priv->lock); - - if (qt_item->priv->new_caps) { - GST_DEBUG ("%p caps change from %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT, - this, qt_item->priv->caps, qt_item->priv->new_caps); - gst_caps_take (&qt_item->priv->caps, qt_item->priv->new_caps); - qt_item->priv->new_caps = NULL; - qt_item->priv->v_info = qt_item->priv->new_v_info; - - if (!_calculate_par (qt_item, &qt_item->priv->v_info)) { - g_mutex_unlock (&qt_item->priv->lock); - return; - } - } - - gst_buffer_replace (&qt_item->priv->buffer, buffer); - - QMetaObject::invokeMethod(qt_item, "update", Qt::QueuedConnection); - - g_mutex_unlock (&qt_item->priv->lock); -} - -void -Qt6GLVideoItem::onSceneGraphInitialized () -{ - QSGRendererInterface *renderer; - QOpenGLContext *gl_context; - - if (this->window() == NULL) - return; - - renderer = this->window()->rendererInterface(); - if (!renderer) - return; - - if (renderer->graphicsApi() != QSGRendererInterface::GraphicsApi::OpenGL) { - GST_WARNING ("%p scene graph initialized with a non-OpenGL renderer interface", this); - return; - } - - gl_context = - static_cast ( - renderer->getResource( - this->window(), - QSGRendererInterface::Resource::OpenGLContextResource)); - - GST_DEBUG ("%p scene graph initialization with Qt GL context %p", this, - gl_context); - - if (this->priv->qt_context == gl_context) - return; - - this->priv->qt_context = gl_context; - if (this->priv->qt_context == NULL) { - GST_ERROR ("%p failed to retrieve Qt GL context", this); - g_assert_not_reached (); - return; - } - - this->priv->initted = gst_qml6_get_gl_wrapcontext (this->priv->display, - &this->priv->other_context, &this->priv->context); - - GST_DEBUG ("%p created wrapped GL context %" GST_PTR_FORMAT, this, - this->priv->other_context); - - emit itemInitializedChanged(); -} - -void -Qt6GLVideoItem::onSceneGraphInvalidated () -{ - this->priv->m_node = nullptr; - GST_FIXME ("%p scene graph invalidated", this); -} - -/** - * Retrieve and populate the GL context information from the current - * OpenGL context. - */ -gboolean -Qt6GLVideoItemInterface::initWinSys () -{ - QMutexLocker locker(&lock); - - GError *error = NULL; - - if (qt_item == NULL) - return FALSE; - - g_mutex_lock (&qt_item->priv->lock); - - if (qt_item->priv->display && qt_item->priv->qt_context - && qt_item->priv->other_context && qt_item->priv->context) { - /* already have the necessary state */ - g_mutex_unlock (&qt_item->priv->lock); - return TRUE; - } - - if (!GST_IS_GL_DISPLAY (qt_item->priv->display)) { - GST_ERROR ("%p failed to retrieve display connection %" GST_PTR_FORMAT, - qt_item, qt_item->priv->display); - g_mutex_unlock (&qt_item->priv->lock); - return FALSE; - } - - if (!GST_IS_GL_CONTEXT (qt_item->priv->other_context)) { - GST_ERROR ("%p failed to retrieve wrapped context %" GST_PTR_FORMAT, qt_item, - qt_item->priv->other_context); - g_mutex_unlock (&qt_item->priv->lock); - return FALSE; - } - - qt_item->priv->context = gst_gl_context_new (qt_item->priv->display); - - if (!qt_item->priv->context) { - g_mutex_unlock (&qt_item->priv->lock); - return FALSE; - } - - if (!gst_gl_context_create (qt_item->priv->context, qt_item->priv->other_context, - &error)) { - GST_ERROR ("%s", error->message); - g_mutex_unlock (&qt_item->priv->lock); - return FALSE; - } - - g_mutex_unlock (&qt_item->priv->lock); - return TRUE; -} - -void -Qt6GLVideoItem::handleWindowChanged (QQuickWindow * win) -{ - if (win) { - if (win->isSceneGraphInitialized ()) - win->scheduleRenderJob (new RenderJob (std:: - bind (&Qt6GLVideoItem::onSceneGraphInitialized, this)), - QQuickWindow::BeforeSynchronizingStage); - else - connect (win, SIGNAL (sceneGraphInitialized ()), this, - SLOT (onSceneGraphInitialized ()), Qt::DirectConnection); - - connect (win, SIGNAL (sceneGraphInvalidated ()), this, - SLOT (onSceneGraphInvalidated ()), Qt::DirectConnection); - } else { - this->priv->qt_context = NULL; - this->priv->initted = FALSE; - } - this->priv->m_node = nullptr; -} - -void -Qt6GLVideoItem::releaseResources() -{ - this->priv->m_node = nullptr; -} - -gboolean -Qt6GLVideoItemInterface::setCaps (GstCaps * caps) -{ - QMutexLocker locker(&lock); - GstVideoInfo v_info; - - g_return_val_if_fail (GST_IS_CAPS (caps), FALSE); - g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE); - - if (qt_item == NULL) - return FALSE; - - if (qt_item->priv->caps && gst_caps_is_equal_fixed (qt_item->priv->caps, caps)) - return TRUE; - - if (!gst_video_info_from_caps (&v_info, caps)) - return FALSE; - - g_mutex_lock (&qt_item->priv->lock); - - GST_DEBUG ("%p set caps %" GST_PTR_FORMAT, qt_item, caps); - - gst_caps_replace (&qt_item->priv->new_caps, caps); - - qt_item->priv->new_v_info = v_info; - - g_mutex_unlock (&qt_item->priv->lock); - - return TRUE; -} - -GstGLContext * -Qt6GLVideoItemInterface::getQtContext () -{ - QMutexLocker locker(&lock); - - if (!qt_item || !qt_item->priv->other_context) - return NULL; - - return (GstGLContext *) gst_object_ref (qt_item->priv->other_context); -} - -GstGLContext * -Qt6GLVideoItemInterface::getContext () -{ - QMutexLocker locker(&lock); - - if (!qt_item || !qt_item->priv->context) - return NULL; - - return (GstGLContext *) gst_object_ref (qt_item->priv->context); -} - -GstGLDisplay * -Qt6GLVideoItemInterface::getDisplay() -{ - QMutexLocker locker(&lock); - - if (!qt_item || !qt_item->priv->display) - return NULL; - - return (GstGLDisplay *) gst_object_ref (qt_item->priv->display); -} - -void -Qt6GLVideoItemInterface::setDAR(gint num, gint den) -{ - QMutexLocker locker(&lock); - if (!qt_item) - return; - qt_item->setDAR(num, den); -} - -void -Qt6GLVideoItemInterface::getDAR(gint * num, gint * den) -{ - QMutexLocker locker(&lock); - if (!qt_item) - return; - qt_item->getDAR (num, den); -} - -void -Qt6GLVideoItemInterface::setForceAspectRatio(bool force_aspect_ratio) -{ - QMutexLocker locker(&lock); - if (!qt_item) - return; - qt_item->setForceAspectRatio(force_aspect_ratio); -} - -bool -Qt6GLVideoItemInterface::getForceAspectRatio() -{ - QMutexLocker locker(&lock); - if (!qt_item) - return FALSE; - return qt_item->getForceAspectRatio(); -} - -void -Qt6GLVideoItemInterface::invalidateRef() -{ - QMutexLocker locker(&lock); - qt_item = NULL; -} - diff --git a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/qt6glitem.h b/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/qt6glitem.h deleted file mode 100644 index 764fba4dbcf..00000000000 --- a/src/VideoManager/VideoReceiver/GStreamer/gstqml6gl/qt6/qt6glitem.h +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2024 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - -/* - * GStreamer - * Copyright (C) 2015 Matthew Waters - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __QT6_GL_ITEM_H__ -#define __QT6_GL_ITEM_H__ - -#include -#include - -#include "gstqt6gl.h" -#include -#include -#include -#include -#include - -typedef struct _Qt6GLVideoItemPrivate Qt6GLVideoItemPrivate; - -class Qt6GLVideoItem; - -class Qt6GLVideoItemInterface : public QObject -{ - Q_OBJECT - QML_ELEMENT -public: - Qt6GLVideoItemInterface (Qt6GLVideoItem *w) : qt_item (w), lock() {}; - - void invalidateRef(); - - void setSink (GstElement * sink); - void setBuffer (GstBuffer * buffer); - gboolean setCaps (GstCaps *caps); - gboolean initWinSys (); - GstGLContext *getQtContext(); - GstGLContext *getContext(); - GstGLDisplay *getDisplay(); - Qt6GLVideoItem *videoItem () { return qt_item; }; - - void setDAR(gint, gint); - void getDAR(gint *, gint *); - void setForceAspectRatio(bool); - bool getForceAspectRatio(); -private: - Qt6GLVideoItem *qt_item; - QMutex lock; -}; - -class Qt6GLVideoItem : public QQuickItem, protected QOpenGLFunctions -{ - Q_OBJECT - QML_ELEMENT - - Q_PROPERTY(bool itemInitialized - READ itemInitialized - NOTIFY itemInitializedChanged) - Q_PROPERTY(bool forceAspectRatio - READ getForceAspectRatio - WRITE setForceAspectRatio - NOTIFY forceAspectRatioChanged) - -public: - Qt6GLVideoItem(); - ~Qt6GLVideoItem(); - - void setDAR(gint, gint); - void getDAR(gint *, gint *); - void setForceAspectRatio(bool); - bool getForceAspectRatio(); - bool itemInitialized(); - - QSharedPointer getInterface() { return proxy; }; - /* private for C interface ... */ - Qt6GLVideoItemPrivate *priv; - -Q_SIGNALS: - void itemInitializedChanged(); - void forceAspectRatioChanged(bool); - -private Q_SLOTS: - void handleWindowChanged(QQuickWindow * win); - void onSceneGraphInitialized(); - void onSceneGraphInvalidated(); - -protected: - QSGNode * updatePaintNode (QSGNode * oldNode, UpdatePaintNodeData * updatePaintNodeData) override; - void releaseResources() override; - void wheelEvent(QWheelEvent *) override; - void hoverEnterEvent(QHoverEvent *) override; - void hoverLeaveEvent (QHoverEvent *) override; - void hoverMoveEvent (QHoverEvent *) override; - void mousePressEvent(QMouseEvent*) override; - void mouseReleaseEvent(QMouseEvent*) override; - void touchEvent(QTouchEvent*) override; - -private: - - void setViewportSize(const QSize &size); - void shareContext(); - - void fitStreamToAllocatedSize(GstVideoRectangle * result); - QPointF mapPointToStreamSize(QPointF); - - void sendMouseEvent(QMouseEvent * event, gboolean is_press); - - quint32 mousePressedButton; - bool mouseHovering; - - QSharedPointer proxy; -}; - -#endif /* __QT_GL_ITEM_H__ */