gstreamer_core/gst/gstbin.c
branchRCL_3
changeset 30 7e817e7e631c
parent 29 567bb019e3e3
--- a/gstreamer_core/gst/gstbin.c	Tue Aug 31 15:30:33 2010 +0300
+++ b/gstreamer_core/gst/gstbin.c	Wed Sep 01 12:16:41 2010 +0100
@@ -51,9 +51,10 @@
  *
  * gst_object_unref() is used to drop your reference to the bin.
  *
- * The #GstBin::element-added signal is fired whenever a new element is added to
- * the bin. Likewise the #GstBin::element-removed signal is fired whenever an
- * element is removed from the bin.
+ * The <link linkend="GstBin-element-added">element-added</link> signal is
+ * fired whenever a new element is added to the bin. Likewise the <link
+ * linkend="GstBin-element-removed">element-removed</link> signal is fired
+ * whenever an element is removed from the bin.
  *
  * <refsect2><title>Notes</title>
  * <para>
@@ -173,6 +174,7 @@
 #ifdef __SYMBIAN32__
 #include <glib_global.h>
 #endif
+
 /* enable for DURATION caching.
  * FIXME currently too many elements don't update
  * their duration when it changes so we return inaccurate values. */
@@ -191,20 +193,9 @@
  * a toplevel bin */
 #define BIN_IS_TOPLEVEL(bin) ((GST_OBJECT_PARENT (bin) == NULL) || bin->priv->asynchandling)
 
-#define GST_BIN_GET_PRIVATE(obj)  \
-   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BIN, GstBinPrivate))
-
 struct _GstBinPrivate
 {
   gboolean asynchandling;
-  /* if we get an ASYNC_DONE message from ourselves, this means that the
-   * subclass will simulate ASYNC behaviour without having ASYNC children. When
-   * such an ASYNC_DONE message is posted while we are doing a state change, we
-   * have to process the message after finishing the state change even when no
-   * child returned GST_STATE_CHANGE_ASYNC. */
-  gboolean pending_async_done;
-
-  guint32 structure_cookie;
 };
 
 typedef struct
@@ -225,15 +216,16 @@
     GstStateChange transition);
 static GstStateChangeReturn gst_bin_get_state_func (GstElement * element,
     GstState * state, GstState * pending, GstClockTime timeout);
-static void bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret,
-    gboolean flag_pending);
+static void bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret);
 static void bin_handle_async_start (GstBin * bin, gboolean new_base_time);
 static void bin_push_state_continue (BinContinueData * data);
 
 static gboolean gst_bin_add_func (GstBin * bin, GstElement * element);
 static gboolean gst_bin_remove_func (GstBin * bin, GstElement * element);
 
+#ifndef GST_DISABLE_INDEX
 static void gst_bin_set_index_func (GstElement * element, GstIndex * index);
+#endif
 static GstClock *gst_bin_provide_clock_func (GstElement * element);
 static gboolean gst_bin_set_clock_func (GstElement * element, GstClock * clock);
 
@@ -243,8 +235,6 @@
     GstMessage * message, GstBin * bin);
 static gboolean gst_bin_query (GstElement * element, GstQuery * query);
 
-static gboolean gst_bin_do_latency_func (GstBin * bin);
-
 #ifndef GST_DISABLE_LOADSAVE
 static xmlNodePtr gst_bin_save_thyself (GstObject * object, xmlNodePtr parent);
 static void gst_bin_restore_thyself (GstObject * object, xmlNodePtr self);
@@ -263,7 +253,6 @@
 {
   ELEMENT_ADDED,
   ELEMENT_REMOVED,
-  DO_LATENCY,
   LAST_SIGNAL
 };
 
@@ -276,35 +265,69 @@
       /* FILL ME */
 };
 
+static void gst_bin_base_init (gpointer g_class);
+static void gst_bin_class_init (GstBinClass * klass);
+static void gst_bin_init (GstBin * bin);
 static void gst_bin_child_proxy_init (gpointer g_iface, gpointer iface_data);
 
+static GstElementClass *parent_class = NULL;
 static guint gst_bin_signals[LAST_SIGNAL] = { 0 };
 
