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();