Merge remote-tracking branch 'origin/0.10'
[platform/upstream/gstreamer.git] / gst / gstbin.c
index bdf01a7..665259e 100644 (file)
  * </para>
  * </refsect2>
  *
- * Last reviewed on 2006-04-28 (0.10.6)
+ * Last reviewed on 2012-03-28 (0.11.3)
  */
 
 #include "gst_private.h"
 
 #include "gstevent.h"
 #include "gstbin.h"
-#include "gstmarshal.h"
-#include "gstxml.h"
 #include "gstinfo.h"
 #include "gsterror.h"
 
-#include "gstindex.h"
-#include "gstindexfactory.h"
 #include "gstutils.h"
 #include "gstchildproxy.h"
 
-#ifdef GST_DISABLE_DEPRECATED
-#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
-#undef GstXmlNodePtr
-#define GstXmlNodePtr xmlNodePtr
-#include <libxml/parser.h>
-GstXmlNodePtr gst_object_save_thyself (GstObject * object,
-    GstXmlNodePtr parent);
-void gst_object_restore_thyself (GstObject * object, GstXmlNodePtr parent);
-GstElement *gst_xml_make_element (xmlNodePtr cur, GstObject * parent);
-#endif
-#endif
-
-/* enable for DURATION caching.
- * FIXME currently too many elements don't update
- * their duration when it changes so we return inaccurate values. */
-#undef DURATION_CACHING
-
-/* latency is by default enabled now.
- * live-preroll and no-live-preroll in the environment var GST_COMPAT
- * to enables or disable it respectively.
- */
-static gboolean enable_latency = TRUE;
-
 GST_DEBUG_CATEGORY_STATIC (bin_debug);
 #define GST_CAT_DEFAULT bin_debug
 
@@ -216,8 +189,11 @@ struct _GstBinPrivate
 
   guint32 structure_cookie;
 
+#if 0
   /* cached index */
   GstIndex *index;
+#endif
+
   /* forward messages from our children */
   gboolean message_forward;
 
@@ -245,16 +221,18 @@ static void gst_bin_state_changed (GstElement * element, GstState oldstate,
 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_start (GstBin * bin, gboolean new_base_time);
+    gboolean flag_pending, gboolean reset_time);
+static void bin_handle_async_start (GstBin * bin);
 static void bin_push_state_continue (BinContinueData * data);
 static void bin_do_eos (GstBin * bin);
 
 static gboolean gst_bin_add_func (GstBin * bin, GstElement * element);
 static gboolean gst_bin_remove_func (GstBin * bin, GstElement * element);
 
+#if 0
 static void gst_bin_set_index_func (GstElement * element, GstIndex * index);
 static GstIndex *gst_bin_get_index_func (GstElement * element);
+#endif
 
 static GstClock *gst_bin_provide_clock_func (GstElement * element);
 static gboolean gst_bin_set_clock_func (GstElement * element, GstClock * clock);
@@ -267,11 +245,6 @@ static gboolean gst_bin_query (GstElement * element, GstQuery * query);
 
 static gboolean gst_bin_do_latency_func (GstBin * bin);
 
-#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
-static xmlNodePtr gst_bin_save_thyself (GstObject * object, xmlNodePtr parent);
-static void gst_bin_restore_thyself (GstObject * object, xmlNodePtr self);
-#endif
-
 static void bin_remove_messages (GstBin * bin, GstObject * src,
     GstMessageType types);
 static void gst_bin_continue_func (BinContinueData * data);
@@ -304,44 +277,24 @@ static void gst_bin_child_proxy_init (gpointer g_iface, gpointer iface_data);
 
 static guint gst_bin_signals[LAST_SIGNAL] = { 0 };
 
-#define _do_init(type) \
+#define _do_init \
 { \
-  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); \
+  g_type_add_interface_static (g_define_type_id, 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_BOILERPLATE_FULL (GstBin, gst_bin, GstElement, GST_TYPE_ELEMENT, _do_init);
+#define gst_bin_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstBin, gst_bin, GST_TYPE_ELEMENT, _do_init);
 
-static void
-gst_bin_base_init (gpointer g_class)
-{
-  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
-
-  gst_element_class_set_details_simple (gstelement_class, "Generic bin",
-      "Generic/Bin",
-      "Simple container object",
-      "Erik Walthinsen <omega@cse.ogi.edu>,"
-      "Wim Taymans <wim.taymans@gmail.com>");
-}
-
-static GstObject *
+static GObject *
 gst_bin_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
     guint index)
 {
@@ -355,7 +308,7 @@ gst_bin_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
     gst_object_ref (res);
   GST_OBJECT_UNLOCK (bin);
 
-  return res;
+  return (GObject *) res;
 }
 
 static guint
@@ -402,12 +355,10 @@ static void
 gst_bin_class_init (GstBinClass * klass)
 {
   GObjectClass *gobject_class;
-  GstObjectClass *gstobject_class;
   GstElementClass *gstelement_class;
   GError *err;
 
   gobject_class = (GObjectClass *) klass;
-  gstobject_class = (GstObjectClass *) klass;
   gstelement_class = (GstElementClass *) klass;
 
   g_type_class_add_private (klass, sizeof (GstBinPrivate));
@@ -439,7 +390,7 @@ gst_bin_class_init (GstBinClass * klass)
   gst_bin_signals[ELEMENT_ADDED] =
       g_signal_new ("element-added", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_added), NULL,
-      NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
+      NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
   /**
    * GstBin::element-removed:
    * @bin: the #GstBin
@@ -450,7 +401,7 @@ gst_bin_class_init (GstBinClass * klass)
   gst_bin_signals[ELEMENT_REMOVED] =
       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);
+      NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
   /**
    * GstBin::do-latency:
    * @bin: the #GstBin
@@ -472,7 +423,7 @@ gst_bin_class_init (GstBinClass * klass)
   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,
+      _gst_boolean_accumulator, NULL, g_cclosure_marshal_generic,
       G_TYPE_BOOLEAN, 0, G_TYPE_NONE);
 
   /**
@@ -496,21 +447,20 @@ gst_bin_class_init (GstBinClass * klass)
 
   gobject_class->dispose = gst_bin_dispose;
 
-#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
-  gstobject_class->save_thyself =
-      ((gpointer (*)(GstObject * object,
-              gpointer self)) * GST_DEBUG_FUNCPTR (gst_bin_save_thyself));
-  gstobject_class->restore_thyself =
-      ((void (*)(GstObject * object,
-              gpointer self)) *GST_DEBUG_FUNCPTR (gst_bin_restore_thyself));
-#endif
+  gst_element_class_set_metadata (gstelement_class, "Generic bin",
+      "Generic/Bin",
+      "Simple container object",
+      "Erik Walthinsen <omega@cse.ogi.edu>,"
+      "Wim Taymans <wim.taymans@gmail.com>");
 
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_bin_change_state_func);
   gstelement_class->state_changed = GST_DEBUG_FUNCPTR (gst_bin_state_changed);
   gstelement_class->get_state = GST_DEBUG_FUNCPTR (gst_bin_get_state_func);
+#if 0
   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_bin_get_index_func);
   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);
@@ -534,7 +484,7 @@ gst_bin_class_init (GstBinClass * klass)
 }
 
 static void
-gst_bin_init (GstBin * bin, GstBinClass * klass)
+gst_bin_init (GstBin * bin)
 {
   GstBus *bus;
 
@@ -546,7 +496,7 @@ gst_bin_init (GstBin * bin, GstBinClass * klass)
   bin->clock_dirty = FALSE;
 
   /* Set up a bus for listening to child elements */
-  bus = gst_bus_new ();
+  bus = g_object_new (GST_TYPE_BUS, "enable-async", FALSE, NULL);
   bin->child_bus = bus;
   GST_DEBUG_OBJECT (bin, "using bus %" GST_PTR_FORMAT " to listen to children",
       bus);
@@ -565,7 +515,6 @@ gst_bin_dispose (GObject * object)
   GstBus **child_bus_p = &bin->child_bus;
   GstClock **provided_clock_p = &bin->provided_clock;
   GstElement **clock_provider_p = &bin->clock_provider;
-  GstIndex **index_p = &bin->priv->index;
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
 
@@ -573,7 +522,6 @@ gst_bin_dispose (GObject * object)
   gst_object_replace ((GstObject **) child_bus_p, NULL);
   gst_object_replace ((GstObject **) provided_clock_p, NULL);
   gst_object_replace ((GstObject **) clock_provider_p, NULL);
-  gst_object_replace ((GstObject **) index_p, NULL);
   bin_remove_messages (bin, NULL, GST_MESSAGE_ANY);
   GST_OBJECT_UNLOCK (object);
 
@@ -594,7 +542,7 @@ gst_bin_dispose (GObject * object)
  *
  * Creates a new bin with the given name.
  *
- * Returns: (transfer full): a new #GstBin
+ * Returns: (transfer floating): a new #GstBin
  */
 GstElement *
 gst_bin_new (const gchar * name)
@@ -652,6 +600,7 @@ gst_bin_get_property (GObject * object, guint prop_id,
   }
 }
 