-#define _do_init(type) \
-{ \
-  const gchar *compat; \
-  static const GInterfaceInfo iface_info = { \
-    gst_bin_child_proxy_init, \
-    NULL, \
-    NULL}; \
-  \
-  g_type_add_interface_static (type, GST_TYPE_CHILD_PROXY, &iface_info); \
-  \
-  GST_DEBUG_CATEGORY_INIT (bin_debug, "bin", GST_DEBUG_BOLD, \
-      "debugging info for the 'bin' container element"); \
-  \
-  /* compatibility stuff */ \
-  compat = g_getenv ("GST_COMPAT"); \
-  if (compat != NULL) { \
-    if (strstr (compat, "no-live-preroll")) \
-      enable_latency = FALSE; \
-    else if (strstr (compat, "live-preroll")) \
-      enable_latency = TRUE; \
-  } \
+/**
+ * gst_bin_get_type:
+ *
+ * Returns: the type of #GstBin
+ */
+#ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+
+GType
+gst_bin_get_type (void)
+{
+  static GType gst_bin_type = 0;
+  const gchar *compat;
+
+  if (G_UNLIKELY (gst_bin_type == 0)) {
+    static const GTypeInfo bin_info = {
+      sizeof (GstBinClass),
+      gst_bin_base_init,
+      NULL,
+      (GClassInitFunc) gst_bin_class_init,
+      NULL,
+      NULL,
+      sizeof (GstBin),
+      0,
+      (GInstanceInitFunc) gst_bin_init,
+      NULL
+    };
+    static const GInterfaceInfo child_proxy_info = {
+      gst_bin_child_proxy_init,
+      NULL,
+      NULL
+    };
+
+    gst_bin_type =
+        g_type_register_static (GST_TYPE_ELEMENT, "GstBin", &bin_info, 0);
+
+    g_type_add_interface_static (gst_bin_type, GST_TYPE_CHILD_PROXY,
+        &child_proxy_info);
+
+    GST_DEBUG_CATEGORY_INIT (bin_debug, "bin", GST_DEBUG_BOLD,
+        "debugging info for the 'bin' container element");
+
+    /* compatibility stuff */
+    compat = g_getenv ("GST_COMPAT");
+    if (compat != NULL) {
+      if (strstr (compat, "no-live-preroll"))
+        enable_latency = FALSE;
+      else if (strstr (compat, "live-preroll"))
+        enable_latency = TRUE;
+    }
+  }
+  return gst_bin_type;
 }
 
-GST_BOILERPLATE_FULL (GstBin, gst_bin, GstElement, GST_TYPE_ELEMENT, _do_init);
-
 static void
 gst_bin_base_init (gpointer g_class)
 {
@@ -362,22 +385,6 @@
   iface->get_child_by_index = gst_bin_child_proxy_get_child_by_index;
 }
 
-static gboolean
-_gst_boolean_accumulator (GSignalInvocationHint * ihint,
-    GValue * return_accu, const GValue * handler_return, gpointer dummy)
-{
-  gboolean myboolean;
-
-  myboolean = g_value_get_boolean (handler_return);
-  if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
-    g_value_set_boolean (return_accu, myboolean);
-
-  GST_DEBUG ("invocation %d, %d", ihint->run_type, myboolean);
-
-  /* stop emission */
-  return FALSE;
-}
-
 static void
 gst_bin_class_init (GstBinClass * klass)
 {
@@ -390,7 +397,7 @@
   gstobject_class = (GstObjectClass *) klass;
   gstelement_class = (GstElementClass *) klass;
 
-  g_type_class_add_private (klass, sizeof (GstBinPrivate));
+  parent_class = g_type_class_peek_parent (klass);
 
   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_bin_set_property);
   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_bin_get_property);
@@ -407,7 +414,7 @@
   g_object_class_install_property (gobject_class, PROP_ASYNC_HANDLING,
       g_param_spec_boolean ("async-handling", "Async Handling",
           "The bin will handle Asynchronous state changes",
-          DEFAULT_ASYNC_HANDLING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          DEFAULT_ASYNC_HANDLING, G_PARAM_READWRITE));
 
   /**
    * GstBin::element-added:
@@ -431,29 +438,6 @@
       g_signal_new ("element-removed", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_removed), NULL,
       NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
-  /**
-   * GstBin::do-latency:
-   * @bin: the #GstBin
-   *
-   * Will be emitted when the bin needs to perform latency calculations. This
-   * signal is only emited for toplevel bins or when async-handling is
-   * enabled.
-   *
-   * Only one signal handler is invoked. If no signals are connected, the
-   * default handler is invoked, which will query and distribute the lowest
-   * possible latency to all sinks.
-   *
-   * Connect to this signal if the default latency calculations are not
-   * sufficient, like when you need different latencies for different sinks in
-   * the same pipeline.
-   *
-   * Since: 0.10.22
-   */
-  gst_bin_signals[DO_LATENCY] =
-      g_signal_new ("do-latency", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstBinClass, do_latency),
-      _gst_boolean_accumulator, NULL, gst_marshal_BOOLEAN__VOID,
-      G_TYPE_BOOLEAN, 0, G_TYPE_NONE);
 
   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_bin_dispose);
 
@@ -466,7 +450,9 @@
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_bin_change_state_func);
   gstelement_class->get_state = GST_DEBUG_FUNCPTR (gst_bin_get_state_func);
+#ifndef GST_DISABLE_INDEX
   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index_func);
+#endif
   gstelement_class->provide_clock =
       GST_DEBUG_FUNCPTR (gst_bin_provide_clock_func);
   gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_bin_set_clock_func);
@@ -478,8 +464,6 @@
   klass->remove_element = GST_DEBUG_FUNCPTR (gst_bin_remove_func);
   klass->handle_message = GST_DEBUG_FUNCPTR (gst_bin_handle_message_func);
 
-  klass->do_latency = GST_DEBUG_FUNCPTR (gst_bin_do_latency_func);
-
   GST_DEBUG ("creating bin thread pool");
   err = NULL;
   klass->pool =
@@ -490,7 +474,7 @@
 }
 
 static void
