diff --git a/src/gsttools/qgstreamerplayersession.cpp b/src/gsttools/qgstreamerplayersession.cpp index 8ee099590f48b5c35943d143da60c2c7cd09d90c..adf27e4a0c4035f4bd59ffe34036a4f1369e3178 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 de4f255d57809b99eb0cedc652207d38c2fb4100..1f3e28549f7d074c44ede171f2475f0dec2c7f7f 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 412257739970a04be88394d4ef0ed94848a06ee3..1b5cc8caf907c060c3edb03671218d8b1fdec3f5 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 792df4243d5fedbf3a51f4eb4ce3e60d46ed3f7b..633f39fa2219bf75840c8d4b4ceb2cac298af38d 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 4c73c26a30abe761cd47d7250ff281300400298f..09fdd42a68c9e48d6e847c00679e3e496b692b08 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 81c3856008a98bc0e7d2d6f90846eb56d47bff5a..447b9816a7c9a9c0b91bd8455ffab014c9ebf1e5 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 4228f0fd028c15c12f3cf508a575eaa6a221be40..f2ca8a23ba0c5ed69fe9cfa8fb3f22953fc74c4d 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 2f0b80d45b126c4eae1b59f53324bdf6d6058e1b..d87bfcb8fc88833ca9fa41eea282d1ab18a69f0b 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 0d172167b23df3e1be68880de4818f70fdfb9a39..231c843db39d13fd650ab9affde752fe8bd3dc77 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 3e324072565f1d68aea06ffb30f8e518d7f5524a..1ddb738dff187ec320e991ed8540de2337112336 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 3971c959d965ce98c65d26de0360dcd60bec5329..d2417a7c959eedb8548f65a3b3eda93f7637d04c 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();