+#if 0
 /* return the cached index */
 static GstIndex *
 gst_bin_get_index_func (GstElement * element)
@@ -680,6 +629,7 @@ gst_bin_set_index_func (GstElement * element, GstIndex * index)
   gboolean done;
   GstIterator *it;
   GstIndex *old;
+  GValue data = { 0, };
 
   bin = GST_BIN_CAST (element);
 
@@ -700,18 +650,16 @@ gst_bin_set_index_func (GstElement * element, GstIndex * index)
   /* set the index on all elements in the bin */
   done = FALSE;
   while (!done) {
-    gpointer data;
-
     switch (gst_iterator_next (it, &data)) {
       case GST_ITERATOR_OK:
       {
-        GstElement *child = GST_ELEMENT_CAST (data);
+        GstElement *child = g_value_get_object (&data);
 
         GST_DEBUG_OBJECT (bin, "setting index on '%s'",
             GST_ELEMENT_NAME (child));
         gst_element_set_index (child, index);
 
-        gst_object_unref (child);
+        g_value_reset (&data);
         break;
       }
       case GST_ITERATOR_RESYNC:
@@ -725,6 +673,7 @@ gst_bin_set_index_func (GstElement * element, GstIndex * index)
         break;
     }
   }
+  g_value_unset (&data);
   gst_iterator_free (it);
   return;
 
@@ -735,6 +684,7 @@ was_set:
     return;
   }
 }
+#endif
 
 /* set the clock on all elements in this bin
  *
@@ -747,6 +697,7 @@ gst_bin_set_clock_func (GstElement * element, GstClock * clock)
   gboolean done;
   GstIterator *it;
   gboolean res = TRUE;
+  GValue data = { 0, };
 
   bin = GST_BIN_CAST (element);
 
@@ -754,16 +705,14 @@ gst_bin_set_clock_func (GstElement * element, GstClock * clock)
 
   done = FALSE;
   while (!done) {
-    gpointer data;
-
     switch (gst_iterator_next (it, &data)) {
       case GST_ITERATOR_OK:
       {
-        GstElement *child = GST_ELEMENT_CAST (data);
+        GstElement *child = g_value_get_object (&data);
 
         res &= gst_element_set_clock (child, clock);
 
-        gst_object_unref (child);
+        g_value_reset (&data);
         break;
       }
       case GST_ITERATOR_RESYNC:
@@ -778,8 +727,12 @@ gst_bin_set_clock_func (GstElement * element, GstClock * clock)
         break;
     }
   }
+  g_value_unset (&data);
   gst_iterator_free (it);
 
+  if (res)
+    res = GST_ELEMENT_CLASS (parent_class)->set_clock (element, clock);
+
   return res;
 }
 
@@ -799,7 +752,8 @@ gst_bin_provide_clock_func (GstElement * element)
   GstElement *provider = NULL;
   GstBin *bin;
   GstIterator *it;
-  gpointer val;
+  gboolean done;
+  GValue val = { 0, };
   GstClock **provided_clock_p;
   GstElement **clock_provider_p;
 
@@ -812,25 +766,53 @@ gst_bin_provide_clock_func (GstElement * element)
   GST_DEBUG_OBJECT (bin, "finding new clock");
 
   it = gst_bin_sort_iterator_new (bin);
+  GST_OBJECT_UNLOCK (bin);
+
+  done = FALSE;
+  while (!done) {
+    switch (gst_iterator_next (it, &val)) {
+      case GST_ITERATOR_OK:
+      {
+        GstElement *child = g_value_get_object (&val);
+        GstClock *clock;
+
+        clock = gst_element_provide_clock (child);
+        if (clock) {
+          GST_DEBUG_OBJECT (bin, "found candidate clock %p by element %s",
+              clock, GST_ELEMENT_NAME (child));
+          if (result) {
+            gst_object_unref (result);
+            gst_object_unref (provider);
+          }
+          result = clock;
+          provider = gst_object_ref (child);
+        }
 
-  while (it->next (it, &val) == GST_ITERATOR_OK) {
-    GstElement *child = GST_ELEMENT_CAST (val);
-    GstClock *clock;
-
-    clock = gst_element_provide_clock (child);
-    if (clock) {
-      GST_DEBUG_OBJECT (bin, "found candidate clock %p by element %s",
-          clock, GST_ELEMENT_NAME (child));
-      if (result) {
-        gst_object_unref (result);
-        gst_object_unref (provider);
+        g_value_reset (&val);
+        break;
       }
-      result = clock;
-      provider = child;
-    } else {
-      gst_object_unref (child);
+      case GST_ITERATOR_RESYNC:
+        gst_iterator_resync (it);
+        break;
+      default:
+      case GST_ITERATOR_DONE:
+        done = TRUE;
+        break;
     }
   }
+  g_value_unset (&val);
+  gst_iterator_free (it);
+
+  GST_OBJECT_LOCK (bin);
+  if (!bin->clock_dirty) {
+    if (provider)
+      gst_object_unref (provider);
+    if (result)
+      gst_object_unref (result);
+    result = NULL;
+
+    goto not_dirty;
+  }
 
   provided_clock_p = &bin->provided_clock;
   clock_provider_p = &bin->clock_provider;
@@ -845,8 +827,6 @@ gst_bin_provide_clock_func (GstElement * element)
     gst_object_unref (provider);
   GST_OBJECT_UNLOCK (bin);
 
-  gst_iterator_free (it);
-
   return result;
 
 not_dirty:
@@ -1029,10 +1009,13 @@ is_eos (GstBin * bin, guint32 * seqnum)
 }
 
 static void
-unlink_pads (GstPad * pad)
+unlink_pads (const GValue * item, gpointer user_data)
 {
+  GstPad *pad;
   GstPad *peer;
 
+  pad = g_value_get_object (item);
+
   if ((peer = gst_pad_get_peer (pad))) {
     if (gst_pad_get_direction (pad) == GST_PAD_SRC)
       gst_pad_unlink (pad, peer);
@@ -1040,7 +1023,6 @@ unlink_pads (GstPad * pad)
       gst_pad_unlink (peer, pad);
     gst_object_unref (peer);
   }
-  gst_object_unref (pad);
 }
 
 /* vmethod that adds an element to a bin
@@ -1052,7 +1034,7 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
 {
   gchar *elem_name;
   GstIterator *it;
-  gboolean is_sink, is_source;
+  gboolean is_sink, is_source, provides_clock, requires_clock;
   GstMessage *clock_message = NULL, *async_message = NULL;
   GstStateChangeReturn ret;
 
@@ -1065,8 +1047,12 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
   /* get the element name to make sure it is unique in this bin. */
   GST_OBJECT_LOCK (element);
   elem_name = g_strdup (GST_ELEMENT_NAME (element));
