summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@theqtcompany.com>2015-03-24 17:32:28 +0100
committerYoann Lopes <yoann.lopes@theqtcompany.com>2015-05-27 12:18:50 +0000
commit8143aff1b293501f2ea37b98affbadd936e55f9b (patch)
tree2481ecdfe0c09db729484d55c956b7cbc9c1b409
parent83d1255080ab2be678efbbc42e259c9681619619 (diff)
downloadqtmultimedia-8143aff1b293501f2ea37b98affbadd936e55f9b.tar.gz
GStreamer: flush the current frame when stopping a media player.
When stopping, we don't actually stop the GStreamer pipeline, we just pause it and prevent preroll frames from being shown. We also need to make sure the last presented frame is cleared in that case, otherwise it stays on screen. Fixed for both 0.10 and 1.0. Change-Id: Ibe26a7567f271ae0c3d8819eb9d35d6a95da1c6a Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
-rw-r--r--src/gsttools/qgstvideorenderersink.cpp47
-rw-r--r--src/gsttools/qvideosurfacegstsink.cpp62
-rw-r--r--src/multimedia/gsttools_headers/qgstvideorenderersink_p.h4
-rw-r--r--src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h5
4 files changed, 110 insertions, 8 deletions
diff --git a/src/gsttools/qgstvideorenderersink.cpp b/src/gsttools/qgstvideorenderersink.cpp
index 615348c14..31ac94e86 100644
--- a/src/gsttools/qgstvideorenderersink.cpp
+++ b/src/gsttools/qgstvideorenderersink.cpp
@@ -222,6 +222,17 @@ bool QVideoSurfaceGstDelegate::proposeAllocation(GstQuery *query)
}
}
+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);
@@ -388,6 +399,8 @@ QGstVideoRendererSink *QGstVideoRendererSink::createSink(QAbstractVideoSurface *
sink->delegate = new QVideoSurfaceGstDelegate(surface);
+ g_signal_connect(G_OBJECT(sink), "notify::show-preroll-frame", G_CALLBACK(handleShowPrerollChange), sink);
+
return sink;
}
@@ -472,13 +485,41 @@ void QGstVideoRendererSink::finalize(GObject *object)
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, NULL);
+
+ if (!showPrerollFrame) {
+ GstState state = GST_STATE_VOID_PENDING;
+ gst_element_get_state(GST_ELEMENT(sink), &state, NULL, 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 QGstVideoRendererSink::change_state(
GstElement *element, GstStateChange transition)
{
- Q_UNUSED(element);
+ 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, NULL);
+
+ // 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);
+ return GST_ELEMENT_CLASS(sink_parent_class)->change_state(element, transition);
}
GstCaps *QGstVideoRendererSink::get_caps(GstBaseSink *base, GstCaps *filter)
diff --git a/src/gsttools/qvideosurfacegstsink.cpp b/src/gsttools/qvideosurfacegstsink.cpp
index 4a786ea16..737bc648d 100644
--- a/src/gsttools/qvideosurfacegstsink.cpp
+++ b/src/gsttools/qvideosurfacegstsink.cpp
@@ -184,6 +184,21 @@ void QVideoSurfaceGstDelegate::clearPoolBuffers()
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) {
@@ -244,6 +259,14 @@ void QVideoSurfaceGstDelegate::queuedStop()
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);
@@ -316,6 +339,8 @@ QVideoSurfaceGstSink *QVideoSurfaceGstSink::createSink(QAbstractVideoSurface *su
sink->delegate = new QVideoSurfaceGstDelegate(surface);
+ g_signal_connect(G_OBJECT(sink), "notify::show-preroll-frame", G_CALLBACK(handleShowPrerollChange), sink);
+
return sink;
}
@@ -420,13 +445,40 @@ void QVideoSurfaceGstSink::finalize(GObject *object)
G_OBJECT_CLASS(sink_parent_class)->finalize(object);
}
-GstStateChangeReturn QVideoSurfaceGstSink::change_state(
- GstElement *element, GstStateChange transition)
+void QVideoSurfaceGstSink::handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d)
{
- Q_UNUSED(element);
+ 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, NULL);
+
+ if (!showPrerollFrame) {
+ GstState state = GST_STATE_VOID_PENDING;
+ gst_element_get_state(GST_ELEMENT(sink), &state, NULL, 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, NULL);
+
+ // 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);
+ return GST_ELEMENT_CLASS(sink_parent_class)->change_state(element, transition);
}
GstCaps *QVideoSurfaceGstSink::get_caps(GstBaseSink *base)
diff --git a/src/multimedia/gsttools_headers/qgstvideorenderersink_p.h b/src/multimedia/gsttools_headers/qgstvideorenderersink_p.h
index 186708872..78bdf8cb8 100644
--- a/src/multimedia/gsttools_headers/qgstvideorenderersink_p.h
+++ b/src/multimedia/gsttools_headers/qgstvideorenderersink_p.h
@@ -99,6 +99,8 @@ public:
void unlock();
bool proposeAllocation(GstQuery *query);
+ void flush();
+
GstFlowReturn render(GstBuffer *buffer);
bool event(QEvent *event);
@@ -145,6 +147,8 @@ private:
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);
diff --git a/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h b/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h
index e8f61afe0..a1ef5616b 100644
--- a/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h
+++ b/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h
@@ -96,11 +96,14 @@ public:
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();
@@ -139,6 +142,8 @@ private:
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);