-gst_bin_init (GstBin * bin, GstBinClass * klass)
+gst_bin_init (GstBin * bin)
 {
   GstBus *bus;
 
@@ -508,9 +492,8 @@
       bus);
   gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bin_bus_handler, bin);
 
-  bin->priv = GST_BIN_GET_PRIVATE (bin);
+  bin->priv = g_new0 (GstBinPrivate, 1);
   bin->priv->asynchandling = DEFAULT_ASYNC_HANDLING;
-  bin->priv->structure_cookie = 0;
 }
 
 static void
@@ -523,12 +506,11 @@
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
 
-  GST_OBJECT_LOCK (object);
+  bin_remove_messages (bin, NULL, GST_MESSAGE_ANY);
+
   gst_object_replace ((GstObject **) child_bus_p, NULL);
   gst_object_replace ((GstObject **) provided_clock_p, NULL);
   gst_object_replace ((GstObject **) clock_provider_p, NULL);
-  bin_remove_messages (bin, NULL, GST_MESSAGE_ANY);
-  GST_OBJECT_UNLOCK (object);
 
   while (bin->children) {
     gst_bin_remove (bin, GST_ELEMENT_CAST (bin->children->data));
@@ -538,6 +520,11 @@
         GST_STR_NULL (GST_OBJECT_NAME (object)));
   }
 
+  if (bin->priv) {
+    g_free (bin->priv);
+    bin->priv = NULL;
+  }
+
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
@@ -603,45 +590,24 @@
  *
  * MT safe
  */
