summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicola Murino <nicola.murino@gmail.com>2013-03-12 10:50:48 +0100
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2013-03-12 11:20:25 +0100
commitf97c9d5213f14f12dc056b9eaa2253325bc3a18c (patch)
treecb975f6b9c52ed270760b8c2a94e1301487d4a75
parent99a09678f5978f30a021044fefbc50f8048ad890 (diff)
downloadgstreamer-plugins-base-f97c9d5213f14f12dc056b9eaa2253325bc3a18c.tar.gz
appsrc: fix deadlock setting pipeline in NULL state with block=true
-rw-r--r--gst-libs/gst/app/gstappsrc.c1
-rw-r--r--tests/check/elements/appsrc.c152
2 files changed, 153 insertions, 0 deletions
diff --git a/gst-libs/gst/app/gstappsrc.c b/gst-libs/gst/app/gstappsrc.c
index 2db8b1853..e74a3a320 100644
--- a/gst-libs/gst/app/gstappsrc.c
+++ b/gst-libs/gst/app/gstappsrc.c
@@ -752,6 +752,7 @@ gst_app_src_stop (GstBaseSrc * bsrc)
priv->flushing = TRUE;
priv->started = FALSE;
gst_app_src_flush_queued (appsrc);
+ g_cond_broadcast (priv->cond);
g_mutex_unlock (priv->mutex);
return TRUE;
diff --git a/tests/check/elements/appsrc.c b/tests/check/elements/appsrc.c
index b888f4802..ceb3ecaf8 100644
--- a/tests/check/elements/appsrc.c
+++ b/tests/check/elements/appsrc.c
@@ -20,6 +20,7 @@
#include <gst/check/gstcheck.h>
#include <gst/app/gstappsrc.h>
+#include <gst/app/gstappsink.h>
#define SAMPLE_CAPS "application/x-gst-check-test"
@@ -170,6 +171,155 @@ GST_START_TEST (test_appsrc_non_null_caps)
GST_END_TEST;
+static GstAppSinkCallbacks app_callbacks;
+
+typedef struct
+{
+ GMainLoop *loop;
+ GstElement *source;
+ GstElement *sink;
+} ProgramData;
+
+static GstFlowReturn
+on_new_buffer_from_source (GstAppSink * elt, gpointer user_data)
+{
+ ProgramData *data = (ProgramData *) user_data;
+ GstBuffer *buffer;
+ GstElement *source;
+
+ buffer = gst_app_sink_pull_buffer (GST_APP_SINK (elt));
+ source = gst_bin_get_by_name (GST_BIN (data->sink), "testsource");
+ gst_app_src_push_buffer (GST_APP_SRC (source), gst_buffer_ref (buffer));
+ g_object_unref (source);
+ return GST_FLOW_OK;
+}
+
+/* called when we get a GstMessage from the source pipeline when we get EOS, we
+ * notify the appsrc of it. */
+static gboolean
+on_source_message (GstBus * bus, GstMessage * message, ProgramData * data)
+{
+ GstElement *source;
+
+ switch (GST_MESSAGE_TYPE (message)) {
+ case GST_MESSAGE_EOS:
+ source = gst_bin_get_by_name (GST_BIN (data->sink), "testsource");
+ fail_unless (gst_app_src_end_of_stream (GST_APP_SRC (source)) ==
+ GST_FLOW_OK);
+ break;
+ case GST_MESSAGE_ERROR:
+ g_main_loop_quit (data->loop);
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+static gboolean
+on_sink_message (GstBus * bus, GstMessage * message, ProgramData * data)
+{
+ switch (GST_MESSAGE_TYPE (message)) {
+ case GST_MESSAGE_EOS:
+ g_main_loop_quit (data->loop);
+ break;
+ case GST_MESSAGE_ERROR:
+ ASSERT_SET_STATE (data->sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
+ ASSERT_SET_STATE (data->source, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
+ g_main_loop_quit (data->loop);
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+static gboolean
+error_timeout (ProgramData * data)
+{
+ GstBus *bus;
+ bus = gst_element_get_bus (data->sink);
+ gst_bus_post (bus, gst_message_new_error (GST_OBJECT (data->sink), NULL,
+ "test error"));
+ gst_object_unref (bus);
+ return FALSE;
+}
+
+/*
+ * appsink => appsrc pipelines executed 100 times:
+ * - appsink pipeline has sync=false
+ * - appsrc pipeline has sync=true
+ * - appsrc has block=true
+ * after 1 second an error message is posted on appsink pipeline bus
+ * when the error is received the appsrc pipeline is set to NULL
+ * and then the appsink pipeline is
+ * set to NULL too, this must not deadlock
+ */
+
+GST_START_TEST (test_appsrc_block_deadlock)
+{
+ int i = 0;
+ int num_iteration = 100;
+ while (i < num_iteration) {
+ ProgramData *data = NULL;
+ GstBus *bus = NULL;
+ GstElement *testsink = NULL;
+
+ gint tout;
+
+ data = g_new0 (ProgramData, 1);
+
+ data->loop = g_main_loop_new (NULL, FALSE);
+
+ data->source =
+ gst_parse_launch ("videotestsrc ! appsink sync=false name=testsink",
+ NULL);
+
+ fail_unless (data->source != NULL);
+
+ bus = gst_element_get_bus (data->source);
+ gst_bus_add_watch (bus, (GstBusFunc) on_source_message, data);
+ gst_object_unref (bus);
+
+ app_callbacks.new_buffer = on_new_buffer_from_source;
+ testsink = gst_bin_get_by_name (GST_BIN (data->source), "testsink");
+ gst_app_sink_set_callbacks (GST_APP_SINK_CAST (testsink), &app_callbacks,
+ data, NULL);
+
+ gst_object_unref (testsink);
+
+ data->sink =
+ gst_parse_launch
+ ("appsrc name=testsource block=1 max-bytes=1000 is-live=true ! fakesink sync=true",
+ NULL);
+
+ fail_unless (data->sink != NULL);
+
+ bus = gst_element_get_bus (data->sink);
+ gst_bus_add_watch (bus, (GstBusFunc) on_sink_message, data);
+ gst_object_unref (bus);
+
+ tout = g_timeout_add (150, (GSourceFunc) error_timeout, data);
+
+ ASSERT_SET_STATE (data->sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
+ ASSERT_SET_STATE (data->source, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
+
+ g_main_loop_run (data->loop);
+
+ ASSERT_SET_STATE (data->sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
+ ASSERT_SET_STATE (data->source, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
+
+ g_source_remove (tout);
+ gst_object_unref (data->source);
+ gst_object_unref (data->sink);
+ g_main_loop_unref (data->loop);
+ g_free (data);
+ i++;
+ g_print ("appsrc deadlock test iteration number %d/%d\n", i, num_iteration);
+ }
+}
+
+GST_END_TEST;
static Suite *
appsrc_suite (void)
@@ -179,7 +329,9 @@ appsrc_suite (void)
tcase_add_test (tc_chain, test_appsrc_null_caps);
tcase_add_test (tc_chain, test_appsrc_non_null_caps);
+ tcase_add_test (tc_chain, test_appsrc_block_deadlock);
+ tcase_set_timeout (tc_chain, 20);
suite_add_tcase (s, tc_chain);
return s;