bufferlist: hook up the pad functions
authorJonas Holmberg <jonas.holmberg at axis.com>
Tue, 12 May 2009 11:10:55 +0000 (13:10 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 12 May 2009 13:18:53 +0000 (15:18 +0200)
Reuse buffer code for bufferlists. Not sure if this measurably impacts performance
for the simple buffer case, if it does after doing some benchmarks, we can
decouple it later.

Fixes #572285

docs/gst/gstreamer-sections.txt
gst/gstpad.c
gst/gstpad.h
tests/check/gst/gstpad.c
win32/common/libgstreamer.def

index 38aafbf..b4447d5 100644 (file)
@@ -134,6 +134,7 @@ gst_bus_sync_reply_get_type
 GstBusPrivate
 </SECTION>
 
+
 <SECTION>
 <FILE>gstbuffer</FILE>
 <TITLE>GstBuffer</TITLE>
@@ -1354,6 +1355,9 @@ GstPadBufferAllocFunction
 gst_pad_set_chain_function
 GstPadChainFunction
 
+gst_pad_set_chain_list_function
+GstPadChainListFunction
+
 gst_pad_set_checkgetrange_function
 GstPadCheckGetRangeFunction
 
@@ -1398,6 +1402,7 @@ GstPadActivateModeFunction
 
 gst_pad_push
 gst_pad_push_event
+gst_pad_push_list
 gst_pad_check_pull_range
 gst_pad_pull_range
 gst_pad_activate_pull
@@ -1441,6 +1446,7 @@ gst_pad_get_element_private
 
 <SUBSECTION Core>
 gst_pad_chain
+gst_pad_chain_list
 
 gst_pad_start_task
 gst_pad_pause_task
@@ -1516,6 +1522,7 @@ GST_PAD_ACTIVATEPULLFUNC
 GST_PAD_ACTIVATEPUSHFUNC
 GST_PAD_BUFFERALLOCFUNC
 GST_PAD_CHAINFUNC
+GST_PAD_CHAINLISTFUNC
 GST_PAD_CHECKGETRANGEFUNC
 GST_PAD_EVENTFUNC
 GST_PAD_FIXATECAPSFUNC
index d9398c3..724d087 100644 (file)
@@ -1235,6 +1235,29 @@ gst_pad_set_chain_function (GstPad * pad, GstPadChainFunction chain)
 }
 
 /**
+ * gst_pad_set_chain_list_function:
+ * @pad: a sink #GstPad.
+ * @chainlist: the #GstPadChainListFunction to set.
+ *
+ * Sets the given chain list function for the pad. The chainlist function is
+ * called to process a #GstBufferList input buffer list. See
+ * #GstPadChainListFunction for more details.
+ *
+ * Since: 0.10.24
+ */
+void
+gst_pad_set_chain_list_function (GstPad * pad,
+    GstPadChainListFunction chainlist)
+{
+  g_return_if_fail (GST_IS_PAD (pad));
+  g_return_if_fail (GST_PAD_IS_SINK (pad));
+
+  GST_PAD_CHAINLISTFUNC (pad) = chainlist;
+  GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "chainlistfunc set to %s",
+      GST_DEBUG_FUNCPTR_NAME (chainlist));
+}
+
+/**
  * gst_pad_set_getrange_function:
  * @pad: a source #GstPad.
  * @get: the #GstPadGetRangeFunction to set.
@@ -3925,15 +3948,48 @@ gst_pad_emit_have_data_signal (GstPad * pad, GstMiniObject * obj)
   return res;
 }
 
+static void
+gst_pad_data_unref (gboolean is_buffer, void *data)
+{
+  if (G_LIKELY (is_buffer)) {
+    gst_buffer_unref (data);
+  } else {
+    gst_buffer_list_unref (data);
+  }
+}
+
+static GstCaps *
+gst_pad_data_get_caps (gboolean is_buffer, void *data)
+{
+  GstCaps *caps;
+
+  if (G_LIKELY (is_buffer)) {
+    caps = GST_BUFFER_CAPS (data);
+  } else {
+    GstBufferListIterator *it;
+    GstBuffer *buf;
+
+    caps = NULL;
+    it = gst_buffer_list_iterate (GST_BUFFER_LIST_CAST (data));
+    if (gst_buffer_list_iterator_next_group (it)) {
+      buf = gst_buffer_list_iterator_next (it);
+      if (buf != NULL) {
+        caps = GST_BUFFER_CAPS (buf);
+      }
+    }
+    gst_buffer_list_iterator_free (it);
+  }
+  return caps;
+}
+
 /* this is the chain function that does not perform the additional argument
  * checking for that little extra speed.
  */
 static inline GstFlowReturn