+#ifndef GST_DISABLE_INDEX
 static void
 gst_bin_set_index_func (GstElement * element, GstIndex * index)
 {
   GstBin *bin;
-  gboolean done;
-  GstIterator *it;
+  GList *children;
 
   bin = GST_BIN (element);
 
-  it = gst_bin_iterate_elements (bin);
-
-  done = FALSE;
-  while (!done) {
-    gpointer data;
-
-    switch (gst_iterator_next (it, &data)) {
-      case GST_ITERATOR_OK:
-      {
-        GstElement *child = GST_ELEMENT_CAST (data);
-
-        GST_DEBUG_OBJECT (bin, "setting index on %s", GST_ELEMENT_NAME (child));
-        gst_element_set_index (child, index);
-
-        gst_object_unref (child);
-        break;
-      }
-      case GST_ITERATOR_RESYNC:
-        GST_DEBUG_OBJECT (bin, "iterator doing resync");
-        gst_iterator_resync (it);
-        break;
-      default:
-      case GST_ITERATOR_DONE:
-        GST_DEBUG_OBJECT (bin, "iterator done");
-        done = TRUE;
-        break;
-    }
+  GST_OBJECT_LOCK (bin);
+  for (children = bin->children; children; children = g_list_next (children)) {
+    GstElement *child = GST_ELEMENT (children->data);
+
+    gst_element_set_index (child, index);
   }
-  gst_iterator_free (it);
+  GST_OBJECT_UNLOCK (bin);
 }
+#endif
 
 /* set the clock on all elements in this bin
  *
@@ -650,42 +616,21 @@
 static gboolean
 gst_bin_set_clock_func (GstElement * element, GstClock * clock)
 {
+  GList *children;
   GstBin *bin;
-  gboolean done;
-  GstIterator *it;
   gboolean res = TRUE;
 
   bin = GST_BIN (element);
 
-  it = gst_bin_iterate_elements (bin);
-
-  done = FALSE;
-  while (!done) {
-    gpointer data;
-
-    switch (gst_iterator_next (it, &data)) {
-      case GST_ITERATOR_OK:
-      {
-        GstElement *child = GST_ELEMENT_CAST (data);
-
-        res &= gst_element_set_clock (child, clock);
-
-        gst_object_unref (child);
-        break;
-      }
-      case GST_ITERATOR_RESYNC:
-        GST_DEBUG_OBJECT (bin, "iterator doing resync");
-        gst_iterator_resync (it);
-        res = TRUE;
-        break;
-      default:
-      case GST_ITERATOR_DONE:
-        GST_DEBUG_OBJECT (bin, "iterator done");
-        done = TRUE;
-        break;
+  GST_OBJECT_LOCK (bin);
+  if (element->clock != clock) {
+    for (children = bin->children; children; children = g_list_next (children)) {
+      GstElement *child = GST_ELEMENT (children->data);
+
+      res &= gst_element_set_clock (child, clock);
     }
   }
-  gst_iterator_free (it);
+  GST_OBJECT_UNLOCK (bin);
 
   return res;
 }
@@ -786,7 +731,6 @@
     eq &= GST_MESSAGE_SRC (message) == target->src;
   if (target->types)
     eq &= (GST_MESSAGE_TYPE (message) & target->types) != 0;
-  GST_LOG ("looking at message %p: %d", message, eq);
 
   return (eq ? 0 : 1);
 }
@@ -823,7 +767,7 @@
   return result;
 }
 
-/* with LOCK, returns TRUE if message had a valid SRC, takes ownership of
+/* with LOCK, returns TRUE if message had a valid SRC, takes ref on
  * the message.
  *
  * A message that is cached and has the same SRC and type is replaced
@@ -842,16 +786,12 @@
   if ((src = GST_MESSAGE_SRC (message))) {
     /* first find the previous message posted by this element */
     if ((previous = find_message (bin, src, types))) {
-      GstMessage *previous_msg;
-
       /* if we found a previous message, replace it */
-      previous_msg = previous->data;
+      gst_message_unref (previous->data);
       previous->data = message;
 
-      GST_DEBUG_OBJECT (bin, "replace old message %s from %s with %s message",
-          GST_MESSAGE_TYPE_NAME (previous_msg), GST_ELEMENT_NAME (src), name);
-
-      gst_message_unref (previous_msg);
+      GST_DEBUG_OBJECT (bin, "replace old message %s from %s",
+          name, GST_ELEMENT_NAME (src));
     } else {
       /* keep new message */
       bin->messages = g_list_prepend (bin->messages, message);
@@ -995,14 +935,12 @@
   bin->children = g_list_prepend (bin->children, element);
   bin->numchildren++;
   bin->children_cookie++;
-  bin->priv->structure_cookie++;
 
   /* distribute the bus */
   gst_element_set_bus (element, bin->child_bus);
 
-  /* propagate the current base_time, start_time and clock */
+  /* propagate the current base_time and clock */
   gst_element_set_base_time (element, GST_ELEMENT (bin)->base_time);
-  gst_element_set_start_time (element, GST_ELEMENT_START_TIME (bin));
   /* it's possible that the element did not accept the clock but
    * that is not important right now. When the pipeline goes to PLAYING,
    * a new clock will be selected */
@@ -1030,7 +968,7 @@
     }
     case GST_STATE_CHANGE_NO_PREROLL:
       /* ignore all async elements we might have and commit our state */
-      bin_handle_async_done (bin, ret, FALSE);
+      bin_handle_async_done (bin, ret);
       break;
     case GST_STATE_CHANGE_FAILURE:
       break;
@@ -1149,8 +1087,6 @@
   GstIterator *it;
   gboolean is_sink, othersink, found;
   GstMessage *clock_message = NULL;
-  GstClock **provided_clock_p;
-  GstElement **clock_provider_p;
   GList *walk, *next;
   gboolean other_async, this_async, have_no_preroll;
   GstStateChangeReturn ret;
@@ -1212,7 +1148,6 @@
    * so that others can detect a change in the children list. */
   bin->numchildren--;
   bin->children_cookie++;
-  bin->priv->structure_cookie++;
 
   if (is_sink && !othersink) {
     /* we're not a sink anymore */
@@ -1228,10 +1163,6 @@
     bin->clock_dirty = TRUE;
     clock_message =
         gst_message_new_clock_lost (GST_OBJECT_CAST (bin), bin->provided_clock);
-    provided_clock_p = &bin->provided_clock;
-    clock_provider_p = &bin->clock_provider;
-    gst_object_replace ((GstObject **) provided_clock_p, NULL);
-    gst_object_replace ((GstObject **) clock_provider_p, NULL);
   }
 
   /* remove messages for the element, if there was a pending ASYNC_START
@@ -1242,46 +1173,22 @@
   for (walk = bin->messages; walk; walk = next) {
     GstMessage *message = (GstMessage *) walk->data;
     GstElement *src = GST_ELEMENT_CAST (GST_MESSAGE_SRC (message));
-    gboolean remove;
 
     next = g_list_next (walk);
-    remove = FALSE;
-
-    switch (GST_MESSAGE_TYPE (message)) {
-      case GST_MESSAGE_ASYNC_START:
-        if (src == element)
-          this_async = TRUE;
-        else
-          other_async = TRUE;
-
-        GST_DEBUG_OBJECT (src, "looking at message %p", message);
-        break;
-      case GST_MESSAGE_STRUCTURE_CHANGE:
-      {
-        GstElement *owner;
-
-        GST_DEBUG_OBJECT (src, "looking at structure change message %p",
-            message);
-        /* it's unlikely that this message is still in the list of messages
-         * because this would mean that a link/unlink is busy in another thread
-         * while we remove the element. We still have to remove the message
-         * because we might not receive the done message anymore when the element
-         * is removed from the bin. */
-        gst_message_parse_structure_change (message, NULL, &owner, NULL);
-        if (owner == element)
-          remove = TRUE;
-        break;
-      }
-      default:
-        break;
+
+    if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ASYNC_START) {
+      if (src == element)
+        this_async = TRUE;
+      else
+        other_async = TRUE;
+
+      GST_DEBUG_OBJECT (GST_MESSAGE_SRC (message),
+          "looking at message %p", message);
     }
