gst/gstpad.c: Only sanity-check the buffer size if requested_caps == buffer_caps...
[platform/upstream/gstreamer.git] / gst / gstpad.c
index 6e02742..df8eba2 100644 (file)
@@ -308,16 +308,16 @@ gst_pad_class_init (GstPadClass * klass)
 
   g_object_class_install_property (gobject_class, PAD_PROP_CAPS,
       g_param_spec_boxed ("caps", "Caps", "The capabilities of the pad",
-          GST_TYPE_CAPS, G_PARAM_READABLE));
+          GST_TYPE_CAPS, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (gobject_class, PAD_PROP_DIRECTION,
       g_param_spec_enum ("direction", "Direction", "The direction of the pad",
           GST_TYPE_PAD_DIRECTION, GST_PAD_UNKNOWN,
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
   /* FIXME, Make G_PARAM_CONSTRUCT_ONLY when we fix ghostpads. */
   g_object_class_install_property (gobject_class, PAD_PROP_TEMPLATE,
       g_param_spec_object ("template", "Template",
           "The GstPadTemplate of this pad", GST_TYPE_PAD_TEMPLATE,
-          G_PARAM_READWRITE));
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
 #ifndef GST_DISABLE_LOADSAVE
   gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_pad_save_thyself);
@@ -352,8 +352,7 @@ gst_pad_init (GstPad * pad)
   pad->do_buffer_signals = 0;
   pad->do_event_signals = 0;
 
-  /* FIXME, should be set flushing initially, see #339326 */
-  GST_PAD_UNSET_FLUSHING (pad);
+  GST_PAD_SET_FLUSHING (pad);
 
   pad->preroll_lock = g_mutex_new ();
   pad->preroll_cond = g_cond_new ();
@@ -368,12 +367,22 @@ static void
 gst_pad_dispose (GObject * object)
 {
   GstPad *pad = GST_PAD (object);
+  GstPad *peer;
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, pad, "dispose");
 
-  /* we don't hold a ref to the peer so we can just set the
-   * peer to NULL. */
-  GST_PAD_PEER (pad) = NULL;
+  /* unlink the peer pad */
+  if ((peer = gst_pad_get_peer (pad))) {
+    /* window for MT unsafeness, someone else could unlink here
+     * and then we call unlink with wrong pads. The unlink
+     * function would catch this and safely return failed. */
+    if (GST_PAD_IS_SRC (pad))
+      gst_pad_unlink (pad, peer);
+    else
+      gst_pad_unlink (peer, pad);
+
+    gst_object_unref (peer);
+  }
 
   /* clear the caps */
   gst_caps_replace (&GST_PAD_CAPS (pad), NULL);
@@ -577,8 +586,9 @@ pre_activate (GstPad * pad, GstActivateMode new_mode)
       GST_OBJECT_LOCK (pad);
       GST_DEBUG_OBJECT (pad, "setting ACTIVATE_MODE NONE, set flushing");
       GST_PAD_SET_FLUSHING (pad);
+      GST_PAD_ACTIVATE_MODE (pad) = new_mode;
       /* unlock blocked pads so element can resume and stop */
-      GST_PAD_BLOCK_SIGNAL (pad);
+      GST_PAD_BLOCK_BROADCAST (pad);
       GST_OBJECT_UNLOCK (pad);
       break;
   }
@@ -595,11 +605,7 @@ post_activate (GstPad * pad, GstActivateMode new_mode)
     case GST_ACTIVATE_NONE:
       /* ensures that streaming stops */
       GST_PAD_STREAM_LOCK (pad);
-      /* while we're at it set activation mode */
-      GST_OBJECT_LOCK (pad);
-      GST_DEBUG_OBJECT (pad, "setting ACTIVATE_MODE %d", new_mode);
-      GST_PAD_ACTIVATE_MODE (pad) = new_mode;
-      GST_OBJECT_UNLOCK (pad);
+      GST_DEBUG_OBJECT (pad, "stopped streaming");
       GST_PAD_STREAM_UNLOCK (pad);
       break;
   }
@@ -640,22 +646,30 @@ gst_pad_set_active (GstPad * pad, gboolean active)
   if (active) {
     switch (old) {
       case GST_ACTIVATE_PUSH:
+        GST_DEBUG_OBJECT (pad, "activating pad from push");
+        ret = TRUE;
+        break;
       case GST_ACTIVATE_PULL:
+        GST_DEBUG_OBJECT (pad, "activating pad from pull");
         ret = TRUE;
         break;
       case GST_ACTIVATE_NONE:
+        GST_DEBUG_OBJECT (pad, "activating pad from none");
         ret = (GST_PAD_ACTIVATEFUNC (pad)) (pad);
         break;
     }
   } else {
     switch (old) {
       case GST_ACTIVATE_PUSH:
+        GST_DEBUG_OBJECT (pad, "deactivating pad from push");
         ret = gst_pad_activate_push (pad, FALSE);
         break;
       case GST_ACTIVATE_PULL:
+        GST_DEBUG_OBJECT (pad, "deactivating pad from pull");
         ret = gst_pad_activate_pull (pad, FALSE);
         break;
       case GST_ACTIVATE_NONE:
+        GST_DEBUG_OBJECT (pad, "deactivating pad from none");
         ret = TRUE;
         break;
     }
@@ -667,7 +681,7 @@ gst_pad_set_active (GstPad * pad, gboolean active)
       g_critical ("Failed to deactivate pad %s:%s, very bad",
           GST_DEBUG_PAD_NAME (pad));
     } else {
-      GST_WARNING ("Failed to activate pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+      GST_WARNING_OBJECT (pad, "Failed to activate pad");
     }
     GST_OBJECT_UNLOCK (pad);
   }
@@ -682,9 +696,9 @@ gst_pad_set_active (GstPad * pad, gboolean active)
  *
  * Activates or deactivates the given pad in pull mode via dispatching to the
  * pad's activatepullfunc. For use from within pad activation functions only.
- * When called on sink pads, will first proxy the call to the peer pad, which is
- * expected to activate its internally linked pads from within its activate_pull
- * function.
+ * When called on sink pads, will first proxy the call to the peer pad, which
+ * is expected to activate its internally linked pads from within its
+ * activate_pull function.
  *
  * If you don't know what this is, you probably don't want to call it.
  *
@@ -707,21 +721,27 @@ gst_pad_activate_pull (GstPad * pad, gboolean active)
   if (active) {
     switch (old) {
       case GST_ACTIVATE_PULL:
+        GST_DEBUG_OBJECT (pad, "activating pad from pull, was ok");
         goto was_ok;
       case GST_ACTIVATE_PUSH:
+        GST_DEBUG_OBJECT (pad,
+            "activating pad from push, deactivate push first");
         /* pad was activate in the wrong direction, deactivate it
          * and reactivate it in pull mode */
         if (G_UNLIKELY (!gst_pad_activate_push (pad, FALSE)))
           goto deactivate_failed;
         /* fallthrough, pad is deactivated now. */
       case GST_ACTIVATE_NONE:
+        GST_DEBUG_OBJECT (pad, "activating pad from none");
         break;
     }
   } else {
     switch (old) {
       case GST_ACTIVATE_NONE:
+        GST_DEBUG_OBJECT (pad, "deactivating pad from none, was ok");
         goto was_ok;
       case GST_ACTIVATE_PUSH:
+        GST_DEBUG_OBJECT (pad, "deactivating pad from push, weird");
         /* pad was activated in the other direction, deactivate it
          * in push mode, this should not happen... */
         if (G_UNLIKELY (!gst_pad_activate_push (pad, FALSE)))
@@ -729,19 +749,23 @@ gst_pad_activate_pull (GstPad * pad, gboolean active)
         /* everything is fine now */
         goto was_ok;
       case GST_ACTIVATE_PULL:
+        GST_DEBUG_OBJECT (pad, "deactivating pad from pull");
         break;
     }
   }
 
   if (gst_pad_get_direction (pad) == GST_PAD_SINK) {
     if ((peer = gst_pad_get_peer (pad))) {
+      GST_DEBUG_OBJECT (pad, "calling peer");
       if (G_UNLIKELY (!gst_pad_activate_pull (peer, active)))
         goto peer_failed;
       gst_object_unref (peer);
+    } else {
+      goto not_linked;
     }
   } else {
     if (G_UNLIKELY (GST_PAD_GETRANGEFUNC (pad) == NULL))
-      goto failure;             /* Can't activate pull on a src without a 
+      goto failure;             /* Can't activate pull on a src without a
                                    getrange function */
   }
 