-gst_pad_chain_unchecked (GstPad * pad, GstBuffer * buffer)
+gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data)
 {
   GstCaps *caps;
   gboolean caps_changed;
-  GstPadChainFunction chainfunc;
   GstFlowReturn ret;
   gboolean emit_signal;
 
@@ -3943,7 +3999,7 @@ gst_pad_chain_unchecked (GstPad * pad, GstBuffer * buffer)
   if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
     goto flushing;
 
-  caps = GST_BUFFER_CAPS (buffer);
+  caps = gst_pad_data_get_caps (is_buffer, data);
   caps_changed = caps && caps != GST_PAD_CAPS (pad);
 
   emit_signal = GST_PAD_DO_BUFFER_SIGNALS (pad) > 0;
@@ -3952,8 +4008,14 @@ gst_pad_chain_unchecked (GstPad * pad, GstBuffer * buffer)
   /* see if the signal should be emited, we emit before caps nego as
    * we might drop the buffer and do capsnego for nothing. */
   if (G_UNLIKELY (emit_signal)) {
-    if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT (buffer)))
-      goto dropping;
+    if (G_LIKELY (is_buffer)) {
+      if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT (data)))
+        goto dropping;
+    } else {
+      /* chain all groups in the buffer list one by one to avoid problems with
+       * buffer probes that push buffers or events */
+      goto chain_groups;
+    }
   }
 
   /* we got a new datatype on the pad, see if it can handle it */
@@ -3968,26 +4030,81 @@ gst_pad_chain_unchecked (GstPad * pad, GstBuffer * buffer)
    * the data to the wrong function. This is not really a
    * problem since functions are assigned at creation time
    * and don't change that often... */
-  if (G_UNLIKELY ((chainfunc = GST_PAD_CHAINFUNC (pad)) == NULL))
-    goto no_function;
+  if (G_LIKELY (is_buffer)) {
+    GstPadChainFunction chainfunc;
 
-  GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
-      "calling chainfunction &%s", GST_DEBUG_FUNCPTR_NAME (chainfunc));
+    if (G_UNLIKELY ((chainfunc = GST_PAD_CHAINFUNC (pad)) == NULL))
+      goto no_function;
 
-  ret = chainfunc (pad, buffer);
+    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+        "calling chainfunction &%s", GST_DEBUG_FUNCPTR_NAME (chainfunc));
 
-  GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
-      "called chainfunction &%s, returned %s",
-      GST_DEBUG_FUNCPTR_NAME (chainfunc), gst_flow_get_name (ret));
+    ret = chainfunc (pad, GST_BUFFER_CAST (data));
+
+    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+        "called chainfunction &%s, returned %s",
+        GST_DEBUG_FUNCPTR_NAME (chainfunc), gst_flow_get_name (ret));
+  } else {
+    GstPadChainListFunction chainlistfunc;
+
+    if (G_UNLIKELY ((chainlistfunc = GST_PAD_CHAINLISTFUNC (pad)) == NULL))
+      goto chain_groups;
+
+    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+        "calling chainlistfunction &%s",
+        GST_DEBUG_FUNCPTR_NAME (chainlistfunc));
+
+    ret = chainlistfunc (pad, GST_BUFFER_LIST_CAST (data));
+
+    GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+        "called chainlistfunction &%s, returned %s",
+        GST_DEBUG_FUNCPTR_NAME (chainlistfunc), gst_flow_get_name (ret));
+  }
 
   GST_PAD_STREAM_UNLOCK (pad);
 
   return ret;
 
