utils: check the correct element's state on ghosting pads
authorMatthew Waters <matthew@centricular.com>
Mon, 4 Apr 2016 10:28:18 +0000 (10:28 +0000)
committerMatthew Waters <matthew@centricular.com>
Wed, 6 Apr 2016 13:26:41 +0000 (23:26 +1000)
Checking the current element's state when we're adding pads to
the parent element is checking the wrong thing.

Silences a 'attempting to add an inactive pad to a running element'
warning when adding a ghost pad to a running parent bin of the parent
bin of the element.

https://bugzilla.gnome.org/show_bug.cgi?id=764176

gst/gstutils.c
tests/check/gst/gstutils.c

index 9e3cbb3..05ab76b 100644 (file)
@@ -1387,20 +1387,20 @@ ghost_up (GstElement * e, GstPad * pad)
   gpad = gst_ghost_pad_new (name, pad);
   g_free (name);
 
-  GST_STATE_LOCK (e);
-  gst_element_get_state (e, &current, &next, 0);
+  GST_STATE_LOCK (parent);
+  gst_element_get_state (GST_ELEMENT (parent), &current, &next, 0);
 
-  if (current > GST_STATE_READY || next == GST_STATE_PAUSED)
+  if (current > GST_STATE_READY || next >= GST_STATE_PAUSED)
     gst_pad_set_active (gpad, TRUE);
 
   if (!gst_element_add_pad ((GstElement *) parent, gpad)) {
     g_warning ("Pad named %s already exists in element %s\n",
         GST_OBJECT_NAME (gpad), GST_OBJECT_NAME (parent));
     gst_object_unref ((GstObject *) gpad);
-    GST_STATE_UNLOCK (e);
+    GST_STATE_UNLOCK (parent);
     return NULL;
   }
-  GST_STATE_UNLOCK (e);
+  GST_STATE_UNLOCK (parent);
 
   return gpad;
 }
index 60e4d66..3a5de64 100644 (file)
@@ -1701,6 +1701,52 @@ GST_START_TEST (test_element_get_compatible_pad_request)
 
 GST_END_TEST;
 
+GST_START_TEST (test_element_link_with_ghost_pads)
+{
+  GstElement *sink_bin, *sink2_bin, *pipeline;
+  GstElement *src, *tee, *queue, *queue2, *sink, *sink2;
+  GstMessage *message;
+  GstBus *bus;
+
+  fail_unless (pipeline = gst_pipeline_new (NULL));
+  fail_unless (sink_bin = gst_bin_new (NULL));
+  fail_unless (sink2_bin = gst_bin_new (NULL));
+  fail_unless (src = gst_element_factory_make ("fakesrc", NULL));
+  fail_unless (tee = gst_element_factory_make ("tee", NULL));
+  fail_unless (queue = gst_element_factory_make ("queue", NULL));
+  fail_unless (sink = gst_element_factory_make ("fakesink", NULL));
+  fail_unless (queue2 = gst_element_factory_make ("queue", NULL));
+  fail_unless (sink2 = gst_element_factory_make ("fakesink", NULL));
+
+  gst_bin_add_many (GST_BIN (pipeline), src, tee, queue, sink, sink2_bin, NULL);
+  fail_unless (gst_element_link_many (src, tee, queue, sink, NULL));
+  fail_unless (gst_element_set_state (pipeline,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_ASYNC);
+
+  /* wait for a buffer to arrive at the sink */
+  bus = gst_element_get_bus (pipeline);
+  message = gst_bus_poll (bus, GST_MESSAGE_ASYNC_DONE, -1);
+  gst_message_unref (message);
+  gst_object_unref (bus);
+
+  gst_bin_add_many (GST_BIN (sink_bin), queue2, sink2, NULL);
+  fail_unless (gst_element_link (queue2, sink2));
+
+  gst_bin_add (GST_BIN (sink2_bin), sink_bin);
+  /* The two levels of bins with the outer bin in the running state is
+   * important, when the second ghost pad is created (from this
+   * gst_element_link()) in the running bin, we need to activate the
+   * created ghost pad */
+  fail_unless (gst_element_link (tee, queue2));
+
+  fail_unless (gst_element_set_state (pipeline,
+          GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS);
+
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
 static Suite *
 gst_utils_suite (void)
 {
@@ -1729,6 +1775,7 @@ gst_utils_suite (void)
 #endif
   tcase_add_test (tc_chain, test_element_found_tags);
   tcase_add_test (tc_chain, test_element_link);
+  tcase_add_test (tc_chain, test_element_link_with_ghost_pads);
   tcase_add_test (tc_chain, test_element_unlink);
   tcase_add_test (tc_chain, test_element_get_compatible_pad_request);
   tcase_add_test (tc_chain, test_set_value_from_string);
@@ -1739,6 +1786,7 @@ gst_utils_suite (void)
 
   tcase_add_test (tc_chain, test_read_macros);
   tcase_add_test (tc_chain, test_write_macros);
+
   return s;
 }