]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gstreamer0-10.git/blobdiff - gst/gstelement.c
gstelement: add gst_element_class_add_pad_template_from_static
[glsdk/gstreamer0-10.git] / gst / gstelement.c
index ca7d813b5c636f36fc137da448e778fca7ea0da6..afa25b9d3717cbe247c5606cf9bbd57e73886cc7 100644 (file)
  * Core and plug-in writers can add and remove pads with gst_element_add_pad()
  * and gst_element_remove_pad().
  *
- * A pad of an element can be retrieved by name with gst_element_get_pad().
+ * An existing pad of an element can be retrieved by name with
+ * gst_element_get_static_pad(). A new dynamic pad can be created using
+ * gst_element_request_pad() with a #GstPadTemplate or 
+ * gst_element_get_request_pad() with the template name such as "src_\%d".
  * An iterator of all pads can be retrieved with gst_element_iterate_pads().
  *
  * Elements can be linked through their pads.
@@ -56,8 +59,8 @@
  *
  * Each element has a state (see #GstState).  You can get and set the state
  * of an element with gst_element_get_state() and gst_element_set_state().
- * To get a string representation of a #GstState, use
- * gst_element_state_get_name().
+ * Setting a state triggers a #GstStateChange. To get a string representation
+ * of a #GstState, use gst_element_state_get_name().
  *
  * You can get and set a #GstClock on an element using gst_element_get_clock()
  * and gst_element_set_clock().
@@ -73,7 +76,7 @@
  * toplevel #GstPipeline so the clock functions are only to be used in very
  * specific situations.
  *
- * Last reviewed on 2006-03-12 (0.10.5)
+ * Last reviewed on 2009-05-29 (0.10.24)
  */
 
 #include "gst_private.h"
@@ -82,6 +85,7 @@
 #include <gobject/gvaluecollector.h>
 
 #include "gstelement.h"
+#include "gstelementdetails.h"
 #include "gstenumtypes.h"
 #include "gstbus.h"
 #include "gstmarshal.h"
@@ -89,6 +93,7 @@
 #include "gstevent.h"
 #include "gstutils.h"
 #include "gstinfo.h"
+#include "gstvalue.h"
 #include "gst-i18n-lib.h"
 
 /* Element signals and args */
@@ -107,9 +112,15 @@ enum
       /* FILL ME */
 };
 
-extern void __gst_element_details_clear (GstElementDetails * dp);
-extern void __gst_element_details_copy (GstElementDetails * dest,
-    const GstElementDetails * src);
+#ifdef GST_DISABLE_DEPRECATED
+#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
+#include <libxml/parser.h>
+xmlNodePtr gst_object_save_thyself (const GstObject * object,
+    xmlNodePtr parent);
+GstObject *gst_object_load_thyself (xmlNodePtr parent);
+void gst_pad_load_and_link (xmlNodePtr self, GstObject * parent);
+#endif
+#endif
 
 static void gst_element_class_init (GstElementClass * klass);
 static void gst_element_init (GstElement * element);
@@ -136,7 +147,7 @@ static GstPadTemplate
     * gst_element_class_get_request_pad_template (GstElementClass *
     element_class, const gchar * name);
 
-#ifndef GST_DISABLE_LOADSAVE
+#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
 static xmlNodePtr gst_element_save_thyself (GstObject * object,
     xmlNodePtr parent);
 static void gst_element_restore_thyself (GstObject * parent, xmlNodePtr self);
@@ -145,12 +156,16 @@ static void gst_element_restore_thyself (GstObject * parent, xmlNodePtr self);
 static GstObjectClass *parent_class = NULL;
 static guint gst_element_signals[LAST_SIGNAL] = { 0 };
 
+/* this is used in gstelementfactory.c:gst_element_register() */
+GQuark _gst_elementclass_factory = 0;
+
 GType
 gst_element_get_type (void)
 {
-  static GType gst_element_type = 0;
+  static volatile gsize gst_element_type = 0;
 
-  if (G_UNLIKELY (gst_element_type == 0)) {
+  if (g_once_init_enter (&gst_element_type)) {
+    GType _type;
     static const GTypeInfo element_info = {
       sizeof (GstElementClass),
       gst_element_base_class_init,
@@ -164,8 +179,12 @@ gst_element_get_type (void)
       NULL
     };
 
-    gst_element_type = g_type_register_static (GST_TYPE_OBJECT, "GstElement",
+    _type = g_type_register_static (GST_TYPE_OBJECT, "GstElement",
         &element_info, G_TYPE_FLAG_ABSTRACT);
+
+    _gst_elementclass_factory =
+        g_quark_from_static_string ("GST_ELEMENTCLASS_FACTORY");
+    g_once_init_leave (&gst_element_type, _type);
   }
   return gst_element_type;
 }
@@ -173,11 +192,10 @@ gst_element_get_type (void)
 static void
 gst_element_class_init (GstElementClass * klass)
 {
-  GObjectClass *gobject_class;
-  GstObjectClass *gstobject_class;
-
-  gobject_class = (GObjectClass *) klass;
-  gstobject_class = (GstObjectClass *) klass;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
+  GstObjectClass *gstobject_class = (GstObjectClass *) klass;
+#endif
 
   parent_class = g_type_class_peek_parent (klass);
 
@@ -186,7 +204,11 @@ gst_element_class_init (GstElementClass * klass)
    * @gstelement: the object which received the signal
    * @new_pad: the pad that has been added
    *
-   * a new #GstPad has been added to the element.
+   * a new #GstPad has been added to the element. Note that this signal will
+   * usually be emitted from the context of the streaming thread. Also keep in
+   * mind that if you add new elements to the pipeline in the signal handler
+   * you will need to set them to the desired target state with
+   * gst_element_set_state() or gst_element_sync_state_with_parent().
    */
   gst_element_signals[PAD_ADDED] =
       g_signal_new ("pad-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
@@ -208,19 +230,24 @@ gst_element_class_init (GstElementClass * klass)
    * @gstelement: the object which received the signal
    *
    * This signals that the element will not generate more dynamic pads.
+   * Note that this signal will usually be emitted from the context of
+   * the streaming thread.
    */
   gst_element_signals[NO_MORE_PADS] =
       g_signal_new ("no-more-pads", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstElementClass, no_more_pads), NULL,
       NULL, gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
 
-  gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_element_dispose);
-  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_element_finalize);
+  gobject_class->dispose = gst_element_dispose;
+  gobject_class->finalize = gst_element_finalize;
 
-#ifndef GST_DISABLE_LOADSAVE
-  gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_element_save_thyself);
+#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
+  gstobject_class->save_thyself =
+      ((gpointer (*)(GstObject * object,
+              gpointer self)) * GST_DEBUG_FUNCPTR (gst_element_save_thyself));
   gstobject_class->restore_thyself =
-      GST_DEBUG_FUNCPTR (gst_element_restore_thyself);
+      ((void (*)(GstObject * object,
+              gpointer self)) *GST_DEBUG_FUNCPTR (gst_element_restore_thyself));
 #endif
 
   klass->change_state = GST_DEBUG_FUNCPTR (gst_element_change_state_func);
@@ -239,8 +266,25 @@ gst_element_base_class_init (gpointer g_class)
 {
   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
 
+  /* FIXME 0.11: Copy the element details and instead of clearing the
+   * pad template list copy the list and increase the refcount of
+   * the pad templates by one.
+   *
+   * This will make it possible to add pad templates and set element
+   * details in the class_init functions and is the real GObject way
+   * of doing things.
+   * See http://bugzilla.gnome.org/show_bug.cgi?id=491501
+   */
   memset (&element_class->details, 0, sizeof (GstElementDetails));
+  element_class->meta_data = NULL;
   element_class->padtemplates = NULL;
+
+  /* set the factory, see gst_element_register() */
+  element_class->elementfactory =
+      g_type_get_qdata (G_TYPE_FROM_CLASS (element_class),
+      _gst_elementclass_factory);
+  GST_DEBUG ("type %s : factory %p", G_OBJECT_CLASS_NAME (element_class),
+      element_class->elementfactory);
 }
 
 static void
@@ -251,6 +295,10 @@ gst_element_base_class_finalize (gpointer g_class)
   g_list_foreach (klass->padtemplates, (GFunc) gst_object_unref, NULL);
   g_list_free (klass->padtemplates);
   __gst_element_details_clear (&klass->details);
+  if (klass->meta_data) {
+    gst_structure_free (klass->meta_data);
+    klass->meta_data = NULL;
+  }
 }
 
 static void
