]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gstreamer0-10.git/blobdiff - gst/gstelement.c
ignore these test code
[glsdk/gstreamer0-10.git] / gst / gstelement.c
index bae0ebc780bf3f161d6f79096e6b60afefbff690..bc215b04fbc6d1cf1ffb6ad617f8efeff7fa35a1 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
-/* #define GST_DEBUG_ENABLED */
 #include <glib.h>
 #include <stdarg.h>
 #include <gobject/gvaluecollector.h>
 #include "gst_private.h"
 
 #include "gstelement.h"
-#include "gstextratypes.h"
 #include "gstbin.h"
 #include "gstscheduler.h"
 #include "gstevent.h"
 #include "gstutils.h"
-#include "gstlog.h"
+#include "gstinfo.h"
 
 /* Element signals and args */
 enum {
@@ -41,7 +39,6 @@ enum {
   PAD_REMOVED,
   ERROR,
   EOS,
-  DEEP_NOTIFY,
   LAST_SIGNAL
 };
 
@@ -50,8 +47,6 @@ enum {
   /* FILL ME */
 };
 
-#define CLASS(element) GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element))
-
 static void                    gst_element_class_init          (GstElementClass *klass);
 static void                    gst_element_init                (GstElement *element);
 static void                    gst_element_base_class_init     (GstElementClass *klass);
@@ -60,14 +55,9 @@ static void                  gst_element_real_set_property   (GObject *object, guint prop_id,
                                                                 const GValue *value, GParamSpec *pspec);
 static void                    gst_element_real_get_property   (GObject *object, guint prop_id, GValue *value, 
                                                                 GParamSpec *pspec);
-static void                    gst_element_dispatch_properties_changed (GObject * object, guint n_pspecs, GParamSpec **pspecs);
 
 static void                    gst_element_dispose             (GObject *object);
 
-static gboolean                gst_element_send_event_default  (GstElement *element, GstEvent *event);
-static gboolean                gst_element_query_default       (GstElement *element, GstPadQueryType type,
-                                                                GstFormat *format, gint64 *value);
-
 static GstElementStateReturn   gst_element_change_state        (GstElement *element);
 static void                    gst_element_error_func          (GstElement* element, GstElement *source, gchar *errormsg);
 
@@ -137,21 +127,10 @@ gst_element_class_init (GstElementClass *klass)
     g_signal_new ("eos", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (GstElementClass,eos), NULL, NULL,
                   gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
-  gst_element_signals[DEEP_NOTIFY] =
-    g_signal_new ("deep_notify", G_TYPE_FROM_CLASS (klass), 
-                 G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS,
-                 G_STRUCT_OFFSET (GstElementClass, deep_notify), NULL, NULL,
-                 gst_marshal_VOID__OBJECT_PARAM, G_TYPE_NONE,
-                 2, G_TYPE_OBJECT, G_TYPE_PARAM);
-
 
   gobject_class->set_property          = GST_DEBUG_FUNCPTR (gst_element_real_set_property);
   gobject_class->get_property          = GST_DEBUG_FUNCPTR (gst_element_real_get_property);
 
-  /* see the comments at gst_element_dispatch_properties_changed */
-  gobject_class->dispatch_properties_changed
-    = GST_DEBUG_FUNCPTR (gst_element_dispatch_properties_changed);
-
   gobject_class->dispose               = GST_DEBUG_FUNCPTR (gst_element_dispose);
 
 #ifndef GST_DISABLE_LOADSAVE
@@ -164,8 +143,6 @@ gst_element_class_init (GstElementClass *klass)
   klass->elementfactory                = NULL;
   klass->padtemplates                  = NULL;
   klass->numpadtemplates               = 0;
-  klass->send_event                    = GST_DEBUG_FUNCPTR (gst_element_send_event_default);
-  klass->query                         = GST_DEBUG_FUNCPTR (gst_element_query_default);
 }
 
 static void
@@ -199,7 +176,7 @@ gst_element_init (GstElement *element)
 static void
 gst_element_real_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
 {
-  GstElementClass *oclass = CLASS (object);
+  GstElementClass *oclass = GST_ELEMENT_GET_CLASS (object);
 
   if (oclass->set_property)
     (oclass->set_property) (object, prop_id, value, pspec);
@@ -208,93 +185,12 @@ gst_element_real_set_property (GObject *object, guint prop_id, const GValue *val
 static void
 gst_element_real_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 {
-  GstElementClass *oclass = CLASS (object);
+  GstElementClass *oclass = GST_ELEMENT_GET_CLASS (object);
 
   if (oclass->get_property)
     (oclass->get_property) (object, prop_id, value, pspec);
 }
 
-/* Changing a GObject property of an element will result in "deep_notify"
- * signals being emitted by the element itself, as well as in each parent
- * element. This is so that an application can connect a listener to the
- * top-level bin to catch property-change notifications for all contained
- * elements. */
-static void
-gst_element_dispatch_properties_changed (GObject     *object,
-                                         guint        n_pspecs,
-                                         GParamSpec **pspecs)
-{
-  GstObject *gst_object;
-  guint i;
-
-  /* do the standard dispatching */
-  G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs);
-
-  /* now let the parent dispatch those, too */
-  gst_object = GST_OBJECT_PARENT (object);
-  while (gst_object) {
-    /* need own category? */
-    for (i = 0; i < n_pspecs; i++) {
-      GST_DEBUG (GST_CAT_EVENT, "deep notification from %s to %s (%s)", GST_OBJECT_NAME (object), 
-                   GST_OBJECT_NAME (gst_object), pspecs[i]->name);
-      g_signal_emit (gst_object, gst_element_signals[DEEP_NOTIFY], g_quark_from_string (pspecs[i]->name), 
-                    (GstObject *) object, pspecs[i]);
-    }
-
-    gst_object = GST_OBJECT_PARENT (gst_object);
-  }
-}
-
-/** 
- * gst_element_default_deep_notify:
- * @object: the #GObject that signalled the notify.
- * @orig: a #GstObject that initiated the notify.
- * @pspec: a #GParamSpec of the property.
- * @excluded_props: a set of user-specified properties to exclude.
- *
- * Adds a default deep_notify signal callback to an
- * element. The user data should contain a pointer to an array of
- * strings that should be excluded from the notify.
- * The default handler will print the new value of the property 
- * using g_print.
- */
-void
-gst_element_default_deep_notify (GObject *object, GstObject *orig, 
-                                 GParamSpec *pspec, gchar **excluded_props)
-{
-  GValue value = { 0, }; /* the important thing is that value.type = 0 */
-  gchar *str = 0;
-
-  if (pspec->flags & G_PARAM_READABLE) {
-    /* let's not print these out for excluded properties... */
-    while (excluded_props != NULL && *excluded_props != NULL) {
-      if (strcmp (pspec->name, *excluded_props) == 0)
-        return;
-      excluded_props++;
-    }
-    g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
-    g_object_get_property (G_OBJECT (orig), pspec->name, &value);
-
-    if (G_IS_PARAM_SPEC_ENUM (pspec)) {
-      GEnumValue *enum_value;
-      enum_value = g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (pspec->value_type)),
-      g_value_get_enum (&value));
-
-      str = g_strdup_printf ("%s (%d)", enum_value->value_nick, 
-                                       enum_value->value);
-    }
-    else {
-      str = g_strdup_value_contents (&value);
-    }
-    g_print ("%s: %s = %s\n", GST_OBJECT_NAME (orig), pspec->name, str);
-    g_free (str);
-    g_value_unset (&value);
-  } else {
-    g_warning ("Parameter %s not readable in %s.", 
-              pspec->name, GST_OBJECT_NAME (orig));
-  }
-}
-
 /** 
  * gst_element_default_error:
  * @object: a #GObject that signalled the error.
@@ -310,7 +206,9 @@ gst_element_default_deep_notify (GObject *object, GstObject *orig,
 void
 gst_element_default_error (GObject *object, GstObject *orig, gchar *error)
 { 
-  g_print ("ERROR: %s: %s\n", GST_OBJECT_NAME (orig), error);
+  gchar *name = gst_object_get_path_string (orig);
+  g_print ("ERROR: %s: %s\n", name, error);
+  g_free (name);
 } 
 
 typedef struct {
@@ -340,7 +238,7 @@ element_get_property (GstElement *element, const GParamSpec *pspec, GValue *valu
 static void
 gst_element_threadsafe_properties_pre_run (GstElement *element)
 {
-  GST_DEBUG (GST_CAT_THREAD, "locking element %s", GST_OBJECT_NAME (element));
+  GST_CAT_DEBUG (GST_CAT_THREAD, "locking element %s", GST_OBJECT_NAME (element));
   g_mutex_lock (element->property_mutex);
   gst_element_set_pending_properties (element);
 }
@@ -348,7 +246,7 @@ gst_element_threadsafe_properties_pre_run (GstElement *element)
 static void
 gst_element_threadsafe_properties_post_run (GstElement *element)
 {
-  GST_DEBUG (GST_CAT_THREAD, "unlocking element %s", GST_OBJECT_NAME (element));
+  GST_CAT_DEBUG (GST_CAT_THREAD, "unlocking element %s", GST_OBJECT_NAME (element));
   g_mutex_unlock (element->property_mutex);
 }
 
@@ -474,7 +372,11 @@ gst_element_set_valist (GstElement *element, const gchar *first_property_name, v
   
   g_return_if_fail (GST_IS_ELEMENT (element));
   
-  object = (GObject*)element;
+  object = (GObject *) element;
+
+  GST_CAT_DEBUG (GST_CAT_PROPERTIES, 
+            "setting valist of properties starting with %s on element %s",
+            first_property_name, gst_element_get_name (element));
 
   if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
     g_object_set_valist (object, first_property_name, var_args);
@@ -617,7 +519,8 @@ gst_element_get_valist (GstElement *element, const gchar *first_property_name, v
  * the property will be put on the async queue.
  */
 void
