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
This commit is contained in:
Evan Callaway 2015-10-15 10:38:16 -04:00 committed by Sebastian Dröge
parent 761142e15a
commit a1f789770d
2 changed files with 83 additions and 1 deletions

View file

@ -79,6 +79,7 @@ struct _GstAppSinkPrivate
guint num_buffers; guint num_buffers;
guint max_buffers; guint max_buffers;
gboolean drop; gboolean drop;
gboolean wait_on_eos;
GCond cond; GCond cond;
GMutex mutex; GMutex mutex;
@ -119,6 +120,7 @@ enum
#define DEFAULT_PROP_EMIT_SIGNALS FALSE #define DEFAULT_PROP_EMIT_SIGNALS FALSE
#define DEFAULT_PROP_MAX_BUFFERS 0 #define DEFAULT_PROP_MAX_BUFFERS 0
#define DEFAULT_PROP_DROP FALSE #define DEFAULT_PROP_DROP FALSE
#define DEFAULT_PROP_WAIT_ON_EOS TRUE
enum enum
{ {
@ -128,6 +130,7 @@ enum
PROP_EMIT_SIGNALS, PROP_EMIT_SIGNALS,
PROP_MAX_BUFFERS, PROP_MAX_BUFFERS,
PROP_DROP, PROP_DROP,
PROP_WAIT_ON_EOS,
PROP_LAST 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, "Drop old buffers when the buffer queue is filled", DEFAULT_PROP_DROP,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 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: * GstAppSink::eos:
* @appsink: the appsink element that emitted the signal * @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->emit_signals = DEFAULT_PROP_EMIT_SIGNALS;
priv->max_buffers = DEFAULT_PROP_MAX_BUFFERS; priv->max_buffers = DEFAULT_PROP_MAX_BUFFERS;
priv->drop = DEFAULT_PROP_DROP; priv->drop = DEFAULT_PROP_DROP;
priv->wait_on_eos = DEFAULT_PROP_WAIT_ON_EOS;
} }
static void static void
@ -424,6 +444,9 @@ gst_app_sink_set_property (GObject * object, guint prop_id,
case PROP_DROP: case PROP_DROP:
gst_app_sink_set_drop (appsink, g_value_get_boolean (value)); gst_app_sink_set_drop (appsink, g_value_get_boolean (value));
break; break;
case PROP_WAIT_ON_EOS:
gst_app_sink_set_wait_on_eos (appsink, g_value_get_boolean (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -459,6 +482,9 @@ gst_app_sink_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_DROP: case PROP_DROP:
g_value_set_boolean (value, gst_app_sink_get_drop (appsink)); g_value_set_boolean (value, gst_app_sink_get_drop (appsink));
break; break;
case PROP_WAIT_ON_EOS:
g_value_set_boolean (value, gst_app_sink_get_wait_on_eos (appsink));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -593,7 +619,7 @@ gst_app_sink_event (GstBaseSink * sink, GstEvent * event)
* Otherwise we might signal EOS before all buffers are * Otherwise we might signal EOS before all buffers are
* consumed, which is a bit confusing for the application * 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); g_cond_wait (&priv->cond, &priv->mutex);
if (priv->flushing) if (priv->flushing)
emit = FALSE; emit = FALSE;
@ -1096,6 +1122,59 @@ gst_app_sink_get_drop (GstAppSink * appsink)
return result; 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: * gst_app_sink_pull_preroll:
* @appsink: a #GstAppSink * @appsink: a #GstAppSink

View file

@ -115,6 +115,9 @@ guint gst_app_sink_get_max_buffers (GstAppSink *appsink);
void gst_app_sink_set_drop (GstAppSink *appsink, gboolean drop); void gst_app_sink_set_drop (GstAppSink *appsink, gboolean drop);
gboolean gst_app_sink_get_drop (GstAppSink *appsink); 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_preroll (GstAppSink *appsink);
GstSample * gst_app_sink_pull_sample (GstAppSink *appsink); GstSample * gst_app_sink_pull_sample (GstAppSink *appsink);