Index: gst/gstbin.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstbin.c,v
retrieving revision 1.336
diff -u -p -r1.336 gstbin.c
--- gst/gstbin.c	7 Jul 2006 15:42:08 -0000	1.336
+++ gst/gstbin.c	11 Jul 2006 12:08:02 -0000
@@ -1762,6 +1762,87 @@ done:
   return ret;
 }
 
+/* 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. */
+static gboolean
+activate_pads (GstPad * pad, GValue * ret, gboolean * active)
+{
+  if (!gst_pad_set_active (pad, *active))
+    g_value_set_boolean (ret, FALSE);
+  else if (!*active)
+    gst_pad_set_caps (pad, NULL);
+
+  /* unref the object that was reffed for us by _fold */
+  gst_object_unref (pad);
+  return 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
+ * pads in @iter were (de)activated successfully. */
+static gboolean
+iterator_activate_fold_with_resync (GstIterator * iter, gpointer user_data)
+{
+  GstIteratorResult ires;
+  GValue ret = { 0 };
+
+  /* no need to unset this later, it's just a boolean */
+  g_value_init (&ret, G_TYPE_BOOLEAN);
+  g_value_set_boolean (&ret, TRUE);
+
+  while (1) {
+    ires = gst_iterator_fold (iter, (GstIteratorFoldFunction) activate_pads,
+        &ret, user_data);
+    switch (ires) {
+      case GST_ITERATOR_RESYNC:
+        /* need to reset the result again */
+        g_value_set_boolean (&ret, TRUE);
+        gst_iterator_resync (iter);
+        break;
+      case GST_ITERATOR_DONE:
+        /* all pads iterated, return collected value */
+        goto done;
+      default:
+        /* iterator returned _ERROR or premature end with _OK, 
+         * mark an error and exit */
+        g_value_set_boolean (&ret, FALSE);
+        goto done;
+    }
+  }
+done:
+  /* return collected value */
+  return g_value_get_boolean (&ret);
+}
+
+/* is called with STATE_LOCK
+ */
+static gboolean
+gst_bin_src_pads_activate (GstBin * bin, gboolean active)
+{
+  GstIterator *iter;
+  gboolean fold_ok;
+
+  GST_DEBUG_OBJECT (bin, "src_pads_activate with active %d", active);
+
+  iter = gst_element_iterate_src_pads ((GstElement*) bin);
+  fold_ok = iterator_activate_fold_with_resync (iter, &active);
+  gst_iterator_free (iter);
+  if (G_UNLIKELY (!fold_ok))
+    goto failed;
+
+  GST_DEBUG_OBJECT (bin, "pads_activate successful");
+
+  return TRUE;
+
+  /* ERRORS */
+failed:
+  {
+    GST_DEBUG_OBJECT (bin, "source pads_activate failed");
+    return FALSE;
+  }
+}
 static GstStateChangeReturn
 gst_bin_change_state_func (GstElement * element, GstStateChange transition)
 {
@@ -1791,6 +1872,9 @@ gst_bin_change_state_func (GstElement * 
       GST_DEBUG_OBJECT (element, "clearing EOS elements");
       bin_remove_messages (bin, NULL, GST_MESSAGE_EOS);
       GST_OBJECT_UNLOCK (bin);
+      if (current == GST_STATE_READY)
+	if (!(gst_bin_src_pads_activate (bin, TRUE)))
+	  goto activate_failure;
       break;
     case GST_STATE_READY:
       /* Clear message list on next READY */
@@ -1798,7 +1882,15 @@ gst_bin_change_state_func (GstElement * 
       GST_DEBUG_OBJECT (element, "clearing all cached messages");
       bin_remove_messages (bin, NULL, GST_MESSAGE_ANY);
       GST_OBJECT_UNLOCK (bin);
-      break;
+      if (current == GST_STATE_PAUSED)
+	if (!(gst_bin_src_pads_activate (bin, FALSE)))
+	  goto activate_failure;
+      break;
+  case GST_STATE_NULL:
+    if (current == GST_STATE_READY)
+      if (!(gst_bin_src_pads_activate (bin, FALSE)))
+	goto activate_failure;
+    break;
     default:
       break;
   }
@@ -1897,6 +1989,11 @@ done:
       gst_element_state_get_name (GST_STATE (element)), ret);
 
   return ret;
+
+ activate_failure:
+  GST_CAT_WARNING_OBJECT (GST_CAT_STATES, element,
+			  "failure (de)activating src pads");
+  return GST_STATE_CHANGE_FAILURE;
 }
 
 /*
Index: gst/gstghostpad.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstghostpad.c,v
retrieving revision 1.36
diff -u -p -r1.36 gstghostpad.c
--- gst/gstghostpad.c	5 May 2006 12:53:33 -0000	1.36
+++ gst/gstghostpad.c	11 Jul 2006 12:08:02 -0000
@@ -51,6 +51,7 @@
 #define GST_PROXY_PAD(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PROXY_PAD, GstProxyPad))
 #define GST_PROXY_PAD_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_PROXY_PAD, GstProxyPadClass))
 #define GST_PROXY_PAD_TARGET(pad)       (GST_PROXY_PAD (pad)->target)
+#define GST_PROXY_PAD_INTERNAL(pad)     (GST_PROXY_PAD (pad)->internal)
 
 
 typedef struct _GstProxyPad GstProxyPad;
@@ -67,9 +68,7 @@ struct _GstProxyPad
   /* with PROXY_LOCK */
   GMutex *proxy_lock;
   GstPad *target;
-
-  /*< private > */
-  gpointer _gst_reserved[1];
+  GstPad *internal;
 };
 
 struct _GstProxyPadClass
@@ -84,6 +83,7 @@ struct _GstProxyPadClass
 G_DEFINE_TYPE (GstProxyPad, gst_proxy_pad, GST_TYPE_PAD);
 
 static GstPad *gst_proxy_pad_get_target (GstPad * pad);