-  is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK);
-  is_source = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SOURCE);
+  is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SINK);
+  is_source = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SOURCE);
+  provides_clock =
+      GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
+  requires_clock =
+      GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_REQUIRE_CLOCK);
   GST_OBJECT_UNLOCK (element);
 
   GST_OBJECT_LOCK (bin);
@@ -1087,17 +1073,22 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
   if (is_sink) {
     GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "element \"%s\" was sink",
         elem_name);
-    GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_IS_SINK);
+    GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_SINK);
   }
   if (is_source) {
     GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "element \"%s\" was source",
         elem_name);
-    GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_IS_SOURCE);
+    GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_SOURCE);
   }
-  if (gst_element_provides_clock (element)) {
+  if (provides_clock) {
     GST_DEBUG_OBJECT (bin, "element \"%s\" can provide a clock", elem_name);
     clock_message =
         gst_message_new_clock_provide (GST_OBJECT_CAST (element), NULL, TRUE);
+    GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
+  }
+  if (requires_clock) {
+    GST_DEBUG_OBJECT (bin, "element \"%s\" requires a clock", elem_name);
+    GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_REQUIRE_CLOCK);
   }
 
   bin->children = g_list_prepend (bin->children, element);
@@ -1115,9 +1106,12 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
    * that is not important right now. When the pipeline goes to PLAYING,
    * a new clock will be selected */
   gst_element_set_clock (element, GST_ELEMENT_CLOCK (bin));
+
+#if 0
   /* set the cached index on the children */
   if (bin->priv->index)
     gst_element_set_index (element, bin->priv->index);
+#endif
 
   ret = GST_STATE_RETURN (bin);
   /* no need to update the state if we are in error */
@@ -1135,13 +1129,12 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
     {
       /* create message to track this aync element when it posts an async-done
        * message */
-      async_message =
-          gst_message_new_async_start (GST_OBJECT_CAST (element), FALSE);
+      async_message = gst_message_new_async_start (GST_OBJECT_CAST (element));
       break;
     }
     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, FALSE, FALSE);
       break;
     case GST_STATE_CHANGE_FAILURE:
       break;
@@ -1162,15 +1155,16 @@ no_state_recalc:
 
   /* unlink all linked pads */
   it = gst_element_iterate_pads (element);
-  gst_iterator_foreach (it, (GFunc) unlink_pads, element);
+  gst_iterator_foreach (it, (GstIteratorForeachFunction) unlink_pads, NULL);
   gst_iterator_free (it);
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "added element \"%s\"",
       elem_name);
-  g_free (elem_name);
 
   g_signal_emit (bin, gst_bin_signals[ELEMENT_ADDED], 0, element);
-  gst_child_proxy_child_added ((GstObject *) bin, (GstObject *) element);
+  gst_child_proxy_child_added ((GObject *) bin, (GObject *) element, elem_name);
+
+  g_free (elem_name);
 
   return TRUE;
 
@@ -1263,7 +1257,8 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
 {
   gchar *elem_name;
   GstIterator *it;
-  gboolean is_sink, is_source, othersink, othersource, found;
+  gboolean is_sink, is_source, provides_clock, requires_clock;
+  gboolean othersink, othersource, otherprovider, otherrequirer, found;
   GstMessage *clock_message = NULL;
   GstClock **provided_clock_p;
   GstElement **clock_provider_p;
@@ -1276,25 +1271,32 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
   GST_OBJECT_LOCK (element);
   /* Check if the element is already being removed and immediately
    * return */
-  if (G_UNLIKELY (GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_UNPARENTING)))
+  if (G_UNLIKELY (GST_OBJECT_FLAG_IS_SET (element,
+              GST_ELEMENT_FLAG_UNPARENTING)))
     goto already_removing;
 
-  GST_OBJECT_FLAG_SET (element, GST_ELEMENT_UNPARENTING);
+  GST_OBJECT_FLAG_SET (element, GST_ELEMENT_FLAG_UNPARENTING);
   /* grab element name so we can print it */
   elem_name = g_strdup (GST_ELEMENT_NAME (element));
-  is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK);
-  is_source = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SOURCE);
+  is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SINK);
+  is_source = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SOURCE);
+  provides_clock =
+      GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
+  requires_clock =
+      GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_REQUIRE_CLOCK);
   GST_OBJECT_UNLOCK (element);
 
   /* unlink all linked pads */
   it = gst_element_iterate_pads (element);
-  gst_iterator_foreach (it, (GFunc) unlink_pads, element);
+  gst_iterator_foreach (it, (GstIteratorForeachFunction) unlink_pads, NULL);
   gst_iterator_free (it);
 
   GST_OBJECT_LOCK (bin);
   found = FALSE;
   othersink = FALSE;
   othersource = FALSE;
+  otherprovider = FALSE;
+  otherrequirer = FALSE;
   have_no_preroll = FALSE;
   /* iterate the elements, we collect which ones are async and no_preroll. We
    * also remove the element when we find it. */
@@ -1308,16 +1310,24 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
       /* remove the element */
       bin->children = g_list_delete_link (bin->children, walk);
     } else {
-      gboolean child_sink, child_source;
+      gboolean child_sink, child_source, child_provider, child_requirer;
 
       GST_OBJECT_LOCK (child);
-      child_sink = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_IS_SINK);
-      child_source = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_IS_SOURCE);
+      child_sink = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SINK);
+      child_source = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SOURCE);
+      child_provider =
+          GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
+      child_requirer =
+          GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_REQUIRE_CLOCK);
       /* when we remove a sink, check if there are other sinks. */
       if (is_sink && !othersink && child_sink)
         othersink = TRUE;
       if (is_source && !othersource && child_source)
         othersource = TRUE;