+chain_groups:
+  {
+    GstBufferList *list;
+    GstBufferListIterator *it;
+    GstBuffer *group;
+
+    GST_PAD_STREAM_UNLOCK (pad);
+
+    GST_INFO_OBJECT (pad, "chaining each group in list as a merged buffer");
+
+    list = GST_BUFFER_LIST_CAST (data);
+    it = gst_buffer_list_iterate (list);
+
+    ret = GST_FLOW_OK;
+    if (gst_buffer_list_iterator_next_group (it)) {
+      do {
+        group = gst_buffer_list_iterator_merge_group (it);
+        if (group == NULL) {
+          group = gst_buffer_new ();
+          GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
+        } else {
+          GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining group");
+        }
+        ret = gst_pad_chain_data_unchecked (pad, TRUE, group);
+      } while (ret == GST_FLOW_OK && gst_buffer_list_iterator_next_group (it));
+    } else {
+      GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
+      ret = gst_pad_chain_data_unchecked (pad, TRUE, gst_buffer_new ());
+    }
+
+    gst_buffer_list_iterator_free (it);
+    gst_buffer_list_unref (list);
+
+    return ret;
+  }
+
   /* ERRORS */
 flushing:
   {
-    gst_buffer_unref (buffer);
+    gst_pad_data_unref (is_buffer, data);
     GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
         "pushing, but pad was flushing");
     GST_OBJECT_UNLOCK (pad);
@@ -3996,22 +4113,22 @@ flushing:
   }
 dropping:
   {
-    gst_buffer_unref (buffer);
+    gst_pad_data_unref (is_buffer, data);
     GST_DEBUG_OBJECT (pad, "Dropping buffer due to FALSE probe return");
     GST_PAD_STREAM_UNLOCK (pad);
     return GST_FLOW_OK;
   }
 not_negotiated:
   {
-    gst_buffer_unref (buffer);
+    gst_pad_data_unref (is_buffer, data);
     GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
-        "pushing buffer but pad did not accept");
+        "pushing data but pad did not accept");
     GST_PAD_STREAM_UNLOCK (pad);
     return GST_FLOW_NOT_NEGOTIATED;
   }
 no_function:
   {
-    gst_buffer_unref (buffer);
+    gst_pad_data_unref (is_buffer, data);
     GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
         "pushing, but not chainhandler");
     GST_ELEMENT_ERROR (GST_PAD_PARENT (pad), CORE, PAD, (NULL),
@@ -4055,48 +4172,55 @@ gst_pad_chain (GstPad * pad, GstBuffer * buffer)
   g_return_val_if_fail (GST_PAD_IS_SINK (pad), GST_FLOW_ERROR);
   g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
 
-  return gst_pad_chain_unchecked (pad, buffer);
+  return gst_pad_chain_data_unchecked (pad, TRUE, buffer);
 }
 
 /**
- * gst_pad_push:
- * @pad: a source #GstPad, returns #GST_FLOW_ERROR if not.
- * @buffer: the #GstBuffer to push returns GST_FLOW_ERROR if not.
+ * gst_pad_chain_list:
+ * @pad: a sink #GstPad, returns GST_FLOW_ERROR if not.
+ * @list: the #GstBufferList to send, return GST_FLOW_ERROR if not.
  *
- * Pushes a buffer to the peer of @pad.
+ * Chain a bufferlist to @pad.
  *
- * This function will call an installed pad block before triggering any
- * installed pad probes.
+ * The function returns #GST_FLOW_WRONG_STATE if the pad was flushing.
  *
- * If the caps on @buffer are different from the currently configured caps on
- * @pad, this function will call any installed setcaps function on @pad (see
- * gst_pad_set_setcaps_function()). In case of failure to renegotiate the new
- * format, this function returns #GST_FLOW_NOT_NEGOTIATED.
+ * If the caps on the first buffer of @list 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.
  *
- * 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 the chainlist function installed on @pad (see
+ * gst_pad_set_chain_list_function()) and the return value of that function is
+ * returned to the caller. #GST_FLOW_NOT_SUPPORTED is returned if @pad has no
+ * chainlist function.
  *
- * In all cases, success or failure, the caller loses its reference to @buffer
+ * In all cases, success or failure, the caller loses its reference to @list
  * after calling this function.
  *
- * Returns: a #GstFlowReturn from the peer pad.
+ * Returns: a #GstFlowReturn from the pad.
+ *
+ * Since: 0.10.24
  *
  * MT safe.
  */
 GstFlowReturn
