gst/base/gstbasetransform.c: Debug changes.
authorAndy Wingo <wingo@pobox.com>
Wed, 17 Aug 2005 16:33:27 +0000 (16:33 +0000)
committerAndy Wingo <wingo@pobox.com>
Wed, 17 Aug 2005 16:33:27 +0000 (16:33 +0000)
Original commit message from CVS:
2005-08-17  Andy Wingo  <wingo@pobox.com>

* gst/base/gstbasetransform.c: Debug changes.

* gst/gstutils.h:
* gst/gstutils.c (gst_bin_watch_for_state_change): Add function to
ensure bins post state change messages. A bit of a hack but I can't
think of a way to avoid it.

* check/gst/gstbin.c (test_watch_for_state_change): Added test.

ChangeLog
check/gst/gstbin.c
gst/base/gstbasetransform.c
gst/gstbin.c
gst/gstutils.c
gst/gstutils.h
libs/gst/base/gstbasetransform.c
tests/check/gst/gstbin.c

index 70f6ed7..00661f3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2005-08-17  Andy Wingo  <wingo@pobox.com>
+
+       * gst/base/gstbasetransform.c: Debug changes.
+
+       * gst/gstutils.h:
+       * gst/gstutils.c (gst_bin_watch_for_state_change): Add function to
+       ensure bins post state change messages. A bit of a hack but I can't
+       think of a way to avoid it.
+
+       * check/gst/gstbin.c (test_watch_for_state_change): Added test.
+
 2005-08-16  Andy Wingo  <wingo@pobox.com>
 
        * gst/base/gstadapter.h:
index 0fe0814..bf41dc0 100644 (file)
@@ -270,6 +270,68 @@ GST_START_TEST (test_message_state_changed_children)
 
 GST_END_TEST;
 
+GST_START_TEST (test_watch_for_state_change)
+{
+  GstElement *src, *sink, *bin;
+  GstBus *bus;
+
+  bin = gst_element_factory_make ("bin", NULL);
+  fail_unless (bin != NULL, "Could not create bin");
+
+  src = gst_element_factory_make ("fakesrc", NULL);
+  fail_if (src == NULL, "Could not create fakesrc");
+  sink = gst_element_factory_make ("fakesink", NULL);
+  fail_if (sink == NULL, "Could not create fakesink");
+
+  gst_bin_add (GST_BIN (bin), sink);
+  gst_bin_add (GST_BIN (bin), src);
+
+  fail_unless (gst_element_link (src, sink), "could not link src and sink");
+
+  bus = GST_ELEMENT_BUS (bin);
+
+  /* change state, spawning two times three messages, minus one async */
+  fail_unless (gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED)
+      == GST_STATE_ASYNC);
+
+  pop_messages (bus, 5);
+
+  fail_unless (gst_bus_have_pending (bus) == FALSE,
+      "Unexpected messages on bus");
+
+  gst_bin_watch_for_state_change (GST_BIN (bin));
+
+  /* should get the bin's state change message now */
+  pop_messages (bus, 1);
+
+  fail_unless (gst_bus_have_pending (bus) == FALSE,
+      "Unexpected messages on bus");
+
+  fail_unless (gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING)
+      == GST_STATE_SUCCESS);
+
+  pop_messages (bus, 3);
+
+  /* this one might return either SUCCESS or ASYNC, likely SUCCESS */
+  gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED);
+
+  gst_bin_watch_for_state_change (GST_BIN (bin));
+
+  pop_messages (bus, 3);
+
+  fail_unless (gst_bus_have_pending (bus) == FALSE,
+      "Unexpected messages on bus");
+
+  /* setting bin to NULL flushes the bus automatically */
+  fail_unless (gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL)
+      == GST_STATE_SUCCESS);
+
+  /* clean up */
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
 /* adding an element with linked pads to a bin unlinks the
  * pads */
 GST_START_TEST (test_add_linked)