+      if (provides_clock && !otherprovider && child_provider)
+        otherprovider = TRUE;
+      if (requires_clock && !otherrequirer && child_requirer)
+        otherrequirer = TRUE;
       /* check if we have NO_PREROLL children */
       if (GST_STATE_RETURN (child) == GST_STATE_CHANGE_NO_PREROLL)
         have_no_preroll = TRUE;
@@ -1338,14 +1348,23 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
   if (is_sink && !othersink) {
     /* we're not a sink anymore */
     GST_DEBUG_OBJECT (bin, "we removed the last sink");
-    GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_IS_SINK);
+    GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_FLAG_SINK);
   }
   if (is_source && !othersource) {
     /* we're not a source anymore */
     GST_DEBUG_OBJECT (bin, "we removed the last source");
-    GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_IS_SOURCE);
+    GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_FLAG_SOURCE);
+  }
+  if (provides_clock && !otherprovider) {
+    /* we're not a clock provider anymore */
+    GST_DEBUG_OBJECT (bin, "we removed the last clock provider");
+    GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
+  }
+  if (requires_clock && !otherrequirer) {
+    /* we're not a clock requirer anymore */
+    GST_DEBUG_OBJECT (bin, "we removed the last clock requirer");
+    GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_FLAG_REQUIRE_CLOCK);
   }
-
 
   /* if the clock provider for this element is removed, we lost
    * the clock as well, we need to inform the parent of this
@@ -1435,7 +1454,7 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
     else
       ret = GST_STATE_CHANGE_SUCCESS;
 
-    bin_handle_async_done (bin, ret, FALSE);
+    bin_handle_async_done (bin, ret, FALSE, FALSE);
   } else {
     GST_DEBUG_OBJECT (bin,
         "recalc state preroll: %d, other async: %d, this async %d",
@@ -1462,7 +1481,6 @@ no_state_recalc:
 
   GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "removed child \"%s\"",
       elem_name);
-  g_free (elem_name);
 
   gst_element_set_bus (element, NULL);
 
@@ -1475,12 +1493,14 @@ no_state_recalc:
   gst_object_unparent (GST_OBJECT_CAST (element));
 
   GST_OBJECT_LOCK (element);
-  GST_OBJECT_FLAG_UNSET (element, GST_ELEMENT_UNPARENTING);
+  GST_OBJECT_FLAG_UNSET (element, GST_ELEMENT_FLAG_UNPARENTING);
   GST_OBJECT_UNLOCK (element);
 
   g_signal_emit (bin, gst_bin_signals[ELEMENT_REMOVED], 0, element);
-  gst_child_proxy_child_removed ((GstObject *) bin, (GstObject *) element);
+  gst_child_proxy_child_removed ((GObject *) bin, (GObject *) element,
+      elem_name);
 
+  g_free (elem_name);
   /* element is really out of our control now */
   gst_object_unref (element);
 
@@ -1553,13 +1573,6 @@ no_function:
   }
 }
 
-static GstIteratorItem
-iterate_child (GstIterator * it, GstElement * child)
-{
-  gst_object_ref (child);
-  return GST_ITERATOR_ITEM_PASS;
-}
-
 /**
  * gst_bin_iterate_elements:
  * @bin: a #GstBin
@@ -1581,26 +1594,19 @@ gst_bin_iterate_elements (GstBin * bin)
   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
 
   GST_OBJECT_LOCK (bin);
-  /* add ref because the iterator refs the bin. When the iterator
-   * is freed it will unref the bin again using the provided dispose
-   * function. */
-  gst_object_ref (bin);
   result = gst_iterator_new_list (GST_TYPE_ELEMENT,
       GST_OBJECT_GET_LOCK (bin),
-      &bin->children_cookie,
-      &bin->children,
-      bin,
-      (GstIteratorItemFunction) iterate_child,
-      (GstIteratorDisposeFunction) gst_object_unref);
+      &bin->children_cookie, &bin->children, (GObject *) bin, NULL);
   GST_OBJECT_UNLOCK (bin);
 
   return result;
 }
 
 static GstIteratorItem
-iterate_child_recurse (GstIterator * it, GstElement * child)
+iterate_child_recurse (GstIterator * it, const GValue * item)
 {
-  gst_object_ref (child);
+  GstElement *child = g_value_get_object (item);
+
   if (GST_IS_BIN (child)) {
     GstIterator *other = gst_bin_iterate_recurse (GST_BIN_CAST (child));
 
@@ -1631,17 +1637,11 @@ gst_bin_iterate_recurse (GstBin * bin)
   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
 
   GST_OBJECT_LOCK (bin);
-  /* add ref because the iterator refs the bin. When the iterator
-   * is freed it will unref the bin again using the provided dispose
-   * function. */
-  gst_object_ref (bin);
   result = gst_iterator_new_list (GST_TYPE_ELEMENT,
       GST_OBJECT_GET_LOCK (bin),
       &bin->children_cookie,
       &bin->children,
-      bin,
-      (GstIteratorItemFunction) iterate_child_recurse,
-      (GstIteratorDisposeFunction) gst_object_unref);
+      (GObject *) bin, (GstIteratorItemFunction) iterate_child_recurse);
   GST_OBJECT_UNLOCK (bin);
 
   return result;
@@ -1657,7 +1657,7 @@ bin_element_is_sink (GstElement * child, GstBin * bin)
   /* we lock the child here for the remainder of the function to
    * get its name and flag safely. */
   GST_OBJECT_LOCK (child);
-  is_sink = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_IS_SINK);
+  is_sink = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SINK);
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
       "child %s %s sink", GST_OBJECT_NAME (child), is_sink ? "is" : "is not");
@@ -1667,17 +1667,12 @@ bin_element_is_sink (GstElement * child, GstBin * bin)
 }
 
 static gint
-sink_iterator_filter (GstElement * child, GstBin * bin)
+sink_iterator_filter (const GValue * vchild, GValue * vbin)
 {
-  if (bin_element_is_sink (child, bin) == 0) {
-    /* returns 0 because this is a GCompareFunc */
-    return 0;
-  } else {
-    /* child carries a ref from gst_bin_iterate_elements -- drop if not passing
-       through */
-    gst_object_unref (child);
-    return 1;
-  }
+  GstBin *bin = g_value_get_object (vbin);
+  GstElement *child = g_value_get_object (vchild);
+
+  return (bin_element_is_sink (child, bin));
 }
 
 /**
@@ -1685,7 +1680,7 @@ sink_iterator_filter (GstElement * child, GstBin * bin)
  * @bin: a #GstBin
  *
  * Gets an iterator for all elements in the bin that have the
- * #GST_ELEMENT_IS_SINK flag set.
+ * #GST_ELEMENT_FLAG_SINK flag set.
  *
  * Each element yielded by the iterator will have its refcount increased, so
  * unref after use.
@@ -1699,12 +1694,18 @@ gst_bin_iterate_sinks (GstBin * bin)
 {
   GstIterator *children;
   GstIterator *result;
+  GValue vbin = { 0, };
 
   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
 
+  g_value_init (&vbin, GST_TYPE_BIN);
+  g_value_set_object (&vbin, bin);
+
   children = gst_bin_iterate_elements (bin);
   result = gst_iterator_filter (children,
-      (GCompareFunc) sink_iterator_filter, bin);
+      (GCompareFunc) sink_iterator_filter, &vbin);
+
+  g_value_unset (&vbin);
 
   return result;
 }
@@ -1719,7 +1720,7 @@ bin_element_is_src (GstElement * child, GstBin * bin)
   /* we lock the child here for the remainder of the function to
    * get its name and other info safely. */
   GST_OBJECT_LOCK (child);