-gst_pad_push (GstPad * pad, GstBuffer * buffer)
+gst_pad_chain_list (GstPad * pad, GstBufferList * list)
+{
+  g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
+  g_return_val_if_fail (GST_PAD_IS_SINK (pad), GST_FLOW_ERROR);
+  g_return_val_if_fail (GST_IS_BUFFER_LIST (list), GST_FLOW_ERROR);
+
+  return gst_pad_chain_data_unchecked (pad, FALSE, list);
+}
+
+static GstFlowReturn
+gst_pad_push_data (GstPad * pad, gboolean is_buffer, void *data)
 {
   GstPad *peer;
   GstFlowReturn ret;
-
   GstCaps *caps;
   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 (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
-
   GST_OBJECT_LOCK (pad);
 
   /* FIXME: this check can go away; pad_set_blocked could be implemented with
@@ -4111,25 +4235,29 @@ gst_pad_push (GstPad * pad, GstBuffer * buffer)
     /* unlock before emitting */
     GST_OBJECT_UNLOCK (pad);
 
-    /* if the signal handler returned FALSE, it means we should just drop the
-     * buffer */
-    if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT (buffer)))
-      goto dropped;
-
+    if (G_LIKELY (is_buffer)) {
+      /* if the signal handler returned FALSE, it means we should just drop the
+       * buffer */
+      if (!gst_pad_emit_have_data_signal (pad, GST_MINI_OBJECT (data)))
+        goto dropped;
+    } else {
+      /* push all buffers in the list */
+      goto push_groups;
+    }
     GST_OBJECT_LOCK (pad);
   }
 
   if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
     goto not_linked;
 
-  /* take ref to peer pad before releasing the lock */
-  gst_object_ref (peer);
-
   /* Before pushing the buffer to the peer pad, ensure that caps
    * are set on this pad */
-  caps = GST_BUFFER_CAPS (buffer);
+  caps = gst_pad_data_get_caps (is_buffer, data);
   caps_changed = caps && caps != GST_PAD_CAPS (pad);
 
+  /* take ref to peer pad before releasing the lock */
+  gst_object_ref (peer);
+
   GST_OBJECT_UNLOCK (pad);
 
   /* we got a new datatype from the pad, it had better handle it */
@@ -4141,29 +4269,63 @@ gst_pad_push (GstPad * pad, GstBuffer * buffer)
       goto not_negotiated;
   }
 
-  ret = gst_pad_chain_unchecked (peer, buffer);
+  ret = gst_pad_chain_data_unchecked (peer, is_buffer, data);
 
   gst_object_unref (peer);
 
   return ret;
 