@@ -784,6 +808,12 @@ peer_failed:
     gst_object_unref (peer);
     return FALSE;
   }
+not_linked:
+  {
+    GST_CAT_INFO_OBJECT (GST_CAT_PADS, pad, "can't activate unlinked sink "
+        "pad in pull mode");
+    return FALSE;
+  }
 failure:
   {
     GST_OBJECT_LOCK (pad);
@@ -826,21 +856,27 @@ gst_pad_activate_push (GstPad * pad, gboolean active)
   if (active) {
     switch (old) {
       case GST_ACTIVATE_PUSH:
+        GST_DEBUG_OBJECT (pad, "activating pad from push, was ok");
         goto was_ok;
       case GST_ACTIVATE_PULL:
+        GST_DEBUG_OBJECT (pad,
+            "activating pad from push, deactivating pull first");
         /* pad was activate in the wrong direction, deactivate it
          * an reactivate it in push mode */
         if (G_UNLIKELY (!gst_pad_activate_pull (pad, FALSE)))
           goto deactivate_failed;
         /* fallthrough, pad is deactivated now. */
       case GST_ACTIVATE_NONE:
+        GST_DEBUG_OBJECT (pad, "activating pad from none");
         break;
     }
   } else {
     switch (old) {
       case GST_ACTIVATE_NONE:
+        GST_DEBUG_OBJECT (pad, "deactivating pad from none, was ok");
         goto was_ok;
       case GST_ACTIVATE_PULL:
+        GST_DEBUG_OBJECT (pad, "deactivating pad from pull, weird");
         /* pad was activated in the other direction, deactivate it
          * in pull mode, this should not happen... */
         if (G_UNLIKELY (!gst_pad_activate_pull (pad, FALSE)))
@@ -848,6 +884,7 @@ gst_pad_activate_push (GstPad * pad, gboolean active)
         /* everything is fine now */
         goto was_ok;
       case GST_ACTIVATE_PUSH:
+        GST_DEBUG_OBJECT (pad, "deactivating pad from push");
         break;
     }
   }
@@ -937,9 +974,8 @@ gst_pad_is_active (GstPad * pad)
  * You can pass NULL as the callback to make this call block. Be careful with
  * this blocking call as it might not return for reasons stated above.
  *
- * Returns: TRUE if the pad could be blocked. This function can fail
- *   if wrong parameters were passed or the pad was already in the
- *   requested state.
+ * Returns: TRUE if the pad could be blocked. This function can fail if the
+ * wrong parameters were passed or the pad was already in the requested state.
  *
  * MT safe.
  */
@@ -977,10 +1013,9 @@ gst_pad_set_blocked_async (GstPad * pad, gboolean blocked,
     pad->block_callback = callback;
     pad->block_data = user_data;
 
-    if (callback) {
-      GST_PAD_BLOCK_SIGNAL (pad);
-    } else {
-      GST_PAD_BLOCK_SIGNAL (pad);
+    GST_PAD_BLOCK_BROADCAST (pad);
+    if (!callback) {
+      /* no callback, wait for the unblock to happen */
       GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "waiting for unblock");
       GST_PAD_BLOCK_WAIT (pad);
       GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "unblocked");
@@ -1009,9 +1044,8 @@ had_right_state:
  * a shortcut for gst_pad_set_blocked_async() with a NULL
  * callback.
  *
- * Returns: TRUE if the pad could be blocked. This function can fail
- *   wrong parameters were passed or the pad was already in the
- *   requested state.
+ * Returns: TRUE if the pad could be blocked. This function can fail if the
+ * wrong parameters were passed or the pad was already in the requested state.
  *
  * MT safe.
  */
@@ -1068,9 +1102,7 @@ gst_pad_is_blocking (GstPad * pad)
   g_return_val_if_fail (GST_IS_PAD (pad), result);
 
   GST_OBJECT_LOCK (pad);
-
   /* the blocking flag is only valid if the pad is not flushing */
-
   result = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_BLOCKING) &&
       !GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLUSHING);
   GST_OBJECT_UNLOCK (pad);
@@ -1162,8 +1194,8 @@ gst_pad_set_chain_function (GstPad * pad, GstPadChainFunction chain)
  * @pad: a source #GstPad.
  * @get: the #GstPadGetRangeFunction to set.
  *
- * Sets the given getrange function for the pad. The getrange function is called to
- * produce a new #GstBuffer to start the processing pipeline. see
+ * Sets the given getrange function for the pad. The getrange function is
+ * called to produce a new #GstBuffer to start the processing pipeline. see
  * #GstPadGetRangeFunction for a description of the getrange function.
  */
 void
@@ -1183,8 +1215,8 @@ gst_pad_set_getrange_function (GstPad * pad, GstPadGetRangeFunction get)
  * @pad: a source #GstPad.
  * @check: the #GstPadCheckGetRangeFunction to set.
  *