-    if (src == element)
-      remove = TRUE;
-
-    if (remove) {
+    if (src == element) {
       /* delete all message types */
-      GST_DEBUG_OBJECT (src, "deleting message %p of element \"%s\"",
-          message, elem_name);
+      GST_DEBUG_OBJECT (GST_MESSAGE_SRC (message),
+          "deleting message %p of element \"%s\"", message, elem_name);
       bin->messages = g_list_delete_link (bin->messages, walk);
       gst_message_unref (message);
     }
@@ -1308,7 +1215,7 @@
     else
       ret = GST_STATE_CHANGE_SUCCESS;
 
-    bin_handle_async_done (bin, ret, FALSE);
+    bin_handle_async_done (bin, ret);
   } else {
     GST_DEBUG_OBJECT (bin,
         "recalc state preroll: %d, other async: %d, this async %d",
@@ -1788,28 +1695,18 @@
   gboolean linked = FALSE;
 
   GST_OBJECT_LOCK (element);
-  /* don't touch degree if element has no sinkpads */
+  /* don't touch degree if element has no sourcepads */
   if (element->numsinkpads != 0) {
     /* loop over all sinkpads, decrement degree for all connected
      * elements in this bin */
     GList *pads;
 
     for (pads = element->sinkpads; pads; pads = g_list_next (pads)) {
-      GstPad *pad, *peer;
-
-      pad = GST_PAD_CAST (pads->data);
-
-      if ((peer = gst_pad_get_peer (pad))) {
+      GstPad *peer;
+
+      if ((peer = gst_pad_get_peer (GST_PAD_CAST (pads->data)))) {
         GstElement *peer_element;
 
-        /* we're iterating over the sinkpads, this is the peer and thus the
-         * srcpad, check if it's busy in a link/unlink */
-        if (G_UNLIKELY (find_message (bit->bin, GST_OBJECT_CAST (peer),
-                    GST_MESSAGE_STRUCTURE_CHANGE))) {
-          gst_object_unref (peer);
-          continue;
-        }
-
         if ((peer_element = gst_pad_get_parent_element (peer))) {
           GST_OBJECT_LOCK (peer_element);
           /* check that we don't go outside of this bin */
@@ -1832,10 +1729,7 @@
                 GST_ELEMENT_NAME (peer_element), old_deg, new_deg,
                 GST_ELEMENT_NAME (element));
 
-            /* update degree, it is possible that an element was in 0 and
-             * reaches -1 here. This would mean that the element had no sinkpads
-             * but became linked while the state change was happening. We will
-             * resync on this with the structure change message. */
+            /* update degree */
             if (new_deg == 0) {
               /* degree hit 0, add to queue */
               add_to_queue (bit, peer_element);
@@ -1963,7 +1857,7 @@
       gst_iterator_new (sizeof (GstBinSortIterator),
       GST_TYPE_ELEMENT,
       GST_OBJECT_GET_LOCK (bin),
-      &bin->priv->structure_cookie,
+      &bin->children_cookie,
       (GstIteratorNextFunction) gst_bin_sort_iterator_next,
       (GstIteratorItemFunction) NULL,
       (GstIteratorResyncFunction) gst_bin_sort_iterator_resync,
@@ -2015,20 +1909,14 @@
 
 static GstStateChangeReturn
 gst_bin_element_set_state (GstBin * bin, GstElement * element,
-    GstClockTime base_time, GstClockTime start_time, GstState current,
-    GstState next)
+    GstClockTime base_time, GstState current, GstState next)
 {
   GstStateChangeReturn ret;
   gboolean locked;
   GList *found;
 
-  GST_STATE_LOCK (element);
-
+  /* peel off the locked flag */
   GST_OBJECT_LOCK (element);
-  /* set base_time and start time on child */
-  GST_ELEMENT_START_TIME (element) = start_time;
-  element->base_time = base_time;
-  /* peel off the locked flag */
   locked = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE);
   /* get previous state return */
   ret = GST_STATE_RETURN (element);
@@ -2082,11 +1970,12 @@
       GST_ELEMENT_NAME (element), gst_element_state_get_name (next),
       GST_TIME_ARGS (base_time));
 
+  /* set base_time on child */
+  gst_element_set_base_time (element, base_time);
+
   /* change state */
   ret = gst_element_set_state (element, next);
 
-  GST_STATE_UNLOCK (element);
-
   return ret;
 
 locked:
@@ -2094,14 +1983,12 @@
     GST_DEBUG_OBJECT (element,
         "element is locked, return previous return %s",
         gst_element_state_change_return_get_name (ret));
-    GST_STATE_UNLOCK (element);
     return ret;
   }
 was_busy:
   {
     GST_DEBUG_OBJECT (element, "element was busy, delaying state change");
     GST_OBJECT_UNLOCK (bin);
-    GST_STATE_UNLOCK (element);
     return GST_STATE_CHANGE_ASYNC;
   }
 }
@@ -2188,50 +2075,15 @@
   }
 }
 
-/**
- * gst_bin_recalculate_latency:
- * @bin: a #GstBin
- *
- * Query @bin for the current latency using and reconfigures this latency to all the
- * elements with a LATENCY event.
- *
- * This method is typically called on the pipeline when a #GST_MESSAGE_LATENCY
- * is posted on the bus.
- *
- * This function simply emits the 'do-latency' signal so any custom latency
- * calculations will be performed.
- *
- * Returns: %TRUE if the latency could be queried and reconfigured.
- *
- * Since: 0.10.22.
- */
-#ifdef __SYMBIAN32__
-EXPORT_C
-#endif
-
-gboolean
-gst_bin_recalculate_latency (GstBin * bin)
-{
-  gboolean res;
-
-  g_signal_emit (G_OBJECT (bin), gst_bin_signals[DO_LATENCY], 0, &res);
-  GST_DEBUG_OBJECT (bin, "latency returned %d", res);
-
-  return res;
-}
-
+/* do latency correction. We do a latency query on the bin, and then send a
+ * LATENCY event on the elements fo configure them */
 static gboolean
-gst_bin_do_latency_func (GstBin * bin)
+do_bin_latency (GstElement * element)
 {
   GstQuery *query;
-  GstElement *element;
   GstClockTime min_latency, max_latency;
   gboolean res;
 
-  g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
-
-  element = GST_ELEMENT_CAST (bin);
-
   GST_DEBUG_OBJECT (element, "querying latency");
 
   query = gst_query_new_latency ();
@@ -2284,7 +2136,7 @@
   GstState current, next;
   gboolean have_async;
   gboolean have_no_preroll;
-  GstClockTime base_time, start_time;
+  GstClockTime base_time;
   GstIterator *it;
   gboolean done;
 
@@ -2308,7 +2160,7 @@
       GST_OBJECT_UNLOCK (bin);
 
       if (toplevel)
-        gst_bin_recalculate_latency (bin);
+        do_bin_latency (element);
       break;
     }
     case GST_STATE_PAUSED:
@@ -2358,7 +2210,6 @@
 restart:
   /* take base_time */
   base_time = gst_element_get_base_time (element);
-  start_time = gst_element_get_start_time (element);
 
   have_no_preroll = FALSE;
 
@@ -2374,9 +2225,7 @@
         child = GST_ELEMENT_CAST (data);
 
         /* set state and base_time now */
-        ret =
-            gst_bin_element_set_state (bin, child, base_time, start_time,
-            current, next);
+        ret = gst_bin_element_set_state (bin, child, base_time, current, next);
 
         switch (ret) {
           case GST_STATE_CHANGE_SUCCESS:
@@ -2431,13 +2280,8 @@
     goto done;
 
   if (have_no_preroll) {
-    GST_CAT_DEBUG (GST_CAT_STATES,
-        "we have NO_PREROLL elements %s -> NO_PREROLL",
-        gst_element_state_change_return_get_name (ret));
     ret = GST_STATE_CHANGE_NO_PREROLL;
   } else if (have_async) {
-    GST_CAT_DEBUG (GST_CAT_STATES, "we have ASYNC elements %s -> ASYNC",
-        gst_element_state_change_return_get_name (ret));
     ret = GST_STATE_CHANGE_ASYNC;
   }
 
@@ -2446,13 +2290,8 @@
 
   GST_OBJECT_LOCK (bin);
   bin->polling = FALSE;
-  /* it's possible that we did not get ASYNC from the children while the bin is
-   * simulating ASYNC behaviour by posting an ASYNC_DONE message on the bus with
-   * itself as the source. In that case we still want to check if the state
-   * change completed. */
-  if (ret != GST_STATE_CHANGE_ASYNC && !bin->priv->pending_async_done) {
-    /* no element returned ASYNC and there are no pending async_done messages,
-     * we can just complete. */
+  if (ret != GST_STATE_CHANGE_ASYNC) {
+    /* no element returned ASYNC, we can just complete. */
     GST_DEBUG_OBJECT (bin, "no async elements");
     goto state_end;
   }
@@ -2474,11 +2313,10 @@
     bin_remove_messages (bin, NULL, GST_MESSAGE_ASYNC_DONE);
 
     GST_DEBUG_OBJECT (bin, "async elements commited");
-    bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, FALSE);
+    bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS);
   }
 
 state_end:
-  bin->priv->pending_async_done = FALSE;
   GST_OBJECT_UNLOCK (bin);
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
@@ -2567,6 +2405,7 @@
   GstBin *bin;
   GstState current, next, pending;
   GstStateChange transition;
+  GstStateChangeReturn ret;
 
   bin = data->bin;
   pending = data->pending;
@@ -2587,7 +2426,6 @@
   transition = (GstStateChange) GST_STATE_TRANSITION (current, next);
 
   GST_STATE_NEXT (bin) = next;
-  GST_STATE_PENDING (bin) = pending;
   /* mark busy */
   GST_STATE_RETURN (bin) = GST_STATE_CHANGE_ASYNC;
   GST_OBJECT_UNLOCK (bin);
@@ -2597,7 +2435,7 @@
       gst_element_state_get_name (current),
       gst_element_state_get_name (next), gst_element_state_get_name (pending));
 