+push_groups:
+  {
+    GstBufferList *list;
+    GstBufferListIterator *it;
+    GstBuffer *group;
+
+    GST_INFO_OBJECT (pad, "pushing each group in list as a merged buffer");
+
+    list = GST_BUFFER_LIST_CAST (data);
+    it = gst_buffer_list_iterate (list);
+
+    ret = GST_FLOW_OK;
+    if (gst_buffer_list_iterator_next_group (it)) {
+      do {
+        group = gst_buffer_list_iterator_merge_group (it);
+        if (group == NULL) {
+          group = gst_buffer_new ();
+          GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "pushing empty group");
+        } else {
+          GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "pushing group");
+        }
+        ret = gst_pad_push_data (pad, TRUE, group);
+      } while (ret == GST_FLOW_OK && gst_buffer_list_iterator_next_group (it));
+    } else {
+      GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "pushing empty group");
+      ret = gst_pad_push_data (pad, TRUE, gst_buffer_new ());
+    }
+
+    gst_buffer_list_iterator_free (it);
+    gst_buffer_list_unref (list);
+
+    return ret;
+  }
+
   /* ERROR recovery here */
 flushed:
   {
-    gst_buffer_unref (buffer);
+    gst_pad_data_unref (is_buffer, data);
     GST_DEBUG_OBJECT (pad, "pad block stopped by flush");
     GST_OBJECT_UNLOCK (pad);
     return ret;
   }
 dropped:
   {
-    gst_buffer_unref (buffer);
+    gst_pad_data_unref (is_buffer, data);
     GST_DEBUG_OBJECT (pad, "Dropping buffer due to FALSE probe return");
     return GST_FLOW_OK;
   }
 not_linked:
   {
-    gst_buffer_unref (buffer);
+    gst_pad_data_unref (is_buffer, data);
     GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
         "pushing, but it was not linked");
     GST_OBJECT_UNLOCK (pad);
