From a1f789770d1383648031030a4b5bb19e8029a05d Mon Sep 17 00:00:00 2001 From: Evan Callaway Date: Thu, 15 Oct 2015 10:38:16 -0400 Subject: [PATCH] Add WAIT_ON_EOS flag to gstappsink. If set, an appsink that receives an EOS will wait until all of its buffers have been processed before continuing. https://bugzilla.gnome.org/show_bug.cgi?id=756187 --- gst-libs/gst/app/gstappsink.c | 81 ++++++++++++++++++++++++++++++++++- gst-libs/gst/app/gstappsink.h | 3 ++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/app/gstappsink.c b/gst-libs/gst/app/gstappsink.c index 9a7fcb418f..e5293ee3b3 100644 --- a/gst-libs/gst/app/gstappsink.c +++ b/gst-libs/gst/app/gstappsink.c @@ -79,6 +79,7 @@ struct _GstAppSinkPrivate guint num_buffers; guint max_buffers; gboolean drop; + gboolean wait_on_eos; GCond cond; GMutex mutex; @@ -119,6 +120,7 @@ enum #define DEFAULT_PROP_EMIT_SIGNALS FALSE #define DEFAULT_PROP_MAX_BUFFERS 0 #define DEFAULT_PROP_DROP FALSE +#define DEFAULT_PROP_WAIT_ON_EOS TRUE enum { @@ -128,6 +130,7 @@ enum PROP_EMIT_SIGNALS, PROP_MAX_BUFFERS, PROP_DROP, + PROP_WAIT_ON_EOS, PROP_LAST }; @@ -210,6 +213,22 @@ gst_app_sink_class_init (GstAppSinkClass * klass) "Drop old buffers when the buffer queue is filled", DEFAULT_PROP_DROP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstAppSink::wait-on-eos: + * + * Wait for all buffers to be processed after receiving an EOS. + * + * In cases where it is uncertain if an @appsink will have a consumer for its buffers + * when it receives an EOS, set to %FALSE to ensure that the @appsink will not hang. + * + * Since: 1.8 + */ + g_object_class_install_property (gobject_class, PROP_WAIT_ON_EOS, + g_param_spec_boolean ("wait-on-eos", "Wait on EOS", + "Wait for all buffers to be processed after receiving an EOS", + DEFAULT_PROP_WAIT_ON_EOS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** * GstAppSink::eos: * @appsink: the appsink element that emitted the signal @@ -359,6 +378,7 @@ gst_app_sink_init (GstAppSink * appsink) priv->emit_signals = DEFAULT_PROP_EMIT_SIGNALS; priv->max_buffers = DEFAULT_PROP_MAX_BUFFERS; priv->drop = DEFAULT_PROP_DROP; + priv->wait_on_eos = DEFAULT_PROP_WAIT_ON_EOS; } static void @@ -424,6 +444,9 @@ gst_app_sink_set_property (GObject * object, guint prop_id, case PROP_DROP: gst_app_sink_set_drop (appsink, g_value_get_boolean (value)); break; + case PROP_WAIT_ON_EOS: + gst_app_sink_set_wait_on_eos (appsink, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -459,6 +482,9 @@ gst_app_sink_get_property (GObject * object, guint prop_id, GValue * value, case PROP_DROP: g_value_set_boolean (value, gst_app_sink_get_drop (appsink)); break; + case PROP_WAIT_ON_EOS: + g_value_set_boolean (value, gst_app_sink_get_wait_on_eos (appsink)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -593,7 +619,7 @@ gst_app_sink_event (GstBaseSink * sink, GstEvent * event) * Otherwise we might signal EOS before all buffers are * consumed, which is a bit confusing for the application */ - while (priv->num_buffers > 0 && !priv->flushing) + while (priv->num_buffers > 0 && !priv->flushing && priv->wait_on_eos) g_cond_wait (&priv->cond, &priv->mutex); if (priv->flushing) emit = FALSE; @@ -1096,6 +1122,59 @@ gst_app_sink_get_drop (GstAppSink * appsink) return result; } +/** + * gst_app_sink_set_wait_on_eos: + * @appsink: a #GstAppSink + * @wait: the new state + * + * Instruct @appsink to wait for all buffers to be consumed when an EOS is received. + * + */ +void +gst_app_sink_set_wait_on_eos (GstAppSink * appsink, gboolean wait) +{ + GstAppSinkPrivate *priv; + + g_return_if_fail (GST_IS_APP_SINK (appsink)); + + priv = appsink->priv; + + g_mutex_lock (&priv->mutex); + if (priv->wait_on_eos != wait) { + priv->wait_on_eos = wait; + /* signal the change */ + g_cond_signal (&priv->cond); + } + g_mutex_unlock (&priv->mutex); +} + +/** + * gst_app_sink_get_wait_on_eos: + * @appsink: a #GstAppSink + * + * Check if @appsink will wait for all buffers to be consumed when an EOS is + * received. + * + * Returns: %TRUE if @appsink will wait for all buffers to be consumed when an + * EOS is received. + */ +gboolean +gst_app_sink_get_wait_on_eos (GstAppSink * appsink) +{ + gboolean result; + GstAppSinkPrivate *priv; + + g_return_val_if_fail (GST_IS_APP_SINK (appsink), FALSE); + + priv = appsink->priv; + + g_mutex_lock (&priv->mutex); + result = priv->wait_on_eos; + g_mutex_unlock (&priv->mutex); + + return result; +} + /** * gst_app_sink_pull_preroll: * @appsink: a #GstAppSink diff --git a/gst-libs/gst/app/gstappsink.h b/gst-libs/gst/app/gstappsink.h index 05c2b13e9c..e268b62f22 100644 --- a/gst-libs/gst/app/gstappsink.h +++ b/gst-libs/gst/app/gstappsink.h @@ -115,6 +115,9 @@ guint gst_app_sink_get_max_buffers (GstAppSink *appsink); void gst_app_sink_set_drop (GstAppSink *appsink, gboolean drop); gboolean gst_app_sink_get_drop (GstAppSink *appsink); +void gst_app_sink_set_wait_on_eos (GstAppSink *appsink, gboolean wait); +gboolean gst_app_sink_get_wait_on_eos (GstAppSink *appsink); + GstSample * gst_app_sink_pull_preroll (GstAppSink *appsink); GstSample * gst_app_sink_pull_sample (GstAppSink *appsink);