@@ -262,38 +310,12 @@ gst_element_init (GstElement * element)
   GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
   GST_STATE_RETURN (element) = GST_STATE_CHANGE_SUCCESS;
 
-  element->state_lock = g_new0 (GStaticRecMutex, 1);
+  /* FIXME 0.11: Store this directly in the instance struct */
+  element->state_lock = g_slice_new (GStaticRecMutex);
   g_static_rec_mutex_init (element->state_lock);
   element->state_cond = g_cond_new ();
 }
 
-/**
- * gst_element_default_error:
- * @object: a #GObject that signalled the error.
- * @orig: the #GstObject that initiated the error.
- * @error: the GError.
- * @debug: an additional debug information string, or %NULL.
- *
- * A default error signal callback to attach to an element.
- * The user data passed to the g_signal_connect is ignored.
- *
- * The default handler will simply print the error string using g_print.
- *
- * MT safe.
- */
-void
-gst_element_default_error (GObject * object, GstObject * source, GError * error,
-    gchar * debug)
-{
-  gchar *name = gst_object_get_path_string (source);
-
-  g_print (_("ERROR: from element %s: %s\n"), name, error->message);
-  if (debug)
-    g_print (_("Additional debug info:\n%s\n"), debug);
-
-  g_free (name);
-}
-
 /**
  * gst_element_release_request_pad:
  * @element: a #GstElement to release the request pad of.
@@ -302,6 +324,10 @@ gst_element_default_error (GObject * object, GstObject * source, GError * error,
  * Makes the element free the previously requested pad as obtained
  * with gst_element_get_request_pad().
  *
+ * This does not unref the pad. If the pad was created by using
+ * gst_element_get_request_pad(), gst_element_release_request_pad() needs to be
+ * followed by gst_object_unref() to free the @pad.
+ *
  * MT safe.
  */
 void
@@ -378,7 +404,7 @@ gst_element_provides_clock (GstElement * element)
  * <note>An element is only required to provide a clock in the PAUSED
  * state. Some elements can provide a clock in other states.</note>
  *
- * Returns: the GstClock provided by the element or %NULL
+ * Returns: (transfer full): the GstClock provided by the element or %NULL
  * if no clock could be provided.  Unref after usage.
  *
  * MT safe.
@@ -422,10 +448,11 @@ gst_element_set_clock (GstElement * element, GstClock * clock)
   GstClock **clock_p;
 
   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+  g_return_val_if_fail (clock == NULL || GST_IS_CLOCK (clock), FALSE);
 
   oclass = GST_ELEMENT_GET_CLASS (element);
 
-  GST_DEBUG_OBJECT (element, "setting clock %p", clock);
+  GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, element, "setting clock %p", clock);
 
   if (oclass->set_clock)
     res = oclass->set_clock (element, clock);
@@ -447,7 +474,7 @@ gst_element_set_clock (GstElement * element, GstClock * clock)
  * Gets the currently configured clock of the element. This is the clock as was
  * last set with gst_element_set_clock().
  *
- * Returns: the #GstClock of the element. unref after usage.
+ * Returns: (transfer full): the #GstClock of the element. unref after usage.
  *
  * MT safe.
  */