+static GstPad *gst_proxy_pad_get_internal (GstPad * pad);
 
 static void gst_proxy_pad_dispose (GObject * object);
 static void gst_proxy_pad_finalize (GObject * object);
@@ -116,40 +116,43 @@ const GstQueryType *
 gst_proxy_pad_do_query_type (GstPad * pad)
 {
   GstPad *target = gst_proxy_pad_get_target (pad);
-  const GstQueryType *res;
-
-  g_return_val_if_fail (target != NULL, NULL);
-
-  res = gst_pad_get_query_types (target);
-  gst_object_unref (target);
+  const GstQueryType *res = NULL;
 
+  if (target) {
+    res = gst_pad_get_query_types (target);
+    gst_object_unref (target);
+  }
   return res;
 }
 
 static gboolean
 gst_proxy_pad_do_event (GstPad * pad, GstEvent * event)
 {
-  gboolean res;
-  GstPad *target = gst_proxy_pad_get_target (pad);
-
-  g_return_val_if_fail (target != NULL, FALSE);
-
-  res = gst_pad_send_event (target, event);
-  gst_object_unref (target);
+  gboolean res = FALSE;
+  GstPad *neighbour = gst_proxy_pad_get_internal (pad);
 
+  g_return_val_if_fail (neighbour != NULL, FALSE);
+  
+  GST_DEBUG_OBJECT (pad, "direction:%d , neighbour is %s:%s : direction:%d",
+		    GST_PAD_DIRECTION (pad),
+		    GST_DEBUG_PAD_NAME (neighbour), GST_PAD_DIRECTION (neighbour));
+  
+  res = gst_pad_push_event (neighbour, event);
+  gst_object_unref (neighbour);
+  
   return res;
 }
 
 static gboolean
 gst_proxy_pad_do_query (GstPad * pad, GstQuery * query)
 {
-  gboolean res;
+  gboolean res = FALSE;
   GstPad *target = gst_proxy_pad_get_target (pad);
 
-  g_return_val_if_fail (target != NULL, FALSE);
-
-  res = gst_pad_query (target, query);
-  gst_object_unref (target);
+  if (target) {
+    res = gst_pad_query (target, query);
+    gst_object_unref (target);
+  }
 
   return res;
 }
@@ -158,12 +161,12 @@ static GList *
 gst_proxy_pad_do_internal_link (GstPad * pad)
 {
   GstPad *target = gst_proxy_pad_get_target (pad);
-  GList *res;
-
-  g_return_val_if_fail (target != NULL, NULL);
+  GList *res = NULL;
 
-  res = gst_pad_get_internal_links (target);
-  gst_object_unref (target);
+  if (target) {
+    res = gst_pad_get_internal_links (target);
+    gst_object_unref (target);
+  }
 
   return res;
 }
@@ -173,38 +176,27 @@ gst_proxy_pad_do_bufferalloc (GstPad * p
     GstCaps * caps, GstBuffer ** buf)
 {
   GstFlowReturn result;
-  GstPad *target = gst_proxy_pad_get_target (pad);
-  GstPad *peer;
-
-  g_return_val_if_fail (target != NULL, GST_FLOW_NOT_LINKED);
-
-  peer = gst_pad_get_peer (target);
-  if (peer) {
-    GST_DEBUG ("buffer alloc on %s:%s", GST_DEBUG_PAD_NAME (target));
-
-    result = gst_pad_alloc_buffer (peer, offset, size, caps, buf);
-
-    gst_object_unref (peer);
-  } else {
-    result = GST_FLOW_NOT_LINKED;
-  }
-
-  gst_object_unref (target);
+  GstPad *neighbour = gst_proxy_pad_get_internal (pad);
 
+  g_return_val_if_fail (neighbour != NULL, GST_FLOW_NOT_LINKED);
+  
+  result = gst_pad_alloc_buffer (neighbour, offset, size, caps, buf);
+  gst_object_unref (neighbour);
+  
   return result;
 }
 
 static GstFlowReturn
 gst_proxy_pad_do_chain (GstPad * pad, GstBuffer * buffer)
 {
-  GstPad *target = gst_proxy_pad_get_target (pad);
+  GstPad *neighbour = gst_proxy_pad_get_internal (pad);
   GstFlowReturn res;
 
-  g_return_val_if_fail (target != NULL, GST_FLOW_NOT_LINKED);
-
-  res = gst_pad_chain (target, buffer);
-  gst_object_unref (target);
-
+  g_return_val_if_fail (neighbour != NULL, GST_FLOW_NOT_LINKED);
+  
+  res = gst_pad_push (neighbour, buffer);
+  gst_object_unref (neighbour);
+  
   return res;
 }
 
@@ -212,14 +204,14 @@ static GstFlowReturn
 gst_proxy_pad_do_getrange (GstPad * pad, guint64 offset, guint size,
     GstBuffer ** buffer)
 {
-  GstPad *target = gst_proxy_pad_get_target (pad);
+  GstPad *neighbour = gst_proxy_pad_get_internal (pad);
   GstFlowReturn res;
 
-  g_return_val_if_fail (target != NULL, GST_FLOW_NOT_LINKED);
-
-  res = gst_pad_get_range (target, offset, size, buffer);
-  gst_object_unref (target);
+  g_return_val_if_fail (neighbour != NULL, GST_FLOW_NOT_LINKED);
 
+  res = gst_pad_pull_range (neighbour, offset, size, buffer);
+  gst_object_unref (neighbour);
+  
   return res;
 }
 