- * Sets the given checkgetrange function for the pad. Implement this function on
- * a pad if you dynamically support getrange based scheduling on the pad.
+ * Sets the given checkgetrange function for the pad. Implement this function
+ * on a pad if you dynamically support getrange based scheduling on the pad.
  */
 void
 gst_pad_set_checkgetrange_function (GstPad * pad,
@@ -1201,7 +1233,7 @@ gst_pad_set_checkgetrange_function (GstPad * pad,
 
 /**
  * gst_pad_set_event_function:
- * @pad: a source #GstPad.
+ * @pad: a #GstPad of either direction.
  * @event: the #GstPadEventFunction to set.
  *
  * Sets the given event handler for the pad.
@@ -1397,8 +1429,8 @@ gst_pad_set_unlink_function (GstPad * pad, GstPadUnlinkFunction unlink)
  * @getcaps should return the most specific caps it reasonably can, since this
  * helps with autoplugging.
  *
- * Note that the return value from @getcaps is owned by the caller, so the caller
- * should unref the caps after usage.
+ * Note that the return value from @getcaps is owned by the caller, so the
+ * caller should unref the caps after usage.
  */
 void
 gst_pad_set_getcaps_function (GstPad * pad, GstPadGetCapsFunction getcaps)
@@ -1417,7 +1449,7 @@ gst_pad_set_getcaps_function (GstPad * pad, GstPadGetCapsFunction getcaps)
  *
  * Sets the given acceptcaps function for the pad.  The acceptcaps function
  * will be called to check if the pad can accept the given caps. Setting the
- * acceptcaps function to NULL restores the default behaviour of allowing 
+ * acceptcaps function to NULL restores the default behaviour of allowing
  * any caps that matches the caps from gst_pad_get_caps.
  */
 void
@@ -1497,8 +1529,8 @@ gst_pad_set_bufferalloc_function (GstPad * pad,
  * @srcpad: the source #GstPad to unlink.
  * @sinkpad: the sink #GstPad to unlink.
  *
- * Unlinks the source pad from the sink pad. Will emit the "unlinked" signal on
- * both pads.
+ * Unlinks the source pad from the sink pad. Will emit the #GstPad::unlinked
+ * signal on both pads.
  *
  * Returns: TRUE if the pads were unlinked. This function returns FALSE if
  * the pads were not linked together.
@@ -1673,6 +1705,10 @@ gst_pad_link_check_hierarchy (GstPad * src, GstPad * sink)
   if (G_UNLIKELY (psrc == NULL || psink == NULL))
     goto no_parent;
 
+  /* only care about parents that are elements */
+  if (G_UNLIKELY (!GST_IS_ELEMENT (psrc) || !GST_IS_ELEMENT (psink)))
+    goto no_element_parent;
+
   /* if the parents are the same, we have a loop */
   if (G_UNLIKELY (psrc == psink))
     goto same_parents;
@@ -1697,6 +1733,13 @@ no_parent:
         GST_PTR_FORMAT, psrc, psink);
     return TRUE;
   }
+no_element_parent:
+  {
+    GST_CAT_DEBUG (GST_CAT_CAPS,
+        "one of the pads has no element parent %" GST_PTR_FORMAT " and %"
+        GST_PTR_FORMAT, psrc, psink);
+    return TRUE;
+  }
 same_parents:
   {
     GST_CAT_DEBUG (GST_CAT_CAPS, "pads have same parent %" GST_PTR_FORMAT,
@@ -1921,6 +1964,7 @@ static GstCaps *
 gst_pad_get_caps_unlocked (GstPad * pad)
 {
   GstCaps *result = NULL;
+  GstPadTemplate *templ;
 
   GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get pad caps");
 
@@ -1964,9 +2008,7 @@ gst_pad_get_caps_unlocked (GstPad * pad)
       goto done;
     }
   }
-  if (GST_PAD_PAD_TEMPLATE (pad)) {
-    GstPadTemplate *templ = GST_PAD_PAD_TEMPLATE (pad);
-
+  if ((templ = GST_PAD_PAD_TEMPLATE (pad))) {
     result = GST_PAD_TEMPLATE_CAPS (templ);
     GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
         "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, result,
@@ -1975,9 +2017,7 @@ gst_pad_get_caps_unlocked (GstPad * pad)
     result = gst_caps_ref (result);
     goto done;
   }
-  if (GST_PAD_CAPS (pad)) {
-    result = GST_PAD_CAPS (pad);
-
+  if ((result = GST_PAD_CAPS (pad))) {
     GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
         "using pad caps %p %" GST_PTR_FORMAT, result, result);
 
@@ -1998,7 +2038,7 @@ done:
  *
  * Gets the capabilities this pad can produce or consume.
  * Note that this method doesn't necessarily return the caps set by
- * gst_pad_set_caps() - use #GST_PAD_CAPS for that instead.
+ * gst_pad_set_caps() - use GST_PAD_CAPS() for that instead.
  * gst_pad_get_caps returns all possible caps a pad can operate with, using
  * the pad's get_caps function;
  * this returns the pad template caps if not explicitly set.
@@ -2019,6 +2059,11 @@ gst_pad_get_caps (GstPad * pad)
   GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get pad caps");
 
   result = gst_pad_get_caps_unlocked (pad);
+
+  /* be sure that we have a copy */
+  if (result)
+    result = gst_caps_make_writable (result);
+
   GST_OBJECT_UNLOCK (pad);
 
   return result;
@@ -2030,9 +2075,9 @@ gst_pad_get_caps (GstPad * pad)
  *
  * Gets the capabilities of the peer connected to this pad.
  *
- * Returns: the #GstCaps of the peer pad. This function returns a new caps, so use
- * gst_caps_unref to get rid of it. this function returns NULL if there is no
- * peer pad.
+ * Returns: the #GstCaps of the peer pad. This function returns a new caps, so
+ * use gst_caps_unref to get rid of it. this function returns NULL if there is
+ * no peer pad.
  */
 GstCaps *
 gst_pad_peer_get_caps (GstPad * pad)
@@ -2080,7 +2125,12 @@ fixate_value (GValue * dest, const GValue * src)
   } else if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
     GValue temp = { 0 };
 
+    /* list could be empty */
+    if (gst_value_list_get_size (src) <= 0)
+      return FALSE;
+
     gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0));
+
     if (!fixate_value (dest, &temp))
       gst_value_init_and_copy (dest, &temp);
     g_value_unset (&temp);
@@ -2159,7 +2209,7 @@ gst_pad_fixate_caps (GstPad * pad, GstCaps * caps)
   }
 }
 
-/* Default accept caps implementation just checks against 
+/* Default accept caps implementation just checks against
  * against the allowed caps for the pad */
 static gboolean
 gst_pad_acceptcaps_default (GstPad * pad, GstCaps * caps)
@@ -2170,17 +2220,33 @@ gst_pad_acceptcaps_default (GstPad * pad, GstCaps * caps)
   GstCaps *allowed;
   gboolean result = FALSE;
 
+  GST_DEBUG_OBJECT (pad, "caps %" GST_PTR_FORMAT, caps);
+
   allowed = gst_pad_get_caps (pad);
-  if (allowed) {
-    intersect = gst_caps_intersect (allowed, caps);
+  if (!allowed)
+    goto nothing_allowed;
 
-    result = !gst_caps_is_empty (intersect);
+  GST_DEBUG_OBJECT (pad, "allowed caps %" GST_PTR_FORMAT, allowed);
 
-    gst_caps_unref (allowed);
-    gst_caps_unref (intersect);
-  }
+  intersect = gst_caps_intersect (allowed, caps);
+
+  GST_DEBUG_OBJECT (pad, "intersection %" GST_PTR_FORMAT, intersect);
+
+  result = !gst_caps_is_empty (intersect);
+  if (!result)
+    GST_DEBUG_OBJECT (pad, "intersection gave empty caps");
+
+  gst_caps_unref (allowed);
+  gst_caps_unref (intersect);
 
   return result;
+
+  /* ERRORS */
+nothing_allowed:
+  {
+    GST_DEBUG_OBJECT (pad, "no caps allowed on the pad");
+    return FALSE;
+  }
 }
 
 /**
@@ -2219,14 +2285,17 @@ gst_pad_accept_caps (GstPad * pad, GstCaps * caps)
   if (G_LIKELY (acceptfunc)) {
     /* we can call the function */
     result = acceptfunc (pad, caps);
+    GST_DEBUG_OBJECT (pad, "acceptfunc returned %d", result);
   } else {
     /* Only null if the element explicitly unset it */
     result = gst_pad_acceptcaps_default (pad, caps);
+    GST_DEBUG_OBJECT (pad, "default acceptcaps returned %d", result);
   }
   return result;
 
 is_same_caps:
   {
+    GST_DEBUG_OBJECT (pad, "pad had same caps");
     GST_OBJECT_UNLOCK (pad);
     return TRUE;
   }
@@ -2258,9 +2327,14 @@ gst_pad_peer_accept_caps (GstPad * pad, GstCaps * caps)
   if (G_UNLIKELY (peerpad == NULL))
     goto no_peer;
 
-  result = gst_pad_accept_caps (peerpad, caps);
+  gst_object_ref (peerpad);
+  /* release lock before calling external methods but keep ref to pad */
   GST_OBJECT_UNLOCK (pad);
 
+  result = gst_pad_accept_caps (peerpad, caps);
+
+  gst_object_unref (peerpad);
+
   return result;
 
 no_peer:
@@ -2358,16 +2432,11 @@ could_not_set:
 static gboolean
 gst_pad_configure_sink (GstPad * pad, GstCaps * caps)
 {
-  GstPadSetCapsFunction setcaps;
   gboolean res;
 
-  setcaps = GST_PAD_SETCAPSFUNC (pad);
-
-  /* See if pad accepts the caps - only needed if 
-   * no setcaps function */
-  if (setcaps == NULL)
-    if (!gst_pad_accept_caps (pad, caps))
-      goto not_accepted;
+  /* See if pad accepts the caps */
+  if (!gst_pad_accept_caps (pad, caps))
+    goto not_accepted;
 
   /* set caps on pad if call succeeds */
   res = gst_pad_set_caps (pad, caps);
@@ -2388,16 +2457,11 @@ not_accepted:
 static gboolean
 gst_pad_configure_src (GstPad * pad, GstCaps * caps, gboolean dosetcaps)
 {
-  GstPadSetCapsFunction setcaps;
   gboolean res;
 
-  setcaps = GST_PAD_SETCAPSFUNC (pad);
-
-  /* See if pad accepts the caps - only needed if 
-   * no setcaps function */
-  if (setcaps == NULL)
-    if (!gst_pad_accept_caps (pad, caps))
-      goto not_accepted;
+  /* See if pad accepts the caps */
+  if (!gst_pad_accept_caps (pad, caps))
+    goto not_accepted;
 
   if (dosetcaps)
     res = gst_pad_set_caps (pad, caps);
@@ -2420,8 +2484,8 @@ not_accepted:
  *
  * Gets the capabilities for @pad's template.
  *
- * Returns: the #GstCaps of this pad template. If you intend to keep a reference
- * on the caps, make a copy (see gst_caps_copy ()).
+ * Returns: the #GstCaps of this pad template. If you intend to keep a
+ * reference on the caps, make a copy (see gst_caps_copy ()).
  */
 const GstCaps *
 gst_pad_get_pad_template_caps (GstPad * pad)
@@ -2436,7 +2500,6 @@ gst_pad_get_pad_template_caps (GstPad * pad)
   return gst_static_caps_get (&anycaps);
 }
 
-
 /**
  * gst_pad_get_peer:
  * @pad: a #GstPad to get the peer of.
@@ -2466,40 +2529,41 @@ gst_pad_get_peer (GstPad * pad)
 
 /**
  * gst_pad_get_allowed_caps:
- * @srcpad: a #GstPad, it must a a source pad.
+ * @pad: a #GstPad.
  *
  * Gets the capabilities of the allowed media types that can flow through
- * @srcpad and its peer. The pad must be a source pad.
- * The caller must free the resulting caps.
+ * @pad and its peer.
+ *
+ * The allowed capabilities is calculated as the intersection of the results of
+ * calling gst_pad_get_caps() on @pad and its peer. The caller owns a reference
+ * on the resulting caps.
  *
- * Returns: the allowed #GstCaps of the pad link.  Free the caps when
- * you no longer need it. This function returns NULL when the @srcpad has no
- * peer.
+ * Returns: the allowed #GstCaps of the pad link. Unref the caps when you no
+ * longer need it. This function returns NULL when @pad has no peer.
  *
  * MT safe.
  */
 GstCaps *
-gst_pad_get_allowed_caps (GstPad * srcpad)
+gst_pad_get_allowed_caps (GstPad * pad)
 {
   GstCaps *mycaps;
   GstCaps *caps;
   GstCaps *peercaps;
   GstPad *peer;
 
-  g_return_val_if_fail (GST_IS_PAD (srcpad), NULL);
-  g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), NULL);
+  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
 
-  GST_OBJECT_LOCK (srcpad);
+  GST_OBJECT_LOCK (pad);
 
-  peer = GST_PAD_PEER (srcpad);
+  peer = GST_PAD_PEER (pad);
   if (G_UNLIKELY (peer == NULL))
     goto no_peer;
 
-  GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, srcpad, "getting allowed caps");
+  GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, pad, "getting allowed caps");
 
   gst_object_ref (peer);
-  GST_OBJECT_UNLOCK (srcpad);
-  mycaps = gst_pad_get_caps (srcpad);
+  GST_OBJECT_UNLOCK (pad);
+  mycaps = gst_pad_get_caps (pad);
 
   peercaps = gst_pad_get_caps (peer);
   gst_object_unref (peer);
@@ -2508,15 +2572,15 @@ gst_pad_get_allowed_caps (GstPad * srcpad)
   gst_caps_unref (peercaps);
   gst_caps_unref (mycaps);
 
-  GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, srcpad, "allowed caps %" GST_PTR_FORMAT,
+  GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "allowed caps %" GST_PTR_FORMAT,
       caps);
 
   return caps;
 
 no_peer:
   {
-    GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, srcpad, "no peer");
-    GST_OBJECT_UNLOCK (srcpad);
+    GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, pad, "no peer");
+    GST_OBJECT_UNLOCK (pad);
 
     return NULL;
   }
@@ -2533,7 +2597,7 @@ no_peer:
  * always negotiated before sinkpads so it is possible that the negotiated caps
  * on the srcpad do not match the negotiated caps of the peer.
  *
- * Returns: the negotiated #GstCaps of the pad link.  Free the caps when
+ * Returns: the negotiated #GstCaps of the pad link.  Unref the caps when
  * you no longer need it. This function returns NULL when the @pad has no
  * peer or is not negotiated yet.
  *
@@ -2607,8 +2671,10 @@ gst_pad_buffer_alloc_unchecked (GstPad * pad, guint64 offset, gint size,
     goto fallback;
 
   ret = bufferallocfunc (pad, offset, size, caps, buf);
+
   if (G_UNLIKELY (ret != GST_FLOW_OK))
     goto error;
+
   /* no error, but NULL buffer means fallback to the default */
   if (G_UNLIKELY (*buf == NULL))
     goto fallback;
@@ -2640,25 +2706,34 @@ fallback:
     /* fallback case, allocate a buffer of our own, add pad caps. */
     GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "fallback buffer alloc");
 
-    *buf = gst_buffer_new_and_alloc (size);
-    GST_BUFFER_OFFSET (*buf) = offset;
-    gst_buffer_set_caps (*buf, caps);
-
-    return GST_FLOW_OK;
+    if ((*buf = gst_buffer_try_new_and_alloc (size))) {
+      GST_BUFFER_OFFSET (*buf) = offset;
+      gst_buffer_set_caps (*buf, caps);
+      return GST_FLOW_OK;
+    } else {
+      GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
+          "out of memory allocating %d bytes", size);
+      return GST_FLOW_ERROR;
+    }
   }
 }
 
+/* FIXME 0.11: size should be unsigned */
 static GstFlowReturn
 gst_pad_alloc_buffer_full (GstPad * pad, guint64 offset, gint size,
     GstCaps * caps, GstBuffer ** buf, gboolean setcaps)
 {
   GstPad *peer;
   GstFlowReturn ret;
+  GstCaps *newcaps;
   gboolean caps_changed;
 
   g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
   g_return_val_if_fail (GST_PAD_IS_SRC (pad), GST_FLOW_ERROR);
   g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
+  g_return_val_if_fail (size >= 0, GST_FLOW_ERROR);
+
+  GST_DEBUG_OBJECT (pad, "offset %" G_GUINT64_FORMAT ", size %d", offset, size);
 
   GST_OBJECT_LOCK (pad);
   while (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad)))