-  is_src = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_IS_SOURCE);
+  is_src = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SOURCE);
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
       "child %s %s src", GST_OBJECT_NAME (child), is_src ? "is" : "is not");
@@ -1729,17 +1730,12 @@ bin_element_is_src (GstElement * child, GstBin * bin)
 }
 
 static gint
-src_iterator_filter (GstElement * child, GstBin * bin)
+src_iterator_filter (const GValue * vchild, GValue * vbin)
 {
-  if (bin_element_is_src (child, bin) == 0) {
-    /* returns 0 because this is a GCompareFunc */
-    return 0;
-  } else {
-    /* child carries a ref from gst_bin_iterate_elements -- drop if not passing
-       through */
-    gst_object_unref (child);
-    return 1;
-  }
+  GstBin *bin = g_value_get_object (vbin);
+  GstElement *child = g_value_get_object (vchild);
+
+  return (bin_element_is_src (child, bin));
 }
 
 /**
@@ -1747,7 +1743,7 @@ src_iterator_filter (GstElement * child, GstBin * bin)
  * @bin: a #GstBin
  *
  * Gets an iterator for all elements in the bin that have the
- * #GST_ELEMENT_IS_SOURCE flag set.
+ * #GST_ELEMENT_FLAG_SOURCE flag set.
  *
  * Each element yielded by the iterator will have its refcount increased, so
  * unref after use.
@@ -1761,12 +1757,18 @@ gst_bin_iterate_sources (GstBin * bin)
 {
   GstIterator *children;
   GstIterator *result;
+  GValue vbin = { 0, };
 
   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
 
+  g_value_init (&vbin, GST_TYPE_BIN);
+  g_value_set_object (&vbin, bin);
+
   children = gst_bin_iterate_elements (bin);
   result = gst_iterator_filter (children,
-      (GCompareFunc) src_iterator_filter, bin);
+      (GCompareFunc) src_iterator_filter, &vbin);
+
+  g_value_unset (&vbin);
 
   return result;
 }
@@ -1782,7 +1784,9 @@ gst_bin_get_state_func (GstElement * element, GstState * state,
 
   GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "getting state");
 
-  ret = parent_class->get_state (element, state, pending, timeout);
+  ret =
+      GST_ELEMENT_CLASS (parent_class)->get_state (element, state, pending,
+      timeout);
 
   return ret;
 }
@@ -1802,7 +1806,7 @@ gst_bin_get_state_func (GstElement * element, GstState * state,
 typedef struct _GstBinSortIterator
 {
   GstIterator it;
-  GQueue *queue;                /* elements queued for state change */
+  GQueue queue;                 /* elements queued for state change */
   GstBin *bin;                  /* bin we iterate */
   gint mode;                    /* adding or removing dependency */
   GstElement *best;             /* next element with least dependencies */
@@ -1811,6 +1815,26 @@ typedef struct _GstBinSortIterator
   gboolean dirty;               /* we detected structure change */
 } GstBinSortIterator;
 
+static void
+gst_bin_sort_iterator_copy (const GstBinSortIterator * it,
+    GstBinSortIterator * copy)
+{
+  GHashTableIter iter;
+  gpointer key, value;
+
+  copy->queue = it->queue;
+  g_queue_foreach (&copy->queue, (GFunc) gst_object_ref, NULL);
+
+  copy->bin = gst_object_ref (it->bin);
+  if (it->best)
+    copy->best = gst_object_ref (it->best);
+
+  copy->hash = g_hash_table_new (NULL, NULL);
+  g_hash_table_iter_init (&iter, it->hash);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    g_hash_table_insert (copy->hash, key, value);
+}
+
 /* we add and subtract 1 to make sure we don't confuse NULL and 0 */
 #define HASH_SET_DEGREE(bit, elem, deg) \
     g_hash_table_replace (bit->hash, elem, GINT_TO_POINTER(deg+1))
@@ -1826,7 +1850,7 @@ add_to_queue (GstBinSortIterator * bit, GstElement * element)
   GST_DEBUG_OBJECT (bit->bin, "adding '%s' to queue",
       GST_ELEMENT_NAME (element));
   gst_object_ref (element);
-  g_queue_push_tail (bit->queue, element);
+  g_queue_push_tail (&bit->queue, element);
   HASH_SET_DEGREE (bit, element, -1);
 }
 