@@ -227,19 +219,12 @@ static gboolean
 gst_proxy_pad_do_checkgetrange (GstPad * pad)
 {
   gboolean result;
-  GstPad *target = gst_proxy_pad_get_target (pad);
-  GstPad *peer;
+  GstPad *neighbour = gst_proxy_pad_get_internal (pad);
 
-  g_return_val_if_fail (target != NULL, FALSE);
+  g_return_val_if_fail (neighbour != NULL, FALSE);
 
-  peer = gst_pad_get_peer (target);
-  if (peer) {
-    result = gst_pad_check_pull_range (peer);
-    gst_object_unref (peer);
-  } else {
-    result = FALSE;
-  }
-  gst_object_unref (target);
+  result = gst_pad_check_pull_range (neighbour);
+  gst_object_unref (neighbour);
 
   return result;
 }
@@ -250,11 +235,15 @@ gst_proxy_pad_do_getcaps (GstPad * pad)
   GstPad *target = gst_proxy_pad_get_target (pad);
   GstCaps *res;
 
-  g_return_val_if_fail (target != NULL, NULL);
-
-  res = gst_pad_get_caps (target);
-  gst_object_unref (target);
-
+  if (target) {
+    GST_LOG_OBJECT (pad, "Returning caps of %s:%s",
+		    GST_DEBUG_PAD_NAME (target));
+    res = gst_pad_get_caps (target);
+    gst_object_unref (target);
+  } else {
+    GST_LOG_OBJECT (pad, "NO TARGET !! Returning ANY");
+    res = gst_caps_new_any ();
+  }
   return res;
 }
 
@@ -262,12 +251,12 @@ static gboolean
 gst_proxy_pad_do_acceptcaps (GstPad * pad, GstCaps * caps)
 {
   GstPad *target = gst_proxy_pad_get_target (pad);
-  gboolean res;
+  gboolean res = FALSE;
 
-  g_return_val_if_fail (target != NULL, FALSE);
-
-  res = gst_pad_accept_caps (target, caps);
-  gst_object_unref (target);
+  if (target) {
+    res = gst_pad_accept_caps (target, caps);
+    gst_object_unref (target);
+  }
 
   return res;
 }
@@ -277,10 +266,10 @@ gst_proxy_pad_do_fixatecaps (GstPad * pa
 {
   GstPad *target = gst_proxy_pad_get_target (pad);
 
-  g_return_if_fail (target != NULL);
-
-  gst_pad_fixate_caps (target, caps);
-  gst_object_unref (target);
+  if (target) {
+    gst_pad_fixate_caps (target, caps);
+    gst_object_unref (target);
+  }
 }
 
 static gboolean
@@ -289,11 +278,17 @@ gst_proxy_pad_do_setcaps (GstPad * pad, 
   GstPad *target = gst_proxy_pad_get_target (pad);
   gboolean res;
 
-  g_return_val_if_fail (target != NULL, FALSE);
-
-  res = gst_pad_set_caps (target, caps);
-  gst_object_unref (target);
-
+  if (target) {
+    res = gst_pad_set_caps (target, caps);
+    gst_object_unref (target);
+  } else {
+    /*
+      We don't have any target, but we shouldn't return FALSE since this
+      would stop the actual push of a buffer (which might trigger a pad block
+      or probe, or properly return GST_FLOW_NOT_LINKED.
+    */
+    res = TRUE;
+  }
   return res;
 }
 
@@ -302,8 +297,14 @@ gst_proxy_pad_set_target_unlocked (GstPa
 {
   GstPad *oldtarget;
 
-  GST_DEBUG ("set target %s:%s on %s:%s",
-      GST_DEBUG_PAD_NAME (target), GST_DEBUG_PAD_NAME (pad));
+  if (target) {
+    GST_DEBUG_OBJECT (pad, "setting target %s:%s", GST_DEBUG_PAD_NAME (target));
+    if (G_UNLIKELY (GST_PAD_DIRECTION (pad) != GST_PAD_DIRECTION (target))) {
+      GST_ERROR_OBJECT (pad, "target pad doesn't have the same direction as ourself");
+      return FALSE;
+    }
+  } else
+    GST_DEBUG_OBJECT (pad, "clearing target");
 
   /* clear old target */
   if ((oldtarget = GST_PROXY_PAD_TARGET (pad))) {
@@ -314,35 +315,6 @@ gst_proxy_pad_set_target_unlocked (GstPa
   if (target) {
     /* set and ref new target if any */
     GST_PROXY_PAD_TARGET (pad) = gst_object_ref (target);
-
-    gst_pad_set_query_type_function (pad,
-        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query_type));
-    gst_pad_set_event_function (pad,
-        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_event));
-    gst_pad_set_query_function (pad,
-        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query));
-    gst_pad_set_internal_link_function (pad,
-        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_internal_link));
-    gst_pad_set_getcaps_function (pad,
-        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getcaps));
-    gst_pad_set_acceptcaps_function (pad,
-        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_acceptcaps));
-    gst_pad_set_fixatecaps_function (pad,
-        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_fixatecaps));
-    gst_pad_set_setcaps_function (pad,
-        GST_DEBUG_FUNCPTR (gst_proxy_pad_do_setcaps));
-
-    if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
-      gst_pad_set_bufferalloc_function (pad,
-          GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
-      gst_pad_set_chain_function (pad,
-          GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));
-    } else {
-      gst_pad_set_getrange_function (pad,
-          GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
-      gst_pad_set_checkgetrange_function (pad,
-          GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
-    }
   }
   return TRUE;
 }
@@ -373,10 +345,18 @@ gst_proxy_pad_get_target (GstPad * pad)
   return target;
 }
 
-static void
-gst_proxy_pad_init (GstProxyPad * pad)
+static GstPad *
+gst_proxy_pad_get_internal (GstPad * pad)
 {
-  pad->proxy_lock = g_mutex_new ();
+  GstPad * internal;
+  
+  GST_PROXY_LOCK (pad);
+  internal = GST_PROXY_PAD_INTERNAL (pad);
+  if (internal)
+    gst_object_ref (internal);
+  GST_PROXY_UNLOCK (pad);
+
+  return internal;
 }
 
 static void
