summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/plugins/gst_plugins_cache.json16
-rw-r--r--gst-libs/gst/app/gstappsink.c221
-rw-r--r--gst-libs/gst/app/gstappsink.h28
-rw-r--r--tests/check/elements/appsink.c195
4 files changed, 445 insertions, 15 deletions
diff --git a/docs/plugins/gst_plugins_cache.json b/docs/plugins/gst_plugins_cache.json
index 3cf309000..73789d37f 100644
--- a/docs/plugins/gst_plugins_cache.json
+++ b/docs/plugins/gst_plugins_cache.json
@@ -369,6 +369,11 @@
"return-type": "GstFlowReturn",
"when": "last"
},
+ "new-serialized-event": {
+ "args": [],
+ "return-type": "gboolean",
+ "when": "last"
+ },
"pull-preroll": {
"action": true,
"args": [],
@@ -381,6 +386,17 @@
"return-type": "GstSample",
"when": "last"
},
+ "try-pull-object": {
+ "action": true,
+ "args": [
+ {
+ "name": "arg0",
+ "type": "guint64"
+ }
+ ],
+ "return-type": "GstMiniObject",
+ "when": "last"
+ },
"try-pull-preroll": {
"action": true,
"args": [
diff --git a/gst-libs/gst/app/gstappsink.c b/gst-libs/gst/app/gstappsink.c
index 65822c849..16da11cea 100644
--- a/gst-libs/gst/app/gstappsink.c
+++ b/gst-libs/gst/app/gstappsink.c
@@ -113,6 +113,7 @@ struct _GstAppSinkPrivate
GstCaps *caps;
gboolean emit_signals;
guint num_buffers;
+ guint num_events;
guint max_buffers;
gboolean drop;
gboolean wait_on_eos;
@@ -146,12 +147,14 @@ enum
SIGNAL_EOS,
SIGNAL_NEW_PREROLL,
SIGNAL_NEW_SAMPLE,
+ SIGNAL_NEW_SERIALIZED_EVENT,
/* actions */
SIGNAL_PULL_PREROLL,
SIGNAL_PULL_SAMPLE,
SIGNAL_TRY_PULL_PREROLL,
SIGNAL_TRY_PULL_SAMPLE,
+ SIGNAL_TRY_PULL_OBJECT,
LAST_SIGNAL
};
@@ -333,6 +336,34 @@ gst_app_sink_class_init (GstAppSinkClass * klass)
NULL, NULL, NULL, GST_TYPE_FLOW_RETURN, 0, G_TYPE_NONE);
/**
+ * GstAppSink::new-serialized-event:
+ * @appsink: the appsink element that emitted the signal
+ *
+ * Signal that a new downstream serialized event is available.
+ *
+ * This signal is emitted from the streaming thread and only when the
+ * "emit-signals" property is %TRUE.
+ *
+ * The new event can be retrieved with the "try-pull-object" action
+ * signal or gst_app_sink_pull_object() either from this signal callback
+ * or from any other thread.
+ *
+ * EOS will not be notified using this signal, use #GstAppSink::eos instead.
+ * EOS cannot be pulled either, use gst_app_sink_is_eos() to check for it.
+ *
+ * Note that this signal is only emitted when the "emit-signals" property is
+ * set to %TRUE, which it is not by default for performance reasons.
+ *
+ * The callback should return %TRUE if the event has been handled, which will
+ * skip basesink handling of the event, %FALSE otherwise.
+ *
+ * Since: 1.20
+ */
+ gst_app_sink_signals[SIGNAL_NEW_SERIALIZED_EVENT] =
+ g_signal_new ("new-serialized-event", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_BOOLEAN, 0, G_TYPE_NONE);
+
+ /**
* GstAppSink::pull-preroll:
* @appsink: the appsink element to emit this signal on
*
@@ -386,6 +417,7 @@ gst_app_sink_class_init (GstAppSinkClass * klass)
g_signal_new ("pull-sample", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstAppSinkClass,
pull_sample), NULL, NULL, NULL, GST_TYPE_SAMPLE, 0, G_TYPE_NONE);
+
/**
* GstAppSink::try-pull-preroll:
* @appsink: the appsink element to emit this signal on
@@ -451,6 +483,44 @@ gst_app_sink_class_init (GstAppSinkClass * klass)
G_STRUCT_OFFSET (GstAppSinkClass, try_pull_sample), NULL, NULL, NULL,
GST_TYPE_SAMPLE, 1, GST_TYPE_CLOCK_TIME);
+ /**
+ * GstAppSink::try-pull-object:
+ * @appsink: the appsink element to emit this signal on
+ * @timeout: the maximum amount of time to wait for a sample
+ *
+ * This function blocks until a sample or an event becomes available or the appsink
+ * element is set to the READY/NULL state or the timeout expires.
+ *
+ * This function will only return samples when the appsink is in the PLAYING
+ * state. All rendered samples and events will be put in a queue so that the application
+ * can pull them at its own rate.
+ * Events can be pulled when the appsink is in the READY, PAUSED or PLAYING state.
+ *
+ * Note that when the application does not pull samples fast enough, the
+ * queued samples could consume a lot of memory, especially when dealing with
+ * raw video frames. It's possible to control the behaviour of the queue with
+ * the "drop" and "max-buffers" properties.
+ *
+ * This function will only pull serialized events, excluding
+ * the EOS event for which this functions returns
+ * %NULL. Use gst_app_sink_is_eos() to check for the EOS condition.
+ *
+ * This signal is a variant of #GstAppSink::try-pull-sample: that can be used
+ * to handle incoming events as well as samples.
+ *
+ * Note that future releases may extend this API to return other object types
+ * so make sure that your code is checking for the actual type it is handling.
+ *
+ * Returns: (transfer full): a #GstSample or a #GstEvent or NULL when the appsink is stopped or EOS or the timeout expires.
+ *
+ * Since: 1.20
+ */
+ gst_app_sink_signals[SIGNAL_TRY_PULL_OBJECT] =
+ g_signal_new ("try-pull-object", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GstAppSinkClass, try_pull_object), NULL, NULL, NULL,
+ GST_TYPE_MINI_OBJECT, 1, GST_TYPE_CLOCK_TIME);
+
gst_element_class_set_static_metadata (element_class, "AppSink",
"Generic/Sink", "Allow the application to get access to raw buffer",
"David Schleef <ds@schleef.org>, Wim Taymans <wim.taymans@gmail.com>");
@@ -474,6 +544,7 @@ gst_app_sink_class_init (GstAppSinkClass * klass)
klass->pull_sample = gst_app_sink_pull_sample;
klass->try_pull_preroll = gst_app_sink_try_pull_preroll;
klass->try_pull_sample = gst_app_sink_try_pull_sample;
+ klass->try_pull_object = gst_app_sink_try_pull_object;
}
static void
@@ -659,6 +730,7 @@ gst_app_sink_flush_unlocked (GstAppSink * appsink)
while ((obj = gst_queue_array_pop_head (priv->queue)))
gst_mini_object_unref (obj);
priv->num_buffers = 0;
+ priv->num_events = 0;
g_cond_signal (&priv->cond);
}
@@ -716,6 +788,7 @@ gst_app_sink_setcaps (GstBaseSink * sink, GstCaps * caps)
g_mutex_lock (&priv->mutex);
GST_DEBUG_OBJECT (appsink, "receiving CAPS");
gst_queue_array_push_tail (priv->queue, gst_event_new_caps (caps));
+ priv->num_events++;
if (!priv->preroll_buffer)
gst_caps_replace (&priv->preroll_caps, caps);
g_mutex_unlock (&priv->mutex);
@@ -729,11 +802,12 @@ gst_app_sink_event (GstBaseSink * sink, GstEvent * event)
GstAppSink *appsink = GST_APP_SINK_CAST (sink);
GstAppSinkPrivate *priv = appsink->priv;
+ GST_DEBUG_OBJECT (appsink, "%" GST_PTR_FORMAT, event);
+
switch (event->type) {
case GST_EVENT_SEGMENT:
g_mutex_lock (&priv->mutex);
GST_DEBUG_OBJECT (appsink, "receiving SEGMENT");
- gst_queue_array_push_tail (priv->queue, gst_event_ref (event));
if (!priv->preroll_buffer)
gst_event_copy_segment (event, &priv->preroll_segment);
g_mutex_unlock (&priv->mutex);
@@ -805,6 +879,40 @@ gst_app_sink_event (GstBaseSink * sink, GstEvent * event)
default:
break;
}
+
+ if (GST_EVENT_TYPE (event) != GST_EVENT_EOS
+ && GST_EVENT_IS_SERIALIZED (event)) {
+ gboolean emit;
+ Callbacks *callbacks = NULL;
+ gboolean ret;
+
+ g_mutex_lock (&priv->mutex);
+
+ emit = priv->emit_signals;
+ if (priv->callbacks)
+ callbacks = callbacks_ref (priv->callbacks);
+
+ gst_queue_array_push_tail (priv->queue, gst_event_ref (event));
+ priv->num_events++;
+
+ g_mutex_unlock (&priv->mutex);
+
+ if (callbacks && callbacks->callbacks.new_event) {
+ ret = callbacks->callbacks.new_event (appsink, callbacks->user_data);
+ } else {
+ ret = FALSE;
+ if (emit)
+ g_signal_emit (appsink,
+ gst_app_sink_signals[SIGNAL_NEW_SERIALIZED_EVENT], 0, &ret);
+ }
+ g_clear_pointer (&callbacks, callbacks_unref);
+
+ if (ret) {
+ gst_event_unref (event);
+ return TRUE;
+ }
+ }
+
return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
}
@@ -867,6 +975,8 @@ dequeue_object (GstAppSink * appsink)
} else if (GST_IS_EVENT (obj)) {
GstEvent *event = GST_EVENT_CAST (obj);
+ priv->num_events--;
+
switch (GST_EVENT_TYPE (obj)) {
case GST_EVENT_CAPS:
{
@@ -1548,6 +1658,41 @@ gst_app_sink_pull_sample (GstAppSink * appsink)
}
/**
+ * gst_app_sink_pull_object: (skip)
+ * @appsink: a #GstAppSink
+ *
+ * This function blocks until a sample or an event becomes available or the appsink
+ * element is set to the READY/NULL state.
+ *
+ * This function will only return samples when the appsink is in the PLAYING
+ * state. All rendered buffers and events will be put in a queue so that the application
+ * can pull them at its own rate. Note that when the application does not
+ * pull samples fast enough, the queued buffers could consume a lot of memory,
+ * especially when dealing with raw video frames.
+ * Events can be pulled when the appsink is in the READY, PAUSED or PLAYING state.
+ *
+ * This function will only pull serialized events, excluding
+ * the EOS event for which this functions returns
+ * %NULL. Use gst_app_sink_is_eos() to check for the EOS condition.
+ *
+ * This method is a variant of gst_app_sink_pull_sample() that can be used
+ * to handle incoming events events as well as samples.
+ *
+ * Note that future releases may extend this API to return other object types
+ * so make sure that your code is checking for the actual type it is handling.
+ *
+ * Returns: (transfer full): a #GstSample, or a #GstEvent or NULL when the appsink is stopped or EOS.
+ * Call gst_mini_object_unref() after usage.
+ *
+ * Since: 1.20
+ */
+GstMiniObject *
+gst_app_sink_pull_object (GstAppSink * appsink)
+{
+ return gst_app_sink_try_pull_object (appsink, GST_CLOCK_TIME_NONE);
+}
+
+/**
* gst_app_sink_try_pull_preroll:
* @appsink: a #GstAppSink
* @timeout: the maximum amount of time to wait for the preroll sample
@@ -1676,9 +1821,56 @@ not_started:
GstSample *
gst_app_sink_try_pull_sample (GstAppSink * appsink, GstClockTime timeout)
{
+ while (TRUE) {
+ GstMiniObject *obj;
+
+ obj = gst_app_sink_try_pull_object (appsink, timeout);
+
+ if (!obj) {
+ return NULL;
+ } else if (GST_IS_SAMPLE (obj)) {
+ return GST_SAMPLE_CAST (obj);
+ } else {
+ gst_mini_object_unref (obj);
+ }
+ }
+}
+
+/**
+ * gst_app_sink_try_pull_object: (skip)
+ * @appsink: a #GstAppSink
+ * @timeout: the maximum amount of time to wait for a sample
+ *
+ * This function blocks until a sample or an event or EOS becomes available or the appsink
+ * element is set to the READY/NULL state or the timeout expires.
+ *
+ * This function will only return samples when the appsink is in the PLAYING
+ * state. All rendered buffers and events will be put in a queue so that the application
+ * can pull them at its own rate. Note that when the application does not
+ * pull samples fast enough, the queued buffers could consume a lot of memory,
+ * especially when dealing with raw video frames.
+ * Events can be pulled when the appsink is in the READY, PAUSED or PLAYING state.
+ *
+ * This function will only pull serialized events, excluding
+ * the EOS event for which this functions returns
+ * %NULL. Use gst_app_sink_is_eos() to check for the EOS condition.
+ *
+ * This method is a variant of gst_app_sink_try_pull_sample() that can be used
+ * to handle incoming events events as well as samples.
+ *
+ * Note that future releases may extend this API to return other object types
+ * so make sure that your code is checking for the actual type it is handling.
+ *
+ * Returns: (transfer full): a #GstSample, or #GstEvent or NULL when the appsink is stopped or EOS or the timeout expires.
+ * Call gst_mini_object_unref() after usage.
+ *
+ * Since: 1.20
+ */
+GstMiniObject *
+gst_app_sink_try_pull_object (GstAppSink * appsink, GstClockTime timeout)
+{
GstAppSinkPrivate *priv;
- GstSample *sample = NULL;
- GstMiniObject *obj;
+ GstMiniObject *obj = NULL, *ret;
gboolean timeout_valid;
gint64 end_time;
@@ -1696,18 +1888,18 @@ gst_app_sink_try_pull_sample (GstAppSink * appsink, GstClockTime timeout)
gst_buffer_replace (&priv->preroll_buffer, NULL);
while (TRUE) {
- GST_DEBUG_OBJECT (appsink, "trying to grab a buffer");
+ GST_DEBUG_OBJECT (appsink, "trying to grab an object");
if (!priv->started)
goto not_started;
- if (priv->num_buffers > 0)
+ if (priv->num_buffers > 0 || priv->num_events > 0)
break;
if (priv->is_eos)
goto eos;
/* nothing to return, wait */
- GST_DEBUG_OBJECT (appsink, "waiting for a buffer");
+ GST_DEBUG_OBJECT (appsink, "waiting for an object");
priv->wait_status |= APP_WAITING;
if (timeout_valid) {
if (!g_cond_wait_until (&priv->cond, &priv->mutex, end_time))
@@ -1718,28 +1910,33 @@ gst_app_sink_try_pull_sample (GstAppSink * appsink, GstClockTime timeout)
priv->wait_status &= ~APP_WAITING;
}
- obj = dequeue_buffer (appsink);
+ obj = dequeue_object (appsink);
+
+ /* convert buffer and buffer list to sample */
if (GST_IS_BUFFER (obj)) {
GST_DEBUG_OBJECT (appsink, "we have a buffer %p", obj);
priv->sample = gst_sample_make_writable (priv->sample);
gst_sample_set_buffer_list (priv->sample, NULL);
gst_sample_set_buffer (priv->sample, GST_BUFFER_CAST (obj));
- sample = gst_sample_ref (priv->sample);
- } else {
+ ret = GST_MINI_OBJECT_CAST (gst_sample_ref (priv->sample));
+ gst_mini_object_unref (obj);
+ } else if (GST_IS_BUFFER_LIST (obj)) {
GST_DEBUG_OBJECT (appsink, "we have a list %p", obj);
priv->sample = gst_sample_make_writable (priv->sample);
gst_sample_set_buffer (priv->sample, NULL);
gst_sample_set_buffer_list (priv->sample, GST_BUFFER_LIST_CAST (obj));
- sample = gst_sample_ref (priv->sample);
+ ret = GST_MINI_OBJECT_CAST (gst_sample_ref (priv->sample));
+ gst_mini_object_unref (obj);
+ } else {
+ ret = obj;
}
- gst_mini_object_unref (obj);
if ((priv->wait_status & STREAM_WAITING))
g_cond_signal (&priv->cond);
g_mutex_unlock (&priv->mutex);
- return sample;
+ return ret;
/* special conditions */
expired:
diff --git a/gst-libs/gst/app/gstappsink.h b/gst-libs/gst/app/gstappsink.h
index 036b86e50..90e678f53 100644
--- a/gst-libs/gst/app/gstappsink.h
+++ b/gst-libs/gst/app/gstappsink.h
@@ -59,6 +59,14 @@ typedef struct _GstAppSinkPrivate GstAppSinkPrivate;
* The new sample can be retrieved with
* gst_app_sink_pull_sample() either from this callback
* or from any other thread.
+ * @new_event: Called when a new event is available.
+ * This callback is called from the streaming thread.
+ * The new event can be retrieved with
+ * gst_app_sink_pull_event() either from this callback
+ * or from any other thread.
+ * The callback should return %TRUE if the event has been handled,
+ * %FALSE otherwise.
+ * Since: 1.20
*
* A set of callbacks that can be installed on the appsink with
* gst_app_sink_set_callbacks().
@@ -67,9 +75,10 @@ typedef struct {
void (*eos) (GstAppSink *appsink, gpointer user_data);
GstFlowReturn (*new_preroll) (GstAppSink *appsink, gpointer user_data);
GstFlowReturn (*new_sample) (GstAppSink *appsink, gpointer user_data);
+ gboolean (*new_event) (GstAppSink *appsink, gpointer user_data);
/*< private >*/
- gpointer _gst_reserved[GST_PADDING];
+ gpointer _gst_reserved[GST_PADDING - 1];
} GstAppSinkCallbacks;
struct _GstAppSink
@@ -91,15 +100,24 @@ struct _GstAppSinkClass
void (*eos) (GstAppSink *appsink);
GstFlowReturn (*new_preroll) (GstAppSink *appsink);
GstFlowReturn (*new_sample) (GstAppSink *appsink);
+ /* new_event is missing as we ran out padding */
/* actions */
GstSample * (*pull_preroll) (GstAppSink *appsink);
GstSample * (*pull_sample) (GstAppSink *appsink);
GstSample * (*try_pull_preroll) (GstAppSink *appsink, GstClockTime timeout);
GstSample * (*try_pull_sample) (GstAppSink *appsink, GstClockTime timeout);
+ /**
+ * GstAppSinkClass::try_pull_object:
+ *
+ * See #GstAppSink::try-pull-object: signal.
+ *
+ * Since: 1.20
+ */
+ GstMiniObject * (*try_pull_object) (GstAppSink *appsink, GstClockTime timeout);
/*< private >*/
- gpointer _gst_reserved[GST_PADDING - 2];
+ gpointer _gst_reserved[GST_PADDING - 3];
};
GST_APP_API
@@ -151,12 +169,18 @@ GST_APP_API
GstSample * gst_app_sink_pull_sample (GstAppSink *appsink);
GST_APP_API
+GstMiniObject * gst_app_sink_pull_object (GstAppSink *appsink);
+
+GST_APP_API
GstSample * gst_app_sink_try_pull_preroll (GstAppSink *appsink, GstClockTime timeout);
GST_APP_API
GstSample * gst_app_sink_try_pull_sample (GstAppSink *appsink, GstClockTime timeout);
GST_APP_API
+GstMiniObject * gst_app_sink_try_pull_object (GstAppSink *appsink, GstClockTime timeout);
+
+GST_APP_API
void gst_app_sink_set_callbacks (GstAppSink * appsink,
GstAppSinkCallbacks *callbacks,
gpointer user_data,
diff --git a/tests/check/elements/appsink.c b/tests/check/elements/appsink.c
index 9acbdcb9b..d5e62ac4b 100644
--- a/tests/check/elements/appsink.c
+++ b/tests/check/elements/appsink.c
@@ -714,6 +714,197 @@ GST_START_TEST (test_pull_sample_refcounts)
GST_END_TEST;
+static gboolean
+new_event_cb (GstAppSink * appsink, gpointer callback_data)
+{
+ guint *new_event_count = callback_data;
+ *new_event_count += 1;
+ return TRUE;
+}
+
+/* Verifies that the event callback is called */
+GST_START_TEST (test_event_callback)
+{
+ GstElement *sink;
+ GstPad *sinkpad;
+ GstBuffer *buffer;
+ guint new_event_count;
+ GstAppSinkCallbacks callbacks = { NULL };
+ GstMiniObject *object;
+ GstAppSink *app_sink;
+
+ sink = setup_appsink ();
+ app_sink = GST_APP_SINK (sink);
+
+ callbacks.new_event = new_event_cb;
+
+ gst_app_sink_set_callbacks (app_sink, &callbacks, &new_event_count, NULL);
+
+ ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
+
+ /* push a buffer so pending events are pushed */
+ buffer = gst_buffer_new_and_alloc (4);
+ fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+
+ /* flush pending events from the queue */
+ while ((object = gst_app_sink_try_pull_object (app_sink, 0)))
+ gst_mini_object_unref (object);
+ new_event_count = 0;
+
+ /* push a buffer */
+ buffer = gst_buffer_new_and_alloc (4);
+ fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+
+ /* push custom event */
+ sinkpad = gst_element_get_static_pad (sink, "sink");
+ fail_unless (sinkpad);
+ fail_unless (gst_pad_send_event (sinkpad,
+ gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
+ gst_structure_new ("custom", NULL, NULL))));
+ fail_unless_equals_int (new_event_count, 1);
+ gst_object_unref (sinkpad);
+
+ /* push a second buffer */
+ buffer = gst_buffer_new_and_alloc (4);
+ fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+
+ /* check if the samples and events are pulled in the right order */
+ object = gst_app_sink_pull_object (app_sink);
+ fail_unless (GST_IS_SAMPLE (object));
+ gst_mini_object_unref (object);
+
+ object = gst_app_sink_pull_object (app_sink);
+ fail_unless (GST_IS_EVENT (object));
+ fail_unless_equals_int (GST_EVENT_TYPE (object), GST_EVENT_CUSTOM_DOWNSTREAM);
+ gst_mini_object_unref (object);
+
+ object = gst_app_sink_pull_object (app_sink);
+ fail_unless (GST_IS_SAMPLE (object));
+ gst_mini_object_unref (object);
+
+ GST_DEBUG ("cleaning up appsink");
+ ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
+ cleanup_appsink (sink);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_event_signals)
+{
+ GstElement *sink;
+ GstPad *sinkpad;
+ GstBuffer *buffer;
+ GstMiniObject *object;
+ GstAppSink *app_sink;
+ guint new_event_count = 0;
+
+ sink = setup_appsink ();
+ app_sink = GST_APP_SINK (sink);
+
+ g_object_set (sink, "emit-signals", TRUE, NULL);
+
+ g_signal_connect (sink, "new-serialized-event", G_CALLBACK (new_event_cb),
+ &new_event_count);
+
+ ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
+
+ /* push a buffer so pending events are pushed */
+ buffer = gst_buffer_new_and_alloc (4);
+ fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+
+ /* flush pending events from the queue */
+ while ((object = gst_app_sink_try_pull_object (app_sink, 0)))
+ gst_mini_object_unref (object);
+ new_event_count = 0;
+
+ /* push a buffer */
+ buffer = gst_buffer_new_and_alloc (4);
+ fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+
+ /* push custom event */
+ sinkpad = gst_element_get_static_pad (sink, "sink");
+ fail_unless (sinkpad);
+ fail_unless (gst_pad_send_event (sinkpad,
+ gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
+ gst_structure_new ("custom", NULL, NULL))));
+ fail_unless_equals_int (new_event_count, 1);
+ gst_object_unref (sinkpad);
+
+ /* push a second buffer */
+ buffer = gst_buffer_new_and_alloc (4);
+ fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+
+ /* check if the buffers and events are pulled in the right order */
+ g_signal_emit_by_name (sink, "try-pull-object", GST_CLOCK_TIME_NONE, &object);
+ fail_unless (GST_IS_SAMPLE (object));
+ gst_mini_object_unref (object);
+
+ g_signal_emit_by_name (sink, "try-pull-object", GST_CLOCK_TIME_NONE, &object);
+ fail_unless (GST_IS_EVENT (object));
+ fail_unless_equals_int (GST_EVENT_TYPE (object), GST_EVENT_CUSTOM_DOWNSTREAM);
+ gst_mini_object_unref (object);
+
+ g_signal_emit_by_name (sink, "try-pull-object", GST_CLOCK_TIME_NONE, &object);
+ fail_unless (GST_IS_SAMPLE (object));
+ gst_mini_object_unref (object);
+
+ GST_DEBUG ("cleaning up appsink");
+ ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
+ cleanup_appsink (sink);
+
+}
+
+GST_END_TEST;
+
+/* try pulling events when appsink is in PAUSED */
+GST_START_TEST (test_event_paused)
+{
+ GstElement *sink;
+ guint new_event_count = 0;
+ GstAppSinkCallbacks callbacks = { NULL };
+ GstMiniObject *object;
+ GstAppSink *app_sink;
+ GstCaps *caps;
+
+ sink = setup_appsink ();
+ app_sink = GST_APP_SINK (sink);
+
+ callbacks.new_event = new_event_cb;
+
+ gst_app_sink_set_callbacks (app_sink, &callbacks, &new_event_count, NULL);
+
+ ASSERT_SET_STATE (sink, GST_STATE_PAUSED, GST_STATE_CHANGE_ASYNC);
+
+ /* push a couple of events while in PAUSED */
+ gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test"));
+ caps = gst_caps_new_simple ("audio/x-raw", NULL, NULL);
+ gst_pad_push_event (mysrcpad, gst_event_new_caps (caps));
+ gst_caps_unref (caps);
+
+ fail_unless_equals_int (new_event_count, 2);
+
+ /* check pulled events */
+ object = gst_app_sink_pull_object (app_sink);
+ fail_unless (GST_IS_EVENT (object));
+ fail_unless_equals_int (GST_EVENT_TYPE (object), GST_EVENT_STREAM_START);
+ gst_mini_object_unref (object);
+
+ object = gst_app_sink_pull_object (app_sink);
+ fail_unless (GST_IS_EVENT (object));
+ fail_unless_equals_int (GST_EVENT_TYPE (object), GST_EVENT_CAPS);
+ gst_mini_object_unref (object);
+
+ object = gst_app_sink_try_pull_object (app_sink, 0);
+ fail_if (object);
+
+ GST_DEBUG ("cleaning up appsink");
+ ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
+ cleanup_appsink (sink);
+}
+
+GST_END_TEST;
+
static Suite *
appsink_suite (void)
{
@@ -735,7 +926,9 @@ appsink_suite (void)
tcase_add_test (tc_chain, test_pull_preroll);
tcase_add_test (tc_chain, test_do_not_care_preroll);
tcase_add_test (tc_chain, test_pull_sample_refcounts);
-
+ tcase_add_test (tc_chain, test_event_callback);
+ tcase_add_test (tc_chain, test_event_signals);
+ tcase_add_test (tc_chain, test_event_paused);
return s;
}