@@ -478,14 +505,18 @@ gst_element_get_clock (GstElement * element)
 void
 gst_element_set_base_time (GstElement * element, GstClockTime time)
 {
+  GstClockTime old;
+
   g_return_if_fail (GST_IS_ELEMENT (element));
 
   GST_OBJECT_LOCK (element);
+  old = element->base_time;
   element->base_time = time;
   GST_OBJECT_UNLOCK (element);
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, element,
-      "set base_time=%" GST_TIME_FORMAT, GST_TIME_ARGS (time));
+      "set base_time=%" GST_TIME_FORMAT ", old %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (time), GST_TIME_ARGS (old));
 }
 
 /**
@@ -495,7 +526,7 @@ gst_element_set_base_time (GstElement * element, GstClockTime time)
  * Returns the base time of the element. The base time is the
  * absolute time of the clock when this element was last put to
  * PLAYING. Subtracting the base time from the clock time gives
- * the stream time of the element.
+ * the running time of the element.
  *
  * Returns: the base time of the element.
  *
@@ -515,7 +546,73 @@ gst_element_get_base_time (GstElement * element)
   return result;
 }
 
-#ifndef GST_DISABLE_INDEX
+/**
+ * gst_element_set_start_time:
+ * @element: a #GstElement.
+ * @time: the base time to set.
+ *
+ * Set the start time of an element. The start time of the element is the
+ * running time of the element when it last went to the PAUSED state. In READY
+ * or after a flushing seek, it is set to 0.
+ *
+ * Toplevel elements like #GstPipeline will manage the start_time and
+ * base_time on its children. Setting the start_time to #GST_CLOCK_TIME_NONE
+ * on such a toplevel element will disable the distribution of the base_time to
+ * the children and can be useful if the application manages the base_time
+ * itself, for example if you want to synchronize capture from multiple
+ * pipelines, and you can also ensure that the pipelines have the same clock.
+ *
+ * MT safe.
+ *
+ * Since: 0.10.24
+ */
+void
+gst_element_set_start_time (GstElement * element, GstClockTime time)
+{
+  GstClockTime old;
+
+  g_return_if_fail (GST_IS_ELEMENT (element));
+
+  GST_OBJECT_LOCK (element);
+  old = GST_ELEMENT_START_TIME (element);
+  GST_ELEMENT_START_TIME (element) = time;
+  GST_OBJECT_UNLOCK (element);
+
+  GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, element,
+      "set start_time=%" GST_TIME_FORMAT ", old %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (time), GST_TIME_ARGS (old));
+}
+
+/**
+ * gst_element_get_start_time:
+ * @element: a #GstElement.
+ *
+ * Returns the start time of the element. The start time is the
+ * running time of the clock when this element was last put to PAUSED.
+ *
+ * Usually the start_time is managed by a toplevel element such as
+ * #GstPipeline.
+ *
+ * MT safe.
+ *
+ * Returns: the start time of the element.
+ *
+ * Since: 0.10.24
+ */
+GstClockTime
+gst_element_get_start_time (GstElement * element)
+{
+  GstClockTime result;
+
+  g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_TIME_NONE);
+
+  GST_OBJECT_LOCK (element);
+  result = GST_ELEMENT_START_TIME (element);
+  GST_OBJECT_UNLOCK (element);
+
+  return result;
+}
+
 /**
  * gst_element_is_indexable:
  * @element: a #GstElement.
@@ -541,7 +638,7 @@ gst_element_is_indexable (GstElement * element)
 /**
  * gst_element_set_index:
  * @element: a #GstElement.
- * @index: a #GstIndex.
+ * @index: (transfer none): a #GstIndex.
  *
  * Set @index on the element. The refcount of the index
  * will be increased, any previously set index is unreffed.
@@ -554,7 +651,7 @@ gst_element_set_index (GstElement * element, GstIndex * index)
   GstElementClass *oclass;
 
   g_return_if_fail (GST_IS_ELEMENT (element));
-  g_return_if_fail (GST_IS_INDEX (index));
+  g_return_if_fail (index == NULL || GST_IS_INDEX (index));
 
   oclass = GST_ELEMENT_GET_CLASS (element);
 
@@ -568,7 +665,7 @@ gst_element_set_index (GstElement * element, GstIndex * index)
  *
  * Gets the index from the element.
  *
- * Returns: a #GstIndex or %NULL when no index was set on the
+ * Returns: (transfer full): a #GstIndex or %NULL when no index was set on the
  * element. unref after usage.
  *
  * MT safe.
@@ -588,12 +685,11 @@ gst_element_get_index (GstElement * element)
 
   return result;
 }
-#endif
 
 /**
  * gst_element_add_pad:
  * @element: a #GstElement to add the pad to.
- * @pad: the #GstPad to add to the element.
+ * @pad: (transfer full): the #GstPad to add to the element.
  *
  * Adds a pad (link point) to @element. @pad's parent will be set to @element;
  * see gst_object_set_parent() for refcounting information.
@@ -642,7 +738,8 @@ gst_element_add_pad (GstElement * element, GstPad * pad)
   /* check for flushing pads */
   if (flushing && (GST_STATE (element) > GST_STATE_READY ||
           GST_STATE_NEXT (element) == GST_STATE_PAUSED)) {
-    g_warning ("adding flushing pad '%s' to running element '%s'",
+    g_warning ("adding flushing pad '%s' to running element '%s', you need to "
+        "use gst_pad_set_active(pad,TRUE) before adding it.",
         GST_STR_NULL (pad_name), GST_ELEMENT_NAME (element));
     /* unset flushing */
     GST_OBJECT_LOCK (pad);
@@ -708,7 +805,7 @@ no_direction:
 /**
  * gst_element_remove_pad:
  * @element: a #GstElement to remove pad from.
- * @pad: the #GstPad to remove from the element.
+ * @pad: (transfer none): the #GstPad to remove from the element.
  *
  * Removes @pad from @element. @pad will be destroyed if it has not been
  * referenced elsewhere using gst_object_unparent().
@@ -844,8 +941,8 @@ pad_compare_name (GstPad * pad1, const gchar * name)
  * Retrieves a pad from @element by name. This version only retrieves
  * already-existing (i.e. 'static') pads.
  *
- * Returns: the requested #GstPad if found, otherwise %NULL. unref after
- * usage.
+ * Returns: (transfer full): the requested #GstPad if found, otherwise %NULL.
+ *     unref after usage.
  *
  * MT safe.
  */
@@ -879,15 +976,66 @@ gst_element_get_static_pad (GstElement * element, const gchar * name)
 }
 
 static GstPad *
-gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
-    const gchar * name)
+_gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
+    const gchar * name, const GstCaps * caps)
 {
   GstPad *newpad = NULL;
   GstElementClass *oclass;
 
   oclass = GST_ELEMENT_GET_CLASS (element);
 
-  if (oclass->request_new_pad)
+#ifndef G_DISABLE_CHECKS
+  /* Some sanity checking here */
+  if (name) {
+    GstPad *pad;
+
+    /* Is this the template name? */
+    if (strstr (name, "%") || !strchr (templ->name_template, '%')) {
+      g_return_val_if_fail (strcmp (name, templ->name_template) == 0, NULL);
+    } else {
+      const gchar *str, *data;
+      gchar *endptr;
+
+      /* Otherwise check if it's a valid name for the name template */
+      str = strchr (templ->name_template, '%');
+      g_return_val_if_fail (str != NULL, NULL);
+      g_return_val_if_fail (strncmp (templ->name_template, name,
+              str - templ->name_template) == 0, NULL);
+      g_return_val_if_fail (strlen (name) > str - templ->name_template, NULL);
+
+      data = name + (str - templ->name_template);
+
+      /* Can either be %s or %d or %u, do sanity checking for %d */
+      if (*(str + 1) == 'd') {
+        gint64 tmp;
+
+        /* it's an int */
+        tmp = g_ascii_strtoll (data, &endptr, 10);
+        g_return_val_if_fail (tmp >= G_MININT && tmp <= G_MAXINT
+            && *endptr == '\0', NULL);
+      } else if (*(str + 1) == 'u') {
+        guint64 tmp;
+
+        /* it's an int */
+        tmp = g_ascii_strtoull (data, &endptr, 10);
+        g_return_val_if_fail (tmp <= G_MAXUINT && *endptr == '\0', NULL);
+      }
+    }
+
+    pad = gst_element_get_static_pad (element, name);
+    if (pad) {
+      gst_object_unref (pad);
+      /* FIXME 0.11: Change this to g_return_val_if_fail() */
+      g_critical ("Element %s already has a pad named %s, the behaviour of "
+          " gst_element_get_request_pad() for existing pads is undefined!",
+          GST_ELEMENT_NAME (element), name);
+    }
+  }
+#endif
+
+  if (oclass->request_new_pad_full)
+    newpad = (oclass->request_new_pad_full) (element, templ, name, caps);
+  else if (oclass->request_new_pad)
     newpad = (oclass->request_new_pad) (element, templ, name);
 
   if (newpad)
@@ -901,11 +1049,15 @@ gst_element_request_pad (GstElement * element, GstPadTemplate * templ,
  * @element: a #GstElement to find a request pad of.
  * @name: the name of the request #GstPad to retrieve.
  *
- * Retrieves a pad from the element by name. This version only retrieves
- * request pads. The pad should be released with
+ * Retrieves a pad from the element by name (e.g. "src_\%d"). This version only
+ * retrieves request pads. The pad should be released with
  * gst_element_release_request_pad().
  *
- * Returns: requested #GstPad if found, otherwise %NULL. Release after usage.
+ * This method is slow and will be deprecated in the future. New code should
+ * use gst_element_request_pad() with the requested template.
+ *
+ * Returns: (transfer full): requested #GstPad if found, otherwise %NULL.
+ *     Release after usage.
  */
 GstPad *
 gst_element_get_request_pad (GstElement * element, const gchar * name)
@@ -915,7 +1067,6 @@ gst_element_get_request_pad (GstElement * element, const gchar * name)
   const gchar *req_name = NULL;
   gboolean templ_found = FALSE;
   GList *list;
-  gint n;
   const gchar *data;
   gchar *str, *endptr = NULL;
   GstElementClass *class;
@@ -934,7 +1085,7 @@ gst_element_get_request_pad (GstElement * element, const gchar * name)
       templ_found = TRUE;
   } else {
     /* there is no % in the name, try to find a matching template */
-    list = gst_element_class_get_pad_template_list (class);
+    list = class->padtemplates;
     while (!templ_found && list) {
       templ = (GstPadTemplate *) list->data;
       if (templ->presence == GST_PAD_REQUEST) {
@@ -947,7 +1098,7 @@ gst_element_get_request_pad (GstElement * element, const gchar * name)
           break;
         }
         /* Because of sanity checks in gst_pad_template_new(), we know that %s
-           and %d, occurring at the end of the name_template, are the only
+           and %d and %u, occurring at the end of the name_template, are the only
            possibilities. */
         else if ((str = strchr (templ->name_template, '%'))
             && strncmp (templ->name_template, name,
@@ -955,9 +1106,22 @@ gst_element_get_request_pad (GstElement * element, const gchar * name)
             && strlen (name) > str - templ->name_template) {
           data = name + (str - templ->name_template);
           if (*(str + 1) == 'd') {
+            glong tmp;
+
             /* it's an int */
-            n = (gint) strtol (data, &endptr, 10);
-            if (endptr && *endptr == '\0') {
+            tmp = strtol (data, &endptr, 10);
+            if (tmp != G_MINLONG && tmp != G_MAXLONG && endptr &&
+                *endptr == '\0') {
+              templ_found = TRUE;
+              req_name = name;
+              break;
+            }
+          } else if (*(str + 1) == 'u') {
+            gulong tmp;
+
+            /* it's an int */
+            tmp = strtoul (data, &endptr, 10);
+            if (tmp != G_MAXULONG && endptr && *endptr == '\0') {
               templ_found = TRUE;
               req_name = name;
               break;
@@ -977,11 +1141,45 @@ gst_element_get_request_pad (GstElement * element, const gchar * name)
   if (!templ_found)
     return NULL;
 
-  pad = gst_element_request_pad (element, templ, req_name);
+  pad = _gst_element_request_pad (element, templ, req_name, NULL);
 
   return pad;
 }
 
+/**
+ * gst_element_request_pad:
+ * @element: a #GstElement to find a request pad of.
+ * @templ: a #GstPadTemplate of which we want a pad of.
+ * @name: (transfer none) (allow-none): the name of the request #GstPad
+ * to retrieve. Can be %NULL.
+ * @caps: (transfer none) (allow-none): the caps of the pad we want to
+ * request. Can be %NULL.
+ *
+ * Retrieves a request pad from the element according to the provided template.
+ * Pad templates can be looked up using
+ * gst_element_factory_get_static_pad_templates().
+ *
+ * If the @caps are specified and the element implements thew new
+ * request_new_pad_full virtual method, the element will use them to select
+ * which pad to create.
+ *
+ * The pad should be released with gst_element_release_request_pad().
+ *
+ * Returns: (transfer full): requested #GstPad if found, otherwise %NULL.
+ *     Release after usage.
+ *
+ * Since: 0.10.32
+ */
+GstPad *
+gst_element_request_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
+{
+  g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
+  g_return_val_if_fail (templ != NULL, NULL);
+
+  return _gst_element_request_pad (element, templ, name, caps);
+}
+
 /**
  * gst_element_get_pad:
  * @element: a #GstElement.
@@ -990,13 +1188,18 @@ gst_element_get_request_pad (GstElement * element, const gchar * name)
  * Retrieves a pad from @element by name. Tries gst_element_get_static_pad()
  * first, then gst_element_get_request_pad().
  *
- * <note>Usage of this function is not recommended as it is unclear if the reference
+ * Deprecated: This function is deprecated as it's unclear if the reference
  * to the result pad should be released with gst_object_unref() in case of a static pad
- * or gst_element_release_request_pad() in case of a request pad.</note>
+ * or gst_element_release_request_pad() in case of a request pad.
+ * Use gst_element_get_static_pad() or gst_element_get_request_pad() instead.
  *
- * Returns: the #GstPad if found, otherwise %NULL. Unref or Release after usage,
+ * Returns: (transfer full): the #GstPad if found, otherwise %NULL. Unref or Release after usage,
  * depending on the type of the pad.
  */
+#ifndef GST_REMOVE_DEPRECATED
+#ifdef GST_DISABLE_DEPRECATED
+GstPad *gst_element_get_pad (GstElement * element, const gchar * name);
+#endif
 GstPad *
 gst_element_get_pad (GstElement * element, const gchar * name)
 {
@@ -1011,6 +1214,7 @@ gst_element_get_pad (GstElement * element, const gchar * name)
 
   return pad;
 }
+#endif /* GST_REMOVE_DEPRECATED */
 
 static GstIteratorItem
 iterate_pad (GstIterator * it, GstPad * pad)
@@ -1042,10 +1246,12 @@ gst_element_iterate_pad_list (GstElement * element, GList ** padlist)
  * gst_element_iterate_pads:
  * @element: a #GstElement to iterate pads of.
  *
- * Retrieves an iterattor of @element's pads. The iterator should
- * be freed after usage.
+ * Retrieves an iterator of @element's pads. The iterator should
+ * be freed after usage. Also more specialized iterators exists such as
+ * gst_element_iterate_src_pads() or gst_element_iterate_sink_pads().
  *
- * Returns: the #GstIterator of #GstPad. Unref each pad after use.
+ * Returns: (transfer full): the #GstIterator of #GstPad. Unref each pad
+ *     after use.
  *
  * MT safe.
  */
@@ -1063,7 +1269,8 @@ gst_element_iterate_pads (GstElement * element)
  *
  * Retrieves an iterator of @element's source pads.
  *
- * Returns: the #GstIterator of #GstPad. Unref each pad after use.
+ * Returns: (transfer full): the #GstIterator of #GstPad. Unref each pad
+ *     after use.
  *
  * MT safe.
  */
@@ -1081,7 +1288,8 @@ gst_element_iterate_src_pads (GstElement * element)
  *
  * Retrieves an iterator of @element's sink pads.
  *
- * Returns: the #GstIterator of #GstPad. Unref each pad after use.
+ * Returns: (transfer full): the #GstIterator of #GstPad. Unref each pad
+ *     after use.
  *
  * MT safe.
  */
@@ -1096,7 +1304,7 @@ gst_element_iterate_sink_pads (GstElement * element)
 /**
  * gst_element_class_add_pad_template:
  * @klass: the #GstElementClass to add the pad template to.
- * @templ: a #GstPadTemplate to add to the element class.
+ * @templ: (transfer none): a #GstPadTemplate to add to the element class.
  *
  * Adds a padtemplate to an element class. This is mainly used in the _base_init
  * functions of classes.
@@ -1108,6 +1316,12 @@ gst_element_class_add_pad_template (GstElementClass * klass,
   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
   g_return_if_fail (GST_IS_PAD_TEMPLATE (templ));
 
+  /* FIXME 0.11: allow replacing the pad templates by
+   * calling this with the same name as an already existing pad
+   * template. For this we _must_ _not_ ref the added pad template
+   * a second time and _must_ document that this function takes
+   * ownership of the pad template. Otherwise we will leak pad templates
+   * or the caller unref's the pad template and it disappears */
   /* avoid registering pad templates with the same name */
   g_return_if_fail (gst_element_class_get_pad_template (klass,
           templ->name_template) == NULL);
@@ -1117,6 +1331,82 @@ gst_element_class_add_pad_template (GstElementClass * klass,
   klass->numpadtemplates++;
 }
 
+/**
+ * gst_element_class_add_static_pad_template:
+ * @klass: the #GstElementClass to add the pad template to.
+ * @templ: (transfer none): a #GstStaticPadTemplate describing the pad
+ * to add to the element class.
+ *
+ * Adds a padtemplate to an element class. This is mainly used in the _base_init
+ * functions of classes.
+ *
+ * Since: 0.10.36
+ */
+void
+gst_element_class_add_static_pad_template (GstElementClass * klass,
+    GstStaticPadTemplate * templ)
+{
+  GstPadTemplate *pt;
+
+  g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
+
+  pt = gst_static_pad_template_get (templ);
+  gst_element_class_add_pad_template (klass, pt);
+  gst_object_unref (pt);
+}
+
+static void
+gst_element_class_add_meta_data (GstElementClass * klass,
+    const gchar * key, const gchar * value)
+{
+  if (!klass->meta_data) {
+    /* FIXME: use a quark for "metadata" */
+    klass->meta_data = gst_structure_empty_new ("metadata");
+  }
+
+  gst_structure_set ((GstStructure *) klass->meta_data,
+      key, G_TYPE_STRING, value, NULL);
+}
+
+/**
+ * gst_element_class_set_documentation_uri:
+ * @klass: class to set details for
+ * @uri: uri of element documentation
+ *
+ * Set uri pointing to user documentation. Applications can use this to show
+ * help for e.g. effects to users.
+ *
+ * Since: 0.10.31
+ */
+void
+gst_element_class_set_documentation_uri (GstElementClass * klass,
+    const gchar * uri)
+{
+  g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
+
+  gst_element_class_add_meta_data (klass, "doc-uri", uri);
+}
+
+/**
+ * gst_element_class_set_icon_name:
+ * @klass: class to set details for
+ * @name: name of an icon
+ *
+ * Elements that bridge to certain other products can include an icon of that
+ * used product. Application can show the icon in menus/selectors to help
+ * identifying specific elements.
+ *
+ * Since: 0.10.31
+ */
+void
+gst_element_class_set_icon_name (GstElementClass * klass, const gchar * name)
+{
+  g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
+
+  gst_element_class_add_meta_data (klass, "icon-name", name);
+}
+
+/* FIXME-0.11: deprecate and remove gst_element_class_set_details*() */
 /**
  * gst_element_class_set_details:
  * @klass: class to set details for
@@ -1126,7 +1416,14 @@ gst_element_class_add_pad_template (GstElementClass * klass,
  * <note>This function is for use in _base_init functions only.</note>
  *
  * The @details are copied.
+ *
+ * Deprecated: Use gst_element_class_set_details_simple() instead.
  */
+#ifndef GST_REMOVE_DEPRECATED
+#ifdef GST_DISABLE_DEPRECATED
+void gst_element_class_set_details (GstElementClass * klass,
+    const GstElementDetails * details);
+#endif
 void
 gst_element_class_set_details (GstElementClass * klass,
     const GstElementDetails * details)
@@ -1136,6 +1433,7 @@ gst_element_class_set_details (GstElementClass * klass,
 
   __gst_element_details_copy (&klass->details, details);
 }
+#endif
 
 /**
  * gst_element_class_set_details_simple:
@@ -1144,12 +1442,12 @@ gst_element_class_set_details (GstElementClass * klass,
  * @classification: String describing the type of element, as an unordered list
  * separated with slashes ('/'). See draft-klass.txt of the design docs
  * for more details and common types. E.g: "Sink/File"
- * @description: Sentence describing the purpose of the element. 
+ * @description: Sentence describing the purpose of the element.
  * E.g: "Write stream to a file"
- * @author: Name and contact details of the author(s). Use \n to separate 
+ * @author: Name and contact details of the author(s). Use \n to separate
  * multiple author details. E.g: "Joe Bloggs &lt;joe.blogs at foo.com&gt;"
  *
- * Sets the detailed information for a #GstElementClass. Simpler version of 
+ * Sets the detailed information for a #GstElementClass. Simpler version of
  * gst_element_class_set_details() that generates less linker overhead.
  * <note>This function is for use in _base_init functions only.</note>
  *
@@ -1182,7 +1480,8 @@ gst_element_class_set_details_simple (GstElementClass * klass,
  * that has subclasses, make sure to pass the g_class parameter of the
  * #GInstanceInitFunc here.</note>
  *
- * Returns: the #GList of padtemplates.
+ * Returns: (transfer none) (element-type Gst.PadTemplate): the #GList of
+ *     pad templates.
  */
 GList *
 gst_element_class_get_pad_template_list (GstElementClass * element_class)
@@ -1202,19 +1501,19 @@ gst_element_class_get_pad_template_list (GstElementClass * element_class)
  * that has subclasses, make sure to pass the g_class parameter of the
  * #GInstanceInitFunc here.</note>
  *
- * Returns: the #GstPadTemplate with the given name, or %NULL if none was found.
- * No unreferencing is necessary.
+ * Returns: (transfer none): the #GstPadTemplate with the given name, or %NULL
+ *     if none was found. No unreferencing is necessary.
  */
 GstPadTemplate *
-gst_element_class_get_pad_template (GstElementClass * element_class,
-    const gchar * name)
+gst_element_class_get_pad_template (GstElementClass *
+    element_class, const gchar * name)
 {
   GList *padlist;
 
   g_return_val_if_fail (GST_IS_ELEMENT_CLASS (element_class), NULL);
   g_return_val_if_fail (name != NULL, NULL);
 
-  padlist = gst_element_class_get_pad_template_list (element_class);
+  padlist = element_class->padtemplates;
 
   while (padlist) {
     GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data;
@@ -1229,8 +1528,8 @@ gst_element_class_get_pad_template (GstElementClass * element_class,
 }
 
 static GstPadTemplate *
-gst_element_class_get_request_pad_template (GstElementClass * element_class,
-    const gchar * name)
+gst_element_class_get_request_pad_template (GstElementClass *
+    element_class, const gchar * name)
 {
   GstPadTemplate *tmpl;
 
@@ -1245,8 +1544,8 @@ gst_element_class_get_request_pad_template (GstElementClass * element_class,
  * The pad is random in a sense that it is the first pad that is (optionaly) linked.
  */
 static GstPad *
-gst_element_get_random_pad (GstElement * element, gboolean need_linked,
-    GstPadDirection dir)
+gst_element_get_random_pad (GstElement * element,
+    gboolean need_linked, GstPadDirection dir)
 {
   GstPad *result = NULL;
   GList *pads;
@@ -1325,6 +1624,7 @@ gst_element_default_send_event (GstElement * element, GstEvent * event)
   } else {
     GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "can't send %s event on element %s",
         GST_EVENT_TYPE_NAME (event), GST_ELEMENT_NAME (element));
+    gst_event_unref (event);
   }
   return result;
 }
@@ -1332,7 +1632,7 @@ gst_element_default_send_event (GstElement * element, GstEvent * event)
 /**
  * gst_element_send_event:
  * @element: a #GstElement to send the event to.
- * @event: the #GstEvent to send to the element.
+ * @event: (transfer full): the #GstEvent to send to the element.
  *
  * Sends an event to an element. If the element doesn't implement an
  * event handler, the event will be pushed on a random linked sink pad for
@@ -1477,7 +1777,7 @@ gst_element_default_query (GstElement * element, GstQuery * query)
 /**
  * gst_element_query:
  * @element: a #GstElement to perform the query on.
- * @query: the #GstQuery.
+ * @query: (transfer none): the #GstQuery.
  *
  * Performs a query on the given element.
  *
@@ -1485,6 +1785,8 @@ gst_element_default_query (GstElement * element, GstQuery * query)
  * forwards the query to a random srcpad or to the peer of a
  * random linked sinkpad of this element.
  *
+ * Please note that some queries might need a running pipeline to work.
+ *
  * Returns: TRUE if the query could be performed.
  *
  * MT safe.
@@ -1513,7 +1815,7 @@ gst_element_query (GstElement * element, GstQuery * query)
 /**
  * gst_element_post_message:
  * @element: a #GstElement posting the message
- * @message: a #GstMessage to post
+ * @message: (transfer full): a #GstMessage to post
  *
  * Post a message on the element's #GstBus. This function takes ownership of the
  * message; if you want to access the message after this call, you should add an
@@ -1566,7 +1868,8 @@ no_bus:
  *
  * This function is only used internally by the gst_element_error() macro.
  *
- * Returns: a newly allocated string, or %NULL if the format was %NULL or ""
+ * Returns: (transfer full): a newly allocated string, or %NULL if the format
+ *     was %NULL or ""
  *
  * MT safe.
  */
@@ -1593,10 +1896,12 @@ _gst_element_error_printf (const gchar * format, ...)
  * @type:     the #GstMessageType
  * @domain:   the GStreamer GError domain this message belongs to
  * @code:     the GError code belonging to the domain
- * @text:     an allocated text string to be used as a replacement for the
- *            default message connected to code, or %NULL
- * @debug:    an allocated debug message to be used as a replacement for the
- *            default debugging information, or %NULL
+ * @text:     (allow-none) (transfer full): an allocated text string to be used
+ *            as a replacement for the default message connected to code,
+ *            or %NULL
+ * @debug:    (allow-none) (transfer full): an allocated debug message to be
+ *            used as a replacement for the default debugging information,
+ *            or %NULL
  * @file:     the source code file where the error was generated
  * @function: the source code function where the error was generated
  * @line:     the source code line where the error was generated
@@ -1621,7 +1926,7 @@ void gst_element_message_full
   GstMessage *message = NULL;
 
   /* checks */
-  GST_DEBUG_OBJECT (element, "start");
+  GST_CAT_DEBUG_OBJECT (GST_CAT_MESSAGE, element, "start");
   g_return_if_fail (GST_IS_ELEMENT (element));
   g_return_if_fail ((type == GST_MESSAGE_ERROR) ||
       (type == GST_MESSAGE_WARNING) || (type == GST_MESSAGE_INFO));
@@ -1752,7 +2057,8 @@ gst_element_set_locked_state (GstElement * element, gboolean locked_state)
 
 was_ok:
   {
-    GST_CAT_DEBUG (GST_CAT_STATES, "elements %s was in locked state %d",
+    GST_CAT_DEBUG (GST_CAT_STATES,
+        "elements %s was already in locked state %d",
         GST_ELEMENT_NAME (element), old);
     GST_OBJECT_UNLOCK (element);
 
@@ -1820,6 +2126,7 @@ failed:
     GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
         "syncing state failed (%s)",
         gst_element_state_change_return_get_name (ret));
+    gst_object_unref (parent);
     return FALSE;
   }
 }
@@ -1840,11 +2147,11 @@ gst_element_get_state_func (GstElement * element,
   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "RETURN is %s",
       gst_element_state_change_return_get_name (ret));
 
-  /* we got an error, report immediatly */
+  /* we got an error, report immediately */
   if (ret == GST_STATE_CHANGE_FAILURE)
     goto done;
 
-  /* we got no_preroll, report immediatly */
+  /* we got no_preroll, report immediately */
   if (ret == GST_STATE_CHANGE_NO_PREROLL)
     goto done;
 
@@ -1870,7 +2177,7 @@ gst_element_get_state_func (GstElement * element,
     } else {
       timeval = NULL;
     }
-    /* get cookie to dected state change during waiting */
+    /* get cookie to detect state changes during waiting */
     cookie = element->state_cookie;
 
     GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
@@ -1934,9 +2241,10 @@ interrupted:
 /**
  * gst_element_get_state:
  * @element: a #GstElement to get the state of.
- * @state: a pointer to #GstState to hold the state. Can be %NULL.
- * @pending: a pointer to #GstState to hold the pending state.
- *           Can be %NULL.
+ * @state: (out) (allow-none): a pointer to #GstState to hold the state.
+ *     Can be %NULL.
+ * @pending: (out) (allow-none): a pointer to #GstState to hold the pending
+ *     state. Can be %NULL.
  * @timeout: a #GstClockTime to specify the timeout for an async
  *           state change or %GST_CLOCK_TIME_NONE for infinite timeout.
  *
@@ -1954,8 +2262,8 @@ interrupted:
  *
  * This function returns %GST_STATE_CHANGE_NO_PREROLL if the element
  * successfully changed its state but is not able to provide data yet.
- * This mostly happens for live sources that only produce data in the PLAYING
- * state. While the state change return is equivalent to
+ * This mostly happens for live sources that only produce data in
+ * %GST_STATE_PLAYING. While the state change return is equivalent to
  * %GST_STATE_CHANGE_SUCCESS, it is returned to the application to signal that
  * some sink elements might not be able to complete their state change because
  * an element is not producing data to complete the preroll. When setting the
@@ -2038,6 +2346,28 @@ nothing_aborted:
   }
 }
 
+/* Not static because GstBin has manual state handling too */
+void
+_priv_gst_element_state_changed (GstElement * element, GstState oldstate,
+    GstState newstate, GstState pending)
+{
+  GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
+  GstMessage *message;
+
+  GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
+      "notifying about state-changed %s to %s (%s pending)",
+      gst_element_state_get_name (oldstate),
+      gst_element_state_get_name (newstate),
+      gst_element_state_get_name (pending));
+
+  if (klass->state_changed)
+    klass->state_changed (element, oldstate, newstate, pending);
+
+  message = gst_message_new_state_changed (GST_OBJECT_CAST (element),
+      oldstate, newstate, pending);
+  gst_element_post_message (element, message);
+}
+
 /**
  * gst_element_continue_state:
  * @element: a #GstElement to continue the state change of.
@@ -2065,7 +2395,6 @@ gst_element_continue_state (GstElement * element, GstStateChangeReturn ret)
   GstStateChangeReturn old_ret;
   GstState old_state, old_next;
   GstState current, next, pending;
-  GstMessage *message;
   GstStateChange transition;
 
   GST_OBJECT_LOCK (element);
@@ -2096,14 +2425,12 @@ gst_element_continue_state (GstElement * element, GstStateChangeReturn ret)
   GST_OBJECT_UNLOCK (element);
 
   GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
-      "committing state from %s to %s, pending %s",
+      "committing state from %s to %s, pending %s, next %s",
       gst_element_state_get_name (old_state),
       gst_element_state_get_name (old_next),
-      gst_element_state_get_name (pending));
+      gst_element_state_get_name (pending), gst_element_state_get_name (next));
 
-  message = gst_message_new_state_changed (GST_OBJECT_CAST (element),
-      old_state, old_next, pending);
-  gst_element_post_message (element, message);
+  _priv_gst_element_state_changed (element, old_state, old_next, pending);
 
   GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
       "continue state change %s to %s, final %s",
@@ -2135,16 +2462,9 @@ complete:
      * previous return value.
      * We do signal the cond though as a _get_state() might be blocking
      * on it. */
-    if (old_state != old_next || old_ret == GST_STATE_CHANGE_ASYNC) {
-      GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
-          "posting state-changed %s to %s",
-          gst_element_state_get_name (old_state),
-          gst_element_state_get_name (old_next));
-      message =
-          gst_message_new_state_changed (GST_OBJECT_CAST (element), old_state,
-          old_next, GST_STATE_VOID_PENDING);
-      gst_element_post_message (element, message);
-    }
+    if (old_state != old_next || old_ret == GST_STATE_CHANGE_ASYNC)
+      _priv_gst_element_state_changed (element, old_state, old_next,
+          GST_STATE_VOID_PENDING);
 
     GST_STATE_BROADCAST (element);
 
@@ -2153,15 +2473,16 @@ complete:
 }
 
 /**
- * gst_element_lost_state:
+ * gst_element_lost_state_full:
  * @element: a #GstElement the state is lost of
+ * @new_base_time: if a new base time should be distributed
  *
  * Brings the element to the lost state. The current state of the
  * element is copied to the pending state so that any call to
  * gst_element_get_state() will return %GST_STATE_CHANGE_ASYNC.
  *
- * An ASYNC_START message is posted with an indication to distribute a new
- * base_time to the element.
+ * An ASYNC_START message is posted with indication to distribute a new
+ * base_time to the element when @new_base_time is %TRUE.
  * If the element was PLAYING, it will go to PAUSED. The element
  * will be restored to its PLAYING state by the parent pipeline when it
  * prerolls again.
@@ -2176,9 +2497,11 @@ complete:
  * plugins or applications.
  *
  * MT safe.
+ *
+ * Since: 0.10.24
  */
 void
-gst_element_lost_state (GstElement * element)
+gst_element_lost_state_full (GstElement * element, gboolean new_base_time)
 {
   GstState old_state, new_state;
   GstMessage *message;
@@ -2186,10 +2509,12 @@ gst_element_lost_state (GstElement * element)
   g_return_if_fail (GST_IS_ELEMENT (element));
 
   GST_OBJECT_LOCK (element);
-  if (GST_STATE_PENDING (element) != GST_STATE_VOID_PENDING ||
-      GST_STATE_RETURN (element) == GST_STATE_CHANGE_FAILURE)
+  if (GST_STATE_RETURN (element) == GST_STATE_CHANGE_FAILURE)
     goto nothing_lost;
 
+  if (GST_STATE_PENDING (element) != GST_STATE_VOID_PENDING)
+    goto only_async_start;
+
   old_state = GST_STATE (element);
 
   /* when we were PLAYING, the new state is PAUSED. We will also not
@@ -2208,13 +2533,14 @@ gst_element_lost_state (GstElement * element)
   GST_STATE_NEXT (element) = new_state;
   GST_STATE_PENDING (element) = new_state;
   GST_STATE_RETURN (element) = GST_STATE_CHANGE_ASYNC;
+  if (new_base_time)
+    GST_ELEMENT_START_TIME (element) = 0;
   GST_OBJECT_UNLOCK (element);
 
-  message = gst_message_new_state_changed (GST_OBJECT_CAST (element),
-      new_state, new_state, new_state);
-  gst_element_post_message (element, message);
+  _priv_gst_element_state_changed (element, new_state, new_state, new_state);
 
-  message = gst_message_new_async_start (GST_OBJECT_CAST (element), TRUE);
+  message =
+      gst_message_new_async_start (GST_OBJECT_CAST (element), new_base_time);
   gst_element_post_message (element, message);
 
   return;
@@ -2224,6 +2550,32 @@ nothing_lost:
     GST_OBJECT_UNLOCK (element);
     return;
   }
+only_async_start:
+  {
+    GST_OBJECT_UNLOCK (element);
+
+    message = gst_message_new_async_start (GST_OBJECT_CAST (element), TRUE);
+    gst_element_post_message (element, message);
+    return;
+  }
+}
+
+/**
+ * gst_element_lost_state:
+ * @element: a #GstElement the state is lost of
+ *
+ * Brings the element to the lost state. This function calls
+ * gst_element_lost_state_full() with the new_base_time set to %TRUE.
+ *
+ * This function is used internally and should normally not be called from
+ * plugins or applications.
+ *
+ * MT safe.
+ */
+void
+gst_element_lost_state (GstElement * element)
+{
+  gst_element_lost_state_full (element, TRUE);
 }
 
 /**
@@ -2241,6 +2593,9 @@ nothing_lost:
  * An application can use gst_element_get_state() to wait for the completion
  * of the state change or it can wait for a state change message on the bus.
  *
+ * State changes to %GST_STATE_READY or %GST_STATE_NULL never return
+ * #GST_STATE_CHANGE_ASYNC.
+ *
  * Returns: Result of the state change using #GstStateChangeReturn.
  *
  * MT safe.
@@ -2296,12 +2651,17 @@ gst_element_set_state_func (GstElement * element, GstState state)
   current = GST_STATE (element);
   next = GST_STATE_NEXT (element);
   old_pending = GST_STATE_PENDING (element);
-  /* increment state cookie so that we can track each state change */
-  element->state_cookie++;
 
   /* this is the (new) state we should go to. TARGET is the last state we set on
    * the element. */
-  GST_STATE_TARGET (element) = state;
+  if (state != GST_STATE_TARGET (element)) {
+    GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
+        "setting target state to %s", gst_element_state_get_name (state));
+    GST_STATE_TARGET (element) = state;
+    /* increment state cookie so that we can track each state change. We only do
+     * this if this is actually a new state change. */
+    element->state_cookie++;
+  }
   GST_STATE_PENDING (element) = state;
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
@@ -2389,15 +2749,9 @@ gst_element_change_state (GstElement * element, GstStateChange transition)
 {
   GstElementClass *oclass;
   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
-  GstState current;
-  GstState next;
 
   oclass = GST_ELEMENT_GET_CLASS (element);
 
-  /* start with the current state. */
-  current = (GstState) GST_STATE_TRANSITION_CURRENT (transition);
-  next = GST_STATE_TRANSITION_NEXT (transition);
-
   /* call the state change function so it can set the state */
   if (oclass->change_state)
     ret = (oclass->change_state) (element, transition);
@@ -2478,18 +2832,18 @@ invalid_return:
 }
 
 /* gst_iterator_fold functions for pads_activate
- * Note how we don't stop the iterator when we fail an activation. This is
- * probably a FIXME since when one pad activation fails, we don't want to
- * continue our state change. */
+ * Stop the iterator if activating one pad failed. */
 static gboolean
 activate_pads (GstPad * pad, GValue * ret, gboolean * active)
 {
-  if (!gst_pad_set_active (pad, *active))
+  gboolean cont = TRUE;
+
+  if (!(cont = gst_pad_set_active (pad, *active)))
     g_value_set_boolean (ret, FALSE);
 
   /* unref the object that was reffed for us by _fold */
   gst_object_unref (pad);
-  return TRUE;
+  return cont;
 }
 
 /* set the caps on the pad to NULL */
@@ -2501,8 +2855,7 @@ clear_caps (GstPad * pad, GValue * ret, gboolean * active)
   return TRUE;
 }
 
-/* returns false on error or early cutout (will never happen because the fold
- * function always returns TRUE, see FIXME above) of the fold, true if all
+/* returns false on error or early cutout of the fold, true if all
  * pads in @iter were (de)activated successfully. */
 static gboolean
 iterator_activate_fold_with_resync (GstIterator * iter,
@@ -2586,17 +2939,20 @@ gst_element_pads_activate (GstElement * element, gboolean active)
   /* ERRORS */
 src_failed:
   {
-    GST_DEBUG_OBJECT (element, "source pads_activate failed");
+    GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
+        "source pads_activate failed");
     return FALSE;
   }
 sink_failed:
   {
-    GST_DEBUG_OBJECT (element, "sink pads_activate failed");
+    GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
+        "sink pads_activate failed");
     return FALSE;
   }
 caps_failed:
   {
-    GST_DEBUG_OBJECT (element, "failed to clear caps on pads");
+    GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
+        "failed to clear caps on pads");
     return FALSE;
   }
 }
@@ -2607,6 +2963,7 @@ gst_element_change_state_func (GstElement * element, GstStateChange transition)
 {
   GstState state, next;
   GstStateChangeReturn result = GST_STATE_CHANGE_SUCCESS;
+  GstClock **clock_p;
 
   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE);
 
@@ -2643,6 +3000,12 @@ gst_element_change_state_func (GstElement * element, GstStateChange transition)
       } else {
         gst_element_set_base_time (element, 0);
       }