@@ -1835,11 +1859,11 @@ remove_from_queue (GstBinSortIterator * bit, GstElement * element)
 {
   GList *find;
 
-  if ((find = g_queue_find (bit->queue, element))) {
+  if ((find = g_queue_find (&bit->queue, element))) {
     GST_DEBUG_OBJECT (bit->bin, "removing '%s' from queue",
         GST_ELEMENT_NAME (element));
 
-    g_queue_delete_link (bit->queue, find);
+    g_queue_delete_link (&bit->queue, find);
     gst_object_unref (element);
   } else {
     GST_DEBUG_OBJECT (bit->bin, "unable to remove '%s' from queue",
@@ -1870,7 +1894,7 @@ reset_degree (GstElement * element, GstBinSortIterator * bit)
 
   /* sinks are added right away */
   GST_OBJECT_LOCK (element);
-  is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK);
+  is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SINK);
   GST_OBJECT_UNLOCK (element);
 
   if (is_sink) {
@@ -1990,14 +2014,13 @@ find_element (GstElement * element, GstBinSortIterator * bit)
 /* get next element in iterator. the returned element has the
  * refcount increased */
 static GstIteratorResult
-gst_bin_sort_iterator_next (GstBinSortIterator * bit, gpointer * result)
+gst_bin_sort_iterator_next (GstBinSortIterator * bit, GValue * result)
 {
+  GstElement *best;
   GstBin *bin = bit->bin;
 
   /* empty queue, we have to find a next best element */
-  if (g_queue_is_empty (bit->queue)) {
-    GstElement *best;
-
+  if (g_queue_is_empty (&bit->queue)) {
     bit->best = NULL;
     bit->best_deg = G_MAXINT;
     g_list_foreach (bin->children, (GFunc) find_element, bit);
@@ -2013,9 +2036,8 @@ gst_bin_sort_iterator_next (GstBinSortIterator * bit, gpointer * result)
       /* best unhandled element, schedule as next element */
       GST_DEBUG_OBJECT (bin, "queue empty, next best: %s",
           GST_ELEMENT_NAME (best));
-      gst_object_ref (best);
       HASH_SET_DEGREE (bit, best, -1);
-      *result = best;
+      g_value_set_object (result, best);
     } else {
       GST_DEBUG_OBJECT (bin, "queue empty, elements exhausted");
       /* no more unhandled elements, we are done */
@@ -2023,12 +2045,14 @@ gst_bin_sort_iterator_next (GstBinSortIterator * bit, gpointer * result)
     }
   } else {
     /* everything added to the queue got reffed */
-    *result = g_queue_pop_head (bit->queue);
+    best = g_queue_pop_head (&bit->queue);
+    g_value_set_object (result, best);
+    gst_object_unref (best);
   }
 
-  GST_DEBUG_OBJECT (bin, "queue head gives %s", GST_ELEMENT_NAME (*result));
+  GST_DEBUG_OBJECT (bin, "queue head gives %s", GST_ELEMENT_NAME (best));
   /* update degrees of linked elements */
-  update_degree (GST_ELEMENT_CAST (*result), bit);
+  update_degree (best, bit);
 
   return GST_ITERATOR_OK;
 }
@@ -2041,7 +2065,7 @@ gst_bin_sort_iterator_resync (GstBinSortIterator * bit)
 
   GST_DEBUG_OBJECT (bin, "resync");
   bit->dirty = FALSE;
-  clear_queue (bit->queue);
+  clear_queue (&bit->queue);
   /* reset degrees */
   g_list_foreach (bin->children, (GFunc) reset_degree, bit);
   /* calc degrees, incrementing */
@@ -2058,11 +2082,9 @@ gst_bin_sort_iterator_free (GstBinSortIterator * bit)
   GstBin *bin = bit->bin;
 
   GST_DEBUG_OBJECT (bin, "free");
-  clear_queue (bit->queue);
-  g_queue_free (bit->queue);
+  clear_queue (&bit->queue);
   g_hash_table_destroy (bit->hash);
   gst_object_unref (bin);
-  g_free (bit);
 }
 
 /* should be called with the bin LOCK held */
@@ -2078,11 +2100,12 @@ gst_bin_sort_iterator_new (GstBin * bin)
       GST_TYPE_ELEMENT,
       GST_OBJECT_GET_LOCK (bin),
       &bin->priv->structure_cookie,
+      (GstIteratorCopyFunction) gst_bin_sort_iterator_copy,
       (GstIteratorNextFunction) gst_bin_sort_iterator_next,
       (GstIteratorItemFunction) NULL,
       (GstIteratorResyncFunction) gst_bin_sort_iterator_resync,
       (GstIteratorFreeFunction) gst_bin_sort_iterator_free);
-  result->queue = g_queue_new ();
+  g_queue_init (&result->queue);
   result->hash = g_hash_table_new (NULL, NULL);
   gst_object_ref (bin);
   result->bin = bin;
@@ -2140,7 +2163,7 @@ gst_bin_element_set_state (GstBin * bin, GstElement * element,
   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);
+  locked = GST_ELEMENT_IS_LOCKED_STATE (element);
   /* Get the previous set_state result to preserve NO_PREROLL and ASYNC */
   ret = GST_STATE_RETURN (element);
   child_current = GST_STATE (element);
@@ -2185,18 +2208,9 @@ gst_bin_element_set_state (GstBin * bin, GstElement * element,
     if (next > current) {
       /* We found an async element check if we can force its state to change or
        * if we have to wait for it to preroll. */
-      if (G_UNLIKELY (!enable_latency)) {
-        g_warning ("Future versions of GStreamer will wait for element \"%s\"\n"
-            "\tto preroll in order to perform correct latency calculations.\n"
-            "\tPlease verify that the application continues to work correctly by\n"
-            "\tsetting the environment variable GST_COMPAT to a value containing\n"
-            "\tthe string 'live-preroll'.", GST_ELEMENT_NAME (element));
-        goto no_latency;
-      }
       goto was_busy;
     }
   }
-no_latency:
   GST_OBJECT_UNLOCK (bin);
 
 no_preroll:
@@ -2244,17 +2258,14 @@ unneeded:
 /* gst_iterator_fold functions for pads_activate
  * Stop the iterator if activating one pad failed. */
 static gboolean
-activate_pads (GstPad * pad, GValue * ret, gboolean * active)
+activate_pads (const GValue * vpad, GValue * ret, gboolean * active)
 {
+  GstPad *pad = g_value_get_object (vpad);
   gboolean cont = TRUE;
 
   if (!(cont = gst_pad_set_active (pad, *active)))
     g_value_set_boolean (ret, FALSE);
-  else if (!*active)
-    gst_pad_set_caps (pad, NULL);
 
-  /* unref the object that was reffed for us by _fold */
-  gst_object_unref (pad);
   return cont;
 }
 
@@ -2427,6 +2438,7 @@ gst_bin_change_state_func (GstElement * element, GstStateChange transition)
   GstClockTime base_time, start_time;
   GstIterator *it;
   gboolean done;
+  GValue data = { 0, };
 
   /* we don't need to take the STATE_LOCK, it is already taken */
   current = (GstState) GST_STATE_TRANSITION_CURRENT (transition);
@@ -2505,14 +2517,12 @@ restart:
 
   done = FALSE;
   while (!done) {
-    gpointer data;
-
     switch (gst_iterator_next (it, &data)) {
       case GST_ITERATOR_OK:
       {
         GstElement *child;
 
-        child = GST_ELEMENT_CAST (data);
+        child = g_value_get_object (&data);
 
         /* set state and base_time now */
         ret = gst_bin_element_set_state (bin, child, base_time, start_time,
@@ -2548,7 +2558,6 @@ restart:
             parent = gst_object_get_parent (GST_OBJECT_CAST (child));
             if (parent == GST_OBJECT_CAST (element)) {
               /* element is still in bin, really error now */
-              gst_object_unref (child);
               gst_object_unref (parent);
               goto done;
             }
@@ -2574,7 +2583,7 @@ restart:
             g_assert_not_reached ();
             break;
         }
-        gst_object_unref (child);
+        g_value_reset (&data);
         break;
       }
       case GST_ITERATOR_RESYNC:
@@ -2589,7 +2598,7 @@ restart:
     }
   }
 
-  ret = parent_class->change_state (element, transition);
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
   if (G_UNLIKELY (ret == GST_STATE_CHANGE_FAILURE))
     goto done;
 
@@ -2606,6 +2615,7 @@ restart:
   }
 
 done:
+  g_value_unset (&data);
   gst_iterator_free (it);
 
   GST_OBJECT_LOCK (bin);
@@ -2638,7 +2648,7 @@ done:
     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, FALSE, FALSE);
   }
 
 state_end:
@@ -2679,6 +2689,7 @@ gst_bin_send_event (GstElement * element, GstEvent * event)
   GstIterator *iter;
   gboolean res = TRUE;
   gboolean done = FALSE;
+  GValue data = { 0, };
 
   if (GST_EVENT_IS_DOWNSTREAM (event)) {
     iter = gst_bin_iterate_sources (bin);
@@ -2691,19 +2702,15 @@ gst_bin_send_event (GstElement * element, GstEvent * event)
   }
 
   while (!done) {
-    gpointer data;
-
     switch (gst_iterator_next (iter, &data)) {
       case GST_ITERATOR_OK:
       {
-        GstElement *child;
+        GstElement *child = g_value_get_object (&data);;
 
         gst_event_ref (event);
-        child = GST_ELEMENT_CAST (data);
         res &= gst_element_send_event (child, event);
         GST_LOG_OBJECT (child, "After handling %s event: %d",
             GST_EVENT_TYPE_NAME (event), res);
-        gst_object_unref (child);
         break;
       }
       case GST_ITERATOR_RESYNC:
@@ -2718,6 +2725,7 @@ gst_bin_send_event (GstElement * element, GstEvent * event)
         break;
     }
   }
