gst/gstpad.c: Only sanity-check the buffer size if requested_caps == buffer_caps...
[platform/upstream/gstreamer.git] / gst / gstpad.c
index 1d2a046..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);
@@ -367,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);
@@ -755,7 +765,7 @@ gst_pad_activate_pull (GstPad * pad, gboolean active)
     }
   } 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 */
   }
 
@@ -1439,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
@@ -1519,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.
@@ -2028,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.
@@ -2049,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;
@@ -2110,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);
@@ -2189,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)
@@ -2307,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:
@@ -2475,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.
@@ -2573,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.
  *
@@ -2647,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;
@@ -2680,25 +2706,32 @@ 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);
 
@@ -2720,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. */
   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:
@@ -2766,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;
+    }
+  }
 }
 
 /**
@@ -2791,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)
@@ -2818,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)
@@ -2911,10 +2973,19 @@ gst_pad_event_default_dispatch (GstPad * pad, GstEvent * event)
   GST_INFO_OBJECT (pad, "Sending event %p (%s) to all internally linked pads",
       event, GST_EVENT_TYPE_NAME (event));
 
-  result = (GST_PAD_DIRECTION (pad) == GST_PAD_SINK);
-
   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);
 
@@ -2926,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 */
@@ -3064,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.
  *
@@ -3117,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);
@@ -3153,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;
@@ -3240,19 +3365,19 @@ 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 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 useful way of
  *   dealing with the callback is to post a message to the main thread
@@ -3285,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);
@@ -3315,7 +3440,7 @@ handle_pad_block (GstPad * pad)
    * 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. */
@@ -3601,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);
@@ -3610,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;
   }
@@ -3792,7 +3919,7 @@ gst_pad_get_range (GstPad * pad, guint64 offset, guint size,
     gboolean caps_changed;
 
     GST_OBJECT_LOCK (pad);
-    /* 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);
@@ -3877,7 +4004,7 @@ not_negotiated:
  * 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.
@@ -3925,7 +4052,7 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
     gboolean caps_changed;
 
     GST_OBJECT_LOCK (pad);
-    /* 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);
@@ -4059,7 +4186,8 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
   result = gst_pad_send_event (peerpad, event);
 
   /* Note: we gave away ownership of the event at this point */
-  GST_LOG_OBJECT (pad, "sent event to peerpad %" GST_PTR_FORMAT, peerpad);
+  GST_LOG_OBJECT (pad, "sent event to peerpad %" GST_PTR_FORMAT ", result %d",
+      peerpad, result);
   gst_object_unref (peerpad);
 
   return result;
@@ -4204,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 */
@@ -4321,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.
@@ -4343,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);