@@ -4171,15 +4333,96 @@ not_linked:
   }
 not_negotiated:
   {
-    gst_buffer_unref (buffer);
+    gst_pad_data_unref (is_buffer, data);
     gst_object_unref (peer);
     GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, pad,
-        "element pushed buffer then refused to accept the caps");
+        "element pushed data then refused to accept the caps");
     return GST_FLOW_NOT_NEGOTIATED;
   }
 }
 
 /**
+ * gst_pad_push:
+ * @pad: a source #GstPad, returns #GST_FLOW_ERROR if not.
+ * @buffer: the #GstBuffer to push returns GST_FLOW_ERROR if not.
+ *
+ * Pushes a buffer to the peer of @pad.
+ *
+ * This function will call an installed pad block before triggering any
+ * installed pad probes.
+ *
+ * If the caps on @buffer are different from the currently configured caps on
+ * @pad, this function will call any installed setcaps function on @pad (see
+ * 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.
+ *
+ * In all cases, success or failure, the caller loses its reference to @buffer
+ * after calling this function.
+ *
+ * Returns: a #GstFlowReturn from the peer pad.
+ *
+ * MT safe.
+ */
+GstFlowReturn
+gst_pad_push (GstPad * pad, GstBuffer * buffer)
+{
+  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 (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
+
+  return gst_pad_push_data (pad, TRUE, buffer);
+}
+
+/**
+ * gst_pad_push_list:
+ * @pad: a source #GstPad, returns #GST_FLOW_ERROR if not.
+ * @list: the #GstBufferList to push returns GST_FLOW_ERROR if not.
+ *
+ * Pushes a buffer list to the peer of @pad.
+ *
+ * This function will call an installed pad block before triggering any
+ * installed pad probes.
+ *
+ * If the caps on the first buffer in the first group of @list are different
+ * from the currently configured caps on @pad, this function will call any
+ * installed setcaps function on @pad (see gst_pad_set_setcaps_function()). In
+ * case of failure to renegotiate the new format, this function returns
+ * #GST_FLOW_NOT_NEGOTIATED.
+ *
+ * If there are any probes installed on @pad every group of the buffer list
+ * will be merged into a normal #GstBuffer and pushed via gst_pad_push and the
+ * buffer list will be unreffed.
+ *
+ * The function proceeds calling the chain function on the peer pad and returns
+ * the value from that function. If @pad has no peer, #GST_FLOW_NOT_LINKED will
+ * be returned. If the peer pad does not have any installed chainlist function
+ * every group buffer of the list will be merged into a normal #GstBuffer and
+ * chained via gst_pad_chain().
+ *
+ * In all cases, success or failure, the caller loses its reference to @list
+ * after calling this function.
+ *
+ * Returns: a #GstFlowReturn from the peer pad.
+ *
+ * MT safe.
+ *
+ * Since: 0.10.24
+ */
+GstFlowReturn
+gst_pad_push_list (GstPad * pad, GstBufferList * list)
+{
+  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 (GST_IS_BUFFER_LIST (list), GST_FLOW_ERROR);
+
+  return gst_pad_push_data (pad, FALSE, list);
+}
+
+/**
  * gst_pad_check_pull_range:
  * @pad: a sink #GstPad.
  *
index 2f167ca..2b71939 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <gst/gstobject.h>
 #include <gst/gstbuffer.h>
+#include <gst/gstbufferlist.h>
 #include <gst/gstcaps.h>
 #include <gst/gstevent.h>
 #include <gst/gstquery.h>
@@ -230,6 +231,26 @@ typedef gboolean           (*GstPadActivateModeFunction)   (GstPad *pad, gboolean active);
  * Returns: #GST_FLOW_OK for success
  */
 typedef GstFlowReturn          (*GstPadChainFunction)          (GstPad *pad, GstBuffer *buffer);
+
+/**
+ * GstPadChainListFunction:
+ * @pad: the sink #GstPad that performed the chain.
+ * @list: the #GstBufferList that is chained, not %NULL.
+ *
+ * A function that will be called on sinkpads when chaining buffer lists.
+ * The function typically processes the data contained in the buffer list and
+ * either consumes the data or passes it on to the internally linked pad(s).
+ *
+ * The implementer of this function receives a refcount to @list and
+ * should gst_buffer_list_unref() when the list is no longer needed.
+ *
+ * When a chainlist function detects an error in the data stream, it must
+ * post an error on the bus and return an appropriate #GstFlowReturn value.
+ *
+ * Returns: #GST_FLOW_OK for success
+ */
+typedef GstFlowReturn          (*GstPadChainListFunction)      (GstPad *pad, GstBufferList *list);
+
 /**
  * GstPadGetRangeFunction:
  * @pad: the src #GstPad to perform the getrange on.
@@ -546,7 +567,8 @@ typedef struct _GstPadTemplate GstPadTemplate;
  * @unlinkfunc: function called when pad is unlinked
  * @peer: the pad this pad is linked to
  * @sched_private: private storage for the scheduler
- * @chainfunc: function to chain data to pad
+ * @chainfunc: function to chain buffer to pad
+ * @chainlistfunc: function to chain buffer list to pad
  * @checkgetrangefunc: function to check if pad can operate in pull mode
  * @getrangefunc: function to get a range of data from a pad
  * @eventfunc: function to send an event to a pad
@@ -629,6 +651,7 @@ struct _GstPad {
   /* ABI added */
   /* iterate internal links */
   GstPadIterIntLinkFunction     iterintlinkfunc;
+  GstPadChainListFunction       chainlistfunc;
 
   /* free block_data */
   GDestroyNotify block_destroy_data;
@@ -638,7 +661,7 @@ struct _GstPad {
     struct {
       gboolean                      block_callback_called;
     } ABI;
-    gpointer _gst_reserved[GST_PADDING - 2];
+    gpointer _gst_reserved[GST_PADDING - 3];
   } abidata;
 };
 