+  g_value_unset (&data);
   gst_iterator_free (iter);
   gst_event_unref (event);
 
@@ -2816,7 +2824,7 @@ bin_push_state_continue (BinContinueData * data)
  * This function is called with the OBJECT lock.
  */
 static void
-bin_handle_async_start (GstBin * bin, gboolean new_base_time)
+bin_handle_async_start (GstBin * bin)
 {
   GstState old_state, new_state;
   gboolean toplevel;
@@ -2832,8 +2840,7 @@ bin_handle_async_start (GstBin * bin, gboolean new_base_time)
    * are busy with a state change or when we are NO_PREROLL. */
   if (!toplevel)
     /* non toplevel bin, prepare async-start for the parent */
-    amessage =
-        gst_message_new_async_start (GST_OBJECT_CAST (bin), new_base_time);
+    amessage = gst_message_new_async_start (GST_OBJECT_CAST (bin));
 
   if (bin->polling || GST_STATE_PENDING (bin) != GST_STATE_VOID_PENDING)
     goto was_busy;
@@ -2900,7 +2907,7 @@ was_no_preroll:
  */
 static void
 bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret,
-    gboolean flag_pending)
+    gboolean flag_pending, gboolean reset_time)
 {
   GstState current, pending, target;
   GstStateChangeReturn old_ret;
@@ -2928,7 +2935,7 @@ bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret,
   target = GST_STATE_TARGET (bin);
   pending = GST_STATE_PENDING (bin) = target;
 
-  amessage = gst_message_new_async_done (GST_OBJECT_CAST (bin));
+  amessage = gst_message_new_async_done (GST_OBJECT_CAST (bin), reset_time);
 
   old_state = GST_STATE (bin);
   /* this is the state we should go to next */
@@ -3051,6 +3058,16 @@ bin_do_eos (GstBin * bin)
       && g_atomic_int_compare_and_exchange (&bin->priv->posted_eos, FALSE,
           TRUE)) {
     GstMessage *tmessage;
+
+    /* Clear out any further messages, and reset posted_eos so we can
+       detect any new EOS that happens (eg, after a seek). Since all
+       sinks have now posted an EOS, there will be no further EOS events
+       seen unless there is a new logical EOS */
+    GST_OBJECT_LOCK (bin);
+    bin_remove_messages (bin, NULL, GST_MESSAGE_EOS);
+    bin->priv->posted_eos = FALSE;
+    GST_OBJECT_UNLOCK (bin);
+
     tmessage = gst_message_new_eos (GST_OBJECT_CAST (bin));
     gst_message_set_seqnum (tmessage, seqnum);
     GST_DEBUG_OBJECT (bin,
@@ -3318,14 +3335,11 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
     }
     case GST_MESSAGE_ASYNC_START:
     {
-      gboolean new_base_time;
       GstState target;
 
       GST_DEBUG_OBJECT (bin, "ASYNC_START message %p, %s", message,
           src ? GST_OBJECT_NAME (src) : "(NULL)");
 
-      gst_message_parse_async_start (message, &new_base_time);
-
       GST_OBJECT_LOCK (bin);
       bin_do_message_forward (bin, message);
 
@@ -3336,7 +3350,7 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
       /* takes ownership of the message */
       bin_replace_message (bin, message, GST_MESSAGE_ASYNC_START);
 
-      bin_handle_async_start (bin, new_base_time);
+      bin_handle_async_start (bin);
       GST_OBJECT_UNLOCK (bin);
       break;
 
@@ -3351,11 +3365,14 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
     }
     case GST_MESSAGE_ASYNC_DONE:
     {
+      gboolean reset_time;
       GstState target;
 
       GST_DEBUG_OBJECT (bin, "ASYNC_DONE message %p, %s", message,
           src ? GST_OBJECT_NAME (src) : "(NULL)");
 
+      gst_message_parse_async_done (message, &reset_time);
+
       GST_OBJECT_LOCK (bin);
       bin_do_message_forward (bin, message);
 
@@ -3376,7 +3393,7 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
          * 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);
+        bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, TRUE, reset_time);
       } else {
         GST_DEBUG_OBJECT (bin, "there are more async elements pending");
       }
@@ -3457,8 +3474,10 @@ bin_query_min_max_init (GstBin * bin, QueryFold * fold)
 }
 
 static gboolean
-bin_query_duration_fold (GstElement * item, GValue * ret, QueryFold * fold)
+bin_query_duration_fold (const GValue * vitem, GValue * ret, QueryFold * fold)
 {
+  GstElement *item = g_value_get_object (vitem);
+
   if (gst_element_query (item, fold->query)) {
     gint64 duration;
 
@@ -3472,7 +3491,6 @@ bin_query_duration_fold (GstElement * item, GValue * ret, QueryFold * fold)
       fold->max = duration;
   }
 
-  gst_object_unref (item);
   return TRUE;
 }
 
@@ -3487,18 +3505,18 @@ bin_query_duration_done (GstBin * bin, QueryFold * fold)
 
   GST_DEBUG_OBJECT (bin, "max duration %" G_GINT64_FORMAT, fold->max);
 
-#ifdef DURATION_CACHING
   /* and cache now */
   GST_OBJECT_LOCK (bin);
   bin->messages = g_list_prepend (bin->messages,
       gst_message_new_duration (GST_OBJECT_CAST (bin), format, fold->max));
   GST_OBJECT_UNLOCK (bin);
-#endif
 }
 
 static gboolean
-bin_query_position_fold (GstElement * item, GValue * ret, QueryFold * fold)
+bin_query_position_fold (const GValue * vitem, GValue * ret, QueryFold * fold)
 {
+  GstElement *item = g_value_get_object (vitem);
+
   if (gst_element_query (item, fold->query)) {
     gint64 position;
 
@@ -3512,7 +3530,6 @@ bin_query_position_fold (GstElement * item, GValue * ret, QueryFold * fold)
       fold->max = position;
   }
 
-  gst_object_unref (item);
   return TRUE;
 }
 
@@ -3529,8 +3546,10 @@ bin_query_position_done (GstBin * bin, QueryFold * fold)
 }
 
 static gboolean
-bin_query_latency_fold (GstElement * item, GValue * ret, QueryFold * fold)
+bin_query_latency_fold (const GValue * vitem, GValue * ret, QueryFold * fold)
 {
+  GstElement *item = g_value_get_object (vitem);
+
   if (gst_element_query (item, fold->query)) {
     GstClockTime min, max;
     gboolean live;
@@ -3558,7 +3577,6 @@ bin_query_latency_fold (GstElement * item, GValue * ret, QueryFold * fold)
     GST_DEBUG_OBJECT (item, "failed query");
   }
 
-  gst_object_unref (item);
   return TRUE;
 }
 
@@ -3576,8 +3594,9 @@ bin_query_latency_done (GstBin * bin, QueryFold * fold)
 
 /* generic fold, return first valid result */
 static gboolean
-bin_query_generic_fold (GstElement * item, GValue * ret, QueryFold * fold)
+bin_query_generic_fold (const GValue * vitem, GValue * ret, QueryFold * fold)
 {
+  GstElement *item = g_value_get_object (vitem);
   gboolean res;
 
   if ((res = gst_element_query (item, fold->query))) {
@@ -3585,8 +3604,6 @@ bin_query_generic_fold (GstElement * item, GValue * ret, QueryFold * fold)
     GST_DEBUG_OBJECT (item, "answered query %p", fold->query);
   }
 
-  gst_object_unref (item);
-
   /* and stop as soon as we have a valid result */
   return !res;
 }