-gst_element_set_property (GstElement *element, const gchar *property_name, const GValue *value)
+gst_element_set_property (GstElement *element, const gchar *property_name, 
+                         const GValue *value)
 {
   GParamSpec *pspec;
   GObject *object;
@@ -626,8 +529,10 @@ gst_element_set_property (GstElement *element, const gchar *property_name, const
   g_return_if_fail (property_name != NULL);
   g_return_if_fail (G_IS_VALUE (value));
   
-  object = (GObject*)element;
+  object = (GObject*) element;
 
+  GST_CAT_DEBUG (GST_CAT_PROPERTIES, "setting property %s on element %s",
+            property_name, gst_element_get_name (element));
   if (!GST_FLAG_IS_SET (element, GST_ELEMENT_USE_THREADSAFE_PROPERTIES)) {
     g_object_set_property (object, property_name, value);
     return;
@@ -635,7 +540,8 @@ gst_element_set_property (GstElement *element, const gchar *property_name, const
 
   g_object_ref (object);
   
-  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name);
+  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), 
+                                       property_name);
   
   if (!pspec)
     g_warning ("%s: object class `%s' has no property named `%s'",
@@ -725,7 +631,8 @@ gst_element_request_pad (GstElement *element, GstPadTemplate *templ, const gchar
   GstPad *newpad = NULL;
   GstElementClass *oclass;
 
-  oclass = CLASS (element);
+  oclass = GST_ELEMENT_GET_CLASS (element);
+
   if (oclass->request_new_pad)
     newpad = (oclass->request_new_pad)(element, templ, name);
 
@@ -748,81 +655,42 @@ gst_element_release_request_pad (GstElement *element, GstPad *pad)
   g_return_if_fail (GST_IS_ELEMENT (element));
   g_return_if_fail (GST_IS_PAD (pad));
 
-  oclass = CLASS (element);
+  oclass = GST_ELEMENT_GET_CLASS (element);
+
   if (oclass->release_pad)
     (oclass->release_pad) (element, pad);
 }
 
-
-/**
- * gst_element_set_name:
- * @element: a #GstElement to set the name of.
- * @name: the new name of the element.
- *
- * Sets the name of the element, getting rid of the old name if there was
- * one.
- */
-void
-gst_element_set_name (GstElement *element, const gchar *name)
-{
-  g_return_if_fail (element != NULL);
-  g_return_if_fail (GST_IS_ELEMENT (element));
-
-  gst_object_set_name (GST_OBJECT (element), name);
-}
-
 /**
- * gst_element_get_name:
- * @element: a #GstElement to get the name of.
+ * gst_element_requires_clock:
+ * @element: a #GstElement to query
  *
- * Gets the name of the element.
+ * Query if the element requiresd a clock
  *
- * Returns: the name of the element.
+ * Returns: TRUE if the element requires a clock
  */
-const gchar*
-gst_element_get_name (GstElement *element)
-{
-  g_return_val_if_fail (element != NULL, NULL);
-  g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
-
-  return GST_OBJECT_NAME (element);
-}
-
-/**
- * gst_element_set_parent:
- * @element: a #GstElement to set parent of.
- * @parent: the new #GstObject parent of the object.
- *
- * Sets the parent of the element.
- */
-void
-gst_element_set_parent (GstElement *element, GstObject *parent)
+gboolean
+gst_element_requires_clock (GstElement *element)
 {
-  g_return_if_fail (element != NULL);
-  g_return_if_fail (GST_IS_ELEMENT (element));
-  g_return_if_fail (GST_OBJECT_PARENT (element) == NULL);
-  g_return_if_fail (parent != NULL);
-  g_return_if_fail (GST_IS_OBJECT (parent));
-  g_return_if_fail ((gpointer)element != (gpointer)parent);
+  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
 
-  gst_object_set_parent (GST_OBJECT (element), parent);
+  return (GST_ELEMENT_GET_CLASS (element)->set_clock != NULL);
 }
 
 /**
- * gst_element_get_parent:
- * @element: a #GstElement to get the parent of.
+ * gst_element_provides_clock:
+ * @element: a #GstElement to query
  *
- * Gets the parent of the element.
+ * Query if the element provides a clock
  *
- * Returns: the #GstObject parent of the element.
+ * Returns: TRUE if the element provides a clock
  */
-GstObject*
-gst_element_get_parent (GstElement *element)
+gboolean
+gst_element_provides_clock (GstElement *element)
 {
-  g_return_val_if_fail (element != NULL, NULL);
-  g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
+  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
 
-  return GST_OBJECT_PARENT (element);
+  return (GST_ELEMENT_GET_CLASS (element)->get_clock != NULL);
 }
 
 /**
@@ -835,13 +703,16 @@ gst_element_get_parent (GstElement *element)
 void
 gst_element_set_clock (GstElement *element, GstClock *clock)
 {
-  g_return_if_fail (element != NULL);
+  GstElementClass *oclass;
+
   g_return_if_fail (GST_IS_ELEMENT (element));
 
-  if (element->setclockfunc)
-    element->setclockfunc (element, clock);
+  oclass = GST_ELEMENT_GET_CLASS (element);
+
+  if (oclass->set_clock)
+    oclass->set_clock (element, clock);
 
-  element->clock = clock;
+  gst_object_replace ((GstObject **)&element->clock, (GstObject *)clock);
 }
 
 /**
@@ -855,11 +726,14 @@ gst_element_set_clock (GstElement *element, GstClock *clock)
 GstClock*
 gst_element_get_clock (GstElement *element)
 {
-  g_return_val_if_fail (element != NULL, NULL);
+  GstElementClass *oclass;
+
   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
+
+  oclass = GST_ELEMENT_GET_CLASS (element);
   
-  if (element->getclockfunc)
-    return element->getclockfunc (element);
+  if (oclass->get_clock)
+    return oclass->get_clock (element);
 
   return NULL;
 }
@@ -867,8 +741,7 @@ gst_element_get_clock (GstElement *element)
 /**
  * gst_element_clock_wait:
  * @element: a #GstElement.
- * @clock: the #GstClock to use.
- * @time: the #GstClockTime to wait for on the clock.
+ * @id: the #GstClock to use.
  * @jitter: the difference between requested time and actual time.
  *
  * Waits for a specific time on the clock.
@@ -876,22 +749,86 @@ gst_element_get_clock (GstElement *element)
  * Returns: the #GstClockReturn result of the wait operation.
  */
 GstClockReturn
-gst_element_clock_wait (GstElement *element, GstClock *clock, GstClockTime time, GstClockTimeDiff *jitter)
+gst_element_clock_wait (GstElement *element, GstClockID id, GstClockTimeDiff *jitter)
 {
   GstClockReturn res;
 
-  g_return_val_if_fail (element != NULL, GST_CLOCK_ERROR);
   g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_ERROR);
 
   if (GST_ELEMENT_SCHED (element)) {
-    res = gst_scheduler_clock_wait (GST_ELEMENT_SCHED (element), element, clock, time, jitter);
+    GST_CAT_DEBUG (GST_CAT_CLOCK, "waiting on scheduler clock");
+    res = gst_scheduler_clock_wait (GST_ELEMENT_SCHED (element), element, id, jitter);
   }
-  else 
+  else {
+    GST_CAT_DEBUG (GST_CAT_CLOCK, "no scheduler, returning GST_CLOCK_TIMEOUT");
     res = GST_CLOCK_TIMEOUT;
+  }
 
   return res;
 }
 
+#ifndef GST_DISABLE_INDEX
+/**
+ * gst_element_is_indexable:
+ * @element: a #GstElement.
+ *
+ * Queries if the element can be indexed/
+ *
+ * Returns: TRUE if the element can be indexed.
+ */
+gboolean
+gst_element_is_indexable (GstElement *element)
+{
+  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+
+  return (GST_ELEMENT_GET_CLASS (element)->set_index != NULL);
+}
+
+/**
+ * gst_element_set_index:
+ * @element: a #GstElement.
+ * @index: a #GstIndex.
+ *
+ * Set the specified GstIndex on the element.
+ */
+void
+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));
+
+  oclass = GST_ELEMENT_GET_CLASS (element);
+
+  if (oclass->set_index)
+    oclass->set_index (element, index);
+}
+
+/**
+ * gst_element_get_index:
+ * @element: a #GstElement.
+ *
+ * Gets the index from the element.
+ *
+ * Returns: a #GstIndex or NULL when no index was set on the
+ * element.
+ */
+GstIndex*
+gst_element_get_index (GstElement *element)
+{
+  GstElementClass *oclass;
+
+  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+
+  oclass = GST_ELEMENT_GET_CLASS (element);
+
+  if (oclass->get_index)
+    return oclass->get_index (element);
+
+  return NULL;
+}
+#endif
 
 /**
  * gst_element_release_locks:
@@ -905,10 +842,14 @@ gst_element_clock_wait (GstElement *element, GstClock *clock, GstClockTime time,
 gboolean
 gst_element_release_locks (GstElement *element)
 {
+  GstElementClass *oclass;
+
   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
 
-  if (CLASS (element)->release_locks)
-    return CLASS (element)->release_locks (element);
+  oclass = GST_ELEMENT_GET_CLASS (element);
+
+  if (oclass->release_locks)
+    return oclass->release_locks (element);
   
   return TRUE;
 }
@@ -918,15 +859,14 @@ gst_element_release_locks (GstElement *element)
  * @element: a #GstElement to add the pad to.
  * @pad: the #GstPad to add to the element.
  *
- * Add a pad (connection point) to the element, setting the parent of the
+ * Add a pad (link point) to the element, setting the parent of the
  * pad to the element (and thus adding a reference).
+ * Pads are automatically activated when the element is in state PLAYING.
  */
 void
 gst_element_add_pad (GstElement *element, GstPad *pad)
 {
-  g_return_if_fail (element != NULL);
   g_return_if_fail (GST_IS_ELEMENT (element));
-  g_return_if_fail (pad != NULL);
   g_return_if_fail (GST_IS_PAD (pad));
 
   /* first check to make sure the pad's parent is already set */
@@ -936,8 +876,8 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
   g_return_if_fail (gst_object_check_uniqueness (element->pads, GST_PAD_NAME(pad)) == TRUE);
 
   /* set the pad's parent */
-  GST_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'",
-        GST_PAD_NAME (pad), GST_ELEMENT_NAME (element));
+  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,"setting parent of pad '%s' to '%s'",
+        GST_PAD_NAME (pad), GST_STR_NULL (GST_ELEMENT_NAME (element)));
   gst_object_set_parent (GST_OBJECT (pad), GST_OBJECT (element));
 
   /* add it to the list */
@@ -948,6 +888,10 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
   else
     element->numsinkpads++;
 
+  /* activate element when we are playing */
+  if (GST_STATE (element) == GST_STATE_PLAYING)
+    gst_pad_set_active (pad, TRUE);
+  
   /* emit the NEW_PAD signal */
   g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, pad);
 }
@@ -957,7 +901,7 @@ gst_element_add_pad (GstElement *element, GstPad *pad)
  * @element: a #GstElement to remove pad from.
  * @pad: the #GstPad to remove from the element.
  *
- * Remove a pad (connection point) from the element.
+ * Remove a pad (link point) from the element.
  */
 void
 gst_element_remove_pad (GstElement *element, GstPad *pad)
