}
/**
+ * 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.
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;
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;
/* 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 */
* 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);
}
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),
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
/* 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 */
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);
}
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.
*
#include <gst/gstobject.h>
#include <gst/gstbuffer.h>
+#include <gst/gstbufferlist.h>
#include <gst/gstcaps.h>
#include <gst/gstevent.h>
#include <gst/gstquery.h>
* 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.
* @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
/* ABI added */
/* iterate internal links */
GstPadIterIntLinkFunction iterintlinkfunc;
+ GstPadChainListFunction chainlistfunc;
/* free block_data */
GDestroyNotify block_destroy_data;
struct {
gboolean block_callback_called;
} ABI;
- gpointer _gst_reserved[GST_PADDING - 2];
+ gpointer _gst_reserved[GST_PADDING - 3];
} abidata;
};
#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)
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);
/* 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);
/* 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);
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;
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);