@@ -2678,22 +2753,29 @@ gst_pad_alloc_buffer_full (GstPad * pad, guint64 offset, gint size,
     goto peer_error;
 
   /* FIXME, move capnego this into a base class? */
-  caps = GST_BUFFER_CAPS (*buf);
+  newcaps = GST_BUFFER_CAPS (*buf);
 
   /* Lock for checking caps, pretty pointless as the _pad_push() function might
    * change it concurrently, one of the problems with automatic caps setting in
-   * pad_alloc_and_set_caps. Worst case, if does a check too much, but only when
-   * there is heavy renegotiation going on in both directions. */
+   * pad_alloc_and_set_caps. Worst case, if does a check too much, but only
+   * when there is heavy renegotiation going on in both directions. */
   GST_OBJECT_LOCK (pad);
-  caps_changed = caps && caps != GST_PAD_CAPS (pad);
+  caps_changed = newcaps && newcaps != GST_PAD_CAPS (pad);
   GST_OBJECT_UNLOCK (pad);
 
   /* we got a new datatype on the pad, see if it can handle it */
   if (G_UNLIKELY (caps_changed)) {
-    GST_DEBUG_OBJECT (pad, "caps changed to %p %" GST_PTR_FORMAT, caps, caps);
-    if (G_UNLIKELY (!gst_pad_configure_src (pad, caps, setcaps)))
+    GST_DEBUG_OBJECT (pad,
+        "caps changed from %" GST_PTR_FORMAT " to %p %" GST_PTR_FORMAT,
+        GST_PAD_CAPS (pad), newcaps, newcaps);
+    if (G_UNLIKELY (!gst_pad_configure_src (pad, newcaps, setcaps)))
       goto not_negotiated;
   }
+
+  /* sanity check (only if caps are the same) */
+  if (G_LIKELY (newcaps == caps) && G_UNLIKELY (GST_BUFFER_SIZE (*buf) < size))
+    goto wrong_size_fallback;
+
   return ret;
 
 flushed:
@@ -2724,6 +2806,24 @@ not_negotiated:
         "alloc function returned unacceptable buffer");
     return GST_FLOW_NOT_NEGOTIATED;
   }
+wrong_size_fallback:
+  {
+    GST_CAT_ERROR_OBJECT (GST_CAT_PADS, pad, "buffer returned by alloc "
+        "function is too small (%u < %d), doing fallback buffer alloc",
+        GST_BUFFER_SIZE (*buf), size);
+
+    gst_buffer_unref (*buf);
+
+    if ((*buf = gst_buffer_try_new_and_alloc (size))) {
+      GST_BUFFER_OFFSET (*buf) = offset;
+      gst_buffer_set_caps (*buf, caps);
+      return GST_FLOW_OK;
+    } else {
+      GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad,
+          "out of memory allocating %d bytes", size);
+      return GST_FLOW_ERROR;
+    }
+  }
 }
 
 /**
@@ -2749,6 +2849,8 @@ not_negotiated:
  *
  * MT safe.
  */
+
+/* FIXME 0.11: size should be unsigned */
 GstFlowReturn
 gst_pad_alloc_buffer (GstPad * pad, guint64 offset, gint size, GstCaps * caps,
     GstBuffer ** buf)
@@ -2776,6 +2878,8 @@ gst_pad_alloc_buffer (GstPad * pad, guint64 offset, gint size, GstCaps * caps,
  *
  * MT safe.
  */
+
+/* FIXME 0.11: size should be unsigned */
 GstFlowReturn
 gst_pad_alloc_buffer_and_set_caps (GstPad * pad, guint64 offset, gint size,
     GstCaps * caps, GstBuffer ** buf)
@@ -2811,7 +2915,7 @@ gst_pad_get_internal_links_default (GstPad * pad)
 
   parent = GST_PAD_PARENT (pad);
   if (!parent)
-    return NULL;
+    goto no_parent;
 
   parent_pads = parent->pads;
 
@@ -2819,13 +2923,19 @@ gst_pad_get_internal_links_default (GstPad * pad)
     GstPad *parent_pad = GST_PAD_CAST (parent_pads->data);
 
     if (parent_pad->direction != direction) {
+      GST_DEBUG_OBJECT (pad, "adding pad %s:%s",
+          GST_DEBUG_PAD_NAME (parent_pad));
       res = g_list_prepend (res, parent_pad);
     }
-
     parent_pads = g_list_next (parent_pads);
   }
-
   return res;
+
+no_parent:
+  {
+    GST_DEBUG_OBJECT (pad, "no parent");
+    return NULL;
+  }
 }
 
 /**
@@ -2860,13 +2970,22 @@ gst_pad_event_default_dispatch (GstPad * pad, GstEvent * event)
   GList *orig, *pads;
   gboolean result;
 
-  GST_INFO_OBJECT (pad, "Sending event %p to all internally linked pads",
-      event);
-
-  result = (GST_PAD_DIRECTION (pad) == GST_PAD_SINK);
+  GST_INFO_OBJECT (pad, "Sending event %p (%s) to all internally linked pads",
+      event, GST_EVENT_TYPE_NAME (event));
 
   orig = pads = gst_pad_get_internal_links (pad);
 
+  if (!pads) {
+    /* If this is a sinkpad and we don't have pads to send the event to, we
+     * return TRUE. This is so that when using the default handler on a sink
+     * element, we don't fail to push it. */
+    result = (GST_PAD_DIRECTION (pad) == GST_PAD_SINK);
+  } else {
+    /* we have pads, the result will be TRUE if one of the pads handled the
+     * event in the code below. */
+    result = FALSE;
+  }
+
   while (pads) {
     GstPad *eventpad = GST_PAD_CAST (pads->data);
 
@@ -2878,7 +2997,7 @@ gst_pad_event_default_dispatch (GstPad * pad, GstEvent * event)
       GST_LOG_OBJECT (pad, "Reffing and sending event %p (%s) to %s:%s",
           event, GST_EVENT_TYPE_NAME (event), GST_DEBUG_PAD_NAME (eventpad));
       gst_event_ref (event);
-      gst_pad_push_event (eventpad, event);
+      result |= gst_pad_push_event (eventpad, event);
     } else {
       /* we only send the event on one pad, multi-sinkpad elements
        * should implement a handler */
@@ -2923,6 +3042,7 @@ gst_pad_event_default (GstPad * pad, GstEvent * event)
       GST_DEBUG_OBJECT (pad, "pausing task because of eos");
       gst_pad_pause_task (pad);
     }
+      /* fall thru */
     default:
       break;
   }
@@ -2936,8 +3056,8 @@ gst_pad_event_default (GstPad * pad, GstEvent * event)
  * @dispatch: the #GstDispatcherFunction to call.
  * @data: gpointer user data passed to the dispatcher function.
  *
- * Invokes the given dispatcher function on all pads that are
- * internally linked to the given pad.
+ * Invokes the given dispatcher function on each respective peer of
+ * all pads that are internally linked to the given pad.
  * The GstPadDispatcherFunction should return TRUE when no further pads
  * need to be processed.
  *
@@ -2957,17 +3077,22 @@ gst_pad_dispatcher (GstPad * pad, GstPadDispatcherFunction dispatch,
 
   while (int_pads) {
     GstPad *int_pad = GST_PAD_CAST (int_pads->data);
-    GstPad *int_peer = GST_PAD_PEER (int_pad);
+    GstPad *int_peer = gst_pad_get_peer (int_pad);
 
     if (int_peer) {
+      GST_DEBUG_OBJECT (int_pad, "dispatching to peer %s:%s",
+          GST_DEBUG_PAD_NAME (int_peer));
       res = dispatch (int_peer, data);
+      gst_object_unref (int_peer);
       if (res)
         break;
+    } else {
+      GST_DEBUG_OBJECT (int_pad, "no peer");
     }
     int_pads = g_list_next (int_pads);
   }
-
   g_list_free (orig);
+  GST_DEBUG_OBJECT (pad, "done, result %d", res);
 
   return res;
 }