@@ -969,7 +913,7 @@ gst_element_remove_pad (GstElement *element, GstPad *pad)
 
   g_return_if_fail (GST_PAD_PARENT (pad) == element);
 
-  /* check to see if the pad is still connected */
+  /* check to see if the pad is still linked */
   /* FIXME: what if someone calls _remove_pad instead of 
     _remove_ghost_pad? */
   if (GST_IS_REAL_PAD (pad)) {
@@ -1013,20 +957,20 @@ gst_element_add_ghost_pad (GstElement *element, GstPad *pad, const gchar *name)
   /* then check to see if there's already a pad by that name here */
   g_return_val_if_fail (gst_object_check_uniqueness (element->pads, name) == TRUE, NULL);
 
-  GST_DEBUG (GST_CAT_ELEMENT_PADS, 
+  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, 
              "creating new ghost pad called %s, from pad %s:%s",
              name, GST_DEBUG_PAD_NAME(pad));
   ghostpad = gst_ghost_pad_new (name, pad);
 
   /* add it to the list */
-  GST_DEBUG(GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s",
+  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,"adding ghost pad %s to element %s",
             name, GST_ELEMENT_NAME (element));
   element->pads = g_list_append (element->pads, ghostpad);
   element->numpads++;
   /* set the parent of the ghostpad */
   gst_object_set_parent (GST_OBJECT (ghostpad), GST_OBJECT (element));
 
-  GST_DEBUG(GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s",GST_DEBUG_PAD_NAME(ghostpad));
+  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,"added ghostpad %s:%s",GST_DEBUG_PAD_NAME(ghostpad));
 
   /* emit the NEW_GHOST_PAD signal */
   g_signal_emit (G_OBJECT (element), gst_element_signals[NEW_PAD], 0, ghostpad);
@@ -1044,9 +988,7 @@ gst_element_add_ghost_pad (GstElement *element, GstPad *pad, const gchar *name)
 void
 gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
 {
-  g_return_if_fail (element != NULL);
   g_return_if_fail (GST_IS_ELEMENT (element));
-  g_return_if_fail (pad != NULL);
   g_return_if_fail (GST_IS_GHOST_PAD (pad));
 
   /* FIXME this is redundant?
@@ -1054,8 +996,10 @@ gst_element_remove_ghost_pad (GstElement *element, GstPad *pad)
    * from the element. gst_pad_remove_ghost_pad just removes the ghostpad from
    * the real pad's ghost pad list
    */
-  gst_pad_remove_ghost_pad (GST_PAD (GST_PAD_REALIZE (pad)), pad);
+  gst_object_ref (GST_OBJECT (pad));
   gst_element_remove_pad (element, pad);
+  gst_pad_remove_ghost_pad (GST_PAD (GST_PAD_REALIZE (pad)), pad);
+  gst_object_unref (GST_OBJECT (pad));
 }
 
 
@@ -1077,11 +1021,10 @@ gst_element_get_pad (GstElement *element, const gchar *name)
   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
   g_return_val_if_fail (name != NULL, NULL);
 
-  if ((pad = gst_element_get_static_pad (element, name)))
-    return pad;
-  
-  pad = gst_element_get_request_pad (element, name);
-  
+  pad = gst_element_get_static_pad (element, name);
+  if (!pad) 
+    pad = gst_element_get_request_pad (element, name);
+
   return pad;
 }
 
@@ -1110,13 +1053,13 @@ gst_element_get_static_pad (GstElement *element, const gchar *name)
     
     pad = GST_PAD(walk->data);
     if (strcmp (GST_PAD_NAME(pad), name) == 0) {
-      GST_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+      GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "found pad %s:%s", GST_DEBUG_PAD_NAME (pad));
       return pad;
     }
     walk = g_list_next (walk);
   }
 
-  GST_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"", name, GST_OBJECT_NAME (element));
+  GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "no such pad '%s' in element \"%s\"", name, GST_OBJECT_NAME (element));
   return NULL;
 }
 