-  gst_element_change_state (GST_ELEMENT_CAST (bin), transition);
+  ret = gst_element_change_state (GST_ELEMENT_CAST (bin), transition);
 
   GST_STATE_UNLOCK (bin);
   GST_DEBUG_OBJECT (bin, "state continue done");
@@ -2675,6 +2513,7 @@
   if (GST_STATE_RETURN (bin) == GST_STATE_CHANGE_NO_PREROLL)
     goto was_no_preroll;
 
+
   old_state = GST_STATE (bin);
 
   /* when we PLAYING we go back to PAUSED, when preroll happens, we go back to
@@ -2733,8 +2572,7 @@
  * This function is called with the OBJECT lock.
  */
 static void
-bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret,
-    gboolean flag_pending)
+bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret)
 {
   GstState current, pending, target;
   GstStateChangeReturn old_ret;
@@ -2778,11 +2616,6 @@
     /* update current state */
     current = GST_STATE (bin) = old_next;
   } else {
-    GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin,
-        "setting state from %s to %s, pending %s",
-        gst_element_state_get_name (old_state),
-        gst_element_state_get_name (old_state),
-        gst_element_state_get_name (pending));
     current = old_state;
   }
 
@@ -2814,7 +2647,7 @@
     cont->pending = pending;
     /* mark busy */
     GST_STATE_RETURN (bin) = GST_STATE_CHANGE_ASYNC;