+
+      /* In null state release the reference to the clock */
+      GST_OBJECT_LOCK (element);
+      clock_p = &element->clock;
+      gst_object_replace ((GstObject **) clock_p, NULL);
+      GST_OBJECT_UNLOCK (element);
       break;
     default:
       /* this will catch real but unhandled state changes;
@@ -2676,8 +3039,8 @@ was_ok:
  *
  * Retrieves the factory that was used to create this element.
  *
- * Returns: the #GstElementFactory used for creating this element.
- * no refcounting is needed.
+ * Returns: (transfer none): the #GstElementFactory used for creating this
+ *     element. no refcounting is needed.
  */
 GstElementFactory *
 gst_element_get_factory (GstElement * element)
@@ -2690,7 +3053,7 @@ gst_element_get_factory (GstElement * element)
 static void
 gst_element_dispose (GObject * object)
 {
-  GstElement *element = GST_ELEMENT (object);
+  GstElement *element = GST_ELEMENT_CAST (object);
   GstClock **clock_p;
   GstBus **bus_p;
 
@@ -2699,13 +3062,14 @@ gst_element_dispose (GObject * object)
   if (GST_STATE (element) != GST_STATE_NULL)
     goto not_null;
 
-  GST_DEBUG_OBJECT (element, "removing %d pads", g_list_length (element->pads));
+  GST_CAT_DEBUG_OBJECT (GST_CAT_ELEMENT_PADS, element,
+      "removing %d pads", g_list_length (element->pads));
   /* first we break all our links with the outside */
   while (element->pads && element->pads->data) {
     /* don't call _remove_pad with NULL */
     gst_element_remove_pad (element, GST_PAD_CAST (element->pads->data));
   }
-  if (G_UNLIKELY (element->pads != 0)) {
+  if (G_UNLIKELY (element->pads != NULL)) {
     g_critical ("could not remove pads from element %s",
         GST_STR_NULL (GST_OBJECT_NAME (object)));
   }
@@ -2726,11 +3090,19 @@ gst_element_dispose (GObject * object)
   /* ERRORS */
 not_null:
   {
+    gboolean is_locked;
+
+    is_locked = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE);
     g_critical
-        ("\nTrying to dispose element %s, but it is not in the NULL state.\n"
+        ("\nTrying to dispose element %s, but it is in %s%s instead of the NULL"
+        " state.\n"
         "You need to explicitly set elements to the NULL state before\n"
-        "dropping the final reference, to allow them to clean up.\n",
-        GST_OBJECT_NAME (element));
+        "dropping the final reference, to allow them to clean up.\n"
+        "This problem may also be caused by a refcounting bug in the\n"
+        "application or some element.\n",
+        GST_OBJECT_NAME (element),
+        gst_element_state_get_name (GST_STATE (element)),
+        is_locked ? " (locked)" : "");
     return;
   }
 }
