summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVaL Doroshchuk <valentyn.doroshchuk@qt.io>2018-06-26 16:18:35 +0200
committerVaL Doroshchuk <valentyn.doroshchuk@qt.io>2018-08-30 10:13:35 +0000
commit35ace9e289dcaada5e0828a59ca7dfee78a6342c (patch)
tree3132cb84abb0df2f347e47edb2b196ec0727d218
parent11b90699d2f355f6223a21a9e8491963903cb635 (diff)
Gstreamer: Introduce custom pipeline
Added an ability to define custom pipeline. Since new pipeline is used, playbin features will not work. Registered "qtvideosink" gstreamer element to be used in pipelines. In case if there is a need to render to QML VideoOutput element. I.e. if a pipeline is "videotestsrc ! qtvideosink" then QGstVideoRendererSink will be used as a sink and rendering will be done by one of QSGVideoNode's. In this case there is a need to create a pipeline after video surface is ready. Also added an ability to override default video sink and define custom one instead. QGstreamerVideoRendererInterface::setVideoSink() provides functionality to override default one. QGstreamerPlayerSession::rendererChanged() can be used to check if the renderer is ready to create a pipeline or set custom video sink. Task-number: QTBUG-39327 Change-Id: I635d3a07fb9a5dcf30ee63284a849b0ad3438536 Reviewed-by: VaL Doroshchuk <valentyn.doroshchuk@qt.io>
-rw-r--r--src/gsttools/qgstreamerplayersession.cpp87
-rw-r--r--src/gsttools/qgstreamervideooverlay.cpp47
-rw-r--r--src/gsttools/qgstreamervideorenderer.cpp46
-rw-r--r--src/gsttools/qgstreamervideowidget.cpp5
-rw-r--r--src/gsttools/qgstvideorenderersink.cpp23
-rw-r--r--src/multimedia/gsttools_headers/qgstreamerplayersession_p.h7
-rw-r--r--src/multimedia/gsttools_headers/qgstreamervideooverlay_p.h1
-rw-r--r--src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h3
-rw-r--r--src/multimedia/gsttools_headers/qgstreamervideorendererinterface_p.h1
-rw-r--r--src/multimedia/gsttools_headers/qgstreamervideowidget_p.h1
-rw-r--r--src/multimedia/gsttools_headers/qgstvideorenderersink_p.h3
11 files changed, 160 insertions, 64 deletions
diff --git a/src/gsttools/qgstreamerplayersession.cpp b/src/gsttools/qgstreamerplayersession.cpp
index 8ee099590..adf27e4a0 100644
--- a/src/gsttools/qgstreamerplayersession.cpp
+++ b/src/gsttools/qgstreamerplayersession.cpp
@@ -114,7 +114,6 @@ QGstreamerPlayerSession::QGstreamerPlayerSession(QObject *parent)
m_state(QMediaPlayer::StoppedState),
m_pendingState(QMediaPlayer::StoppedState),
m_busHelper(0),
- m_playbin(0),
m_videoSink(0),
#if !GST_CHECK_VERSION(1,0,0)
m_usingColorspaceElement(false),
@@ -241,12 +240,15 @@ QGstreamerPlayerSession::QGstreamerPlayerSession(QObject *parent)
#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_playbin) {
+ if (m_pipeline) {
stop();
removeVideoBufferProbe();
@@ -254,7 +256,9 @@ QGstreamerPlayerSession::~QGstreamerPlayerSession()
delete m_busHelper;
gst_object_unref(GST_OBJECT(m_bus));
- gst_object_unref(GST_OBJECT(m_playbin));
+ if (m_playbin)
+ gst_object_unref(GST_OBJECT(m_playbin));
+ gst_object_unref(GST_OBJECT(m_pipeline));
#if !GST_CHECK_VERSION(1,0,0)
gst_object_unref(GST_OBJECT(m_colorSpace));
#endif
@@ -268,6 +272,33 @@ GstElement *QGstreamerPlayerSession::playbin() const
return m_playbin;
}
+void QGstreamerPlayerSession::setPipeline(GstElement *pipeline)
+{
+ GstBus *bus = pipeline ? gst_element_get_bus(pipeline) : nullptr;
+ if (!bus)
+ return;
+
+ gst_object_unref(GST_OBJECT(m_pipeline));
+ m_pipeline = pipeline;
+ gst_object_unref(GST_OBJECT(m_bus));
+ m_bus = bus;
+ delete m_busHelper;
+ m_busHelper = new QGstreamerBusHelper(m_bus, this);
+ m_busHelper->installMessageFilter(this);
+
+ if (m_videoOutput)
+ m_busHelper->installMessageFilter(m_videoOutput);
+
+ if (m_playbin) {
+ gst_element_set_state(m_playbin, GST_STATE_NULL);
+ gst_object_unref(GST_OBJECT(m_playbin));
+ }
+
+ m_playbin = nullptr;
+ m_volumeElement = nullptr;
+ m_videoIdentity = nullptr;
+}
+
#if QT_CONFIG(gstreamer_app)
void QGstreamerPlayerSession::configureAppSrcElement(GObject* object, GObject *orig, GParamSpec *pspec, QGstreamerPlayerSession* self)
{
@@ -357,7 +388,7 @@ qint64 QGstreamerPlayerSession::position() const
{
gint64 position = 0;
- if (m_playbin && qt_gst_element_query_position(m_playbin, GST_FORMAT_TIME, &position))
+ if (m_pipeline && qt_gst_element_query_position(m_pipeline, GST_FORMAT_TIME, &position))
m_lastPosition = position / 1000000;
return m_lastPosition;
}
@@ -374,8 +405,8 @@ void QGstreamerPlayerSession::setPlaybackRate(qreal rate)
#endif
if (!qFuzzyCompare(m_playbackRate, rate)) {
m_playbackRate = rate;
- if (m_playbin && m_seekable) {
- gst_element_seek(m_playbin, rate, GST_FORMAT_TIME,
+ if (m_pipeline && m_seekable) {
+ gst_element_seek(m_pipeline, rate, GST_FORMAT_TIME,
GstSeekFlags(GST_SEEK_FLAG_FLUSH),
GST_SEEK_TYPE_NONE,0,
GST_SEEK_TYPE_NONE,0 );
@@ -396,7 +427,7 @@ QMediaTimeRange QGstreamerPlayerSession::availablePlaybackRanges() const
//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_playbin, query)) {
+ if (!gst_element_query(m_pipeline, query)) {
gst_query_unref(query);
return ranges;
}
@@ -551,6 +582,14 @@ void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput)
m_renderer = renderer;
+ // If custom pipeline is considered to use video sink from the renderer
+ // need to create the pipeline when the renderer is ready.
+ emit rendererChanged();
+
+ // No sense to continue if custom pipeline requested.
+ if (!m_playbin)
+ return;
+
#ifdef DEBUG_VO_BIN_DUMP
gst_debug_bin_to_dot_file_with_ts(GST_BIN(m_playbin),
GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL /* GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES*/),
@@ -684,7 +723,7 @@ void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput)
void QGstreamerPlayerSession::finishVideoOutputChange()
{
- if (!m_pendingVideoSink)
+ if (!m_playbin || !m_pendingVideoSink)
return;
#ifdef DEBUG_PLAYBIN
@@ -889,9 +928,9 @@ bool QGstreamerPlayerSession::play()
#endif
m_everPlayed = false;
- if (m_playbin) {
+ if (m_pipeline) {
m_pendingState = QMediaPlayer::PlayingState;
- if (gst_element_set_state(m_playbin, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+ 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);
@@ -909,12 +948,12 @@ bool QGstreamerPlayerSession::pause()
#ifdef DEBUG_PLAYBIN
qDebug() << Q_FUNC_INFO;
#endif
- if (m_playbin) {
+ if (m_pipeline) {
m_pendingState = QMediaPlayer::PausedState;
if (m_pendingVideoSink != 0)
return true;
- if (gst_element_set_state(m_playbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
+ 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);
@@ -933,13 +972,13 @@ void QGstreamerPlayerSession::stop()
qDebug() << Q_FUNC_INFO;
#endif
m_everPlayed = false;
- if (m_playbin) {
+ if (m_pipeline) {
if (m_renderer)
m_renderer->stopRenderer();
flushVideoProbes();
- gst_element_set_state(m_playbin, GST_STATE_NULL);
+ gst_element_set_state(m_pipeline, GST_STATE_NULL);
m_lastPosition = 0;
QMediaPlayer::State oldState = m_state;
@@ -960,10 +999,10 @@ bool QGstreamerPlayerSession::seek(qint64 ms)
qDebug() << Q_FUNC_INFO << ms;
#endif
//seek locks when the video output sink is changing and pad is blocked
- if (m_playbin && !m_pendingVideoSink && m_state != QMediaPlayer::StoppedState && m_seekable) {
+ if (m_pipeline && !m_pendingVideoSink && m_state != QMediaPlayer::StoppedState && m_seekable) {
ms = qMax(ms,qint64(0));
gint64 position = ms * 1000000;
- bool isSeeking = gst_element_seek(m_playbin,
+ bool isSeeking = gst_element_seek(m_pipeline,
m_playbackRate,
GST_FORMAT_TIME,
GstSeekFlags(GST_SEEK_FLAG_FLUSH),
@@ -1061,7 +1100,7 @@ bool QGstreamerPlayerSession::processBusMessage(const QGstreamerMessage &message
}
bool handlePlaybin2 = false;
- if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_playbin)) {
+ if (GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_pipeline)) {
switch (GST_MESSAGE_TYPE(gm)) {
case GST_MESSAGE_STATE_CHANGED:
{
@@ -1217,7 +1256,7 @@ bool QGstreamerPlayerSession::processBusMessage(const QGstreamerMessage &message
case GST_MESSAGE_ASYNC_DONE:
{
gint64 position = 0;
- if (qt_gst_element_query_position(m_playbin, GST_FORMAT_TIME, &position)) {
+ if (qt_gst_element_query_position(m_pipeline, GST_FORMAT_TIME, &position)) {
position /= 1000000;
m_lastPosition = position;
emit positionChanged(position);
@@ -1317,6 +1356,9 @@ bool QGstreamerPlayerSession::processBusMessage(const QGstreamerMessage &message
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;
@@ -1408,6 +1450,9 @@ void QGstreamerPlayerSession::getStreamsInfo()
void QGstreamerPlayerSession::updateVideoResolutionTag()
{
+ if (!m_videoIdentity)
+ return;
+
#ifdef DEBUG_PLAYBIN
qDebug() << Q_FUNC_INFO;
#endif
@@ -1457,7 +1502,7 @@ void QGstreamerPlayerSession::updateDuration()
gint64 gstDuration = 0;
int duration = -1;
- if (m_playbin && qt_gst_element_query_duration(m_playbin, GST_FORMAT_TIME, &gstDuration))
+ if (m_pipeline && qt_gst_element_query_duration(m_pipeline, GST_FORMAT_TIME, &gstDuration))
duration = gstDuration / 1000000;
if (m_duration != duration) {
@@ -1469,7 +1514,7 @@ void QGstreamerPlayerSession::updateDuration()
if (m_duration > 0) {
m_durationQueries = 0;
GstQuery *query = gst_query_new_seeking(GST_FORMAT_TIME);
- if (gst_element_query(m_playbin, query))
+ if (gst_element_query(m_pipeline, query))
gst_query_parse_seeking(query, 0, &seekable, 0, 0);
gst_query_unref(query);
}
@@ -1802,7 +1847,7 @@ void QGstreamerPlayerSession::endOfMediaReset()
m_renderer->stopRenderer();
flushVideoProbes();
- gst_element_set_state(m_playbin, GST_STATE_NULL);
+ gst_element_set_state(m_pipeline, GST_STATE_NULL);
QMediaPlayer::State oldState = m_state;
m_pendingState = m_state = QMediaPlayer::StoppedState;
diff --git a/src/gsttools/qgstreamervideooverlay.cpp b/src/gsttools/qgstreamervideooverlay.cpp
index de4f255d5..1f3e28549 100644
--- a/src/gsttools/qgstreamervideooverlay.cpp
+++ b/src/gsttools/qgstreamervideooverlay.cpp
@@ -379,27 +379,13 @@ QGstreamerVideoOverlay::QGstreamerVideoOverlay(QObject *parent, const QByteArray
: QObject(parent)
, QGstreamerBufferProbe(QGstreamerBufferProbe::ProbeCaps)
{
+ GstElement *sink = nullptr;
if (!elementName.isEmpty())
- m_videoSink = gst_element_factory_make(elementName.constData(), NULL);
+ sink = gst_element_factory_make(elementName.constData(), NULL);
else
- m_videoSink = findBestVideoSink();
+ sink = findBestVideoSink();
- if (m_videoSink) {
- qt_gst_object_ref_sink(GST_OBJECT(m_videoSink)); //Take ownership
-
- GstPad *pad = gst_element_get_static_pad(m_videoSink, "sink");
- addProbeToPad(pad);
- gst_object_unref(GST_OBJECT(pad));
-
- QString sinkName(QLatin1String(GST_OBJECT_NAME(m_videoSink)));
- bool isVaapi = sinkName.startsWith(QLatin1String("vaapisink"));
- m_sinkProperties = isVaapi ? new QVaapiSinkProperties(m_videoSink) : new QXVImageSinkProperties(m_videoSink);
-
- if (m_sinkProperties->hasShowPrerollFrame()) {
- g_signal_connect(m_videoSink, "notify::show-preroll-frame",
- G_CALLBACK(showPrerollFrameChanged), this);
- }
- }
+ setVideoSink(sink);
}
QGstreamerVideoOverlay::~QGstreamerVideoOverlay()
@@ -418,6 +404,31 @@ 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;
diff --git a/src/gsttools/qgstreamervideorenderer.cpp b/src/gsttools/qgstreamervideorenderer.cpp
index 412257739..1b5cc8caf 100644
--- a/src/gsttools/qgstreamervideorenderer.cpp
+++ b/src/gsttools/qgstreamervideorenderer.cpp
@@ -45,25 +45,44 @@
#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),m_videoSink(0), m_surface(0)
+ : QVideoRendererControl(parent)
{
}
QGstreamerVideoRenderer::~QGstreamerVideoRenderer()
{
- if (m_videoSink)
- gst_object_unref(GST_OBJECT(m_videoSink));
+ 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) {
- m_videoSink = QVideoSurfaceGstSink::createSink(m_surface);
- qt_gst_object_ref_sink(GST_OBJECT(m_videoSink)); //Take ownership
+ auto sink = reinterpret_cast<GstElement *>(QVideoSurfaceGstSink::createSink(m_surface));
+ resetSink(m_videoSink, sink);
}
- return reinterpret_cast<GstElement*>(m_videoSink);
+ return m_videoSink;
}
void QGstreamerVideoRenderer::stopRenderer()
@@ -80,11 +99,7 @@ QAbstractVideoSurface *QGstreamerVideoRenderer::surface() const
void QGstreamerVideoRenderer::setSurface(QAbstractVideoSurface *surface)
{
if (m_surface != surface) {
- //qDebug() << Q_FUNC_INFO << surface;
- if (m_videoSink)
- gst_object_unref(GST_OBJECT(m_videoSink));
-
- m_videoSink = 0;
+ resetSink(m_videoSink);
if (m_surface) {
disconnect(m_surface.data(), SIGNAL(supportedFormatsChanged()),
@@ -98,6 +113,7 @@ void QGstreamerVideoRenderer::setSurface(QAbstractVideoSurface *surface)
if (m_surface) {
connect(m_surface.data(), SIGNAL(supportedFormatsChanged()),
this, SLOT(handleFormatChange()));
+ QGstVideoRendererSink::setSurface(m_surface);
}
if (wasReady != isReady())
@@ -109,11 +125,5 @@ void QGstreamerVideoRenderer::setSurface(QAbstractVideoSurface *surface)
void QGstreamerVideoRenderer::handleFormatChange()
{
- //qDebug() << "Supported formats list has changed, reload video output";
-
- if (m_videoSink)
- gst_object_unref(GST_OBJECT(m_videoSink));
-
- m_videoSink = 0;
- emit sinkChanged();
+ setVideoSink(nullptr);
}
diff --git a/src/gsttools/qgstreamervideowidget.cpp b/src/gsttools/qgstreamervideowidget.cpp
index 792df4243..633f39fa2 100644
--- a/src/gsttools/qgstreamervideowidget.cpp
+++ b/src/gsttools/qgstreamervideowidget.cpp
@@ -135,6 +135,11 @@ GstElement *QGstreamerVideoWidgetControl::videoSink()
return m_videoOverlay.videoSink();
}
+void QGstreamerVideoWidgetControl::setVideoSink(GstElement *sink)
+{
+ m_videoOverlay.setVideoSink(sink);
+}
+
void QGstreamerVideoWidgetControl::onOverlayActiveChanged()
{
updateWidgetAttributes();
diff --git a/src/gsttools/qgstvideorenderersink.cpp b/src/gsttools/qgstvideorenderersink.cpp
index 4c73c26a3..09fdd42a6 100644
--- a/src/gsttools/qgstvideorenderersink.cpp
+++ b/src/gsttools/qgstvideorenderersink.cpp
@@ -394,21 +394,27 @@ void QVideoSurfaceGstDelegate::updateSupportedFormats()
}
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));
- sink->delegate = new QVideoSurfaceGstDelegate(surface);
-
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;
@@ -430,6 +436,10 @@ GType QGstVideoRendererSink::get_type()
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;
@@ -453,6 +463,11 @@ void QGstVideoRendererSink::class_init(gpointer g_class, gpointer class_data)
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;
@@ -476,8 +491,8 @@ void QGstVideoRendererSink::instance_init(GTypeInstance *instance, gpointer g_cl
VO_SINK(instance);
Q_UNUSED(g_class);
-
- sink->delegate = 0;
+ sink->delegate = new QVideoSurfaceGstDelegate(current_surface);
+ sink->delegate->moveToThread(current_surface->thread());
}
void QGstVideoRendererSink::finalize(GObject *object)
diff --git a/src/multimedia/gsttools_headers/qgstreamerplayersession_p.h b/src/multimedia/gsttools_headers/qgstreamerplayersession_p.h
index 81c385600..447b9816a 100644
--- a/src/multimedia/gsttools_headers/qgstreamerplayersession_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamerplayersession_p.h
@@ -94,6 +94,8 @@ public:
virtual ~QGstreamerPlayerSession();
GstElement *playbin() const;
+ void setPipeline(GstElement *pipeline);
+ GstElement *pipeline() const { return m_pipeline; }
QGstreamerBusHelper *bus() const { return m_busHelper; }
QNetworkRequest request() const;
@@ -110,6 +112,7 @@ public:
bool isAudioAvailable() const;
void setVideoRenderer(QObject *renderer);
+ QGstreamerVideoRendererInterface *renderer() const { return m_renderer; }
bool isVideoAvailable() const;
bool isSeekable() const;
@@ -174,6 +177,7 @@ signals:
void error(int error, const QString &errorString);
void invalidMedia();
void playbackRateChanged(qreal);
+ void rendererChanged();
private slots:
void getStreamsInfo();
@@ -209,7 +213,8 @@ private:
QMediaPlayer::State m_state;
QMediaPlayer::State m_pendingState;
QGstreamerBusHelper* m_busHelper;
- GstElement* m_playbin;
+ GstElement *m_playbin = nullptr; // Can be null
+ GstElement *m_pipeline = nullptr; // Never null
GstElement* m_videoSink;
diff --git a/src/multimedia/gsttools_headers/qgstreamervideooverlay_p.h b/src/multimedia/gsttools_headers/qgstreamervideooverlay_p.h
index 4228f0fd0..f2ca8a23b 100644
--- a/src/multimedia/gsttools_headers/qgstreamervideooverlay_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamervideooverlay_p.h
@@ -72,6 +72,7 @@ public:
virtual ~QGstreamerVideoOverlay();
GstElement *videoSink() const;
+ void setVideoSink(GstElement *);
QSize nativeVideoSize() const;
void setWindowHandle(WId id);
diff --git a/src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h b/src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h
index 2f0b80d45..d87bfcb8f 100644
--- a/src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h
@@ -72,6 +72,7 @@ public:
void setSurface(QAbstractVideoSurface *surface) override;
GstElement *videoSink() override;
+ void setVideoSink(GstElement *) override;
void stopRenderer() override;
bool isReady() const override { return m_surface != 0; }
@@ -84,7 +85,7 @@ private slots:
void handleFormatChange();
private:
- QVideoSurfaceGstSink *m_videoSink;
+ GstElement *m_videoSink = nullptr;
QPointer<QAbstractVideoSurface> m_surface;
};
diff --git a/src/multimedia/gsttools_headers/qgstreamervideorendererinterface_p.h b/src/multimedia/gsttools_headers/qgstreamervideorendererinterface_p.h
index 0d172167b..231c843db 100644
--- a/src/multimedia/gsttools_headers/qgstreamervideorendererinterface_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamervideorendererinterface_p.h
@@ -62,6 +62,7 @@ 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
diff --git a/src/multimedia/gsttools_headers/qgstreamervideowidget_p.h b/src/multimedia/gsttools_headers/qgstreamervideowidget_p.h
index 3e3240725..1ddb738df 100644
--- a/src/multimedia/gsttools_headers/qgstreamervideowidget_p.h
+++ b/src/multimedia/gsttools_headers/qgstreamervideowidget_p.h
@@ -75,6 +75,7 @@ public:
virtual ~QGstreamerVideoWidgetControl();
GstElement *videoSink() override;
+ void setVideoSink(GstElement *) override;
QWidget *videoWidget() override;
diff --git a/src/multimedia/gsttools_headers/qgstvideorenderersink_p.h b/src/multimedia/gsttools_headers/qgstvideorenderersink_p.h
index 3971c959d..d2417a7c9 100644
--- a/src/multimedia/gsttools_headers/qgstvideorenderersink_p.h
+++ b/src/multimedia/gsttools_headers/qgstvideorenderersink_p.h
@@ -138,12 +138,13 @@ private:
bool m_flush;
};
-class QGstVideoRendererSink
+class Q_GSTTOOLS_EXPORT QGstVideoRendererSink
{
public:
GstVideoSink parent;
static QGstVideoRendererSink *createSink(QAbstractVideoSurface *surface);
+ static void setSurface(QAbstractVideoSurface *surface);
private:
static GType get_type();