@@ -404,6 +384,30 @@ gst_proxy_pad_finalize (GObject * object
   G_OBJECT_CLASS (gst_proxy_pad_parent_class)->finalize (object);
 }
 
+static void
+gst_proxy_pad_init (GstProxyPad * ppad)
+{
+  GstPad *pad = (GstPad *) ppad;
+
+  ppad->proxy_lock = g_mutex_new ();
+
+  gst_pad_set_query_type_function (pad,
+      GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query_type));
+  gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_event));
+  gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_proxy_pad_do_query));
+  gst_pad_set_internal_link_function (pad,
+      GST_DEBUG_FUNCPTR (gst_proxy_pad_do_internal_link));
+  gst_pad_set_getcaps_function (pad,
+      GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getcaps));
+  gst_pad_set_acceptcaps_function (pad,
+      GST_DEBUG_FUNCPTR (gst_proxy_pad_do_acceptcaps));
+  gst_pad_set_fixatecaps_function (pad,
+      GST_DEBUG_FUNCPTR (gst_proxy_pad_do_fixatecaps));
+  gst_pad_set_setcaps_function (pad,
+      GST_DEBUG_FUNCPTR (gst_proxy_pad_do_setcaps));
+
+}
+
 #ifndef GST_DISABLE_LOADSAVE
 /**
  * gst_proxy_pad_save_thyself:
@@ -444,7 +448,6 @@ struct _GstGhostPad
   GstProxyPad pad;
 
   /* with PROXY_LOCK */
-  GstPad *internal;
   gulong notify_id;
 
   /*< private > */
@@ -479,26 +482,68 @@ gst_critical (const gchar * format, ...)
   va_end (args);
 }
 
-static GstPad *
-gst_ghost_pad_get_internal (GstPad * pad)
+static void
+gst_ghost_pad_parent_set (GstObject * object, GstObject * parent)
 {
-  GstPad *internal;
+  GstPad * gpad = GST_PAD (object);
+  GstPad * target = gst_proxy_pad_get_target (gpad);
+  GstPad * internal = gst_proxy_pad_get_internal (gpad);
+
+  GST_LOG_OBJECT (object, "parent:%s", GST_OBJECT_NAME (parent));
+
+  if (target && !(gst_pad_is_linked(internal))) {
+    GST_DEBUG_OBJECT (gpad, "linking internal pad with target");
+    if (GST_PAD_IS_SRC (internal))
+      gst_pad_link (internal, target);
+    else
+      gst_pad_link (target, internal);
+  }
+  if (target)
+    gst_object_unref (target);
+  gst_object_unref (internal);
 
-  GST_PROXY_LOCK (pad);
-  internal = GST_GHOST_PAD (pad)->internal;
-  if (internal)
-    gst_object_ref (internal);
-  GST_PROXY_UNLOCK (pad);
+  if (GST_OBJECT_CLASS (gst_ghost_pad_parent_class)->parent_set)
+    GST_OBJECT_CLASS (gst_ghost_pad_parent_class)->parent_set (object, parent);
 
-  return internal;
+  GST_LOG_OBJECT (object, "done");
 }
 
 static void
+gst_ghost_pad_parent_unset (GstObject * object, GstObject * parent)
+{
+  GstPad * gpad = GST_PAD (object);
+  GstPad * target = gst_proxy_pad_get_target (gpad);
+  GstPad * internal = gst_proxy_pad_get_internal (gpad);
+
+  GST_LOG_OBJECT (object, "parent:%s", GST_OBJECT_NAME (parent));
+
+  if (target && gst_pad_is_linked(internal)) {
+    GST_DEBUG_OBJECT (gpad, "unlinking internal pad with target");
+    if (GST_PAD_IS_SRC (internal))
+      gst_pad_unlink (internal, target);
+    else
+      gst_pad_unlink (target, internal);
+  }
+  if (target)
+    gst_object_unref (target);
+  gst_object_unref (internal);
+
+  if (GST_OBJECT_CLASS (gst_ghost_pad_parent_class)->parent_unset)
+    GST_OBJECT_CLASS (gst_ghost_pad_parent_class)->parent_unset (object, parent);
+
+  GST_LOG_OBJECT (object, "done");
+}
+
+
+static void
 gst_ghost_pad_class_init (GstGhostPadClass * klass)
 {
   GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstObjectClass *gstobject_class = (GstObjectClass *) klass;
 
   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ghost_pad_dispose);
+  gstobject_class->parent_set = GST_DEBUG_FUNCPTR (gst_ghost_pad_parent_set);
+  gstobject_class->parent_unset = GST_DEBUG_FUNCPTR (gst_ghost_pad_parent_unset);
 }
 
 /* see gstghostpad design docs */
@@ -508,7 +553,7 @@ gst_ghost_pad_internal_do_activate_push 
   gboolean ret;
 
   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