-    GST_STATE_NEXT (bin) = GST_STATE_GET_NEXT (old_state, pending);
+    GST_STATE_NEXT (bin) = pending;
   }
 
   if (old_next != GST_STATE_PLAYING) {
@@ -2854,10 +2687,6 @@
 was_busy:
   {
     GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin, "state change busy");
-    /* if we were busy with a state change and we are requested to flag a
-     * pending async done, we do so here */
-    if (flag_pending)
-      bin->priv->pending_async_done = TRUE;
     return;
   }
 nothing_pending:
@@ -2926,16 +2755,18 @@
 {
   GstObject *src;
   GstMessageType type;
-  GstMessage *tmessage;
-  guint32 seqnum;
 
   src = GST_MESSAGE_SRC (message);
   type = GST_MESSAGE_TYPE (message);
 
+// Message src can be NULL
+  if(src)
   GST_DEBUG_OBJECT (bin, "[msg %p] handling child %s message of type %s",
-      message, src ? GST_ELEMENT_NAME (src) : "(NULL)",
-      GST_MESSAGE_TYPE_NAME (message));
-
+      message, GST_ELEMENT_NAME (src), GST_MESSAGE_TYPE_NAME (message));
+  else
+  GST_DEBUG_OBJECT (bin, "[msg %p] handling child %s message of type %s",
+            message, "Null ", GST_MESSAGE_TYPE_NAME (message));
+  
   switch (type) {
     case GST_MESSAGE_EOS:
     {
@@ -2949,13 +2780,9 @@
 
       /* if we are completely EOS, we forward an EOS message */
       if (eos) {
-        seqnum = gst_message_get_seqnum (message);
-        tmessage = gst_message_new_eos (GST_OBJECT_CAST (bin));
-        gst_message_set_seqnum (tmessage, seqnum);
-
-        GST_DEBUG_OBJECT (bin,
-            "all sinks posted EOS, posting seqnum #%" G_GUINT32_FORMAT, seqnum);
-        gst_element_post_message (GST_ELEMENT_CAST (bin), tmessage);
+        GST_DEBUG_OBJECT (bin, "all sinks posted EOS");
+        gst_element_post_message (GST_ELEMENT_CAST (bin),
+            gst_message_new_eos (GST_OBJECT_CAST (bin)));
       }
       break;
     }
@@ -2967,37 +2794,13 @@
       gst_message_unref (message);
       break;
     }
-    case GST_MESSAGE_SEGMENT_START:{
-      gboolean post = FALSE;
-      GstFormat format;
-      gint64 position;
-
-      gst_message_parse_segment_start (message, &format, &position);
-      seqnum = gst_message_get_seqnum (message);
-
+    case GST_MESSAGE_SEGMENT_START:
       GST_OBJECT_LOCK (bin);
-      /* if this is the first segment-start, post to parent but not to the
-       * application */
-      if (!find_message (bin, NULL, GST_MESSAGE_SEGMENT_START) &&
-          (GST_OBJECT_PARENT (bin) != NULL)) {
-        post = TRUE;
-      }
       /* replace any previous segment_start message from this source
        * with the new segment start message */
       bin_replace_message (bin, message, GST_MESSAGE_SEGMENT_START);
       GST_OBJECT_UNLOCK (bin);
-      if (post) {
-        tmessage = gst_message_new_segment_start (GST_OBJECT_CAST (bin),
-            format, position);
-        gst_message_set_seqnum (tmessage, seqnum);
-
-        /* post segment start with initial format and position. */
-        GST_DEBUG_OBJECT (bin, "posting SEGMENT_START (%u) bus message: %p",
-            seqnum, message);
-        gst_element_post_message (GST_ELEMENT_CAST (bin), tmessage);
-      }
       break;
-    }
     case GST_MESSAGE_SEGMENT_DONE:
     {
       gboolean post = FALSE;
@@ -3005,7 +2808,6 @@
       gint64 position;
 
       gst_message_parse_segment_done (message, &format, &position);
-      seqnum = gst_message_get_seqnum (message);
 
       GST_OBJECT_LOCK (bin);
       bin_replace_message (bin, message, GST_MESSAGE_SEGMENT_START);
@@ -3021,14 +2823,10 @@
       }
       GST_OBJECT_UNLOCK (bin);
       if (post) {
-        tmessage = gst_message_new_segment_done (GST_OBJECT_CAST (bin),
-            format, position);
-        gst_message_set_seqnum (tmessage, seqnum);
-
         /* post segment done with latest format and position. */
-        GST_DEBUG_OBJECT (bin, "posting SEGMENT_DONE (%u) bus message: %p",
-            seqnum, message);
-        gst_element_post_message (GST_ELEMENT_CAST (bin), tmessage);
+        gst_element_post_message (GST_ELEMENT_CAST (bin),
+            gst_message_new_segment_done (GST_OBJECT_CAST (bin),
+                format, position));
       }
       break;
     }