@@ -331,6 +393,7 @@ gst_bin_suite (void)
   tcase_add_test (tc_chain, test_message_state_changed);
   tcase_add_test (tc_chain, test_message_state_changed_child);
   tcase_add_test (tc_chain, test_message_state_changed_children);
+  tcase_add_test (tc_chain, test_watch_for_state_change);
   tcase_add_test (tc_chain, test_add_linked);
 
   return s;
index 3dea71c..aa86771 100644 (file)
@@ -215,8 +215,6 @@ gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad,
 
   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
 
-  GST_DEBUG_OBJECT (trans, "from: %" GST_PTR_FORMAT, caps);
-
   /* if there is a custom transform function, use this */
   if (klass->transform_caps) {
     GstCaps *temp;
@@ -230,10 +228,10 @@ gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad,
       GstCaps *nth;
 
       nth = gst_caps_copy_nth (caps, i);
-      GST_DEBUG_OBJECT (trans, "  from: %" GST_PTR_FORMAT, nth);
+      GST_DEBUG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
       temp = klass->transform_caps (trans, pad, nth);
       gst_caps_unref (nth);
-      GST_DEBUG_OBJECT (trans, "  to  : %" GST_PTR_FORMAT, temp);
+      GST_DEBUG_OBJECT (trans, "  to[%d]: %" GST_PTR_FORMAT, i, temp);
 
       gst_caps_append (ret, temp);
     }
index bbb9c8e..4119fb1 100644 (file)
@@ -1073,6 +1073,7 @@ clear_queue (GQueue * queue, gboolean unref)
     if (unref)
       gst_object_unref (p);
 }
+
 static void
 remove_all_from_queue (GQueue * queue, gpointer elem, gboolean unref)
 {
index cf7d6d0..90234d2 100644 (file)
@@ -1786,6 +1786,52 @@ gst_bin_remove_many (GstBin * bin, GstElement * element_1, ...)
 }
 
 static void