@@ -3606,7 +3623,6 @@ gst_bin_query (GstElement * element, GstQuery * query)
   switch (GST_QUERY_TYPE (query)) {
     case GST_QUERY_DURATION:
     {
-#ifdef DURATION_CACHING
       GList *cached;
       GstFormat qformat;
 
@@ -3637,7 +3653,6 @@ gst_bin_query (GstElement * element, GstQuery * query)
         }
       }
       GST_OBJECT_UNLOCK (bin);
-#endif
       /* no cached value found, iterate and collect durations */
       fold_func = (GstIteratorFoldFunction) bin_query_duration_fold;
       fold_init = bin_query_min_max_init;
@@ -3703,26 +3718,22 @@ gst_bin_query (GstElement * element, GstQuery * query)
 done:
   gst_iterator_free (iter);
 
-#ifdef DURATION_CACHING
 exit:
-#endif
   GST_DEBUG_OBJECT (bin, "query %p result %d", query, res);
 
   return res;
 }
 
 static gint
-compare_name (GstElement * element, const gchar * name)
+compare_name (const GValue * velement, const gchar * name)
 {
   gint eq;
+  GstElement *element = g_value_get_object (velement);
 
   GST_OBJECT_LOCK (element);
   eq = strcmp (GST_ELEMENT_NAME (element), name);
   GST_OBJECT_UNLOCK (element);
 
-  if (eq != 0) {
-    gst_object_unref (element);
-  }
   return eq;
 }
 
@@ -3744,7 +3755,9 @@ GstElement *
 gst_bin_get_by_name (GstBin * bin, const gchar * name)
 {
   GstIterator *children;
-  gpointer result;
+  GValue result = { 0, };
+  GstElement *element;
+  gboolean found;
 
   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
 
@@ -3752,11 +3765,18 @@ gst_bin_get_by_name (GstBin * bin, const gchar * name)
       GST_ELEMENT_NAME (bin), name);
 
   children = gst_bin_iterate_recurse (bin);
-  result = gst_iterator_find_custom (children,
-      (GCompareFunc) compare_name, (gpointer) name);
+  found = gst_iterator_find_custom (children,
+      (GCompareFunc) compare_name, &result, (gpointer) name);
   gst_iterator_free (children);
 
-  return GST_ELEMENT_CAST (result);
+  if (found) {
+    element = g_value_dup_object (&result);
+    g_value_unset (&result);
+  } else {
+    element = NULL;
+  }
+
+  return element;
 }
 
 /**
@@ -3800,17 +3820,15 @@ gst_bin_get_by_name_recurse_up (GstBin * bin, const gchar * name)
 }
 
 static gint
-compare_interface (GstElement * element, gpointer interface)
+compare_interface (const GValue * velement, GValue * interface)
 {
-  GType interface_type = (GType) interface;
+  GstElement *element = g_value_get_object (velement);
+  GType interface_type = (GType) g_value_get_pointer (interface);
   gint ret;
 
   if (G_TYPE_CHECK_INSTANCE_TYPE (element, interface_type)) {
     ret = 0;
   } else {
-    /* we did not find the element, need to release the ref
-     * added by the iterator */
-    gst_object_unref (element);
     ret = 1;
   }
   return ret;
@@ -3835,17 +3853,31 @@ GstElement *
 gst_bin_get_by_interface (GstBin * bin, GType iface)
 {
   GstIterator *children;
-  gpointer result;
+  GValue result = { 0, };
+  GstElement *element;
+  gboolean found;
+  GValue viface = { 0, };
 
   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
   g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface), NULL);
 
+  g_value_init (&viface, G_TYPE_POINTER);
+  g_value_set_pointer (&viface, (gpointer) iface);
+
   children = gst_bin_iterate_recurse (bin);
-  result = gst_iterator_find_custom (children, (GCompareFunc) compare_interface,
-      (gpointer) iface);
+  found = gst_iterator_find_custom (children, (GCompareFunc) compare_interface,
+      &result, &viface);
   gst_iterator_free (children);
 
-  return GST_ELEMENT_CAST (result);
+  if (found) {
+    element = g_value_dup_object (&result);
+    g_value_unset (&result);
+  } else {
+    element = NULL;
+  }
+  g_value_unset (&viface);
+
+  return element;
 }
 
 /**
@@ -3871,68 +3903,19 @@ gst_bin_iterate_all_by_interface (GstBin * bin, GType iface)
 {
   GstIterator *children;
   GstIterator *result;
+  GValue viface = { 0, };
 
   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
   g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface), NULL);
 
+  g_value_init (&viface, G_TYPE_POINTER);
+  g_value_set_pointer (&viface, (gpointer) iface);
+
   children = gst_bin_iterate_recurse (bin);
   result = gst_iterator_filter (children, (GCompareFunc) compare_interface,
-      (gpointer) iface);
+      &viface);
 
-  return result;
-}
+  g_value_unset (&viface);
 
-#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
-static xmlNodePtr
-gst_bin_save_thyself (GstObject * object, xmlNodePtr parent)
-{
-  GstBin *bin = GST_BIN_CAST (object);
-  xmlNodePtr childlist, elementnode;
-  GList *children;
-  GstElement *child;
-
-  if (GST_OBJECT_CLASS (parent_class)->save_thyself)
-    GST_OBJECT_CLASS (parent_class)->save_thyself (GST_OBJECT (bin), parent);
-
-  childlist = xmlNewChild (parent, NULL, (xmlChar *) "children", NULL);
-
-  GST_CAT_INFO (GST_CAT_XML, "[%s]: saving %d children",
-      GST_ELEMENT_NAME (bin), bin->numchildren);
-
-  children = g_list_last (bin->children);
-  while (children) {
-    child = GST_ELEMENT_CAST (children->data);
-    elementnode = xmlNewChild (childlist, NULL, (xmlChar *) "element", NULL);
-    gst_object_save_thyself (GST_OBJECT (child), elementnode);
-    children = g_list_previous (children);
-  }
-  return childlist;
-}
-
-static void
-gst_bin_restore_thyself (GstObject * object, xmlNodePtr self)
-{
-  GstBin *bin = GST_BIN_CAST (object);
-  xmlNodePtr field = self->xmlChildrenNode;
-  xmlNodePtr childlist;
-
-  while (field) {
-    if (!strcmp ((char *) field->name, "children")) {
-      GST_CAT_INFO (GST_CAT_XML, "[%s]: loading children",
-          GST_ELEMENT_NAME (object));
-      childlist = field->xmlChildrenNode;
-      while (childlist) {
-        if (!strcmp ((char *) childlist->name, "element")) {
-          /* gst_xml_make_element will gst_bin_add() the element to ourself */
-          gst_xml_make_element (childlist, GST_OBJECT (bin));
-        }
-        childlist = childlist->next;
-      }
-    }
-
-    field = field->next;
-  }
-  if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
-    (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
+  return result;
 }
-#endif /* GST_DISABLE_LOADSAVE */