@@ -3099,9 +2897,12 @@
     {
       gboolean new_base_time;
       GstState target;
-
+	if(src)
       GST_DEBUG_OBJECT (bin, "ASYNC_START message %p, %s", message,
-          src ? GST_OBJECT_NAME (src) : "(NULL)");
+          GST_OBJECT_NAME (src));
+	else
+	GST_DEBUG_OBJECT (bin, "ASYNC_START message %p, %s", message,
+          "Null Source");
 
       gst_message_parse_async_start (message, &new_base_time);
 
@@ -3130,9 +2931,13 @@
     case GST_MESSAGE_ASYNC_DONE:
     {
       GstState target;
-
+	  
+	  if(src)
       GST_DEBUG_OBJECT (bin, "ASYNC_DONE message %p, %s", message,
-          src ? GST_OBJECT_NAME (src) : "(NULL)");
+          GST_OBJECT_NAME (src));
+	  else
+	  GST_DEBUG_OBJECT (bin, "ASYNC_DONE message %p, %s", message,
+          "Null Source");
 
       GST_OBJECT_LOCK (bin);
       target = GST_STATE_TARGET (bin);
@@ -3149,13 +2954,7 @@
         bin_remove_messages (bin, NULL, GST_MESSAGE_ASYNC_DONE);
 
         GST_DEBUG_OBJECT (bin, "async elements commited");
-        /* when we get an async done message when a state change was busy, we
-         * need to set the pending_done flag so that at the end of the state
-         * change we can see if we need to verify pending async elements, hence
-         * the TRUE argument here. */
-        bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, TRUE);
-      } else {
-        GST_DEBUG_OBJECT (bin, "there are more async elements pending");
+        bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS);
       }
       GST_OBJECT_UNLOCK (bin);
       break;
@@ -3169,34 +2968,6 @@
         break;
       }
     }
-    case GST_MESSAGE_STRUCTURE_CHANGE:
-    {
-      gboolean busy;
-
-      gst_message_parse_structure_change (message, NULL, NULL, &busy);
-
-      GST_OBJECT_LOCK (bin);
-      if (busy) {
-        /* while the pad is busy, avoid following it when doing state changes.
-         * Don't update the cookie yet, we will do that after the structure
-         * change finished and we are ready to inspect the new updated
-         * structure. */
-        bin_replace_message (bin, message, GST_MESSAGE_STRUCTURE_CHANGE);
-        message = NULL;
-      } else {
-        /* a pad link/unlink ended, signal the state change iterator that we
-         * need to resync by updating the structure_cookie. */
-        bin_remove_messages (bin, GST_MESSAGE_SRC (message),
-            GST_MESSAGE_STRUCTURE_CHANGE);
-        bin->priv->structure_cookie++;
-      }
-      GST_OBJECT_UNLOCK (bin);
-
-      if (message)
-        gst_message_unref (message);
-
-      break;
-    }
     default:
       goto forward;
   }
@@ -3252,7 +3023,6 @@
   gst_object_unref (item);
   return TRUE;
 }
-
 static void
 bin_query_duration_done (GstBin * bin, QueryFold * fold)
 {
@@ -3292,7 +3062,6 @@
   gst_object_unref (item);
   return TRUE;
 }
-
 static void
 bin_query_position_done (GstBin * bin, QueryFold * fold)
 {
@@ -3320,16 +3089,14 @@
 
     /* for the combined latency we collect the MAX of all min latencies and
      * the MIN of all max latencies */
-    if (live) {
-      if (min > fold->min)
-        fold->min = min;
-      if (fold->max == -1)
-        fold->max = max;
-      else if (max < fold->max)
-        fold->max = max;
-      if (fold->live == FALSE)
-        fold->live = live;
-    }
+    if (min > fold->min)
+      fold->min = min;
+    if (fold->max == -1)
+      fold->max = max;
+    else if (max < fold->max)
+      fold->max = max;
+    if (fold->live == FALSE)
+      fold->live = live;
   } else {
     g_value_set_boolean (ret, FALSE);
     GST_DEBUG_OBJECT (item, "failed query");
@@ -3443,7 +3210,6 @@
 
   fold_data.query = query;
 
-  /* set the result of the query to FALSE initially */
   g_value_init (&ret, G_TYPE_BOOLEAN);
   g_value_set_boolean (&ret, res);
 
@@ -3692,12 +3458,12 @@
   GST_CAT_INFO (GST_CAT_XML, "[%s]: saving %d children",
       GST_ELEMENT_NAME (bin), bin->numchildren);
 
-  children = g_list_last (bin->children);
+  children = bin->children;
   while (children) {
     child = GST_ELEMENT (children->data);
     elementnode = xmlNewChild (childlist, NULL, (xmlChar *) "element", NULL);
     gst_object_save_thyself (GST_OBJECT (child), elementnode);
-    children = g_list_previous (children);
+    children = g_list_next (children);
   }
   return childlist;
 }