+get_state_func (GstElement * element, gpointer unused)
+{
+  GstElementStateReturn ret = GST_STATE_ASYNC;
+
+  GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
+      "new thread waiting on state change");
+
+  /* wait indefinitely */
+  while (ret == GST_STATE_ASYNC)
+    ret = gst_element_get_state (element, NULL, NULL, NULL);
+
+  gst_object_unref (element);
+}
+
+/**
+ * gst_bin_watch_for_state_change:
+ * @bin: the bin to watch for state changes
+ *
+ * Spawns a thread calling gst_element_get_state on @bin with infinite timeout.
+ *
+ * In practice this is done because if a bin returns GST_STATE_ASYNC from a
+ * state change it will not commit its state until someone calls
+ * gst_element_get_state on it. Thus having another thread checking the bin's
+ * state will ensure that a state-changed message gets posted on the bus
+ * eventually.
+ *
+ * This function is admittedly a bit of a hack. Bins should always post
+ * messages. However this behavior was broken out into this function to avoid
+ * spawning threads when scrubbing, when the bin's state is changing quickly and
+ * asynchronously.
+ */
+void
+gst_bin_watch_for_state_change (GstBin * bin)
+{
+  static GThreadPool *pool = NULL;
+  static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+  g_static_mutex_lock (&mutex);
+  if (pool == NULL)
+    pool = g_thread_pool_new ((GFunc) get_state_func, NULL, -1, FALSE, NULL);
+  g_static_mutex_unlock (&mutex);
+
+  g_thread_pool_push (pool, gst_object_ref (bin), NULL);
+}
+
+static void
 gst_element_populate_std_props (GObjectClass * klass, const gchar * prop_name,
     guint arg_id, GParamFlags flags)
 {
index 3e21b9f..fe68681 100644 (file)
@@ -302,6 +302,7 @@ gboolean                gst_pad_query_convert           (GstPad *pad, GstFormat
 /* bin functions */
 void                   gst_bin_add_many                (GstBin *bin, GstElement *element_1, ...);
 void                   gst_bin_remove_many             (GstBin *bin, GstElement *element_1, ...);
+void                   gst_bin_watch_for_state_change  (GstBin *bin);
 
 /* buffer functions */
 GstBuffer *            gst_buffer_merge                (GstBuffer * buf1, GstBuffer * buf2);
index 3dea71c..aa86771 100644 (file)
@@ -215,8 +215,6 @@ gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad,
 
   klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
 
-  GST_DEBUG_OBJECT (trans, "from: %" GST_PTR_FORMAT, caps);
-
   /* if there is a custom transform function, use this */
   if (klass->transform_caps) {
     GstCaps *temp;
@@ -230,10 +228,10 @@ gst_base_transform_transform_caps (GstBaseTransform * trans, GstPad * pad,
       GstCaps *nth;
 
       nth = gst_caps_copy_nth (caps, i);
-      GST_DEBUG_OBJECT (trans, "  from: %" GST_PTR_FORMAT, nth);
+      GST_DEBUG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
       temp = klass->transform_caps (trans, pad, nth);
       gst_caps_unref (nth);
-      GST_DEBUG_OBJECT (trans, "  to  : %" GST_PTR_FORMAT, temp);
+      GST_DEBUG_OBJECT (trans, "  to[%d]: %" GST_PTR_FORMAT, i, temp);
 
       gst_caps_append (ret, temp);
     }
index 0fe0814..bf41dc0 100644 (file)
@@ -270,6 +270,68 @@ GST_START_TEST (test_message_state_changed_children)
 
 GST_END_TEST;
 
+GST_START_TEST (test_watch_for_state_change)
+{
+  GstElement *src, *sink, *bin;
+  GstBus *bus;
+
+  bin = gst_element_factory_make ("bin", NULL);
+  fail_unless (bin != NULL, "Could not create bin");
+
+  src = gst_element_factory_make ("fakesrc", NULL);
+  fail_if (src == NULL, "Could not create fakesrc");
+  sink = gst_element_factory_make ("fakesink", NULL);
+  fail_if (sink == NULL, "Could not create fakesink");
+
+  gst_bin_add (GST_BIN (bin), sink);
+  gst_bin_add (GST_BIN (bin), src);
+
+  fail_unless (gst_element_link (src, sink), "could not link src and sink");
+
+  bus = GST_ELEMENT_BUS (bin);
+
+  /* change state, spawning two times three messages, minus one async */
+  fail_unless (gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED)
+      == GST_STATE_ASYNC);
+
+  pop_messages (bus, 5);
+
+  fail_unless (gst_bus_have_pending (bus) == FALSE,
+      "Unexpected messages on bus");
+
+  gst_bin_watch_for_state_change (GST_BIN (bin));
+
+  /* should get the bin's state change message now */
+  pop_messages (bus, 1);
+
+  fail_unless (gst_bus_have_pending (bus) == FALSE,
+      "Unexpected messages on bus");
+
+  fail_unless (gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING)
+      == GST_STATE_SUCCESS);
+
+  pop_messages (bus, 3);
+
+  /* this one might return either SUCCESS or ASYNC, likely SUCCESS */
+  gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED);
+
+  gst_bin_watch_for_state_change (GST_BIN (bin));
+
+  pop_messages (bus, 3);
+
+  fail_unless (gst_bus_have_pending (bus) == FALSE,
+      "Unexpected messages on bus");
+
+  /* setting bin to NULL flushes the bus automatically */
+  fail_unless (gst_element_set_state (GST_ELEMENT (bin), GST_STATE_NULL)
+      == GST_STATE_SUCCESS);
+
+  /* clean up */
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
 /* adding an element with linked pads to a bin unlinks the
  * pads */
 GST_START_TEST (test_add_linked)
@@ -331,6 +393,7 @@ gst_bin_suite (void)
   tcase_add_test (tc_chain, test_message_state_changed);
   tcase_add_test (tc_chain, test_message_state_changed_child);
   tcase_add_test (tc_chain, test_message_state_changed_children);
+  tcase_add_test (tc_chain, test_watch_for_state_change);
   tcase_add_test (tc_chain, test_add_linked);
 
   return s;