@@ -3010,13 +3135,63 @@ no_func:
 }
 
 /**
+ * gst_pad_peer_query:
+ * @pad: a #GstPad to invoke the peer query on.
+ * @query: the #GstQuery to perform.
+ *
+ * Performs gst_pad_query() on the peer of @pad.
+ *
+ * The caller is responsible for both the allocation and deallocation of
+ * the query structure.
+ *
+ * Returns: TRUE if the query could be performed. This function returns %FALSE
+ * if @pad has no peer.
+ *
+ * Since: 0.10.15
+ */
+gboolean
+gst_pad_peer_query (GstPad * pad, GstQuery * query)
+{
+  GstPad *peerpad;
+  gboolean result;
+
+  g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
+  g_return_val_if_fail (GST_IS_QUERY (query), FALSE);
+
+  GST_OBJECT_LOCK (pad);
+
+  GST_DEBUG_OBJECT (pad, "peer query");
+
+  peerpad = GST_PAD_PEER (pad);
+  if (G_UNLIKELY (peerpad == NULL))
+    goto no_peer;
+
+  gst_object_ref (peerpad);
+  GST_OBJECT_UNLOCK (pad);
+
+  result = gst_pad_query (peerpad, query);
+
+  gst_object_unref (peerpad);
+
+  return result;
+
+  /* ERRORS */
+no_peer:
+  {
+    GST_WARNING_OBJECT (pad, "pad has no peer");
+    GST_OBJECT_UNLOCK (pad);
+    return FALSE;
+  }
+}
+
+/**
  * gst_pad_query_default:
  * @pad: a #GstPad to call the default query handler on.
  * @query: the #GstQuery to handle.
  *
- * Invokes the default query handler for the given pad. 
- * The query is sent to all pads internally linked to @pad. Note that 
- * if there are many possible sink pads that are internally linked to 
+ * Invokes the default query handler for the given pad.
+ * The query is sent to all pads internally linked to @pad. Note that
+ * if there are many possible sink pads that are internally linked to
  * @pad, only one will be sent the query.
  * Multi-sinkpad elements should implement custom query handlers.
  *
@@ -3063,7 +3238,9 @@ gst_pad_load_and_link (xmlNodePtr self, GstObject * parent)
   while (field) {
     if (!strcmp ((char *) field->name, "name")) {
       name = (gchar *) xmlNodeGetContent (field);
-      pad = gst_element_get_pad (GST_ELEMENT (parent), name);
+      pad = gst_element_get_static_pad (GST_ELEMENT (parent), name);
+      if (!pad)
+        pad = gst_element_get_request_pad (GST_ELEMENT (parent), name);
       g_free (name);
     } else if (!strcmp ((char *) field->name, "peer")) {
       peer = (gchar *) xmlNodeGetContent (field);
@@ -3099,7 +3276,9 @@ gst_pad_load_and_link (xmlNodePtr self, GstObject * parent)
   if (target == NULL)
     goto cleanup;
 
-  targetpad = gst_element_get_pad (target, split[1]);
+  targetpad = gst_element_get_static_pad (target, split[1]);
+  if (!pad)
+    targetpad = gst_element_get_request_pad (target, split[1]);
 
   if (targetpad == NULL)
     goto cleanup;
@@ -3186,21 +3365,21 @@ gst_ghost_pad_save_thyself (GstPad * pad, xmlNodePtr parent)
 #endif /* GST_DISABLE_LOADSAVE */
 
 /*
- * should be called with pad OBJECT_LOCK and STREAM_LOCK held. 
+ * should be called with pad OBJECT_LOCK and STREAM_LOCK held.
  * GST_PAD_IS_BLOCKED (pad) == TRUE when this function is
  * called.
  *
- * This function perform the pad blocking when an event, buffer push
+ * This function performs the pad blocking when an event, buffer push
  * or buffer_alloc is performed on a _SRC_ pad. It blocks the
- * streaming thread after informing the pad has been blocked. 
+ * streaming thread after informing the pad has been blocked.
  *
  * An application can with this method wait and block any streaming
  * thread and perform operations such as seeking or linking.
  *
  * Two methods are available for notifying the application of the
- * block: 
+ * block:
  * - the callback method, which happens in the STREAMING thread with
- *   the STREAM_LOCK held. With this method, the most usefull way of
+ *   the STREAM_LOCK held. With this method, the most useful way of
  *   dealing with the callback is to post a message to the main thread
  *   where the pad block can then be handled outside of the streaming
  *   thread. With the last method one can perform all operations such
@@ -3210,9 +3389,7 @@ gst_ghost_pad_save_thyself (GstPad * pad, xmlNodePtr parent)
  *   the pad block happens.
  *
  * During the actual blocking state, the GST_PAD_BLOCKING flag is set.
- * The GST_PAD_BLOCKING flag is unset when the pad was unblocked without a
- * flush. This is to know whether the pad was blocking when GST_PAD_FLUSHING
- * was set.
+ * The GST_PAD_BLOCKING flag is unset when the pad was unblocked.
  *
  * MT safe.
  */
@@ -3233,7 +3410,7 @@ handle_pad_block (GstPad * pad)
   /* we grab an extra ref for the callbacks, this is probably not
    * needed (callback code does not have a ref and cannot unref). I
    * think this was done to make it possible to unref the element in
-   * the callback, which is in the end totally impossible as it 
+   * the callback, which is in the end totally impossible as it
    * requires grabbing the STREAM_LOCK and OBJECT_LOCK which are
    * all taken when calling this function. */
   gst_object_ref (pad);
@@ -3256,14 +3433,14 @@ handle_pad_block (GstPad * pad)
   } else {
     /* no callback, signal the thread that is doing a GCond wait
      * if any. */
-    GST_PAD_BLOCK_SIGNAL (pad);
+    GST_PAD_BLOCK_BROADCAST (pad);
   }
 
   /* OBJECT_LOCK could have been released when we did the callback, which
    * then could have made the pad unblock so we need to check the blocking
    * condition again.   */
   while (GST_PAD_IS_BLOCKED (pad)) {
-    /* now we block the streaming thread. It can be unlocked when we 
+    /* now we block the streaming thread. It can be unlocked when we
      * deactivate the pad (which will also set the FLUSHING flag) or
      * when the pad is unblocked. A flushing event will also unblock
      * the pad after setting the FLUSHING flag. */
@@ -3271,14 +3448,11 @@ handle_pad_block (GstPad * pad)
         "Waiting to be unblocked or set flushing");
     GST_OBJECT_FLAG_SET (pad, GST_PAD_BLOCKING);
     GST_PAD_BLOCK_WAIT (pad);
+    GST_OBJECT_FLAG_UNSET (pad, GST_PAD_BLOCKING);
 
-    /* see if we got unlocked by a flush or not */
+    /* see if we got unblocked by a flush or not */
     if (GST_PAD_IS_FLUSHING (pad))
       goto flushing;
-
-    /* If we made it here we were unblocked and not flushing, remove the
-     * blocking flag now. */
-    GST_OBJECT_FLAG_UNSET (pad, GST_PAD_BLOCKING);
   }
 
   GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "got unblocked");