@@ -2738,7 +3110,7 @@ not_null:
 static void
 gst_element_finalize (GObject * object)
 {
-  GstElement *element = GST_ELEMENT (object);
+  GstElement *element = GST_ELEMENT_CAST (object);
 
   GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "finalize");
 
@@ -2748,7 +3120,7 @@ gst_element_finalize (GObject * object)
   element->state_cond = NULL;
   GST_STATE_UNLOCK (element);
   g_static_rec_mutex_free (element->state_lock);
-  g_free (element->state_lock);
+  g_slice_free (GStaticRecMutex, element->state_lock);
   element->state_lock = NULL;
 
   GST_CAT_INFO_OBJECT (GST_CAT_REFCOUNTING, element, "finalize parent");
@@ -2756,7 +3128,7 @@ gst_element_finalize (GObject * object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-#ifndef GST_DISABLE_LOADSAVE
+#if !defined(GST_DISABLE_LOADSAVE) && !defined(GST_REMOVE_DEPRECATED)
 /**
  * gst_element_save_thyself:
  * @element: a #GstElement to save.
@@ -2779,7 +3151,7 @@ gst_element_save_thyself (GstObject * object, xmlNodePtr parent)
 
   g_return_val_if_fail (GST_IS_ELEMENT (object), parent);
 
-  element = GST_ELEMENT (object);
+  element = GST_ELEMENT_CAST (object);
 
   oclass = GST_ELEMENT_GET_CLASS (element);
 
@@ -2802,7 +3174,7 @@ gst_element_save_thyself (GstObject * object, xmlNodePtr parent)
       xmlNodePtr param;
       char *contents;
 
-      g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (spec));
+      g_value_init (&value, spec->value_type);
 
       g_object_get_property (G_OBJECT (element), spec->name, &value);
       param = xmlNewChild (parent, NULL, (xmlChar *) "param", NULL);
@@ -2815,7 +3187,13 @@ gst_element_save_thyself (GstObject * object, xmlNodePtr parent)
       else if (G_IS_PARAM_SPEC_INT64 (spec))
         contents = g_strdup_printf ("%" G_GINT64_FORMAT,
             g_value_get_int64 (&value));
-      else
+      else if (GST_VALUE_HOLDS_STRUCTURE (&value)) {
+        if (g_value_get_boxed (&value) != NULL) {
+          contents = g_strdup_value_contents (&value);
+        } else {
+          contents = g_strdup ("NULL");
+        }
+      } else
         contents = g_strdup_value_contents (&value);
 
       xmlNewChild (param, NULL, (xmlChar *) "value", (xmlChar *) contents);
@@ -2827,18 +3205,18 @@ gst_element_save_thyself (GstObject * object, xmlNodePtr parent)
 
   g_free (specs);
 
-  pads = GST_ELEMENT_PADS (element);
+  pads = g_list_last (GST_ELEMENT_PADS (element));
 
   while (pads) {
     GstPad *pad = GST_PAD_CAST (pads->data);
 
     /* figure out if it's a direct pad or a ghostpad */
-    if (GST_ELEMENT (GST_OBJECT_PARENT (pad)) == element) {
+    if (GST_ELEMENT_CAST (GST_OBJECT_PARENT (pad)) == element) {
       xmlNodePtr padtag = xmlNewChild (parent, NULL, (xmlChar *) "pad", NULL);
 
       gst_object_save_thyself (GST_OBJECT_CAST (pad), padtag);
     }
-    pads = g_list_next (pads);
+    pads = g_list_previous (pads);
   }
 
   return parent;
@@ -2852,7 +3230,7 @@ gst_element_restore_thyself (GstObject * object, xmlNodePtr self)
   gchar *name = NULL;
   gchar *value = NULL;
 
-  element = GST_ELEMENT (object);
+  element = GST_ELEMENT_CAST (object);
   g_return_if_fail (element != NULL);
 
   /* parameters */
@@ -2910,7 +3288,7 @@ gst_element_set_bus_func (GstElement * element, GstBus * bus)
 /**
  * gst_element_set_bus:
  * @element: a #GstElement to set the bus of.
- * @bus: the #GstBus to set.
+ * @bus: (transfer none): the #GstBus to set.
  *
  * Sets the bus of the element. Increases the refcount on the bus.
  * For internal use only, unless you're testing elements.
@@ -2937,7 +3315,7 @@ gst_element_set_bus (GstElement * element, GstBus * bus)
  * Returns the bus of the element. Note that only a #GstPipeline will provide a
  * bus for the application.
  *
- * Returns: the element's #GstBus. unref after usage.
+ * Returns: (transfer full): the element's #GstBus. unref after usage.
  *
  * MT safe.
  */
@@ -2953,7 +3331,8 @@ gst_element_get_bus (GstElement * element)
     gst_object_ref (result);
   GST_OBJECT_UNLOCK (element);
 
-  GST_DEBUG_OBJECT (element, "got bus %" GST_PTR_FORMAT, result);
+  GST_CAT_DEBUG_OBJECT (GST_CAT_BUS, element, "got bus %" GST_PTR_FORMAT,
+      result);
 
   return result;
 }