diff options
Diffstat (limited to 'src/gsttools')
48 files changed, 0 insertions, 12458 deletions
diff --git a/src/gsttools/gsttools.pro b/src/gsttools/gsttools.pro deleted file mode 100644 index 0127cbe92..000000000 --- a/src/gsttools/gsttools.pro +++ /dev/null @@ -1,104 +0,0 @@ -TARGET = QtMultimediaGstTools -MODULE = multimediagsttools -CONFIG += internal_module - -QT = core-private multimedia-private gui-private - -!static:DEFINES += QT_MAKEDLL -DEFINES += GLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_26 - -qtConfig(alsa): \ - QMAKE_USE += alsa - -QMAKE_USE += gstreamer - -qtConfig(resourcepolicy): \ - QMAKE_USE += libresourceqt5 - -PRIVATE_HEADERS += \ - qgstreamerbushelper_p.h \ - qgstreamermessage_p.h \ - qgstutils_p.h \ - qgstvideobuffer_p.h \ - qgstreamerbufferprobe_p.h \ - qgstreamervideorendererinterface_p.h \ - qgstreameraudioinputselector_p.h \ - qgstreamervideorenderer_p.h \ - qgstreamervideoinputdevicecontrol_p.h \ - qgstcodecsinfo_p.h \ - qgstreamervideoprobecontrol_p.h \ - qgstreameraudioprobecontrol_p.h \ - qgstreamervideowindow_p.h \ - qgstreamervideooverlay_p.h \ - qgsttools_global_p.h \ - qgstreamerplayersession_p.h \ - qgstreamerplayercontrol_p.h - -SOURCES += \ - qgstreamerbushelper.cpp \ - qgstreamermessage.cpp \ - qgstutils.cpp \ - qgstvideobuffer.cpp \ - qgstreamerbufferprobe.cpp \ - qgstreamervideorendererinterface.cpp \ - qgstreameraudioinputselector.cpp \ - qgstreamervideorenderer.cpp \ - qgstreamervideoinputdevicecontrol.cpp \ - qgstcodecsinfo.cpp \ - qgstreamervideoprobecontrol.cpp \ - qgstreameraudioprobecontrol.cpp \ - qgstreamervideowindow.cpp \ - qgstreamervideooverlay.cpp \ - qgstreamerplayersession.cpp \ - qgstreamerplayercontrol.cpp - -qtHaveModule(widgets) { - QT += multimediawidgets - - PRIVATE_HEADERS += \ - qgstreamervideowidget_p.h - - SOURCES += \ - qgstreamervideowidget.cpp -} - -qtConfig(gstreamer_0_10) { - PRIVATE_HEADERS += \ - qgstbufferpoolinterface_p.h \ - qvideosurfacegstsink_p.h \ - gstvideoconnector_p.h - - SOURCES += \ - qgstbufferpoolinterface.cpp \ - qvideosurfacegstsink.cpp \ - gstvideoconnector.c -} else { - PRIVATE_HEADERS += \ - qgstvideorendererplugin_p.h \ - qgstvideorenderersink_p.h - - SOURCES += \ - qgstvideorendererplugin.cpp \ - qgstvideorenderersink.cpp -} - -qtConfig(gstreamer_gl): QMAKE_USE += gstreamer_gl - -qtConfig(gstreamer_app) { - QMAKE_USE += gstreamer_app - PRIVATE_HEADERS += qgstappsrc_p.h - SOURCES += qgstappsrc.cpp -} - -android { - LIBS_PRIVATE += \ - -L$$(GSTREAMER_ROOT_ANDROID)/armv7/lib \ - -Wl,--whole-archive \ - -lgstapp-1.0 -lgstreamer-1.0 -lgstaudio-1.0 -lgsttag-1.0 -lgstvideo-1.0 -lgstbase-1.0 -lgstpbutils-1.0 \ - -lgobject-2.0 -lgmodule-2.0 -lglib-2.0 -lffi -lintl -liconv -lorc-0.4 \ - -Wl,--no-whole-archive -} - -HEADERS += $$PRIVATE_HEADERS - -load(qt_module) diff --git a/src/gsttools/gstvideoconnector.c b/src/gsttools/gstvideoconnector.c deleted file mode 100644 index b85f5bdbe..000000000 --- a/src/gsttools/gstvideoconnector.c +++ /dev/null @@ -1,471 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "gstvideoconnector_p.h" -#include <unistd.h> - -/* signals */ -enum -{ - SIGNAL_RESEND_NEW_SEGMENT, - SIGNAL_CONNECTION_FAILED, - LAST_SIGNAL -}; -static guint gst_video_connector_signals[LAST_SIGNAL] = { 0 }; - - -GST_DEBUG_CATEGORY_STATIC (video_connector_debug); -#define GST_CAT_DEFAULT video_connector_debug - -static GstStaticPadTemplate gst_video_connector_sink_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static GstStaticPadTemplate gst_video_connector_src_factory = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -#define _do_init(bla) \ - GST_DEBUG_CATEGORY_INIT (video_connector_debug, \ - "video-connector", 0, "An identity like element for reconnecting video stream"); - -GST_BOILERPLATE_FULL (GstVideoConnector, gst_video_connector, GstElement, - GST_TYPE_ELEMENT, _do_init); - -static void gst_video_connector_dispose (GObject * object); -static GstFlowReturn gst_video_connector_chain (GstPad * pad, GstBuffer * buf); -static GstFlowReturn gst_video_connector_buffer_alloc (GstPad * pad, - guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); -static GstStateChangeReturn gst_video_connector_change_state (GstElement * - element, GstStateChange transition); -static gboolean gst_video_connector_handle_sink_event (GstPad * pad, - GstEvent * event); -static gboolean gst_video_connector_new_buffer_probe(GstObject *pad, GstBuffer *buffer, guint * object); -static void gst_video_connector_resend_new_segment(GstElement * element, gboolean emitFailedSignal); -static gboolean gst_video_connector_setcaps (GstPad *pad, GstCaps *caps); -static GstCaps *gst_video_connector_getcaps (GstPad * pad); -static gboolean gst_video_connector_acceptcaps (GstPad * pad, GstCaps * caps); - -static void -gst_video_connector_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details_simple (element_class, "Video Connector", - "Generic", - "An identity like element used for reconnecting video stream", - "Dmytro Poplavskiy <dmytro.poplavskiy@nokia.com>"); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_video_connector_sink_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_video_connector_src_factory)); -} - -static void -gst_video_connector_class_init (GstVideoConnectorClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->dispose = gst_video_connector_dispose; - gstelement_class->change_state = gst_video_connector_change_state; - klass->resend_new_segment = gst_video_connector_resend_new_segment; - - gst_video_connector_signals[SIGNAL_RESEND_NEW_SEGMENT] = - g_signal_new ("resend-new-segment", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstVideoConnectorClass, resend_new_segment), NULL, NULL, - g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); - - gst_video_connector_signals[SIGNAL_CONNECTION_FAILED] = - g_signal_new ("connection-failed", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); -} - -static void -gst_video_connector_init (GstVideoConnector *element, - GstVideoConnectorClass *g_class) -{ - (void) g_class; - element->sinkpad = - gst_pad_new_from_static_template (&gst_video_connector_sink_factory, - "sink"); - gst_pad_set_chain_function(element->sinkpad, - GST_DEBUG_FUNCPTR (gst_video_connector_chain)); - gst_pad_set_event_function(element->sinkpad, - GST_DEBUG_FUNCPTR (gst_video_connector_handle_sink_event)); - gst_pad_set_bufferalloc_function(element->sinkpad, - GST_DEBUG_FUNCPTR (gst_video_connector_buffer_alloc)); - gst_pad_set_setcaps_function(element->sinkpad, - GST_DEBUG_FUNCPTR (gst_video_connector_setcaps)); - gst_pad_set_getcaps_function(element->sinkpad, - GST_DEBUG_FUNCPTR(gst_video_connector_getcaps)); - gst_pad_set_acceptcaps_function(element->sinkpad, - GST_DEBUG_FUNCPTR(gst_video_connector_acceptcaps)); - - gst_element_add_pad (GST_ELEMENT (element), element->sinkpad); - - element->srcpad = - gst_pad_new_from_static_template (&gst_video_connector_src_factory, - "src"); - gst_pad_add_buffer_probe(element->srcpad, - G_CALLBACK(gst_video_connector_new_buffer_probe), element); - gst_element_add_pad (GST_ELEMENT (element), element->srcpad); - - element->relinked = FALSE; - element->failedSignalEmited = FALSE; - gst_segment_init (&element->segment, GST_FORMAT_TIME); - element->latest_buffer = NULL; -} - -static void -gst_video_connector_reset (GstVideoConnector * element) -{ - element->relinked = FALSE; - element->failedSignalEmited = FALSE; - if (element->latest_buffer != NULL) { - gst_buffer_unref (element->latest_buffer); - element->latest_buffer = NULL; - } - gst_segment_init (&element->segment, GST_FORMAT_UNDEFINED); -} - -static void -gst_video_connector_dispose (GObject * object) -{ - GstVideoConnector *element = GST_VIDEO_CONNECTOR (object); - - gst_video_connector_reset (element); - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -// "When this function returns anything else than GST_FLOW_OK, -// the buffer allocation failed and buf does not contain valid data." -static GstFlowReturn -gst_video_connector_buffer_alloc (GstPad * pad, guint64 offset, guint size, - GstCaps * caps, GstBuffer ** buf) -{ - GstVideoConnector *element; - GstFlowReturn res = GST_FLOW_OK; - element = GST_VIDEO_CONNECTOR (GST_PAD_PARENT (pad)); - - if (!buf) - return GST_FLOW_ERROR; - *buf = NULL; - - gboolean isFailed = FALSE; - while (1) { - GST_OBJECT_LOCK (element); - gst_object_ref(element->srcpad); - GST_OBJECT_UNLOCK (element); - - // Check if downstream element is in NULL state - // and wait for up to 1 second for it to switch. - GstPad *peerPad = gst_pad_get_peer(element->srcpad); - if (peerPad) { - GstElement *parent = gst_pad_get_parent_element(peerPad); - gst_object_unref (peerPad); - if (parent) { - GstState state; - GstState pending; - int totalTimeout = 0; - // This seems to sleep for about 10ms usually. - while (totalTimeout < 1000000) { - gst_element_get_state(parent, &state, &pending, 0); - if (state != GST_STATE_NULL) - break; - usleep(5000); - totalTimeout += 5000; - } - - gst_object_unref (parent); - if (state == GST_STATE_NULL) { - GST_DEBUG_OBJECT (element, "Downstream element is in NULL state"); - // Downstream filter seems to be in the wrong state - return GST_FLOW_UNEXPECTED; - } - } - } - - res = gst_pad_alloc_buffer(element->srcpad, offset, size, caps, buf); - gst_object_unref (element->srcpad); - - GST_DEBUG_OBJECT (element, "buffer alloc finished: %s", gst_flow_get_name (res)); - - if (res == GST_FLOW_WRONG_STATE) { - // Just in case downstream filter is still somehow in the wrong state. - // Pipeline stalls if we report GST_FLOW_WRONG_STATE. - return GST_FLOW_UNEXPECTED; - } - - if (res >= GST_FLOW_OK || isFailed == TRUE) - break; - - //if gst_pad_alloc_buffer failed, emit "connection-failed" signal - //so colorspace transformation element can be inserted - GST_INFO_OBJECT(element, "gst_video_connector_buffer_alloc failed, emit connection-failed signal"); - g_signal_emit(G_OBJECT(element), gst_video_connector_signals[SIGNAL_CONNECTION_FAILED], 0); - isFailed = TRUE; - } - - return res; -} - -static gboolean -gst_video_connector_setcaps (GstPad *pad, GstCaps *caps) -{ - GstVideoConnector *element; - element = GST_VIDEO_CONNECTOR (GST_PAD_PARENT (pad)); - - /* forward-negotiate */ - gboolean res = gst_pad_set_caps(element->srcpad, caps); - - gchar * debugmsg = NULL; - GST_DEBUG_OBJECT(element, "gst_video_connector_setcaps %s %i", debugmsg = gst_caps_to_string(caps), res); - if (debugmsg) - g_free(debugmsg); - - if (!res) { - //if set_caps failed, emit "connection-failed" signal - //so colorspace transformation element can be inserted - GST_INFO_OBJECT(element, "gst_video_connector_setcaps failed, emit connection-failed signal"); - g_signal_emit(G_OBJECT(element), gst_video_connector_signals[SIGNAL_CONNECTION_FAILED], 0); - - return gst_pad_set_caps(element->srcpad, caps); - } - - return TRUE; -} - -static GstCaps *gst_video_connector_getcaps (GstPad * pad) -{ - GstVideoConnector *element; - element = GST_VIDEO_CONNECTOR (GST_PAD_PARENT (pad)); - -#if (GST_VERSION_MICRO > 25) - GstCaps *caps = gst_pad_peer_get_caps_reffed(element->srcpad); -#else - GstCaps *caps = gst_pad_peer_get_caps(element->srcpad); -#endif - - if (!caps) - caps = gst_caps_new_any(); - - return caps; -} - -static gboolean gst_video_connector_acceptcaps (GstPad * pad, GstCaps * caps) -{ - GstVideoConnector *element; - element = GST_VIDEO_CONNECTOR (GST_PAD_PARENT (pad)); - - return gst_pad_peer_accept_caps(element->srcpad, caps); -} - -static void -gst_video_connector_resend_new_segment(GstElement * element, gboolean emitFailedSignal) -{ - GST_INFO_OBJECT(element, "New segment requested, failed signal enabled: %i", emitFailedSignal); - GstVideoConnector *connector = GST_VIDEO_CONNECTOR(element); - connector->relinked = TRUE; - if (emitFailedSignal) - connector->failedSignalEmited = FALSE; -} - - -static gboolean gst_video_connector_new_buffer_probe(GstObject *pad, GstBuffer *buffer, guint * object) -{ - (void) pad; - (void) buffer; - - GstVideoConnector *element = GST_VIDEO_CONNECTOR (object); - - /* - If relinking is requested, the current buffer should be rejected and - the new segment + previous buffer should be pushed first - */ - - if (element->relinked) - GST_LOG_OBJECT(element, "rejected buffer because of new segment request"); - - return !element->relinked; -} - - -static GstFlowReturn -gst_video_connector_chain (GstPad * pad, GstBuffer * buf) -{ - GstFlowReturn res; - GstVideoConnector *element; - - element = GST_VIDEO_CONNECTOR (gst_pad_get_parent (pad)); - - do { - /* - Resend the segment message and last buffer to preroll the new sink. - Sinks can be changed multiple times while paused, - while loop allows to send the segment message and preroll - all of them with the same buffer. - */ - while (element->relinked) { - element->relinked = FALSE; - - gint64 pos = element->segment.last_stop; - - if (element->latest_buffer && GST_BUFFER_TIMESTAMP_IS_VALID(element->latest_buffer)) { - pos = GST_BUFFER_TIMESTAMP (element->latest_buffer); - } - - //push a new segment and last buffer - GstEvent *ev = gst_event_new_new_segment (TRUE, - element->segment.rate, - element->segment.format, - pos, //start - element->segment.stop, - pos); - - GST_DEBUG_OBJECT (element, "Pushing new segment event"); - if (!gst_pad_push_event (element->srcpad, ev)) { - GST_WARNING_OBJECT (element, - "Newsegment handling failed in %" GST_PTR_FORMAT, - element->srcpad); - } - - if (element->latest_buffer) { - GST_DEBUG_OBJECT (element, "Pushing latest buffer..."); - gst_buffer_ref(element->latest_buffer); - gst_pad_push(element->srcpad, element->latest_buffer); - } - } - - gst_buffer_ref(buf); - - //it's possible video sink is changed during gst_pad_push blocked by - //pad lock, in this case ( element->relinked == TRUE ) - //the buffer should be rejected by the buffer probe and - //the new segment + prev buffer should be sent before - - GST_LOG_OBJECT (element, "Pushing buffer..."); - res = gst_pad_push (element->srcpad, buf); - GST_LOG_OBJECT (element, "Pushed buffer: %s", gst_flow_get_name (res)); - - //if gst_pad_push failed give the service another chance, - //it may still work with the colorspace element added - if (!element->failedSignalEmited && res == GST_FLOW_NOT_NEGOTIATED) { - element->failedSignalEmited = TRUE; - GST_INFO_OBJECT(element, "gst_pad_push failed, emit connection-failed signal"); - g_signal_emit(G_OBJECT(element), gst_video_connector_signals[SIGNAL_CONNECTION_FAILED], 0); - } - - } while (element->relinked); - - - if (element->latest_buffer) { - gst_buffer_unref (element->latest_buffer); - element->latest_buffer = NULL; - } - - element->latest_buffer = gst_buffer_ref(buf); - - gst_buffer_unref(buf); - gst_object_unref (element); - - return res; -} - -static GstStateChangeReturn -gst_video_connector_change_state (GstElement * element, - GstStateChange transition) -{ - GstVideoConnector *connector; - GstStateChangeReturn result; - - connector = GST_VIDEO_CONNECTOR(element); - result = GST_ELEMENT_CLASS (parent_class)->change_state(element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_video_connector_reset (connector); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - connector->relinked = FALSE; - break; - default: - break; - } - - return result; -} - -static gboolean -gst_video_connector_handle_sink_event (GstPad * pad, GstEvent * event) -{ - if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) { - GstVideoConnector *element = GST_VIDEO_CONNECTOR (gst_pad_get_parent (pad)); - - gboolean update; - GstFormat format; - gdouble rate, arate; - gint64 start, stop, time; - - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, - &start, &stop, &time); - - GST_LOG_OBJECT (element, - "NEWSEGMENT update %d, rate %lf, applied rate %lf, " - "format %d, " "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %" - G_GINT64_FORMAT, update, rate, arate, format, start, stop, time); - - gst_segment_set_newsegment_full (&element->segment, update, - rate, arate, format, start, stop, time); - - gst_object_unref (element); - } - - return gst_pad_event_default (pad, event); -} diff --git a/src/gsttools/gstvideoconnector_p.h b/src/gsttools/gstvideoconnector_p.h deleted file mode 100644 index a38ca2e65..000000000 --- a/src/gsttools/gstvideoconnector_p.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTVIDEOCONNECTOR_H -#define QGSTVIDEOCONNECTOR_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> - -#include <gst/gst.h> - -G_BEGIN_DECLS - -#define GST_TYPE_VIDEO_CONNECTOR \ - (gst_video_connector_get_type()) -#define GST_VIDEO_CONNECTOR(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VIDEO_CONNECTOR, GstVideoConnector)) -#define GST_VIDEO_CONNECTOR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VIDEO_CONNECTOR, GstVideoConnectorClass)) -#define GST_IS_VIDEO_CONNECTOR(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VIDEO_CONNECTOR)) -#define GST_IS_VIDEO_CONNECTOR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VIDEO_CONNECTOR)) - -typedef struct _GstVideoConnector GstVideoConnector; -typedef struct _GstVideoConnectorClass GstVideoConnectorClass; - -struct Q_GSTTOOLS_EXPORT _GstVideoConnector { - GstElement element; - - GstPad *srcpad; - GstPad *sinkpad; - - gboolean relinked; - gboolean failedSignalEmited; - GstSegment segment; - GstBuffer *latest_buffer; -}; - -struct Q_GSTTOOLS_EXPORT _GstVideoConnectorClass { - GstElementClass parent_class; - - /* action signal to resend new segment */ - void (*resend_new_segment) (GstElement * element, gboolean emitFailedSignal); -}; - -GType Q_GSTTOOLS_EXPORT gst_video_connector_get_type (void); - -G_END_DECLS - -#endif - diff --git a/src/gsttools/qgstappsrc.cpp b/src/gsttools/qgstappsrc.cpp deleted file mode 100644 index f6ecd48be..000000000 --- a/src/gsttools/qgstappsrc.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QDebug> - -#include "qgstappsrc_p.h" - -QGstAppSrc::QGstAppSrc(QObject *parent) - : QObject(parent) -{ - m_callbacks.need_data = &QGstAppSrc::on_need_data; - m_callbacks.enough_data = &QGstAppSrc::on_enough_data; - m_callbacks.seek_data = &QGstAppSrc::on_seek_data; -} - -QGstAppSrc::~QGstAppSrc() -{ - if (m_appSrc) - gst_object_unref(G_OBJECT(m_appSrc)); -} - -bool QGstAppSrc::setup(GstElement* appsrc) -{ - if (m_appSrc) { - gst_object_unref(G_OBJECT(m_appSrc)); - m_appSrc = 0; - } - - if (!appsrc || !m_stream) - return false; - - m_appSrc = GST_APP_SRC(appsrc); - gst_object_ref(G_OBJECT(m_appSrc)); - gst_app_src_set_callbacks(m_appSrc, (GstAppSrcCallbacks*)&m_callbacks, this, (GDestroyNotify)&QGstAppSrc::destroy_notify); - - g_object_get(G_OBJECT(m_appSrc), "max-bytes", &m_maxBytes, nullptr); - - if (m_sequential) - m_streamType = GST_APP_STREAM_TYPE_STREAM; - else - m_streamType = GST_APP_STREAM_TYPE_RANDOM_ACCESS; - gst_app_src_set_stream_type(m_appSrc, m_streamType); - gst_app_src_set_size(m_appSrc, (m_sequential) ? -1 : m_stream->size()); - - return true; -} - -void QGstAppSrc::setStream(QIODevice *stream) -{ - if (m_stream) { - disconnect(m_stream, SIGNAL(readyRead()), this, SLOT(onDataReady())); - disconnect(m_stream, SIGNAL(destroyed()), this, SLOT(streamDestroyed())); - m_stream = 0; - } - - if (m_appSrc) { - gst_object_unref(G_OBJECT(m_appSrc)); - m_appSrc = 0; - } - - m_dataRequestSize = ~0; - m_dataRequested = false; - m_enoughData = false; - m_forceData = false; - m_sequential = false; - m_maxBytes = 0; - - if (stream) { - m_stream = stream; - connect(m_stream, SIGNAL(destroyed()), SLOT(streamDestroyed())); - connect(m_stream, SIGNAL(readyRead()), this, SLOT(onDataReady())); - m_sequential = m_stream->isSequential(); - } -} - -QIODevice *QGstAppSrc::stream() const -{ - return m_stream; -} - -GstAppSrc *QGstAppSrc::element() -{ - return m_appSrc; -} - -void QGstAppSrc::onDataReady() -{ - if (!m_enoughData) { - m_dataRequested = true; - pushDataToAppSrc(); - } -} - -void QGstAppSrc::streamDestroyed() -{ - if (sender() == m_stream) { - m_stream = 0; - sendEOS(); - } -} - -void QGstAppSrc::pushDataToAppSrc() -{ - if (!isStreamValid() || !m_appSrc) - return; - - if (m_dataRequested && !m_enoughData) { - qint64 size; - if (m_dataRequestSize == ~0u) - size = qMin(m_stream->bytesAvailable(), queueSize()); - else - size = qMin(m_stream->bytesAvailable(), (qint64)m_dataRequestSize); - - if (size) { - GstBuffer* buffer = gst_buffer_new_and_alloc(size); - -#if GST_CHECK_VERSION(1,0,0) - GstMapInfo mapInfo; - gst_buffer_map(buffer, &mapInfo, GST_MAP_WRITE); - void* bufferData = mapInfo.data; -#else - void* bufferData = GST_BUFFER_DATA(buffer); -#endif - - buffer->offset = m_stream->pos(); - qint64 bytesRead = m_stream->read((char*)bufferData, size); - buffer->offset_end = buffer->offset + bytesRead - 1; - -#if GST_CHECK_VERSION(1,0,0) - gst_buffer_unmap(buffer, &mapInfo); -#endif - - if (bytesRead > 0) { - m_dataRequested = false; - m_enoughData = false; - GstFlowReturn ret = gst_app_src_push_buffer (GST_APP_SRC (element()), buffer); - if (ret == GST_FLOW_ERROR) { - qWarning()<<"appsrc: push buffer error"; -#if GST_CHECK_VERSION(1,0,0) - } else if (ret == GST_FLOW_FLUSHING) { - qWarning()<<"appsrc: push buffer wrong state"; - } -#else - } else if (ret == GST_FLOW_WRONG_STATE) { - qWarning()<<"appsrc: push buffer wrong state"; - } -#endif -#if GST_VERSION_MAJOR < 1 - else if (ret == GST_FLOW_RESEND) { - qWarning()<<"appsrc: push buffer resend"; - } -#endif - } - } else if (!m_sequential) { - sendEOS(); - } - } else if (m_stream->atEnd() && !m_sequential) { - sendEOS(); - } -} - -bool QGstAppSrc::doSeek(qint64 value) -{ - if (isStreamValid()) - return stream()->seek(value); - return false; -} - - -gboolean QGstAppSrc::on_seek_data(GstAppSrc *element, guint64 arg0, gpointer userdata) -{ - Q_UNUSED(element); - QGstAppSrc *self = reinterpret_cast<QGstAppSrc*>(userdata); - if (self && self->isStreamValid()) { - if (!self->stream()->isSequential()) - QMetaObject::invokeMethod(self, "doSeek", Qt::AutoConnection, Q_ARG(qint64, arg0)); - } - else - return false; - - return true; -} - -void QGstAppSrc::on_enough_data(GstAppSrc *element, gpointer userdata) -{ - Q_UNUSED(element); - QGstAppSrc *self = reinterpret_cast<QGstAppSrc*>(userdata); - if (self) - self->enoughData() = true; -} - -void QGstAppSrc::on_need_data(GstAppSrc *element, guint arg0, gpointer userdata) -{ - Q_UNUSED(element); - QGstAppSrc *self = reinterpret_cast<QGstAppSrc*>(userdata); - if (self) { - self->dataRequested() = true; - self->enoughData() = false; - self->dataRequestSize()= arg0; - QMetaObject::invokeMethod(self, "pushDataToAppSrc", Qt::AutoConnection); - } -} - -void QGstAppSrc::destroy_notify(gpointer data) -{ - Q_UNUSED(data); -} - -void QGstAppSrc::sendEOS() -{ - if (!m_appSrc) - return; - - gst_app_src_end_of_stream(GST_APP_SRC(m_appSrc)); - if (isStreamValid() && !stream()->isSequential()) - stream()->reset(); -} diff --git a/src/gsttools/qgstappsrc_p.h b/src/gsttools/qgstappsrc_p.h deleted file mode 100644 index c1c8cdabe..000000000 --- a/src/gsttools/qgstappsrc_p.h +++ /dev/null @@ -1,121 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTAPPSRC_H -#define QGSTAPPSRC_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <QtCore/qobject.h> -#include <QtCore/qiodevice.h> - -#include <gst/gst.h> -#include <gst/app/gstappsrc.h> - -#if GST_VERSION_MAJOR < 1 -#include <gst/app/gstappbuffer.h> -#endif - -QT_BEGIN_NAMESPACE - -class Q_GSTTOOLS_EXPORT QGstAppSrc : public QObject -{ - Q_OBJECT -public: - QGstAppSrc(QObject *parent = 0); - ~QGstAppSrc(); - - bool setup(GstElement *); - - void setStream(QIODevice *); - QIODevice *stream() const; - - GstAppSrc *element(); - - qint64 queueSize() const { return m_maxBytes; } - - bool& enoughData() { return m_enoughData; } - bool& dataRequested() { return m_dataRequested; } - unsigned int& dataRequestSize() { return m_dataRequestSize; } - - bool isStreamValid() const - { - return m_stream != 0 && - m_stream->isOpen(); - } - -private slots: - void pushDataToAppSrc(); - bool doSeek(qint64); - void onDataReady(); - - void streamDestroyed(); -private: - static gboolean on_seek_data(GstAppSrc *element, guint64 arg0, gpointer userdata); - static void on_enough_data(GstAppSrc *element, gpointer userdata); - static void on_need_data(GstAppSrc *element, uint arg0, gpointer userdata); - static void destroy_notify(gpointer data); - - void sendEOS(); - - QIODevice *m_stream = nullptr; - GstAppSrc *m_appSrc = nullptr; - bool m_sequential = false; - GstAppStreamType m_streamType = GST_APP_STREAM_TYPE_RANDOM_ACCESS; - GstAppSrcCallbacks m_callbacks; - qint64 m_maxBytes = 0; - unsigned int m_dataRequestSize = ~0; - bool m_dataRequested = false; - bool m_enoughData = false; - bool m_forceData = false; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/gsttools/qgstbufferpoolinterface.cpp b/src/gsttools/qgstbufferpoolinterface.cpp deleted file mode 100644 index be8a2e116..000000000 --- a/src/gsttools/qgstbufferpoolinterface.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgstbufferpoolinterface_p.h" - -QT_BEGIN_NAMESPACE - -QGstBufferPoolPlugin::QGstBufferPoolPlugin(QObject *parent) : - QObject(parent) -{ -} - -QT_END_NAMESPACE - -#include "moc_qgstbufferpoolinterface_p.cpp" diff --git a/src/gsttools/qgstbufferpoolinterface_p.h b/src/gsttools/qgstbufferpoolinterface_p.h deleted file mode 100644 index f5cbc35aa..000000000 --- a/src/gsttools/qgstbufferpoolinterface_p.h +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTBUFFERPOOLINTERFACE_P_H -#define QGSTBUFFERPOOLINTERFACE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <qabstractvideobuffer.h> -#include <qvideosurfaceformat.h> -#include <QtCore/qobject.h> -#include <QtCore/qplugin.h> - -#include <gst/gst.h> - -QT_BEGIN_NAMESPACE - -const QLatin1String QGstBufferPoolPluginKey("bufferpool"); - -/*! - Abstract interface for video buffers allocation. -*/ -class Q_GSTTOOLS_EXPORT QGstBufferPoolInterface -{ -public: - virtual ~QGstBufferPoolInterface() {} - - virtual bool isFormatSupported(const QVideoSurfaceFormat &format) const = 0; - virtual GstBuffer *takeBuffer(const QVideoSurfaceFormat &format, GstCaps *caps) = 0; - virtual void clear() = 0; - - virtual QAbstractVideoBuffer::HandleType handleType() const = 0; - - /*! - Build an QAbstractVideoBuffer instance from GstBuffer. - Returns nullptr if GstBuffer is not compatible with this buffer pool. - - This method is called from gstreamer video sink thread. - */ - virtual QAbstractVideoBuffer *prepareVideoBuffer(GstBuffer *buffer, int bytesPerLine) = 0; -}; - -#define QGstBufferPoolInterface_iid "org.qt-project.qt.gstbufferpool/5.0" -Q_DECLARE_INTERFACE(QGstBufferPoolInterface, QGstBufferPoolInterface_iid) - -class QGstBufferPoolPlugin : public QObject, public QGstBufferPoolInterface -{ - Q_OBJECT - Q_INTERFACES(QGstBufferPoolInterface) -public: - explicit QGstBufferPoolPlugin(QObject *parent = 0); - virtual ~QGstBufferPoolPlugin() {} - - bool isFormatSupported(const QVideoSurfaceFormat &format) const override = 0; - GstBuffer *takeBuffer(const QVideoSurfaceFormat &format, GstCaps *caps) override = 0; - void clear() override = 0; - - QAbstractVideoBuffer::HandleType handleType() const override = 0; - - /*! - Build an QAbstractVideoBuffer instance from compatible GstBuffer. - Returns nullptr if GstBuffer is not compatible with this buffer pool. - - This method is called from gstreamer video sink thread. - */ - QAbstractVideoBuffer *prepareVideoBuffer(GstBuffer *buffer, int bytesPerLine) override = 0; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/gsttools/qgstcodecsinfo.cpp b/src/gsttools/qgstcodecsinfo.cpp deleted file mode 100644 index 2522ee19c..000000000 --- a/src/gsttools/qgstcodecsinfo.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgstcodecsinfo_p.h" -#include "qgstutils_p.h" -#include <QtCore/qset.h> - -#include <gst/pbutils/pbutils.h> - -static QSet<QString> streamTypes(GstElementFactory *factory, GstPadDirection direction) -{ - QSet<QString> types; - const GList *pads = gst_element_factory_get_static_pad_templates(factory); - for (const GList *pad = pads; pad; pad = g_list_next(pad)) { - GstStaticPadTemplate *templ = reinterpret_cast<GstStaticPadTemplate *>(pad->data); - if (templ->direction == direction) { - GstCaps *caps = gst_static_caps_get(&templ->static_caps); - for (uint i = 0; i < gst_caps_get_size(caps); ++i) { - GstStructure *structure = gst_caps_get_structure(caps, i); - types.insert(QString::fromUtf8(gst_structure_get_name(structure))); - } - gst_caps_unref(caps); - } - } - - return types; -} - -QGstCodecsInfo::QGstCodecsInfo(QGstCodecsInfo::ElementType elementType) -{ - updateCodecs(elementType); - for (auto &codec : supportedCodecs()) { - GstElementFactory *factory = gst_element_factory_find(codecElement(codec).constData()); - if (factory) { - GstPadDirection direction = elementType == Muxer ? GST_PAD_SINK : GST_PAD_SRC; - m_streamTypes.insert(codec, streamTypes(factory, direction)); - gst_object_unref(GST_OBJECT(factory)); - } - } -} - -QStringList QGstCodecsInfo::supportedCodecs() const -{ - return m_codecs; -} - -QString QGstCodecsInfo::codecDescription(const QString &codec) const -{ - return m_codecInfo.value(codec).description; -} - -QByteArray QGstCodecsInfo::codecElement(const QString &codec) const - -{ - return m_codecInfo.value(codec).elementName; -} - -QStringList QGstCodecsInfo::codecOptions(const QString &codec) const -{ - QStringList options; - - QByteArray elementName = m_codecInfo.value(codec).elementName; - if (elementName.isEmpty()) - return options; - - GstElement *element = gst_element_factory_make(elementName, nullptr); - if (element) { - guint numProperties; - GParamSpec **properties = g_object_class_list_properties(G_OBJECT_GET_CLASS(element), - &numProperties); - for (guint j = 0; j < numProperties; ++j) { - GParamSpec *property = properties[j]; - // ignore some properties - if (strcmp(property->name, "name") == 0 || strcmp(property->name, "parent") == 0) - continue; - - options.append(QLatin1String(property->name)); - } - g_free(properties); - gst_object_unref(element); - } - - return options; -} - -void QGstCodecsInfo::updateCodecs(ElementType elementType) -{ - m_codecs.clear(); - m_codecInfo.clear(); - - GList *elements = elementFactories(elementType); - - QSet<QByteArray> fakeEncoderMimeTypes; - fakeEncoderMimeTypes << "unknown/unknown" - << "audio/x-raw-int" << "audio/x-raw-float" - << "video/x-raw-yuv" << "video/x-raw-rgb"; - - QSet<QByteArray> fieldsToAdd; - fieldsToAdd << "mpegversion" << "layer" << "layout" << "raversion" - << "wmaversion" << "wmvversion" << "variant" << "systemstream"; - - GList *element = elements; - while (element) { - GstElementFactory *factory = (GstElementFactory *)element->data; - element = element->next; - - const GList *padTemplates = gst_element_factory_get_static_pad_templates(factory); - while (padTemplates) { - GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *)padTemplates->data; - padTemplates = padTemplates->next; - - if (padTemplate->direction == GST_PAD_SRC) { - GstCaps *caps = gst_static_caps_get(&padTemplate->static_caps); - for (uint i=0; i<gst_caps_get_size(caps); i++) { - const GstStructure *structure = gst_caps_get_structure(caps, i); - - //skip "fake" encoders - if (fakeEncoderMimeTypes.contains(gst_structure_get_name(structure))) - continue; - - GstStructure *newStructure = qt_gst_structure_new_empty(gst_structure_get_name(structure)); - - //add structure fields to distinguish between formats with similar mime types, - //like audio/mpeg - for (int j=0; j<gst_structure_n_fields(structure); j++) { - const gchar* fieldName = gst_structure_nth_field_name(structure, j); - if (fieldsToAdd.contains(fieldName)) { - const GValue *value = gst_structure_get_value(structure, fieldName); - GType valueType = G_VALUE_TYPE(value); - - //don't add values of range type, - //gst_pb_utils_get_codec_description complains about not fixed caps - - if (valueType != GST_TYPE_INT_RANGE && valueType != GST_TYPE_DOUBLE_RANGE && - valueType != GST_TYPE_FRACTION_RANGE && valueType != GST_TYPE_LIST && - valueType != GST_TYPE_ARRAY) - gst_structure_set_value(newStructure, fieldName, value); - } - } - - GstCaps *newCaps = gst_caps_new_full(newStructure, nullptr); - - gchar *capsString = gst_caps_to_string(newCaps); - QString codec = QLatin1String(capsString); - if (capsString) - g_free(capsString); - GstRank rank = GstRank(gst_plugin_feature_get_rank(GST_PLUGIN_FEATURE(factory))); - - // If two elements provide the same codec, use the highest ranked one - QMap<QString, CodecInfo>::const_iterator it = m_codecInfo.constFind(codec); - if (it == m_codecInfo.constEnd() || it->rank < rank) { - if (it == m_codecInfo.constEnd()) - m_codecs.append(codec); - - CodecInfo info; - info.elementName = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory)); - - gchar *description = gst_pb_utils_get_codec_description(newCaps); - info.description = QString::fromUtf8(description); - if (description) - g_free(description); - - info.rank = rank; - - m_codecInfo.insert(codec, info); - } - - gst_caps_unref(newCaps); - } - gst_caps_unref(caps); - } - } - } - - gst_plugin_feature_list_free(elements); -} - -#if !GST_CHECK_VERSION(0, 10, 31) -static gboolean element_filter(GstPluginFeature *feature, gpointer user_data) -{ - if (Q_UNLIKELY(!GST_IS_ELEMENT_FACTORY(feature))) - return FALSE; - - const QGstCodecsInfo::ElementType type = *reinterpret_cast<QGstCodecsInfo::ElementType *>(user_data); - - const gchar *klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature)); - if (type == QGstCodecsInfo::AudioEncoder && !(strstr(klass, "Encoder") && strstr(klass, "Audio"))) - return FALSE; - if (type == QGstCodecsInfo::VideoEncoder && !(strstr(klass, "Encoder") && strstr(klass, "Video"))) - return FALSE; - if (type == QGstCodecsInfo::Muxer && !strstr(klass, "Muxer")) - return FALSE; - - guint rank = gst_plugin_feature_get_rank(feature); - if (rank < GST_RANK_MARGINAL) - return FALSE; - - return TRUE; -} - -static gint compare_plugin_func(const void *item1, const void *item2) -{ - GstPluginFeature *f1 = reinterpret_cast<GstPluginFeature *>(const_cast<void *>(item1)); - GstPluginFeature *f2 = reinterpret_cast<GstPluginFeature *>(const_cast<void *>(item2)); - - gint diff = gst_plugin_feature_get_rank(f2) - gst_plugin_feature_get_rank(f1); - if (diff != 0) - return diff; - - return strcmp(gst_plugin_feature_get_name(f1), gst_plugin_feature_get_name (f2)); -} -#endif - -GList *QGstCodecsInfo::elementFactories(ElementType elementType) const -{ -#if GST_CHECK_VERSION(0,10,31) - GstElementFactoryListType gstElementType = 0; - switch (elementType) { - case AudioEncoder: - gstElementType = GST_ELEMENT_FACTORY_TYPE_AUDIO_ENCODER; - break; - case VideoEncoder: - gstElementType = GST_ELEMENT_FACTORY_TYPE_VIDEO_ENCODER; - break; - case Muxer: - gstElementType = GST_ELEMENT_FACTORY_TYPE_MUXER; - break; - } - - GList *list = gst_element_factory_list_get_elements(gstElementType, GST_RANK_MARGINAL); - if (elementType == AudioEncoder) { - // Manually add "audioconvert" to the list - // to allow linking with various containers. - auto factory = gst_element_factory_find("audioconvert"); - if (factory) - list = g_list_prepend(list, factory); - } - - return list; -#else - GList *result = gst_registry_feature_filter(gst_registry_get_default(), - element_filter, - FALSE, &elementType); - result = g_list_sort(result, compare_plugin_func); - return result; -#endif -} - -QSet<QString> QGstCodecsInfo::supportedStreamTypes(const QString &codec) const -{ - return m_streamTypes.value(codec); -} - -QStringList QGstCodecsInfo::supportedCodecs(const QSet<QString> &types) const -{ - QStringList result; - for (auto &candidate : supportedCodecs()) { - auto candidateTypes = supportedStreamTypes(candidate); - if (candidateTypes.intersects(types)) - result << candidate; - } - - return result; -} diff --git a/src/gsttools/qgstcodecsinfo_p.h b/src/gsttools/qgstcodecsinfo_p.h deleted file mode 100644 index d7aadef21..000000000 --- a/src/gsttools/qgstcodecsinfo_p.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTCODECSINFO_H -#define QGSTCODECSINFO_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <QtCore/qmap.h> -#include <QtCore/qstringlist.h> -#include <QSet> - -#include <gst/gst.h> - -QT_BEGIN_NAMESPACE - -class Q_GSTTOOLS_EXPORT QGstCodecsInfo -{ -public: - enum ElementType { AudioEncoder, VideoEncoder, Muxer }; - - struct CodecInfo { - QString description; - QByteArray elementName; - GstRank rank; - }; - - QGstCodecsInfo(ElementType elementType); - - QStringList supportedCodecs() const; - QString codecDescription(const QString &codec) const; - QByteArray codecElement(const QString &codec) const; - QStringList codecOptions(const QString &codec) const; - QSet<QString> supportedStreamTypes(const QString &codec) const; - QStringList supportedCodecs(const QSet<QString> &types) const; - -private: - void updateCodecs(ElementType elementType); - GList *elementFactories(ElementType elementType) const; - - QStringList m_codecs; - QMap<QString, CodecInfo> m_codecInfo; - QMap<QString, QSet<QString>> m_streamTypes; -}; - -Q_DECLARE_TYPEINFO(QGstCodecsInfo::CodecInfo, Q_MOVABLE_TYPE); - -QT_END_NAMESPACE - -#endif diff --git a/src/gsttools/qgstreameraudioinputselector.cpp b/src/gsttools/qgstreameraudioinputselector.cpp deleted file mode 100644 index 3bf5538c2..000000000 --- a/src/gsttools/qgstreameraudioinputselector.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtMultimedia/private/qtmultimediaglobal_p.h> -#include "qgstreameraudioinputselector_p.h" - -#include <QtCore/QDir> -#include <QtCore/QDebug> - -#include <gst/gst.h> - -#if QT_CONFIG(alsa) -#include <alsa/asoundlib.h> -#endif - -QGstreamerAudioInputSelector::QGstreamerAudioInputSelector(QObject *parent) - :QAudioInputSelectorControl(parent) -{ - update(); -} - -QGstreamerAudioInputSelector::~QGstreamerAudioInputSelector() -{ -} - -QList<QString> QGstreamerAudioInputSelector::availableInputs() const -{ - return m_names; -} - -QString QGstreamerAudioInputSelector::inputDescription(const QString& name) const -{ - QString desc; - - for (int i = 0; i < m_names.size(); i++) { - if (m_names.at(i).compare(name) == 0) { - desc = m_descriptions.at(i); - break; - } - } - return desc; -} - -QString QGstreamerAudioInputSelector::defaultInput() const -{ - if (m_names.size() > 0) - return m_names.at(0); - - return QString(); -} - -QString QGstreamerAudioInputSelector::activeInput() const -{ - return m_audioInput; -} - -void QGstreamerAudioInputSelector::setActiveInput(const QString& name) -{ - if (m_audioInput.compare(name) != 0) { - m_audioInput = name; - emit activeInputChanged(name); - } -} - -void QGstreamerAudioInputSelector::update() -{ - m_names.clear(); - m_descriptions.clear(); - - //use autoaudiosrc as the first default device - m_names.append(QLatin1String("default:")); - m_descriptions.append(tr("System default device")); - - updatePulseDevices(); - updateAlsaDevices(); - updateOssDevices(); - if (m_names.size() > 0) - m_audioInput = m_names.at(0); -} - -void QGstreamerAudioInputSelector::updateAlsaDevices() -{ -#if QT_CONFIG(alsa) - void **hints, **n; - if (snd_device_name_hint(-1, "pcm", &hints) < 0) { - qWarning()<<"no alsa devices available"; - return; - } - n = hints; - - while (*n != nullptr) { - char *name = snd_device_name_get_hint(*n, "NAME"); - char *descr = snd_device_name_get_hint(*n, "DESC"); - char *io = snd_device_name_get_hint(*n, "IOID"); - - if ((name != nullptr) && (descr != nullptr)) { - if (io == nullptr || qstrcmp(io, "Input") == 0) { - m_names.append(QLatin1String("alsa:")+QString::fromUtf8(name)); - m_descriptions.append(QString::fromUtf8(descr)); - } - } - - free(name); - free(descr); - free(io); - n++; - } - snd_device_name_free_hint(hints); -#endif -} - -void QGstreamerAudioInputSelector::updateOssDevices() -{ - QDir devDir(QStringLiteral("/dev")); - devDir.setFilter(QDir::System); - const QFileInfoList entries = devDir.entryInfoList(QStringList() << QLatin1String("dsp*")); - for (const QFileInfo& entryInfo : entries) { - m_names.append(QLatin1String("oss:")+entryInfo.filePath()); - m_descriptions.append(QString::fromLatin1("OSS device %1").arg(entryInfo.fileName())); - } -} - -void QGstreamerAudioInputSelector::updatePulseDevices() -{ - GstElementFactory *factory = gst_element_factory_find("pulsesrc"); - if (factory) { - m_names.append(QLatin1String("pulseaudio:")); - m_descriptions.append(QLatin1String("PulseAudio device.")); - gst_object_unref(GST_OBJECT(factory)); - } -} diff --git a/src/gsttools/qgstreameraudioinputselector_p.h b/src/gsttools/qgstreameraudioinputselector_p.h deleted file mode 100644 index 0c193fda9..000000000 --- a/src/gsttools/qgstreameraudioinputselector_p.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERAUDIOINPUTSELECTOR_H -#define QGSTREAMERAUDIOINPUTSELECTOR_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <qaudioinputselectorcontrol.h> -#include <QtCore/qstringlist.h> - -QT_BEGIN_NAMESPACE - -class Q_GSTTOOLS_EXPORT QGstreamerAudioInputSelector : public QAudioInputSelectorControl -{ -Q_OBJECT -public: - QGstreamerAudioInputSelector(QObject *parent); - ~QGstreamerAudioInputSelector(); - - QList<QString> availableInputs() const override; - QString inputDescription(const QString &name) const override; - QString defaultInput() const override; - QString activeInput() const override; - -public Q_SLOTS: - void setActiveInput(const QString &name) override; - -private: - void update(); - void updateAlsaDevices(); - void updateOssDevices(); - void updatePulseDevices(); - - QString m_audioInput; - QList<QString> m_names; - QList<QString> m_descriptions; -}; - -QT_END_NAMESPACE - -#endif // QGSTREAMERAUDIOINPUTSELECTOR_H diff --git a/src/gsttools/qgstreameraudioprobecontrol.cpp b/src/gsttools/qgstreameraudioprobecontrol.cpp deleted file mode 100644 index d40b39939..000000000 --- a/src/gsttools/qgstreameraudioprobecontrol.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgstreameraudioprobecontrol_p.h" -#include <private/qgstutils_p.h> - -QGstreamerAudioProbeControl::QGstreamerAudioProbeControl(QObject *parent) - : QMediaAudioProbeControl(parent) -{ -} - -QGstreamerAudioProbeControl::~QGstreamerAudioProbeControl() -{ -} - -void QGstreamerAudioProbeControl::probeCaps(GstCaps *caps) -{ - QAudioFormat format = QGstUtils::audioFormatForCaps(caps); - - QMutexLocker locker(&m_bufferMutex); - m_format = format; -} - -bool QGstreamerAudioProbeControl::probeBuffer(GstBuffer *buffer) -{ - qint64 position = GST_BUFFER_TIMESTAMP(buffer); - position = position >= 0 - ? position / G_GINT64_CONSTANT(1000) // microseconds - : -1; - - QByteArray data; -#if GST_CHECK_VERSION(1,0,0) - GstMapInfo info; - if (gst_buffer_map(buffer, &info, GST_MAP_READ)) { - data = QByteArray(reinterpret_cast<const char *>(info.data), info.size); - gst_buffer_unmap(buffer, &info); - } else { - return true; - } -#else - data = QByteArray(reinterpret_cast<const char *>(buffer->data), buffer->size); -#endif - - QMutexLocker locker(&m_bufferMutex); - if (m_format.isValid()) { - if (!m_pendingBuffer.isValid()) - QMetaObject::invokeMethod(this, "bufferProbed", Qt::QueuedConnection); - m_pendingBuffer = QAudioBuffer(data, m_format, position); - } - - return true; -} - -void QGstreamerAudioProbeControl::bufferProbed() -{ - QAudioBuffer audioBuffer; - { - QMutexLocker locker(&m_bufferMutex); - if (!m_pendingBuffer.isValid()) - return; - audioBuffer = m_pendingBuffer; - m_pendingBuffer = QAudioBuffer(); - } - emit audioBufferProbed(audioBuffer); -} diff --git a/src/gsttools/qgstreameraudioprobecontrol_p.h b/src/gsttools/qgstreameraudioprobecontrol_p.h deleted file mode 100644 index 4fc5c7704..000000000 --- a/src/gsttools/qgstreameraudioprobecontrol_p.h +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERAUDIOPROBECONTROL_H -#define QGSTREAMERAUDIOPROBECONTROL_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <gst/gst.h> -#include <qmediaaudioprobecontrol.h> -#include <QtCore/qmutex.h> -#include <qaudiobuffer.h> -#include <qshareddata.h> - -#include <private/qgstreamerbufferprobe_p.h> - -QT_BEGIN_NAMESPACE - -class Q_GSTTOOLS_EXPORT QGstreamerAudioProbeControl - : public QMediaAudioProbeControl - , public QGstreamerBufferProbe - , public QSharedData -{ - Q_OBJECT -public: - explicit QGstreamerAudioProbeControl(QObject *parent); - virtual ~QGstreamerAudioProbeControl(); - -protected: - void probeCaps(GstCaps *caps) override; - bool probeBuffer(GstBuffer *buffer) override; - -private slots: - void bufferProbed(); - -private: - QAudioBuffer m_pendingBuffer; - QAudioFormat m_format; - QMutex m_bufferMutex; -}; - -QT_END_NAMESPACE - -#endif // QGSTREAMERAUDIOPROBECONTROL_H diff --git a/src/gsttools/qgstreamerbufferprobe.cpp b/src/gsttools/qgstreamerbufferprobe.cpp deleted file mode 100644 index e2956eadd..000000000 --- a/src/gsttools/qgstreamerbufferprobe.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Jolla Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgstreamerbufferprobe_p.h" -#include "qgstutils_p.h" - -QT_BEGIN_NAMESPACE - -QGstreamerBufferProbe::QGstreamerBufferProbe(Flags flags) - : m_flags(flags) -{ -} - -QGstreamerBufferProbe::~QGstreamerBufferProbe() -{ -#if !GST_CHECK_VERSION(1,0,0) - if (m_caps) - gst_caps_unref(m_caps); -#endif -} - -void QGstreamerBufferProbe::addProbeToPad(GstPad *pad, bool downstream) -{ - if (GstCaps *caps = qt_gst_pad_get_current_caps(pad)) { - probeCaps(caps); - gst_caps_unref(caps); - } -#if GST_CHECK_VERSION(1,0,0) - if (m_flags & ProbeCaps) { - m_capsProbeId = gst_pad_add_probe( - pad, - downstream - ? GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM - : GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, - capsProbe, - this, - nullptr); - } - if (m_flags & ProbeBuffers) { - m_bufferProbeId = gst_pad_add_probe( - pad, GST_PAD_PROBE_TYPE_BUFFER, bufferProbe, this, nullptr); - } -#else - Q_UNUSED(downstream); - - m_bufferProbeId = gst_pad_add_buffer_probe(pad, G_CALLBACK(bufferProbe), this); -#endif -} - -void QGstreamerBufferProbe::removeProbeFromPad(GstPad *pad) -{ -#if GST_CHECK_VERSION(1,0,0) - if (m_capsProbeId != -1) { - gst_pad_remove_probe(pad, m_capsProbeId); - m_capsProbeId = -1; - } - if (m_bufferProbeId != -1) { - gst_pad_remove_probe(pad, m_bufferProbeId); - m_bufferProbeId = -1; - } -#else - if (m_bufferProbeId != -1) { - gst_pad_remove_buffer_probe(pad, m_bufferProbeId); - m_bufferProbeId = -1; - if (m_caps) { - gst_caps_unref(m_caps); - m_caps = 0; - } - } -#endif -} - -void QGstreamerBufferProbe::probeCaps(GstCaps *) -{ -} - -bool QGstreamerBufferProbe::probeBuffer(GstBuffer *) -{ - return true; -} - -#if GST_CHECK_VERSION(1,0,0) -GstPadProbeReturn QGstreamerBufferProbe::capsProbe( - GstPad *, GstPadProbeInfo *info, gpointer user_data) -{ - QGstreamerBufferProbe * const control = static_cast<QGstreamerBufferProbe *>(user_data); - - if (GstEvent * const event = gst_pad_probe_info_get_event(info)) { - if (GST_EVENT_TYPE(event) == GST_EVENT_CAPS) { - GstCaps *caps; - gst_event_parse_caps(event, &caps); - - control->probeCaps(caps); - } - } - return GST_PAD_PROBE_OK; -} - -GstPadProbeReturn QGstreamerBufferProbe::bufferProbe( - GstPad *, GstPadProbeInfo *info, gpointer user_data) -{ - QGstreamerBufferProbe * const control = static_cast<QGstreamerBufferProbe *>(user_data); - if (GstBuffer * const buffer = gst_pad_probe_info_get_buffer(info)) - return control->probeBuffer(buffer) ? GST_PAD_PROBE_OK : GST_PAD_PROBE_DROP; - return GST_PAD_PROBE_OK; -} -#else -gboolean QGstreamerBufferProbe::bufferProbe(GstElement *, GstBuffer *buffer, gpointer user_data) -{ - QGstreamerBufferProbe * const control = static_cast<QGstreamerBufferProbe *>(user_data); - - if (control->m_flags & ProbeCaps) { - GstCaps *caps = gst_buffer_get_caps(buffer); - if (caps && (!control->m_caps || !gst_caps_is_equal(control->m_caps, caps))) { - qSwap(caps, control->m_caps); - control->probeCaps(control->m_caps); - } - if (caps) - gst_caps_unref(caps); - } - - if (control->m_flags & ProbeBuffers) { - return control->probeBuffer(buffer) ? TRUE : FALSE; - } else { - return TRUE; - } -} -#endif - -QT_END_NAMESPACE diff --git a/src/gsttools/qgstreamerbufferprobe_p.h b/src/gsttools/qgstreamerbufferprobe_p.h deleted file mode 100644 index 2dda73e40..000000000 --- a/src/gsttools/qgstreamerbufferprobe_p.h +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Jolla Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERBUFFERPROBE_H -#define QGSTREAMERBUFFERPROBE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <gst/gst.h> - -#include <QtCore/qglobal.h> - - -QT_BEGIN_NAMESPACE - -class Q_GSTTOOLS_EXPORT QGstreamerBufferProbe -{ -public: - enum Flags - { - ProbeCaps = 0x01, - ProbeBuffers = 0x02, - ProbeAll = ProbeCaps | ProbeBuffers - }; - - explicit QGstreamerBufferProbe(Flags flags = ProbeAll); - virtual ~QGstreamerBufferProbe(); - - void addProbeToPad(GstPad *pad, bool downstream = true); - void removeProbeFromPad(GstPad *pad); - -protected: - virtual void probeCaps(GstCaps *caps); - virtual bool probeBuffer(GstBuffer *buffer); - -private: -#if GST_CHECK_VERSION(1,0,0) - static GstPadProbeReturn capsProbe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data); - static GstPadProbeReturn bufferProbe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data); - int m_capsProbeId = -1; -#else - static gboolean bufferProbe(GstElement *element, GstBuffer *buffer, gpointer user_data); - GstCaps *m_caps = nullptr; -#endif - int m_bufferProbeId = -1; - const Flags m_flags; -}; - -QT_END_NAMESPACE - -#endif // QGSTREAMERAUDIOPROBECONTROL_H diff --git a/src/gsttools/qgstreamerbushelper.cpp b/src/gsttools/qgstreamerbushelper.cpp deleted file mode 100644 index 1a4034eee..000000000 --- a/src/gsttools/qgstreamerbushelper.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtCore/qmap.h> -#include <QtCore/qtimer.h> -#include <QtCore/qmutex.h> -#include <QtCore/qlist.h> -#include <QtCore/qabstracteventdispatcher.h> -#include <QtCore/qcoreapplication.h> - -#include "qgstreamerbushelper_p.h" - -QT_BEGIN_NAMESPACE - - -class QGstreamerBusHelperPrivate : public QObject -{ - Q_OBJECT -public: - QGstreamerBusHelperPrivate(QGstreamerBusHelper *parent, GstBus* bus) : - QObject(parent), - m_tag(0), - m_bus(bus), - m_helper(parent), - m_intervalTimer(nullptr) - { - // glib event loop can be disabled either by env variable or QT_NO_GLIB define, so check the dispacher - QAbstractEventDispatcher *dispatcher = QCoreApplication::eventDispatcher(); - const bool hasGlib = dispatcher && dispatcher->inherits("QEventDispatcherGlib"); - if (!hasGlib) { - m_intervalTimer = new QTimer(this); - m_intervalTimer->setInterval(250); - connect(m_intervalTimer, SIGNAL(timeout()), SLOT(interval())); - m_intervalTimer->start(); - } else { - m_tag = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT, busCallback, this, nullptr); - } - } - - ~QGstreamerBusHelperPrivate() - { - m_helper = 0; - delete m_intervalTimer; - - if (m_tag) -#if GST_CHECK_VERSION(1, 6, 0) - gst_bus_remove_watch(m_bus); -#else - g_source_remove(m_tag); -#endif - } - - GstBus* bus() const { return m_bus; } - -private slots: - void interval() - { - GstMessage* message; - while ((message = gst_bus_poll(m_bus, GST_MESSAGE_ANY, 0)) != 0) { - processMessage(message); - gst_message_unref(message); - } - } - -private: - void processMessage(GstMessage* message) - { - QGstreamerMessage msg(message); - doProcessMessage(msg); - } - - void queueMessage(GstMessage* message) - { - QGstreamerMessage msg(message); - QMetaObject::invokeMethod(this, "doProcessMessage", Qt::QueuedConnection, - Q_ARG(QGstreamerMessage, msg)); - } - - static gboolean busCallback(GstBus *bus, GstMessage *message, gpointer data) - { - Q_UNUSED(bus); - reinterpret_cast<QGstreamerBusHelperPrivate*>(data)->queueMessage(message); - return TRUE; - } - - guint m_tag; - GstBus* m_bus; - QGstreamerBusHelper* m_helper; - QTimer* m_intervalTimer; - -private slots: - void doProcessMessage(const QGstreamerMessage& msg) - { - for (QGstreamerBusMessageFilter *filter : qAsConst(busFilters)) { - if (filter->processBusMessage(msg)) - break; - } - emit m_helper->message(msg); - } - -public: - QMutex filterMutex; - QList<QGstreamerSyncMessageFilter*> syncFilters; - QList<QGstreamerBusMessageFilter*> busFilters; -}; - - -static GstBusSyncReply syncGstBusFilter(GstBus* bus, GstMessage* message, QGstreamerBusHelperPrivate *d) -{ - Q_UNUSED(bus); - QMutexLocker lock(&d->filterMutex); - - for (QGstreamerSyncMessageFilter *filter : qAsConst(d->syncFilters)) { - if (filter->processSyncMessage(QGstreamerMessage(message))) { - gst_message_unref(message); - return GST_BUS_DROP; - } - } - - return GST_BUS_PASS; -} - - -/*! - \class QGstreamerBusHelper - \internal -*/ - -QGstreamerBusHelper::QGstreamerBusHelper(GstBus* bus, QObject* parent): - QObject(parent) -{ - d = new QGstreamerBusHelperPrivate(this, bus); -#if GST_CHECK_VERSION(1,0,0) - gst_bus_set_sync_handler(bus, (GstBusSyncHandler)syncGstBusFilter, d, 0); -#else - gst_bus_set_sync_handler(bus, (GstBusSyncHandler)syncGstBusFilter, d); -#endif - gst_object_ref(GST_OBJECT(bus)); -} - -QGstreamerBusHelper::~QGstreamerBusHelper() -{ -#if GST_CHECK_VERSION(1,0,0) - gst_bus_set_sync_handler(d->bus(), 0, 0, 0); -#else - gst_bus_set_sync_handler(d->bus(),0,0); -#endif - gst_object_unref(GST_OBJECT(d->bus())); -} - -void QGstreamerBusHelper::installMessageFilter(QObject *filter) -{ - auto syncFilter = qobject_cast<QGstreamerSyncMessageFilter*>(filter); - if (syncFilter) { - QMutexLocker lock(&d->filterMutex); - if (!d->syncFilters.contains(syncFilter)) - d->syncFilters.append(syncFilter); - } - - auto busFilter = qobject_cast<QGstreamerBusMessageFilter*>(filter); - if (busFilter && !d->busFilters.contains(busFilter)) - d->busFilters.append(busFilter); -} - -void QGstreamerBusHelper::removeMessageFilter(QObject *filter) -{ - auto syncFilter = qobject_cast<QGstreamerSyncMessageFilter*>(filter); - if (syncFilter) { - QMutexLocker lock(&d->filterMutex); - d->syncFilters.removeAll(syncFilter); - } - - auto busFilter = qobject_cast<QGstreamerBusMessageFilter*>(filter); - if (busFilter) - d->busFilters.removeAll(busFilter); -} - -QT_END_NAMESPACE - -#include "qgstreamerbushelper.moc" diff --git a/src/gsttools/qgstreamerbushelper_p.h b/src/gsttools/qgstreamerbushelper_p.h deleted file mode 100644 index e784f6e41..000000000 --- a/src/gsttools/qgstreamerbushelper_p.h +++ /dev/null @@ -1,104 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERBUSHELPER_P_H -#define QGSTREAMERBUSHELPER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <QObject> - -#include "qgstreamermessage_p.h" - -#include <gst/gst.h> - -QT_BEGIN_NAMESPACE - -class QGstreamerSyncMessageFilter { -public: - //returns true if message was processed and should be dropped, false otherwise - virtual bool processSyncMessage(const QGstreamerMessage &message) = 0; -}; -#define QGstreamerSyncMessageFilter_iid "org.qt-project.qt.gstreamersyncmessagefilter/5.0" -Q_DECLARE_INTERFACE(QGstreamerSyncMessageFilter, QGstreamerSyncMessageFilter_iid) - - -class QGstreamerBusMessageFilter { -public: - //returns true if message was processed and should be dropped, false otherwise - virtual bool processBusMessage(const QGstreamerMessage &message) = 0; -}; -#define QGstreamerBusMessageFilter_iid "org.qt-project.qt.gstreamerbusmessagefilter/5.0" -Q_DECLARE_INTERFACE(QGstreamerBusMessageFilter, QGstreamerBusMessageFilter_iid) - - -class QGstreamerBusHelperPrivate; - -class Q_GSTTOOLS_EXPORT QGstreamerBusHelper : public QObject -{ - Q_OBJECT - friend class QGstreamerBusHelperPrivate; - -public: - QGstreamerBusHelper(GstBus* bus, QObject* parent = 0); - ~QGstreamerBusHelper(); - - void installMessageFilter(QObject *filter); - void removeMessageFilter(QObject *filter); - -signals: - void message(QGstreamerMessage const& message); - -private: - QGstreamerBusHelperPrivate *d = nullptr; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/gsttools/qgstreamermessage.cpp b/src/gsttools/qgstreamermessage.cpp deleted file mode 100644 index 7191565e1..000000000 --- a/src/gsttools/qgstreamermessage.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <gst/gst.h> - -#include "qgstreamermessage_p.h" - -QT_BEGIN_NAMESPACE - -static int wuchi = qRegisterMetaType<QGstreamerMessage>(); - - -/*! - \class QGstreamerMessage - \internal -*/ - -QGstreamerMessage::QGstreamerMessage(GstMessage* message): - m_message(message) -{ - gst_message_ref(m_message); -} - -QGstreamerMessage::QGstreamerMessage(QGstreamerMessage const& m): - m_message(m.m_message) -{ - gst_message_ref(m_message); -} - - -QGstreamerMessage::~QGstreamerMessage() -{ - if (m_message != 0) - gst_message_unref(m_message); -} - -GstMessage* QGstreamerMessage::rawMessage() const -{ - return m_message; -} - -QGstreamerMessage& QGstreamerMessage::operator=(QGstreamerMessage const& rhs) -{ - if (rhs.m_message != m_message) { - if (rhs.m_message != 0) - gst_message_ref(rhs.m_message); - - if (m_message != 0) - gst_message_unref(m_message); - - m_message = rhs.m_message; - } - - return *this; -} - -QT_END_NAMESPACE diff --git a/src/gsttools/qgstreamermessage_p.h b/src/gsttools/qgstreamermessage_p.h deleted file mode 100644 index baeecc360..000000000 --- a/src/gsttools/qgstreamermessage_p.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERMESSAGE_P_H -#define QGSTREAMERMESSAGE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <QMetaType> - -#include <gst/gst.h> - -QT_BEGIN_NAMESPACE - -// Required for QDoc workaround -class QString; - -class Q_GSTTOOLS_EXPORT QGstreamerMessage -{ -public: - QGstreamerMessage() = default; - QGstreamerMessage(GstMessage* message); - QGstreamerMessage(QGstreamerMessage const& m); - ~QGstreamerMessage(); - - GstMessage* rawMessage() const; - - QGstreamerMessage& operator=(QGstreamerMessage const& rhs); - -private: - GstMessage* m_message = nullptr; -}; - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(QGstreamerMessage); - -#endif diff --git a/src/gsttools/qgstreamerplayercontrol.cpp b/src/gsttools/qgstreamerplayercontrol.cpp deleted file mode 100644 index 689467db8..000000000 --- a/src/gsttools/qgstreamerplayercontrol.cpp +++ /dev/null @@ -1,613 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <private/qgstreamerplayercontrol_p.h> -#include <private/qgstreamerplayersession_p.h> - -#include <private/qmediaplaylistnavigator_p.h> -#include <private/qmediaresourcepolicy_p.h> -#include <private/qmediaresourceset_p.h> - -#include <QtCore/qdir.h> -#include <QtCore/qsocketnotifier.h> -#include <QtCore/qurl.h> -#include <QtCore/qdebug.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -//#define DEBUG_PLAYBIN - -QT_BEGIN_NAMESPACE - -QGstreamerPlayerControl::QGstreamerPlayerControl(QGstreamerPlayerSession *session, QObject *parent) - : QMediaPlayerControl(parent) - , m_session(session) -{ - m_resources = QMediaResourcePolicy::createResourceSet<QMediaPlayerResourceSetInterface>(); - Q_ASSERT(m_resources); - - connect(m_session, &QGstreamerPlayerSession::positionChanged, this, &QGstreamerPlayerControl::positionChanged); - connect(m_session, &QGstreamerPlayerSession::durationChanged, this, &QGstreamerPlayerControl::durationChanged); - connect(m_session, &QGstreamerPlayerSession::mutedStateChanged, this, &QGstreamerPlayerControl::mutedChanged); - connect(m_session, &QGstreamerPlayerSession::volumeChanged, this, &QGstreamerPlayerControl::volumeChanged); - connect(m_session, &QGstreamerPlayerSession::stateChanged, this, &QGstreamerPlayerControl::updateSessionState); - connect(m_session, &QGstreamerPlayerSession::bufferingProgressChanged, this, &QGstreamerPlayerControl::setBufferProgress); - connect(m_session, &QGstreamerPlayerSession::playbackFinished, this, &QGstreamerPlayerControl::processEOS); - connect(m_session, &QGstreamerPlayerSession::audioAvailableChanged, this, &QGstreamerPlayerControl::audioAvailableChanged); - connect(m_session, &QGstreamerPlayerSession::videoAvailableChanged, this, &QGstreamerPlayerControl::videoAvailableChanged); - connect(m_session, &QGstreamerPlayerSession::seekableChanged, this, &QGstreamerPlayerControl::seekableChanged); - connect(m_session, &QGstreamerPlayerSession::error, this, &QGstreamerPlayerControl::error); - connect(m_session, &QGstreamerPlayerSession::invalidMedia, this, &QGstreamerPlayerControl::handleInvalidMedia); - connect(m_session, &QGstreamerPlayerSession::playbackRateChanged, this, &QGstreamerPlayerControl::playbackRateChanged); - - connect(m_resources, &QMediaPlayerResourceSetInterface::resourcesGranted, this, &QGstreamerPlayerControl::handleResourcesGranted); - //denied signal should be queued to have correct state update process, - //since in playOrPause, when acquire is call on resource set, it may trigger a resourcesDenied signal immediately, - //so handleResourcesDenied should be processed later, otherwise it will be overwritten by state update later in playOrPause. - connect(m_resources, &QMediaPlayerResourceSetInterface::resourcesDenied, - this, &QGstreamerPlayerControl::handleResourcesDenied, Qt::QueuedConnection); - connect(m_resources, &QMediaPlayerResourceSetInterface::resourcesLost, this, &QGstreamerPlayerControl::handleResourcesLost); -} - -QGstreamerPlayerControl::~QGstreamerPlayerControl() -{ - QMediaResourcePolicy::destroyResourceSet(m_resources); -} - -QMediaPlayerResourceSetInterface* QGstreamerPlayerControl::resources() const -{ - return m_resources; -} - -qint64 QGstreamerPlayerControl::position() const -{ - if (m_mediaStatus == QMediaPlayer::EndOfMedia) - return m_session->duration(); - - return m_pendingSeekPosition != -1 ? m_pendingSeekPosition : m_session->position(); -} - -qint64 QGstreamerPlayerControl::duration() const -{ - return m_session->duration(); -} - -QMediaPlayer::State QGstreamerPlayerControl::state() const -{ - return m_currentState; -} - -QMediaPlayer::MediaStatus QGstreamerPlayerControl::mediaStatus() const -{ - return m_mediaStatus; -} - -int QGstreamerPlayerControl::bufferStatus() const -{ - if (m_bufferProgress == -1) { - return m_session->state() == QMediaPlayer::StoppedState ? 0 : 100; - } else - return m_bufferProgress; -} - -int QGstreamerPlayerControl::volume() const -{ - return m_session->volume(); -} - -bool QGstreamerPlayerControl::isMuted() const -{ - return m_session->isMuted(); -} - -bool QGstreamerPlayerControl::isSeekable() const -{ - return m_session->isSeekable(); -} - -QMediaTimeRange QGstreamerPlayerControl::availablePlaybackRanges() const -{ - return m_session->availablePlaybackRanges(); -} - -qreal QGstreamerPlayerControl::playbackRate() const -{ - return m_session->playbackRate(); -} - -void QGstreamerPlayerControl::setPlaybackRate(qreal rate) -{ - m_session->setPlaybackRate(rate); -} - -void QGstreamerPlayerControl::setPosition(qint64 pos) -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO << pos/1000.0; -#endif - - pushState(); - - if (m_mediaStatus == QMediaPlayer::EndOfMedia) { - m_mediaStatus = QMediaPlayer::LoadedMedia; - } - - if (m_currentState == QMediaPlayer::StoppedState) { - m_pendingSeekPosition = pos; - emit positionChanged(m_pendingSeekPosition); - } else if (m_session->isSeekable()) { - m_session->showPrerollFrames(true); - m_session->seek(pos); - m_pendingSeekPosition = -1; - } else if (m_session->state() == QMediaPlayer::StoppedState) { - m_pendingSeekPosition = pos; - emit positionChanged(m_pendingSeekPosition); - } else if (m_pendingSeekPosition != -1) { - m_pendingSeekPosition = -1; - emit positionChanged(m_pendingSeekPosition); - } - - popAndNotifyState(); -} - -void QGstreamerPlayerControl::play() -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO; -#endif - //m_userRequestedState is needed to know that we need to resume playback when resource-policy - //regranted the resources after lost, since m_currentState will become paused when resources are - //lost. - m_userRequestedState = QMediaPlayer::PlayingState; - playOrPause(QMediaPlayer::PlayingState); -} - -void QGstreamerPlayerControl::pause() -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO; -#endif - m_userRequestedState = QMediaPlayer::PausedState; - // If the playback has not been started yet but pause is requested. - // Seek to the beginning to show first frame. - if (m_pendingSeekPosition == -1 && m_session->position() == 0) - m_pendingSeekPosition = 0; - - playOrPause(QMediaPlayer::PausedState); -} - -void QGstreamerPlayerControl::playOrPause(QMediaPlayer::State newState) -{ - if (m_mediaStatus == QMediaPlayer::NoMedia) - return; - - pushState(); - - if (m_setMediaPending) { - m_mediaStatus = QMediaPlayer::LoadingMedia; - setMedia(m_currentResource, m_stream); - } - - if (m_mediaStatus == QMediaPlayer::EndOfMedia && m_pendingSeekPosition == -1) { - m_pendingSeekPosition = 0; - } - - if (!m_resources->isGranted()) - m_resources->acquire(); - - if (m_resources->isGranted()) { - // show prerolled frame if switching from stopped state - if (m_pendingSeekPosition == -1) { - m_session->showPrerollFrames(true); - } else if (m_session->state() == QMediaPlayer::StoppedState) { - // Don't evaluate the next two conditions. - } else if (m_session->isSeekable()) { - m_session->pause(); - m_session->showPrerollFrames(true); - m_session->seek(m_pendingSeekPosition); - m_pendingSeekPosition = -1; - } else { - m_pendingSeekPosition = -1; - } - - bool ok = false; - - //To prevent displaying the first video frame when playback is resumed - //the pipeline is paused instead of playing, seeked to requested position, - //and after seeking is finished (position updated) playback is restarted - //with show-preroll-frame enabled. - if (newState == QMediaPlayer::PlayingState && m_pendingSeekPosition == -1) - ok = m_session->play(); - else - ok = m_session->pause(); - - if (!ok) - newState = QMediaPlayer::StoppedState; - } - - if (m_mediaStatus == QMediaPlayer::InvalidMedia) - m_mediaStatus = QMediaPlayer::LoadingMedia; - - m_currentState = newState; - - if (m_mediaStatus == QMediaPlayer::EndOfMedia || m_mediaStatus == QMediaPlayer::LoadedMedia) { - if (m_bufferProgress == -1 || m_bufferProgress == 100) - m_mediaStatus = QMediaPlayer::BufferedMedia; - else - m_mediaStatus = QMediaPlayer::BufferingMedia; - } - - popAndNotifyState(); - - emit positionChanged(position()); -} - -void QGstreamerPlayerControl::stop() -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO; -#endif - m_userRequestedState = QMediaPlayer::StoppedState; - - pushState(); - - if (m_currentState != QMediaPlayer::StoppedState) { - m_currentState = QMediaPlayer::StoppedState; - m_session->showPrerollFrames(false); // stop showing prerolled frames in stop state - // Since gst is not going to send GST_STATE_PAUSED - // when pipeline is already paused, - // needs to update media status directly. - if (m_session->state() == QMediaPlayer::PausedState) - updateMediaStatus(); - else if (m_resources->isGranted()) - m_session->pause(); - - if (m_mediaStatus != QMediaPlayer::EndOfMedia) { - m_pendingSeekPosition = 0; - emit positionChanged(position()); - } - } - - popAndNotifyState(); -} - -void QGstreamerPlayerControl::setVolume(int volume) -{ - m_session->setVolume(volume); -} - -void QGstreamerPlayerControl::setMuted(bool muted) -{ - m_session->setMuted(muted); -} - -QMediaContent QGstreamerPlayerControl::media() const -{ - return m_currentResource; -} - -const QIODevice *QGstreamerPlayerControl::mediaStream() const -{ - return m_stream; -} - -void QGstreamerPlayerControl::setMedia(const QMediaContent &content, QIODevice *stream) -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO; -#endif - - pushState(); - - m_currentState = QMediaPlayer::StoppedState; - QMediaContent oldMedia = m_currentResource; - m_pendingSeekPosition = -1; - m_session->showPrerollFrames(false); // do not show prerolled frames until pause() or play() explicitly called - m_setMediaPending = false; - - if (!content.isNull() || stream) { - if (!m_resources->isGranted()) - m_resources->acquire(); - } else { - m_resources->release(); - } - - m_session->stop(); - - bool userStreamValid = false; - - if (m_bufferProgress != -1) { - m_bufferProgress = -1; - emit bufferStatusChanged(0); - } - - m_currentResource = content; - m_stream = stream; - - QNetworkRequest request = content.request(); - - if (m_stream) - userStreamValid = stream->isOpen() && m_stream->isReadable(); - -#if !QT_CONFIG(gstreamer_app) - m_session->loadFromUri(request); -#else - if (m_stream) { - if (userStreamValid){ - m_session->loadFromStream(request, m_stream); - } else { - m_mediaStatus = QMediaPlayer::InvalidMedia; - emit error(QMediaPlayer::FormatError, tr("Attempting to play invalid user stream")); - if (m_currentState != QMediaPlayer::PlayingState) - m_resources->release(); - popAndNotifyState(); - return; - } - } else - m_session->loadFromUri(request); -#endif - -#if QT_CONFIG(gstreamer_app) - if (!request.url().isEmpty() || userStreamValid) { -#else - if (!request.url().isEmpty()) { -#endif - m_mediaStatus = QMediaPlayer::LoadingMedia; - m_session->pause(); - } else { - m_mediaStatus = QMediaPlayer::NoMedia; - setBufferProgress(0); - } - - if (m_currentResource != oldMedia) - emit mediaChanged(m_currentResource); - - emit positionChanged(position()); - - if (content.isNull() && !stream) - m_resources->release(); - - popAndNotifyState(); -} - -void QGstreamerPlayerControl::setVideoOutput(QObject *output) -{ - m_session->setVideoRenderer(output); -} - -bool QGstreamerPlayerControl::isAudioAvailable() const -{ - return m_session->isAudioAvailable(); -} - -bool QGstreamerPlayerControl::isVideoAvailable() const -{ - return m_session->isVideoAvailable(); -} - -void QGstreamerPlayerControl::updateSessionState(QMediaPlayer::State state) -{ - pushState(); - - if (state == QMediaPlayer::StoppedState) { - m_session->showPrerollFrames(false); - m_currentState = QMediaPlayer::StoppedState; - } - - if (state == QMediaPlayer::PausedState && m_currentState != QMediaPlayer::StoppedState) { - if (m_pendingSeekPosition != -1 && m_session->isSeekable()) { - m_session->showPrerollFrames(true); - m_session->seek(m_pendingSeekPosition); - } - m_pendingSeekPosition = -1; - - if (m_currentState == QMediaPlayer::PlayingState) { - if (m_bufferProgress == -1 || m_bufferProgress == 100) - m_session->play(); - } - } - - updateMediaStatus(); - - popAndNotifyState(); -} - -void QGstreamerPlayerControl::updateMediaStatus() -{ - //EndOfMedia status should be kept, until reset by pause, play or setMedia - if (m_mediaStatus == QMediaPlayer::EndOfMedia) - return; - - pushState(); - QMediaPlayer::MediaStatus oldStatus = m_mediaStatus; - - switch (m_session->state()) { - case QMediaPlayer::StoppedState: - if (m_currentResource.isNull()) - m_mediaStatus = QMediaPlayer::NoMedia; - else if (oldStatus != QMediaPlayer::InvalidMedia) - m_mediaStatus = QMediaPlayer::LoadingMedia; - break; - - case QMediaPlayer::PlayingState: - case QMediaPlayer::PausedState: - if (m_currentState == QMediaPlayer::StoppedState) { - m_mediaStatus = QMediaPlayer::LoadedMedia; - } else { - if (m_bufferProgress == -1 || m_bufferProgress == 100) - m_mediaStatus = QMediaPlayer::BufferedMedia; - else - m_mediaStatus = QMediaPlayer::StalledMedia; - } - break; - } - - if (m_currentState == QMediaPlayer::PlayingState && !m_resources->isGranted()) - m_mediaStatus = QMediaPlayer::StalledMedia; - - popAndNotifyState(); -} - -void QGstreamerPlayerControl::processEOS() -{ - pushState(); - m_mediaStatus = QMediaPlayer::EndOfMedia; - emit positionChanged(position()); - m_session->endOfMediaReset(); - - if (m_currentState != QMediaPlayer::StoppedState) { - m_currentState = QMediaPlayer::StoppedState; - m_session->showPrerollFrames(false); // stop showing prerolled frames in stop state - } - - popAndNotifyState(); -} - -void QGstreamerPlayerControl::setBufferProgress(int progress) -{ - if (m_bufferProgress == progress || m_mediaStatus == QMediaPlayer::NoMedia) - return; - -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO << progress; -#endif - m_bufferProgress = progress; - - if (m_resources->isGranted()) { - if (m_currentState == QMediaPlayer::PlayingState && - m_bufferProgress == 100 && - m_session->state() != QMediaPlayer::PlayingState) - m_session->play(); - - if (!m_session->isLiveSource() && m_bufferProgress < 100 && - (m_session->state() == QMediaPlayer::PlayingState || - m_session->pendingState() == QMediaPlayer::PlayingState)) - m_session->pause(); - } - - updateMediaStatus(); - - emit bufferStatusChanged(m_bufferProgress); -} - -void QGstreamerPlayerControl::handleInvalidMedia() -{ - pushState(); - m_mediaStatus = QMediaPlayer::InvalidMedia; - m_currentState = QMediaPlayer::StoppedState; - m_setMediaPending = true; - popAndNotifyState(); -} - -void QGstreamerPlayerControl::handleResourcesGranted() -{ - pushState(); - - //This may be triggered when there is an auto resume - //from resource-policy, we need to take action according to m_userRequestedState - //rather than m_currentState - m_currentState = m_userRequestedState; - if (m_currentState != QMediaPlayer::StoppedState) - playOrPause(m_currentState); - else - updateMediaStatus(); - - popAndNotifyState(); -} - -void QGstreamerPlayerControl::handleResourcesLost() -{ - //on resource lost the pipeline should be paused - //player status is changed to paused - pushState(); - QMediaPlayer::State oldState = m_currentState; - - m_session->pause(); - - if (oldState != QMediaPlayer::StoppedState ) - m_currentState = QMediaPlayer::PausedState; - - popAndNotifyState(); -} - -void QGstreamerPlayerControl::handleResourcesDenied() -{ - //on resource denied the pipeline should stay paused - //player status is changed to paused - pushState(); - - if (m_currentState != QMediaPlayer::StoppedState ) - m_currentState = QMediaPlayer::PausedState; - - popAndNotifyState(); -} - -void QGstreamerPlayerControl::pushState() -{ - m_stateStack.push(m_currentState); - m_mediaStatusStack.push(m_mediaStatus); -} - -void QGstreamerPlayerControl::popAndNotifyState() -{ - Q_ASSERT(!m_stateStack.isEmpty()); - - QMediaPlayer::State oldState = m_stateStack.pop(); - QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatusStack.pop(); - - if (m_stateStack.isEmpty()) { - if (m_mediaStatus != oldMediaStatus) { -#ifdef DEBUG_PLAYBIN - qDebug() << "Media status changed:" << m_mediaStatus; -#endif - emit mediaStatusChanged(m_mediaStatus); - } - - if (m_currentState != oldState) { -#ifdef DEBUG_PLAYBIN - qDebug() << "State changed:" << m_currentState; -#endif - emit stateChanged(m_currentState); - } - } -} - -QT_END_NAMESPACE diff --git a/src/gsttools/qgstreamerplayercontrol_p.h b/src/gsttools/qgstreamerplayercontrol_p.h deleted file mode 100644 index ef94df925..000000000 --- a/src/gsttools/qgstreamerplayercontrol_p.h +++ /dev/null @@ -1,145 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERPLAYERCONTROL_P_H -#define QGSTREAMERPLAYERCONTROL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/qstack.h> -#include <qmediaplayercontrol.h> -#include <private/qgsttools_global_p.h> - -QT_BEGIN_NAMESPACE - -class QMediaPlayerResourceSetInterface; -class QGstreamerPlayerSession; -class Q_GSTTOOLS_EXPORT QGstreamerPlayerControl : public QMediaPlayerControl -{ - Q_OBJECT - -public: - QGstreamerPlayerControl(QGstreamerPlayerSession *session, QObject *parent = 0); - ~QGstreamerPlayerControl(); - - QGstreamerPlayerSession *session() { return m_session; } - - QMediaPlayer::State state() const override; - QMediaPlayer::MediaStatus mediaStatus() const override; - - qint64 position() const override; - qint64 duration() const override; - - int bufferStatus() const override; - - int volume() const override; - bool isMuted() const override; - - bool isAudioAvailable() const override; - bool isVideoAvailable() const override; - void setVideoOutput(QObject *output); - - bool isSeekable() const override; - QMediaTimeRange availablePlaybackRanges() const override; - - qreal playbackRate() const override; - void setPlaybackRate(qreal rate) override; - - QMediaContent media() const override; - const QIODevice *mediaStream() const override; - void setMedia(const QMediaContent&, QIODevice *) override; - - QMediaPlayerResourceSetInterface* resources() const; - -public Q_SLOTS: - void setPosition(qint64 pos) override; - - void play() override; - void pause() override; - void stop() override; - - void setVolume(int volume) override; - void setMuted(bool muted) override; - -private Q_SLOTS: - void updateSessionState(QMediaPlayer::State state); - void updateMediaStatus(); - void processEOS(); - void setBufferProgress(int progress); - - void handleInvalidMedia(); - - void handleResourcesGranted(); - void handleResourcesLost(); - void handleResourcesDenied(); - -private: - void playOrPause(QMediaPlayer::State state); - - void pushState(); - void popAndNotifyState(); - - QGstreamerPlayerSession *m_session = nullptr; - QMediaPlayer::State m_userRequestedState = QMediaPlayer::StoppedState; - QMediaPlayer::State m_currentState = QMediaPlayer::StoppedState; - QMediaPlayer::MediaStatus m_mediaStatus = QMediaPlayer::NoMedia; - QStack<QMediaPlayer::State> m_stateStack; - QStack<QMediaPlayer::MediaStatus> m_mediaStatusStack; - - int m_bufferProgress = -1; - qint64 m_pendingSeekPosition = -1; - bool m_setMediaPending = false; - QMediaContent m_currentResource; - QIODevice *m_stream = nullptr; - - QMediaPlayerResourceSetInterface *m_resources = nullptr; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/gsttools/qgstreamerplayersession.cpp b/src/gsttools/qgstreamerplayersession.cpp deleted file mode 100644 index adf11b022..000000000 --- a/src/gsttools/qgstreamerplayersession.cpp +++ /dev/null @@ -1,2016 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <private/qgstreamerplayersession_p.h> -#include <private/qgstreamerbushelper_p.h> - -#include <private/qgstreameraudioprobecontrol_p.h> -#include <private/qgstreamervideoprobecontrol_p.h> -#include <private/qgstreamervideorendererinterface_p.h> -#if !GST_CHECK_VERSION(1,0,0) -#include <private/gstvideoconnector_p.h> -#endif -#include <private/qgstutils_p.h> -#include <private/qvideosurfacegstsink_p.h> - -#include <gst/gstvalue.h> -#include <gst/base/gstbasesrc.h> - -#include <QtMultimedia/qmediametadata.h> -#include <QtCore/qdatetime.h> -#include <QtCore/qdebug.h> -#include <QtCore/qsize.h> -#include <QtCore/qtimer.h> -#include <QtCore/qdebug.h> -#include <QtCore/qdir.h> -#include <QtCore/qstandardpaths.h> -#include <qvideorenderercontrol.h> -#include <QUrlQuery> - -//#define DEBUG_PLAYBIN - -QT_BEGIN_NAMESPACE - -static bool usePlaybinVolume() -{ - static enum { Yes, No, Unknown } status = Unknown; - if (status == Unknown) { - QByteArray v = qgetenv("QT_GSTREAMER_USE_PLAYBIN_VOLUME"); - bool value = !v.isEmpty() && v != "0" && v != "false"; - if (value) - status = Yes; - else - status = No; - } - return status == Yes; -} - -typedef enum { - GST_PLAY_FLAG_VIDEO = 0x00000001, - GST_PLAY_FLAG_AUDIO = 0x00000002, - GST_PLAY_FLAG_TEXT = 0x00000004, - GST_PLAY_FLAG_VIS = 0x00000008, - GST_PLAY_FLAG_SOFT_VOLUME = 0x00000010, - GST_PLAY_FLAG_NATIVE_AUDIO = 0x00000020, - GST_PLAY_FLAG_NATIVE_VIDEO = 0x00000040, - GST_PLAY_FLAG_DOWNLOAD = 0x00000080, - GST_PLAY_FLAG_BUFFERING = 0x000000100 -} GstPlayFlags; - -#if !GST_CHECK_VERSION(1,0,0) -#define DEFAULT_RAW_CAPS \ - "video/x-raw-yuv; " \ - "video/x-raw-rgb; " \ - "video/x-raw-gray; " \ - "video/x-surface; " \ - "video/x-android-buffer; " \ - "audio/x-raw-int; " \ - "audio/x-raw-float; " \ - "text/plain; " \ - "text/x-pango-markup; " \ - "video/x-dvd-subpicture; " \ - "subpicture/x-pgs" - -static GstStaticCaps static_RawCaps = GST_STATIC_CAPS(DEFAULT_RAW_CAPS); -#endif - -QGstreamerPlayerSession::QGstreamerPlayerSession(QObject *parent) - : QObject(parent) -{ - initPlaybin(); -} - -void QGstreamerPlayerSession::initPlaybin() -{ - m_playbin = gst_element_factory_make(QT_GSTREAMER_PLAYBIN_ELEMENT_NAME, nullptr); - if (m_playbin) { - //GST_PLAY_FLAG_NATIVE_VIDEO omits configuration of ffmpegcolorspace and videoscale, - //since those elements are included in the video output bin when necessary. - int flags = GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_AUDIO; - QByteArray envFlags = qgetenv("QT_GSTREAMER_PLAYBIN_FLAGS"); - if (!envFlags.isEmpty()) { - flags |= envFlags.toInt(); -#if !GST_CHECK_VERSION(1,0,0) - } else { - flags |= GST_PLAY_FLAG_NATIVE_VIDEO; -#endif - } - g_object_set(G_OBJECT(m_playbin), "flags", flags, nullptr); - - const QByteArray envAudioSink = qgetenv("QT_GSTREAMER_PLAYBIN_AUDIOSINK"); - GstElement *audioSink = gst_element_factory_make(envAudioSink.isEmpty() ? "autoaudiosink" : envAudioSink, "audiosink"); - if (audioSink) { - if (usePlaybinVolume()) { - m_audioSink = audioSink; - m_volumeElement = m_playbin; - } else { - m_volumeElement = gst_element_factory_make("volume", "volumeelement"); - if (m_volumeElement) { - m_audioSink = gst_bin_new("audio-output-bin"); - - gst_bin_add_many(GST_BIN(m_audioSink), m_volumeElement, audioSink, nullptr); - gst_element_link(m_volumeElement, audioSink); - - GstPad *pad = gst_element_get_static_pad(m_volumeElement, "sink"); - gst_element_add_pad(GST_ELEMENT(m_audioSink), gst_ghost_pad_new("sink", pad)); - gst_object_unref(GST_OBJECT(pad)); - } else { - m_audioSink = audioSink; - m_volumeElement = m_playbin; - } - } - - g_object_set(G_OBJECT(m_playbin), "audio-sink", m_audioSink, nullptr); - addAudioBufferProbe(); - } - } - -#if GST_CHECK_VERSION(1,0,0) - static const auto convDesc = qEnvironmentVariable("QT_GSTREAMER_PLAYBIN_CONVERT"); - GError *err = nullptr; - auto convPipeline = !convDesc.isEmpty() ? convDesc.toLatin1().constData() : "identity"; - auto convElement = gst_parse_launch(convPipeline, &err); - if (err) { - qWarning() << "Error:" << convDesc << ":" << QLatin1String(err->message); - g_clear_error(&err); - } - m_videoIdentity = convElement; -#else - m_videoIdentity = GST_ELEMENT(g_object_new(gst_video_connector_get_type(), 0)); // floating ref - g_signal_connect(G_OBJECT(m_videoIdentity), "connection-failed", G_CALLBACK(insertColorSpaceElement), (gpointer)this); - m_colorSpace = gst_element_factory_make(QT_GSTREAMER_COLORCONVERSION_ELEMENT_NAME, "ffmpegcolorspace-vo"); - - // might not get a parent, take ownership to avoid leak - qt_gst_object_ref_sink(GST_OBJECT(m_colorSpace)); -#endif - - m_nullVideoSink = gst_element_factory_make("fakesink", nullptr); - g_object_set(G_OBJECT(m_nullVideoSink), "sync", true, nullptr); - gst_object_ref(GST_OBJECT(m_nullVideoSink)); - - m_videoOutputBin = gst_bin_new("video-output-bin"); - // might not get a parent, take ownership to avoid leak - qt_gst_object_ref_sink(GST_OBJECT(m_videoOutputBin)); - - GstElement *videoOutputSink = m_videoIdentity; -#if QT_CONFIG(gstreamer_gl) - if (QGstUtils::useOpenGL()) { - videoOutputSink = gst_element_factory_make("glupload", nullptr); - GstElement *colorConvert = gst_element_factory_make("glcolorconvert", nullptr); - gst_bin_add_many(GST_BIN(m_videoOutputBin), videoOutputSink, colorConvert, m_videoIdentity, m_nullVideoSink, nullptr); - gst_element_link_many(videoOutputSink, colorConvert, m_videoIdentity, nullptr); - } else { - gst_bin_add_many(GST_BIN(m_videoOutputBin), m_videoIdentity, m_nullVideoSink, nullptr); - } -#else - gst_bin_add_many(GST_BIN(m_videoOutputBin), m_videoIdentity, m_nullVideoSink, nullptr); -#endif - gst_element_link(m_videoIdentity, m_nullVideoSink); - - m_videoSink = m_nullVideoSink; - - // add ghostpads - GstPad *pad = gst_element_get_static_pad(videoOutputSink, "sink"); - gst_element_add_pad(GST_ELEMENT(m_videoOutputBin), gst_ghost_pad_new("sink", pad)); - gst_object_unref(GST_OBJECT(pad)); - - if (m_playbin != 0) { - // Sort out messages - setBus(gst_element_get_bus(m_playbin)); - - g_object_set(G_OBJECT(m_playbin), "video-sink", m_videoOutputBin, nullptr); - - g_signal_connect(G_OBJECT(m_playbin), "notify::source", G_CALLBACK(playbinNotifySource), this); - g_signal_connect(G_OBJECT(m_playbin), "element-added", G_CALLBACK(handleElementAdded), this); - - if (usePlaybinVolume()) { - updateVolume(); - updateMuted(); - g_signal_connect(G_OBJECT(m_playbin), "notify::volume", G_CALLBACK(handleVolumeChange), this); - g_signal_connect(G_OBJECT(m_playbin), "notify::mute", G_CALLBACK(handleMutedChange), this); - } - - g_signal_connect(G_OBJECT(m_playbin), "video-changed", G_CALLBACK(handleStreamsChange), this); - g_signal_connect(G_OBJECT(m_playbin), "audio-changed", G_CALLBACK(handleStreamsChange), this); - g_signal_connect(G_OBJECT(m_playbin), "text-changed", G_CALLBACK(handleStreamsChange), this); - -#if QT_CONFIG(gstreamer_app) - g_signal_connect(G_OBJECT(m_playbin), "deep-notify::source", G_CALLBACK(configureAppSrcElement), this); -#endif - - m_pipeline = m_playbin; - gst_object_ref(GST_OBJECT(m_pipeline)); - } -} - -QGstreamerPlayerSession::~QGstreamerPlayerSession() -{ - if (m_pipeline) { - stop(); - - removeVideoBufferProbe(); - removeAudioBufferProbe(); - - delete m_busHelper; - m_busHelper = nullptr; - resetElements(); - } -} - -template <class T> -static inline void resetGstObject(T *&obj, T *v = nullptr) -{ - if (obj) - gst_object_unref(GST_OBJECT(obj)); - - obj = v; -} - -void QGstreamerPlayerSession::resetElements() -{ - setBus(nullptr); - resetGstObject(m_playbin); - resetGstObject(m_pipeline); -#if !GST_CHECK_VERSION(1,0,0) - resetGstObject(m_colorSpace); -#endif - resetGstObject(m_nullVideoSink); - resetGstObject(m_videoOutputBin); - - m_audioSink = nullptr; - m_volumeElement = nullptr; - m_videoIdentity = nullptr; - m_pendingVideoSink = nullptr; - m_videoSink = nullptr; -} - -GstElement *QGstreamerPlayerSession::playbin() const -{ - return m_playbin; -} - -#if QT_CONFIG(gstreamer_app) -void QGstreamerPlayerSession::configureAppSrcElement(GObject* object, GObject *orig, GParamSpec *pspec, QGstreamerPlayerSession* self) -{ - Q_UNUSED(object); - Q_UNUSED(pspec); - - if (!self->appsrc()) - return; - - GstElement *appsrc; - g_object_get(orig, "source", &appsrc, nullptr); - - if (!self->appsrc()->setup(appsrc)) - qWarning()<<"Could not setup appsrc element"; - - g_object_unref(G_OBJECT(appsrc)); -} -#endif - -void QGstreamerPlayerSession::loadFromStream(const QNetworkRequest &request, QIODevice *appSrcStream) -{ -#if QT_CONFIG(gstreamer_app) -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO; -#endif - m_request = request; - m_duration = 0; - m_lastPosition = 0; - - if (!m_appSrc) - m_appSrc = new QGstAppSrc(this); - m_appSrc->setStream(appSrcStream); - - if (!parsePipeline() && m_playbin) { - m_tags.clear(); - emit tagsChanged(); - - g_object_set(G_OBJECT(m_playbin), "uri", "appsrc://", nullptr); - - if (!m_streamTypes.isEmpty()) { - m_streamProperties.clear(); - m_streamTypes.clear(); - - emit streamsChanged(); - } - } -#endif -} - -void QGstreamerPlayerSession::loadFromUri(const QNetworkRequest &request) -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO << request.url(); -#endif - m_request = request; - m_duration = 0; - m_lastPosition = 0; - -#if QT_CONFIG(gstreamer_app) - if (m_appSrc) { - m_appSrc->deleteLater(); - m_appSrc = 0; - } -#endif - - if (!parsePipeline() && m_playbin) { - m_tags.clear(); - emit tagsChanged(); - - g_object_set(G_OBJECT(m_playbin), "uri", m_request.url().toEncoded().constData(), nullptr); - - if (!m_streamTypes.isEmpty()) { - m_streamProperties.clear(); - m_streamTypes.clear(); - - emit streamsChanged(); - } - } -} - -bool QGstreamerPlayerSession::parsePipeline() -{ - if (m_request.url().scheme() != QLatin1String("gst-pipeline")) { - if (!m_playbin) { - resetElements(); - initPlaybin(); - updateVideoRenderer(); - } - return false; - } - - // Set current surface to video sink before creating a pipeline. - auto renderer = qobject_cast<QVideoRendererControl *>(m_videoOutput); - if (renderer) - QVideoSurfaceGstSink::setSurface(renderer->surface()); - - QString url = m_request.url().toString(QUrl::RemoveScheme); - QString desc = QUrl::fromPercentEncoding(url.toLatin1().constData()); - GError *err = nullptr; - GstElement *pipeline = gst_parse_launch(desc.toLatin1().constData(), &err); - if (err) { - auto errstr = QLatin1String(err->message); - qWarning() << "Error:" << desc << ":" << errstr; - emit error(QMediaPlayer::FormatError, errstr); - g_clear_error(&err); - } - - return setPipeline(pipeline); -} - -static void gst_foreach(GstIterator *it, const std::function<bool(GstElement *)> &cmp) -{ -#if GST_CHECK_VERSION(1,0,0) - GValue value = G_VALUE_INIT; - while (gst_iterator_next (it, &value) == GST_ITERATOR_OK) { - auto child = static_cast<GstElement*>(g_value_get_object(&value)); -#else - GstElement *child = nullptr; - while (gst_iterator_next(it, reinterpret_cast<gpointer *>(&child)) == GST_ITERATOR_OK) { -#endif - if (cmp(child)) - break; - } - - gst_iterator_free(it); -#if GST_CHECK_VERSION(1,0,0) - g_value_unset(&value); -#endif -} - -bool QGstreamerPlayerSession::setPipeline(GstElement *pipeline) -{ - GstBus *bus = pipeline ? gst_element_get_bus(pipeline) : nullptr; - if (!bus) - return false; - - if (m_playbin) - gst_element_set_state(m_playbin, GST_STATE_NULL); - - resetElements(); - setBus(bus); - m_pipeline = pipeline; - - if (m_renderer) { - gst_foreach(gst_bin_iterate_sinks(GST_BIN(pipeline)), - [this](GstElement *child) { - if (qstrcmp(GST_OBJECT_NAME(child), "qtvideosink") == 0) { - m_renderer->setVideoSink(child); - return true; - } - return false; - }); - } - -#if QT_CONFIG(gstreamer_app) - if (m_appSrc) { - gst_foreach(gst_bin_iterate_sources(GST_BIN(pipeline)), - [this](GstElement *child) { - if (qstrcmp(qt_gst_element_get_factory_name(child), "appsrc") == 0) { - m_appSrc->setup(child); - return true; - } - return false; - }); - } -#endif - - emit pipelineChanged(); - return true; -} - -void QGstreamerPlayerSession::setBus(GstBus *bus) -{ - resetGstObject(m_bus, bus); - - // It might still accept gst messages. - if (m_busHelper) - m_busHelper->deleteLater(); - m_busHelper = nullptr; - - if (!m_bus) - return; - - m_busHelper = new QGstreamerBusHelper(m_bus, this); - m_busHelper->installMessageFilter(this); - - if (m_videoOutput) - m_busHelper->installMessageFilter(m_videoOutput); -} - -qint64 QGstreamerPlayerSession::duration() const -{ - return m_duration; -} - -qint64 QGstreamerPlayerSession::position() const -{ - gint64 position = 0; - - if (m_pipeline && qt_gst_element_query_position(m_pipeline, GST_FORMAT_TIME, &position)) - m_lastPosition = position / 1000000; - return m_lastPosition; -} - -qreal QGstreamerPlayerSession::playbackRate() const -{ - return m_playbackRate; -} - -void QGstreamerPlayerSession::setPlaybackRate(qreal rate) -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO << rate; -#endif - if (!qFuzzyCompare(m_playbackRate, rate)) { - m_playbackRate = rate; - if (m_pipeline && m_seekable) { - qint64 from = rate > 0 ? position() : 0; - qint64 to = rate > 0 ? duration() : position(); - gst_element_seek(m_pipeline, rate, GST_FORMAT_TIME, - GstSeekFlags(GST_SEEK_FLAG_FLUSH), - GST_SEEK_TYPE_SET, from * 1000000, - GST_SEEK_TYPE_SET, to * 1000000); - } - emit playbackRateChanged(m_playbackRate); - } -} - -QMediaTimeRange QGstreamerPlayerSession::availablePlaybackRanges() const -{ - QMediaTimeRange ranges; - - if (duration() <= 0) - return ranges; - -#if GST_CHECK_VERSION(0, 10, 31) - //GST_FORMAT_TIME would be more appropriate, but unfortunately it's not supported. - //with GST_FORMAT_PERCENT media is treated as encoded with constant bitrate. - GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT); - - if (!gst_element_query(m_pipeline, query)) { - gst_query_unref(query); - return ranges; - } - - gint64 rangeStart = 0; - gint64 rangeStop = 0; - for (guint index = 0; index < gst_query_get_n_buffering_ranges(query); index++) { - if (gst_query_parse_nth_buffering_range(query, index, &rangeStart, &rangeStop)) - ranges.addInterval(rangeStart * duration() / 100, - rangeStop * duration() / 100); - } - - gst_query_unref(query); -#endif - - if (ranges.isEmpty() && !isLiveSource() && isSeekable()) - ranges.addInterval(0, duration()); - -#ifdef DEBUG_PLAYBIN - qDebug() << ranges; -#endif - - return ranges; -} - -int QGstreamerPlayerSession::activeStream(QMediaStreamsControl::StreamType streamType) const -{ - int streamNumber = -1; - if (m_playbin) { - switch (streamType) { - case QMediaStreamsControl::AudioStream: - g_object_get(G_OBJECT(m_playbin), "current-audio", &streamNumber, nullptr); - break; - case QMediaStreamsControl::VideoStream: - g_object_get(G_OBJECT(m_playbin), "current-video", &streamNumber, nullptr); - break; - case QMediaStreamsControl::SubPictureStream: - g_object_get(G_OBJECT(m_playbin), "current-text", &streamNumber, nullptr); - break; - default: - break; - } - } - - if (streamNumber >= 0) - streamNumber += m_playbin2StreamOffset.value(streamType,0); - - return streamNumber; -} - -void QGstreamerPlayerSession::setActiveStream(QMediaStreamsControl::StreamType streamType, int streamNumber) -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO << streamType << streamNumber; -#endif - - if (streamNumber >= 0) - streamNumber -= m_playbin2StreamOffset.value(streamType,0); - - if (m_playbin) { - switch (streamType) { - case QMediaStreamsControl::AudioStream: - g_object_set(G_OBJECT(m_playbin), "current-audio", streamNumber, nullptr); - break; - case QMediaStreamsControl::VideoStream: - g_object_set(G_OBJECT(m_playbin), "current-video", streamNumber, nullptr); - break; - case QMediaStreamsControl::SubPictureStream: - g_object_set(G_OBJECT(m_playbin), "current-text", streamNumber, nullptr); - break; - default: - break; - } - } -} - -int QGstreamerPlayerSession::volume() const -{ - return m_volume; -} - -bool QGstreamerPlayerSession::isMuted() const -{ - return m_muted; -} - -bool QGstreamerPlayerSession::isAudioAvailable() const -{ - return m_audioAvailable; -} - -#if GST_CHECK_VERSION(1,0,0) -static GstPadProbeReturn block_pad_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) -#else -static void block_pad_cb(GstPad *pad, gboolean blocked, gpointer user_data) -#endif -{ - Q_UNUSED(pad); -#if GST_CHECK_VERSION(1,0,0) - Q_UNUSED(info); - Q_UNUSED(user_data); - return GST_PAD_PROBE_OK; -#else -#ifdef DEBUG_PLAYBIN - qDebug() << "block_pad_cb, blocked:" << blocked; -#endif - if (blocked && user_data) { - QGstreamerPlayerSession *session = reinterpret_cast<QGstreamerPlayerSession*>(user_data); - QMetaObject::invokeMethod(session, "finishVideoOutputChange", Qt::QueuedConnection); - } -#endif -} - -void QGstreamerPlayerSession::updateVideoRenderer() -{ -#ifdef DEBUG_PLAYBIN - qDebug() << "Video sink has chaged, reload video output"; -#endif - - if (m_videoOutput) - setVideoRenderer(m_videoOutput); -} - -void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput) -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO; -#endif - if (m_videoOutput != videoOutput) { - if (m_videoOutput) { - disconnect(m_videoOutput, SIGNAL(sinkChanged()), - this, SLOT(updateVideoRenderer())); - disconnect(m_videoOutput, SIGNAL(readyChanged(bool)), - this, SLOT(updateVideoRenderer())); - - m_busHelper->removeMessageFilter(m_videoOutput); - } - - m_videoOutput = videoOutput; - - if (m_videoOutput) { - connect(m_videoOutput, SIGNAL(sinkChanged()), - this, SLOT(updateVideoRenderer())); - connect(m_videoOutput, SIGNAL(readyChanged(bool)), - this, SLOT(updateVideoRenderer())); - - m_busHelper->installMessageFilter(m_videoOutput); - } - } - - m_renderer = qobject_cast<QGstreamerVideoRendererInterface*>(videoOutput); - emit rendererChanged(); - - // No sense to continue if custom pipeline requested. - if (!m_playbin) - return; - - GstElement *videoSink = 0; - if (m_renderer && m_renderer->isReady()) - videoSink = m_renderer->videoSink(); - - if (!videoSink) - videoSink = m_nullVideoSink; - -#ifdef DEBUG_PLAYBIN - qDebug() << "Set video output:" << videoOutput; - qDebug() << "Current sink:" << (m_videoSink ? GST_ELEMENT_NAME(m_videoSink) : "") << m_videoSink - << "pending:" << (m_pendingVideoSink ? GST_ELEMENT_NAME(m_pendingVideoSink) : "") << m_pendingVideoSink - << "new sink:" << (videoSink ? GST_ELEMENT_NAME(videoSink) : "") << videoSink; -#endif - - if (m_pendingVideoSink == videoSink || - (m_pendingVideoSink == 0 && m_videoSink == videoSink)) { -#ifdef DEBUG_PLAYBIN - qDebug() << "Video sink has not changed, skip video output reconfiguration"; -#endif - return; - } - -#ifdef DEBUG_PLAYBIN - qDebug() << "Reconfigure video output"; -#endif - - if (m_state == QMediaPlayer::StoppedState) { -#ifdef DEBUG_PLAYBIN - qDebug() << "The pipeline has not started yet, pending state:" << m_pendingState; -#endif - //the pipeline has not started yet - flushVideoProbes(); - m_pendingVideoSink = 0; - gst_element_set_state(m_videoSink, GST_STATE_NULL); - gst_element_set_state(m_playbin, GST_STATE_NULL); - -#if !GST_CHECK_VERSION(1,0,0) - if (m_usingColorspaceElement) { - gst_element_unlink(m_colorSpace, m_videoSink); - gst_bin_remove(GST_BIN(m_videoOutputBin), m_colorSpace); - } else { - gst_element_unlink(m_videoIdentity, m_videoSink); - } -#endif - - removeVideoBufferProbe(); - - gst_bin_remove(GST_BIN(m_videoOutputBin), m_videoSink); - - m_videoSink = videoSink; - - gst_bin_add(GST_BIN(m_videoOutputBin), m_videoSink); - - bool linked = gst_element_link(m_videoIdentity, m_videoSink); -#if !GST_CHECK_VERSION(1,0,0) - m_usingColorspaceElement = false; - if (!linked) { - m_usingColorspaceElement = true; -#ifdef DEBUG_PLAYBIN - qDebug() << "Failed to connect video output, inserting the colorspace element."; -#endif - gst_bin_add(GST_BIN(m_videoOutputBin), m_colorSpace); - linked = gst_element_link_many(m_videoIdentity, m_colorSpace, m_videoSink, nullptr); - } -#endif - - if (!linked) - qWarning() << "Linking video output element failed"; - - if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "show-preroll-frame") != 0) { - gboolean value = m_displayPrerolledFrame; - g_object_set(G_OBJECT(m_videoSink), "show-preroll-frame", value, nullptr); - } - - addVideoBufferProbe(); - - switch (m_pendingState) { - case QMediaPlayer::PausedState: - gst_element_set_state(m_playbin, GST_STATE_PAUSED); - break; - case QMediaPlayer::PlayingState: - gst_element_set_state(m_playbin, GST_STATE_PLAYING); - break; - default: - break; - } - - resumeVideoProbes(); - - } else { - if (m_pendingVideoSink) { -#ifdef DEBUG_PLAYBIN - qDebug() << "already waiting for pad to be blocked, just change the pending sink"; -#endif - m_pendingVideoSink = videoSink; - return; - } - - m_pendingVideoSink = videoSink; - -#ifdef DEBUG_PLAYBIN - qDebug() << "Blocking the video output pad..."; -#endif - - //block pads, async to avoid locking in paused state - GstPad *srcPad = gst_element_get_static_pad(m_videoIdentity, "src"); -#if GST_CHECK_VERSION(1,0,0) - this->pad_probe_id = gst_pad_add_probe(srcPad, (GstPadProbeType)(GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BLOCKING), block_pad_cb, this, nullptr); -#else - gst_pad_set_blocked_async(srcPad, true, &block_pad_cb, this); -#endif - gst_object_unref(GST_OBJECT(srcPad)); - - //Unpause the sink to avoid waiting until the buffer is processed - //while the sink is paused. The pad will be blocked as soon as the current - //buffer is processed. - if (m_state == QMediaPlayer::PausedState) { -#ifdef DEBUG_PLAYBIN - qDebug() << "Starting video output to avoid blocking in paused state..."; -#endif - gst_element_set_state(m_videoSink, GST_STATE_PLAYING); - } - } -} - -void QGstreamerPlayerSession::finishVideoOutputChange() -{ - if (!m_playbin || !m_pendingVideoSink) - return; - -#ifdef DEBUG_PLAYBIN - qDebug() << "finishVideoOutputChange" << m_pendingVideoSink; -#endif - - GstPad *srcPad = gst_element_get_static_pad(m_videoIdentity, "src"); - - if (!gst_pad_is_blocked(srcPad)) { - //pad is not blocked, it's possible to swap outputs only in the null state - qWarning() << "Pad is not blocked yet, could not switch video sink"; - GstState identityElementState = GST_STATE_NULL; - gst_element_get_state(m_videoIdentity, &identityElementState, nullptr, GST_CLOCK_TIME_NONE); - if (identityElementState != GST_STATE_NULL) { - gst_object_unref(GST_OBJECT(srcPad)); - return; //can't change vo yet, received async call from the previous change - } - } - - if (m_pendingVideoSink == m_videoSink) { - qDebug() << "Abort, no change"; - //video output was change back to the current one, - //no need to torment the pipeline, just unblock the pad - if (gst_pad_is_blocked(srcPad)) -#if GST_CHECK_VERSION(1,0,0) - gst_pad_remove_probe(srcPad, this->pad_probe_id); -#else - gst_pad_set_blocked_async(srcPad, false, &block_pad_cb, 0); -#endif - - m_pendingVideoSink = 0; - gst_object_unref(GST_OBJECT(srcPad)); - return; - } - -#if !GST_CHECK_VERSION(1,0,0) - if (m_usingColorspaceElement) { - gst_element_set_state(m_colorSpace, GST_STATE_NULL); - gst_element_set_state(m_videoSink, GST_STATE_NULL); - - gst_element_unlink(m_colorSpace, m_videoSink); - gst_bin_remove(GST_BIN(m_videoOutputBin), m_colorSpace); - } else { -#else - { -#endif - gst_element_set_state(m_videoSink, GST_STATE_NULL); - gst_element_unlink(m_videoIdentity, m_videoSink); - } - - removeVideoBufferProbe(); - - gst_bin_remove(GST_BIN(m_videoOutputBin), m_videoSink); - - m_videoSink = m_pendingVideoSink; - m_pendingVideoSink = 0; - - gst_bin_add(GST_BIN(m_videoOutputBin), m_videoSink); - - addVideoBufferProbe(); - - bool linked = gst_element_link(m_videoIdentity, m_videoSink); -#if !GST_CHECK_VERSION(1,0,0) - m_usingColorspaceElement = false; - if (!linked) { - m_usingColorspaceElement = true; -#ifdef DEBUG_PLAYBIN - qDebug() << "Failed to connect video output, inserting the colorspace element."; -#endif - gst_bin_add(GST_BIN(m_videoOutputBin), m_colorSpace); - linked = gst_element_link_many(m_videoIdentity, m_colorSpace, m_videoSink, nullptr); - } -#endif - - if (!linked) - qWarning() << "Linking video output element failed"; - -#ifdef DEBUG_PLAYBIN - qDebug() << "notify the video connector it has to emit a new segment message..."; -#endif - -#if !GST_CHECK_VERSION(1,0,0) - //it's necessary to send a new segment event just before - //the first buffer pushed to the new sink - g_signal_emit_by_name(m_videoIdentity, - "resend-new-segment", - true //emit connection-failed signal - //to have a chance to insert colorspace element - ); -#endif - - GstState state = GST_STATE_VOID_PENDING; - - switch (m_pendingState) { - case QMediaPlayer::StoppedState: - state = GST_STATE_NULL; - break; - case QMediaPlayer::PausedState: - state = GST_STATE_PAUSED; - break; - case QMediaPlayer::PlayingState: - state = GST_STATE_PLAYING; - break; - } - -#if !GST_CHECK_VERSION(1,0,0) - if (m_usingColorspaceElement) - gst_element_set_state(m_colorSpace, state); -#endif - - gst_element_set_state(m_videoSink, state); - - if (state == GST_STATE_NULL) - flushVideoProbes(); - - // Set state change that was deferred due the video output - // change being pending - gst_element_set_state(m_playbin, state); - - if (state != GST_STATE_NULL) - resumeVideoProbes(); - - //don't have to wait here, it will unblock eventually - if (gst_pad_is_blocked(srcPad)) -#if GST_CHECK_VERSION(1,0,0) - gst_pad_remove_probe(srcPad, this->pad_probe_id); -#else - gst_pad_set_blocked_async(srcPad, false, &block_pad_cb, 0); -#endif - - gst_object_unref(GST_OBJECT(srcPad)); - -} - -#if !GST_CHECK_VERSION(1,0,0) - -void QGstreamerPlayerSession::insertColorSpaceElement(GstElement *element, gpointer data) -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO; -#endif - Q_UNUSED(element); - QGstreamerPlayerSession* session = reinterpret_cast<QGstreamerPlayerSession*>(data); - - if (session->m_usingColorspaceElement) - return; - session->m_usingColorspaceElement = true; - -#ifdef DEBUG_PLAYBIN - qDebug() << "Failed to connect video output, inserting the colorspace elemnt."; - qDebug() << "notify the video connector it has to emit a new segment message..."; -#endif - //it's necessary to send a new segment event just before - //the first buffer pushed to the new sink - g_signal_emit_by_name(session->m_videoIdentity, - "resend-new-segment", - false // don't emit connection-failed signal - ); - - gst_element_unlink(session->m_videoIdentity, session->m_videoSink); - gst_bin_add(GST_BIN(session->m_videoOutputBin), session->m_colorSpace); - gst_element_link_many(session->m_videoIdentity, session->m_colorSpace, session->m_videoSink, nullptr); - - GstState state = GST_STATE_VOID_PENDING; - - switch (session->m_pendingState) { - case QMediaPlayer::StoppedState: - state = GST_STATE_NULL; - break; - case QMediaPlayer::PausedState: - state = GST_STATE_PAUSED; - break; - case QMediaPlayer::PlayingState: - state = GST_STATE_PLAYING; - break; - } - - gst_element_set_state(session->m_colorSpace, state); -} - -#endif - -bool QGstreamerPlayerSession::isVideoAvailable() const -{ - return m_videoAvailable; -} - -bool QGstreamerPlayerSession::isSeekable() const -{ - return m_seekable; -} - -bool QGstreamerPlayerSession::play() -{ -#if GST_CHECK_VERSION(1,0,0) - static bool dumpDot = qEnvironmentVariableIsSet("GST_DEBUG_DUMP_DOT_DIR"); - if (dumpDot) - gst_debug_bin_to_dot_file_with_ts(GST_BIN(m_pipeline), GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL), "gst.play"); -#endif -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO; -#endif - - m_everPlayed = false; - if (m_pipeline) { - m_pendingState = QMediaPlayer::PlayingState; - if (gst_element_set_state(m_pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { - qWarning() << "GStreamer; Unable to play -" << m_request.url().toString(); - m_pendingState = m_state = QMediaPlayer::StoppedState; - emit stateChanged(m_state); - } else { - resumeVideoProbes(); - return true; - } - } - - return false; -} - -bool QGstreamerPlayerSession::pause() -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO; -#endif - if (m_pipeline) { - m_pendingState = QMediaPlayer::PausedState; - if (m_pendingVideoSink != 0) - return true; - - if (gst_element_set_state(m_pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { - qWarning() << "GStreamer; Unable to pause -" << m_request.url().toString(); - m_pendingState = m_state = QMediaPlayer::StoppedState; - emit stateChanged(m_state); - } else { - resumeVideoProbes(); - return true; - } - } - - return false; -} - -void QGstreamerPlayerSession::stop() -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO; -#endif - m_everPlayed = false; - if (m_pipeline) { - - if (m_renderer) - m_renderer->stopRenderer(); - - flushVideoProbes(); - gst_element_set_state(m_pipeline, GST_STATE_NULL); - - m_lastPosition = 0; - QMediaPlayer::State oldState = m_state; - m_pendingState = m_state = QMediaPlayer::StoppedState; - - finishVideoOutputChange(); - - //we have to do it here, since gstreamer will not emit bus messages any more - setSeekable(false); - if (oldState != m_state) - emit stateChanged(m_state); - } -} - -bool QGstreamerPlayerSession::seek(qint64 ms) -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO << ms; -#endif - //seek locks when the video output sink is changing and pad is blocked - if (m_pipeline && !m_pendingVideoSink && m_state != QMediaPlayer::StoppedState && m_seekable) { - ms = qMax(ms,qint64(0)); - qint64 from = m_playbackRate > 0 ? ms : 0; - qint64 to = m_playbackRate > 0 ? duration() : ms; - - bool isSeeking = gst_element_seek(m_pipeline, m_playbackRate, GST_FORMAT_TIME, - GstSeekFlags(GST_SEEK_FLAG_FLUSH), - GST_SEEK_TYPE_SET, from * 1000000, - GST_SEEK_TYPE_SET, to * 1000000); - if (isSeeking) - m_lastPosition = ms; - - return isSeeking; - } - - return false; -} - -void QGstreamerPlayerSession::setVolume(int volume) -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO << volume; -#endif - - if (m_volume != volume) { - m_volume = volume; - - if (m_volumeElement) - g_object_set(G_OBJECT(m_volumeElement), "volume", m_volume / 100.0, nullptr); - - emit volumeChanged(m_volume); - } -} - -void QGstreamerPlayerSession::setMuted(bool muted) -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO << muted; -#endif - if (m_muted != muted) { - m_muted = muted; - - if (m_volumeElement) - g_object_set(G_OBJECT(m_volumeElement), "mute", m_muted ? TRUE : FALSE, nullptr); - - emit mutedStateChanged(m_muted); - } -} - - -void QGstreamerPlayerSession::setSeekable(bool seekable) -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO << seekable; -#endif - if (seekable != m_seekable) { - m_seekable = seekable; - emit seekableChanged(m_seekable); - } -} - -bool QGstreamerPlayerSession::processBusMessage(const QGstreamerMessage &message) -{ - GstMessage* gm = message.rawMessage(); - if (gm) { - //tag message comes from elements inside playbin, not from playbin itself - if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_TAG) { - GstTagList *tag_list; - gst_message_parse_tag(gm, &tag_list); - - QMap<QByteArray, QVariant> newTags = QGstUtils::gstTagListToMap(tag_list); - QMap<QByteArray, QVariant>::const_iterator it = newTags.constBegin(); - for ( ; it != newTags.constEnd(); ++it) - m_tags.insert(it.key(), it.value()); // overwrite existing tags - - gst_tag_list_free(tag_list); - - emit tagsChanged(); - } else if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_DURATION) { - updateDuration(); - } - -#ifdef DEBUG_PLAYBIN - if (m_sourceType == MMSSrc && qstrcmp(GST_OBJECT_NAME(GST_MESSAGE_SRC(gm)), "source") == 0) { - qDebug() << "Message from MMSSrc: " << GST_MESSAGE_TYPE(gm); - } else if (m_sourceType == RTSPSrc && qstrcmp(GST_OBJECT_NAME(GST_MESSAGE_SRC(gm)), "source") == 0) { - qDebug() << "Message from RTSPSrc: " << GST_MESSAGE_TYPE(gm); - } else { - qDebug() << "Message from " << GST_OBJECT_NAME(GST_MESSAGE_SRC(gm)) << ":" << GST_MESSAGE_TYPE(gm); - } -#endif - - if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_BUFFERING) { - int progress = 0; - gst_message_parse_buffering(gm, &progress); - emit bufferingProgressChanged(progress); - } - - bool handlePlaybin2 = false; - if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_pipeline)) { - switch (GST_MESSAGE_TYPE(gm)) { - case GST_MESSAGE_STATE_CHANGED: - { - GstState oldState; - GstState newState; - GstState pending; - - gst_message_parse_state_changed(gm, &oldState, &newState, &pending); - -#ifdef DEBUG_PLAYBIN - static QStringList states = { - QStringLiteral("GST_STATE_VOID_PENDING"), QStringLiteral("GST_STATE_NULL"), - QStringLiteral("GST_STATE_READY"), QStringLiteral("GST_STATE_PAUSED"), - QStringLiteral("GST_STATE_PLAYING") }; - - qDebug() << QStringLiteral("state changed: old: %1 new: %2 pending: %3") \ - .arg(states[oldState]) \ - .arg(states[newState]) \ - .arg(states[pending]); -#endif - - switch (newState) { - case GST_STATE_VOID_PENDING: - case GST_STATE_NULL: - setSeekable(false); - finishVideoOutputChange(); - if (m_state != QMediaPlayer::StoppedState) - emit stateChanged(m_state = QMediaPlayer::StoppedState); - break; - case GST_STATE_READY: - setSeekable(false); - if (m_state != QMediaPlayer::StoppedState) - emit stateChanged(m_state = QMediaPlayer::StoppedState); - break; - case GST_STATE_PAUSED: - { - QMediaPlayer::State prevState = m_state; - m_state = QMediaPlayer::PausedState; - - //check for seekable - if (oldState == GST_STATE_READY) { - if (m_sourceType == SoupHTTPSrc || m_sourceType == MMSSrc) { - //since udpsrc is a live source, it is not applicable here - m_everPlayed = true; - } - - getStreamsInfo(); - updateVideoResolutionTag(); - - //gstreamer doesn't give a reliable indication the duration - //information is ready, GST_MESSAGE_DURATION is not sent by most elements - //the duration is queried up to 5 times with increasing delay - m_durationQueries = 5; - // This should also update the seekable flag. - updateDuration(); - - if (!qFuzzyCompare(m_playbackRate, qreal(1.0))) { - qreal rate = m_playbackRate; - m_playbackRate = 1.0; - setPlaybackRate(rate); - } - } - - if (m_state != prevState) - emit stateChanged(m_state); - - break; - } - case GST_STATE_PLAYING: - m_everPlayed = true; - if (m_state != QMediaPlayer::PlayingState) { - emit stateChanged(m_state = QMediaPlayer::PlayingState); - - // For rtsp streams duration information might not be available - // until playback starts. - if (m_duration <= 0) { - m_durationQueries = 5; - updateDuration(); - } - } - - break; - } - } - break; - - case GST_MESSAGE_EOS: - emit playbackFinished(); - break; - - case GST_MESSAGE_TAG: - case GST_MESSAGE_STREAM_STATUS: - case GST_MESSAGE_UNKNOWN: - break; - case GST_MESSAGE_ERROR: { - GError *err; - gchar *debug; - gst_message_parse_error(gm, &err, &debug); - if (err->domain == GST_STREAM_ERROR && err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND) - processInvalidMedia(QMediaPlayer::FormatError, tr("Cannot play stream of type: <unknown>")); - else - processInvalidMedia(QMediaPlayer::ResourceError, QString::fromUtf8(err->message)); - qWarning() << "Error:" << QString::fromUtf8(err->message); - g_error_free(err); - g_free(debug); - } - break; - case GST_MESSAGE_WARNING: - { - GError *err; - gchar *debug; - gst_message_parse_warning (gm, &err, &debug); - qWarning() << "Warning:" << QString::fromUtf8(err->message); - g_error_free (err); - g_free (debug); - } - break; - case GST_MESSAGE_INFO: -#ifdef DEBUG_PLAYBIN - { - GError *err; - gchar *debug; - gst_message_parse_info (gm, &err, &debug); - qDebug() << "Info:" << QString::fromUtf8(err->message); - g_error_free (err); - g_free (debug); - } -#endif - break; - case GST_MESSAGE_BUFFERING: - case GST_MESSAGE_STATE_DIRTY: - case GST_MESSAGE_STEP_DONE: - case GST_MESSAGE_CLOCK_PROVIDE: - case GST_MESSAGE_CLOCK_LOST: - case GST_MESSAGE_NEW_CLOCK: - case GST_MESSAGE_STRUCTURE_CHANGE: - case GST_MESSAGE_APPLICATION: - case GST_MESSAGE_ELEMENT: - break; - case GST_MESSAGE_SEGMENT_START: - { - const GstStructure *structure = gst_message_get_structure(gm); - qint64 position = g_value_get_int64(gst_structure_get_value(structure, "position")); - position /= 1000000; - m_lastPosition = position; - emit positionChanged(position); - } - break; - case GST_MESSAGE_SEGMENT_DONE: - break; - case GST_MESSAGE_LATENCY: -#if GST_CHECK_VERSION(0,10,13) - case GST_MESSAGE_ASYNC_START: - break; - case GST_MESSAGE_ASYNC_DONE: - { - gint64 position = 0; - if (qt_gst_element_query_position(m_pipeline, GST_FORMAT_TIME, &position)) { - position /= 1000000; - m_lastPosition = position; - emit positionChanged(position); - } - break; - } -#if GST_CHECK_VERSION(0,10,23) - case GST_MESSAGE_REQUEST_STATE: -#endif -#endif - case GST_MESSAGE_ANY: - break; - default: - break; - } - } else if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ERROR) { - GError *err; - gchar *debug; - gst_message_parse_error(gm, &err, &debug); - // If the source has given up, so do we. - if (qstrcmp(GST_OBJECT_NAME(GST_MESSAGE_SRC(gm)), "source") == 0) { - bool everPlayed = m_everPlayed; - // Try and differentiate network related resource errors from the others - if (!m_request.url().isRelative() && m_request.url().scheme().compare(QLatin1String("file"), Qt::CaseInsensitive) != 0 ) { - if (everPlayed || - (err->domain == GST_RESOURCE_ERROR && ( - err->code == GST_RESOURCE_ERROR_BUSY || - err->code == GST_RESOURCE_ERROR_OPEN_READ || - err->code == GST_RESOURCE_ERROR_READ || - err->code == GST_RESOURCE_ERROR_SEEK || - err->code == GST_RESOURCE_ERROR_SYNC))) { - processInvalidMedia(QMediaPlayer::NetworkError, QString::fromUtf8(err->message)); - } else { - processInvalidMedia(QMediaPlayer::ResourceError, QString::fromUtf8(err->message)); - } - } - else - processInvalidMedia(QMediaPlayer::ResourceError, QString::fromUtf8(err->message)); - } else if (err->domain == GST_STREAM_ERROR - && (err->code == GST_STREAM_ERROR_DECRYPT || err->code == GST_STREAM_ERROR_DECRYPT_NOKEY)) { - processInvalidMedia(QMediaPlayer::AccessDeniedError, QString::fromUtf8(err->message)); - } else { - handlePlaybin2 = true; - } - if (!handlePlaybin2) - qWarning() << "Error:" << QString::fromUtf8(err->message); - g_error_free(err); - g_free(debug); - } else if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT - && qstrcmp(GST_OBJECT_NAME(GST_MESSAGE_SRC(gm)), "source") == 0 - && m_sourceType == UDPSrc - && gst_structure_has_name(gst_message_get_structure(gm), "GstUDPSrcTimeout")) { - //since udpsrc will not generate an error for the timeout event, - //we need to process its element message here and treat it as an error. - processInvalidMedia(m_everPlayed ? QMediaPlayer::NetworkError : QMediaPlayer::ResourceError, - tr("UDP source timeout")); - } else { - handlePlaybin2 = true; - } - - if (handlePlaybin2) { - if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_WARNING) { - GError *err; - gchar *debug; - gst_message_parse_warning(gm, &err, &debug); - if (err->domain == GST_STREAM_ERROR && err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND) - emit error(int(QMediaPlayer::FormatError), tr("Cannot play stream of type: <unknown>")); - // GStreamer shows warning for HTTP playlists - if (err && err->message) - qWarning() << "Warning:" << QString::fromUtf8(err->message); - g_error_free(err); - g_free(debug); - } else if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ERROR) { - GError *err; - gchar *debug; - gst_message_parse_error(gm, &err, &debug); - - // Nearly all errors map to ResourceError - QMediaPlayer::Error qerror = QMediaPlayer::ResourceError; - if (err->domain == GST_STREAM_ERROR - && (err->code == GST_STREAM_ERROR_DECRYPT - || err->code == GST_STREAM_ERROR_DECRYPT_NOKEY)) { - qerror = QMediaPlayer::AccessDeniedError; - } - processInvalidMedia(qerror, QString::fromUtf8(err->message)); - if (err && err->message) - qWarning() << "Error:" << QString::fromUtf8(err->message); - - g_error_free(err); - g_free(debug); - } - } - } - - return false; -} - -void QGstreamerPlayerSession::getStreamsInfo() -{ - if (!m_playbin) - return; - - QList< QMap<QString,QVariant> > oldProperties = m_streamProperties; - QList<QMediaStreamsControl::StreamType> oldTypes = m_streamTypes; - QMap<QMediaStreamsControl::StreamType, int> oldOffset = m_playbin2StreamOffset; - - //check if video is available: - bool haveAudio = false; - bool haveVideo = false; - m_streamProperties.clear(); - m_streamTypes.clear(); - m_playbin2StreamOffset.clear(); - - gint audioStreamsCount = 0; - gint videoStreamsCount = 0; - gint textStreamsCount = 0; - - g_object_get(G_OBJECT(m_playbin), "n-audio", &audioStreamsCount, nullptr); - g_object_get(G_OBJECT(m_playbin), "n-video", &videoStreamsCount, nullptr); - g_object_get(G_OBJECT(m_playbin), "n-text", &textStreamsCount, nullptr); - - haveAudio = audioStreamsCount > 0; - haveVideo = videoStreamsCount > 0; - - m_playbin2StreamOffset[QMediaStreamsControl::AudioStream] = 0; - m_playbin2StreamOffset[QMediaStreamsControl::VideoStream] = audioStreamsCount; - m_playbin2StreamOffset[QMediaStreamsControl::SubPictureStream] = audioStreamsCount+videoStreamsCount; - - for (int i=0; i<audioStreamsCount; i++) - m_streamTypes.append(QMediaStreamsControl::AudioStream); - - for (int i=0; i<videoStreamsCount; i++) - m_streamTypes.append(QMediaStreamsControl::VideoStream); - - for (int i=0; i<textStreamsCount; i++) - m_streamTypes.append(QMediaStreamsControl::SubPictureStream); - - for (int i=0; i<m_streamTypes.count(); i++) { - QMediaStreamsControl::StreamType streamType = m_streamTypes[i]; - QMap<QString, QVariant> streamProperties; - - int streamIndex = i - m_playbin2StreamOffset[streamType]; - - GstTagList *tags = 0; - switch (streamType) { - case QMediaStreamsControl::AudioStream: - g_signal_emit_by_name(G_OBJECT(m_playbin), "get-audio-tags", streamIndex, &tags); - break; - case QMediaStreamsControl::VideoStream: - g_signal_emit_by_name(G_OBJECT(m_playbin), "get-video-tags", streamIndex, &tags); - break; - case QMediaStreamsControl::SubPictureStream: - g_signal_emit_by_name(G_OBJECT(m_playbin), "get-text-tags", streamIndex, &tags); - break; - default: - break; - } -#if GST_CHECK_VERSION(1,0,0) - if (tags && GST_IS_TAG_LIST(tags)) { -#else - if (tags && gst_is_tag_list(tags)) { -#endif - gchar *languageCode = 0; - if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &languageCode)) - streamProperties[QMediaMetaData::Language] = QString::fromUtf8(languageCode); - - //qDebug() << "language for setream" << i << QString::fromUtf8(languageCode); - g_free (languageCode); - gst_tag_list_free(tags); - } - - m_streamProperties.append(streamProperties); - } - - bool emitAudioChanged = (haveAudio != m_audioAvailable); - bool emitVideoChanged = (haveVideo != m_videoAvailable); - - m_audioAvailable = haveAudio; - m_videoAvailable = haveVideo; - - if (emitAudioChanged) { - emit audioAvailableChanged(m_audioAvailable); - } - if (emitVideoChanged) { - emit videoAvailableChanged(m_videoAvailable); - } - - if (oldProperties != m_streamProperties || oldTypes != m_streamTypes || oldOffset != m_playbin2StreamOffset) - emit streamsChanged(); -} - -void QGstreamerPlayerSession::updateVideoResolutionTag() -{ - if (!m_videoIdentity) - return; - -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO; -#endif - QSize size; - QSize aspectRatio; - GstPad *pad = gst_element_get_static_pad(m_videoIdentity, "src"); - GstCaps *caps = qt_gst_pad_get_current_caps(pad); - - if (caps) { - const GstStructure *structure = gst_caps_get_structure(caps, 0); - gst_structure_get_int(structure, "width", &size.rwidth()); - gst_structure_get_int(structure, "height", &size.rheight()); - - gint aspectNum = 0; - gint aspectDenum = 0; - if (!size.isEmpty() && gst_structure_get_fraction( - structure, "pixel-aspect-ratio", &aspectNum, &aspectDenum)) { - if (aspectDenum > 0) - aspectRatio = QSize(aspectNum, aspectDenum); - } - gst_caps_unref(caps); - } - - gst_object_unref(GST_OBJECT(pad)); - - QSize currentSize = m_tags.value("resolution").toSize(); - QSize currentAspectRatio = m_tags.value("pixel-aspect-ratio").toSize(); - - if (currentSize != size || currentAspectRatio != aspectRatio) { - if (aspectRatio.isEmpty()) - m_tags.remove("pixel-aspect-ratio"); - - if (size.isEmpty()) { - m_tags.remove("resolution"); - } else { - m_tags.insert("resolution", QVariant(size)); - if (!aspectRatio.isEmpty()) - m_tags.insert("pixel-aspect-ratio", QVariant(aspectRatio)); - } - - emit tagsChanged(); - } -} - -void QGstreamerPlayerSession::updateDuration() -{ - gint64 gstDuration = 0; - int duration = 0; - - if (m_pipeline && qt_gst_element_query_duration(m_pipeline, GST_FORMAT_TIME, &gstDuration)) - duration = gstDuration / 1000000; - - if (m_duration != duration) { - m_duration = duration; - emit durationChanged(m_duration); - } - - gboolean seekable = false; - if (m_duration > 0) { - m_durationQueries = 0; - GstQuery *query = gst_query_new_seeking(GST_FORMAT_TIME); - if (gst_element_query(m_pipeline, query)) - gst_query_parse_seeking(query, 0, &seekable, 0, 0); - gst_query_unref(query); - } - setSeekable(seekable); - - if (m_durationQueries > 0) { - //increase delay between duration requests - int delay = 25 << (5 - m_durationQueries); - QTimer::singleShot(delay, this, SLOT(updateDuration())); - m_durationQueries--; - } -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO << m_duration; -#endif -} - -void QGstreamerPlayerSession::playbinNotifySource(GObject *o, GParamSpec *p, gpointer d) -{ - Q_UNUSED(p); - - GstElement *source = 0; - g_object_get(o, "source", &source, nullptr); - if (source == 0) - return; - -#ifdef DEBUG_PLAYBIN - qDebug() << "Playbin source added:" << G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(source)); -#endif - - // Set Headers - const QByteArray userAgentString("User-Agent"); - - QGstreamerPlayerSession *self = reinterpret_cast<QGstreamerPlayerSession *>(d); - - // User-Agent - special case, souphhtpsrc will always set something, even if - // defined in extra-headers - if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "user-agent") != 0) { - g_object_set(G_OBJECT(source), "user-agent", - self->m_request.rawHeader(userAgentString).constData(), nullptr); - } - - // The rest - if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "extra-headers") != 0) { - GstStructure *extras = qt_gst_structure_new_empty("extras"); - - const auto rawHeaderList = self->m_request.rawHeaderList(); - for (const QByteArray &rawHeader : rawHeaderList) { - if (rawHeader == userAgentString) // Filter User-Agent - continue; - else { - GValue headerValue; - - memset(&headerValue, 0, sizeof(GValue)); - g_value_init(&headerValue, G_TYPE_STRING); - - g_value_set_string(&headerValue, - self->m_request.rawHeader(rawHeader).constData()); - - gst_structure_set_value(extras, rawHeader.constData(), &headerValue); - } - } - - if (gst_structure_n_fields(extras) > 0) - g_object_set(G_OBJECT(source), "extra-headers", extras, nullptr); - - gst_structure_free(extras); - } - - //set timeout property to 30 seconds - const int timeout = 30; - if (qstrcmp(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(source)), "GstUDPSrc") == 0) { - quint64 convertedTimeout = timeout; -#if GST_CHECK_VERSION(1,0,0) - // Gst 1.x -> nanosecond - convertedTimeout *= 1000000000; -#else - // Gst 0.10 -> microsecond - convertedTimeout *= 1000000; -#endif - g_object_set(G_OBJECT(source), "timeout", convertedTimeout, nullptr); - self->m_sourceType = UDPSrc; - //The udpsrc is always a live source. - self->m_isLiveSource = true; - - QUrlQuery query(self->m_request.url()); - const QString var = QLatin1String("udpsrc.caps"); - if (query.hasQueryItem(var)) { - GstCaps *caps = gst_caps_from_string(query.queryItemValue(var).toLatin1().constData()); - g_object_set(G_OBJECT(source), "caps", caps, nullptr); - gst_caps_unref(caps); - } - } else if (qstrcmp(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(source)), "GstSoupHTTPSrc") == 0) { - //souphttpsrc timeout unit = second - g_object_set(G_OBJECT(source), "timeout", guint(timeout), nullptr); - self->m_sourceType = SoupHTTPSrc; - //since gst_base_src_is_live is not reliable, so we check the source property directly - gboolean isLive = false; - g_object_get(G_OBJECT(source), "is-live", &isLive, nullptr); - self->m_isLiveSource = isLive; - } else if (qstrcmp(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(source)), "GstMMSSrc") == 0) { - self->m_sourceType = MMSSrc; - self->m_isLiveSource = gst_base_src_is_live(GST_BASE_SRC(source)); - g_object_set(G_OBJECT(source), "tcp-timeout", G_GUINT64_CONSTANT(timeout*1000000), nullptr); - } else if (qstrcmp(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(source)), "GstRTSPSrc") == 0) { - //rtspsrc acts like a live source and will therefore only generate data in the PLAYING state. - self->m_sourceType = RTSPSrc; - self->m_isLiveSource = true; - g_object_set(G_OBJECT(source), "buffer-mode", 1, nullptr); - } else { - self->m_sourceType = UnknownSrc; - self->m_isLiveSource = gst_base_src_is_live(GST_BASE_SRC(source)); - } - -#ifdef DEBUG_PLAYBIN - if (self->m_isLiveSource) - qDebug() << "Current source is a live source"; - else - qDebug() << "Current source is a non-live source"; -#endif - - if (self->m_videoSink) - g_object_set(G_OBJECT(self->m_videoSink), "sync", !self->m_isLiveSource, nullptr); - - gst_object_unref(source); -} - -bool QGstreamerPlayerSession::isLiveSource() const -{ - return m_isLiveSource; -} - -void QGstreamerPlayerSession::handleVolumeChange(GObject *o, GParamSpec *p, gpointer d) -{ - Q_UNUSED(o); - Q_UNUSED(p); - QGstreamerPlayerSession *session = reinterpret_cast<QGstreamerPlayerSession *>(d); - QMetaObject::invokeMethod(session, "updateVolume", Qt::QueuedConnection); -} - -void QGstreamerPlayerSession::updateVolume() -{ - double volume = 1.0; - g_object_get(m_playbin, "volume", &volume, nullptr); - - if (m_volume != int(volume*100 + 0.5)) { - m_volume = int(volume*100 + 0.5); -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO << m_volume; -#endif - emit volumeChanged(m_volume); - } -} - -void QGstreamerPlayerSession::handleMutedChange(GObject *o, GParamSpec *p, gpointer d) -{ - Q_UNUSED(o); - Q_UNUSED(p); - QGstreamerPlayerSession *session = reinterpret_cast<QGstreamerPlayerSession *>(d); - QMetaObject::invokeMethod(session, "updateMuted", Qt::QueuedConnection); -} - -void QGstreamerPlayerSession::updateMuted() -{ - gboolean muted = FALSE; - g_object_get(G_OBJECT(m_playbin), "mute", &muted, nullptr); - if (m_muted != muted) { - m_muted = muted; -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO << m_muted; -#endif - emit mutedStateChanged(muted); - } -} - -#if !GST_CHECK_VERSION(0, 10, 33) -static gboolean factory_can_src_any_caps (GstElementFactory *factory, const GstCaps *caps) -{ - GList *templates; - - g_return_val_if_fail(factory != nullptr, FALSE); - g_return_val_if_fail(caps != nullptr, FALSE); - - templates = factory->staticpadtemplates; - - while (templates) { - GstStaticPadTemplate *templ = (GstStaticPadTemplate *)templates->data; - - if (templ->direction == GST_PAD_SRC) { - GstCaps *templcaps = gst_static_caps_get(&templ->static_caps); - - if (qt_gst_caps_can_intersect(caps, templcaps)) { - gst_caps_unref(templcaps); - return TRUE; - } - gst_caps_unref(templcaps); - } - templates = g_list_next(templates); - } - - return FALSE; -} -#endif - -GstAutoplugSelectResult QGstreamerPlayerSession::handleAutoplugSelect(GstBin *bin, GstPad *pad, GstCaps *caps, GstElementFactory *factory, QGstreamerPlayerSession *session) -{ - Q_UNUSED(bin); - Q_UNUSED(pad); - Q_UNUSED(caps); - - GstAutoplugSelectResult res = GST_AUTOPLUG_SELECT_TRY; - - // if VAAPI is available and can be used to decode but the current video sink cannot handle - // the decoded format, don't use it - const gchar *factoryName = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory)); - if (g_str_has_prefix(factoryName, "vaapi")) { - GstPad *sinkPad = gst_element_get_static_pad(session->m_videoSink, "sink"); -#if GST_CHECK_VERSION(1,0,0) - GstCaps *sinkCaps = gst_pad_query_caps(sinkPad, nullptr); -#else - GstCaps *sinkCaps = gst_pad_get_caps(sinkPad); -#endif - -#if !GST_CHECK_VERSION(0, 10, 33) - if (!factory_can_src_any_caps(factory, sinkCaps)) -#else - if (!gst_element_factory_can_src_any_caps(factory, sinkCaps)) -#endif - res = GST_AUTOPLUG_SELECT_SKIP; - - gst_object_unref(sinkPad); - gst_caps_unref(sinkCaps); - } - - return res; -} - -void QGstreamerPlayerSession::handleElementAdded(GstBin *bin, GstElement *element, QGstreamerPlayerSession *session) -{ - Q_UNUSED(bin); - //we have to configure queue2 element to enable media downloading - //and reporting available ranges, - //but it's added dynamically to playbin2 - - gchar *elementName = gst_element_get_name(element); - - if (g_str_has_prefix(elementName, "queue2")) { - // Disable on-disk buffering. - g_object_set(G_OBJECT(element), "temp-template", nullptr, nullptr); - } else if (g_str_has_prefix(elementName, "uridecodebin") || -#if GST_CHECK_VERSION(1,0,0) - g_str_has_prefix(elementName, "decodebin")) { -#else - g_str_has_prefix(elementName, "decodebin2")) { - if (g_str_has_prefix(elementName, "uridecodebin")) { - // Add video/x-surface (VAAPI) to default raw formats - g_object_set(G_OBJECT(element), "caps", gst_static_caps_get(&static_RawCaps), nullptr); - // listen for uridecodebin autoplug-select to skip VAAPI usage when the current - // video sink doesn't support it - g_signal_connect(element, "autoplug-select", G_CALLBACK(handleAutoplugSelect), session); - } -#endif - //listen for queue2 element added to uridecodebin/decodebin2 as well. - //Don't touch other bins since they may have unrelated queues - g_signal_connect(element, "element-added", - G_CALLBACK(handleElementAdded), session); - } - - g_free(elementName); -} - -void QGstreamerPlayerSession::handleStreamsChange(GstBin *bin, gpointer user_data) -{ - Q_UNUSED(bin); - - QGstreamerPlayerSession* session = reinterpret_cast<QGstreamerPlayerSession*>(user_data); - QMetaObject::invokeMethod(session, "getStreamsInfo", Qt::QueuedConnection); -} - -//doing proper operations when detecting an invalidMedia: change media status before signal the erorr -void QGstreamerPlayerSession::processInvalidMedia(QMediaPlayer::Error errorCode, const QString& errorString) -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO; -#endif - emit invalidMedia(); - stop(); - emit error(int(errorCode), errorString); -} - -void QGstreamerPlayerSession::showPrerollFrames(bool enabled) -{ -#ifdef DEBUG_PLAYBIN - qDebug() << Q_FUNC_INFO << enabled; -#endif - if (enabled != m_displayPrerolledFrame && m_videoSink && - g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "show-preroll-frame") != 0) { - - gboolean value = enabled; - g_object_set(G_OBJECT(m_videoSink), "show-preroll-frame", value, nullptr); - m_displayPrerolledFrame = enabled; - } -} - -void QGstreamerPlayerSession::addProbe(QGstreamerVideoProbeControl* probe) -{ - Q_ASSERT(!m_videoProbe); - m_videoProbe = probe; - addVideoBufferProbe(); -} - -void QGstreamerPlayerSession::removeProbe(QGstreamerVideoProbeControl* probe) -{ - Q_ASSERT(m_videoProbe == probe); - removeVideoBufferProbe(); - m_videoProbe = 0; -} - -void QGstreamerPlayerSession::addProbe(QGstreamerAudioProbeControl* probe) -{ - Q_ASSERT(!m_audioProbe); - m_audioProbe = probe; - addAudioBufferProbe(); -} - -void QGstreamerPlayerSession::removeProbe(QGstreamerAudioProbeControl* probe) -{ - Q_ASSERT(m_audioProbe == probe); - removeAudioBufferProbe(); - m_audioProbe = 0; -} - -// This function is similar to stop(), -// but does not set m_everPlayed, m_lastPosition, -// and setSeekable() values. -void QGstreamerPlayerSession::endOfMediaReset() -{ - if (m_renderer) - m_renderer->stopRenderer(); - - flushVideoProbes(); - gst_element_set_state(m_pipeline, GST_STATE_PAUSED); - - QMediaPlayer::State oldState = m_state; - m_pendingState = m_state = QMediaPlayer::StoppedState; - - finishVideoOutputChange(); - - if (oldState != m_state) - emit stateChanged(m_state); -} - -void QGstreamerPlayerSession::removeVideoBufferProbe() -{ - if (!m_videoProbe) - return; - - GstPad *pad = gst_element_get_static_pad(m_videoSink, "sink"); - if (pad) { - m_videoProbe->removeProbeFromPad(pad); - gst_object_unref(GST_OBJECT(pad)); - } -} - -void QGstreamerPlayerSession::addVideoBufferProbe() -{ - if (!m_videoProbe) - return; - - GstPad *pad = gst_element_get_static_pad(m_videoSink, "sink"); - if (pad) { - m_videoProbe->addProbeToPad(pad); - gst_object_unref(GST_OBJECT(pad)); - } -} - -void QGstreamerPlayerSession::removeAudioBufferProbe() -{ - if (!m_audioProbe) - return; - - GstPad *pad = gst_element_get_static_pad(m_audioSink, "sink"); - if (pad) { - m_audioProbe->removeProbeFromPad(pad); - gst_object_unref(GST_OBJECT(pad)); - } -} - -void QGstreamerPlayerSession::addAudioBufferProbe() -{ - if (!m_audioProbe) - return; - - GstPad *pad = gst_element_get_static_pad(m_audioSink, "sink"); - if (pad) { - m_audioProbe->addProbeToPad(pad); - gst_object_unref(GST_OBJECT(pad)); - } -} - -void QGstreamerPlayerSession::flushVideoProbes() -{ - if (m_videoProbe) - m_videoProbe->startFlushing(); -} - -void QGstreamerPlayerSession::resumeVideoProbes() -{ - if (m_videoProbe) - m_videoProbe->stopFlushing(); -} - -QT_END_NAMESPACE diff --git a/src/gsttools/qgstreamerplayersession_p.h b/src/gsttools/qgstreamerplayersession_p.h deleted file mode 100644 index 797229e69..000000000 --- a/src/gsttools/qgstreamerplayersession_p.h +++ /dev/null @@ -1,284 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERPLAYERSESSION_P_H -#define QGSTREAMERPLAYERSESSION_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtMultimedia/private/qtmultimediaglobal_p.h> -#include <QObject> -#include <QtCore/qmutex.h> -#include <QtNetwork/qnetworkrequest.h> -#include <private/qgstreamerplayercontrol_p.h> -#include <private/qgstreamerbushelper_p.h> -#include <qmediaplayer.h> -#include <qmediastreamscontrol.h> -#include <qaudioformat.h> - -#if QT_CONFIG(gstreamer_app) -#include <private/qgstappsrc_p.h> -#endif - -#include <gst/gst.h> - -QT_BEGIN_NAMESPACE - -class QGstreamerBusHelper; -class QGstreamerMessage; - -class QGstreamerVideoRendererInterface; -class QGstreamerVideoProbeControl; -class QGstreamerAudioProbeControl; - -typedef enum { - GST_AUTOPLUG_SELECT_TRY, - GST_AUTOPLUG_SELECT_EXPOSE, - GST_AUTOPLUG_SELECT_SKIP -} GstAutoplugSelectResult; - -class Q_GSTTOOLS_EXPORT QGstreamerPlayerSession - : public QObject - , public QGstreamerBusMessageFilter -{ -Q_OBJECT -Q_INTERFACES(QGstreamerBusMessageFilter) - -public: - QGstreamerPlayerSession(QObject *parent); - virtual ~QGstreamerPlayerSession(); - - GstElement *playbin() const; - GstElement *pipeline() const { return m_pipeline; } - QGstreamerBusHelper *bus() const { return m_busHelper; } - - QNetworkRequest request() const; - - QMediaPlayer::State state() const { return m_state; } - QMediaPlayer::State pendingState() const { return m_pendingState; } - - qint64 duration() const; - qint64 position() const; - - int volume() const; - bool isMuted() const; - - bool isAudioAvailable() const; - - void setVideoRenderer(QObject *renderer); - QGstreamerVideoRendererInterface *renderer() const { return m_renderer; } - bool isVideoAvailable() const; - - bool isSeekable() const; - - qreal playbackRate() const; - void setPlaybackRate(qreal rate); - - QMediaTimeRange availablePlaybackRanges() const; - - QMap<QByteArray ,QVariant> tags() const { return m_tags; } - QMap<QString,QVariant> streamProperties(int streamNumber) const { return m_streamProperties[streamNumber]; } - int streamCount() const { return m_streamProperties.count(); } - QMediaStreamsControl::StreamType streamType(int streamNumber) { return m_streamTypes.value(streamNumber, QMediaStreamsControl::UnknownStream); } - - int activeStream(QMediaStreamsControl::StreamType streamType) const; - void setActiveStream(QMediaStreamsControl::StreamType streamType, int streamNumber); - - bool processBusMessage(const QGstreamerMessage &message) override; - -#if QT_CONFIG(gstreamer_app) - QGstAppSrc *appsrc() const { return m_appSrc; } - static void configureAppSrcElement(GObject*, GObject*, GParamSpec*,QGstreamerPlayerSession* _this); -#endif - - bool isLiveSource() const; - - void addProbe(QGstreamerVideoProbeControl* probe); - void removeProbe(QGstreamerVideoProbeControl* probe); - - void addProbe(QGstreamerAudioProbeControl* probe); - void removeProbe(QGstreamerAudioProbeControl* probe); - - void endOfMediaReset(); - -public slots: - void loadFromUri(const QNetworkRequest &url); - void loadFromStream(const QNetworkRequest &url, QIODevice *stream); - bool play(); - bool pause(); - void stop(); - - bool seek(qint64 pos); - - void setVolume(int volume); - void setMuted(bool muted); - - void showPrerollFrames(bool enabled); - -signals: - void durationChanged(qint64 duration); - void positionChanged(qint64 position); - void stateChanged(QMediaPlayer::State state); - void volumeChanged(int volume); - void mutedStateChanged(bool muted); - void audioAvailableChanged(bool audioAvailable); - void videoAvailableChanged(bool videoAvailable); - void bufferingProgressChanged(int percentFilled); - void playbackFinished(); - void tagsChanged(); - void streamsChanged(); - void seekableChanged(bool); - void error(int error, const QString &errorString); - void invalidMedia(); - void playbackRateChanged(qreal); - void rendererChanged(); - void pipelineChanged(); - -private slots: - void getStreamsInfo(); - void setSeekable(bool); - void finishVideoOutputChange(); - void updateVideoRenderer(); - void updateVideoResolutionTag(); - void updateVolume(); - void updateMuted(); - void updateDuration(); - -private: - static void playbinNotifySource(GObject *o, GParamSpec *p, gpointer d); - static void handleVolumeChange(GObject *o, GParamSpec *p, gpointer d); - static void handleMutedChange(GObject *o, GParamSpec *p, gpointer d); -#if !GST_CHECK_VERSION(1,0,0) - static void insertColorSpaceElement(GstElement *element, gpointer data); -#endif - static void handleElementAdded(GstBin *bin, GstElement *element, QGstreamerPlayerSession *session); - static void handleStreamsChange(GstBin *bin, gpointer user_data); - static GstAutoplugSelectResult handleAutoplugSelect(GstBin *bin, GstPad *pad, GstCaps *caps, GstElementFactory *factory, QGstreamerPlayerSession *session); - - void processInvalidMedia(QMediaPlayer::Error errorCode, const QString& errorString); - - void removeVideoBufferProbe(); - void addVideoBufferProbe(); - void removeAudioBufferProbe(); - void addAudioBufferProbe(); - void flushVideoProbes(); - void resumeVideoProbes(); - bool parsePipeline(); - bool setPipeline(GstElement *pipeline); - void resetElements(); - void initPlaybin(); - void setBus(GstBus *bus); - - QNetworkRequest m_request; - QMediaPlayer::State m_state = QMediaPlayer::StoppedState; - QMediaPlayer::State m_pendingState = QMediaPlayer::StoppedState; - QGstreamerBusHelper *m_busHelper = nullptr; - GstElement *m_playbin = nullptr; - GstElement *m_pipeline = nullptr; - - GstElement *m_videoSink = nullptr; - - GstElement *m_videoOutputBin = nullptr; - GstElement *m_videoIdentity = nullptr; -#if !GST_CHECK_VERSION(1,0,0) - GstElement *m_colorSpace = nullptr; - bool m_usingColorspaceElement = false; -#endif - GstElement *m_pendingVideoSink = nullptr; - GstElement *m_nullVideoSink = nullptr; - - GstElement *m_audioSink = nullptr; - GstElement *m_volumeElement = nullptr; - - GstBus *m_bus = nullptr; - QObject *m_videoOutput = nullptr; - QGstreamerVideoRendererInterface *m_renderer = nullptr; - -#if QT_CONFIG(gstreamer_app) - QGstAppSrc *m_appSrc = nullptr; -#endif - - QMap<QByteArray, QVariant> m_tags; - QList< QMap<QString,QVariant> > m_streamProperties; - QList<QMediaStreamsControl::StreamType> m_streamTypes; - QMap<QMediaStreamsControl::StreamType, int> m_playbin2StreamOffset; - - QGstreamerVideoProbeControl *m_videoProbe = nullptr; - QGstreamerAudioProbeControl *m_audioProbe = nullptr; - - int m_volume = 100; - qreal m_playbackRate = 1.0; - bool m_muted = false; - bool m_audioAvailable = false; - bool m_videoAvailable = false; - bool m_seekable = false; - - mutable qint64 m_lastPosition = 0; - qint64 m_duration = 0; - int m_durationQueries = 0; - - bool m_displayPrerolledFrame = true; - - enum SourceType - { - UnknownSrc, - SoupHTTPSrc, - UDPSrc, - MMSSrc, - RTSPSrc, - }; - SourceType m_sourceType = UnknownSrc; - bool m_everPlayed = false; - bool m_isLiveSource = false; - - gulong pad_probe_id = 0; -}; - -QT_END_NAMESPACE - -#endif // QGSTREAMERPLAYERSESSION_H diff --git a/src/gsttools/qgstreamervideoinputdevicecontrol.cpp b/src/gsttools/qgstreamervideoinputdevicecontrol.cpp deleted file mode 100644 index 4d98afa62..000000000 --- a/src/gsttools/qgstreamervideoinputdevicecontrol.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgstreamervideoinputdevicecontrol_p.h" - -#include <QtCore/QDir> -#include <QtCore/QDebug> - -#include <private/qgstutils_p.h> - -QGstreamerVideoInputDeviceControl::QGstreamerVideoInputDeviceControl(QObject *parent) - : QVideoDeviceSelectorControl(parent) -{ -} - -QGstreamerVideoInputDeviceControl::QGstreamerVideoInputDeviceControl( - GstElementFactory *factory, QObject *parent) - : QVideoDeviceSelectorControl(parent) - , m_factory(factory) -{ - if (m_factory) - gst_object_ref(GST_OBJECT(m_factory)); -} - -QGstreamerVideoInputDeviceControl::~QGstreamerVideoInputDeviceControl() -{ - if (m_factory) - gst_object_unref(GST_OBJECT(m_factory)); -} - -int QGstreamerVideoInputDeviceControl::deviceCount() const -{ - return QGstUtils::enumerateCameras(m_factory).count(); -} - -QString QGstreamerVideoInputDeviceControl::deviceName(int index) const -{ - return QGstUtils::enumerateCameras(m_factory).value(index).name; -} - -QString QGstreamerVideoInputDeviceControl::deviceDescription(int index) const -{ - return QGstUtils::enumerateCameras(m_factory).value(index).description; -} - -int QGstreamerVideoInputDeviceControl::defaultDevice() const -{ - return 0; -} - -int QGstreamerVideoInputDeviceControl::selectedDevice() const -{ - return m_selectedDevice; -} - -void QGstreamerVideoInputDeviceControl::setSelectedDevice(int index) -{ - // Always update selected device and proxy it to clients - m_selectedDevice = index; - emit selectedDeviceChanged(index); - emit selectedDeviceChanged(deviceName(index)); -} diff --git a/src/gsttools/qgstreamervideoinputdevicecontrol_p.h b/src/gsttools/qgstreamervideoinputdevicecontrol_p.h deleted file mode 100644 index 9d8dffd72..000000000 --- a/src/gsttools/qgstreamervideoinputdevicecontrol_p.h +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERVIDEOINPUTDEVICECONTROL_H -#define QGSTREAMERVIDEOINPUTDEVICECONTROL_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <qvideodeviceselectorcontrol.h> -#include <QtCore/qstringlist.h> - -#include <gst/gst.h> -#include <qcamera.h> - -QT_BEGIN_NAMESPACE - -class Q_GSTTOOLS_EXPORT QGstreamerVideoInputDeviceControl : public QVideoDeviceSelectorControl -{ -Q_OBJECT -public: - QGstreamerVideoInputDeviceControl(QObject *parent); - QGstreamerVideoInputDeviceControl(GstElementFactory *factory, QObject *parent); - ~QGstreamerVideoInputDeviceControl(); - - int deviceCount() const override; - - QString deviceName(int index) const override; - QString deviceDescription(int index) const override; - - int defaultDevice() const override; - int selectedDevice() const override; - - static QString primaryCamera() { return tr("Main camera"); } - static QString secondaryCamera() { return tr("Front camera"); } - -public Q_SLOTS: - void setSelectedDevice(int index) override; - -private: - GstElementFactory *m_factory = nullptr; - - int m_selectedDevice = 0; -}; - -QT_END_NAMESPACE - -#endif // QGSTREAMERAUDIOINPUTDEVICECONTROL_H diff --git a/src/gsttools/qgstreamervideooverlay.cpp b/src/gsttools/qgstreamervideooverlay.cpp deleted file mode 100644 index ea8149442..000000000 --- a/src/gsttools/qgstreamervideooverlay.cpp +++ /dev/null @@ -1,639 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgstreamervideooverlay_p.h" - -#include <QtGui/qguiapplication.h> -#include "qgstutils_p.h" - -#if !GST_CHECK_VERSION(1,0,0) -#include <gst/interfaces/xoverlay.h> -#else -#include <gst/video/videooverlay.h> -#endif - -#include <QtMultimedia/private/qtmultimediaglobal_p.h> - -QT_BEGIN_NAMESPACE - -struct ElementMap -{ - const char *qtPlatform; - const char *gstreamerElement; -}; - -// Ordered by descending priority -static const ElementMap elementMap[] = -{ -#if QT_CONFIG(gstreamer_gl) - { "xcb", "glimagesink" }, -#endif - { "xcb", "vaapisink" }, - { "xcb", "xvimagesink" }, - { "xcb", "ximagesink" } -}; - -class QGstreamerSinkProperties -{ -public: - virtual ~QGstreamerSinkProperties() - { - } - - virtual bool hasShowPrerollFrame() const = 0; - virtual void reset() = 0; - virtual int brightness() const = 0; - virtual bool setBrightness(int brightness) = 0; - virtual int contrast() const = 0; - virtual bool setContrast(int contrast) = 0; - virtual int hue() const = 0; - virtual bool setHue(int hue) = 0; - virtual int saturation() const = 0; - virtual bool setSaturation(int saturation) = 0; - virtual Qt::AspectRatioMode aspectRatioMode() const = 0; - virtual void setAspectRatioMode(Qt::AspectRatioMode mode) = 0; -}; - -class QXVImageSinkProperties : public QGstreamerSinkProperties -{ -public: - QXVImageSinkProperties(GstElement *sink) - : m_videoSink(sink) - { - m_hasForceAspectRatio = g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "force-aspect-ratio"); - m_hasBrightness = g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "brightness"); - m_hasContrast = g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "contrast"); - m_hasHue = g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "hue"); - m_hasSaturation = g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "saturation"); - m_hasShowPrerollFrame = g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "show-preroll-frame"); - } - - bool hasShowPrerollFrame() const override - { - return m_hasShowPrerollFrame; - } - - void reset() override - { - setAspectRatioMode(m_aspectRatioMode); - setBrightness(m_brightness); - setContrast(m_contrast); - setHue(m_hue); - setSaturation(m_saturation); - } - - int brightness() const override - { - int brightness = 0; - if (m_hasBrightness) - g_object_get(G_OBJECT(m_videoSink), "brightness", &brightness, nullptr); - - return brightness / 10; - } - - bool setBrightness(int brightness) override - { - m_brightness = brightness; - if (m_hasBrightness) - g_object_set(G_OBJECT(m_videoSink), "brightness", brightness * 10, nullptr); - - return m_hasBrightness; - } - - int contrast() const override - { - int contrast = 0; - if (m_hasContrast) - g_object_get(G_OBJECT(m_videoSink), "contrast", &contrast, nullptr); - - return contrast / 10; - } - - bool setContrast(int contrast) override - { - m_contrast = contrast; - if (m_hasContrast) - g_object_set(G_OBJECT(m_videoSink), "contrast", contrast * 10, nullptr); - - return m_hasContrast; - } - - int hue() const override - { - int hue = 0; - if (m_hasHue) - g_object_get(G_OBJECT(m_videoSink), "hue", &hue, nullptr); - - return hue / 10; - } - - bool setHue(int hue) override - { - m_hue = hue; - if (m_hasHue) - g_object_set(G_OBJECT(m_videoSink), "hue", hue * 10, nullptr); - - return m_hasHue; - } - - int saturation() const override - { - int saturation = 0; - if (m_hasSaturation) - g_object_get(G_OBJECT(m_videoSink), "saturation", &saturation, nullptr); - - return saturation / 10; - } - - bool setSaturation(int saturation) override - { - m_saturation = saturation; - if (m_hasSaturation) - g_object_set(G_OBJECT(m_videoSink), "saturation", saturation * 10, nullptr); - - return m_hasSaturation; - } - - Qt::AspectRatioMode aspectRatioMode() const override - { - Qt::AspectRatioMode mode = Qt::KeepAspectRatio; - if (m_hasForceAspectRatio) { - gboolean forceAR = false; - g_object_get(G_OBJECT(m_videoSink), "force-aspect-ratio", &forceAR, nullptr); - if (!forceAR) - mode = Qt::IgnoreAspectRatio; - } - - return mode; - } - - void setAspectRatioMode(Qt::AspectRatioMode mode) override - { - m_aspectRatioMode = mode; - if (m_hasForceAspectRatio) { - g_object_set(G_OBJECT(m_videoSink), - "force-aspect-ratio", - (mode == Qt::KeepAspectRatio), - nullptr); - } - } - -protected: - - GstElement *m_videoSink = nullptr; - bool m_hasForceAspectRatio = false; - bool m_hasBrightness = false; - bool m_hasContrast = false; - bool m_hasHue = false; - bool m_hasSaturation = false; - bool m_hasShowPrerollFrame = false; - Qt::AspectRatioMode m_aspectRatioMode = Qt::KeepAspectRatio; - int m_brightness = 0; - int m_contrast = 0; - int m_hue = 0; - int m_saturation = 0; -}; - -class QVaapiSinkProperties : public QXVImageSinkProperties -{ -public: - QVaapiSinkProperties(GstElement *sink) - : QXVImageSinkProperties(sink) - { - // Set default values. - m_contrast = 1; - m_saturation = 1; - } - - int brightness() const override - { - gfloat brightness = 0; - if (m_hasBrightness) - g_object_get(G_OBJECT(m_videoSink), "brightness", &brightness, nullptr); - - return brightness * 100; // [-1,1] -> [-100,100] - } - - bool setBrightness(int brightness) override - { - m_brightness = brightness; - if (m_hasBrightness) { - gfloat v = brightness / 100.0; // [-100,100] -> [-1,1] - g_object_set(G_OBJECT(m_videoSink), "brightness", v, nullptr); - } - - return m_hasBrightness; - } - - int contrast() const override - { - gfloat contrast = 1; - if (m_hasContrast) - g_object_get(G_OBJECT(m_videoSink), "contrast", &contrast, nullptr); - - return (contrast - 1) * 100; // [0,2] -> [-100,100] - } - - bool setContrast(int contrast) override - { - m_contrast = contrast; - if (m_hasContrast) { - gfloat v = (contrast / 100.0) + 1; // [-100,100] -> [0,2] - g_object_set(G_OBJECT(m_videoSink), "contrast", v, nullptr); - } - - return m_hasContrast; - } - - int hue() const override - { - gfloat hue = 0; - if (m_hasHue) - g_object_get(G_OBJECT(m_videoSink), "hue", &hue, nullptr); - - return hue / 180 * 100; // [-180,180] -> [-100,100] - } - - bool setHue(int hue) override - { - m_hue = hue; - if (m_hasHue) { - gfloat v = hue / 100.0 * 180; // [-100,100] -> [-180,180] - g_object_set(G_OBJECT(m_videoSink), "hue", v, nullptr); - } - - return m_hasHue; - } - - int saturation() const override - { - gfloat saturation = 1; - if (m_hasSaturation) - g_object_get(G_OBJECT(m_videoSink), "saturation", &saturation, nullptr); - - return (saturation - 1) * 100; // [0,2] -> [-100,100] - } - - bool setSaturation(int saturation) override - { - m_saturation = saturation; - if (m_hasSaturation) { - gfloat v = (saturation / 100.0) + 1; // [-100,100] -> [0,2] - g_object_set(G_OBJECT(m_videoSink), "saturation", v, nullptr); - } - - return m_hasSaturation; - } -}; - -static bool qt_gst_element_is_functioning(GstElement *element) -{ - GstStateChangeReturn ret = gst_element_set_state(element, GST_STATE_READY); - if (ret == GST_STATE_CHANGE_SUCCESS) { - gst_element_set_state(element, GST_STATE_NULL); - return true; - } - - return false; -} - -static GstElement *findBestVideoSink() -{ - GstElement *choice = 0; - QString platform = QGuiApplication::platformName(); - - // We need a native window ID to use the GstVideoOverlay interface. - // Bail out if the Qt platform plugin in use cannot provide a sensible WId. - if (platform != QLatin1String("xcb")) - return 0; - - // First, try some known video sinks, depending on the Qt platform plugin in use. - for (quint32 i = 0; i < (sizeof(elementMap) / sizeof(ElementMap)); ++i) { -#if QT_CONFIG(gstreamer_gl) - if (!QGstUtils::useOpenGL() && qstrcmp(elementMap[i].gstreamerElement, "glimagesink") == 0) - continue; -#endif - if (platform == QLatin1String(elementMap[i].qtPlatform) - && (choice = gst_element_factory_make(elementMap[i].gstreamerElement, nullptr))) { - - if (qt_gst_element_is_functioning(choice)) - return choice; - - gst_object_unref(choice); - choice = 0; - } - } - - // If none of the known video sinks are available, try to find one that implements the - // GstVideoOverlay interface and has autoplugging rank. - GList *list = qt_gst_video_sinks(); - for (GList *item = list; item != nullptr; item = item->next) { - GstElementFactory *f = GST_ELEMENT_FACTORY(item->data); - - if (!gst_element_factory_has_interface(f, QT_GSTREAMER_VIDEOOVERLAY_INTERFACE_NAME)) - continue; - - if (GstElement *el = gst_element_factory_create(f, nullptr)) { - if (qt_gst_element_is_functioning(el)) { - choice = el; - break; - } - - gst_object_unref(el); - } - } - - gst_plugin_feature_list_free(list); - - return choice; -} - -QGstreamerVideoOverlay::QGstreamerVideoOverlay(QObject *parent, const QByteArray &elementName) - : QObject(parent) - , QGstreamerBufferProbe(QGstreamerBufferProbe::ProbeCaps) -{ - GstElement *sink = nullptr; - if (!elementName.isEmpty()) - sink = gst_element_factory_make(elementName.constData(), nullptr); - else - sink = findBestVideoSink(); - - setVideoSink(sink); -} - -QGstreamerVideoOverlay::~QGstreamerVideoOverlay() -{ - if (m_videoSink) { - delete m_sinkProperties; - GstPad *pad = gst_element_get_static_pad(m_videoSink, "sink"); - removeProbeFromPad(pad); - gst_object_unref(GST_OBJECT(pad)); - gst_object_unref(GST_OBJECT(m_videoSink)); - } -} - -GstElement *QGstreamerVideoOverlay::videoSink() const -{ - return m_videoSink; -} - -void QGstreamerVideoOverlay::setVideoSink(GstElement *sink) -{ - if (!sink) - return; - - if (m_videoSink) - gst_object_unref(GST_OBJECT(m_videoSink)); - - m_videoSink = sink; - qt_gst_object_ref_sink(GST_OBJECT(m_videoSink)); - - GstPad *pad = gst_element_get_static_pad(m_videoSink, "sink"); - addProbeToPad(pad); - gst_object_unref(GST_OBJECT(pad)); - - QString sinkName(QLatin1String(GST_OBJECT_NAME(sink))); - bool isVaapi = sinkName.startsWith(QLatin1String("vaapisink")); - delete m_sinkProperties; - m_sinkProperties = isVaapi ? new QVaapiSinkProperties(sink) : new QXVImageSinkProperties(sink); - - if (m_sinkProperties->hasShowPrerollFrame()) - g_signal_connect(m_videoSink, "notify::show-preroll-frame", - G_CALLBACK(showPrerollFrameChanged), this); -} - -QSize QGstreamerVideoOverlay::nativeVideoSize() const -{ - return m_nativeVideoSize; -} - -void QGstreamerVideoOverlay::setWindowHandle(WId id) -{ - m_windowId = id; - - if (isActive()) - setWindowHandle_helper(id); -} - -void QGstreamerVideoOverlay::setWindowHandle_helper(WId id) -{ -#if GST_CHECK_VERSION(1,0,0) - if (m_videoSink && GST_IS_VIDEO_OVERLAY(m_videoSink)) { - gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(m_videoSink), id); -#else - if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) { -# if GST_CHECK_VERSION(0,10,31) - gst_x_overlay_set_window_handle(GST_X_OVERLAY(m_videoSink), id); -# else - gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(m_videoSink), id); -# endif -#endif - - // Properties need to be reset when changing the winId. - m_sinkProperties->reset(); - } -} - -void QGstreamerVideoOverlay::expose() -{ - if (!isActive()) - return; - -#if !GST_CHECK_VERSION(1,0,0) - if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) - gst_x_overlay_expose(GST_X_OVERLAY(m_videoSink)); -#else - if (m_videoSink && GST_IS_VIDEO_OVERLAY(m_videoSink)) { - gst_video_overlay_expose(GST_VIDEO_OVERLAY(m_videoSink)); - } -#endif -} - -void QGstreamerVideoOverlay::setRenderRectangle(const QRect &rect) -{ - int x = -1; - int y = -1; - int w = -1; - int h = -1; - - if (!rect.isEmpty()) { - x = rect.x(); - y = rect.y(); - w = rect.width(); - h = rect.height(); - } - -#if GST_CHECK_VERSION(1,0,0) - if (m_videoSink && GST_IS_VIDEO_OVERLAY(m_videoSink)) - gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(m_videoSink), x, y, w, h); -#elif GST_CHECK_VERSION(0, 10, 29) - if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) - gst_x_overlay_set_render_rectangle(GST_X_OVERLAY(m_videoSink), x, y , w , h); -#else - Q_UNUSED(x); - Q_UNUSED(y); - Q_UNUSED(w); - Q_UNUSED(h); -#endif -} - -bool QGstreamerVideoOverlay::processSyncMessage(const QGstreamerMessage &message) -{ - GstMessage* gm = message.rawMessage(); - -#if !GST_CHECK_VERSION(1,0,0) - if (gm && (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT) && - gst_structure_has_name(gm->structure, "prepare-xwindow-id")) { -#else - if (gm && (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT) && - gst_structure_has_name(gst_message_get_structure(gm), "prepare-window-handle")) { -#endif - setWindowHandle_helper(m_windowId); - return true; - } - - return false; -} - -bool QGstreamerVideoOverlay::processBusMessage(const QGstreamerMessage &message) -{ - GstMessage* gm = message.rawMessage(); - - if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_STATE_CHANGED && - GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_videoSink)) { - - updateIsActive(); - } - - return false; -} - -void QGstreamerVideoOverlay::probeCaps(GstCaps *caps) -{ - QSize size = QGstUtils::capsCorrectedResolution(caps); - if (size != m_nativeVideoSize) { - m_nativeVideoSize = size; - emit nativeVideoSizeChanged(); - } -} - -bool QGstreamerVideoOverlay::isActive() const -{ - return m_isActive; -} - -void QGstreamerVideoOverlay::updateIsActive() -{ - if (!m_videoSink) - return; - - GstState state = GST_STATE(m_videoSink); - gboolean showPreroll = true; - - if (m_sinkProperties->hasShowPrerollFrame()) - g_object_get(G_OBJECT(m_videoSink), "show-preroll-frame", &showPreroll, nullptr); - - bool newIsActive = (state == GST_STATE_PLAYING || (state == GST_STATE_PAUSED && showPreroll)); - - if (newIsActive != m_isActive) { - m_isActive = newIsActive; - emit activeChanged(); - } -} - -void QGstreamerVideoOverlay::showPrerollFrameChanged(GObject *, GParamSpec *, QGstreamerVideoOverlay *overlay) -{ - overlay->updateIsActive(); -} - -Qt::AspectRatioMode QGstreamerVideoOverlay::aspectRatioMode() const -{ - return m_sinkProperties->aspectRatioMode(); -} - -void QGstreamerVideoOverlay::setAspectRatioMode(Qt::AspectRatioMode mode) -{ - m_sinkProperties->setAspectRatioMode(mode); -} - -int QGstreamerVideoOverlay::brightness() const -{ - return m_sinkProperties->brightness(); -} - -void QGstreamerVideoOverlay::setBrightness(int brightness) -{ - if (m_sinkProperties->setBrightness(brightness)) - emit brightnessChanged(brightness); -} - -int QGstreamerVideoOverlay::contrast() const -{ - return m_sinkProperties->contrast(); -} - -void QGstreamerVideoOverlay::setContrast(int contrast) -{ - if (m_sinkProperties->setContrast(contrast)) - emit contrastChanged(contrast); -} - -int QGstreamerVideoOverlay::hue() const -{ - return m_sinkProperties->hue(); -} - -void QGstreamerVideoOverlay::setHue(int hue) -{ - if (m_sinkProperties->setHue(hue)) - emit hueChanged(hue); -} - -int QGstreamerVideoOverlay::saturation() const -{ - return m_sinkProperties->saturation(); -} - -void QGstreamerVideoOverlay::setSaturation(int saturation) -{ - if (m_sinkProperties->setSaturation(saturation)) - emit saturationChanged(saturation); -} - -QT_END_NAMESPACE diff --git a/src/gsttools/qgstreamervideooverlay_p.h b/src/gsttools/qgstreamervideooverlay_p.h deleted file mode 100644 index f2ca8a23b..000000000 --- a/src/gsttools/qgstreamervideooverlay_p.h +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERVIDEOOVERLAY_P_H -#define QGSTREAMERVIDEOOVERLAY_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgstreamerbushelper_p.h> -#include <private/qgstreamerbufferprobe_p.h> -#include <QtGui/qwindowdefs.h> -#include <QtCore/qsize.h> - -QT_BEGIN_NAMESPACE - -class QGstreamerSinkProperties; -class QGstreamerVideoOverlay - : public QObject - , public QGstreamerSyncMessageFilter - , public QGstreamerBusMessageFilter - , private QGstreamerBufferProbe -{ - Q_OBJECT - Q_INTERFACES(QGstreamerSyncMessageFilter QGstreamerBusMessageFilter) -public: - explicit QGstreamerVideoOverlay(QObject *parent = 0, const QByteArray &elementName = QByteArray()); - virtual ~QGstreamerVideoOverlay(); - - GstElement *videoSink() const; - void setVideoSink(GstElement *); - QSize nativeVideoSize() const; - - void setWindowHandle(WId id); - void expose(); - void setRenderRectangle(const QRect &rect); - - bool isActive() const; - - Qt::AspectRatioMode aspectRatioMode() const; - void setAspectRatioMode(Qt::AspectRatioMode mode); - - int brightness() const; - void setBrightness(int brightness); - - int contrast() const; - void setContrast(int contrast); - - int hue() const; - void setHue(int hue); - - int saturation() const; - void setSaturation(int saturation); - - bool processSyncMessage(const QGstreamerMessage &message) override; - bool processBusMessage(const QGstreamerMessage &message) override; - -Q_SIGNALS: - void nativeVideoSizeChanged(); - void activeChanged(); - void brightnessChanged(int brightness); - void contrastChanged(int contrast); - void hueChanged(int hue); - void saturationChanged(int saturation); - -private: - void setWindowHandle_helper(WId id); - void updateIsActive(); - void probeCaps(GstCaps *caps) override; - static void showPrerollFrameChanged(GObject *, GParamSpec *, QGstreamerVideoOverlay *); - - GstElement *m_videoSink = nullptr; - QSize m_nativeVideoSize; - bool m_isActive = false; - - QGstreamerSinkProperties *m_sinkProperties = nullptr; - WId m_windowId = 0; -}; - -QT_END_NAMESPACE - -#endif // QGSTREAMERVIDEOOVERLAY_P_H - diff --git a/src/gsttools/qgstreamervideoprobecontrol.cpp b/src/gsttools/qgstreamervideoprobecontrol.cpp deleted file mode 100644 index f9ce4e412..000000000 --- a/src/gsttools/qgstreamervideoprobecontrol.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgstreamervideoprobecontrol_p.h" - -#include "qgstutils_p.h" -#include <private/qgstvideobuffer_p.h> - -QGstreamerVideoProbeControl::QGstreamerVideoProbeControl(QObject *parent) - : QMediaVideoProbeControl(parent) -{ -} - -QGstreamerVideoProbeControl::~QGstreamerVideoProbeControl() -{ -} - -void QGstreamerVideoProbeControl::startFlushing() -{ - m_flushing = true; - - { - QMutexLocker locker(&m_frameMutex); - m_pendingFrame = QVideoFrame(); - } - - // only emit flush if at least one frame was probed - if (m_frameProbed) - emit flush(); -} - -void QGstreamerVideoProbeControl::stopFlushing() -{ - m_flushing = false; -} - -void QGstreamerVideoProbeControl::probeCaps(GstCaps *caps) -{ -#if GST_CHECK_VERSION(1,0,0) - GstVideoInfo videoInfo; - QVideoSurfaceFormat format = QGstUtils::formatForCaps(caps, &videoInfo); - - QMutexLocker locker(&m_frameMutex); - m_videoInfo = videoInfo; -#else - int bytesPerLine = 0; - QVideoSurfaceFormat format = QGstUtils::formatForCaps(caps, &bytesPerLine); - - QMutexLocker locker(&m_frameMutex); - m_bytesPerLine = bytesPerLine; -#endif - m_format = format; -} - -bool QGstreamerVideoProbeControl::probeBuffer(GstBuffer *buffer) -{ - QMutexLocker locker(&m_frameMutex); - - if (m_flushing || !m_format.isValid()) - return true; - - QVideoFrame frame( -#if GST_CHECK_VERSION(1,0,0) - new QGstVideoBuffer(buffer, m_videoInfo), -#else - new QGstVideoBuffer(buffer, m_bytesPerLine), -#endif - m_format.frameSize(), - m_format.pixelFormat()); - - QGstUtils::setFrameTimeStamps(&frame, buffer); - - m_frameProbed = true; - - if (!m_pendingFrame.isValid()) - QMetaObject::invokeMethod(this, "frameProbed", Qt::QueuedConnection); - m_pendingFrame = frame; - - return true; -} - -void QGstreamerVideoProbeControl::frameProbed() -{ - QVideoFrame frame; - { - QMutexLocker locker(&m_frameMutex); - if (!m_pendingFrame.isValid()) - return; - frame = m_pendingFrame; - m_pendingFrame = QVideoFrame(); - } - emit videoFrameProbed(frame); -} diff --git a/src/gsttools/qgstreamervideoprobecontrol_p.h b/src/gsttools/qgstreamervideoprobecontrol_p.h deleted file mode 100644 index 8f2101d74..000000000 --- a/src/gsttools/qgstreamervideoprobecontrol_p.h +++ /dev/null @@ -1,100 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERVIDEOPROBECONTROL_H -#define QGSTREAMERVIDEOPROBECONTROL_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <gst/gst.h> -#include <gst/video/video.h> -#include <qmediavideoprobecontrol.h> -#include <QtCore/qmutex.h> -#include <qvideoframe.h> -#include <qvideosurfaceformat.h> - -#include <private/qgstreamerbufferprobe_p.h> - -QT_BEGIN_NAMESPACE - -class Q_GSTTOOLS_EXPORT QGstreamerVideoProbeControl - : public QMediaVideoProbeControl - , public QGstreamerBufferProbe - , public QSharedData -{ - Q_OBJECT -public: - explicit QGstreamerVideoProbeControl(QObject *parent); - virtual ~QGstreamerVideoProbeControl(); - - void probeCaps(GstCaps *caps) override; - bool probeBuffer(GstBuffer *buffer) override; - - void startFlushing(); - void stopFlushing(); - -private slots: - void frameProbed(); - -private: - QVideoSurfaceFormat m_format; - QVideoFrame m_pendingFrame; - QMutex m_frameMutex; -#if GST_CHECK_VERSION(1,0,0) - GstVideoInfo m_videoInfo; -#else - int m_bytesPerLine = 0; -#endif - bool m_flushing = false; - bool m_frameProbed = false; // true if at least one frame was probed -}; - -QT_END_NAMESPACE - -#endif // QGSTREAMERVIDEOPROBECONTROL_H diff --git a/src/gsttools/qgstreamervideorenderer.cpp b/src/gsttools/qgstreamervideorenderer.cpp deleted file mode 100644 index c2226d658..000000000 --- a/src/gsttools/qgstreamervideorenderer.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgstreamervideorenderer_p.h" -#include <private/qvideosurfacegstsink_p.h> -#include <private/qgstutils_p.h> -#include <qabstractvideosurface.h> -#include <QtCore/qdebug.h> - -#include <gst/gst.h> - -static inline void resetSink(GstElement *&element, GstElement *v = nullptr) -{ - if (element) - gst_object_unref(GST_OBJECT(element)); - - if (v) - qt_gst_object_ref_sink(GST_OBJECT(v)); - - element = v; -} - -QGstreamerVideoRenderer::QGstreamerVideoRenderer(QObject *parent) - : QVideoRendererControl(parent) -{ -} - -QGstreamerVideoRenderer::~QGstreamerVideoRenderer() -{ - resetSink(m_videoSink); -} - -void QGstreamerVideoRenderer::setVideoSink(GstElement *sink) -{ - if (!sink) - return; - - resetSink(m_videoSink, sink); - emit sinkChanged(); -} - -GstElement *QGstreamerVideoRenderer::videoSink() -{ - if (!m_videoSink && m_surface) { - auto sink = reinterpret_cast<GstElement *>(QVideoSurfaceGstSink::createSink(m_surface)); - resetSink(m_videoSink, sink); - } - - return m_videoSink; -} - -void QGstreamerVideoRenderer::stopRenderer() -{ - if (m_surface) - m_surface->stop(); -} - -QAbstractVideoSurface *QGstreamerVideoRenderer::surface() const -{ - return m_surface; -} - -void QGstreamerVideoRenderer::setSurface(QAbstractVideoSurface *surface) -{ - if (m_surface != surface) { - resetSink(m_videoSink); - - if (m_surface) { - disconnect(m_surface.data(), SIGNAL(supportedFormatsChanged()), - this, SLOT(handleFormatChange())); - } - - bool wasReady = isReady(); - - m_surface = surface; - - if (m_surface) { - connect(m_surface.data(), SIGNAL(supportedFormatsChanged()), - this, SLOT(handleFormatChange())); - } - - if (wasReady != isReady()) - emit readyChanged(isReady()); - - emit sinkChanged(); - } -} - -void QGstreamerVideoRenderer::handleFormatChange() -{ - setVideoSink(nullptr); -} diff --git a/src/gsttools/qgstreamervideorenderer_p.h b/src/gsttools/qgstreamervideorenderer_p.h deleted file mode 100644 index d87bfcb8f..000000000 --- a/src/gsttools/qgstreamervideorenderer_p.h +++ /dev/null @@ -1,94 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERVIDEORENDERER_H -#define QGSTREAMERVIDEORENDERER_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <qvideorenderercontrol.h> -#include <private/qvideosurfacegstsink_p.h> -#include <qabstractvideosurface.h> - -#include "qgstreamervideorendererinterface_p.h" - -QT_BEGIN_NAMESPACE - -class Q_GSTTOOLS_EXPORT QGstreamerVideoRenderer : public QVideoRendererControl, public QGstreamerVideoRendererInterface -{ - Q_OBJECT - Q_INTERFACES(QGstreamerVideoRendererInterface) -public: - QGstreamerVideoRenderer(QObject *parent = 0); - virtual ~QGstreamerVideoRenderer(); - - QAbstractVideoSurface *surface() const override; - void setSurface(QAbstractVideoSurface *surface) override; - - GstElement *videoSink() override; - void setVideoSink(GstElement *) override; - - void stopRenderer() override; - bool isReady() const override { return m_surface != 0; } - -signals: - void sinkChanged(); - void readyChanged(bool); - -private slots: - void handleFormatChange(); - -private: - GstElement *m_videoSink = nullptr; - QPointer<QAbstractVideoSurface> m_surface; -}; - -QT_END_NAMESPACE - -#endif // QGSTREAMERVIDEORENDRER_H diff --git a/src/gsttools/qgstreamervideorendererinterface.cpp b/src/gsttools/qgstreamervideorendererinterface.cpp deleted file mode 100644 index ae7de06f1..000000000 --- a/src/gsttools/qgstreamervideorendererinterface.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgstreamervideorendererinterface_p.h" - -QGstreamerVideoRendererInterface::~QGstreamerVideoRendererInterface() -{ -} diff --git a/src/gsttools/qgstreamervideorendererinterface_p.h b/src/gsttools/qgstreamervideorendererinterface_p.h deleted file mode 100644 index 231c843db..000000000 --- a/src/gsttools/qgstreamervideorendererinterface_p.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERVIDEOOUTPUTCONTROL_H -#define QGSTREAMERVIDEOOUTPUTCONTROL_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <gst/gst.h> - -#include <QtCore/qobject.h> - -QT_BEGIN_NAMESPACE - -class QGstreamerVideoRendererInterface -{ -public: - virtual ~QGstreamerVideoRendererInterface(); - virtual GstElement *videoSink() = 0; - virtual void setVideoSink(GstElement *) {}; - - //stopRenderer() is called when the renderer element is stopped. - //it can be reimplemented when video renderer can't detect - //changes to NULL state but has to free video resources. - virtual void stopRenderer() {} - - //the video output is configured, usually after the first paint event - //(winId is known, - virtual bool isReady() const { return true; } - - //signals: - //void sinkChanged(); - //void readyChanged(bool); -}; - -#define QGstreamerVideoRendererInterface_iid "org.qt-project.qt.gstreamervideorenderer/5.0" -Q_DECLARE_INTERFACE(QGstreamerVideoRendererInterface, QGstreamerVideoRendererInterface_iid) -QT_END_NAMESPACE - -#endif diff --git a/src/gsttools/qgstreamervideowidget.cpp b/src/gsttools/qgstreamervideowidget.cpp deleted file mode 100644 index 4137aff32..000000000 --- a/src/gsttools/qgstreamervideowidget.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgstreamervideowidget_p.h" -#include "qgstutils_p.h" - -#include <QtCore/qcoreevent.h> -#include <QtCore/qdebug.h> -#include <QtGui/qpainter.h> - -QT_BEGIN_NAMESPACE - -class QGstreamerVideoWidget : public QWidget -{ -public: - QGstreamerVideoWidget(QWidget *parent = 0) - :QWidget(parent) - { - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - QPalette palette; - palette.setColor(QPalette::Window, Qt::black); - setPalette(palette); - } - - virtual ~QGstreamerVideoWidget() {} - - QSize sizeHint() const override - { - return m_nativeSize; - } - - void setNativeSize( const QSize &size) - { - if (size != m_nativeSize) { - m_nativeSize = size; - if (size.isEmpty()) - setMinimumSize(0,0); - else - setMinimumSize(160,120); - - updateGeometry(); - } - } - - void paint_helper() - { - QPainter painter(this); - painter.fillRect(rect(), palette().window()); - } - -protected: - void paintEvent(QPaintEvent *) override - { - paint_helper(); - } - - QSize m_nativeSize; -}; - -QGstreamerVideoWidgetControl::QGstreamerVideoWidgetControl(QObject *parent, const QByteArray &elementName) - : QVideoWidgetControl(parent) - , m_videoOverlay(this, !elementName.isEmpty() ? elementName : qgetenv("QT_GSTREAMER_WIDGET_VIDEOSINK")) -{ - connect(&m_videoOverlay, &QGstreamerVideoOverlay::activeChanged, - this, &QGstreamerVideoWidgetControl::onOverlayActiveChanged); - connect(&m_videoOverlay, &QGstreamerVideoOverlay::nativeVideoSizeChanged, - this, &QGstreamerVideoWidgetControl::onNativeVideoSizeChanged); - connect(&m_videoOverlay, &QGstreamerVideoOverlay::brightnessChanged, - this, &QGstreamerVideoWidgetControl::brightnessChanged); - connect(&m_videoOverlay, &QGstreamerVideoOverlay::contrastChanged, - this, &QGstreamerVideoWidgetControl::contrastChanged); - connect(&m_videoOverlay, &QGstreamerVideoOverlay::hueChanged, - this, &QGstreamerVideoWidgetControl::hueChanged); - connect(&m_videoOverlay, &QGstreamerVideoOverlay::saturationChanged, - this, &QGstreamerVideoWidgetControl::saturationChanged); -} - -QGstreamerVideoWidgetControl::~QGstreamerVideoWidgetControl() -{ - delete m_widget; -} - -void QGstreamerVideoWidgetControl::createVideoWidget() -{ - if (m_widget) - return; - - m_widget = new QGstreamerVideoWidget; - - m_widget->installEventFilter(this); - m_videoOverlay.setWindowHandle(m_windowId = m_widget->winId()); -} - -GstElement *QGstreamerVideoWidgetControl::videoSink() -{ - return m_videoOverlay.videoSink(); -} - -void QGstreamerVideoWidgetControl::setVideoSink(GstElement *sink) -{ - m_videoOverlay.setVideoSink(sink); -} - -void QGstreamerVideoWidgetControl::onOverlayActiveChanged() -{ - updateWidgetAttributes(); -} - -void QGstreamerVideoWidgetControl::stopRenderer() -{ - m_stopped = true; - updateWidgetAttributes(); - m_widget->setNativeSize(QSize()); -} - -void QGstreamerVideoWidgetControl::onNativeVideoSizeChanged() -{ - const QSize &size = m_videoOverlay.nativeVideoSize(); - - if (size.isValid()) - m_stopped = false; - - if (m_widget) - m_widget->setNativeSize(size); -} - -bool QGstreamerVideoWidgetControl::eventFilter(QObject *object, QEvent *e) -{ - if (m_widget && object == m_widget) { - if (e->type() == QEvent::ParentChange || e->type() == QEvent::Show || e->type() == QEvent::WinIdChange) { - WId newWId = m_widget->winId(); - if (newWId != m_windowId) - m_videoOverlay.setWindowHandle(m_windowId = newWId); - } - - if (e->type() == QEvent::Paint) { - // Update overlay by new size if any. - if (QGstUtils::useOpenGL()) - m_videoOverlay.setRenderRectangle(QRect(0, 0, m_widget->width(), m_widget->height())); - if (m_videoOverlay.isActive()) - m_videoOverlay.expose(); // triggers a repaint of the last frame - else - m_widget->paint_helper(); // paints the black background - - return true; - } - } - - return false; -} - -void QGstreamerVideoWidgetControl::updateWidgetAttributes() -{ - // When frames are being rendered (sink is active), we need the WA_PaintOnScreen attribute to - // be set in order to avoid flickering when the widget is repainted (for example when resized). - // We need to clear that flag when the the sink is inactive to allow the widget to paint its - // background, otherwise some garbage will be displayed. - if (m_videoOverlay.isActive() && !m_stopped) { - m_widget->setAttribute(Qt::WA_NoSystemBackground, true); - m_widget->setAttribute(Qt::WA_PaintOnScreen, true); - } else { - m_widget->setAttribute(Qt::WA_NoSystemBackground, false); - m_widget->setAttribute(Qt::WA_PaintOnScreen, false); - m_widget->update(); - } -} - -bool QGstreamerVideoWidgetControl::processSyncMessage(const QGstreamerMessage &message) -{ - return m_videoOverlay.processSyncMessage(message); -} - -bool QGstreamerVideoWidgetControl::processBusMessage(const QGstreamerMessage &message) -{ - return m_videoOverlay.processBusMessage(message); -} - -QWidget *QGstreamerVideoWidgetControl::videoWidget() -{ - createVideoWidget(); - return m_widget; -} - -Qt::AspectRatioMode QGstreamerVideoWidgetControl::aspectRatioMode() const -{ - return m_videoOverlay.aspectRatioMode(); -} - -void QGstreamerVideoWidgetControl::setAspectRatioMode(Qt::AspectRatioMode mode) -{ - m_videoOverlay.setAspectRatioMode(mode); -} - -bool QGstreamerVideoWidgetControl::isFullScreen() const -{ - return m_fullScreen; -} - -void QGstreamerVideoWidgetControl::setFullScreen(bool fullScreen) -{ - emit fullScreenChanged(m_fullScreen = fullScreen); -} - -int QGstreamerVideoWidgetControl::brightness() const -{ - return m_videoOverlay.brightness(); -} - -void QGstreamerVideoWidgetControl::setBrightness(int brightness) -{ - m_videoOverlay.setBrightness(brightness); -} - -int QGstreamerVideoWidgetControl::contrast() const -{ - return m_videoOverlay.contrast(); -} - -void QGstreamerVideoWidgetControl::setContrast(int contrast) -{ - m_videoOverlay.setContrast(contrast); -} - -int QGstreamerVideoWidgetControl::hue() const -{ - return m_videoOverlay.hue(); -} - -void QGstreamerVideoWidgetControl::setHue(int hue) -{ - m_videoOverlay.setHue(hue); -} - -int QGstreamerVideoWidgetControl::saturation() const -{ - return m_videoOverlay.saturation(); -} - -void QGstreamerVideoWidgetControl::setSaturation(int saturation) -{ - m_videoOverlay.setSaturation(saturation); -} - -QT_END_NAMESPACE diff --git a/src/gsttools/qgstreamervideowidget_p.h b/src/gsttools/qgstreamervideowidget_p.h deleted file mode 100644 index 6eec6ae52..000000000 --- a/src/gsttools/qgstreamervideowidget_p.h +++ /dev/null @@ -1,128 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERVIDEOWIDGET_H -#define QGSTREAMERVIDEOWIDGET_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <qvideowidgetcontrol.h> - -#include "qgstreamervideorendererinterface_p.h" -#include <private/qgstreamerbushelper_p.h> -#include <private/qgstreamervideooverlay_p.h> - -QT_BEGIN_NAMESPACE - -class Q_GSTTOOLS_EXPORT QGstreamerVideoWidget; - -class Q_GSTTOOLS_EXPORT QGstreamerVideoWidgetControl - : public QVideoWidgetControl - , public QGstreamerVideoRendererInterface - , public QGstreamerSyncMessageFilter - , public QGstreamerBusMessageFilter -{ - Q_OBJECT - Q_INTERFACES(QGstreamerVideoRendererInterface QGstreamerSyncMessageFilter QGstreamerBusMessageFilter) -public: - explicit QGstreamerVideoWidgetControl(QObject *parent = 0, const QByteArray &elementName = QByteArray()); - virtual ~QGstreamerVideoWidgetControl(); - - GstElement *videoSink() override; - void setVideoSink(GstElement *) override; - - QWidget *videoWidget() override; - - void stopRenderer() override; - - Qt::AspectRatioMode aspectRatioMode() const override; - void setAspectRatioMode(Qt::AspectRatioMode mode) override; - - bool isFullScreen() const override; - void setFullScreen(bool fullScreen) override; - - int brightness() const override; - void setBrightness(int brightness) override; - - int contrast() const override; - void setContrast(int contrast) override; - - int hue() const override; - void setHue(int hue) override; - - int saturation() const override; - void setSaturation(int saturation) override; - - bool eventFilter(QObject *object, QEvent *event) override; - -signals: - void sinkChanged(); - void readyChanged(bool); - -private Q_SLOTS: - void onOverlayActiveChanged(); - void onNativeVideoSizeChanged(); - -private: - void createVideoWidget(); - void updateWidgetAttributes(); - - bool processSyncMessage(const QGstreamerMessage &message) override; - bool processBusMessage(const QGstreamerMessage &message) override; - - QGstreamerVideoOverlay m_videoOverlay; - QGstreamerVideoWidget *m_widget = nullptr; - bool m_stopped = false; - WId m_windowId = 0; - bool m_fullScreen = false; -}; - -QT_END_NAMESPACE - -#endif // QGSTREAMERVIDEOWIDGET_H diff --git a/src/gsttools/qgstreamervideowindow.cpp b/src/gsttools/qgstreamervideowindow.cpp deleted file mode 100644 index e7e3c5044..000000000 --- a/src/gsttools/qgstreamervideowindow.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgstreamervideowindow_p.h" -#include <private/qgstutils_p.h> - -#include <QtCore/qdebug.h> - -QGstreamerVideoWindow::QGstreamerVideoWindow(QObject *parent, const QByteArray &elementName) - : QVideoWindowControl(parent) - , m_videoOverlay(this, !elementName.isEmpty() ? elementName : qgetenv("QT_GSTREAMER_WINDOW_VIDEOSINK")) -{ - connect(&m_videoOverlay, &QGstreamerVideoOverlay::nativeVideoSizeChanged, - this, &QGstreamerVideoWindow::nativeSizeChanged); - connect(&m_videoOverlay, &QGstreamerVideoOverlay::brightnessChanged, - this, &QGstreamerVideoWindow::brightnessChanged); - connect(&m_videoOverlay, &QGstreamerVideoOverlay::contrastChanged, - this, &QGstreamerVideoWindow::contrastChanged); - connect(&m_videoOverlay, &QGstreamerVideoOverlay::hueChanged, - this, &QGstreamerVideoWindow::hueChanged); - connect(&m_videoOverlay, &QGstreamerVideoOverlay::saturationChanged, - this, &QGstreamerVideoWindow::saturationChanged); -} - -QGstreamerVideoWindow::~QGstreamerVideoWindow() -{ -} - -GstElement *QGstreamerVideoWindow::videoSink() -{ - return m_videoOverlay.videoSink(); -} - -WId QGstreamerVideoWindow::winId() const -{ - return m_windowId; -} - -void QGstreamerVideoWindow::setWinId(WId id) -{ - if (m_windowId == id) - return; - - WId oldId = m_windowId; - m_videoOverlay.setWindowHandle(m_windowId = id); - - if (!oldId) - emit readyChanged(true); - - if (!id) - emit readyChanged(false); -} - -bool QGstreamerVideoWindow::processSyncMessage(const QGstreamerMessage &message) -{ - return m_videoOverlay.processSyncMessage(message); -} - -bool QGstreamerVideoWindow::processBusMessage(const QGstreamerMessage &message) -{ - return m_videoOverlay.processBusMessage(message); -} - -QRect QGstreamerVideoWindow::displayRect() const -{ - return m_displayRect; -} - -void QGstreamerVideoWindow::setDisplayRect(const QRect &rect) -{ - m_videoOverlay.setRenderRectangle(m_displayRect = rect); - repaint(); -} - -Qt::AspectRatioMode QGstreamerVideoWindow::aspectRatioMode() const -{ - return m_videoOverlay.aspectRatioMode(); -} - -void QGstreamerVideoWindow::setAspectRatioMode(Qt::AspectRatioMode mode) -{ - m_videoOverlay.setAspectRatioMode(mode); -} - -void QGstreamerVideoWindow::repaint() -{ - m_videoOverlay.expose(); -} - -int QGstreamerVideoWindow::brightness() const -{ - return m_videoOverlay.brightness(); -} - -void QGstreamerVideoWindow::setBrightness(int brightness) -{ - m_videoOverlay.setBrightness(brightness); -} - -int QGstreamerVideoWindow::contrast() const -{ - return m_videoOverlay.contrast(); -} - -void QGstreamerVideoWindow::setContrast(int contrast) -{ - m_videoOverlay.setContrast(contrast); -} - -int QGstreamerVideoWindow::hue() const -{ - return m_videoOverlay.hue(); -} - -void QGstreamerVideoWindow::setHue(int hue) -{ - m_videoOverlay.setHue(hue); -} - -int QGstreamerVideoWindow::saturation() const -{ - return m_videoOverlay.saturation(); -} - -void QGstreamerVideoWindow::setSaturation(int saturation) -{ - m_videoOverlay.setSaturation(saturation); -} - -bool QGstreamerVideoWindow::isFullScreen() const -{ - return m_fullScreen; -} - -void QGstreamerVideoWindow::setFullScreen(bool fullScreen) -{ - emit fullScreenChanged(m_fullScreen = fullScreen); -} - -QSize QGstreamerVideoWindow::nativeSize() const -{ - return m_videoOverlay.nativeVideoSize(); -} diff --git a/src/gsttools/qgstreamervideowindow_p.h b/src/gsttools/qgstreamervideowindow_p.h deleted file mode 100644 index a0ed8599b..000000000 --- a/src/gsttools/qgstreamervideowindow_p.h +++ /dev/null @@ -1,127 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTREAMERVIDEOWINDOW_H -#define QGSTREAMERVIDEOWINDOW_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <qvideowindowcontrol.h> - -#include "qgstreamervideorendererinterface_p.h" -#include <private/qgstreamerbushelper_p.h> -#include <private/qgstreamervideooverlay_p.h> -#include <QtGui/qcolor.h> - -QT_BEGIN_NAMESPACE -class QAbstractVideoSurface; - -class Q_GSTTOOLS_EXPORT QGstreamerVideoWindow : - public QVideoWindowControl, - public QGstreamerVideoRendererInterface, - public QGstreamerSyncMessageFilter, - public QGstreamerBusMessageFilter -{ - Q_OBJECT - Q_INTERFACES(QGstreamerVideoRendererInterface QGstreamerSyncMessageFilter QGstreamerBusMessageFilter) -public: - explicit QGstreamerVideoWindow(QObject *parent = 0, const QByteArray &elementName = QByteArray()); - ~QGstreamerVideoWindow(); - - WId winId() const override; - void setWinId(WId id) override; - - QRect displayRect() const override; - void setDisplayRect(const QRect &rect) override; - - bool isFullScreen() const override; - void setFullScreen(bool fullScreen) override; - - QSize nativeSize() const override; - - Qt::AspectRatioMode aspectRatioMode() const override; - void setAspectRatioMode(Qt::AspectRatioMode mode) override; - - void repaint() override; - - int brightness() const override; - void setBrightness(int brightness) override; - - int contrast() const override; - void setContrast(int contrast) override; - - int hue() const override; - void setHue(int hue) override; - - int saturation() const override; - void setSaturation(int saturation) override; - - QAbstractVideoSurface *surface() const; - - GstElement *videoSink() override; - - bool processSyncMessage(const QGstreamerMessage &message) override; - bool processBusMessage(const QGstreamerMessage &message) override; - bool isReady() const override { return m_windowId != 0; } - -signals: - void sinkChanged(); - void readyChanged(bool); - -private: - QGstreamerVideoOverlay m_videoOverlay; - WId m_windowId = 0; - QRect m_displayRect; - bool m_fullScreen = false; - mutable QColor m_colorKey = QColor::Invalid; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/gsttools/qgsttools_global_p.h b/src/gsttools/qgsttools_global_p.h deleted file mode 100644 index babcd3aaf..000000000 --- a/src/gsttools/qgsttools_global_p.h +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTTOOLS_GLOBAL_H -#define QGSTTOOLS_GLOBAL_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/qglobal.h> - -QT_BEGIN_NAMESPACE - -#ifndef QT_STATIC -# if defined(QT_BUILD_MULTIMEDIAGSTTOOLS_LIB) -# define Q_GSTTOOLS_EXPORT Q_DECL_EXPORT -# else -# define Q_GSTTOOLS_EXPORT Q_DECL_IMPORT -# endif -#else -# define Q_GSTTOOLS_EXPORT -#endif - -QT_END_NAMESPACE - -#endif // QGSTTOOLS_GLOBAL_H diff --git a/src/gsttools/qgstutils.cpp b/src/gsttools/qgstutils.cpp deleted file mode 100644 index 5c8d4c90c..000000000 --- a/src/gsttools/qgstutils.cpp +++ /dev/null @@ -1,1746 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtMultimedia/private/qtmultimediaglobal_p.h> -#include "qgstutils_p.h" - -#include <QtCore/qdatetime.h> -#include <QtCore/qdir.h> -#include <QtCore/qbytearray.h> -#include <QtCore/qvariant.h> -#include <QtCore/qregularexpression.h> -#include <QtCore/qsize.h> -#include <QtCore/qset.h> -#include <QtCore/qstringlist.h> -#include <QtGui/qimage.h> -#include <qaudioformat.h> -#include <QtCore/qelapsedtimer.h> -#include <QtMultimedia/qvideosurfaceformat.h> -#include <private/qmultimediautils_p.h> - -#include <gst/audio/audio.h> -#include <gst/video/video.h> - -template<typename T, int N> static int lengthOf(const T (&)[N]) { return N; } - -#if QT_CONFIG(linux_v4l) -# include <private/qcore_unix_p.h> -# include <linux/videodev2.h> -#endif - -#include "qgstreamervideoinputdevicecontrol_p.h" - -QT_BEGIN_NAMESPACE - -//internal -static void addTagToMap(const GstTagList *list, - const gchar *tag, - gpointer user_data) -{ - QMap<QByteArray, QVariant> *map = reinterpret_cast<QMap<QByteArray, QVariant>* >(user_data); - - GValue val; - val.g_type = 0; - gst_tag_list_copy_value(&val,list,tag); - - switch( G_VALUE_TYPE(&val) ) { - case G_TYPE_STRING: - { - const gchar *str_value = g_value_get_string(&val); - map->insert(QByteArray(tag), QString::fromUtf8(str_value)); - break; - } - case G_TYPE_INT: - map->insert(QByteArray(tag), g_value_get_int(&val)); - break; - case G_TYPE_UINT: - map->insert(QByteArray(tag), g_value_get_uint(&val)); - break; - case G_TYPE_LONG: - map->insert(QByteArray(tag), qint64(g_value_get_long(&val))); - break; - case G_TYPE_BOOLEAN: - map->insert(QByteArray(tag), g_value_get_boolean(&val)); - break; - case G_TYPE_CHAR: -#if GLIB_CHECK_VERSION(2,32,0) - map->insert(QByteArray(tag), g_value_get_schar(&val)); -#else - map->insert(QByteArray(tag), g_value_get_char(&val)); -#endif - break; - case G_TYPE_DOUBLE: - map->insert(QByteArray(tag), g_value_get_double(&val)); - break; - default: - // GST_TYPE_DATE is a function, not a constant, so pull it out of the switch -#if GST_CHECK_VERSION(1,0,0) - if (G_VALUE_TYPE(&val) == G_TYPE_DATE) { - const GDate *date = (const GDate *)g_value_get_boxed(&val); -#else - if (G_VALUE_TYPE(&val) == GST_TYPE_DATE) { - const GDate *date = gst_value_get_date(&val); -#endif - if (g_date_valid(date)) { - int year = g_date_get_year(date); - int month = g_date_get_month(date); - int day = g_date_get_day(date); - map->insert(QByteArray(tag), QDate(year,month,day)); - if (!map->contains("year")) - map->insert("year", year); - } -#if GST_CHECK_VERSION(1,0,0) - } else if (G_VALUE_TYPE(&val) == GST_TYPE_DATE_TIME) { - const GstDateTime *dateTime = (const GstDateTime *)g_value_get_boxed(&val); - int year = gst_date_time_has_year(dateTime) ? gst_date_time_get_year(dateTime) : 0; - int month = gst_date_time_has_month(dateTime) ? gst_date_time_get_month(dateTime) : 0; - int day = gst_date_time_has_day(dateTime) ? gst_date_time_get_day(dateTime) : 0; - if (gst_date_time_has_time(dateTime)) { - int hour = gst_date_time_get_hour(dateTime); - int minute = gst_date_time_get_minute(dateTime); - int second = gst_date_time_get_second(dateTime); - float tz = gst_date_time_get_time_zone_offset(dateTime); - QDateTime dateTime(QDate(year, month, day), QTime(hour, minute, second), - Qt::OffsetFromUTC, tz * 60 * 60); - map->insert(QByteArray(tag), dateTime); - } else if (year > 0 && month > 0 && day > 0) { - map->insert(QByteArray(tag), QDate(year,month,day)); - } - if (!map->contains("year") && year > 0) - map->insert("year", year); - } else if (G_VALUE_TYPE(&val) == GST_TYPE_SAMPLE) { - GstSample *sample = (GstSample *)g_value_get_boxed(&val); - GstCaps* caps = gst_sample_get_caps(sample); - if (caps && !gst_caps_is_empty(caps)) { - GstStructure *structure = gst_caps_get_structure(caps, 0); - const gchar *name = gst_structure_get_name(structure); - if (QByteArray(name).startsWith("image/")) { - GstBuffer *buffer = gst_sample_get_buffer(sample); - if (buffer) { - GstMapInfo info; - gst_buffer_map(buffer, &info, GST_MAP_READ); - map->insert(QByteArray(tag), QImage::fromData(info.data, info.size, name)); - gst_buffer_unmap(buffer, &info); - } - } - } -#endif - } else if (G_VALUE_TYPE(&val) == GST_TYPE_FRACTION) { - int nom = gst_value_get_fraction_numerator(&val); - int denom = gst_value_get_fraction_denominator(&val); - - if (denom > 0) { - map->insert(QByteArray(tag), double(nom)/denom); - } - } - break; - } - - g_value_unset(&val); -} - -/*! - \class QGstUtils - \internal -*/ - -/*! - Convert GstTagList structure to QMap<QByteArray, QVariant>. - - Mapping to int, bool, char, string, fractions and date are supported. - Fraction values are converted to doubles. -*/ -QMap<QByteArray, QVariant> QGstUtils::gstTagListToMap(const GstTagList *tags) -{ - QMap<QByteArray, QVariant> res; - gst_tag_list_foreach(tags, addTagToMap, &res); - - return res; -} - -/*! - Returns resolution of \a caps. - If caps doesn't have a valid size, an empty QSize is returned. -*/ -QSize QGstUtils::capsResolution(const GstCaps *caps) -{ - if (gst_caps_get_size(caps) == 0) - return QSize(); - - return structureResolution(gst_caps_get_structure(caps, 0)); -} - -/*! - Returns aspect ratio corrected resolution of \a caps. - If caps doesn't have a valid size, an empty QSize is returned. -*/ -QSize QGstUtils::capsCorrectedResolution(const GstCaps *caps) -{ - QSize size; - - if (caps) { - size = capsResolution(caps); - - gint aspectNum = 0; - gint aspectDenum = 0; - if (!size.isEmpty() && gst_structure_get_fraction( - gst_caps_get_structure(caps, 0), "pixel-aspect-ratio", &aspectNum, &aspectDenum)) { - if (aspectDenum > 0) - size.setWidth(size.width()*aspectNum/aspectDenum); - } - } - - return size; -} - - -#if GST_CHECK_VERSION(1,0,0) -namespace { - -struct AudioFormat -{ - GstAudioFormat format; - QAudioFormat::SampleType sampleType; - QAudioFormat::Endian byteOrder; - int sampleSize; -}; -static const AudioFormat qt_audioLookup[] = -{ - { GST_AUDIO_FORMAT_S8 , QAudioFormat::SignedInt , QAudioFormat::LittleEndian, 8 }, - { GST_AUDIO_FORMAT_U8 , QAudioFormat::UnSignedInt, QAudioFormat::LittleEndian, 8 }, - { GST_AUDIO_FORMAT_S16LE, QAudioFormat::SignedInt , QAudioFormat::LittleEndian, 16 }, - { GST_AUDIO_FORMAT_S16BE, QAudioFormat::SignedInt , QAudioFormat::BigEndian , 16 }, - { GST_AUDIO_FORMAT_U16LE, QAudioFormat::UnSignedInt, QAudioFormat::LittleEndian, 16 }, - { GST_AUDIO_FORMAT_U16BE, QAudioFormat::UnSignedInt, QAudioFormat::BigEndian , 16 }, - { GST_AUDIO_FORMAT_S32LE, QAudioFormat::SignedInt , QAudioFormat::LittleEndian, 32 }, - { GST_AUDIO_FORMAT_S32BE, QAudioFormat::SignedInt , QAudioFormat::BigEndian , 32 }, - { GST_AUDIO_FORMAT_U32LE, QAudioFormat::UnSignedInt, QAudioFormat::LittleEndian, 32 }, - { GST_AUDIO_FORMAT_U32BE, QAudioFormat::UnSignedInt, QAudioFormat::BigEndian , 32 }, - { GST_AUDIO_FORMAT_S24LE, QAudioFormat::SignedInt , QAudioFormat::LittleEndian, 24 }, - { GST_AUDIO_FORMAT_S24BE, QAudioFormat::SignedInt , QAudioFormat::BigEndian , 24 }, - { GST_AUDIO_FORMAT_U24LE, QAudioFormat::UnSignedInt, QAudioFormat::LittleEndian, 24 }, - { GST_AUDIO_FORMAT_U24BE, QAudioFormat::UnSignedInt, QAudioFormat::BigEndian , 24 }, - { GST_AUDIO_FORMAT_F32LE, QAudioFormat::Float , QAudioFormat::LittleEndian, 32 }, - { GST_AUDIO_FORMAT_F32BE, QAudioFormat::Float , QAudioFormat::BigEndian , 32 }, - { GST_AUDIO_FORMAT_F64LE, QAudioFormat::Float , QAudioFormat::LittleEndian, 64 }, - { GST_AUDIO_FORMAT_F64BE, QAudioFormat::Float , QAudioFormat::BigEndian , 64 } -}; - -} -#endif - -/*! - Returns audio format for caps. - If caps doesn't have a valid audio format, an empty QAudioFormat is returned. -*/ - -QAudioFormat QGstUtils::audioFormatForCaps(const GstCaps *caps) -{ - QAudioFormat format; -#if GST_CHECK_VERSION(1,0,0) - GstAudioInfo info; - if (gst_audio_info_from_caps(&info, caps)) { - for (int i = 0; i < lengthOf(qt_audioLookup); ++i) { - if (qt_audioLookup[i].format != info.finfo->format) - continue; - - format.setSampleType(qt_audioLookup[i].sampleType); - format.setByteOrder(qt_audioLookup[i].byteOrder); - format.setSampleSize(qt_audioLookup[i].sampleSize); - format.setSampleRate(info.rate); - format.setChannelCount(info.channels); - format.setCodec(QStringLiteral("audio/pcm")); - - return format; - } - } -#else - const GstStructure *structure = gst_caps_get_structure(caps, 0); - - if (qstrcmp(gst_structure_get_name(structure), "audio/x-raw-int") == 0) { - - format.setCodec("audio/pcm"); - - int endianness = 0; - gst_structure_get_int(structure, "endianness", &endianness); - if (endianness == 1234) - format.setByteOrder(QAudioFormat::LittleEndian); - else if (endianness == 4321) - format.setByteOrder(QAudioFormat::BigEndian); - - gboolean isSigned = FALSE; - gst_structure_get_boolean(structure, "signed", &isSigned); - if (isSigned) - format.setSampleType(QAudioFormat::SignedInt); - else - format.setSampleType(QAudioFormat::UnSignedInt); - - // Number of bits allocated per sample. - int width = 0; - gst_structure_get_int(structure, "width", &width); - - // The number of bits used per sample. This must be less than or equal to the width. - int depth = 0; - gst_structure_get_int(structure, "depth", &depth); - - if (width != depth) { - // Unsupported sample layout. - return QAudioFormat(); - } - format.setSampleSize(width); - - int rate = 0; - gst_structure_get_int(structure, "rate", &rate); - format.setSampleRate(rate); - - int channels = 0; - gst_structure_get_int(structure, "channels", &channels); - format.setChannelCount(channels); - - } else if (qstrcmp(gst_structure_get_name(structure), "audio/x-raw-float") == 0) { - - format.setCodec("audio/pcm"); - - int endianness = 0; - gst_structure_get_int(structure, "endianness", &endianness); - if (endianness == 1234) - format.setByteOrder(QAudioFormat::LittleEndian); - else if (endianness == 4321) - format.setByteOrder(QAudioFormat::BigEndian); - - format.setSampleType(QAudioFormat::Float); - - int width = 0; - gst_structure_get_int(structure, "width", &width); - - format.setSampleSize(width); - - int rate = 0; - gst_structure_get_int(structure, "rate", &rate); - format.setSampleRate(rate); - - int channels = 0; - gst_structure_get_int(structure, "channels", &channels); - format.setChannelCount(channels); - - } else { - return QAudioFormat(); - } -#endif - return format; -} - -#if GST_CHECK_VERSION(1,0,0) -/* - Returns audio format for a sample. - If the buffer doesn't have a valid audio format, an empty QAudioFormat is returned. -*/ -QAudioFormat QGstUtils::audioFormatForSample(GstSample *sample) -{ - GstCaps* caps = gst_sample_get_caps(sample); - if (!caps) - return QAudioFormat(); - - return QGstUtils::audioFormatForCaps(caps); -} -#else -/*! - Returns audio format for a buffer. - If the buffer doesn't have a valid audio format, an empty QAudioFormat is returned. -*/ -QAudioFormat QGstUtils::audioFormatForBuffer(GstBuffer *buffer) -{ - GstCaps* caps = gst_buffer_get_caps(buffer); - if (!caps) - return QAudioFormat(); - - QAudioFormat format = QGstUtils::audioFormatForCaps(caps); - gst_caps_unref(caps); - return format; -} -#endif - -/*! - Builds GstCaps for an audio format. - Returns 0 if the audio format is not valid. - Caller must unref GstCaps. -*/ - -GstCaps *QGstUtils::capsForAudioFormat(const QAudioFormat &format) -{ - if (!format.isValid()) - return 0; - -#if GST_CHECK_VERSION(1,0,0) - const QAudioFormat::SampleType sampleType = format.sampleType(); - const QAudioFormat::Endian byteOrder = format.byteOrder(); - const int sampleSize = format.sampleSize(); - - for (int i = 0; i < lengthOf(qt_audioLookup); ++i) { - if (qt_audioLookup[i].sampleType != sampleType - || qt_audioLookup[i].byteOrder != byteOrder - || qt_audioLookup[i].sampleSize != sampleSize) { - continue; - } - - return gst_caps_new_simple( - "audio/x-raw", - "format" , G_TYPE_STRING, gst_audio_format_to_string(qt_audioLookup[i].format), - "rate" , G_TYPE_INT , format.sampleRate(), - "channels", G_TYPE_INT , format.channelCount(), - nullptr); - } - return 0; -#else - GstStructure *structure = 0; - - if (format.isValid()) { - if (format.sampleType() == QAudioFormat::SignedInt || format.sampleType() == QAudioFormat::UnSignedInt) { - structure = gst_structure_new("audio/x-raw-int", nullptr); - } else if (format.sampleType() == QAudioFormat::Float) { - structure = gst_structure_new("audio/x-raw-float", nullptr); - } - } - - GstCaps *caps = 0; - - if (structure) { - gst_structure_set(structure, "rate", G_TYPE_INT, format.sampleRate(), nullptr); - gst_structure_set(structure, "channels", G_TYPE_INT, format.channelCount(), nullptr); - gst_structure_set(structure, "width", G_TYPE_INT, format.sampleSize(), nullptr); - gst_structure_set(structure, "depth", G_TYPE_INT, format.sampleSize(), nullptr); - - if (format.byteOrder() == QAudioFormat::LittleEndian) - gst_structure_set(structure, "endianness", G_TYPE_INT, 1234, nullptr); - else if (format.byteOrder() == QAudioFormat::BigEndian) - gst_structure_set(structure, "endianness", G_TYPE_INT, 4321, nullptr); - - if (format.sampleType() == QAudioFormat::SignedInt) - gst_structure_set(structure, "signed", G_TYPE_BOOLEAN, TRUE, nullptr); - else if (format.sampleType() == QAudioFormat::UnSignedInt) - gst_structure_set(structure, "signed", G_TYPE_BOOLEAN, FALSE, nullptr); - - caps = gst_caps_new_empty(); - Q_ASSERT(caps); - gst_caps_append_structure(caps, structure); - } - - return caps; -#endif -} - -void QGstUtils::initializeGst() -{ - static bool initialized = false; - if (!initialized) { - initialized = true; - gst_init(nullptr, nullptr); - } -} - -namespace { - const char* getCodecAlias(const QString &codec) - { - if (codec.startsWith(QLatin1String("avc1."))) - return "video/x-h264"; - - if (codec.startsWith(QLatin1String("mp4a."))) - return "audio/mpeg4"; - - if (codec.startsWith(QLatin1String("mp4v.20."))) - return "video/mpeg4"; - - if (codec == QLatin1String("samr")) - return "audio/amr"; - - return 0; - } - - const char* getMimeTypeAlias(const QString &mimeType) - { - if (mimeType == QLatin1String("video/mp4")) - return "video/mpeg4"; - - if (mimeType == QLatin1String("audio/mp4")) - return "audio/mpeg4"; - - if (mimeType == QLatin1String("video/ogg") - || mimeType == QLatin1String("audio/ogg")) - return "application/ogg"; - - return 0; - } -} - -QMultimedia::SupportEstimate QGstUtils::hasSupport(const QString &mimeType, - const QStringList &codecs, - const QSet<QString> &supportedMimeTypeSet) -{ - if (supportedMimeTypeSet.isEmpty()) - return QMultimedia::NotSupported; - - QString mimeTypeLowcase = mimeType.toLower(); - bool containsMimeType = supportedMimeTypeSet.contains(mimeTypeLowcase); - if (!containsMimeType) { - const char* mimeTypeAlias = getMimeTypeAlias(mimeTypeLowcase); - containsMimeType = supportedMimeTypeSet.contains(QLatin1String(mimeTypeAlias)); - if (!containsMimeType) { - containsMimeType = supportedMimeTypeSet.contains(QLatin1String("video/") + mimeTypeLowcase) - || supportedMimeTypeSet.contains(QLatin1String("video/x-") + mimeTypeLowcase) - || supportedMimeTypeSet.contains(QLatin1String("audio/") + mimeTypeLowcase) - || supportedMimeTypeSet.contains(QLatin1String("audio/x-") + mimeTypeLowcase); - } - } - - int supportedCodecCount = 0; - for (const QString &codec : codecs) { - QString codecLowcase = codec.toLower(); - const char* codecAlias = getCodecAlias(codecLowcase); - if (codecAlias) { - if (supportedMimeTypeSet.contains(QLatin1String(codecAlias))) - supportedCodecCount++; - } else if (supportedMimeTypeSet.contains(QLatin1String("video/") + codecLowcase) - || supportedMimeTypeSet.contains(QLatin1String("video/x-") + codecLowcase) - || supportedMimeTypeSet.contains(QLatin1String("audio/") + codecLowcase) - || supportedMimeTypeSet.contains(QLatin1String("audio/x-") + codecLowcase)) { - supportedCodecCount++; - } - } - if (supportedCodecCount > 0 && supportedCodecCount == codecs.size()) - return QMultimedia::ProbablySupported; - - if (supportedCodecCount == 0 && !containsMimeType) - return QMultimedia::NotSupported; - - return QMultimedia::MaybeSupported; -} - -namespace { - -typedef QHash<GstElementFactory *, QList<QGstUtils::CameraInfo>> FactoryCameraInfoMap; - -Q_GLOBAL_STATIC(FactoryCameraInfoMap, qt_camera_device_info); - -} - -QList<QGstUtils::CameraInfo> QGstUtils::enumerateCameras(GstElementFactory *factory) -{ - static QElapsedTimer camerasCacheAgeTimer; - if (camerasCacheAgeTimer.isValid() && camerasCacheAgeTimer.elapsed() > 500) // ms - qt_camera_device_info()->clear(); - - FactoryCameraInfoMap::const_iterator it = qt_camera_device_info()->constFind(factory); - if (it != qt_camera_device_info()->constEnd()) - return *it; - - QList<CameraInfo> &devices = (*qt_camera_device_info())[factory]; - - if (factory) { - bool hasVideoSource = false; - - const GType type = gst_element_factory_get_element_type(factory); - GObjectClass * const objectClass = type - ? static_cast<GObjectClass *>(g_type_class_ref(type)) - : 0; - if (objectClass) { - if (g_object_class_find_property(objectClass, "camera-device")) { - const CameraInfo primary = { - QStringLiteral("primary"), - QGstreamerVideoInputDeviceControl::primaryCamera(), - 0, - QCamera::BackFace, - QByteArray() - }; - const CameraInfo secondary = { - QStringLiteral("secondary"), - QGstreamerVideoInputDeviceControl::secondaryCamera(), - 0, - QCamera::FrontFace, - QByteArray() - }; - - devices.append(primary); - devices.append(secondary); - - GstElement *camera = g_object_class_find_property(objectClass, "sensor-mount-angle") - ? gst_element_factory_create(factory, 0) - : 0; - if (camera) { - if (gst_element_set_state(camera, GST_STATE_READY) != GST_STATE_CHANGE_SUCCESS) { - // no-op - } else for (int i = 0; i < 2; ++i) { - gint orientation = 0; - g_object_set(G_OBJECT(camera), "camera-device", i, nullptr); - g_object_get(G_OBJECT(camera), "sensor-mount-angle", &orientation, nullptr); - - devices[i].orientation = (720 - orientation) % 360; - } - gst_element_set_state(camera, GST_STATE_NULL); - gst_object_unref(GST_OBJECT(camera)); - - } - } else if (g_object_class_find_property(objectClass, "video-source")) { - hasVideoSource = true; - } - - g_type_class_unref(objectClass); - } - - if (!devices.isEmpty() || !hasVideoSource) { - camerasCacheAgeTimer.restart(); - return devices; - } - } - -#if QT_CONFIG(linux_v4l) - QDir devDir(QStringLiteral("/dev")); - devDir.setFilter(QDir::System); - - const QFileInfoList entries = devDir.entryInfoList(QStringList() - << QStringLiteral("video*")); - - for (const QFileInfo &entryInfo : entries) { - //qDebug() << "Try" << entryInfo.filePath(); - - int fd = qt_safe_open(entryInfo.filePath().toLatin1().constData(), O_RDWR ); - if (fd == -1) - continue; - - bool isCamera = false; - - v4l2_input input; - memset(&input, 0, sizeof(input)); - for (; ::ioctl(fd, VIDIOC_ENUMINPUT, &input) >= 0; ++input.index) { - if (input.type == V4L2_INPUT_TYPE_CAMERA || input.type == 0) { - const int ret = ::ioctl(fd, VIDIOC_S_INPUT, &input.index); - isCamera = (ret == 0 || errno == ENOTTY || errno == EBUSY); - break; - } - } - - if (isCamera) { - // find out its driver "name" - QByteArray driver; - QString name; - struct v4l2_capability vcap; - memset(&vcap, 0, sizeof(struct v4l2_capability)); - - if (ioctl(fd, VIDIOC_QUERYCAP, &vcap) != 0) { - name = entryInfo.fileName(); - } else { - driver = QByteArray((const char*)vcap.driver); - name = QString::fromUtf8((const char*)vcap.card); - if (name.isEmpty()) - name = entryInfo.fileName(); - } - //qDebug() << "found camera: " << name; - - - CameraInfo device = { - entryInfo.absoluteFilePath(), - name, - 0, - QCamera::UnspecifiedPosition, - driver - }; - devices.append(device); - } - qt_safe_close(fd); - } - camerasCacheAgeTimer.restart(); -#endif // linux_v4l - -#if GST_CHECK_VERSION(1,4,0) && (defined(Q_OS_WIN) || defined(Q_OS_MACOS)) - if (!devices.isEmpty()) - return devices; - -#if defined(Q_OS_WIN) - const char *propName = "device-path"; - auto deviceDesc = [](GValue *value) { - gchar *desc = g_value_dup_string(value); - const QString id = QLatin1String(desc); - g_free(desc); - return id; - }; -#elif defined(Q_OS_MACOS) - const char *propName = "device-index"; - auto deviceDesc = [](GValue *value) { - return QString::number(g_value_get_int(value)); - }; -#endif - - QGstUtils::initializeGst(); - GstDeviceMonitor *monitor = gst_device_monitor_new(); - auto caps = gst_caps_new_empty_simple("video/x-raw"); - gst_device_monitor_add_filter(monitor, "Video/Source", caps); - gst_caps_unref(caps); - - GList *devs = gst_device_monitor_get_devices(monitor); - while (devs) { - GstDevice *dev = reinterpret_cast<GstDevice*>(devs->data); - GstElement *element = gst_device_create_element(dev, nullptr); - if (element) { - gchar *name = gst_device_get_display_name(dev); - const QString deviceName = QLatin1String(name); - g_free(name); - GParamSpec *prop = g_object_class_find_property(G_OBJECT_GET_CLASS(element), propName); - if (prop) { - GValue value = G_VALUE_INIT; - g_value_init(&value, prop->value_type); - g_object_get_property(G_OBJECT(element), prop->name, &value); - const QString deviceId = deviceDesc(&value); - g_value_unset(&value); - - CameraInfo device = { - deviceId, - deviceName, - 0, - QCamera::UnspecifiedPosition, - QByteArray() - }; - - devices.append(device); - } - - gst_object_unref(element); - } - - gst_object_unref(dev); - devs = g_list_delete_link(devs, devs); - } - gst_object_unref(monitor); -#endif // GST_CHECK_VERSION(1,4,0) && (defined(Q_OS_WIN) || defined(Q_OS_MACOS)) - - return devices; -} - -QList<QByteArray> QGstUtils::cameraDevices(GstElementFactory * factory) -{ - QList<QByteArray> devices; - - const auto cameras = enumerateCameras(factory); - devices.reserve(cameras.size()); - for (const CameraInfo &camera : cameras) - devices.append(camera.name.toUtf8()); - - return devices; -} - -QString QGstUtils::cameraDescription(const QString &device, GstElementFactory * factory) -{ - const auto cameras = enumerateCameras(factory); - for (const CameraInfo &camera : cameras) { - if (camera.name == device) - return camera.description; - } - return QString(); -} - -QCamera::Position QGstUtils::cameraPosition(const QString &device, GstElementFactory * factory) -{ - const auto cameras = enumerateCameras(factory); - for (const CameraInfo &camera : cameras) { - if (camera.name == device) - return camera.position; - } - return QCamera::UnspecifiedPosition; -} - -int QGstUtils::cameraOrientation(const QString &device, GstElementFactory * factory) -{ - const auto cameras = enumerateCameras(factory); - for (const CameraInfo &camera : cameras) { - if (camera.name == device) - return camera.orientation; - } - return 0; -} - -QByteArray QGstUtils::cameraDriver(const QString &device, GstElementFactory *factory) -{ - const auto cameras = enumerateCameras(factory); - for (const CameraInfo &camera : cameras) { - if (camera.name == device) - return camera.driver; - } - return QByteArray(); -} - -QSet<QString> QGstUtils::supportedMimeTypes(bool (*isValidFactory)(GstElementFactory *factory)) -{ - QSet<QString> supportedMimeTypes; - - //enumerate supported mime types - gst_init(nullptr, nullptr); - -#if GST_CHECK_VERSION(1,0,0) - GstRegistry *registry = gst_registry_get(); - GList *orig_plugins = gst_registry_get_plugin_list(registry); -#else - GstRegistry *registry = gst_registry_get_default(); - GList *orig_plugins = gst_default_registry_get_plugin_list (); -#endif - for (GList *plugins = orig_plugins; plugins; plugins = g_list_next(plugins)) { - GstPlugin *plugin = (GstPlugin *) (plugins->data); -#if GST_CHECK_VERSION(1,0,0) - if (GST_OBJECT_FLAG_IS_SET(GST_OBJECT(plugin), GST_PLUGIN_FLAG_BLACKLISTED)) - continue; -#else - if (plugin->flags & (1<<1)) //GST_PLUGIN_FLAG_BLACKLISTED - continue; -#endif - - GList *orig_features = gst_registry_get_feature_list_by_plugin( - registry, gst_plugin_get_name(plugin)); - for (GList *features = orig_features; features; features = g_list_next(features)) { - if (G_UNLIKELY(features->data == nullptr)) - continue; - - GstPluginFeature *feature = GST_PLUGIN_FEATURE(features->data); - GstElementFactory *factory; - - if (GST_IS_TYPE_FIND_FACTORY(feature)) { - QString name(QLatin1String(gst_plugin_feature_get_name(feature))); - if (name.contains(QLatin1Char('/'))) //filter out any string without '/' which is obviously not a mime type - supportedMimeTypes.insert(name.toLower()); - continue; - } else if (!GST_IS_ELEMENT_FACTORY (feature) - || !(factory = GST_ELEMENT_FACTORY(gst_plugin_feature_load(feature)))) { - continue; - } else if (!isValidFactory(factory)) { - // Do nothing - } else for (const GList *pads = gst_element_factory_get_static_pad_templates(factory); - pads; - pads = g_list_next(pads)) { - GstStaticPadTemplate *padtemplate = static_cast<GstStaticPadTemplate *>(pads->data); - - if (padtemplate->direction == GST_PAD_SINK && padtemplate->static_caps.string) { - GstCaps *caps = gst_static_caps_get(&padtemplate->static_caps); - if (gst_caps_is_any(caps) || gst_caps_is_empty(caps)) { - } else for (guint i = 0; i < gst_caps_get_size(caps); i++) { - GstStructure *structure = gst_caps_get_structure(caps, i); - QString nameLowcase = QString::fromLatin1(gst_structure_get_name(structure)).toLower(); - - supportedMimeTypes.insert(nameLowcase); - if (nameLowcase.contains(QLatin1String("mpeg"))) { - //Because mpeg version number is only included in the detail - //description, it is necessary to manually extract this information - //in order to match the mime type of mpeg4. - const GValue *value = gst_structure_get_value(structure, "mpegversion"); - if (value) { - gchar *str = gst_value_serialize(value); - QString versions = QLatin1String(str); - const QStringList elements = versions.split(QRegularExpression(QLatin1String("\\D+")), Qt::SkipEmptyParts); - for (const QString &e : elements) - supportedMimeTypes.insert(nameLowcase + e); - g_free(str); - } - } - } - } - } - gst_object_unref(factory); - } - gst_plugin_feature_list_free(orig_features); - } - gst_plugin_list_free (orig_plugins); - -#if defined QT_SUPPORTEDMIMETYPES_DEBUG - QStringList list = supportedMimeTypes.toList(); - list.sort(); - if (qgetenv("QT_DEBUG_PLUGINS").toInt() > 0) { - for (const QString &type : qAsConst(list)) - qDebug() << type; - } -#endif - return supportedMimeTypes; -} - -#if GST_CHECK_VERSION(1, 0, 0) -namespace { - -struct ColorFormat { QImage::Format imageFormat; GstVideoFormat gstFormat; }; -static const ColorFormat qt_colorLookup[] = -{ - { QImage::Format_RGBX8888, GST_VIDEO_FORMAT_RGBx }, - { QImage::Format_RGBA8888, GST_VIDEO_FORMAT_RGBA }, - { QImage::Format_RGB888 , GST_VIDEO_FORMAT_RGB }, - { QImage::Format_RGB16 , GST_VIDEO_FORMAT_RGB16 } -}; - -} -#endif - -#if GST_CHECK_VERSION(1,0,0) -QImage QGstUtils::bufferToImage(GstBuffer *buffer, const GstVideoInfo &videoInfo) -#else -QImage QGstUtils::bufferToImage(GstBuffer *buffer) -#endif -{ - QImage img; - -#if GST_CHECK_VERSION(1,0,0) - GstVideoInfo info = videoInfo; - GstVideoFrame frame; - if (!gst_video_frame_map(&frame, &info, buffer, GST_MAP_READ)) - return img; -#else - GstCaps *caps = gst_buffer_get_caps(buffer); - if (!caps) - return img; - - GstStructure *structure = gst_caps_get_structure (caps, 0); - gint width = 0; - gint height = 0; - - if (!structure - || !gst_structure_get_int(structure, "width", &width) - || !gst_structure_get_int(structure, "height", &height) - || width <= 0 - || height <= 0) { - gst_caps_unref(caps); - return img; - } - gst_caps_unref(caps); -#endif - -#if GST_CHECK_VERSION(1,0,0) - if (videoInfo.finfo->format == GST_VIDEO_FORMAT_I420) { - const int width = videoInfo.width; - const int height = videoInfo.height; - - const int stride[] = { frame.info.stride[0], frame.info.stride[1], frame.info.stride[2] }; - const uchar *data[] = { - static_cast<const uchar *>(frame.data[0]), - static_cast<const uchar *>(frame.data[1]), - static_cast<const uchar *>(frame.data[2]) - }; -#else - if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-yuv") == 0) { - const int stride[] = { width, width / 2, width / 2 }; - const uchar *data[] = { - (const uchar *)buffer->data, - (const uchar *)buffer->data + width * height, - (const uchar *)buffer->data + width * height * 5 / 4 - }; -#endif - img = QImage(width/2, height/2, QImage::Format_RGB32); - - for (int y=0; y<height; y+=2) { - const uchar *yLine = data[0] + (y * stride[0]); - const uchar *uLine = data[1] + (y * stride[1] / 2); - const uchar *vLine = data[2] + (y * stride[2] / 2); - - for (int x=0; x<width; x+=2) { - const qreal Y = 1.164*(yLine[x]-16); - const int U = uLine[x/2]-128; - const int V = vLine[x/2]-128; - - int b = qBound(0, int(Y + 2.018*U), 255); - int g = qBound(0, int(Y - 0.813*V - 0.391*U), 255); - int r = qBound(0, int(Y + 1.596*V), 255); - - img.setPixel(x/2,y/2,qRgb(r,g,b)); - } - } -#if GST_CHECK_VERSION(1,0,0) - } else for (int i = 0; i < lengthOf(qt_colorLookup); ++i) { - if (qt_colorLookup[i].gstFormat != videoInfo.finfo->format) - continue; - - const QImage image( - static_cast<const uchar *>(frame.data[0]), - videoInfo.width, - videoInfo.height, - frame.info.stride[0], - qt_colorLookup[i].imageFormat); - img = image; - img.detach(); - - break; - } - - gst_video_frame_unmap(&frame); -#else - } else if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-rgb") == 0) { - QImage::Format format = QImage::Format_Invalid; - int bpp = 0; - gst_structure_get_int(structure, "bpp", &bpp); - - if (bpp == 24) - format = QImage::Format_RGB888; - else if (bpp == 32) - format = QImage::Format_RGB32; - - if (format != QImage::Format_Invalid) { - img = QImage((const uchar *)buffer->data, - width, - height, - format); - img.bits(); //detach - } - } -#endif - return img; -} - - -namespace { - -#if GST_CHECK_VERSION(1,0,0) - -struct VideoFormat -{ - QVideoFrame::PixelFormat pixelFormat; - GstVideoFormat gstFormat; -}; - -static const VideoFormat qt_videoFormatLookup[] = -{ - { QVideoFrame::Format_YUV420P, GST_VIDEO_FORMAT_I420 }, - { QVideoFrame::Format_YUV422P, GST_VIDEO_FORMAT_Y42B }, - { QVideoFrame::Format_YV12 , GST_VIDEO_FORMAT_YV12 }, - { QVideoFrame::Format_UYVY , GST_VIDEO_FORMAT_UYVY }, - { QVideoFrame::Format_YUYV , GST_VIDEO_FORMAT_YUY2 }, - { QVideoFrame::Format_NV12 , GST_VIDEO_FORMAT_NV12 }, - { QVideoFrame::Format_NV21 , GST_VIDEO_FORMAT_NV21 }, - { QVideoFrame::Format_AYUV444, GST_VIDEO_FORMAT_AYUV }, -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - { QVideoFrame::Format_RGB32 , GST_VIDEO_FORMAT_BGRx }, - { QVideoFrame::Format_BGR32 , GST_VIDEO_FORMAT_RGBx }, - { QVideoFrame::Format_ARGB32, GST_VIDEO_FORMAT_BGRA }, - { QVideoFrame::Format_ABGR32, GST_VIDEO_FORMAT_RGBA }, - { QVideoFrame::Format_BGRA32, GST_VIDEO_FORMAT_ARGB }, -#else - { QVideoFrame::Format_RGB32 , GST_VIDEO_FORMAT_xRGB }, - { QVideoFrame::Format_BGR32 , GST_VIDEO_FORMAT_xBGR }, - { QVideoFrame::Format_ARGB32, GST_VIDEO_FORMAT_ARGB }, - { QVideoFrame::Format_ABGR32, GST_VIDEO_FORMAT_ABGR }, - { QVideoFrame::Format_BGRA32, GST_VIDEO_FORMAT_BGRA }, -#endif - { QVideoFrame::Format_RGB24 , GST_VIDEO_FORMAT_RGB }, - { QVideoFrame::Format_BGR24 , GST_VIDEO_FORMAT_BGR }, - { QVideoFrame::Format_RGB565, GST_VIDEO_FORMAT_RGB16 } -}; - -static int indexOfVideoFormat(QVideoFrame::PixelFormat format) -{ - for (int i = 0; i < lengthOf(qt_videoFormatLookup); ++i) - if (qt_videoFormatLookup[i].pixelFormat == format) - return i; - - return -1; -} - -static int indexOfVideoFormat(GstVideoFormat format) -{ - for (int i = 0; i < lengthOf(qt_videoFormatLookup); ++i) - if (qt_videoFormatLookup[i].gstFormat == format) - return i; - - return -1; -} - -#else - -struct YuvFormat -{ - QVideoFrame::PixelFormat pixelFormat; - guint32 fourcc; - int bitsPerPixel; -}; - -static const YuvFormat qt_yuvColorLookup[] = -{ - { QVideoFrame::Format_YUV420P, GST_MAKE_FOURCC('I','4','2','0'), 8 }, - { QVideoFrame::Format_YUV422P, GST_MAKE_FOURCC('Y','4','2','B'), 8 }, - { QVideoFrame::Format_YV12, GST_MAKE_FOURCC('Y','V','1','2'), 8 }, - { QVideoFrame::Format_UYVY, GST_MAKE_FOURCC('U','Y','V','Y'), 16 }, - { QVideoFrame::Format_YUYV, GST_MAKE_FOURCC('Y','U','Y','2'), 16 }, - { QVideoFrame::Format_NV12, GST_MAKE_FOURCC('N','V','1','2'), 8 }, - { QVideoFrame::Format_NV21, GST_MAKE_FOURCC('N','V','2','1'), 8 }, - { QVideoFrame::Format_AYUV444, GST_MAKE_FOURCC('A','Y','U','V'), 32 } -}; - -static int indexOfYuvColor(QVideoFrame::PixelFormat format) -{ - const int count = sizeof(qt_yuvColorLookup) / sizeof(YuvFormat); - - for (int i = 0; i < count; ++i) - if (qt_yuvColorLookup[i].pixelFormat == format) - return i; - - return -1; -} - -static int indexOfYuvColor(guint32 fourcc) -{ - const int count = sizeof(qt_yuvColorLookup) / sizeof(YuvFormat); - - for (int i = 0; i < count; ++i) - if (qt_yuvColorLookup[i].fourcc == fourcc) - return i; - - return -1; -} - -struct RgbFormat -{ - QVideoFrame::PixelFormat pixelFormat; - int bitsPerPixel; - int depth; - int endianness; - int red; - int green; - int blue; - int alpha; -}; - -static const RgbFormat qt_rgbColorLookup[] = -{ - { QVideoFrame::Format_RGB32 , 32, 24, 4321, 0x0000FF00, 0x00FF0000, int(0xFF000000), 0x00000000 }, - { QVideoFrame::Format_RGB32 , 32, 24, 1234, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 }, - { QVideoFrame::Format_BGR32 , 32, 24, 4321, int(0xFF000000), 0x00FF0000, 0x0000FF00, 0x00000000 }, - { QVideoFrame::Format_BGR32 , 32, 24, 1234, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 }, - { QVideoFrame::Format_ARGB32, 32, 24, 4321, 0x0000FF00, 0x00FF0000, int(0xFF000000), 0x000000FF }, - { QVideoFrame::Format_ARGB32, 32, 24, 1234, 0x00FF0000, 0x0000FF00, 0x000000FF, int(0xFF000000) }, - { QVideoFrame::Format_RGB24 , 24, 24, 4321, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 }, - { QVideoFrame::Format_BGR24 , 24, 24, 4321, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000 }, - { QVideoFrame::Format_RGB565, 16, 16, 1234, 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 } -}; - -static int indexOfRgbColor( - int bits, int depth, int endianness, int red, int green, int blue, int alpha) -{ - const int count = sizeof(qt_rgbColorLookup) / sizeof(RgbFormat); - - for (int i = 0; i < count; ++i) { - if (qt_rgbColorLookup[i].bitsPerPixel == bits - && qt_rgbColorLookup[i].depth == depth - && qt_rgbColorLookup[i].endianness == endianness - && qt_rgbColorLookup[i].red == red - && qt_rgbColorLookup[i].green == green - && qt_rgbColorLookup[i].blue == blue - && qt_rgbColorLookup[i].alpha == alpha) { - return i; - } - } - return -1; -} -#endif - -} - -#if GST_CHECK_VERSION(1,0,0) - -QVideoSurfaceFormat QGstUtils::formatForCaps( - GstCaps *caps, GstVideoInfo *info, QAbstractVideoBuffer::HandleType handleType) -{ - GstVideoInfo vidInfo; - GstVideoInfo *infoPtr = info ? info : &vidInfo; - - if (gst_video_info_from_caps(infoPtr, caps)) { - int index = indexOfVideoFormat(infoPtr->finfo->format); - - if (index != -1) { - QVideoSurfaceFormat format( - QSize(infoPtr->width, infoPtr->height), - qt_videoFormatLookup[index].pixelFormat, - handleType); - - if (infoPtr->fps_d > 0) - format.setFrameRate(qreal(infoPtr->fps_n) / infoPtr->fps_d); - - if (infoPtr->par_d > 0) - format.setPixelAspectRatio(infoPtr->par_n, infoPtr->par_d); - - return format; - } - } - return QVideoSurfaceFormat(); -} - -#else - -QVideoSurfaceFormat QGstUtils::formatForCaps( - GstCaps *caps, int *bytesPerLine, QAbstractVideoBuffer::HandleType handleType) -{ - const GstStructure *structure = gst_caps_get_structure(caps, 0); - - int bitsPerPixel = 0; - QSize size = structureResolution(structure); - QVideoFrame::PixelFormat pixelFormat = structurePixelFormat(structure, &bitsPerPixel); - - if (pixelFormat != QVideoFrame::Format_Invalid) { - QVideoSurfaceFormat format(size, pixelFormat, handleType); - - QPair<qreal, qreal> rate = structureFrameRateRange(structure); - if (rate.second) - format.setFrameRate(rate.second); - - format.setPixelAspectRatio(structurePixelAspectRatio(structure)); - - if (bytesPerLine) - *bytesPerLine = ((size.width() * bitsPerPixel / 8) + 3) & ~3; - - return format; - } - return QVideoSurfaceFormat(); -} - -#endif - -GstCaps *QGstUtils::capsForFormats(const QList<QVideoFrame::PixelFormat> &formats) -{ - GstCaps *caps = gst_caps_new_empty(); - -#if GST_CHECK_VERSION(1,0,0) - for (QVideoFrame::PixelFormat format : formats) { - int index = indexOfVideoFormat(format); - - if (index != -1) { - gst_caps_append_structure(caps, gst_structure_new( - "video/x-raw", - "format" , G_TYPE_STRING, gst_video_format_to_string(qt_videoFormatLookup[index].gstFormat), - nullptr)); - } - } -#else - for (QVideoFrame::PixelFormat format : formats) { - int index = indexOfYuvColor(format); - - if (index != -1) { - gst_caps_append_structure(caps, gst_structure_new( - "video/x-raw-yuv", - "format", GST_TYPE_FOURCC, qt_yuvColorLookup[index].fourcc, - nullptr)); - continue; - } - - const int count = sizeof(qt_rgbColorLookup) / sizeof(RgbFormat); - - for (int i = 0; i < count; ++i) { - if (qt_rgbColorLookup[i].pixelFormat == format) { - GstStructure *structure = gst_structure_new( - "video/x-raw-rgb", - "bpp" , G_TYPE_INT, qt_rgbColorLookup[i].bitsPerPixel, - "depth" , G_TYPE_INT, qt_rgbColorLookup[i].depth, - "endianness", G_TYPE_INT, qt_rgbColorLookup[i].endianness, - "red_mask" , G_TYPE_INT, qt_rgbColorLookup[i].red, - "green_mask", G_TYPE_INT, qt_rgbColorLookup[i].green, - "blue_mask" , G_TYPE_INT, qt_rgbColorLookup[i].blue, - nullptr); - - if (qt_rgbColorLookup[i].alpha != 0) { - gst_structure_set( - structure, "alpha_mask", G_TYPE_INT, qt_rgbColorLookup[i].alpha, nullptr); - } - gst_caps_append_structure(caps, structure); - } - } - } -#endif - - gst_caps_set_simple( - caps, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, INT_MAX, 1, - "width" , GST_TYPE_INT_RANGE, 1, INT_MAX, - "height" , GST_TYPE_INT_RANGE, 1, INT_MAX, - nullptr); - - return caps; -} - -void QGstUtils::setFrameTimeStamps(QVideoFrame *frame, GstBuffer *buffer) -{ - // GStreamer uses nanoseconds, Qt uses microseconds - qint64 startTime = GST_BUFFER_TIMESTAMP(buffer); - if (startTime >= 0) { - frame->setStartTime(startTime/G_GINT64_CONSTANT (1000)); - - qint64 duration = GST_BUFFER_DURATION(buffer); - if (duration >= 0) - frame->setEndTime((startTime + duration)/G_GINT64_CONSTANT (1000)); - } -} - -void QGstUtils::setMetaData(GstElement *element, const QMap<QByteArray, QVariant> &data) -{ - if (!GST_IS_TAG_SETTER(element)) - return; - - gst_tag_setter_reset_tags(GST_TAG_SETTER(element)); - - for (auto it = data.cbegin(), end = data.cend(); it != end; ++it) { - const QString tagName = QString::fromLatin1(it.key()); - const QVariant &tagValue = it.value(); - - switch (tagValue.type()) { - case QVariant::String: - gst_tag_setter_add_tags(GST_TAG_SETTER(element), - GST_TAG_MERGE_REPLACE, - tagName.toUtf8().constData(), - tagValue.toString().toUtf8().constData(), - nullptr); - break; - case QVariant::Int: - case QVariant::LongLong: - gst_tag_setter_add_tags(GST_TAG_SETTER(element), - GST_TAG_MERGE_REPLACE, - tagName.toUtf8().constData(), - tagValue.toInt(), - nullptr); - break; - case QVariant::Double: - gst_tag_setter_add_tags(GST_TAG_SETTER(element), - GST_TAG_MERGE_REPLACE, - tagName.toUtf8().constData(), - tagValue.toDouble(), - nullptr); - break; -#if GST_CHECK_VERSION(0, 10, 31) - case QVariant::DateTime: { - QDateTime date = tagValue.toDateTime().toLocalTime(); - gst_tag_setter_add_tags(GST_TAG_SETTER(element), - GST_TAG_MERGE_REPLACE, - tagName.toUtf8().constData(), - gst_date_time_new_local_time( - date.date().year(), date.date().month(), date.date().day(), - date.time().hour(), date.time().minute(), date.time().second()), - nullptr); - break; - } -#endif - default: - break; - } - } -} - -void QGstUtils::setMetaData(GstBin *bin, const QMap<QByteArray, QVariant> &data) -{ - GstIterator *elements = gst_bin_iterate_all_by_interface(bin, GST_TYPE_TAG_SETTER); -#if GST_CHECK_VERSION(1,0,0) - GValue item = G_VALUE_INIT; - while (gst_iterator_next(elements, &item) == GST_ITERATOR_OK) { - GstElement * const element = GST_ELEMENT(g_value_get_object(&item)); -#else - GstElement *element = 0; - while (gst_iterator_next(elements, (void**)&element) == GST_ITERATOR_OK) { -#endif - setMetaData(element, data); - } - gst_iterator_free(elements); -} - - -GstCaps *QGstUtils::videoFilterCaps() -{ - const char *caps = -#if GST_CHECK_VERSION(1,2,0) - "video/x-raw(ANY);" -#elif GST_CHECK_VERSION(1,0,0) - "video/x-raw;" -#else - "video/x-raw-yuv;" - "video/x-raw-rgb;" - "video/x-raw-data;" - "video/x-android-buffer;" -#endif - "image/jpeg;" - "video/x-h264"; - static GstStaticCaps staticCaps = GST_STATIC_CAPS(caps); - - return gst_caps_make_writable(gst_static_caps_get(&staticCaps)); -} - -QSize QGstUtils::structureResolution(const GstStructure *s) -{ - QSize size; - - int w, h; - if (s && gst_structure_get_int(s, "width", &w) && gst_structure_get_int(s, "height", &h)) { - size.rwidth() = w; - size.rheight() = h; - } - - return size; -} - -QVideoFrame::PixelFormat QGstUtils::structurePixelFormat(const GstStructure *structure, int *bpp) -{ - QVideoFrame::PixelFormat pixelFormat = QVideoFrame::Format_Invalid; - - if (!structure) - return pixelFormat; - -#if GST_CHECK_VERSION(1,0,0) - Q_UNUSED(bpp); - - if (gst_structure_has_name(structure, "video/x-raw")) { - const gchar *s = gst_structure_get_string(structure, "format"); - if (s) { - GstVideoFormat format = gst_video_format_from_string(s); - int index = indexOfVideoFormat(format); - - if (index != -1) - pixelFormat = qt_videoFormatLookup[index].pixelFormat; - } - } -#else - if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-yuv") == 0) { - guint32 fourcc = 0; - gst_structure_get_fourcc(structure, "format", &fourcc); - - int index = indexOfYuvColor(fourcc); - if (index != -1) { - pixelFormat = qt_yuvColorLookup[index].pixelFormat; - if (bpp) - *bpp = qt_yuvColorLookup[index].bitsPerPixel; - } - } else if (qstrcmp(gst_structure_get_name(structure), "video/x-raw-rgb") == 0) { - int bitsPerPixel = 0; - int depth = 0; - int endianness = 0; - int red = 0; - int green = 0; - int blue = 0; - int alpha = 0; - - gst_structure_get_int(structure, "bpp", &bitsPerPixel); - gst_structure_get_int(structure, "depth", &depth); - gst_structure_get_int(structure, "endianness", &endianness); - gst_structure_get_int(structure, "red_mask", &red); - gst_structure_get_int(structure, "green_mask", &green); - gst_structure_get_int(structure, "blue_mask", &blue); - gst_structure_get_int(structure, "alpha_mask", &alpha); - - int index = indexOfRgbColor(bitsPerPixel, depth, endianness, red, green, blue, alpha); - - if (index != -1) { - pixelFormat = qt_rgbColorLookup[index].pixelFormat; - if (bpp) - *bpp = qt_rgbColorLookup[index].bitsPerPixel; - } - } -#endif - - return pixelFormat; -} - -QSize QGstUtils::structurePixelAspectRatio(const GstStructure *s) -{ - QSize ratio(1, 1); - - gint aspectNum = 0; - gint aspectDenum = 0; - if (s && gst_structure_get_fraction(s, "pixel-aspect-ratio", &aspectNum, &aspectDenum)) { - if (aspectDenum > 0) { - ratio.rwidth() = aspectNum; - ratio.rheight() = aspectDenum; - } - } - - return ratio; -} - -QPair<qreal, qreal> QGstUtils::structureFrameRateRange(const GstStructure *s) -{ - QPair<qreal, qreal> rate; - - if (!s) - return rate; - - int n, d; - if (gst_structure_get_fraction(s, "framerate", &n, &d)) { - rate.second = qreal(n) / d; - rate.first = rate.second; - } else if (gst_structure_get_fraction(s, "max-framerate", &n, &d)) { - rate.second = qreal(n) / d; - if (gst_structure_get_fraction(s, "min-framerate", &n, &d)) - rate.first = qreal(n) / d; - else - rate.first = qreal(1); - } - - return rate; -} - -typedef QMap<QString, QString> FileExtensionMap; -Q_GLOBAL_STATIC(FileExtensionMap, fileExtensionMap) - -QString QGstUtils::fileExtensionForMimeType(const QString &mimeType) -{ - if (fileExtensionMap->isEmpty()) { - //extension for containers hard to guess from mimetype - fileExtensionMap->insert(QStringLiteral("video/x-matroska"), QLatin1String("mkv")); - fileExtensionMap->insert(QStringLiteral("video/quicktime"), QLatin1String("mov")); - fileExtensionMap->insert(QStringLiteral("video/x-msvideo"), QLatin1String("avi")); - fileExtensionMap->insert(QStringLiteral("video/msvideo"), QLatin1String("avi")); - fileExtensionMap->insert(QStringLiteral("audio/mpeg"), QLatin1String("mp3")); - fileExtensionMap->insert(QStringLiteral("application/x-shockwave-flash"), QLatin1String("swf")); - fileExtensionMap->insert(QStringLiteral("application/x-pn-realmedia"), QLatin1String("rm")); - } - - //for container names like avi instead of video/x-msvideo, use it as extension - if (!mimeType.contains(QLatin1Char('/'))) - return mimeType; - - QString format = mimeType.left(mimeType.indexOf(QLatin1Char(','))); - QString extension = fileExtensionMap->value(format); - - if (!extension.isEmpty() || format.isEmpty()) - return extension; - - QRegularExpression rx(QStringLiteral("[-/]([\\w]+)$")); - QRegularExpressionMatch match = rx.match(format); - - if (match.hasMatch()) - extension = match.captured(1); - - return extension; -} - -#if GST_CHECK_VERSION(0,10,30) -QVariant QGstUtils::fromGStreamerOrientation(const QVariant &value) -{ - // Note gstreamer tokens either describe the counter clockwise rotation of the - // image or the clockwise transform to apply to correct the image. The orientation - // value returned is the clockwise rotation of the image. - const QString token = value.toString(); - if (token == QStringLiteral("rotate-90")) - return 270; - if (token == QStringLiteral("rotate-180")) - return 180; - if (token == QStringLiteral("rotate-270")) - return 90; - return 0; -} - -QVariant QGstUtils::toGStreamerOrientation(const QVariant &value) -{ - switch (value.toInt()) { - case 90: - return QStringLiteral("rotate-270"); - case 180: - return QStringLiteral("rotate-180"); - case 270: - return QStringLiteral("rotate-90"); - default: - return QStringLiteral("rotate-0"); - } -} -#endif - -bool QGstUtils::useOpenGL() -{ - static bool result = qEnvironmentVariableIntValue("QT_GSTREAMER_USE_OPENGL_PLUGIN"); - return result; -} - -void qt_gst_object_ref_sink(gpointer object) -{ -#if GST_CHECK_VERSION(0,10,24) - gst_object_ref_sink(object); -#else - g_return_if_fail (GST_IS_OBJECT(object)); - - GST_OBJECT_LOCK(object); - if (G_LIKELY(GST_OBJECT_IS_FLOATING(object))) { - GST_OBJECT_FLAG_UNSET(object, GST_OBJECT_FLOATING); - GST_OBJECT_UNLOCK(object); - } else { - GST_OBJECT_UNLOCK(object); - gst_object_ref(object); - } -#endif -} - -GstCaps *qt_gst_pad_get_current_caps(GstPad *pad) -{ -#if GST_CHECK_VERSION(1,0,0) - return gst_pad_get_current_caps(pad); -#else - return gst_pad_get_negotiated_caps(pad); -#endif -} - -GstCaps *qt_gst_pad_get_caps(GstPad *pad) -{ -#if GST_CHECK_VERSION(1,0,0) - return gst_pad_query_caps(pad, nullptr); -#elif GST_CHECK_VERSION(0, 10, 26) - return gst_pad_get_caps_reffed(pad); -#else - return gst_pad_get_caps(pad); -#endif -} - -GstStructure *qt_gst_structure_new_empty(const char *name) -{ -#if GST_CHECK_VERSION(1,0,0) - return gst_structure_new_empty(name); -#else - return gst_structure_new(name, nullptr); -#endif -} - -gboolean qt_gst_element_query_position(GstElement *element, GstFormat format, gint64 *cur) -{ -#if GST_CHECK_VERSION(1,0,0) - return gst_element_query_position(element, format, cur); -#else - return gst_element_query_position(element, &format, cur); -#endif -} - -gboolean qt_gst_element_query_duration(GstElement *element, GstFormat format, gint64 *cur) -{ -#if GST_CHECK_VERSION(1,0,0) - return gst_element_query_duration(element, format, cur); -#else - return gst_element_query_duration(element, &format, cur); -#endif -} - -GstCaps *qt_gst_caps_normalize(GstCaps *caps) -{ -#if GST_CHECK_VERSION(1,0,0) - // gst_caps_normalize() takes ownership of the argument in 1.0 - return gst_caps_normalize(caps); -#else - // in 0.10, it doesn't. Unref the argument to mimic the 1.0 behavior - GstCaps *res = gst_caps_normalize(caps); - gst_caps_unref(caps); - return res; -#endif -} - -const gchar *qt_gst_element_get_factory_name(GstElement *element) -{ - const gchar *name = 0; - const GstElementFactory *factory = 0; - - if (element && (factory = gst_element_get_factory(element))) - name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory)); - - return name; -} - -gboolean qt_gst_caps_can_intersect(const GstCaps * caps1, const GstCaps * caps2) -{ -#if GST_CHECK_VERSION(0, 10, 25) - return gst_caps_can_intersect(caps1, caps2); -#else - GstCaps *intersection = gst_caps_intersect(caps1, caps2); - gboolean res = !gst_caps_is_empty(intersection); - gst_caps_unref(intersection); - return res; -#endif -} - -#if !GST_CHECK_VERSION(0, 10, 31) -static gboolean qt_gst_videosink_factory_filter(GstPluginFeature *feature, gpointer) -{ - guint rank; - const gchar *klass; - - if (!GST_IS_ELEMENT_FACTORY(feature)) - return FALSE; - - klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature)); - if (!(strstr(klass, "Sink") && strstr(klass, "Video"))) - return FALSE; - - rank = gst_plugin_feature_get_rank(feature); - if (rank < GST_RANK_MARGINAL) - return FALSE; - - return TRUE; -} - -static gint qt_gst_compare_ranks(GstPluginFeature *f1, GstPluginFeature *f2) -{ - gint diff; - - diff = gst_plugin_feature_get_rank(f2) - gst_plugin_feature_get_rank(f1); - if (diff != 0) - return diff; - - return strcmp(gst_plugin_feature_get_name(f2), gst_plugin_feature_get_name (f1)); -} -#endif - -GList *qt_gst_video_sinks() -{ - GList *list = nullptr; - -#if GST_CHECK_VERSION(0, 10, 31) - list = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO, - GST_RANK_MARGINAL); -#else - list = gst_registry_feature_filter(gst_registry_get_default(), - (GstPluginFeatureFilter)qt_gst_videosink_factory_filter, - FALSE, nullptr); - list = g_list_sort(list, (GCompareFunc)qt_gst_compare_ranks); -#endif - - return list; -} - -void qt_gst_util_double_to_fraction(gdouble src, gint *dest_n, gint *dest_d) -{ -#if GST_CHECK_VERSION(0, 10, 26) - gst_util_double_to_fraction(src, dest_n, dest_d); -#else - qt_real_to_fraction(src, dest_n, dest_d); -#endif -} - -QDebug operator <<(QDebug debug, GstCaps *caps) -{ - if (caps) { - gchar *string = gst_caps_to_string(caps); - debug = debug << string; - g_free(string); - } - return debug; -} - -QT_END_NAMESPACE diff --git a/src/gsttools/qgstutils_p.h b/src/gsttools/qgstutils_p.h deleted file mode 100644 index 9ecf2e92c..000000000 --- a/src/gsttools/qgstutils_p.h +++ /dev/null @@ -1,176 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTUTILS_P_H -#define QGSTUTILS_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <QtCore/qlist.h> -#include <QtCore/qmap.h> -#include <QtCore/qset.h> -#include <gst/gst.h> -#include <gst/video/video.h> -#include <qaudioformat.h> -#include <qcamera.h> -#include <qabstractvideobuffer.h> -#include <qvideoframe.h> -#include <QDebug> - -#if GST_CHECK_VERSION(1,0,0) -# define QT_GSTREAMER_PLAYBIN_ELEMENT_NAME "playbin" -# define QT_GSTREAMER_CAMERABIN_ELEMENT_NAME "camerabin" -# define QT_GSTREAMER_COLORCONVERSION_ELEMENT_NAME "videoconvert" -# define QT_GSTREAMER_RAW_AUDIO_MIME "audio/x-raw" -# define QT_GSTREAMER_VIDEOOVERLAY_INTERFACE_NAME "GstVideoOverlay" -#else -# define QT_GSTREAMER_PLAYBIN_ELEMENT_NAME "playbin2" -# define QT_GSTREAMER_CAMERABIN_ELEMENT_NAME "camerabin2" -# define QT_GSTREAMER_COLORCONVERSION_ELEMENT_NAME "ffmpegcolorspace" -# define QT_GSTREAMER_RAW_AUDIO_MIME "audio/x-raw-int" -# define QT_GSTREAMER_VIDEOOVERLAY_INTERFACE_NAME "GstXOverlay" -#endif - -QT_BEGIN_NAMESPACE - -class QSize; -class QVariant; -class QByteArray; -class QImage; -class QVideoSurfaceFormat; - -namespace QGstUtils { - struct Q_GSTTOOLS_EXPORT CameraInfo - { - QString name; - QString description; - int orientation; - QCamera::Position position; - QByteArray driver; - }; - - Q_GSTTOOLS_EXPORT QMap<QByteArray, QVariant> gstTagListToMap(const GstTagList *list); - - Q_GSTTOOLS_EXPORT QSize capsResolution(const GstCaps *caps); - Q_GSTTOOLS_EXPORT QSize capsCorrectedResolution(const GstCaps *caps); - Q_GSTTOOLS_EXPORT QAudioFormat audioFormatForCaps(const GstCaps *caps); -#if GST_CHECK_VERSION(1,0,0) - Q_GSTTOOLS_EXPORT QAudioFormat audioFormatForSample(GstSample *sample); -#else - Q_GSTTOOLS_EXPORT QAudioFormat audioFormatForBuffer(GstBuffer *buffer); -#endif - Q_GSTTOOLS_EXPORT GstCaps *capsForAudioFormat(const QAudioFormat &format); - Q_GSTTOOLS_EXPORT void initializeGst(); - Q_GSTTOOLS_EXPORT QMultimedia::SupportEstimate hasSupport(const QString &mimeType, - const QStringList &codecs, - const QSet<QString> &supportedMimeTypeSet); - - Q_GSTTOOLS_EXPORT QList<CameraInfo> enumerateCameras(GstElementFactory *factory = 0); - Q_GSTTOOLS_EXPORT QList<QByteArray> cameraDevices(GstElementFactory * factory = 0); - Q_GSTTOOLS_EXPORT QString cameraDescription(const QString &device, GstElementFactory * factory = 0); - Q_GSTTOOLS_EXPORT QCamera::Position cameraPosition(const QString &device, GstElementFactory * factory = 0); - Q_GSTTOOLS_EXPORT int cameraOrientation(const QString &device, GstElementFactory * factory = 0); - Q_GSTTOOLS_EXPORT QByteArray cameraDriver(const QString &device, GstElementFactory * factory = 0); - - Q_GSTTOOLS_EXPORT QSet<QString> supportedMimeTypes(bool (*isValidFactory)(GstElementFactory *factory)); - -#if GST_CHECK_VERSION(1,0,0) - Q_GSTTOOLS_EXPORT QImage bufferToImage(GstBuffer *buffer, const GstVideoInfo &info); - Q_GSTTOOLS_EXPORT QVideoSurfaceFormat formatForCaps( - GstCaps *caps, - GstVideoInfo *info = 0, - QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle); -#else - Q_GSTTOOLS_EXPORT QImage bufferToImage(GstBuffer *buffer); - Q_GSTTOOLS_EXPORT QVideoSurfaceFormat formatForCaps( - GstCaps *caps, - int *bytesPerLine = 0, - QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle); -#endif - - Q_GSTTOOLS_EXPORT GstCaps *capsForFormats(const QList<QVideoFrame::PixelFormat> &formats); - void setFrameTimeStamps(QVideoFrame *frame, GstBuffer *buffer); - - Q_GSTTOOLS_EXPORT void setMetaData(GstElement *element, const QMap<QByteArray, QVariant> &data); - Q_GSTTOOLS_EXPORT void setMetaData(GstBin *bin, const QMap<QByteArray, QVariant> &data); - - Q_GSTTOOLS_EXPORT GstCaps *videoFilterCaps(); - - Q_GSTTOOLS_EXPORT QSize structureResolution(const GstStructure *s); - Q_GSTTOOLS_EXPORT QVideoFrame::PixelFormat structurePixelFormat(const GstStructure *s, int *bpp = 0); - Q_GSTTOOLS_EXPORT QSize structurePixelAspectRatio(const GstStructure *s); - Q_GSTTOOLS_EXPORT QPair<qreal, qreal> structureFrameRateRange(const GstStructure *s); - - Q_GSTTOOLS_EXPORT QString fileExtensionForMimeType(const QString &mimeType); - -#if GST_CHECK_VERSION(0,10,30) - Q_GSTTOOLS_EXPORT QVariant fromGStreamerOrientation(const QVariant &value); - Q_GSTTOOLS_EXPORT QVariant toGStreamerOrientation(const QVariant &value); -#endif - - Q_GSTTOOLS_EXPORT bool useOpenGL(); -} - -Q_GSTTOOLS_EXPORT void qt_gst_object_ref_sink(gpointer object); -Q_GSTTOOLS_EXPORT GstCaps *qt_gst_pad_get_current_caps(GstPad *pad); -Q_GSTTOOLS_EXPORT GstCaps *qt_gst_pad_get_caps(GstPad *pad); -Q_GSTTOOLS_EXPORT GstStructure *qt_gst_structure_new_empty(const char *name); -Q_GSTTOOLS_EXPORT gboolean qt_gst_element_query_position(GstElement *element, GstFormat format, gint64 *cur); -Q_GSTTOOLS_EXPORT gboolean qt_gst_element_query_duration(GstElement *element, GstFormat format, gint64 *cur); -Q_GSTTOOLS_EXPORT GstCaps *qt_gst_caps_normalize(GstCaps *caps); -Q_GSTTOOLS_EXPORT const gchar *qt_gst_element_get_factory_name(GstElement *element); -Q_GSTTOOLS_EXPORT gboolean qt_gst_caps_can_intersect(const GstCaps * caps1, const GstCaps * caps2); -Q_GSTTOOLS_EXPORT GList *qt_gst_video_sinks(); -Q_GSTTOOLS_EXPORT void qt_gst_util_double_to_fraction(gdouble src, gint *dest_n, gint *dest_d); - -Q_GSTTOOLS_EXPORT QDebug operator <<(QDebug debug, GstCaps *caps); - -QT_END_NAMESPACE - -#endif diff --git a/src/gsttools/qgstvideobuffer.cpp b/src/gsttools/qgstvideobuffer.cpp deleted file mode 100644 index 245b7e024..000000000 --- a/src/gsttools/qgstvideobuffer.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgstvideobuffer_p.h" - -QT_BEGIN_NAMESPACE - -#if GST_CHECK_VERSION(1,0,0) -QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info) - : QAbstractPlanarVideoBuffer(NoHandle) - , m_videoInfo(info) -#else -QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine) - : QAbstractVideoBuffer(NoHandle) - , m_bytesPerLine(bytesPerLine) -#endif - , m_buffer(buffer) -{ - gst_buffer_ref(m_buffer); -} - -#if GST_CHECK_VERSION(1,0,0) -QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info, - QGstVideoBuffer::HandleType handleType, - const QVariant &handle) - : QAbstractPlanarVideoBuffer(handleType) - , m_videoInfo(info) -#else -QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine, - QGstVideoBuffer::HandleType handleType, - const QVariant &handle) - : QAbstractVideoBuffer(handleType) - , m_bytesPerLine(bytesPerLine) -#endif - , m_buffer(buffer) - , m_handle(handle) -{ - gst_buffer_ref(m_buffer); -} - -QGstVideoBuffer::~QGstVideoBuffer() -{ - unmap(); - - gst_buffer_unref(m_buffer); -} - - -QAbstractVideoBuffer::MapMode QGstVideoBuffer::mapMode() const -{ - return m_mode; -} - -#if GST_CHECK_VERSION(1,0,0) - -int QGstVideoBuffer::map(MapMode mode, int *numBytes, int bytesPerLine[4], uchar *data[4]) -{ - const GstMapFlags flags = GstMapFlags(((mode & ReadOnly) ? GST_MAP_READ : 0) - | ((mode & WriteOnly) ? GST_MAP_WRITE : 0)); - - if (mode == NotMapped || m_mode != NotMapped) { - return 0; - } else if (m_videoInfo.finfo->n_planes == 0) { // Encoded - if (gst_buffer_map(m_buffer, &m_frame.map[0], flags)) { - if (numBytes) - *numBytes = m_frame.map[0].size; - bytesPerLine[0] = -1; - data[0] = static_cast<uchar *>(m_frame.map[0].data); - - m_mode = mode; - - return 1; - } - } else if (gst_video_frame_map(&m_frame, &m_videoInfo, m_buffer, flags)) { - if (numBytes) - *numBytes = m_frame.info.size; - - for (guint i = 0; i < m_frame.info.finfo->n_planes; ++i) { - bytesPerLine[i] = m_frame.info.stride[i]; - data[i] = static_cast<uchar *>(m_frame.data[i]); - } - - m_mode = mode; - - return m_frame.info.finfo->n_planes; - } - return 0; -} - -#else - -uchar *QGstVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine) -{ - if (mode != NotMapped && m_mode == NotMapped) { - if (numBytes) - *numBytes = m_buffer->size; - if (bytesPerLine) - *bytesPerLine = m_bytesPerLine; - - m_mode = mode; - - return m_buffer->data; - } else { - return 0; - } -} - -#endif - -void QGstVideoBuffer::unmap() -{ -#if GST_CHECK_VERSION(1,0,0) - if (m_mode != NotMapped) { - if (m_videoInfo.finfo->n_planes == 0) - gst_buffer_unmap(m_buffer, &m_frame.map[0]); - else - gst_video_frame_unmap(&m_frame); - } -#endif - m_mode = NotMapped; -} - -QT_END_NAMESPACE diff --git a/src/gsttools/qgstvideobuffer_p.h b/src/gsttools/qgstvideobuffer_p.h deleted file mode 100644 index b7de17e19..000000000 --- a/src/gsttools/qgstvideobuffer_p.h +++ /dev/null @@ -1,107 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTVIDEOBUFFER_P_H -#define QGSTVIDEOBUFFER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <qabstractvideobuffer.h> -#include <QtCore/qvariant.h> - -#include <gst/gst.h> -#include <gst/video/video.h> - -QT_BEGIN_NAMESPACE - -#if GST_CHECK_VERSION(1,0,0) -class Q_GSTTOOLS_EXPORT QGstVideoBuffer : public QAbstractPlanarVideoBuffer -{ -public: - QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info); - QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info, - HandleType handleType, const QVariant &handle); -#else -class Q_GSTTOOLS_EXPORT QGstVideoBuffer : public QAbstractVideoBuffer -{ -public: - QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine); - QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine, - HandleType handleType, const QVariant &handle); -#endif - - ~QGstVideoBuffer(); - - GstBuffer *buffer() const { return m_buffer; } - MapMode mapMode() const override; - -#if GST_CHECK_VERSION(1,0,0) - int map(MapMode mode, int *numBytes, int bytesPerLine[4], uchar *data[4]) override; -#else - uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) override; -#endif - - void unmap() override; - - QVariant handle() const override { return m_handle; } -private: -#if GST_CHECK_VERSION(1,0,0) - GstVideoInfo m_videoInfo; - GstVideoFrame m_frame; -#else - int m_bytesPerLine = 0; -#endif - GstBuffer *m_buffer = nullptr; - MapMode m_mode = NotMapped; - QVariant m_handle; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/gsttools/qgstvideorendererplugin.cpp b/src/gsttools/qgstvideorendererplugin.cpp deleted file mode 100644 index 22028ac0e..000000000 --- a/src/gsttools/qgstvideorendererplugin.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Jolla Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qgstvideorendererplugin_p.h" - -QT_BEGIN_NAMESPACE - -QGstVideoRendererPlugin::QGstVideoRendererPlugin(QObject *parent) : - QObject(parent) -{ -} - -QT_END_NAMESPACE - -#include "moc_qgstvideorendererplugin_p.cpp" diff --git a/src/gsttools/qgstvideorendererplugin_p.h b/src/gsttools/qgstvideorendererplugin_p.h deleted file mode 100644 index df36dbe09..000000000 --- a/src/gsttools/qgstvideorendererplugin_p.h +++ /dev/null @@ -1,110 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Jolla Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTVIDEORENDERERPLUGIN_P_H -#define QGSTVIDEORENDERERPLUGIN_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qgsttools_global_p.h> -#include <qabstractvideobuffer.h> -#include <qvideosurfaceformat.h> -#include <QtCore/qobject.h> -#include <QtCore/qplugin.h> - -#include <gst/gst.h> - -QT_BEGIN_NAMESPACE - -class QAbstractVideoSurface; - -const QLatin1String QGstVideoRendererPluginKey("gstvideorenderer"); - -class Q_GSTTOOLS_EXPORT QGstVideoRenderer -{ -public: - virtual ~QGstVideoRenderer() {} - - virtual GstCaps *getCaps(QAbstractVideoSurface *surface) = 0; - virtual bool start(QAbstractVideoSurface *surface, GstCaps *caps) = 0; - virtual void stop(QAbstractVideoSurface *surface) = 0; // surface may be null if unexpectedly deleted. - virtual bool proposeAllocation(GstQuery *query) = 0; // may be called from a thread. - - virtual bool present(QAbstractVideoSurface *surface, GstBuffer *buffer) = 0; - virtual void flush(QAbstractVideoSurface *surface) = 0; // surface may be null if unexpectedly deleted. -}; - -/* - Abstract interface for video buffers allocation. -*/ -class Q_GSTTOOLS_EXPORT QGstVideoRendererInterface -{ -public: - virtual ~QGstVideoRendererInterface() {} - - virtual QGstVideoRenderer *createRenderer() = 0; -}; - -#define QGstVideoRendererInterface_iid "org.qt-project.qt.gstvideorenderer/5.4" -Q_DECLARE_INTERFACE(QGstVideoRendererInterface, QGstVideoRendererInterface_iid) - -class Q_GSTTOOLS_EXPORT QGstVideoRendererPlugin : public QObject, public QGstVideoRendererInterface -{ - Q_OBJECT - Q_INTERFACES(QGstVideoRendererInterface) -public: - explicit QGstVideoRendererPlugin(QObject *parent = 0); - virtual ~QGstVideoRendererPlugin() {} - - QGstVideoRenderer *createRenderer() override = 0; - -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/gsttools/qgstvideorenderersink.cpp b/src/gsttools/qgstvideorenderersink.cpp deleted file mode 100644 index 8f4f59358..000000000 --- a/src/gsttools/qgstvideorenderersink.cpp +++ /dev/null @@ -1,810 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Jolla Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qabstractvideosurface.h> -#include <qvideoframe.h> -#include <QDebug> -#include <QMap> -#include <QThread> -#include <QEvent> -#include <QCoreApplication> - -#include <private/qmediapluginloader_p.h> -#include "qgstvideobuffer_p.h" - -#include "qgstvideorenderersink_p.h" - -#include <gst/video/video.h> - -#include "qgstutils_p.h" - -#if QT_CONFIG(gstreamer_gl) -#include <QOpenGLContext> -#include <QGuiApplication> -#include <QWindow> -#include <qpa/qplatformnativeinterface.h> - -#include <gst/gl/gstglconfig.h> - -#if GST_GL_HAVE_WINDOW_X11 -# include <gst/gl/x11/gstgldisplay_x11.h> -#endif -#if GST_GL_HAVE_PLATFORM_EGL -# include <gst/gl/egl/gstgldisplay_egl.h> -#endif -#if GST_CHECK_VERSION(1,11,1) && GST_GL_HAVE_WINDOW_WAYLAND -# include <gst/gl/wayland/gstgldisplay_wayland.h> -#endif -#endif // #if QT_CONFIG(gstreamer_gl) - -//#define DEBUG_VIDEO_SURFACE_SINK - -QT_BEGIN_NAMESPACE - -QGstDefaultVideoRenderer::QGstDefaultVideoRenderer() -{ -} - -QGstDefaultVideoRenderer::~QGstDefaultVideoRenderer() -{ -} - -GstCaps *QGstDefaultVideoRenderer::getCaps(QAbstractVideoSurface *surface) -{ -#if QT_CONFIG(gstreamer_gl) - if (QGstUtils::useOpenGL()) { - m_handleType = QAbstractVideoBuffer::GLTextureHandle; - auto formats = surface->supportedPixelFormats(m_handleType); - // Even if the surface does not support gl textures, - // glupload will be added to the pipeline and GLMemory will be requested. - // This will lead to upload data to gl textures - // and download it when the buffer will be used within rendering. - if (formats.isEmpty()) { - m_handleType = QAbstractVideoBuffer::NoHandle; - formats = surface->supportedPixelFormats(m_handleType); - } - - GstCaps *caps = QGstUtils::capsForFormats(formats); - for (guint i = 0; i < gst_caps_get_size(caps); ++i) - gst_caps_set_features(caps, i, gst_caps_features_from_string("memory:GLMemory")); - - return caps; - } -#endif - return QGstUtils::capsForFormats(surface->supportedPixelFormats(QAbstractVideoBuffer::NoHandle)); -} - -bool QGstDefaultVideoRenderer::start(QAbstractVideoSurface *surface, GstCaps *caps) -{ - m_flushed = true; - m_format = QGstUtils::formatForCaps(caps, &m_videoInfo, m_handleType); - - return m_format.isValid() && surface->start(m_format); -} - -void QGstDefaultVideoRenderer::stop(QAbstractVideoSurface *surface) -{ - m_flushed = true; - if (surface) - surface->stop(); -} - -bool QGstDefaultVideoRenderer::present(QAbstractVideoSurface *surface, GstBuffer *buffer) -{ - m_flushed = false; - - QGstVideoBuffer *videoBuffer = nullptr; -#if QT_CONFIG(gstreamer_gl) - if (m_format.handleType() == QAbstractVideoBuffer::GLTextureHandle) { - GstGLMemory *glmem = GST_GL_MEMORY_CAST(gst_buffer_peek_memory(buffer, 0)); - guint textureId = gst_gl_memory_get_texture_id(glmem); - videoBuffer = new QGstVideoBuffer(buffer, m_videoInfo, m_format.handleType(), textureId); - } -#endif - - if (!videoBuffer) - videoBuffer = new QGstVideoBuffer(buffer, m_videoInfo); - - auto meta = gst_buffer_get_video_crop_meta (buffer); - if (meta) { - QRect vp(meta->x, meta->y, meta->width, meta->height); - if (m_format.viewport() != vp) { -#ifdef DEBUG_VIDEO_SURFACE_SINK - qDebug() << Q_FUNC_INFO << " Update viewport on Metadata: [" << meta->height << "x" << meta->width << " | " << meta->x << "x" << meta->y << "]"; -#endif - //Update viewport if data is not the same - m_format.setViewport(vp); - surface->start(m_format); - } - } - - QVideoFrame frame( - videoBuffer, - m_format.frameSize(), - m_format.pixelFormat()); - QGstUtils::setFrameTimeStamps(&frame, buffer); - - return surface->present(frame); -} - -void QGstDefaultVideoRenderer::flush(QAbstractVideoSurface *surface) -{ - if (surface && !m_flushed) - surface->present(QVideoFrame()); - m_flushed = true; -} - -bool QGstDefaultVideoRenderer::proposeAllocation(GstQuery *) -{ - return true; -} - -Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, rendererLoader, - (QGstVideoRendererInterface_iid, QLatin1String("video/gstvideorenderer"), Qt::CaseInsensitive)) - -QVideoSurfaceGstDelegate::QVideoSurfaceGstDelegate(QAbstractVideoSurface *surface) - : m_surface(surface) -{ - const auto instances = rendererLoader()->instances(QGstVideoRendererPluginKey); - for (QObject *instance : instances) { - auto plugin = qobject_cast<QGstVideoRendererInterface*>(instance); - if (QGstVideoRenderer *renderer = plugin ? plugin->createRenderer() : nullptr) - m_renderers.append(renderer); - } - - m_renderers.append(new QGstDefaultVideoRenderer); - updateSupportedFormats(); - connect(m_surface, SIGNAL(supportedFormatsChanged()), this, SLOT(updateSupportedFormats())); -} - -QVideoSurfaceGstDelegate::~QVideoSurfaceGstDelegate() -{ - qDeleteAll(m_renderers); - - if (m_surfaceCaps) - gst_caps_unref(m_surfaceCaps); - if (m_startCaps) - gst_caps_unref(m_startCaps); -#if QT_CONFIG(gstreamer_gl) - if (m_gstGLDisplayContext) - gst_object_unref(m_gstGLDisplayContext); -#endif -} - -GstCaps *QVideoSurfaceGstDelegate::caps() -{ - QMutexLocker locker(&m_mutex); - - gst_caps_ref(m_surfaceCaps); - - return m_surfaceCaps; -} - -bool QVideoSurfaceGstDelegate::start(GstCaps *caps) -{ - QMutexLocker locker(&m_mutex); - - if (m_activeRenderer) { - m_flush = true; - m_stop = true; - } - - if (m_startCaps) - gst_caps_unref(m_startCaps); - m_startCaps = caps; - gst_caps_ref(m_startCaps); - - /* - Waiting for start() to be invoked in the main thread may block - if gstreamer blocks the main thread until this call is finished. - This situation is rare and usually caused by setState(Null) - while pipeline is being prerolled. - - The proper solution to this involves controlling gstreamer pipeline from - other thread than video surface. - - Currently start() fails if wait() timed out. - */ - if (!waitForAsyncEvent(&locker, &m_setupCondition, 1000) && m_startCaps) { - qWarning() << "Failed to start video surface due to main thread blocked."; - gst_caps_unref(m_startCaps); - m_startCaps = 0; - } - - return m_activeRenderer != 0; -} - -void QVideoSurfaceGstDelegate::stop() -{ - QMutexLocker locker(&m_mutex); - - if (!m_activeRenderer) - return; - - m_flush = true; - m_stop = true; - - if (m_startCaps) { - gst_caps_unref(m_startCaps); - m_startCaps = 0; - } - - waitForAsyncEvent(&locker, &m_setupCondition, 500); -} - -void QVideoSurfaceGstDelegate::unlock() -{ - QMutexLocker locker(&m_mutex); - - m_setupCondition.wakeAll(); - m_renderCondition.wakeAll(); -} - -bool QVideoSurfaceGstDelegate::proposeAllocation(GstQuery *query) -{ - QMutexLocker locker(&m_mutex); - - if (QGstVideoRenderer *pool = m_activeRenderer) { - locker.unlock(); - - return pool->proposeAllocation(query); - } else { - return false; - } -} - -void QVideoSurfaceGstDelegate::flush() -{ - QMutexLocker locker(&m_mutex); - - m_flush = true; - m_renderBuffer = 0; - m_renderCondition.wakeAll(); - - notify(); -} - -GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer) -{ - QMutexLocker locker(&m_mutex); - - m_renderReturn = GST_FLOW_OK; - m_renderBuffer = buffer; - - waitForAsyncEvent(&locker, &m_renderCondition, 300); - - m_renderBuffer = 0; - - return m_renderReturn; -} - -#if QT_CONFIG(gstreamer_gl) -static GstGLContext *gstGLDisplayContext(QAbstractVideoSurface *surface) -{ - auto glContext = qobject_cast<QOpenGLContext*>(surface->property("GLContext").value<QObject*>()); - // Context is not ready yet. - if (!glContext) - return nullptr; - - GstGLDisplay *display = nullptr; - const QString platform = QGuiApplication::platformName(); - const char *contextName = "eglcontext"; - GstGLPlatform glPlatform = GST_GL_PLATFORM_EGL; - QPlatformNativeInterface *pni = QGuiApplication::platformNativeInterface(); - -#if GST_GL_HAVE_WINDOW_X11 - if (platform == QLatin1String("xcb")) { - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { - contextName = "glxcontext"; - glPlatform = GST_GL_PLATFORM_GLX; - } - - display = (GstGLDisplay *)gst_gl_display_x11_new_with_display( - (Display *)pni->nativeResourceForIntegration("display")); - } -#endif - -#if GST_GL_HAVE_PLATFORM_EGL - if (!display && platform == QLatin1String("eglfs")) { - display = (GstGLDisplay *)gst_gl_display_egl_new_with_egl_display( - pni->nativeResourceForIntegration("egldisplay")); - } -#endif - -#if GST_CHECK_VERSION(1,11,1) -#if GST_GL_HAVE_WINDOW_WAYLAND - if (!display && platform.startsWith(QLatin1String("wayland"))) { - const char *displayName = (platform == QLatin1String("wayland")) - ? "display" : "egldisplay"; - - display = (GstGLDisplay *)gst_gl_display_wayland_new_with_display( - (struct wl_display *)pni->nativeResourceForIntegration(displayName)); - } -#endif -#endif - - if (!display) { - qWarning() << "Could not create GstGLDisplay"; - return nullptr; - } - - void *nativeContext = pni->nativeResourceForContext(contextName, glContext); - if (!nativeContext) - qWarning() << "Could not find resource for" << contextName; - - GstGLContext *appContext = gst_gl_context_new_wrapped(display, (guintptr)nativeContext, glPlatform, GST_GL_API_ANY); - if (!appContext) - qWarning() << "Could not create wrappped context for platform:" << glPlatform; - - GstGLContext *displayContext = nullptr; - GError *error = nullptr; - gst_gl_display_create_context(display, appContext, &displayContext, &error); - if (error) { - qWarning() << "Could not create display context:" << error->message; - g_clear_error(&error); - } - - if (appContext) - gst_object_unref(appContext); - - gst_object_unref(display); - - return displayContext; -} -#endif // #if QT_CONFIG(gstreamer_gl) - -bool QVideoSurfaceGstDelegate::query(GstQuery *query) -{ -#if QT_CONFIG(gstreamer_gl) - if (GST_QUERY_TYPE(query) == GST_QUERY_CONTEXT) { - const gchar *type; - gst_query_parse_context_type(query, &type); - - if (strcmp(type, "gst.gl.local_context") != 0) - return false; - - if (!m_gstGLDisplayContext) - m_gstGLDisplayContext = gstGLDisplayContext(m_surface); - - // No context yet. - if (!m_gstGLDisplayContext) - return false; - - GstContext *context = nullptr; - gst_query_parse_context(query, &context); - context = context ? gst_context_copy(context) : gst_context_new(type, FALSE); - GstStructure *structure = gst_context_writable_structure(context); -#if GST_CHECK_VERSION(1,11,1) - gst_structure_set(structure, "context", GST_TYPE_GL_CONTEXT, m_gstGLDisplayContext, nullptr); -#else - gst_structure_set(structure, "context", GST_GL_TYPE_CONTEXT, m_gstGLDisplayContext, nullptr); -#endif - gst_query_set_context(query, context); - gst_context_unref(context); - - return m_gstGLDisplayContext; - } -#else - Q_UNUSED(query); -#endif - return false; -} - -bool QVideoSurfaceGstDelegate::event(QEvent *event) -{ - if (event->type() == QEvent::UpdateRequest) { - QMutexLocker locker(&m_mutex); - - if (m_notified) { - while (handleEvent(&locker)) {} - m_notified = false; - } - return true; - } else { - return QObject::event(event); - } -} - -bool QVideoSurfaceGstDelegate::handleEvent(QMutexLocker<QMutex> *locker) -{ - if (m_flush) { - m_flush = false; - if (m_activeRenderer) { - locker->unlock(); - - m_activeRenderer->flush(m_surface); - } - } else if (m_stop) { - m_stop = false; - - if (QGstVideoRenderer * const activePool = m_activeRenderer) { - m_activeRenderer = 0; - locker->unlock(); - - activePool->stop(m_surface); - - locker->relock(); - } - } else if (m_startCaps) { - Q_ASSERT(!m_activeRenderer); - - GstCaps * const startCaps = m_startCaps; - m_startCaps = 0; - - if (m_renderer && m_surface) { - locker->unlock(); - - const bool started = m_renderer->start(m_surface, startCaps); - - locker->relock(); - - m_activeRenderer = started - ? m_renderer - : 0; - } else if (QGstVideoRenderer * const activePool = m_activeRenderer) { - m_activeRenderer = 0; - locker->unlock(); - - activePool->stop(m_surface); - - locker->relock(); - } - - gst_caps_unref(startCaps); - } else if (m_renderBuffer) { - GstBuffer *buffer = m_renderBuffer; - m_renderBuffer = 0; - m_renderReturn = GST_FLOW_ERROR; - - if (m_activeRenderer && m_surface) { - gst_buffer_ref(buffer); - - locker->unlock(); - - const bool rendered = m_activeRenderer->present(m_surface, buffer); - - gst_buffer_unref(buffer); - - locker->relock(); - - if (rendered) - m_renderReturn = GST_FLOW_OK; - } - - m_renderCondition.wakeAll(); - } else { - m_setupCondition.wakeAll(); - - return false; - } - return true; -} - -void QVideoSurfaceGstDelegate::notify() -{ - if (!m_notified) { - m_notified = true; - QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); - } -} - -bool QVideoSurfaceGstDelegate::waitForAsyncEvent( - QMutexLocker<QMutex> *locker, QWaitCondition *condition, unsigned long time) -{ - if (QThread::currentThread() == thread()) { - while (handleEvent(locker)) {} - m_notified = false; - - return true; - } else { - notify(); - - return condition->wait(&m_mutex, time); - } -} - -void QVideoSurfaceGstDelegate::updateSupportedFormats() -{ - if (m_surfaceCaps) { - gst_caps_unref(m_surfaceCaps); - m_surfaceCaps = 0; - } - - for (QGstVideoRenderer *pool : qAsConst(m_renderers)) { - if (GstCaps *caps = pool->getCaps(m_surface)) { - if (gst_caps_is_empty(caps)) { - gst_caps_unref(caps); - continue; - } - - if (m_surfaceCaps) - gst_caps_unref(m_surfaceCaps); - - m_renderer = pool; - m_surfaceCaps = caps; - break; - } else { - gst_caps_unref(caps); - } - } -} - -static GstVideoSinkClass *sink_parent_class; -static QAbstractVideoSurface *current_surface; - -#define VO_SINK(s) QGstVideoRendererSink *sink(reinterpret_cast<QGstVideoRendererSink *>(s)) - -QGstVideoRendererSink *QGstVideoRendererSink::createSink(QAbstractVideoSurface *surface) -{ - setSurface(surface); - QGstVideoRendererSink *sink = reinterpret_cast<QGstVideoRendererSink *>( - g_object_new(QGstVideoRendererSink::get_type(), 0)); - - g_signal_connect(G_OBJECT(sink), "notify::show-preroll-frame", G_CALLBACK(handleShowPrerollChange), sink); - - return sink; -} - -void QGstVideoRendererSink::setSurface(QAbstractVideoSurface *surface) -{ - current_surface = surface; - get_type(); -} - -GType QGstVideoRendererSink::get_type() -{ - static GType type = 0; - - if (type == 0) { - static const GTypeInfo info = - { - sizeof(QGstVideoRendererSinkClass), // class_size - base_init, // base_init - nullptr, // base_finalize - class_init, // class_init - nullptr, // class_finalize - nullptr, // class_data - sizeof(QGstVideoRendererSink), // instance_size - 0, // n_preallocs - instance_init, // instance_init - 0 // value_table - }; - - type = g_type_register_static( - GST_TYPE_VIDEO_SINK, "QGstVideoRendererSink", &info, GTypeFlags(0)); - - // Register the sink type to be used in custom piplines. - // When surface is ready the sink can be used. - gst_element_register(nullptr, "qtvideosink", GST_RANK_PRIMARY, type); - } - - return type; -} - -void QGstVideoRendererSink::class_init(gpointer g_class, gpointer class_data) -{ - Q_UNUSED(class_data); - - sink_parent_class = reinterpret_cast<GstVideoSinkClass *>(g_type_class_peek_parent(g_class)); - - GstVideoSinkClass *video_sink_class = reinterpret_cast<GstVideoSinkClass *>(g_class); - video_sink_class->show_frame = QGstVideoRendererSink::show_frame; - - GstBaseSinkClass *base_sink_class = reinterpret_cast<GstBaseSinkClass *>(g_class); - base_sink_class->get_caps = QGstVideoRendererSink::get_caps; - base_sink_class->set_caps = QGstVideoRendererSink::set_caps; - base_sink_class->propose_allocation = QGstVideoRendererSink::propose_allocation; - base_sink_class->stop = QGstVideoRendererSink::stop; - base_sink_class->unlock = QGstVideoRendererSink::unlock; - base_sink_class->query = QGstVideoRendererSink::query; - - GstElementClass *element_class = reinterpret_cast<GstElementClass *>(g_class); - element_class->change_state = QGstVideoRendererSink::change_state; - gst_element_class_set_metadata(element_class, - "Qt built-in video renderer sink", - "Sink/Video", - "Qt default built-in video renderer sink", - "The Qt Company"); - - GObjectClass *object_class = reinterpret_cast<GObjectClass *>(g_class); - object_class->finalize = QGstVideoRendererSink::finalize; -} - -void QGstVideoRendererSink::base_init(gpointer g_class) -{ - static GstStaticPadTemplate sink_pad_template = GST_STATIC_PAD_TEMPLATE( - "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS( - "video/x-raw, " - "framerate = (fraction) [ 0, MAX ], " - "width = (int) [ 1, MAX ], " - "height = (int) [ 1, MAX ]")); - - gst_element_class_add_pad_template( - GST_ELEMENT_CLASS(g_class), gst_static_pad_template_get(&sink_pad_template)); -} - -struct NullSurface : QAbstractVideoSurface -{ - NullSurface(QObject *parent = nullptr) : QAbstractVideoSurface(parent) { } - - QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType) const override - { - return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_RGB32; - } - - bool present(const QVideoFrame &) override - { - return true; - } -}; - -void QGstVideoRendererSink::instance_init(GTypeInstance *instance, gpointer g_class) -{ - Q_UNUSED(g_class); - VO_SINK(instance); - - if (!current_surface) { - qWarning() << "Using qtvideosink element without video surface"; - static NullSurface nullSurface; - current_surface = &nullSurface; - } - - sink->delegate = new QVideoSurfaceGstDelegate(current_surface); - sink->delegate->moveToThread(current_surface->thread()); - current_surface = nullptr; -} - -void QGstVideoRendererSink::finalize(GObject *object) -{ - VO_SINK(object); - - delete sink->delegate; - - // Chain up - G_OBJECT_CLASS(sink_parent_class)->finalize(object); -} - -void QGstVideoRendererSink::handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d) -{ - Q_UNUSED(o); - Q_UNUSED(p); - QGstVideoRendererSink *sink = reinterpret_cast<QGstVideoRendererSink *>(d); - - gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default - g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, nullptr); - - if (!showPrerollFrame) { - GstState state = GST_STATE_VOID_PENDING; - GstClockTime timeout = 10000000; // 10 ms - gst_element_get_state(GST_ELEMENT(sink), &state, nullptr, timeout); - // show-preroll-frame being set to 'false' while in GST_STATE_PAUSED means - // the QMediaPlayer was stopped from the paused state. - // We need to flush the current frame. - if (state == GST_STATE_PAUSED) - sink->delegate->flush(); - } -} - -GstStateChangeReturn QGstVideoRendererSink::change_state( - GstElement *element, GstStateChange transition) -{ - QGstVideoRendererSink *sink = reinterpret_cast<QGstVideoRendererSink *>(element); - - gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default - g_object_get(G_OBJECT(element), "show-preroll-frame", &showPrerollFrame, nullptr); - - // If show-preroll-frame is 'false' when transitioning from GST_STATE_PLAYING to - // GST_STATE_PAUSED, it means the QMediaPlayer was stopped. - // We need to flush the current frame. - if (transition == GST_STATE_CHANGE_PLAYING_TO_PAUSED && !showPrerollFrame) - sink->delegate->flush(); - - return GST_ELEMENT_CLASS(sink_parent_class)->change_state(element, transition); -} - -GstCaps *QGstVideoRendererSink::get_caps(GstBaseSink *base, GstCaps *filter) -{ - VO_SINK(base); - - GstCaps *caps = sink->delegate->caps(); - GstCaps *unfiltered = caps; - if (filter) { - caps = gst_caps_intersect(unfiltered, filter); - gst_caps_unref(unfiltered); - } - - return caps; -} - -gboolean QGstVideoRendererSink::set_caps(GstBaseSink *base, GstCaps *caps) -{ - VO_SINK(base); - -#ifdef DEBUG_VIDEO_SURFACE_SINK - qDebug() << "set_caps:"; - qDebug() << caps; -#endif - - if (!caps) { - sink->delegate->stop(); - - return TRUE; - } else if (sink->delegate->start(caps)) { - return TRUE; - } else { - return FALSE; - } -} - -gboolean QGstVideoRendererSink::propose_allocation(GstBaseSink *base, GstQuery *query) -{ - VO_SINK(base); - return sink->delegate->proposeAllocation(query); -} - -gboolean QGstVideoRendererSink::stop(GstBaseSink *base) -{ - VO_SINK(base); - sink->delegate->stop(); - return TRUE; -} - -gboolean QGstVideoRendererSink::unlock(GstBaseSink *base) -{ - VO_SINK(base); - sink->delegate->unlock(); - return TRUE; -} - -GstFlowReturn QGstVideoRendererSink::show_frame(GstVideoSink *base, GstBuffer *buffer) -{ - VO_SINK(base); - return sink->delegate->render(buffer); -} - -gboolean QGstVideoRendererSink::query(GstBaseSink *base, GstQuery *query) -{ - VO_SINK(base); - if (sink->delegate->query(query)) - return TRUE; - - return GST_BASE_SINK_CLASS(sink_parent_class)->query(base, query); -} - -QT_END_NAMESPACE diff --git a/src/gsttools/qgstvideorenderersink_p.h b/src/gsttools/qgstvideorenderersink_p.h deleted file mode 100644 index 81bcb5c02..000000000 --- a/src/gsttools/qgstvideorenderersink_p.h +++ /dev/null @@ -1,199 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Jolla Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGSTVIDEORENDERERSINK_P_H -#define QGSTVIDEORENDERERSINK_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtMultimedia/private/qtmultimediaglobal_p.h> -#include <gst/video/gstvideosink.h> -#include <gst/video/video.h> - -#include <QtCore/qlist.h> -#include <QtCore/qmutex.h> -#include <QtCore/qqueue.h> -#include <QtCore/qpointer.h> -#include <QtCore/qwaitcondition.h> -#include <qvideosurfaceformat.h> -#include <qvideoframe.h> -#include <qabstractvideobuffer.h> - -#include "qgstvideorendererplugin_p.h" - -#include "qgstvideorendererplugin_p.h" - -#if QT_CONFIG(gstreamer_gl) -#ifndef GST_USE_UNSTABLE_API -#define GST_USE_UNSTABLE_API -#endif -#include <gst/gl/gl.h> -#endif - -QT_BEGIN_NAMESPACE -class QAbstractVideoSurface; - -class QGstDefaultVideoRenderer : public QGstVideoRenderer -{ -public: - QGstDefaultVideoRenderer(); - ~QGstDefaultVideoRenderer(); - - GstCaps *getCaps(QAbstractVideoSurface *surface) override; - bool start(QAbstractVideoSurface *surface, GstCaps *caps) override; - void stop(QAbstractVideoSurface *surface) override; - - bool proposeAllocation(GstQuery *query) override; - - bool present(QAbstractVideoSurface *surface, GstBuffer *buffer) override; - void flush(QAbstractVideoSurface *surface) override; - -private: - QVideoSurfaceFormat m_format; - GstVideoInfo m_videoInfo; - bool m_flushed = true; - QAbstractVideoBuffer::HandleType m_handleType = QAbstractVideoBuffer::NoHandle; -}; - -class QVideoSurfaceGstDelegate : public QObject -{ - Q_OBJECT -public: - QVideoSurfaceGstDelegate(QAbstractVideoSurface *surface); - ~QVideoSurfaceGstDelegate(); - - GstCaps *caps(); - - bool start(GstCaps *caps); - void stop(); - void unlock(); - bool proposeAllocation(GstQuery *query); - - void flush(); - - GstFlowReturn render(GstBuffer *buffer); - - bool event(QEvent *event) override; - bool query(GstQuery *query); - -private slots: - bool handleEvent(QMutexLocker<QMutex> *locker); - void updateSupportedFormats(); - -private: - void notify(); - bool waitForAsyncEvent(QMutexLocker<QMutex> *locker, QWaitCondition *condition, unsigned long time); - - QPointer<QAbstractVideoSurface> m_surface; - - QMutex m_mutex; - QWaitCondition m_setupCondition; - QWaitCondition m_renderCondition; - GstFlowReturn m_renderReturn = GST_FLOW_OK; - QList<QGstVideoRenderer *> m_renderers; - QGstVideoRenderer *m_renderer = nullptr; - QGstVideoRenderer *m_activeRenderer = nullptr; - - GstCaps *m_surfaceCaps = nullptr; - GstCaps *m_startCaps = nullptr; - GstBuffer *m_renderBuffer = nullptr; -#if QT_CONFIG(gstreamer_gl) - GstGLContext *m_gstGLDisplayContext = nullptr; -#endif - - bool m_notified = false; - bool m_stop = false; - bool m_flush = false; -}; - -class Q_GSTTOOLS_EXPORT QGstVideoRendererSink -{ -public: - GstVideoSink parent; - - static QGstVideoRendererSink *createSink(QAbstractVideoSurface *surface); - static void setSurface(QAbstractVideoSurface *surface); - -private: - static GType get_type(); - static void class_init(gpointer g_class, gpointer class_data); - static void base_init(gpointer g_class); - static void instance_init(GTypeInstance *instance, gpointer g_class); - - static void finalize(GObject *object); - - static void handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d); - - static GstStateChangeReturn change_state(GstElement *element, GstStateChange transition); - - static GstCaps *get_caps(GstBaseSink *sink, GstCaps *filter); - static gboolean set_caps(GstBaseSink *sink, GstCaps *caps); - - static gboolean propose_allocation(GstBaseSink *sink, GstQuery *query); - - static gboolean stop(GstBaseSink *sink); - - static gboolean unlock(GstBaseSink *sink); - - static GstFlowReturn show_frame(GstVideoSink *sink, GstBuffer *buffer); - static gboolean query(GstBaseSink *element, GstQuery *query); - -private: - QVideoSurfaceGstDelegate *delegate = nullptr; -}; - - -class QGstVideoRendererSinkClass -{ -public: - GstVideoSinkClass parent_class; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/gsttools/qvideosurfacegstsink.cpp b/src/gsttools/qvideosurfacegstsink.cpp deleted file mode 100644 index c6951bdef..000000000 --- a/src/gsttools/qvideosurfacegstsink.cpp +++ /dev/null @@ -1,712 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qabstractvideosurface.h> -#include <qvideoframe.h> -#include <QDebug> -#include <QMap> -#include <QDebug> -#include <QThread> - -#include <private/qmediapluginloader_p.h> -#include "qgstvideobuffer_p.h" - -#include "qgstutils_p.h" -#include "qvideosurfacegstsink_p.h" - -#if GST_VERSION_MAJOR >=1 -#include <gst/video/video.h> -#endif - -//#define DEBUG_VIDEO_SURFACE_SINK - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC_WITH_ARGS(QMediaPluginLoader, bufferPoolLoader, - (QGstBufferPoolInterface_iid, QLatin1String("video/bufferpool"), Qt::CaseInsensitive)) - - -QVideoSurfaceGstDelegate::QVideoSurfaceGstDelegate( - QAbstractVideoSurface *surface) - : m_surface(surface) -{ - if (m_surface) { - const auto instances = bufferPoolLoader()->instances(QGstBufferPoolPluginKey); - for (QObject *instance : instances) { - auto plugin = qobject_cast<QGstBufferPoolInterface*>(instance); - - if (plugin) { - m_pools.append(plugin); - } - } - - updateSupportedFormats(); - connect(m_surface, SIGNAL(supportedFormatsChanged()), this, SLOT(updateSupportedFormats())); - } -} - -QVideoSurfaceGstDelegate::~QVideoSurfaceGstDelegate() -{ -} - -QList<QVideoFrame::PixelFormat> QVideoSurfaceGstDelegate::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const -{ - QMutexLocker locker(const_cast<QMutex *>(&m_mutex)); - - if (!m_surface) - return QList<QVideoFrame::PixelFormat>(); - else if (handleType == QAbstractVideoBuffer::NoHandle) - return m_supportedPixelFormats; - else if (handleType == m_pool->handleType()) - return m_supportedPoolPixelFormats; - else - return m_surface->supportedPixelFormats(handleType); -} - -QVideoSurfaceFormat QVideoSurfaceGstDelegate::surfaceFormat() const -{ - QMutexLocker locker(const_cast<QMutex *>(&m_mutex)); - return m_format; -} - -bool QVideoSurfaceGstDelegate::start(const QVideoSurfaceFormat &format, int bytesPerLine) -{ - if (!m_surface) - return false; - - QMutexLocker locker(&m_mutex); - - m_format = format; - m_bytesPerLine = bytesPerLine; - - if (QThread::currentThread() == thread()) { - m_started = !m_surface.isNull() ? m_surface->start(m_format) : false; - } else { - m_started = false; - m_startCanceled = false; - QMetaObject::invokeMethod(this, "queuedStart", Qt::QueuedConnection); - - /* - Waiting for start() to be invoked in the main thread may block - if gstreamer blocks the main thread until this call is finished. - This situation is rare and usually caused by setState(Null) - while pipeline is being prerolled. - - The proper solution to this involves controlling gstreamer pipeline from - other thread than video surface. - - Currently start() fails if wait() timed out. - */ - if (!m_setupCondition.wait(&m_mutex, 1000)) { - qWarning() << "Failed to start video surface due to main thread blocked."; - m_startCanceled = true; - } - } - - m_format = m_surface->surfaceFormat(); - - return m_started; -} - -void QVideoSurfaceGstDelegate::stop() -{ - if (!m_surface) - return; - - QMutexLocker locker(&m_mutex); - - if (QThread::currentThread() == thread()) { - if (!m_surface.isNull()) - m_surface->stop(); - } else { - QMetaObject::invokeMethod(this, "queuedStop", Qt::QueuedConnection); - - // Waiting for stop() to be invoked in the main thread may block - // if gstreamer blocks the main thread until this call is finished. - m_setupCondition.wait(&m_mutex, 500); - } - - m_started = false; -} - -void QVideoSurfaceGstDelegate::unlock() -{ - QMutexLocker locker(&m_mutex); - - m_startCanceled = true; - m_setupCondition.wakeAll(); - m_renderCondition.wakeAll(); -} - -bool QVideoSurfaceGstDelegate::isActive() -{ - QMutexLocker locker(&m_mutex); - return !m_surface.isNull() && m_surface->isActive(); -} - -void QVideoSurfaceGstDelegate::clearPoolBuffers() -{ - QMutexLocker locker(&m_poolMutex); - if (m_pool) - m_pool->clear(); -} - -void QVideoSurfaceGstDelegate::flush() -{ - QMutexLocker locker(&m_mutex); - - m_frame = QVideoFrame(); - m_renderCondition.wakeAll(); - - if (QThread::currentThread() == thread()) { - if (!m_surface.isNull()) - m_surface->present(m_frame); - } else { - QMetaObject::invokeMethod(this, "queuedFlush", Qt::QueuedConnection); - } -} - -GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer) -{ - if (!m_surface) { - qWarning() << "Rendering video frame to deleted surface, skip."; - //return GST_FLOW_NOT_NEGOTIATED; - return GST_FLOW_OK; - } - - QMutexLocker locker(&m_mutex); - - QAbstractVideoBuffer *videoBuffer = 0; - - if (m_pool) - videoBuffer = m_pool->prepareVideoBuffer(buffer, m_bytesPerLine); - - if (!videoBuffer) - videoBuffer = new QGstVideoBuffer(buffer, m_bytesPerLine); - - m_frame = QVideoFrame( - videoBuffer, - m_format.frameSize(), - m_format.pixelFormat()); - - QGstUtils::setFrameTimeStamps(&m_frame, buffer); - - m_renderReturn = GST_FLOW_OK; - - if (QThread::currentThread() == thread()) { - if (!m_surface.isNull()) - m_surface->present(m_frame); - else - qWarning() << "m_surface.isNull()."; - } else { - QMetaObject::invokeMethod(this, "queuedRender", Qt::QueuedConnection); - m_renderCondition.wait(&m_mutex, 300); - } - - m_frame = QVideoFrame(); - return m_renderReturn; -} - -void QVideoSurfaceGstDelegate::queuedStart() -{ - QMutexLocker locker(&m_mutex); - - if (!m_startCanceled) { - m_started = m_surface->start(m_format); - m_setupCondition.wakeAll(); - } -} - -void QVideoSurfaceGstDelegate::queuedStop() -{ - QMutexLocker locker(&m_mutex); - - m_surface->stop(); - - m_setupCondition.wakeAll(); -} - -void QVideoSurfaceGstDelegate::queuedFlush() -{ - QMutexLocker locker(&m_mutex); - - if (!m_surface.isNull()) - m_surface->present(QVideoFrame()); -} - -void QVideoSurfaceGstDelegate::queuedRender() -{ - QMutexLocker locker(&m_mutex); - - if (!m_frame.isValid()) - return; - - if (m_surface.isNull()) { - qWarning() << "Rendering video frame to deleted surface, skip the frame"; - m_renderReturn = GST_FLOW_OK; - } else if (m_surface->present(m_frame)) { - m_renderReturn = GST_FLOW_OK; - } else { - switch (m_surface->error()) { - case QAbstractVideoSurface::NoError: - m_renderReturn = GST_FLOW_OK; - break; - case QAbstractVideoSurface::StoppedError: - //It's likely we are in process of changing video output - //and the surface is already stopped, ignore the frame - m_renderReturn = GST_FLOW_OK; - break; - default: - qWarning() << "Failed to render video frame:" << m_surface->error(); - m_renderReturn = GST_FLOW_OK; - break; - } - } - - m_renderCondition.wakeAll(); -} - -void QVideoSurfaceGstDelegate::updateSupportedFormats() -{ - QGstBufferPoolInterface *newPool = 0; - for (QGstBufferPoolInterface *pool : qAsConst(m_pools)) { - if (!m_surface->supportedPixelFormats(pool->handleType()).isEmpty()) { - newPool = pool; - break; - } - } - - if (newPool != m_pool) { - QMutexLocker lock(&m_poolMutex); - - if (m_pool) - m_pool->clear(); - m_pool = newPool; - } - - QMutexLocker locker(&m_mutex); - - m_supportedPixelFormats.clear(); - m_supportedPoolPixelFormats.clear(); - if (m_surface) { - m_supportedPixelFormats = m_surface->supportedPixelFormats(); - if (m_pool) - m_supportedPoolPixelFormats = m_surface->supportedPixelFormats(m_pool->handleType()); - } -} - -static GstVideoSinkClass *sink_parent_class; - -#define VO_SINK(s) QVideoSurfaceGstSink *sink(reinterpret_cast<QVideoSurfaceGstSink *>(s)) - -QVideoSurfaceGstSink *QVideoSurfaceGstSink::createSink(QAbstractVideoSurface *surface) -{ - QVideoSurfaceGstSink *sink = reinterpret_cast<QVideoSurfaceGstSink *>( - g_object_new(QVideoSurfaceGstSink::get_type(), 0)); - - sink->delegate = new QVideoSurfaceGstDelegate(surface); - - g_signal_connect(G_OBJECT(sink), "notify::show-preroll-frame", G_CALLBACK(handleShowPrerollChange), sink); - - return sink; -} - -GType QVideoSurfaceGstSink::get_type() -{ - static GType type = 0; - - if (type == 0) { - static const GTypeInfo info = - { - sizeof(QVideoSurfaceGstSinkClass), // class_size - base_init, // base_init - nullptr, // base_finalize - class_init, // class_init - nullptr, // class_finalize - nullptr, // class_data - sizeof(QVideoSurfaceGstSink), // instance_size - 0, // n_preallocs - instance_init, // instance_init - 0 // value_table - }; - - type = g_type_register_static( - GST_TYPE_VIDEO_SINK, "QVideoSurfaceGstSink", &info, GTypeFlags(0)); - } - - return type; -} - -void QVideoSurfaceGstSink::class_init(gpointer g_class, gpointer class_data) -{ - Q_UNUSED(class_data); - - sink_parent_class = reinterpret_cast<GstVideoSinkClass *>(g_type_class_peek_parent(g_class)); - - GstBaseSinkClass *base_sink_class = reinterpret_cast<GstBaseSinkClass *>(g_class); - base_sink_class->get_caps = QVideoSurfaceGstSink::get_caps; - base_sink_class->set_caps = QVideoSurfaceGstSink::set_caps; - base_sink_class->buffer_alloc = QVideoSurfaceGstSink::buffer_alloc; - base_sink_class->start = QVideoSurfaceGstSink::start; - base_sink_class->stop = QVideoSurfaceGstSink::stop; - base_sink_class->unlock = QVideoSurfaceGstSink::unlock; - -#if GST_CHECK_VERSION(0, 10, 25) - GstVideoSinkClass *video_sink_class = reinterpret_cast<GstVideoSinkClass *>(g_class); - video_sink_class->show_frame = QVideoSurfaceGstSink::show_frame; -#else - base_sink_class->preroll = QVideoSurfaceGstSink::preroll; - base_sink_class->render = QVideoSurfaceGstSink::render; -#endif - - GstElementClass *element_class = reinterpret_cast<GstElementClass *>(g_class); - element_class->change_state = QVideoSurfaceGstSink::change_state; - - GObjectClass *object_class = reinterpret_cast<GObjectClass *>(g_class); - object_class->finalize = QVideoSurfaceGstSink::finalize; -} - -void QVideoSurfaceGstSink::base_init(gpointer g_class) -{ - static GstStaticPadTemplate sink_pad_template = GST_STATIC_PAD_TEMPLATE( - "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS( - "video/x-raw-rgb, " - "framerate = (fraction) [ 0, MAX ], " - "width = (int) [ 1, MAX ], " - "height = (int) [ 1, MAX ]; " - "video/x-raw-yuv, " - "framerate = (fraction) [ 0, MAX ], " - "width = (int) [ 1, MAX ], " - "height = (int) [ 1, MAX ]")); - - gst_element_class_add_pad_template( - GST_ELEMENT_CLASS(g_class), gst_static_pad_template_get(&sink_pad_template)); -} - -void QVideoSurfaceGstSink::instance_init(GTypeInstance *instance, gpointer g_class) -{ - VO_SINK(instance); - - Q_UNUSED(g_class); - - sink->delegate = 0; - - sink->lastRequestedCaps = 0; - sink->lastBufferCaps = 0; - sink->lastSurfaceFormat = new QVideoSurfaceFormat; -} - -void QVideoSurfaceGstSink::finalize(GObject *object) -{ - VO_SINK(object); - - delete sink->lastSurfaceFormat; - sink->lastSurfaceFormat = 0; - - if (sink->lastBufferCaps) - gst_caps_unref(sink->lastBufferCaps); - sink->lastBufferCaps = 0; - - if (sink->lastRequestedCaps) - gst_caps_unref(sink->lastRequestedCaps); - sink->lastRequestedCaps = 0; - - delete sink->delegate; - - // Chain up - G_OBJECT_CLASS(sink_parent_class)->finalize(object); -} - -void QVideoSurfaceGstSink::handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d) -{ - Q_UNUSED(o); - Q_UNUSED(p); - QVideoSurfaceGstSink *sink = reinterpret_cast<QVideoSurfaceGstSink *>(d); - - gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default - g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, nullptr); - - if (!showPrerollFrame) { - GstState state = GST_STATE_VOID_PENDING; - gst_element_get_state(GST_ELEMENT(sink), &state, nullptr, GST_CLOCK_TIME_NONE); - // show-preroll-frame being set to 'false' while in GST_STATE_PAUSED means - // the QMediaPlayer was stopped from the paused state. - // We need to flush the current frame. - if (state == GST_STATE_PAUSED) - sink->delegate->flush(); - } -} - -GstStateChangeReturn QVideoSurfaceGstSink::change_state(GstElement *element, GstStateChange transition) -{ - QVideoSurfaceGstSink *sink = reinterpret_cast<QVideoSurfaceGstSink *>(element); - - gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default - g_object_get(G_OBJECT(element), "show-preroll-frame", &showPrerollFrame, nullptr); - - // If show-preroll-frame is 'false' when transitioning from GST_STATE_PLAYING to - // GST_STATE_PAUSED, it means the QMediaPlayer was stopped. - // We need to flush the current frame. - if (transition == GST_STATE_CHANGE_PLAYING_TO_PAUSED && !showPrerollFrame) - sink->delegate->flush(); - - return GST_ELEMENT_CLASS(sink_parent_class)->change_state(element, transition); -} - -GstCaps *QVideoSurfaceGstSink::get_caps(GstBaseSink *base) -{ - VO_SINK(base); - - // Find the supported pixel formats - // with buffer pool specific formats listed first - QList<QVideoFrame::PixelFormat> supportedFormats; - - QList<QVideoFrame::PixelFormat> poolHandleFormats; - sink->delegate->poolMutex()->lock(); - QGstBufferPoolInterface *pool = sink->delegate->pool(); - - if (pool) - poolHandleFormats = sink->delegate->supportedPixelFormats(pool->handleType()); - sink->delegate->poolMutex()->unlock(); - - supportedFormats = poolHandleFormats; - const auto supportedPixelFormats = sink->delegate->supportedPixelFormats(); - for (QVideoFrame::PixelFormat format : supportedPixelFormats) { - if (!poolHandleFormats.contains(format)) - supportedFormats.append(format); - } - - return QGstUtils::capsForFormats(supportedFormats); -} - -gboolean QVideoSurfaceGstSink::set_caps(GstBaseSink *base, GstCaps *caps) -{ - VO_SINK(base); - -#ifdef DEBUG_VIDEO_SURFACE_SINK - qDebug() << "set_caps:"; - qDebug() << gst_caps_to_string(caps); -#endif - - if (!caps) { - sink->delegate->stop(); - - return TRUE; - } else { - int bytesPerLine = 0; - QGstBufferPoolInterface *pool = sink->delegate->pool(); - QAbstractVideoBuffer::HandleType handleType = - pool ? pool->handleType() : QAbstractVideoBuffer::NoHandle; - - QVideoSurfaceFormat format = QGstUtils::formatForCaps(caps, &bytesPerLine, handleType); - - if (sink->delegate->isActive()) { - QVideoSurfaceFormat surfaceFormst = sink->delegate->surfaceFormat(); - - if (format.pixelFormat() == surfaceFormst.pixelFormat() && - format.frameSize() == surfaceFormst.frameSize()) - return TRUE; - else - sink->delegate->stop(); - } - - if (sink->lastRequestedCaps) - gst_caps_unref(sink->lastRequestedCaps); - sink->lastRequestedCaps = 0; - -#ifdef DEBUG_VIDEO_SURFACE_SINK - qDebug() << "Starting video surface, format:"; - qDebug() << format; - qDebug() << "bytesPerLine:" << bytesPerLine; -#endif - - if (sink->delegate->start(format, bytesPerLine)) - return TRUE; - else - qWarning() << "Failed to start video surface"; - } - - return FALSE; -} - -GstFlowReturn QVideoSurfaceGstSink::buffer_alloc( - GstBaseSink *base, guint64 offset, guint size, GstCaps *caps, GstBuffer **buffer) -{ - VO_SINK(base); - - Q_UNUSED(offset); - Q_UNUSED(size); - - if (!buffer) - return GST_FLOW_ERROR; - - *buffer = nullptr; - - if (!sink->delegate->pool()) - return GST_FLOW_OK; - - QMutexLocker poolLock(sink->delegate->poolMutex()); - QGstBufferPoolInterface *pool = sink->delegate->pool(); - - if (!pool) - return GST_FLOW_OK; - - if (sink->lastRequestedCaps && gst_caps_is_equal(sink->lastRequestedCaps, caps)) { - //qDebug() << "reusing last caps"; - *buffer = GST_BUFFER(pool->takeBuffer(*sink->lastSurfaceFormat, sink->lastBufferCaps)); - return GST_FLOW_OK; - } - - if (sink->delegate->supportedPixelFormats(pool->handleType()).isEmpty()) { - //qDebug() << "sink doesn't support native pool buffers, skip buffers allocation"; - return GST_FLOW_OK; - } - - poolLock.unlock(); - - GstCaps *intersection = gst_caps_intersect(get_caps(GST_BASE_SINK(sink)), caps); - - if (gst_caps_is_empty (intersection)) { - gst_caps_unref(intersection); - return GST_FLOW_NOT_NEGOTIATED; - } - - if (sink->delegate->isActive()) { - //if format was changed, restart the surface - QVideoSurfaceFormat format = QGstUtils::formatForCaps(intersection); - QVideoSurfaceFormat surfaceFormat = sink->delegate->surfaceFormat(); - - if (format.pixelFormat() != surfaceFormat.pixelFormat() || - format.frameSize() != surfaceFormat.frameSize()) { -#ifdef DEBUG_VIDEO_SURFACE_SINK - qDebug() << "new format requested, restart video surface"; -#endif - sink->delegate->stop(); - } - } - - if (!sink->delegate->isActive()) { - int bytesPerLine = 0; - QGstBufferPoolInterface *pool = sink->delegate->pool(); - QAbstractVideoBuffer::HandleType handleType = - pool ? pool->handleType() : QAbstractVideoBuffer::NoHandle; - - QVideoSurfaceFormat format = QGstUtils::formatForCaps(intersection, &bytesPerLine, handleType); - - if (!sink->delegate->start(format, bytesPerLine)) { - qWarning() << "failed to start video surface"; - return GST_FLOW_NOT_NEGOTIATED; - } - } - - poolLock.relock(); - pool = sink->delegate->pool(); - - QVideoSurfaceFormat surfaceFormat = sink->delegate->surfaceFormat(); - - if (!pool->isFormatSupported(surfaceFormat)) { - qDebug() << "sink doesn't support native pool format, skip custom buffers allocation"; - return GST_FLOW_OK; - } - - if (sink->lastRequestedCaps) - gst_caps_unref(sink->lastRequestedCaps); - sink->lastRequestedCaps = caps; - gst_caps_ref(sink->lastRequestedCaps); - - if (sink->lastBufferCaps) - gst_caps_unref(sink->lastBufferCaps); - sink->lastBufferCaps = intersection; - gst_caps_ref(sink->lastBufferCaps); - - *sink->lastSurfaceFormat = surfaceFormat; - - *buffer = GST_BUFFER(pool->takeBuffer(surfaceFormat, intersection)); - - return GST_FLOW_OK; -} - -gboolean QVideoSurfaceGstSink::start(GstBaseSink *base) -{ - Q_UNUSED(base); - return TRUE; -} - -gboolean QVideoSurfaceGstSink::stop(GstBaseSink *base) -{ - VO_SINK(base); - sink->delegate->clearPoolBuffers(); - - return TRUE; -} - -gboolean QVideoSurfaceGstSink::unlock(GstBaseSink *base) -{ - VO_SINK(base); - sink->delegate->unlock(); - return TRUE; -} - -#if GST_CHECK_VERSION(0, 10, 25) -GstFlowReturn QVideoSurfaceGstSink::show_frame(GstVideoSink *base, GstBuffer *buffer) -{ - VO_SINK(base); - return sink->delegate->render(buffer); -} -#else -GstFlowReturn QVideoSurfaceGstSink::preroll(GstBaseSink *base, GstBuffer *buffer) -{ - VO_SINK(base); - gboolean showPrerollFrame = true; - g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, nullptr); - - if (showPrerollFrame) - return sink->delegate->render(buffer); - - return GST_FLOW_OK; -} - -GstFlowReturn QVideoSurfaceGstSink::render(GstBaseSink *base, GstBuffer *buffer) -{ - VO_SINK(base); - return sink->delegate->render(buffer); -} -#endif - -QT_END_NAMESPACE diff --git a/src/gsttools/qvideosurfacegstsink_p.h b/src/gsttools/qvideosurfacegstsink_p.h deleted file mode 100644 index dd758ff82..000000000 --- a/src/gsttools/qvideosurfacegstsink_p.h +++ /dev/null @@ -1,192 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef VIDEOSURFACEGSTSINK_P_H -#define VIDEOSURFACEGSTSINK_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <gst/gst.h> - -#if GST_CHECK_VERSION(1,0,0) - -#include "qgstvideorenderersink_p.h" - -QT_BEGIN_NAMESPACE -typedef QGstVideoRendererSink QVideoSurfaceGstSink; -QT_END_NAMESPACE - -#else - -#include <gst/video/gstvideosink.h> - -#include <QtCore/qlist.h> -#include <QtCore/qmutex.h> -#include <QtCore/qqueue.h> -#include <QtCore/qpointer.h> -#include <QtCore/qwaitcondition.h> -#include <qvideosurfaceformat.h> -#include <qvideoframe.h> -#include <qabstractvideobuffer.h> - -#include "qgstbufferpoolinterface_p.h" - -QT_BEGIN_NAMESPACE -class QAbstractVideoSurface; - -class QVideoSurfaceGstDelegate : public QObject -{ - Q_OBJECT -public: - QVideoSurfaceGstDelegate(QAbstractVideoSurface *surface); - ~QVideoSurfaceGstDelegate(); - - QList<QVideoFrame::PixelFormat> supportedPixelFormats( - QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; - - QVideoSurfaceFormat surfaceFormat() const; - - bool start(const QVideoSurfaceFormat &format, int bytesPerLine); - void stop(); - - void unlock(); - - bool isActive(); - - QGstBufferPoolInterface *pool() { return m_pool; } - QMutex *poolMutex() { return &m_poolMutex; } - void clearPoolBuffers(); - - void flush(); - - GstFlowReturn render(GstBuffer *buffer); - -private slots: - void queuedStart(); - void queuedStop(); - void queuedFlush(); - void queuedRender(); - - void updateSupportedFormats(); - -private: - QPointer<QAbstractVideoSurface> m_surface; - QList<QVideoFrame::PixelFormat> m_supportedPixelFormats; - //pixel formats of buffers pool native type - QList<QVideoFrame::PixelFormat> m_supportedPoolPixelFormats; - QGstBufferPoolInterface *m_pool = nullptr; - QList<QGstBufferPoolInterface *> m_pools; - QMutex m_poolMutex; - QMutex m_mutex; - QWaitCondition m_setupCondition; - QWaitCondition m_renderCondition; - QVideoSurfaceFormat m_format; - QVideoFrame m_frame; - GstFlowReturn m_renderReturn = GST_FLOW_ERROR; - int m_bytesPerLine = 0; - bool m_started = false; - bool m_startCanceled = false; -}; - -class QVideoSurfaceGstSink -{ -public: - GstVideoSink parent; - - static QVideoSurfaceGstSink *createSink(QAbstractVideoSurface *surface); - static void setSurface(QAbstractVideoSurface *surface) { Q_UNUSED(surface); } - -private: - static GType get_type(); - static void class_init(gpointer g_class, gpointer class_data); - static void base_init(gpointer g_class); - static void instance_init(GTypeInstance *instance, gpointer g_class); - - static void finalize(GObject *object); - - static void handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d); - - static GstStateChangeReturn change_state(GstElement *element, GstStateChange transition); - - static GstCaps *get_caps(GstBaseSink *sink); - static gboolean set_caps(GstBaseSink *sink, GstCaps *caps); - - static GstFlowReturn buffer_alloc( - GstBaseSink *sink, guint64 offset, guint size, GstCaps *caps, GstBuffer **buffer); - - static gboolean start(GstBaseSink *sink); - static gboolean stop(GstBaseSink *sink); - - static gboolean unlock(GstBaseSink *sink); - -#if GST_CHECK_VERSION(0, 10, 25) - static GstFlowReturn show_frame(GstVideoSink *sink, GstBuffer *buffer); -#else - static GstFlowReturn preroll(GstBaseSink *sink, GstBuffer *buffer); - static GstFlowReturn render(GstBaseSink *sink, GstBuffer *buffer); -#endif - -private: - QVideoSurfaceGstDelegate *delegate = nullptr; - - GstCaps *lastRequestedCaps = nullptr; - GstCaps *lastBufferCaps = nullptr; - QVideoSurfaceFormat *lastSurfaceFormat = nullptr; -}; - -class QVideoSurfaceGstSinkClass -{ -public: - GstVideoSinkClass parent_class; -}; - -QT_END_NAMESPACE - -#endif - -#endif |