@@ -670,6 +693,7 @@ struct _GstPadClass {
 #define GST_PAD_ACTIVATEPUSHFUNC(pad)  (GST_PAD_CAST(pad)->activatepushfunc)
 #define GST_PAD_ACTIVATEPULLFUNC(pad)  (GST_PAD_CAST(pad)->activatepullfunc)
 #define GST_PAD_CHAINFUNC(pad)         (GST_PAD_CAST(pad)->chainfunc)
+#define GST_PAD_CHAINLISTFUNC(pad)     (GST_PAD_CAST(pad)->chainlistfunc)
 #define GST_PAD_CHECKGETRANGEFUNC(pad) (GST_PAD_CAST(pad)->checkgetrangefunc)
 #define GST_PAD_GETRANGEFUNC(pad)      (GST_PAD_CAST(pad)->getrangefunc)
 #define GST_PAD_EVENTFUNC(pad)         (GST_PAD_CAST(pad)->eventfunc)
@@ -840,6 +864,7 @@ void                        gst_pad_set_activate_function           (GstPad *pad, GstPadActivateFunction activ
 void                   gst_pad_set_activatepull_function       (GstPad *pad, GstPadActivateModeFunction activatepull);
 void                   gst_pad_set_activatepush_function       (GstPad *pad, GstPadActivateModeFunction activatepush);
 void                   gst_pad_set_chain_function              (GstPad *pad, GstPadChainFunction chain);
+void                   gst_pad_set_chain_list_function (GstPad *pad, GstPadChainListFunction chainlist);
 void                   gst_pad_set_getrange_function           (GstPad *pad, GstPadGetRangeFunction get);
 void                   gst_pad_set_checkgetrange_function      (GstPad *pad, GstPadCheckGetRangeFunction check);
 void                   gst_pad_set_event_function              (GstPad *pad, GstPadEventFunction event);
@@ -878,6 +903,7 @@ GstCaps *           gst_pad_get_negotiated_caps             (GstPad * pad);
 
 /* data passing functions to peer */
 GstFlowReturn          gst_pad_push                            (GstPad *pad, GstBuffer *buffer);
+GstFlowReturn          gst_pad_push_list                       (GstPad *pad, GstBufferList *list);
 gboolean               gst_pad_check_pull_range                (GstPad *pad);
 GstFlowReturn          gst_pad_pull_range                      (GstPad *pad, guint64 offset, guint size,
                                                                 GstBuffer **buffer);
@@ -886,6 +912,7 @@ gboolean            gst_pad_event_default                   (GstPad *pad, GstEvent *event);
 
 /* data passing functions on pad */
 GstFlowReturn          gst_pad_chain                           (GstPad *pad, GstBuffer *buffer);
+GstFlowReturn          gst_pad_chain_list                      (GstPad *pad, GstBufferList *list);
 GstFlowReturn          gst_pad_get_range                       (GstPad *pad, guint64 offset, guint size,
                                                                 GstBuffer **buffer);
 gboolean               gst_pad_send_event                      (GstPad *pad, GstEvent *event);
index 2c40379..a3a6f67 100644 (file)
@@ -399,6 +399,87 @@ GST_START_TEST (test_push_linked)
 
 GST_END_TEST;
 
+static GstBuffer *
+buffer_from_string (gchar * str)
+{
+  guint size;
+  GstBuffer *buf;
+
+  size = strlen (str);
+  buf = gst_buffer_new_and_alloc (size);
+  memcpy (GST_BUFFER_DATA (buf), str, size);
+  GST_BUFFER_SIZE (buf) = size;
+
+  return buf;
+}
+
+GST_START_TEST (test_push_buffer_list_compat)
+{
+  GstPad *src, *sink;
+  GstPadLinkReturn plr;
+  GstCaps *caps;
+  GstBufferList *list;
+  GstBufferListIterator *it;
+  GstBuffer *buffer;
+
+  /* setup */
+  sink = gst_pad_new ("sink", GST_PAD_SINK);
+  fail_if (sink == NULL);
+  gst_pad_set_chain_function (sink, gst_check_chain_func);
+  /* leave chainlistfunc unset */
+
+  src = gst_pad_new ("src", GST_PAD_SRC);
+  fail_if (src == NULL);
+
+  caps = gst_caps_from_string ("foo/bar");
+
+  gst_pad_set_caps (src, caps);
+  gst_pad_set_caps (sink, caps);
+
+  plr = gst_pad_link (src, sink);
+  fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
+
+  list = gst_buffer_list_new ();
+
+  /* activate pads */
+  gst_pad_set_active (src, TRUE);
+  gst_pad_set_active (sink, TRUE);
+
+  /* test */
+  /* adding to a buffer list will drop the ref to the buffer */
+  it = gst_buffer_list_iterate (list);
+  gst_buffer_list_iterator_add_group (it);
+  gst_buffer_list_iterator_add (it, buffer_from_string ("List"));
+  gst_buffer_list_iterator_add (it, buffer_from_string ("Group"));
+  gst_buffer_list_iterator_add_group (it);
+  gst_buffer_list_iterator_add (it, buffer_from_string ("Another"));
+  gst_buffer_list_iterator_add (it, buffer_from_string ("List"));
+  gst_buffer_list_iterator_add (it, buffer_from_string ("Group"));
+  gst_buffer_list_iterator_free (it);
+  fail_unless (gst_pad_push_list (src, list) == GST_FLOW_OK);
+  fail_unless_equals_int (g_list_length (buffers), 2);
+  buffer = GST_BUFFER (buffers->data);
+  ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
+  fail_unless (memcmp (GST_BUFFER_DATA (buffer), "ListGroup", 9) == 0);
+  gst_buffer_unref (buffer);
+  buffers = g_list_delete_link (buffers, buffers);
+  buffer = GST_BUFFER (buffers->data);
+  ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
+  fail_unless (memcmp (GST_BUFFER_DATA (buffer), "AnotherListGroup", 16) == 0);
+  gst_buffer_unref (buffer);
+  buffers = g_list_delete_link (buffers, buffers);
+  fail_unless (buffers == NULL);
+
+  /* teardown */
+  gst_pad_unlink (src, sink);
+  gst_object_unref (src);
+  gst_object_unref (sink);
+  ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
+  gst_caps_unref (caps);
+}
+
+GST_END_TEST;
+
 GST_START_TEST (test_flowreturn)
 {
   GstFlowReturn ret;
@@ -904,6 +985,7 @@ gst_pad_suite (void)
   tcase_add_test (tc_chain, test_name_is_valid);
   tcase_add_test (tc_chain, test_push_unlinked);
   tcase_add_test (tc_chain, test_push_linked);
+  tcase_add_test (tc_chain, test_push_buffer_list_compat);
   tcase_add_test (tc_chain, test_flowreturn);
   tcase_add_test (tc_chain, test_push_negotiation);
   tcase_add_test (tc_chain, test_src_unref_unlink);
index febcb4a..c2ef238 100644 (file)
@@ -556,6 +556,7 @@ EXPORTS
        gst_pad_alloc_buffer_and_set_caps
        gst_pad_can_link
        gst_pad_chain
+       gst_pad_chain_list
        gst_pad_check_pull_range
        gst_pad_direction_get_type
        gst_pad_dispatcher
@@ -600,6 +601,7 @@ EXPORTS
        gst_pad_pull_range
        gst_pad_push
        gst_pad_push_event
+       gst_pad_push_list
        gst_pad_query
        gst_pad_query_convert
        gst_pad_query_default
@@ -623,6 +625,7 @@ EXPORTS
        gst_pad_set_bufferalloc_function
        gst_pad_set_caps
        gst_pad_set_chain_function
+       gst_pad_set_chain_list_function
        gst_pad_set_checkgetrange_function
        gst_pad_set_element_private
        gst_pad_set_event_function