@@ -3294,7 +3468,7 @@ handle_pad_block (GstPad * pad)
     GST_OBJECT_LOCK (pad);
   } else {
     /* we need to signal the thread waiting on the GCond */
-    GST_PAD_BLOCK_SIGNAL (pad);
+    GST_PAD_BLOCK_BROADCAST (pad);
   }
 
   gst_object_unref (pad);
@@ -3331,7 +3505,7 @@ gst_pad_emit_have_data_signal (GstPad * pad, GstMiniObject * obj)
   g_value_set_boolean (&ret, TRUE);
   g_value_init (&args[0], GST_TYPE_PAD);
   g_value_set_object (&args[0], pad);
-  g_value_init (&args[1], GST_TYPE_MINI_OBJECT);        // G_TYPE_POINTER);
+  g_value_init (&args[1], GST_TYPE_MINI_OBJECT);
   gst_value_set_mini_object (&args[1], obj);
 
   if (GST_IS_EVENT (obj))
@@ -3459,8 +3633,8 @@ no_function:
  *
  * If the caps on @buffer are different from the current caps on @pad, this
  * function will call any setcaps function (see gst_pad_set_setcaps_function())
- * installed on @pad. If the new caps are not acceptable for @pad, this function
- * returns #GST_FLOW_NOT_NEGOTIATED.
+ * installed on @pad. If the new caps are not acceptable for @pad, this
+ * function returns #GST_FLOW_NOT_NEGOTIATED.
  *
  * The function proceeds calling the chain function installed on @pad (see
  * gst_pad_set_chain_function()) and the return value of that function is
@@ -3500,9 +3674,9 @@ gst_pad_chain (GstPad * pad, GstBuffer * buffer)
  * gst_pad_set_setcaps_function()). In case of failure to renegotiate the new
  * format, this function returns #GST_FLOW_NOT_NEGOTIATED.
  *
- * The function proceeds calling gst_pad_chain() on the peer pad and returns the
- * value from that function. If @pad has no peer, #GST_FLOW_NOT_LINKED will be
- * returned.
+ * The function proceeds calling gst_pad_chain() on the peer pad and returns
+ * the value from that function. If @pad has no peer, #GST_FLOW_NOT_LINKED will
+ * be returned.
  *
  * In all cases, success or failure, the caller loses its reference to @buffer
  * after calling this function.
@@ -3552,7 +3726,7 @@ gst_pad_push (GstPad * pad, GstBuffer * buffer)
   /* take ref to peer pad before releasing the lock */
   gst_object_ref (peer);
 
-  /* Before pushing the buffer to the peer pad, ensure that caps 
+  /* Before pushing the buffer to the peer pad, ensure that caps
    * are set on this pad */
   caps = GST_BUFFER_CAPS (buffer);
   caps_changed = caps && caps != GST_PAD_CAPS (pad);
@@ -3561,7 +3735,9 @@ gst_pad_push (GstPad * pad, GstBuffer * buffer)
 
   /* we got a new datatype from the pad, it had better handle it */
   if (G_UNLIKELY (caps_changed)) {
-    GST_DEBUG_OBJECT (pad, "caps changed to %p %" GST_PTR_FORMAT, caps, caps);
+    GST_DEBUG_OBJECT (pad,
+        "caps changed from %" GST_PTR_FORMAT " to %p %" GST_PTR_FORMAT,
+        GST_PAD_CAPS (pad), caps, caps);
     if (G_UNLIKELY (!gst_pad_configure_src (pad, caps, TRUE)))
       goto not_negotiated;
   }
@@ -3643,6 +3819,8 @@ gst_pad_check_pull_range (GstPad * pad)
   if (G_LIKELY ((checkgetrangefunc = peer->checkgetrangefunc) == NULL)) {
     /* FIXME, kindoff ghetto */
     ret = GST_PAD_GETRANGEFUNC (peer) != NULL;
+    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+        "no checkgetrangefunc, assuming %d", ret);
   } else {
     GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
         "calling checkgetrangefunc %s of peer pad %s:%s",
@@ -3687,6 +3865,12 @@ not_connected:
  * installed (see gst_pad_set_getrange_function()) this function returns
  * #GST_FLOW_NOT_SUPPORTED.
  *
+ * @buffer's caps must either be unset or the same as what is already
+ * configured on @pad. Renegotiation within a running pull-mode pipeline is not
+ * supported.
+ *
+ * This is a lowlevel function. Usualy gst_pad_pull_range() is used.
+ *
  * Returns: a #GstFlowReturn from the pad.
  *
  * MT safe.
@@ -3730,6 +3914,23 @@ gst_pad_get_range (GstPad * pad, guint64 offset, guint size,
 
   GST_PAD_STREAM_UNLOCK (pad);
 
+  if (G_LIKELY (ret == GST_FLOW_OK)) {
+    GstCaps *caps;
+    gboolean caps_changed;
+
+    GST_OBJECT_LOCK (pad);
+    /* Before pushing the buffer to the peer pad, ensure that caps
+     * are set on this pad */
+    caps = GST_BUFFER_CAPS (*buffer);
+    caps_changed = caps && caps != GST_PAD_CAPS (pad);
+    GST_OBJECT_UNLOCK (pad);
+
+    /* we got a new datatype from the pad not supported in a running pull-mode
+     * pipeline */
+    if (G_UNLIKELY (caps_changed))
+      goto not_negotiated;
+  }
+
   return ret;
 
   /* ERRORS */
@@ -3758,6 +3959,24 @@ dropping:
     *buffer = NULL;
     return GST_FLOW_UNEXPECTED;
   }
+not_negotiated:
+  {
+    /* ideally we want to use the commented-out code, but currently demuxers
+     * and typefind do not follow part-negotiation.txt. When switching into
+     * pull mode, typefind should probably return the found caps from
+     * getcaps(), and demuxers should do the setcaps(). */
+
+#if 0
+    gst_buffer_unref (*buffer);
+    *buffer = NULL;
+    GST_CAT_WARNING_OBJECT (GST_CAT_SCHEDULING, pad,
+        "getrange returned buffer of different caps");
+    return GST_FLOW_NOT_NEGOTIATED;
+#endif
+    GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, pad,
+        "getrange returned buffer of different caps");
+    return ret;
+  }
 }
 
 
@@ -3768,9 +3987,9 @@ dropping:
  * @size: The length of the buffer
  * @buffer: a pointer to hold the #GstBuffer, returns GST_FLOW_ERROR if %NULL.
  *
- * Pulls a buffer from the peer pad. 
+ * Pulls a @buffer from the peer pad.
  *
- * This function will first trigger the pad block signal if it was 
+ * This function will first trigger the pad block signal if it was
  * installed.
  *
  * When @pad is not linked #GST_FLOW_NOT_LINKED is returned else this
@@ -3778,10 +3997,14 @@ dropping:
  * See gst_pad_get_range() for a list of return values and for the
  * semantics of the arguments of this function.
  *
+ * @buffer's caps must either be unset or the same as what is already
+ * configured on @pad. Renegotiation within a running pull-mode pipeline is not
+ * supported.
+ *
  * Returns: a #GstFlowReturn from the peer pad.
  * When this function returns #GST_FLOW_OK, @buffer will contain a valid
  * #GstBuffer that should be freed with gst_buffer_unref() after usage.
- * @buffer may not be used or freed when any other return value than 
+ * @buffer may not be used or freed when any other return value than
  * #GST_FLOW_OK is returned.
  *
  * MT safe.
@@ -3823,6 +4046,23 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
     if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT (*buffer)))
       goto dropping;
   }