@@ -1158,7 +1101,7 @@ gst_element_get_request_pad (GstElement *element, const gchar *name)
       if (templ->presence == GST_PAD_REQUEST) {
         /* we know that %s and %d are the only possibilities because of sanity
            checks in gst_pad_template_new */
-        GST_DEBUG (GST_CAT_PADS, "comparing %s to %s", name, templ->name_template);
+        GST_CAT_DEBUG (GST_CAT_PADS, "comparing %s to %s", name, templ->name_template);
         if ((str = strchr (templ->name_template, '%')) &&
             strncmp (templ->name_template, name, str - templ->name_template) == 0 &&
             strlen (name) > str - templ->name_template) {
@@ -1199,7 +1142,7 @@ gst_element_get_request_pad (GstElement *element, const gchar *name)
  *
  * Returns: the #GList of pads.
  */
-GList*
+const GList*
 gst_element_get_pad_list (GstElement *element)
 {
   g_return_val_if_fail (element != NULL, NULL);
@@ -1246,7 +1189,7 @@ gst_element_get_pad_template_list (GstElement *element)
   g_return_val_if_fail (element != NULL, NULL);
   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
 
-  return CLASS (element)->padtemplates;
+  return GST_ELEMENT_GET_CLASS (element)->padtemplates;
 }
 
 /**
@@ -1289,20 +1232,20 @@ gst_element_get_pad_template (GstElement *element, const gchar *name)
  * @compattempl: the #GstPadTemplate to find a compatible template for.
  *
  * Generates a pad template for this element compatible with the given
- * template (meaning it is able to connect with it).
+ * template (meaning it is able to link with it).
  *
  * Returns: the #GstPadTemplate of the element that is compatible with
- * the given GstPadTemplate, or NULL if none was found. No unreferencing 
+ * the given GstPadTemplate, or NULL if none was found. No unreferencing
  * is necessary.
  */
 GstPadTemplate*
-gst_element_get_compatible_pad_template (GstElement *element, 
+gst_element_get_compatible_pad_template (GstElement *element,
                                          GstPadTemplate *compattempl)
 {
   GstPadTemplate *newtempl = NULL;
   GList *padlist;
 
-  GST_DEBUG (GST_CAT_ELEMENT_PADS, "gst_element_get_compatible_pad_template()");
+  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "gst_element_get_compatible_pad_template()");
 
   g_return_val_if_fail (element != NULL, NULL);
   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
@@ -1319,19 +1262,19 @@ gst_element_get_compatible_pad_template (GstElement *element,
      * Check direction (must be opposite)
      * Check caps
      */
-    GST_DEBUG (GST_CAT_CAPS, "checking direction and caps");
+    GST_CAT_DEBUG (GST_CAT_CAPS, "checking direction and caps");
     if (padtempl->direction == GST_PAD_SRC &&
       compattempl->direction == GST_PAD_SINK) {
-      GST_DEBUG (GST_CAT_CAPS, "compatible direction: found src pad template");
-      comp = gst_caps_check_compatibility (GST_PAD_TEMPLATE_CAPS (padtempl),
+      GST_CAT_DEBUG (GST_CAT_CAPS, "compatible direction: found src pad template");
+      comp = gst_caps_is_always_compatible (GST_PAD_TEMPLATE_CAPS (padtempl),
                                           GST_PAD_TEMPLATE_CAPS (compattempl));
-      GST_DEBUG(GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
+      GST_CAT_DEBUG (GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
     } else if (padtempl->direction == GST_PAD_SINK &&
               compattempl->direction == GST_PAD_SRC) {
-      GST_DEBUG (GST_CAT_CAPS, "compatible direction: found sink pad template");
-      comp = gst_caps_check_compatibility (GST_PAD_TEMPLATE_CAPS (compattempl),
+      GST_CAT_DEBUG (GST_CAT_CAPS, "compatible direction: found sink pad template");
+      comp = gst_caps_is_always_compatible (GST_PAD_TEMPLATE_CAPS (compattempl),
                                           GST_PAD_TEMPLATE_CAPS (padtempl));
-      GST_DEBUG (GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
+      GST_CAT_DEBUG (GST_CAT_CAPS, "caps are %scompatible", (comp ? "" : "not "));
     }
 
     if (comp) {
@@ -1348,7 +1291,7 @@ gst_element_get_compatible_pad_template (GstElement *element,
 /**
  * gst_element_request_compatible_pad:
  * @element: a #GstElement to request a new pad from.
- * @templ: the #GstPadTemplate to which the new pad should be able to connect.
+ * @templ: the #GstPadTemplate to which the new pad should be able to link.
  *
  * Requests a new pad from the element. The template will
  * be used to decide what type of pad to create. This function
@@ -1381,43 +1324,43 @@ gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ)
  * @pad: the #GstPad to find a compatible one for.
  * @filtercaps: the #GstCaps to use as a filter.
  *
- * Looks for an unconnected pad to which the given pad can connect to.
- * It is not guaranteed that connecting the pads will work, though
+ * Looks for an unlinked pad to which the given pad can link to.
+ * It is not guaranteed that linking the pads will work, though
  * it should work in most cases.
  *
- * Returns: the #GstPad to which a connection can be made.
+ * Returns: the #GstPad to which a link can be made.
  */
-GstPad*                        
-gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad, 
+GstPad*
+gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
                                          GstCaps *filtercaps)
 {
-  GList *pads;
+  const GList *pads;
   GstPadTemplate *templ;
   GstCaps *templcaps;
   GstPad *foundpad = NULL;
-  
+
   /* checks */
   g_return_val_if_fail (element != NULL, NULL);
   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
   g_return_val_if_fail (pad != NULL, NULL);
   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
-  
+
   /* let's use the real pad */
   pad = (GstPad *) GST_PAD_REALIZE (pad);
   g_return_val_if_fail (pad != NULL, NULL);
   g_return_val_if_fail (GST_RPAD_PEER (pad) == NULL, NULL);
-  
-  /* try to get an existing unconnected pad */
+
+  /* try to get an existing unlinked pad */
   pads = gst_element_get_pad_list (element);
   while (pads) {
     GstPad *current = GST_PAD (pads->data);
     if ((GST_PAD_PEER (GST_PAD_REALIZE (current)) == NULL) &&
-        gst_pad_can_connect_filtered (pad, current, filtercaps)) {
+        gst_pad_can_link_filtered (pad, current, filtercaps)) {
       return current;
     }
     pads = g_list_next (pads);
   }
-  
+
   /* try to create a new one */
   /* requesting is a little crazy, we need a template. Let's create one */
   if (filtercaps != NULL) {
@@ -1425,16 +1368,16 @@ gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
     if (templcaps == NULL)
       return NULL;
   } else {
-    templcaps = gst_caps_copy (gst_pad_get_caps (pad));
+    templcaps = gst_pad_get_caps (pad);
   }
-  
+
   templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad), GST_RPAD_DIRECTION (pad),
                                GST_PAD_ALWAYS, templcaps, NULL);
   foundpad = gst_element_request_compatible_pad (element, templ);
   gst_object_unref (GST_OBJECT (templ)); /* this will take care of the caps too */
-  
+
   /* FIXME: this is broken, but it's in here so autoplugging elements that don't
-     have caps on their source padtemplates (spider) can connect... */
+     have caps on their source padtemplates (spider) can link... */
   if (!foundpad && !filtercaps) {
     templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad), GST_RPAD_DIRECTION (pad),
                                  GST_PAD_ALWAYS, NULL, NULL);
@@ -1450,11 +1393,11 @@ gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
  * @element: a #GstElement in which the pad should be found.
  * @pad: the #GstPad to find a compatible one for.
  *
- * Looks for an unconnected pad to which the given pad can connect to.
- * It is not guaranteed that connecting the pads will work, though
+ * Looks for an unlinked pad to which the given pad can link to.
+ * It is not guaranteed that linking the pads will work, though
  * it should work in most cases.
  *
- * Returns: the #GstPad to which a connection can be made, or NULL if none
+ * Returns: the #GstPad to which a link can be made, or NULL if none
  * could be found.
  */
 GstPad*                        
@@ -1464,75 +1407,142 @@ gst_element_get_compatible_pad (GstElement *element, GstPad *pad)
 }
 
 /**
- * gst_element_connect_filtered:
+ * gst_element_link_pads_filtered:
  * @src: a #GstElement containing the source pad.
+ * @srcpadname: the name of the #GstPad in source element or NULL for any pad.
  * @dest: the #GstElement containing the destination pad.
+ * @destpadname: the name of the #GstPad in destination element or NULL for any pad.
  * @filtercaps: the #GstCaps to use as a filter.
  *
- * Connects the source to the destination element using the filtercaps.
- * The connection must be from source to destination, the other
- * direction will not be tried.
- * The functions looks for existing pads that aren't connected yet. 
- * It will use request pads if possible. But both pads will not be requested.
- * If multiple connections are possible, only one is established.
+ * Links the two named pads of the source and destination elements.
+ * Side effect is that if one of the pads has no parent, it becomes a
+ * child of the parent of the other element.  If they have different
+ * parents, the link fails.
  *
- * Returns: TRUE if the elements could be connected.
+ * Returns: TRUE if the pads could be linked.
  */
 gboolean
-gst_element_connect_filtered (GstElement *src, GstElement *dest, 
-                             GstCaps *filtercaps)
+gst_element_link_pads_filtered (GstElement *src, const gchar *srcpadname,
+                                GstElement *dest, const gchar *destpadname,
+                                GstCaps *filtercaps)
 {
-  GList *srcpads, *destpads, *srctempls, *desttempls, *l;
+  const GList *srcpads, *destpads, *srctempls, *desttempls, *l;
   GstPad *srcpad, *destpad;
   GstPadTemplate *srctempl, *desttempl;
 
   /* checks */
-  g_return_val_if_fail (src != NULL, FALSE);
-  g_return_val_if_fail (GST_IS_ELEMENT(src), FALSE);
-  g_return_val_if_fail (dest != NULL, FALSE);
-  g_return_val_if_fail (GST_IS_ELEMENT(dest), FALSE);
+  g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
+  g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
 
-  GST_DEBUG (GST_CAT_ELEMENT_PADS, "trying to connect element %s to element %s",
-             GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
-   
-  /* loop through the existing pads in the source */
-  srcpads = gst_element_get_pad_list (src);
-  destpads = gst_element_get_pad_list (dest);
+  GST_CAT_INFO (GST_CAT_ELEMENT_PADS, "trying to link element %s:%s to element %s:%s",
+            GST_ELEMENT_NAME (src), srcpadname ? srcpadname : "(any)", 
+            GST_ELEMENT_NAME (dest), destpadname ? destpadname : "(any)");
 
-  if (srcpads || destpads) {
-    while (srcpads) {
-      srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
+  /* now get the pads we're trying to link and a list of all remaining pads */
+  if (srcpadname) {
+    srcpad = gst_element_get_pad (src, srcpadname);
+    if (!srcpad) {
+      GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s", GST_ELEMENT_NAME (src), srcpadname);    
+      return FALSE;
+    } else {
+      if (!(GST_RPAD_DIRECTION (srcpad) == GST_PAD_SRC)) {
+        GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad", GST_DEBUG_PAD_NAME (srcpad));    
+        return FALSE;
+      }
+      if (GST_PAD_PEER (srcpad) != NULL) {
+        GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked", GST_DEBUG_PAD_NAME (srcpad));    
+        return FALSE;
+      }
+    }    
+    srcpads = NULL;
+  } else {
+    srcpads = gst_element_get_pad_list (src);
+    srcpad = srcpads ? (GstPad *) GST_PAD_REALIZE (srcpads->data) : NULL;
+  }
+  if (destpadname) {
+    destpad = gst_element_get_pad (dest, destpadname);
+    if (!destpad) {
+      GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s", GST_ELEMENT_NAME (dest), destpadname);    
+      return FALSE;
+    } else {
+      if (!(GST_RPAD_DIRECTION (destpad) == GST_PAD_SINK)) {
+        GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no sink pad", GST_DEBUG_PAD_NAME (destpad));    
+        return FALSE;
+      }
+      if (GST_PAD_PEER (destpad) != NULL) {
+        GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked", GST_DEBUG_PAD_NAME (destpad));    
+        return FALSE;
+      }
+    }
+    destpads = NULL;
+  } else {
+    destpads = gst_element_get_pad_list (dest);
+    destpad = destpads ? (GstPad *) GST_PAD_REALIZE (destpads->data) : NULL;
+  }
+
+  if (srcpadname && destpadname) {
+    /* two explicitly specified pads */
+    return gst_pad_link_filtered (srcpad, destpad, filtercaps);  
+  }
+  if (srcpad) {
+    /* loop through the allowed pads in the source, trying to find a
+     * compatible destination pad */
+    GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "looping through allowed src and dest pads");
+    do {
+      GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s", 
+                GST_DEBUG_PAD_NAME (srcpad));
       if ((GST_RPAD_DIRECTION (srcpad) == GST_PAD_SRC) &&
           (GST_PAD_PEER (srcpad) == NULL)) {
-        destpad = gst_element_get_compatible_pad_filtered (dest, srcpad, 
-                                                          filtercaps);
-        if (destpad && gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
-          GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s", 
-                    GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
+        GstPad *temp = gst_element_get_compatible_pad_filtered (dest, srcpad, 
+                                                                filtercaps);
+        if (temp && gst_pad_link_filtered (srcpad, temp, filtercaps)) {
+          GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s", 
+                    GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (temp));
           return TRUE;
         }
       }
-      srcpads = g_list_next (srcpads);
-    }
-    
+      /* find a better way for this mess */
+      if (srcpads) {
+       srcpads = g_list_next (srcpads);
+        if (srcpads)
+         srcpad = (GstPad *) GST_PAD_REALIZE (srcpads->data);
+      }
+    } while (srcpads);
+  }
+  if (srcpadname) {
+    GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s:%s to %s", 
+               GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (dest));
+    return FALSE;
+  }
+  if (destpad) {    
     /* loop through the existing pads in the destination */
-    while (destpads) {
-      destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
+    do {
+      GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying dest pad %s:%s", 
+                GST_DEBUG_PAD_NAME (destpad));
       if ((GST_RPAD_DIRECTION (destpad) == GST_PAD_SINK) &&
           (GST_PAD_PEER (destpad) == NULL)) {
-        srcpad = gst_element_get_compatible_pad_filtered (src, destpad, 
+        GstPad *temp = gst_element_get_compatible_pad_filtered (src, destpad, 
                                                          filtercaps);
-        if (srcpad && gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
-          GST_DEBUG (GST_CAT_ELEMENT_PADS, "connected pad %s:%s to pad %s:%s", 
-                    GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
+        if (temp && gst_pad_link_filtered (temp, destpad, filtercaps)) {
+          GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s", 
+                    GST_DEBUG_PAD_NAME (temp), GST_DEBUG_PAD_NAME (destpad));
           return TRUE;
         }
       }
-      destpads = g_list_next (destpads);
-    }
+      if (destpads) {
+       destpads = g_list_next (destpads);
+        if (destpads)
+         destpad = (GstPad *) GST_PAD_REALIZE (destpads->data);
+      }
+    } while (destpads);
+  }
+  if (destpadname) {
+    GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s:%s", 
+               GST_ELEMENT_NAME (src), GST_DEBUG_PAD_NAME (destpad));
+    return FALSE;
   }
 
-  GST_DEBUG (GST_CAT_ELEMENT_PADS, 
+  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, 
              "we might have request pads on both sides, checking...");
   srctempls = gst_element_get_pad_template_list (src);
   desttempls = gst_element_get_pad_template_list (dest);
@@ -1545,15 +1555,15 @@ gst_element_connect_filtered (GstElement *src, GstElement *dest,
           desttempl = (GstPadTemplate*) desttempls->data;
           if (desttempl->presence == GST_PAD_REQUEST && 
              desttempl->direction != srctempl->direction) {
-            if (gst_caps_check_compatibility (gst_pad_template_get_caps (srctempl),
+            if (gst_caps_is_always_compatible (gst_pad_template_get_caps (srctempl),
                                               gst_pad_template_get_caps (desttempl))) {
               srcpad = gst_element_get_request_pad (src, 
                                                    srctempl->name_template);
               destpad = gst_element_get_request_pad (dest, 
                                                     desttempl->name_template);
-              if (gst_pad_connect_filtered (srcpad, destpad, filtercaps)) {
-                GST_DEBUG (GST_CAT_ELEMENT_PADS, 
-                          "connected pad %s:%s to pad %s:%s",
+              if (gst_pad_link_filtered (srcpad, destpad, filtercaps)) {
+                GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, 
+                          "linked pad %s:%s to pad %s:%s",
                            GST_DEBUG_PAD_NAME (srcpad), 
                           GST_DEBUG_PAD_NAME (destpad));
                 return TRUE;
@@ -1567,23 +1577,44 @@ gst_element_connect_filtered (GstElement *src, GstElement *dest,
     }
   }
   
-  GST_DEBUG (GST_CAT_ELEMENT_PADS, "no connection possible from %s to %s", 
+  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s to %s", 
              GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
   return FALSE;  
 }
+/**
+ * gst_element_link_filtered:
+ * @src: a #GstElement containing the source pad.
+ * @dest: the #GstElement containing the destination pad.
+ * @filtercaps: the #GstCaps to use as a filter.
+ *
+ * Links the source to the destination element using the filtercaps.
+ * The link must be from source to destination, the other
+ * direction will not be tried.
+ * The functions looks for existing pads that aren't linked yet.
+ * It will use request pads if possible. But both pads will not be requested.
+ * If multiple links are possible, only one is established.
+ *
+ * Returns: TRUE if the elements could be linked.
+ */
+gboolean
+gst_element_link_filtered (GstElement *src, GstElement *dest,
+                             GstCaps *filtercaps)
+{
+  return gst_element_link_pads_filtered (src, NULL, dest, NULL, filtercaps);
+}
 
 /**
- * gst_element_connect_many:
- * @element_1: the first #GstElement in the connection chain.
- * @element_2: the second #GstElement in the connection chain.
- * @...: the NULL-terminated list of elements to connect in order.
+ * gst_element_link_many:
+ * @element_1: the first #GstElement in the link chain.
+ * @element_2: the second #GstElement in the link chain.
+ * @...: the NULL-terminated list of elements to link in order.
  * 
- * Chain together a series of elements. Uses #gst_element_connect.
+ * Chain together a series of elements. Uses #gst_element_link.
  *
  * Returns: TRUE on success, FALSE otherwise.
  */
 gboolean
-gst_element_connect_many (GstElement *element_1, GstElement *element_2, ...)
+gst_element_link_many (GstElement *element_1, GstElement *element_2, ...)
 {
   va_list args;
 
@@ -1594,7 +1625,7 @@ gst_element_connect_many (GstElement *element_1, GstElement *element_2, ...)
   va_start (args, element_2);
 
   while (element_2) {
-    if (!gst_element_connect (element_1, element_2))
+    if (!gst_element_link (element_1, element_2))
       return FALSE;
     
     element_1 = element_2;
@@ -1607,102 +1638,57 @@ gst_element_connect_many (GstElement *element_1, GstElement *element_2, ...)
 }
 
 /**
- * gst_element_connect:
+ * gst_element_link:
  * @src: a #GstElement containing the source pad.
  * @dest: the #GstElement containing the destination pad.
  *
- * Connects the source to the destination element.
- * The connection must be from source to destination, the other
+ * Links the source to the destination element.
+ * The link must be from source to destination, the other
  * direction will not be tried.
  * The functions looks for existing pads and request pads that aren't
- * connected yet. If multiple connections are possible, only one is
+ * linked yet. If multiple links are possible, only one is
  * established.
  *
- * Returns: TRUE if the elements could be connected.
+ * Returns: TRUE if the elements could be linked.
  */
 gboolean
-gst_element_connect (GstElement *src, GstElement *dest)
+gst_element_link (GstElement *src, GstElement *dest)
 {
-  return gst_element_connect_filtered (src, dest, NULL);
+  return gst_element_link_pads_filtered (src, NULL, dest, NULL, NULL);
 }
 
 /**
- * gst_element_connect_pads_filtered:
- * @src: a #GstElement containing the source pad.
- * @srcpadname: the name of the #GstPad in source element.
- * @dest: the #GstElement containing the destination pad.
- * @destpadname: the name of the #GstPad in destination element.
- * @filtercaps: the #GstCaps to use as a filter.
- *
- * Connects the two named pads of the source and destination elements.
- * Side effect is that if one of the pads has no parent, it becomes a
- * child of the parent of the other element.  If they have different
- * parents, the connection fails.
- *
- * Returns: TRUE if the pads could be connected.
- */
-gboolean
-gst_element_connect_pads_filtered (GstElement *src, const gchar *srcpadname,
-                                   GstElement *dest, const gchar *destpadname, 
-                                   GstCaps *filtercaps)
-{
-  GstPad *srcpad,*destpad;
-
-  g_return_val_if_fail (src != NULL, FALSE);
-  g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);
-  g_return_val_if_fail (srcpadname != NULL, FALSE);
-  g_return_val_if_fail (dest != NULL, FALSE);
-  g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);
-  g_return_val_if_fail (destpadname != NULL, FALSE);
-
-  /* obtain the pads requested */
-  srcpad = gst_element_get_pad (src, srcpadname);
-  if (srcpad == NULL) {
-    GST_ERROR (src, "source element has no pad \"%s\"", srcpadname);
-    return FALSE;
-  }
-  destpad = gst_element_get_pad (dest, destpadname);
-  if (srcpad == NULL) {
-    GST_ERROR (dest, "destination element has no pad \"%s\"", destpadname);
-    return FALSE;
-  }
-
-  /* we're satisified they can be connected, let's do it */
-  return gst_pad_connect_filtered (srcpad, destpad, filtercaps);
-}
-
-/**
- * gst_element_connect_pads:
+ * gst_element_link_pads:
  * @src: a #GstElement containing the source pad.
  * @srcpadname: the name of the #GstPad in the source element.
  * @dest: the #GstElement containing the destination pad.
  * @destpadname: the name of the #GstPad in destination element.
  *
- * Connects the two named pads of the source and destination elements.
+ * Links the two named pads of the source and destination elements.
  * Side effect is that if one of the pads has no parent, it becomes a
  * child of the parent of the other element.  If they have different
- * parents, the connection fails.
+ * parents, the link fails.
  *
- * Returns: TRUE if the pads could be connected.
+ * Returns: TRUE if the pads could be linked.
  */
 gboolean
-gst_element_connect_pads (GstElement *src, const gchar *srcpadname,
+gst_element_link_pads (GstElement *src, const gchar *srcpadname,
                           GstElement *dest, const gchar *destpadname)
 {
-  return gst_element_connect_pads_filtered (src, srcpadname, dest, destpadname, NULL);
+  return gst_element_link_pads_filtered (src, srcpadname, dest, destpadname, NULL);
 }
 
 /**
- * gst_element_disconnect_pads:
+ * gst_element_unlink_pads:
  * @src: a #GstElement containing the source pad.
  * @srcpadname: the name of the #GstPad in source element.
  * @dest: a #GstElement containing the destination pad.
  * @destpadname: the name of the #GstPad in destination element.
  *
- * Disconnects the two named pads of the source and destination elements.
+ * Unlinks the two named pads of the source and destination elements.
  */
 void
-gst_element_disconnect_pads (GstElement *src, const gchar *srcpadname,
+gst_element_unlink_pads (GstElement *src, const gchar *srcpadname,
                              GstElement *dest, const gchar *destpadname)
 {
   GstPad *srcpad,*destpad;
@@ -1717,29 +1703,29 @@ gst_element_disconnect_pads (GstElement *src, const gchar *srcpadname,
   /* obtain the pads requested */
   srcpad = gst_element_get_pad (src, srcpadname);
   if (srcpad == NULL) {
-    GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
+    GST_WARNING_OBJECT (src, "source element has no pad \"%s\"", srcpadname);
     return;
   }
   destpad = gst_element_get_pad (dest, destpadname);
   if (srcpad == NULL) {
-    GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
+    GST_WARNING_OBJECT (dest, "destination element has no pad \"%s\"", destpadname);
     return;
   }
 
-  /* we're satisified they can be disconnected, let's do it */
-  gst_pad_disconnect(srcpad,destpad);
+  /* we're satisified they can be unlinked, let's do it */
+  gst_pad_unlink (srcpad,destpad);
 }
 
 /**
- * gst_element_disconnect_many:
- * @element_1: the first #GstElement in the connection chain.
- * @element_2: the second #GstElement in the connection chain.
- * @...: the NULL-terminated list of elements to disconnect in order.
+ * gst_element_unlink_many:
+ * @element_1: the first #GstElement in the link chain.
+ * @element_2: the second #GstElement in the link chain.
+ * @...: the NULL-terminated list of elements to unlink in order.
  * 
- * Disconnects a series of elements. Uses #gst_element_disconnect.
+ * Unlinks a series of elements. Uses #gst_element_unlink.
  */
 void
-gst_element_disconnect_many (GstElement *element_1, GstElement *element_2, ...)
+gst_element_unlink_many (GstElement *element_1, GstElement *element_2, ...)
 {
   va_list args;
 
@@ -1749,7 +1735,7 @@ gst_element_disconnect_many (GstElement *element_1, GstElement *element_2, ...)
   va_start (args, element_2);
 
   while (element_2) {
-    gst_element_disconnect (element_1, element_2);
+    gst_element_unlink (element_1, element_2);
     
     element_1 = element_2;
     element_2 = va_arg (args, GstElement*);
@@ -1759,36 +1745,40 @@ gst_element_disconnect_many (GstElement *element_1, GstElement *element_2, ...)
 }
 
 /**
- * gst_element_disconnect:
- * @src: the source #GstElement to disconnect.
- * @dest: the sink #GstElement to disconnect.
+ * gst_element_unlink:
+ * @src: the source #GstElement to unlink.
+ * @dest: the sink #GstElement to unlink.
  *
- * Disconnects all source pads of the source element with all sink pads
- * of the sink element to which they are connected.
+ * Unlinks all source pads of the source element with all sink pads
+ * of the sink element to which they are linked.
  */
 void
-gst_element_disconnect (GstElement *src, GstElement *dest)
+gst_element_unlink (GstElement *src, GstElement *dest)
 {
-  GList *srcpads;
+  const GList *srcpads;
   GstPad *pad;
 
   g_return_if_fail (GST_IS_ELEMENT (src));
   g_return_if_fail (GST_IS_ELEMENT (dest));
 
-  GST_DEBUG (GST_CAT_ELEMENT_PADS, "disconnecting \"%s\" and \"%s\"", 
+  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "unlinking \"%s\" and \"%s\"",
              GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (dest));
 
   srcpads = gst_element_get_pad_list (src);
 
   while (srcpads) {
     pad = GST_PAD_CAST (srcpads->data);
-    
-    if (GST_IS_REAL_PAD (pad) && GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
+
+    /* we only care about real src pads */
+    if (GST_IS_REAL_PAD (pad) && GST_PAD_IS_SRC (pad)) {
       GstPad *peerpad = GST_PAD_PEER (pad);
 
+      /* see if the pad is connected and is really a pad
+       * of dest */
       if (peerpad && 
-         (GST_OBJECT_PARENT (GST_PAD_PEER (peerpad)) == (GstObject*) src)) {
-        gst_pad_disconnect (pad, peerpad);
+         (GST_OBJECT_PARENT (peerpad) == (GstObject*) dest)) 
+      {
+        gst_pad_unlink (pad, peerpad);
       }
     }
 
@@ -1802,7 +1792,7 @@ gst_element_error_func (GstElement* element, GstElement *source,
 {
   /* tell the parent */
   if (GST_OBJECT_PARENT (element)) {
-    GST_DEBUG (GST_CAT_EVENT, "forwarding error \"%s\" from %s to %s", 
+    GST_CAT_DEBUG (GST_CAT_EVENT, "forwarding error \"%s\" from %s to %s", 
               errormsg, GST_ELEMENT_NAME (element), 
               GST_OBJECT_NAME (GST_OBJECT_PARENT (element)));
 
@@ -1813,24 +1803,65 @@ gst_element_error_func (GstElement* element, GstElement *source,
   }
 }
 
-static gboolean
-gst_element_send_event_default (GstElement *element, GstEvent *event)
+static GstPad*
+gst_element_get_random_pad (GstElement *element, GstPadDirection dir)
 {
   GList *pads = element->pads;
-  gboolean res = FALSE;
-
+  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "getting a random pad");
   while (pads) {
     GstPad *pad = GST_PAD_CAST (pads->data);
-    
-    if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
-      if (GST_PAD_IS_USABLE (pad)) {
-       res = gst_pad_send_event (GST_PAD_PEER (pad), event);
-       break;
+
+    GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "checking pad %s:%s",
+              GST_DEBUG_PAD_NAME (pad));
+
+    if (GST_PAD_DIRECTION (pad) == dir) {
+      if (GST_PAD_IS_LINKED (pad)) {
+       return pad;
       }
+      else {
+        GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is not linked",
+                  GST_DEBUG_PAD_NAME (pad));
+      }
+    }
+    else {
+      GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is in wrong direction",
+                 GST_DEBUG_PAD_NAME (pad));
     }
+
     pads = g_list_next (pads);
   }
-  return res;
+  return NULL;
+}
+
+/**
+ * gst_element_get_event_masks:
+ * @element: a #GstElement to query
+ *
+ * Get an array of event masks from the element.
+ * If the element doesn't 
+ * implement an event masks function, the query will be forwarded
+ * to a random linked sink pad.
+ * 
+ * Returns: An array of #GstEventMask elements.
+ */
+const GstEventMask*
+gst_element_get_event_masks (GstElement *element)
+{
+  GstElementClass *oclass;
+
+  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+  
+  oclass = GST_ELEMENT_GET_CLASS (element);
+
+  if (oclass->get_event_masks)
+    return oclass->get_event_masks (element);
+  else {
+    GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
+    if (pad)
+      return gst_pad_get_event_masks (GST_PAD_PEER (pad));
+  }
+
+  return FALSE;
 }
 
 /**
@@ -1838,49 +1869,92 @@ gst_element_send_event_default (GstElement *element, GstEvent *event)
  * @element: a #GstElement to send the event to.
  * @event: the #GstEvent to send to the element.
  *
- * Sends an event to an element. If the element doesn't 
+ * Sends an event to an element. If the element doesn't
  * implement an event handler, the event will be forwarded
  * to a random sink pad.
- * 
+ *
  * Returns: TRUE if the event was handled.
  */
 gboolean
 gst_element_send_event (GstElement *element, GstEvent *event)
 {
+  GstElementClass *oclass;
+
   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
   
-  if (CLASS (element)->send_event)
-    return CLASS (element)->send_event (element, event);
+  oclass = GST_ELEMENT_GET_CLASS (element);
 
+  if (oclass->send_event)
+    return oclass->send_event (element, event);
+  else {
+    GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
+    if (pad) {
+      GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "sending event to random pad %s:%s",
+                GST_DEBUG_PAD_NAME (pad));
+      return gst_pad_send_event (GST_PAD_PEER (pad), event);
+    }
+  }
+  GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "can't send event on element %s",
+            GST_ELEMENT_NAME (element));
   return FALSE;
 }
 
-static gboolean
-gst_element_query_default (GstElement *element, GstPadQueryType type,
-                          GstFormat *format, gint64 *value)
+/**
+ * gst_element_seek:
+ * @element: a #GstElement to send the event to.
+ * @seek_type: the method to use for seeking.
+ * @offset: the offset to seek to.
+ *
+ * Sends a seek event to an element.
+ *
+ * Returns: TRUE if the event was handled.
+ */
+gboolean
+gst_element_seek (GstElement  *element,
+                 GstSeekType  seek_type,
+                 guint64      offset)
 {
-  GList *pads = element->pads;
-  gboolean res = FALSE;
+  GstEvent *event = gst_event_new_seek (seek_type, offset);
 
-  while (pads) {
-    GstPad *pad = GST_PAD_CAST (pads->data);
-    
-    if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
-      if (GST_PAD_IS_USABLE (pad)) {
-       res = gst_pad_query (GST_PAD_PEER (pad), type, format, value);
-       break;
-      }
-    }
-    pads = g_list_next (pads);
+  return gst_element_send_event (element, event);
+}
+
+/**
+ * gst_element_get_query_types:
+ * @element: a #GstElement to query
+ *
+ * Get an array of query types from the element.
+ * If the element doesn't 
+ * implement a query types function, the query will be forwarded
+ * to a random sink pad.
+ * 
+ * Returns: An array of #GstQueryType elements.
+ */
+const GstQueryType*
+gst_element_get_query_types (GstElement *element)
+{
+  GstElementClass *oclass;
+
+  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+  
+  oclass = GST_ELEMENT_GET_CLASS (element);
+
+  if (oclass->get_query_types)
+    return oclass->get_query_types (element);
+  else {
+    GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
+    if (pad)
+      return gst_pad_get_query_types (GST_PAD_PEER (pad));
   }
-  return res;
+
+  return FALSE;
 }
 
 /**
  * gst_element_query:
  * @element: a #GstElement to perform the query on.
- * @type: the #GstPadQueryType.
+ * @type: the #GstQueryType.
  * @format: the #GstFormat pointer to hold the format of the result.
  * @value: the pointer to the value of the result.
  *
@@ -1888,20 +1962,108 @@ gst_element_query_default (GstElement *element, GstPadQueryType type,
  * to GST_FORMAT_DEFAULT and this function returns TRUE, the 
  * format pointer will hold the default format.
  * For element that don't implement a query handler, this function
- * forwards the query to a random connected sinkpad of this element.
+ * forwards the query to a random usable sinkpad of this element.
  * 
  * Returns: TRUE if the query could be performed.
  */
 gboolean
-gst_element_query (GstElement *element, GstPadQueryType type,
+gst_element_query (GstElement *element, GstQueryType type,
                   GstFormat *format, gint64 *value)
 {
+  GstElementClass *oclass;
+
   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
   g_return_val_if_fail (format != NULL, FALSE);
   g_return_val_if_fail (value != NULL, FALSE);
+
+  oclass = GST_ELEMENT_GET_CLASS (element);
   
-  if (CLASS (element)->query)
-    return CLASS (element)->query (element, type, format, value);
+  if (oclass->query)
+    return oclass->query (element, type, format, value);
+  else {
+    GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
+    if (pad)
+      return gst_pad_query (GST_PAD_PEER (pad), type, format, value);
+  }
+
+  return FALSE;
+}
+
+/**
+ * gst_element_get_formats:
+ * @element: a #GstElement to query
+ *
+ * Get an array of formst from the element.
+ * If the element doesn't 
+ * implement a formats function, the query will be forwarded
+ * to a random sink pad.
+ * 
+ * Returns: An array of #GstFormat elements.
+ */
+const GstFormat*
+gst_element_get_formats (GstElement *element)
+{
+  GstElementClass *oclass;
+
+  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+  
+  oclass = GST_ELEMENT_GET_CLASS (element);
+
+  if (oclass->get_formats)
+    return oclass->get_formats (element);
+  else {
+    GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
+    if (pad)
+      return gst_pad_get_formats (GST_PAD_PEER (pad));
+  }
+
+  return FALSE;
+}
+
+/**
+ * gst_element_convert:
+ * @element: a #GstElement to invoke the converter on.
+ * @src_format: the source #GstFormat.
+ * @src_value: the source value.
+ * @dest_format: a pointer to the destination #GstFormat.
+ * @dest_value: a pointer to the destination value.
+ *
+ * Invokes a conversion on the element.
+ * If the element doesn't 
+ * implement a convert function, the query will be forwarded
+ * to a random sink pad.
+ *
+ * Returns: TRUE if the conversion could be performed.
+ */
+gboolean
+gst_element_convert (GstElement *element,
+                    GstFormat  src_format,  gint64  src_value,
+                    GstFormat *dest_format, gint64 *dest_value)
+{
+  GstElementClass *oclass;
+
+  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+  g_return_val_if_fail (dest_format != NULL, FALSE);
+  g_return_val_if_fail (dest_value != NULL, FALSE);
+
+  if (src_format == *dest_format) {
+    *dest_value = src_value;
+    return TRUE;
+  }
+
+  oclass = GST_ELEMENT_GET_CLASS (element);
+
+  if (oclass->convert)
+    return oclass->convert (element,
+                           src_format, src_value, 
+                           dest_format, dest_value);
+  else {
+    GstPad *pad = gst_element_get_random_pad (element, GST_PAD_SINK);
+    if (pad)
+      return gst_pad_convert (GST_PAD_PEER (pad), 
+                             src_format, src_value, 
+                             dest_format, dest_value);
+  }
 
   return FALSE;
 }
@@ -1930,7 +2092,16 @@ gst_element_error (GstElement *element, const gchar *error, ...)
   va_start (var_args, error);
   string = g_strdup_vprintf (error, var_args);
   va_end (var_args);
-  GST_INFO (GST_CAT_EVENT, "ERROR in %s: %s", GST_ELEMENT_NAME (element), string);
+  GST_CAT_INFO (GST_CAT_EVENT, "ERROR in %s: %s", GST_ELEMENT_NAME (element), string);
+
+  /* if the element was already in error, stop now */
+  if (GST_FLAG_IS_SET (element, GST_ELEMENT_ERROR)) {
+    GST_CAT_INFO (GST_CAT_EVENT, "recursive ERROR detected in %s", GST_ELEMENT_NAME (element));
+    g_free (string);
+    return;
+  }
+    
+  GST_FLAG_SET (element, GST_ELEMENT_ERROR);
 
   /* emit the signal, make sure the element stays available */
   gst_object_ref (GST_OBJECT (element));
@@ -1941,11 +2112,97 @@ gst_element_error (GstElement *element, const gchar *error, ...)
     gst_scheduler_error (element->sched, element); 
   } 
 
+  if (GST_STATE (element) == GST_STATE_PLAYING) { 
+    GstElementStateReturn ret;
+    
+    ret = gst_element_set_state (element, GST_STATE_PAUSED);
+    if (ret != GST_STATE_SUCCESS) {
+      g_warning ("could not PAUSE element \"%s\" after error, help!", GST_ELEMENT_NAME (element));
+    }
+  }
+
+  GST_FLAG_UNSET (element, GST_ELEMENT_ERROR);
+
   /* cleanup */
   gst_object_unref (GST_OBJECT (element));
   g_free (string);
 }
 
+/**
+ * gst_element_is_locked_state:
+ * @element: a #GstElement.
+ *
+ * Checks if the state of an element is locked.
+ * If the state of an element is locked, state changes of the parent don't 
+ * affect the element.
+ * This way you can leave currently unused elements inside bins. Just lock their
+ * state before changing the state from #GST_STATE_NULL.
+ *
+ * Returns: TRUE, if the element's state is locked.
+ */
+gboolean
+gst_element_is_locked_state (GstElement *element)
+{
+  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+
+  return GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE) ? TRUE : FALSE;
+}
+/**
+ * gst_element_set_locked_state:
+ * @element: a #GstElement
+ * @locked_state: TRUE to lock the element's state
+ *
+ * Locks the state of an element, so state changes of the parent don't affect
+ * this element anymore.
+ */
+void
+gst_element_set_locked_state (GstElement *element, gboolean locked_state)
+{
+  gboolean old;
+
+  g_return_if_fail (GST_IS_ELEMENT (element));
+
+  old = GST_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE);
+
+  if (old == locked_state)
+    return;
+
+  if (locked_state) {
+    GST_CAT_DEBUG (GST_CAT_STATES, "locking state of element %s", 
+               GST_ELEMENT_NAME (element));
+    GST_FLAG_SET (element, GST_ELEMENT_LOCKED_STATE);
+  } else {
+    GST_CAT_DEBUG (GST_CAT_STATES, "unlocking state of element %s", 
+               GST_ELEMENT_NAME (element));
+    GST_FLAG_UNSET (element, GST_ELEMENT_LOCKED_STATE);
+  }
+}
+/**
+ * gst_element_sync_state_with_parent:
+ * @element: a #GstElement.
+ *
+ * Tries to change the state of the element to the same as its parent.
+ * If this function returns FALSE, the state of element is undefined.
+ *
+ * Returns: TRUE, if the element's state could be synced to the parent's state.
+ */
+gboolean
+gst_element_sync_state_with_parent (GstElement *element)
+{
+  GstElement *parent;
+
+  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+  parent = GST_ELEMENT (GST_ELEMENT_PARENT(element));
+  g_return_val_if_fail (GST_IS_BIN (parent), FALSE);
+  
+  GST_CAT_DEBUG (GST_CAT_STATES, "syncing state of element %s (%s) to %s (%s)", 
+             GST_ELEMENT_NAME (element), gst_element_state_get_name (GST_STATE (element)),
+             GST_ELEMENT_NAME (parent), gst_element_state_get_name (GST_STATE (parent)));
+  if (gst_element_set_state (element, GST_STATE (parent)) == GST_STATE_FAILURE) {
+    return FALSE;
+  }
+  return TRUE;
+}
 /**
  * gst_element_get_state:
  * @element: a #GstElement to get the state of.
@@ -1988,7 +2245,7 @@ gst_element_wait_state_change (GstElement *element)
  * Returns: TRUE if the state was successfully set.
  * (using #GstElementStateReturn).
  */
-gint
+GstElementStateReturn
 gst_element_set_state (GstElement *element, GstElementState state)
 {
   GstElementClass *oclass;
@@ -2000,7 +2257,15 @@ gst_element_set_state (GstElement *element, GstElementState state)
   /* start with the current state */
   curpending = GST_STATE(element);
 
-  GST_DEBUG_ELEMENT (GST_CAT_STATES, element, "setting state from %s to %s",
+  if (state == curpending)
+  {
+    GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
+                       "element is already in requested state %s",
+                       gst_element_state_get_name (state));
+    return (GST_STATE_SUCCESS);
+  }
+
+  GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, "setting state from %s to %s",
                      gst_element_state_get_name (curpending),
                      gst_element_state_get_name (state));
 
@@ -2018,37 +2283,39 @@ gst_element_set_state (GstElement *element, GstElementState state)
     GST_STATE_PENDING (element) = curpending;
 
     if (curpending != state) {
-      GST_DEBUG_ELEMENT (GST_CAT_STATES, element, 
+      GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, 
                         "intermediate: setting state from %s to %s",
                         gst_element_state_get_name (GST_STATE (element)),
                          gst_element_state_get_name (curpending));
     }
 
     /* call the state change function so it can set the state */
-    oclass = CLASS (element);
+    oclass = GST_ELEMENT_GET_CLASS (element);
     if (oclass->change_state)
       return_val = (oclass->change_state) (element);
 
     switch (return_val) {
       case GST_STATE_FAILURE:
-        GST_DEBUG_ELEMENT (GST_CAT_STATES, element, 
+        GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, 
                           "have failed change_state return");
         goto exit;
       case GST_STATE_ASYNC:
-        GST_DEBUG_ELEMENT (GST_CAT_STATES, element, 
+        GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, 
                           "element will change state async");
         goto exit;
       case GST_STATE_SUCCESS:
         /* Last thing we do is verify that a successful state change really
          * did change the state... */
-        if (GST_STATE (element) != curpending) {
-          GST_DEBUG_ELEMENT (GST_CAT_STATES, element, 
-                            "element claimed state-change success,"
-                            "but state didn't change %s, %s <-> %s",
-                            gst_element_state_get_name (GST_STATE (element)),
-                            gst_element_state_get_name (GST_STATE_PENDING (element)),
-                            gst_element_state_get_name (curpending));
-          return GST_STATE_FAILURE;
+        /* if it did not, this is an error - fix the element that does this */
+       if (GST_STATE (element) != curpending) {
+         g_warning ("element %s claimed state-change success,"
+                    "but state didn't change to %s. State is %s (%s pending), fix the element",
+                    GST_ELEMENT_NAME (element),
+                    gst_element_state_get_name (curpending),
+                    gst_element_state_get_name (GST_STATE (element)),
+                    gst_element_state_get_name (GST_STATE_PENDING (element)));
+         return_val = GST_STATE_FAILURE;
+          goto exit;
        }
         break;
       default:
@@ -2066,7 +2333,7 @@ gst_element_negotiate_pads (GstElement *element)
 {
   GList *pads = GST_ELEMENT_PADS (element);
 
-  GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "negotiating pads");
+  GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, "negotiating pads");
 
   while (pads) {
     GstPad *pad = GST_PAD (pads->data);
@@ -2079,9 +2346,9 @@ gst_element_negotiate_pads (GstElement *element)
 
     srcpad = GST_PAD_REALIZE (pad);
 
-    /* if we have a connection on this pad and it doesn't have caps
+    /* if we have a link on this pad and it doesn't have caps
      * allready, try to negotiate */
-    if (GST_PAD_IS_USABLE (srcpad) && !GST_PAD_CAPS (srcpad)) {
+    if (GST_PAD_IS_LINKED (srcpad) && !GST_PAD_CAPS (srcpad)) {
       GstRealPad *sinkpad;
       GstElementState otherstate;
       GstElement *parent;
@@ -2093,6 +2360,11 @@ gst_element_negotiate_pads (GstElement *element)
       if (!parent) 
        continue;
 
+      /* skips pads that were already negotiating */
+      if (GST_FLAG_IS_SET (sinkpad, GST_PAD_NEGOTIATING) ||
+          GST_FLAG_IS_SET (srcpad, GST_PAD_NEGOTIATING))
+       continue;
+
       otherstate = GST_STATE (parent);
 
       /* swap pads if needed */
@@ -2106,7 +2378,7 @@ gst_element_negotiate_pads (GstElement *element)
 
       /* only try to negotiate if the peer element is in PAUSED or higher too */
       if (otherstate >= GST_STATE_READY) {
-        GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, 
+        GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, 
                           "perform negotiate for %s:%s and %s:%s",
                           GST_DEBUG_PAD_NAME (srcpad), 
                           GST_DEBUG_PAD_NAME (sinkpad));
@@ -2114,7 +2386,7 @@ gst_element_negotiate_pads (GstElement *element)
          return FALSE;
       }
       else {
-        GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, 
+        GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, 
                           "not negotiating %s:%s and %s:%s, not in READY yet",
                           GST_DEBUG_PAD_NAME (srcpad), 
                           GST_DEBUG_PAD_NAME (sinkpad));
@@ -2130,18 +2402,33 @@ gst_element_clear_pad_caps (GstElement *element)
 {
   GList *pads = GST_ELEMENT_PADS (element);
 
-  GST_DEBUG_ELEMENT (GST_CAT_CAPS, element, "clearing pad caps");
+  GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, element, "clearing pad caps");
 
   while (pads) {
     GstRealPad *pad = GST_PAD_REALIZE (pads->data);
 
-    if (GST_PAD_CAPS (pad)) {
-      GST_PAD_CAPS (pad) = NULL;
-    }
+    gst_caps_replace (&GST_PAD_CAPS (pad), NULL);
+
     pads = g_list_next (pads);
   }
 }
 
+static void
+gst_element_pads_activate (GstElement *element, gboolean active)
+{
+  GList *pads = element->pads;
+
+  while (pads) {
+    GstPad *pad = GST_PAD_CAST (pads->data);
+    pads = g_list_next (pads);
+
+    if (!GST_IS_REAL_PAD (pad))
+      continue;
+
+    gst_pad_set_active (pad, active);
+  }
+}
+
 static GstElementStateReturn
 gst_element_change_state (GstElement *element)
 {
@@ -2157,23 +2444,29 @@ gst_element_change_state (GstElement *element)
 
   if (old_pending == GST_STATE_VOID_PENDING || 
       old_state == GST_STATE_PENDING (element)) {
-    GST_INFO (GST_CAT_STATES, 
+    GST_CAT_INFO (GST_CAT_STATES, 
              "no state change needed for element %s (VOID_PENDING)", 
              GST_ELEMENT_NAME (element));
     return GST_STATE_SUCCESS;
   }
   
-  GST_INFO (GST_CAT_STATES, "%s default handler sets state from %s to %s %d", 
+  GST_CAT_INFO (GST_CAT_STATES, "%s default handler sets state from %s to %s %04x", 
             GST_ELEMENT_NAME (element),
             gst_element_state_get_name (old_state),
             gst_element_state_get_name (old_pending),
-           GST_STATE_TRANSITION (element));
+           old_transition);
 
   /* we set the state change early for the negotiation functions */
   GST_STATE (element) = old_pending;
   GST_STATE_PENDING (element) = GST_STATE_VOID_PENDING;
 
   switch (old_transition) {
+    case GST_STATE_PLAYING_TO_PAUSED:
+      gst_element_pads_activate (element, FALSE);
+      break;
+    case GST_STATE_PAUSED_TO_PLAYING:
+      gst_element_pads_activate (element, TRUE);
+      break;
     /* if we are going to paused, we try to negotiate the pads */
     case GST_STATE_READY_TO_PAUSED:
       if (!gst_element_negotiate_pads (element)) 
@@ -2187,28 +2480,32 @@ gst_element_change_state (GstElement *element)
       break;
   }
 
+  parent = GST_ELEMENT_PARENT (element);
+
+  GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
+                     "signaling state change from %s to %s",
+                     gst_element_state_get_name (old_state),
+                     gst_element_state_get_name (GST_STATE (element)));
+
   /* tell the scheduler if we have one */
   if (element->sched) {
     if (gst_scheduler_state_transition (element->sched, element, 
                                        old_transition) != GST_STATE_SUCCESS) {
+      GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, 
+                        "scheduler could not change state");
       goto failure;
     }
   }
 
-  parent = GST_ELEMENT_PARENT (element);
-
-  GST_DEBUG_ELEMENT (GST_CAT_STATES, element,
-                     "signaling state change from %s to %s",
-                     gst_element_state_get_name (old_state),
-                     gst_element_state_get_name (GST_STATE (element)));
-  g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
-                0, old_state, GST_STATE (element));
-
   /* tell our parent about the state change */
   if (parent && GST_IS_BIN (parent)) {
     gst_bin_child_state_change (GST_BIN (parent), old_state, 
                                GST_STATE (element), element);
   }
+  /* at this point the state of the element could have changed again */
+
+  g_signal_emit (G_OBJECT (element), gst_element_signals[STATE_CHANGE],
+                0, old_state, GST_STATE (element));
 
   /* signal the state change in case somebody is waiting for us */
   g_mutex_lock (element->state_mutex);
@@ -2236,13 +2533,9 @@ failure:
 GstElementFactory*
 gst_element_get_factory (GstElement *element)
 {
-  GstElementClass *oclass;
-
   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
 
-  oclass = CLASS (element);
-
-  return oclass->elementfactory;
+  return GST_ELEMENT_GET_CLASS (element)->elementfactory;
 }
 
 static void
@@ -2251,12 +2544,12 @@ gst_element_dispose (GObject *object)
   GstElement *element = GST_ELEMENT (object);
   GList *pads;
   GstPad *pad;
-  
-  GST_DEBUG_ELEMENT (GST_CAT_REFCOUNTING, element, "dispose");
+
+  GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, element, "dispose");
 
   gst_element_set_state (element, GST_STATE_NULL);
 
-  /* first we break all our connections with the ouside */
+  /* first we break all our links with the ouside */
   if (element->pads) {
     GList *orig;
     orig = pads = g_list_copy (element->pads);
@@ -2264,9 +2557,9 @@ gst_element_dispose (GObject *object)
       pad = GST_PAD (pads->data);
 
       if (GST_PAD_PEER (pad)) {
-        GST_DEBUG (GST_CAT_REFCOUNTING, "disconnecting pad '%s'",
+        GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "unlinking pad '%s'",
                   GST_OBJECT_NAME (GST_OBJECT (GST_PAD (GST_PAD_PEER (pad)))));
-        gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
+        gst_pad_unlink (pad, GST_PAD (GST_PAD_PEER (pad)));
       }
       gst_element_remove_pad (element, pad);
 
@@ -2288,7 +2581,10 @@ gst_element_dispose (GObject *object)
   element->prop_value_queue = NULL;
   if (element->property_mutex)
     g_mutex_free (element->property_mutex);
-  
+
+  gst_object_replace ((GstObject **)&element->sched, NULL);
+  gst_object_replace ((GstObject **)&element->clock, NULL);
+
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
@@ -2317,7 +2613,7 @@ gst_element_save_thyself (GstObject *object,
 
   element = GST_ELEMENT (object);
 
-  oclass = CLASS (element);
+  oclass = GST_ELEMENT_GET_CLASS (element);
 
   xmlNewChild(parent, NULL, "name", GST_ELEMENT_NAME(element));
 
@@ -2352,7 +2648,8 @@ gst_element_save_thyself (GstObject *object,
       else if (G_IS_PARAM_SPEC_ENUM (spec))
        contents = g_strdup_printf ("%d", g_value_get_enum (&value));
       else if (G_IS_PARAM_SPEC_INT64 (spec))
-       contents = g_strdup_printf ("%lld", g_value_get_int64 (&value));
+       contents = g_strdup_printf ("%" G_GINT64_FORMAT,
+                                   g_value_get_int64 (&value));
       else
        contents = g_strdup_value_contents (&value);
       
@@ -2406,6 +2703,7 @@ gst_element_restore_thyself (GstObject *object, xmlNodePtr self)
       }
       /* FIXME: can this just be g_object_set ? */
       gst_util_set_object_arg (G_OBJECT (element), name, value);
+      /* g_object_set (G_OBJECT (element), name, value, NULL); */
     }
     children = children->next;
   }
@@ -2414,13 +2712,13 @@ gst_element_restore_thyself (GstObject *object, xmlNodePtr self)
   children = self->xmlChildrenNode;
   while (children) {
     if (!strcmp (children->name, "pad")) {
-      gst_pad_load_and_connect (children, GST_OBJECT (element));
+      gst_pad_load_and_link (children, GST_OBJECT (element));
     }
     children = children->next;
   }
 
-  if (GST_OBJECT_CLASS(parent_class)->restore_thyself)
-    (GST_OBJECT_CLASS(parent_class)->restore_thyself) (object, self);
+  if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
+    (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
 }
 #endif /* GST_DISABLE_LOADSAVE */
 
@@ -2456,7 +2754,7 @@ gst_element_interrupt (GstElement *element)
     return gst_scheduler_interrupt (GST_ELEMENT_SCHED (element), element);
   }
   else 
-    return FALSE;
+    return TRUE;
 }
 
 /**
@@ -2473,9 +2771,9 @@ gst_element_set_scheduler (GstElement *element,
 {
   g_return_if_fail (GST_IS_ELEMENT (element));
   
-  GST_INFO_ELEMENT (GST_CAT_PARENTAGE, element, "setting scheduler to %p", sched);
+  GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, element, "setting scheduler to %p", sched);
 
-  element->sched = sched;
+  gst_object_replace ((GstObject **)&GST_ELEMENT_SCHED (element), GST_OBJECT (sched));
 }
 
 /**
@@ -2491,7 +2789,7 @@ gst_element_get_scheduler (GstElement *element)
 {
   g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
 
-  return element->sched;
+  return GST_ELEMENT_SCHED (element);
 }
 
 /**
@@ -2511,15 +2809,49 @@ void
 gst_element_set_loop_function (GstElement *element,
                                GstElementLoopFunction loop)
 {
+  gboolean need_notify = FALSE;
+  
   g_return_if_fail (GST_IS_ELEMENT (element));
 
+  /* if the element changed from loop based to chain/get based
+   * or vice versa, we need to inform the scheduler about that */
+  if ((element->loopfunc == NULL && loop != NULL) ||
+      (element->loopfunc != NULL && loop == NULL))
+  {
+    need_notify = TRUE;
+  }
+  
   /* set the loop function */
   element->loopfunc = loop;
 
-  /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
-  GST_FLAG_SET (element, GST_ELEMENT_NEW_LOOPFUNC);
+  if (need_notify) {
+    /* set the NEW_LOOPFUNC flag so everyone knows to go try again */
+    GST_FLAG_SET (element, GST_ELEMENT_NEW_LOOPFUNC);
+
+    if (GST_ELEMENT_SCHED (element)) {
+      gst_scheduler_scheduling_change (GST_ELEMENT_SCHED (element), element);
+    }
+  }
 }
 
+static inline void
+gst_element_set_eos_recursive (GstElement *element)
+{
+  /* this function is only called, when we were in PLAYING before. So every 
+     parent that's PAUSED was PLAYING before. That means it has reached EOS. */
+  GstElement *parent;
+
+  GST_CAT_DEBUG (GST_CAT_EVENT, "setting recursive EOS on %s", 
+             GST_OBJECT_NAME (element));
+  g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
+
+  if (!GST_OBJECT_PARENT (element))
+    return;
+  
+  parent = GST_ELEMENT (GST_OBJECT_PARENT (element));
+  if (GST_STATE (parent) == GST_STATE_PAUSED)
+    gst_element_set_eos_recursive (parent);
+}
 /**
  * gst_element_set_eos:
  * @element: a #GstElement to set to the EOS state.
@@ -2531,12 +2863,15 @@ gst_element_set_eos (GstElement *element)
 {
   g_return_if_fail (GST_IS_ELEMENT (element));
 
-  GST_DEBUG (GST_CAT_EVENT, "setting EOS on element %s", 
+  GST_CAT_DEBUG (GST_CAT_EVENT, "setting EOS on element %s", 
              GST_OBJECT_NAME (element));
 
-  gst_element_set_state (element, GST_STATE_PAUSED);
-
-  g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
+  if (GST_STATE (element) == GST_STATE_PLAYING) {
+    gst_element_set_state (element, GST_STATE_PAUSED);
+    gst_element_set_eos_recursive (element);
+  } else {
+    g_signal_emit (G_OBJECT (element), gst_element_signals[EOS], 0);
+  }
 }
 
 
@@ -2554,13 +2889,13 @@ gst_element_state_get_name (GstElementState state)
   switch (state) {
 #ifdef GST_DEBUG_COLOR
     case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
-    case GST_STATE_NULL: return "\033[01;37mNULL\033[00m";break;
+    case GST_STATE_NULL: return "\033[01;34mNULL\033[00m";break;
     case GST_STATE_READY: return "\033[01;31mREADY\033[00m";break;
     case GST_STATE_PLAYING: return "\033[01;32mPLAYING\033[00m";break;
     case GST_STATE_PAUSED: return "\033[01;33mPAUSED\033[00m";break;
     default:
       /* This is a memory leak */
-      return g_strdup_printf ("\033[01;37;41mUNKNOWN!\033[00m(%d)", state);
+      return g_strdup_printf ("\033[01;35;41mUNKNOWN!\033[00m(%d)", state);
 #else
     case GST_STATE_VOID_PENDING: return "NONE_PENDING";break;
     case GST_STATE_NULL: return "NULL";break;