-    GstPad *parent = GST_PAD (gst_object_get_parent (GST_OBJECT (pad)));
+    GstPad *parent = gst_proxy_pad_get_internal (pad);
 
     if (parent) {
       g_return_val_if_fail (GST_IS_GHOST_PAD (parent), FALSE);
@@ -548,7 +593,7 @@ gst_ghost_pad_internal_do_activate_pull 
       ret = FALSE;
     }
   } else {
-    GstPad *parent = GST_PAD (gst_object_get_parent (GST_OBJECT (pad)));
+    GstPad *parent = gst_proxy_pad_get_internal (pad);
 
     if (parent) {
       g_return_val_if_fail (GST_IS_GHOST_PAD (parent), FALSE);
@@ -570,7 +615,7 @@ gst_ghost_pad_do_activate_push (GstPad *
   gboolean ret;
 
   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
-    GstPad *internal = gst_ghost_pad_get_internal (pad);
+    GstPad *internal = gst_proxy_pad_get_internal (pad);
 
     if (internal) {
       ret = gst_pad_activate_push (internal, active);
@@ -600,7 +645,7 @@ gst_ghost_pad_do_activate_pull (GstPad *
       ret = FALSE;
     }
   } else {
-    GstPad *internal = gst_ghost_pad_get_internal (pad);
+    GstPad *internal = gst_proxy_pad_get_internal (pad);
 
     if (internal) {
       ret = gst_pad_activate_pull (internal, active);
@@ -617,25 +662,16 @@ static GstPadLinkReturn
 gst_ghost_pad_do_link (GstPad * pad, GstPad * peer)
 {
   GstPad *internal, *target;
-  GstPadLinkReturn ret;
+  GstPadLinkReturn ret = GST_FLOW_OK;
 
   target = gst_proxy_pad_get_target (pad);
 
   g_return_val_if_fail (target != NULL, GST_PAD_LINK_NOSCHED);
 
-  /* proxy the peer into the bin */
-  internal = g_object_new (GST_TYPE_PROXY_PAD,
-      "name", NULL,
-      "direction", GST_PAD_DIRECTION (peer),
-      "template", GST_PAD_PAD_TEMPLATE (peer), NULL);
+  internal = gst_proxy_pad_get_internal (pad);
 
   gst_proxy_pad_set_target (internal, peer);
-  gst_ghost_pad_set_internal (GST_GHOST_PAD (pad), internal);
-
-  if (GST_PAD_IS_SRC (internal))
-    ret = gst_pad_link (internal, target);
-  else
-    ret = gst_pad_link (target, internal);
+  GST_PAD_PAD_TEMPLATE (internal) = GST_PAD_PAD_TEMPLATE (peer);
 
   /* if we are a source pad, we should call the peer link function
    * if the peer has one */
@@ -645,6 +681,7 @@ gst_ghost_pad_do_link (GstPad * pad, Gst
   }
 
   gst_object_unref (target);
+  gst_object_unref (internal);
 
   if (ret == GST_PAD_LINK_OK)
     gst_pad_set_active (internal, GST_PAD_ACTIVATE_MODE (pad));
@@ -658,17 +695,20 @@ static void
 gst_ghost_pad_do_unlink (GstPad * pad)
 {
   GstPad *target = gst_proxy_pad_get_target (pad);
+  GstPad *internal = gst_proxy_pad_get_internal (pad);
 
   g_return_if_fail (target != NULL);
 
   GST_DEBUG_OBJECT (pad, "unlinking ghostpad");
 
+  gst_proxy_pad_set_target (internal, NULL);
+  GST_PAD_PAD_TEMPLATE (internal) = NULL;
+
   if (target->unlinkfunc)
     target->unlinkfunc (target);
 
-  gst_ghost_pad_set_internal (GST_GHOST_PAD (pad), NULL);
-
   gst_object_unref (target);
+  gst_object_unref (internal);
 }
 
 static void
@@ -690,26 +730,33 @@ on_int_notify (GstPad * internal, GParam
 static gboolean
 gst_ghost_pad_set_internal (GstGhostPad * pad, GstPad * internal)
 {
+  GstPad * pinternal;
+
+  GST_LOG_OBJECT (pad, "Setting internal to %s:%s",
+		  GST_DEBUG_PAD_NAME (internal));
+
   GST_PROXY_LOCK (pad);
   /* first remove old internal pad */
-  if (pad->internal) {
+  if ((pinternal = GST_PROXY_PAD_INTERNAL (pad))) {
     GstPad *intpeer;
 
-    gst_pad_set_activatepull_function (pad->internal, NULL);
-    gst_pad_set_activatepush_function (pad->internal, NULL);
+    gst_pad_set_activatepull_function (pinternal, NULL);
+    gst_pad_set_activatepush_function (pinternal, NULL);
 
-    g_signal_handler_disconnect (pad->internal, pad->notify_id);
+    g_signal_handler_disconnect (pinternal, pad->notify_id);
 
-    intpeer = gst_pad_get_peer (pad->internal);
+    intpeer = gst_pad_get_peer (pinternal);
     if (intpeer) {
-      if (GST_PAD_IS_SRC (pad->internal))
-        gst_pad_unlink (pad->internal, intpeer);
+      if (GST_PAD_IS_SRC (pinternal))
+        gst_pad_unlink (pinternal, intpeer);
       else
-        gst_pad_unlink (intpeer, pad->internal);
+        gst_pad_unlink (intpeer, pinternal);
       gst_object_unref (intpeer);
     }
+
+    GST_PROXY_PAD_INTERNAL (pinternal) = NULL;
     /* should dispose it */
-    gst_object_unparent (GST_OBJECT_CAST (pad->internal));
+    gst_object_unparent (GST_OBJECT_CAST (pinternal));
   }
 
   /* then set new internal pad */
@@ -717,6 +764,8 @@ gst_ghost_pad_set_internal (GstGhostPad 
     if (!gst_object_set_parent (GST_OBJECT_CAST (internal),
             GST_OBJECT_CAST (pad)))
       goto could_not_set;
+    GST_PROXY_PAD_INTERNAL (pad) = internal;
+    GST_PROXY_PAD_INTERNAL (GST_PROXY_PAD_INTERNAL (pad)) = GST_PAD (pad);
 
     /* could be more general here, iterating over all writable properties...
      * taking the short road for now tho */
@@ -729,7 +778,7 @@ gst_ghost_pad_set_internal (GstGhostPad 
         GST_DEBUG_FUNCPTR (gst_ghost_pad_internal_do_activate_push));
     /* a ref was taken by set_parent */
   }
-  pad->internal = internal;
+  GST_PROXY_PAD_INTERNAL (pad) = internal;
 
   GST_PROXY_UNLOCK (pad);
 
@@ -778,15 +827,49 @@ GstPad *
 gst_ghost_pad_new_no_target (const gchar * name, GstPadDirection dir)
 {
   GstPad *ret;
+  GstPad *internal;
 
+  GST_LOG ("name:%s, direction:%d", name, dir);
+  
   ret = g_object_new (GST_TYPE_GHOST_PAD, "name", name, "direction", dir, NULL);
 
-  gst_pad_set_activatepush_function (ret,
-      GST_DEBUG_FUNCPTR (gst_ghost_pad_do_activate_push));
+  /* Set directional padfunctions for ghostpad */
+  if (dir == GST_PAD_SINK) {
+    gst_pad_set_bufferalloc_function (ret,
+				      GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
+    gst_pad_set_chain_function (ret,
+				GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));   
+  } else {
+    gst_pad_set_getrange_function (ret,
+				   GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
+    gst_pad_set_checkgetrange_function (ret,
+					GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
+  }
+
   gst_pad_set_link_function (ret, GST_DEBUG_FUNCPTR (gst_ghost_pad_do_link));
   gst_pad_set_unlink_function (ret,
       GST_DEBUG_FUNCPTR (gst_ghost_pad_do_unlink));
 
+  internal =
+    g_object_new (GST_TYPE_PROXY_PAD, "name", NULL,
+		  "direction", (dir == GST_PAD_SRC) ? GST_PAD_SINK : GST_PAD_SRC,
+		  NULL);
+
+  /* Set directional padfunctions for internal pad */
+  if (dir == GST_PAD_SRC) {
+    gst_pad_set_bufferalloc_function (internal,
+				      GST_DEBUG_FUNCPTR (gst_proxy_pad_do_bufferalloc));
+    gst_pad_set_chain_function (internal,
+				GST_DEBUG_FUNCPTR (gst_proxy_pad_do_chain));   
+  } else {
+    gst_pad_set_getrange_function (internal,
+				   GST_DEBUG_FUNCPTR (gst_proxy_pad_do_getrange));
+    gst_pad_set_checkgetrange_function (internal,
+					GST_DEBUG_FUNCPTR (gst_proxy_pad_do_checkgetrange));
+  }
+
+  gst_ghost_pad_set_internal ((GstGhostPad*) ret, internal);
+
   return ret;
 }
 
@@ -807,12 +890,12 @@ gst_ghost_pad_new (const gchar * name, G
 {
   GstPad *ret;
 
+  GST_LOG ("name:%s, target:%s:%s", name, GST_DEBUG_PAD_NAME (target));
+
   g_return_val_if_fail (GST_IS_PAD (target), NULL);
   g_return_val_if_fail (!gst_pad_is_linked (target), NULL);
 
   if ((ret = gst_ghost_pad_new_no_target (name, GST_PAD_DIRECTION (target)))) {
-    g_object_set (G_OBJECT (ret),
-        "template", GST_PAD_PAD_TEMPLATE (target), NULL);
     gst_ghost_pad_set_target (GST_GHOST_PAD (ret), target);
   }
   return ret;
@@ -850,15 +933,16 @@ gst_ghost_pad_set_target (GstGhostPad * 
 {
   GstPad *internal;
   GstPad *oldtarget;
+  GstObject * parent;
   gboolean result;
 
   g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE);
 
   GST_PROXY_LOCK (gpad);
-  internal = gpad->internal;
+  internal = GST_PROXY_PAD_INTERNAL (GST_PAD (gpad));
 
-  GST_DEBUG ("set target %s:%s on %s:%s",
-      GST_DEBUG_PAD_NAME (newtarget), GST_DEBUG_PAD_NAME (gpad));
+  GST_DEBUG_OBJECT (gpad, "set target %s:%s",
+		    GST_DEBUG_PAD_NAME (newtarget));
 
   /* clear old target */
   if ((oldtarget = GST_PROXY_PAD_TARGET (gpad))) {
@@ -874,12 +958,18 @@ gst_ghost_pad_set_target (GstGhostPad * 
   result = gst_proxy_pad_set_target_unlocked (GST_PAD_CAST (gpad), newtarget);
 
   if (result && newtarget) {
-    /* and link to internal pad if we have one */
-    if (internal) {
+    g_object_set (G_OBJECT (gpad), "template",
+		  GST_PAD_PAD_TEMPLATE (newtarget), NULL);
+    /* and link to internal pad if we are not unparent-ed */
+    if ((parent = gst_object_get_parent (GST_OBJECT (gpad)))) {
       if (GST_PAD_IS_SRC (internal))
         result = gst_pad_link (internal, newtarget);
       else
         result = gst_pad_link (newtarget, internal);
+      gst_object_unref (parent);
+    } else {
+      /* we need to connect the internal pad once we have a parent */
+      GST_DEBUG_OBJECT (gpad, "GhostPad doesn't have a parent, will connect internal pad later");
     }
   }
   GST_PROXY_UNLOCK (gpad);
Index: gst/gstpad.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstpad.c,v
retrieving revision 1.518
diff -u -p -r1.518 gstpad.c
--- gst/gstpad.c	9 Jul 2006 13:26:06 -0000	1.518
+++ gst/gstpad.c	11 Jul 2006 12:08:02 -0000
@@ -63,7 +63,6 @@
 #include "gst_private.h"
 
 #include "gstpad.h"
-#include "gstghostpad.h"
 #include "gstpadtemplate.h"
 #include "gstenumtypes.h"
 #include "gstmarshal.h"
@@ -939,18 +938,10 @@ gboolean
 gst_pad_set_blocked_async (GstPad * pad, gboolean blocked,
     GstPadBlockCallback callback, gpointer user_data)
 {
-  gboolean was_blocked, was_ghost = FALSE;
+  gboolean was_blocked = FALSE;
 
   g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
 
-  if (GST_IS_GHOST_PAD (pad)) {
-    pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
-    if (!pad) {
-      return FALSE;
-    }
-    was_ghost = TRUE;
-  }
-
   GST_OBJECT_LOCK (pad);
 
   was_blocked = GST_PAD_IS_BLOCKED (pad);
@@ -990,10 +981,6 @@ gst_pad_set_blocked_async (GstPad * pad,
   }
   GST_OBJECT_UNLOCK (pad);
 
-  if (was_ghost) {
-    gst_object_unref (pad);
-  }
-
   return TRUE;
 
 had_right_state:
@@ -1003,9 +990,6 @@ had_right_state:
         was_blocked);
     GST_OBJECT_UNLOCK (pad);
 
-    if (was_ghost) {
-      gst_object_unref (pad);
-    }
     return FALSE;
   }
 }
@@ -1727,8 +1711,9 @@ not_srcpad:
   }
 src_was_linked:
   {
-    GST_CAT_INFO (GST_CAT_PADS, "src %s:%s was already linked",
-        GST_DEBUG_PAD_NAME (srcpad));
+    GST_CAT_INFO (GST_CAT_PADS, "src %s:%s was already linked to %s:%s",
+		  GST_DEBUG_PAD_NAME (srcpad),
+		  GST_DEBUG_PAD_NAME (GST_PAD_PEER (srcpad)));
     /* we do not emit a warning in this case because unlinking cannot
      * be made MT safe.*/
     GST_OBJECT_UNLOCK (srcpad);
@@ -1743,8 +1728,9 @@ not_sinkpad:
   }
 sink_was_linked:
   {
-    GST_CAT_INFO (GST_CAT_PADS, "sink %s:%s was already linked",
-        GST_DEBUG_PAD_NAME (sinkpad));
+    GST_CAT_INFO (GST_CAT_PADS, "sink %s:%s was already linked to %s:%s",
+		  GST_DEBUG_PAD_NAME (sinkpad),
+		  GST_DEBUG_PAD_NAME (GST_PAD_PEER (sinkpad)));
     /* we do not emit a warning in this case because unlinking cannot
      * be made MT safe.*/
     GST_OBJECT_UNLOCK (sinkpad);
@@ -3870,6 +3856,7 @@ dropping:
   }
 not_linked:
   {
+    GST_DEBUG_OBJECT (pad, "Dropping event because pad is not linked");
     gst_event_unref (event);
     GST_OBJECT_UNLOCK (pad);
     return FALSE;
Index: gst/gstutils.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstutils.c,v
retrieving revision 1.142
diff -u -p -r1.142 gstutils.c
--- gst/gstutils.c	19 May 2006 10:29:07 -0000	1.142
+++ gst/gstutils.c	11 Jul 2006 12:08:02 -0000
@@ -2783,19 +2783,10 @@ gulong
 gst_pad_add_data_probe (GstPad * pad, GCallback handler, gpointer data)
 {
   gulong sigid;
-  gboolean was_ghost = FALSE;
 
   g_return_val_if_fail (GST_IS_PAD (pad), 0);
   g_return_val_if_fail (handler != NULL, 0);
 
-  if (GST_IS_GHOST_PAD (pad)) {
-    pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
-    if (!pad) {
-      return 0;
-    }
-    was_ghost = TRUE;
-  }
-
   GST_OBJECT_LOCK (pad);
   sigid = g_signal_connect (pad, "have-data", handler, data);
   GST_PAD_DO_EVENT_SIGNALS (pad)++;
@@ -2805,10 +2796,6 @@ gst_pad_add_data_probe (GstPad * pad, GC
       GST_PAD_DO_BUFFER_SIGNALS (pad), GST_PAD_DO_EVENT_SIGNALS (pad));
   GST_OBJECT_UNLOCK (pad);
 
-  if (was_ghost) {
-    gst_object_unref (pad);
-  }
-
   return sigid;
 }
 
@@ -2827,19 +2814,10 @@ gulong
 gst_pad_add_event_probe (GstPad * pad, GCallback handler, gpointer data)
 {
   gulong sigid;
-  gboolean was_ghost = FALSE;
 
   g_return_val_if_fail (GST_IS_PAD (pad), 0);
   g_return_val_if_fail (handler != NULL, 0);
 
-  if (GST_IS_GHOST_PAD (pad)) {
-    pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
-    if (!pad) {
-      return 0;
-    }
-    was_ghost = TRUE;
-  }
-
   GST_OBJECT_LOCK (pad);
   sigid = g_signal_connect (pad, "have-data::event", handler, data);
   GST_PAD_DO_EVENT_SIGNALS (pad)++;
@@ -2847,10 +2825,6 @@ gst_pad_add_event_probe (GstPad * pad, G
       GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_EVENT_SIGNALS (pad));
   GST_OBJECT_UNLOCK (pad);
 
-  if (was_ghost) {
-    gst_object_unref (pad);
-  }
-
   return sigid;
 }
 
@@ -2869,19 +2843,10 @@ gulong
 gst_pad_add_buffer_probe (GstPad * pad, GCallback handler, gpointer data)
 {
   gulong sigid;
-  gboolean was_ghost = FALSE;
 
   g_return_val_if_fail (GST_IS_PAD (pad), 0);
   g_return_val_if_fail (handler != NULL, 0);
 
-  if (GST_IS_GHOST_PAD (pad)) {
-    pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
-    if (!pad) {
-      return 0;
-    }
-    was_ghost = TRUE;
-  }
-
   GST_OBJECT_LOCK (pad);
   sigid = g_signal_connect (pad, "have-data::buffer", handler, data);
   GST_PAD_DO_BUFFER_SIGNALS (pad)++;
@@ -2889,10 +2854,6 @@ gst_pad_add_buffer_probe (GstPad * pad, 
       GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_BUFFER_SIGNALS (pad));
   GST_OBJECT_UNLOCK (pad);
 
-  if (was_ghost) {
-    gst_object_unref (pad);
-  }
-
   return sigid;
 }
 
@@ -2906,19 +2867,9 @@ gst_pad_add_buffer_probe (GstPad * pad, 
 void
 gst_pad_remove_data_probe (GstPad * pad, guint handler_id)
 {
-  gboolean was_ghost = FALSE;
-
   g_return_if_fail (GST_IS_PAD (pad));
   g_return_if_fail (handler_id > 0);
 
-  if (GST_IS_GHOST_PAD (pad)) {
-    pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
-    if (!pad) {
-      return;
-    }
-    was_ghost = TRUE;
-  }
-
   GST_OBJECT_LOCK (pad);
   g_signal_handler_disconnect (pad, handler_id);
   GST_PAD_DO_BUFFER_SIGNALS (pad)--;
@@ -2929,9 +2880,6 @@ gst_pad_remove_data_probe (GstPad * pad,
       GST_PAD_DO_BUFFER_SIGNALS (pad));
   GST_OBJECT_UNLOCK (pad);
 
-  if (was_ghost) {
-    gst_object_unref (pad);
-  }
 }
 
 /**
@@ -2944,29 +2892,15 @@ gst_pad_remove_data_probe (GstPad * pad,
 void
 gst_pad_remove_event_probe (GstPad * pad, guint handler_id)
 {
-  gboolean was_ghost = FALSE;
-
   g_return_if_fail (GST_IS_PAD (pad));
   g_return_if_fail (handler_id > 0);
 
-  if (GST_IS_GHOST_PAD (pad)) {
-    pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
-    if (!pad) {
-      return;
-    }
-    was_ghost = TRUE;
-  }
-
   GST_OBJECT_LOCK (pad);
   g_signal_handler_disconnect (pad, handler_id);
   GST_PAD_DO_EVENT_SIGNALS (pad)--;
   GST_DEBUG ("removed event probe from pad %s:%s, now %d event probes",
       GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_EVENT_SIGNALS (pad));
   GST_OBJECT_UNLOCK (pad);
-
-  if (was_ghost) {
-    gst_object_unref (pad);
-  }
 }
 
 /**
@@ -2979,19 +2913,9 @@ gst_pad_remove_event_probe (GstPad * pad
 void
 gst_pad_remove_buffer_probe (GstPad * pad, guint handler_id)
 {
-  gboolean was_ghost = FALSE;
-
   g_return_if_fail (GST_IS_PAD (pad));
   g_return_if_fail (handler_id > 0);
 
-  if (GST_IS_GHOST_PAD (pad)) {
-    pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
-    if (!pad) {
-      return;
-    }
-    was_ghost = TRUE;
-  }
-
   GST_OBJECT_LOCK (pad);
   g_signal_handler_disconnect (pad, handler_id);
   GST_PAD_DO_BUFFER_SIGNALS (pad)--;
@@ -2999,9 +2923,6 @@ gst_pad_remove_buffer_probe (GstPad * pa
       GST_DEBUG_PAD_NAME (pad), GST_PAD_DO_BUFFER_SIGNALS (pad));
   GST_OBJECT_UNLOCK (pad);
 
-  if (was_ghost) {
-    gst_object_unref (pad);
-  }
 }
 
 /**
Index: tests/check/gst/gstghostpad.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/tests/check/gst/gstghostpad.c,v
retrieving revision 1.21
diff -u -p -r1.21 gstghostpad.c
--- tests/check/gst/gstghostpad.c	1 Jul 2006 20:56:55 -0000	1.21
+++ tests/check/gst/gstghostpad.c	11 Jul 2006 12:08:02 -0000
@@ -61,7 +61,9 @@ GST_START_TEST (test_remove1)
   /* now remove the bin with the ghostpad, b2 is disposed now. */
   ASSERT_OBJECT_REFCOUNT (b1, "pipeline", 2);
   ASSERT_OBJECT_REFCOUNT (b2, "bin", 1);
+  GST_DEBUG ("before calling bin_remove");
   gst_bin_remove (GST_BIN (b1), b2);
+  GST_DEBUG ("after calling bin_remove");
 
   srcpad = gst_element_get_pad (src, "src");
   /* pad cannot be linked now */
@@ -306,27 +308,27 @@ GST_START_TEST (test_ghost_pads)
   while (GST_OBJECT_REFCOUNT_VALUE (fsrc) > 2)
     THREAD_SWITCH ();
 
-  ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 2);     /* gisrc */
+  ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
   ASSERT_OBJECT_REFCOUNT (gsink, "gsink", 1);
   ASSERT_OBJECT_REFCOUNT (gsrc, "gsink", 1);
-  ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 2);   /* gisink */
+  ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
 
-  ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 1);   /* gsink */
+  ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 2);   /* gsink */
   ASSERT_OBJECT_REFCOUNT (isink, "isink", 2);   /* gsink */
-  ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 1); /* gsrc */
+  ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 2); /* gsrc */
   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 2);     /* gsrc */
 
   gst_object_unref (gsink);
   ASSERT_OBJECT_REFCOUNT (isink, "isink", 1);
   ASSERT_OBJECT_REFCOUNT (gisrc, "gisrc", 1);
-  ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 2);     /* gisrc */
+  ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
   gst_object_unref (gisrc);
   ASSERT_OBJECT_REFCOUNT (fsrc, "fsrc", 1);
 
   gst_object_unref (gsrc);
   ASSERT_OBJECT_REFCOUNT (isrc, "isrc", 1);
   ASSERT_OBJECT_REFCOUNT (gisink, "gisink", 1);
-  ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 2);   /* gisrc */
+  ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
   gst_object_unref (gisink);
   ASSERT_OBJECT_REFCOUNT (fsink, "fsink", 1);
 