+
+  if (G_LIKELY (ret == GST_FLOW_OK)) {
+    GstCaps *caps;
+    gboolean caps_changed;
+
+    GST_OBJECT_LOCK (pad);
+    /* Before pushing the buffer to the peer pad, ensure that caps
+     * are set on this pad */
+    caps = GST_BUFFER_CAPS (*buffer);
+    caps_changed = caps && caps != GST_PAD_CAPS (pad);
+    GST_OBJECT_UNLOCK (pad);
+
+    /* we got a new datatype on the pad, see if it can handle it */
+    if (G_UNLIKELY (caps_changed))
+      goto not_negotiated;
+  }
+
   return ret;
 
   /* ERROR recovery here */
@@ -3841,6 +4081,24 @@ dropping:
     *buffer = NULL;
     return GST_FLOW_UNEXPECTED;
   }
+not_negotiated:
+  {
+    /* ideally we want to use the commented-out code, but currently demuxers
+     * and typefind do not follow part-negotiation.txt. When switching into
+     * pull mode, typefind should probably return the found caps from
+     * getcaps(), and demuxers should do the setcaps(). */
+
+#if 0
+    gst_buffer_unref (*buffer);
+    *buffer = NULL;
+    GST_CAT_WARNING_OBJECT (GST_CAT_SCHEDULING, pad,
+        "pullrange returned buffer of different caps");
+    return GST_FLOW_NOT_NEGOTIATED;
+#endif
+    GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, pad,
+        "pullrange returned buffer of different caps");
+    return ret;
+  }
 }
 
 /**
@@ -3869,7 +4127,7 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
   g_return_val_if_fail (event != NULL, FALSE);
   g_return_val_if_fail (GST_IS_EVENT (event), FALSE);
 
-  GST_LOG_OBJECT (pad, "event:%s", GST_EVENT_TYPE_NAME (event));
+  GST_LOG_OBJECT (pad, "event: %s", GST_EVENT_TYPE_NAME (event));
 
   GST_OBJECT_LOCK (pad);
 
@@ -3880,24 +4138,22 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
     case GST_EVENT_FLUSH_START:
       GST_PAD_SET_FLUSHING (pad);
 
-      if (G_UNLIKELY (GST_PAD_IS_BLOCKING (pad))) {
+      if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) {
         /* flush start will have set the FLUSHING flag and will then
          * unlock all threads doing a GCond wait on the blocking pad. This
          * will typically unblock the STREAMING thread blocked on a pad. */
-        GST_PAD_BLOCK_SIGNAL (pad);
+        GST_LOG_OBJECT (pad, "Pad is blocked, not forwarding flush-start, "
+            "doing block signal.");
+        GST_PAD_BLOCK_BROADCAST (pad);
         goto flushed;
       }
       break;
     case GST_EVENT_FLUSH_STOP:
       GST_PAD_UNSET_FLUSHING (pad);
 
-      /* If pad was blocking on something when the pad received flush-start, the 
-       * BLOCKING flag was never cleared. we don't forward the flush-stop event
-       * either then but unset the blocking flag. */
-      if (G_UNLIKELY (GST_PAD_IS_BLOCKING (pad))) {
-        GST_OBJECT_FLAG_UNSET (pad, GST_PAD_BLOCKING);
-        GST_LOG_OBJECT (pad,
-            "Pad was previously blocking, not forwarding flush-stop");
+      /* if we are blocked, flush away the FLUSH_STOP event */
+      if (G_UNLIKELY (GST_PAD_IS_BLOCKED (pad))) {
+        GST_LOG_OBJECT (pad, "Pad is blocked, not forwarding flush-stop");
         goto flushed;
       }
       break;
@@ -3922,13 +4178,16 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
   if (peerpad == NULL)
     goto not_linked;
 
-  GST_LOG_OBJECT (pad, "sending event to peerpad %" GST_PTR_FORMAT, peerpad);
+  GST_LOG_OBJECT (pad, "sending event %s to peerpad %" GST_PTR_FORMAT,
+      GST_EVENT_TYPE_NAME (event), peerpad);
   gst_object_ref (peerpad);
   GST_OBJECT_UNLOCK (pad);
 
   result = gst_pad_send_event (peerpad, event);
 
-  GST_LOG_OBJECT (pad, "sent event to peerpad %" GST_PTR_FORMAT, peerpad);
+  /* Note: we gave away ownership of the event at this point */
+  GST_LOG_OBJECT (pad, "sent event to peerpad %" GST_PTR_FORMAT ", result %d",
+      peerpad, result);
   gst_object_unref (peerpad);
 
   return result;
@@ -3976,9 +4235,9 @@ flushed:
  * To find out whether an event type is upstream, downstream, or downstream and
  * serialized, see #GstEventTypeFlags, gst_event_type_get_flags(),
  * #GST_EVENT_IS_UPSTREAM, #GST_EVENT_IS_DOWNSTREAM, and
- * #GST_EVENT_IS_SERIALIZED. Note that in practice that an application or plugin
- * doesn't need to bother itself with this information; the core handles all
- * necessary locks and checks.
+ * #GST_EVENT_IS_SERIALIZED. Note that in practice that an application or
+ * plugin doesn't need to bother itself with this information; the core handles
+ * all necessary locks and checks.
  *
  * This function takes owership of the provided event so you should
  * gst_event_ref() it if you want to reuse the event after this call.
@@ -4073,6 +4332,8 @@ gst_pad_send_event (GstPad * pad, GstEvent * event)
   if (need_unlock)
     GST_PAD_STREAM_UNLOCK (pad);
 
+  GST_DEBUG_OBJECT (pad, "sent event, result %d", result);
+
   return result;
 
   /* ERROR handling */
@@ -4096,6 +4357,8 @@ no_function:
     g_warning ("pad %s:%s has no event handler, file a bug.",
         GST_DEBUG_PAD_NAME (pad));
     GST_OBJECT_UNLOCK (pad);
+    if (need_unlock)
+      GST_PAD_STREAM_UNLOCK (pad);
     gst_event_unref (event);
     return FALSE;
   }
@@ -4153,12 +4416,12 @@ gst_pad_get_element_private (GstPad * pad)
  * @func: the task function to call
  * @data: data passed to the task function
  *
- * Starts a task that repeadedly calls @func with @data. This function
- * is nostly used in the pad activation function to start the
- * dataflow. This function will automatically acquire the STREAM_LOCK of
- * the pad before calling @func.
+ * Starts a task that repeatedly calls @func with @data. This function
+ * is mostly used in pad activation functions to start the dataflow.
+ * The #GST_PAD_STREAM_LOCK of @pad will automatically be acquired
+ * before @func is called.
  *
- * Returns: a TRUE if the task could be started.
+ * Returns: a %TRUE if the task could be started.
  */
 gboolean
 gst_pad_start_task (GstPad * pad, GstTaskFunction func, gpointer data)
@@ -4188,8 +4451,9 @@ gst_pad_start_task (GstPad * pad, GstTaskFunction func, gpointer data)
  * gst_pad_pause_task:
  * @pad: the #GstPad to pause the task of
  *
- * Pause the task of @pad. This function will also make sure that the
- * function executed by the task will effectively stop.
+ * Pause the task of @pad. This function will also wait until the
+ * function executed by the task is finished if this function is not
+ * called from the task function.
  *
  * Returns: a TRUE if the task could be paused or FALSE when the pad
  * has no task.
@@ -4210,6 +4474,8 @@ gst_pad_pause_task (GstPad * pad)
   gst_task_pause (task);
   GST_OBJECT_UNLOCK (pad);
 
+  /* wait for task function to finish, this lock is recursive so it does nothing
+   * when the pause is called from the task itself */
   GST_PAD_STREAM_LOCK (pad);
   GST_PAD_STREAM_UNLOCK (pad);