--- /dev/null
+/* GStreamer
+ * Copyright (C) 2009 Axis Communications <dev-gstreamer at axis dot com>
+ * @author Jonas Holmberg <jonas dot holmberg at axis dot com>
+ *
+ * gstbufferlist.c: Buffer list
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:gstbufferlist
+ * @short_description: Grouped scatter data buffer type for data-passing
+ * @see_also: #GstPad, #GstMiniObject
+ *
+ * Buffer lists are units of grouped scatter/gather data transfer in
+ * GStreamer.
+ *
+ * Buffer lists are created with gst_buffer_list_new() and filled with data
+ * using a #GstBufferListIterator. The iterator has no current buffer; its
+ * cursor position lies between buffers, immediately before the buffer that
+ * would be returned by gst_buffer_list_iterator_next(). After iterating to the
+ * end of a group the iterator must be advanced to the next group by a call to
+ * gst_buffer_list_iterator_next_group() before any further calls to
+ * gst_buffer_list_iterator_next() can return buffers again. The cursor position
+ * of a newly created iterator lies before the first group; a call to
+ * gst_buffer_list_iterator_next_group() is necessary before calls to
+ * gst_buffer_list_iterator_next() can return buffers.
+ *
+ * <informalexample>
+ * <programlisting>
+ * +--- group0 ----------------------+--- group1 ------------+
+ * | buffer0 buffer1 buffer2 | buffer3 buffer4 |
+ * ^ ^ ^ ^ ^ ^ ^ ^
+ * Iterator positions
+ * </programlisting>
+ * </informalexample>
+ *
+ * The gst_buffer_list_iterator_remove(), gst_buffer_list_iterator_steal(),
+ * gst_buffer_list_iterator_take(), gst_buffer_list_iterator_do() and
+ * gst_buffer_list_iterator_do_data() functions are not defined in terms of the
+ * cursor position; they operate on the last element returned from
+ * gst_buffer_list_iterator_next().
+ *
+ * The basic use pattern of creating a buffer list with an iterator is as
+ * follows:
+ *
+ * <example>
+ * <title>Creating a buffer list</title>
+ * <programlisting>
+ * GstBufferList *list;
+ * GstBufferListIterator *it;
+ *
+ * list = gst_buffer_list_new ();
+ * it = gst_buffer_list_iterate (list);
+ * gst_buffer_list_iterator_add_group (it);
+ * gst_buffer_list_iterator_add (it, header1);
+ * gst_buffer_list_iterator_add (it, data1);
+ * gst_buffer_list_iterator_add_group (it);
+ * gst_buffer_list_iterator_add (it, header2);
+ * gst_buffer_list_iterator_add (it, data2);
+ * gst_buffer_list_iterator_add_group (it);
+ * gst_buffer_list_iterator_add (it, header3);
+ * gst_buffer_list_iterator_add (it, data3);
+ * ...
+ * gst_buffer_list_iterator_free (it);
+ * </programlisting>
+ * </example>
+ *
+ * The basic use pattern of iterating over a buffer list is as follows:
+ *
+ * <example>
+ * <title>Iterating a buffer list</title>
+ * <programlisting>
+ * GstBufferListIterator *it;
+ *
+ * it = gst_buffer_list_iterate (list);
+ * while (gst_buffer_list_iterator_next_group (it)) {
+ * while ((buffer = gst_buffer_list_iterator_next (it)) != NULL) {
+ * do_something_with_buffer (buffer);
+ * }
+ * }
+ * gst_buffer_list_iterator_free (it);
+ * </programlisting>
+ * </example>
+ *
+ * The basic use pattern of modifying a buffer in a list is as follows:
+ *
+ * <example>
+ * <title>Modifying the data of the first buffer in a list</title>
+ * <programlisting>
+ * GstBufferListIterator *it;
+ *
+ * list = gst_buffer_list_make_writable (list);
+ * it = gst_buffer_list_iterate (list);
+ * if (gst_buffer_list_iterator_next_group (it)) {
+ * GstBuffer *buf
+ *
+ * buf = gst_buffer_list_iterator_next (it);
+ * if (buf != NULL) {
+ * buf = gst_buffer_list_iterator_do (it,
+ * (GstBufferListDoFunction) gst_mini_object_make_writable);
+ * modify_data (GST_BUFFER_DATA (buf));
+ * }
+ * }
+ * gst_buffer_list_iterator_free (it);
+ * </programlisting>
+ * </example>
+ *
+ * Since: 0.10.24
+ */
+#include "gst_private.h"
+
+#include "gstbuffer.h"
+#include "gstbufferlist.h"
+
+#define GST_CAT_DEFAULT GST_CAT_BUFFER_LIST
+
+#define GROUP_START NULL
+static const gpointer STOLEN = "";
+
+/**
+ * GstBufferListIterator:
+ *
+ * Iterator for a #GstBufferList.
+ */
+struct _GstBufferListIterator
+{
+ GstBufferList *list;
+ GList *next;
+ GList *last_returned;
+};
+
+static GType _gst_buffer_list_type = 0;
+static GstMiniObjectClass *parent_class = NULL;
+
+void
+_gst_buffer_list_initialize (void)
+{
+ g_type_class_ref (gst_buffer_list_get_type ());
+}
+
+static void
+gst_buffer_list_init (GTypeInstance * instance, gpointer g_class)
+{
+ GstBufferList *list;
+
+ list = (GstBufferList *) instance;
+ list->buffers = NULL;
+
+ GST_LOG ("init %p", list);
+}
+
+static void
+gst_buffer_list_finalize (GstBufferList * list)
+{
+ GList *tmp;
+
+ g_return_if_fail (list != NULL);
+
+ GST_LOG ("finalize %p", list);
+
+ tmp = list->buffers;
+ while (tmp) {
+ if (tmp->data != GROUP_START && tmp->data != STOLEN) {
+ gst_buffer_unref (GST_BUFFER_CAST (tmp->data));
+ }
+ tmp = tmp->next;
+ }
+ g_list_free (list->buffers);
+
+ parent_class->finalize (GST_MINI_OBJECT_CAST (list));
+}
+
+static GstBufferList *
+_gst_buffer_list_copy (GstBufferList * list)
+{
+ GstBufferList *list_copy;
+ GList *tmp;
+
+ g_return_val_if_fail (list != NULL, NULL);
+
+ list_copy = gst_buffer_list_new ();
+
+ /* shallow copy of list and pointers */
+ list_copy->buffers = g_list_copy (list->buffers);
+
+ /* copy all buffers in the list */
+ tmp = list_copy->buffers;
+ while (tmp) {
+ if (tmp->data != GROUP_START && tmp->data != STOLEN) {
+ tmp->data = gst_buffer_ref (GST_BUFFER_CAST (tmp->data));
+ }
+ tmp = g_list_next (tmp);
+ }
+
+ return list_copy;
+}
+
+static void
+gst_buffer_list_class_init (gpointer g_class, gpointer class_data)
+{
+ GstBufferListClass *list_class = GST_BUFFER_LIST_CLASS (g_class);
+
+ parent_class = g_type_class_peek_parent (g_class);
+
+ list_class->mini_object_class.copy =
+ (GstMiniObjectCopyFunction) _gst_buffer_list_copy;
+ list_class->mini_object_class.finalize =
+ (GstMiniObjectFinalizeFunction) gst_buffer_list_finalize;
+}
+
+/**
+ * gst_buffer_list_new:
+ *
+ * Creates a new, empty #GstBufferList. The caller is responsible for unreffing
+ * the returned #GstBufferList.
+ *
+ * Returns: the new #GstBufferList. gst_buffer_list_unref() after usage.
+ */
+GstBufferList *
+gst_buffer_list_new (void)
+{
+ GstBufferList *list;
+
+ list = (GstBufferList *) gst_mini_object_new (_gst_buffer_list_type);
+
+ GST_LOG ("new %p", list);
+
+ return list;
+}
+
+/**
+ * gst_buffer_list_n_groups:
+ * @list: a #GstBufferList
+ *
+ * Returns the number of groups in @list.
+ *
+ * Returns: the number of groups in the buffer list
+ */
+guint
+gst_buffer_list_n_groups (GstBufferList * list)
+{
+ GList *tmp;
+ guint n;
+
+ g_return_val_if_fail (list != NULL, 0);
+
+ tmp = list->buffers;
+ n = 0;
+ while (tmp) {
+ if (tmp->data == GROUP_START) {
+ n++;
+ }
+ tmp = g_list_next (tmp);
+ }
+
+ return n;
+}
+
+GType
+gst_buffer_list_get_type (void)
+{
+ if (G_UNLIKELY (_gst_buffer_list_type == 0)) {
+ static const GTypeInfo buffer_list_info = {
+ sizeof (GstBufferListClass),
+ NULL,
+ NULL,
+ gst_buffer_list_class_init,
+ NULL,
+ NULL,
+ sizeof (GstBufferList),
+ 0,
+ gst_buffer_list_init,
+ NULL
+ };
+
+ _gst_buffer_list_type = g_type_register_static (GST_TYPE_MINI_OBJECT,
+ "GstBufferList", &buffer_list_info, 0);
+ }
+
+ return _gst_buffer_list_type;
+}
+
+/**
+ * gst_buffer_list_iterate:
+ * @list: a #GstBufferList
+ *
+ * Iterate the buffers in @list. The owner of the iterator must also be the
+ * owner of a reference to @list while the returned iterator is in use.
+ *
+ * Returns: a new #GstBufferListIterator of the buffers in @list.
+ * gst_buffer_list_iterator_free() after usage
+ */
+GstBufferListIterator *
+gst_buffer_list_iterate (GstBufferList * list)
+{
+ GstBufferListIterator *it;
+
+ g_return_val_if_fail (list != NULL, NULL);
+
+ it = g_slice_new (GstBufferListIterator);
+ it->list = list;
+ it->next = list->buffers;
+ it->last_returned = NULL;
+
+ return it;
+}
+
+/**
+ * gst_buffer_list_iterator_free:
+ * @it: the #GstBufferListIterator to free
+ *
+ * Free the iterator.
+ */
+void
+gst_buffer_list_iterator_free (GstBufferListIterator * it)
+{
+ g_return_if_fail (it != NULL);
+
+ g_slice_free (GstBufferListIterator, it);
+}
+
+/**
+ * gst_buffer_list_iterator_n_buffers:
+ * @it: a #GstBufferListIterator
+ *
+ * Returns the number of buffers left to iterate in the current group. I.e. the
+ * number of calls that can be made to gst_buffer_list_iterator_next() before
+ * it returns NULL.
+ *
+ * This function will not move the implicit cursor or in any other way affect
+ * the state of the iterator @it.
+ *
+ * Returns: the number of buffers left to iterate in the current group
+ */
+guint
+gst_buffer_list_iterator_n_buffers (const GstBufferListIterator * it)
+{
+ GList *tmp;
+ guint n;
+
+ g_return_val_if_fail (it != NULL, 0);
+
+ tmp = it->next;
+ n = 0;
+ while (tmp && tmp->data != GROUP_START) {
+ if (tmp->data != STOLEN) {
+ n++;
+ }
+ tmp = g_list_next (tmp);
+ }
+
+ return n;
+}
+
+/**
+ * gst_buffer_list_iterator_add:
+ * @it: a #GstBufferListIterator
+ * @buffer: a #GstBuffer
+ *
+ * Inserts @buffer into the #GstBufferList iterated with @it. The buffer is
+ * inserted into the current group, immediately before the buffer that would be
+ * returned by gst_buffer_list_iterator_next(). The buffer is inserted before
+ * the implicit cursor, a subsequent call to gst_buffer_list_iterator_next()
+ * will return the buffer after the inserted buffer, if any.
+ *
+ * This function takes ownership of @buffer.
+ */
+void
+gst_buffer_list_iterator_add (GstBufferListIterator * it, GstBuffer * buffer)
+{
+ g_return_if_fail (it != NULL);
+ g_return_if_fail (buffer != NULL);
+
+ /* adding before the first group start is not allowed */
+ g_return_if_fail (it->next != it->list->buffers);
+
+ /* cheap insert into the GList */
+ it->list->buffers = g_list_insert_before (it->list->buffers, it->next,
+ buffer);
+}
+
+/**
+ * gst_buffer_list_iterator_add_group:
+ * @it: a #GstBufferListIterator
+ *
+ * Inserts a new, empty group into the #GstBufferList iterated with @it. The
+ * group is inserted immediately before the group that would be returned by
+ * gst_buffer_list_iterator_next_group(). A subsequent call to
+ * gst_buffer_list_iterator_next_group() will advance the iterator to the group
+ * after the inserted group, if any.
+ */
+void
+gst_buffer_list_iterator_add_group (GstBufferListIterator * it)
+{
+ g_return_if_fail (it != NULL);
+
+ /* advance iterator to next group start */
+ while (it->next != NULL && it->next->data != GROUP_START) {
+ it->next = g_list_next (it->next);
+ }
+
+ /* cheap insert of a group start into the GList */
+ it->list->buffers = g_list_insert_before (it->list->buffers, it->next,
+ GROUP_START);
+}
+
+/**
+ * gst_buffer_list_iterator_next:
+ * @it: a #GstBufferListIterator
+ *
+ * Returns the next buffer in the list iterated with @it. If the iterator is at
+ * the end of a group, NULL will be returned. This function may be called
+ * repeatedly to iterate through the current group.
+ *
+ * The caller will not get a new ref to the returned #GstBuffer and must not
+ * unref it.
+ *
+ * Returns: the next buffer in the current group of the buffer list, or NULL
+ */
+GstBuffer *
+gst_buffer_list_iterator_next (GstBufferListIterator * it)
+{
+ GstBuffer *buffer;
+
+ g_return_val_if_fail (it != NULL, NULL);
+
+ while (it->next != NULL && it->next->data != GROUP_START &&
+ it->next->data == STOLEN) {
+ it->next = g_list_next (it->next);
+ }
+
+ if (it->next == NULL || it->next->data == GROUP_START) {
+ goto no_buffer;
+ }
+
+ buffer = GST_BUFFER_CAST (it->next->data);
+
+ it->last_returned = it->next;
+ it->next = g_list_next (it->next);
+
+ return buffer;
+
+no_buffer:
+ it->last_returned = NULL;
+
+ return NULL;
+}
+
+/**
+ * gst_buffer_list_iterator_next_group:
+ * @it: a #GstBufferListIterator
+ *
+ * Advance the iterator @it to the first buffer in the next group. If the
+ * iterator is at the last group, FALSE will be returned. This function may be
+ * called repeatedly to iterate through the groups in a buffer list.
+ *
+ * Returns: TRUE if the iterator could be advanced to the next group, FALSE if
+ * the iterator was already at the last group
+ */
+gboolean
+gst_buffer_list_iterator_next_group (GstBufferListIterator * it)
+{
+ g_return_val_if_fail (it != NULL, FALSE);
+
+ /* advance iterator to next group start */
+ while (it->next != NULL && it->next->data != GROUP_START) {
+ it->next = g_list_next (it->next);
+ }
+
+ if (it->next) {
+ /* move one step beyond the group start */
+ it->next = g_list_next (it->next);
+ }
+
+ it->last_returned = NULL;
+
+ return (it->next != NULL);
+}
+
+/**
+ * gst_buffer_list_iterator_remove:
+ * @it: a #GstBufferListIterator
+ *
+ * Removes the last buffer returned by gst_buffer_list_iterator_next() from
+ * the #GstBufferList iterated with @it. gst_buffer_list_iterator_next() must
+ * have been called on @it before this function is called. This function can
+ * only be called once per call to gst_buffer_list_iterator_next().
+ *
+ * The removed buffer is unreffed.
+ */
+void
+gst_buffer_list_iterator_remove (GstBufferListIterator * it)
+{
+ g_return_if_fail (it != NULL);
+ g_return_if_fail (it->last_returned != NULL);
+ g_assert (it->last_returned->data != GROUP_START);
+
+ if (it->last_returned->data != STOLEN) {
+ gst_buffer_unref (it->last_returned->data);
+ }
+ it->list->buffers = g_list_delete_link (it->list->buffers, it->last_returned);
+ it->last_returned = NULL;
+}
+
+/**
+ * gst_buffer_list_iterator_take:
+ * @it: a #GstBufferListIterator
+ * @buffer: a #GstBuffer
+ *
+ * Replaces the last buffer returned by gst_buffer_list_iterator_next() with
+ * @buffer in the #GstBufferList iterated with @it and takes ownership of
+ * @buffer. gst_buffer_list_iterator_next() must have been called on @it before
+ * this function is called. gst_buffer_list_iterator_remove() must not have been
+ * called since the last call to gst_buffer_list_iterator_next().
+ *
+ * This function unrefs the replaced buffer if it has not been stolen with
+ * gst_buffer_list_iterator_steal() and takes ownership of @buffer (i.e. the
+ * refcount of @buffer is not increased).
+ */
+void
+gst_buffer_list_iterator_take (GstBufferListIterator * it, GstBuffer * buffer)
+{
+ g_return_if_fail (it != NULL);
+ g_return_if_fail (it->last_returned != NULL);
+ g_return_if_fail (buffer != NULL);
+ g_assert (it->last_returned->data != GROUP_START);
+
+ if (it->last_returned->data != STOLEN) {
+ gst_buffer_unref (it->last_returned->data);
+ }
+ it->last_returned->data = buffer;
+}
+
+/**
+ * gst_buffer_list_iterator_steal:
+ * @it: a #GstBufferListIterator
+ *
+ * Returns the last buffer returned by gst_buffer_list_iterator_next() without
+ * modifying the refcount of the buffer.
+ *
+ * Returns: the last buffer returned by gst_buffer_list_iterator_next()
+ */
+GstBuffer *
+gst_buffer_list_iterator_steal (GstBufferListIterator * it)
+{
+ GstBuffer *buffer;
+
+ g_return_val_if_fail (it != NULL, NULL);
+ g_return_val_if_fail (it->last_returned != NULL, NULL);
+ g_return_val_if_fail (it->last_returned->data != STOLEN, NULL);
+ g_assert (it->last_returned->data != GROUP_START);
+
+ buffer = it->last_returned->data;
+ it->last_returned->data = STOLEN;
+
+ return buffer;
+}
+
+/**
+ * gst_buffer_list_iterator_do_data:
+ * @it: a #GstBufferListIterator
+ * @do_func: the function to be called
+ * @data: the gpointer to optional user data.
+ * @data_notify: function to be called when @data is no longer used
+ *
+ * Calls the given function for the last buffer returned by
+ * gst_buffer_list_iterator_next(). gst_buffer_list_iterator_next() must have
+ * been called on @it before this function is called.
+ * gst_buffer_list_iterator_remove() and gst_buffer_list_iterator_steal() must
+ * not have been called since the last call to gst_buffer_list_iterator_next().
+ *
+ * See #GstBufferListDoFunction for more details.
+ *
+ * The @data_notify function is called after @do_func has returned, before this
+ * function returns, usually used to free @data.
+ *
+ * Returns: the return value from @do_func
+ */
+GstBuffer *
+gst_buffer_list_iterator_do_data (GstBufferListIterator * it,
+ GstBufferListDoDataFunction do_func, gpointer data,
+ GDestroyNotify data_notify)
+{
+ GstBuffer *buffer;
+
+ g_return_val_if_fail (it != NULL, NULL);
+ g_return_val_if_fail (it->last_returned != NULL, NULL);
+ g_return_val_if_fail (it->last_returned->data != STOLEN, NULL);
+ g_return_val_if_fail (do_func != NULL, NULL);
+ g_return_val_if_fail (gst_buffer_list_is_writable (it->list), NULL);
+ g_assert (it->last_returned->data != GROUP_START);
+
+ buffer = gst_buffer_list_iterator_steal (it);
+ buffer = do_func (buffer, data);
+ if (buffer == NULL) {
+ gst_buffer_list_iterator_remove (it);
+ } else {
+ gst_buffer_list_iterator_take (it, buffer);
+ }
+
+ if (data_notify != NULL) {
+ data_notify (data);
+ }
+
+ return buffer;
+}
+
+static GstBuffer *
+do_func_no_data (GstBuffer * buffer, GstBufferListDoFunction do_func)
+{
+ return do_func (buffer);
+}
+
+/**
+ * gst_buffer_list_iterator_do:
+ * @it: a #GstBufferListIterator
+ * @do_func: the function to be called
+ *
+ * Calls the given function for the last buffer returned by
+ * gst_buffer_list_iterator_next(). gst_buffer_list_iterator_next() must have
+ * been called on @it before this function is called.
+ * gst_buffer_list_iterator_remove() or gst_buffer_list_iterator_steal() must
+ * not have been called since the last call to gst_buffer_list_iterator_next().
+ *
+ * See #GstBufferListDoFunction for more details.
+ *
+ * Returns: the return value from @do_func
+ */
+GstBuffer *
+gst_buffer_list_iterator_do (GstBufferListIterator * it,
+ GstBufferListDoFunction do_func)
+{
+ g_return_val_if_fail (it != NULL, NULL);
+ g_return_val_if_fail (it->last_returned != NULL, NULL);
+ g_return_val_if_fail (it->last_returned->data != STOLEN, NULL);
+ g_return_val_if_fail (do_func != NULL, NULL);
+ g_return_val_if_fail (gst_buffer_list_is_writable (it->list), NULL);
+ g_assert (it->last_returned->data != GROUP_START);
+
+ return gst_buffer_list_iterator_do_data (it,
+ (GstBufferListDoDataFunction) do_func_no_data, do_func, NULL);
+}
+
+/**
+ * gst_buffer_list_iterator_merge_group:
+ * @it: a #GstBufferListIterator
+ *
+ * Merge a buffer list group into a normal #GstBuffer by copying its metadata
+ * and memcpying its data into consecutive memory. All buffers in the current
+ * group after the implicit cursor will be merged into one new buffer. The
+ * metadata of the new buffer will be a copy of the metadata of the buffer that
+ * would be returned by gst_buffer_list_iterator_next(). If there is no buffer
+ * in the current group after the implicit cursor, NULL will be returned.
+ *
+ * This function will not move the implicit cursor or in any other way affect
+ * the state of the iterator @it or the list.
+ *
+ * Returns: a new #GstBuffer, gst_buffer_unref() after usage, or NULL
+ */
+GstBuffer *
+gst_buffer_list_iterator_merge_group (const GstBufferListIterator * it)
+{
+ GList *tmp;
+ guint size;
+ GstBuffer *buf;
+ guint8 *ptr;
+
+ g_return_val_if_fail (it != NULL, NULL);
+
+ /* calculate size of merged buffer */
+ size = 0;
+ tmp = it->next;
+ while (tmp && tmp->data != GROUP_START) {
+ if (tmp->data != STOLEN) {
+ size += GST_BUFFER_SIZE (tmp->data);
+ }
+ tmp = g_list_next (tmp);
+ }
+
+ if (size == 0) {
+ return NULL;
+ }
+
+ /* allocate a new buffer */
+ buf = gst_buffer_new_and_alloc (size);
+
+ /* copy metadata from the next buffer after the implicit cursor */
+ gst_buffer_copy_metadata (buf, GST_BUFFER_CAST (it->next->data),
+ GST_BUFFER_COPY_ALL);
+
+ /* copy data of all buffers before the next group start into the new buffer */
+ ptr = GST_BUFFER_DATA (buf);
+ tmp = it->next;
+ do {
+ if (tmp->data != STOLEN) {
+ memcpy (ptr, GST_BUFFER_DATA (tmp->data), GST_BUFFER_SIZE (tmp->data));
+ ptr += GST_BUFFER_SIZE (tmp->data);
+ }
+ tmp = g_list_next (tmp);
+ } while (tmp && tmp->data != GROUP_START);
+
+ return buf;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 2009 Axis Communications <dev-gstreamer at axis dot com>
+ * @author Jonas Holmberg <jonas dot holmberg at axis dot com>
+ *
+ * gstbufferlist.h: Header for GstBufferList object
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_BUFFER_LIST_H__
+#define __GST_BUFFER_LIST_H__
+
+#include <gst/gstbuffer.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_BUFFER_LIST (gst_buffer_list_get_type ())
+#define GST_IS_BUFFER_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_BUFFER_LIST))
+#define GST_IS_BUFFER_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_BUFFER_LIST))
+#define GST_BUFFER_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BUFFER_LIST, GstBufferListClass))
+#define GST_BUFFER_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_BUFFER_LIST, GstBufferList))
+#define GST_BUFFER_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_BUFFER_LIST, GstBufferListClass))
+#define GST_BUFFER_LIST_CAST(obj) ((GstBufferList *)obj)
+
+typedef struct _GstBufferList GstBufferList;
+typedef struct _GstBufferListClass GstBufferListClass;
+typedef struct _GstBufferListIterator GstBufferListIterator;
+
+/**
+ * GstBufferListDoFunction:
+ * @buffer: the #GstBuffer
+ *
+ * A function for accessing the last buffer returned by
+ * gst_buffer_list_iterator_next(). The function can leave @buffer in the list,
+ * replace @buffer in the list or remove @buffer from the list, depending on
+ * the return value. If the function returns NULL, @buffer will be removed from
+ * the list, otherwise @buffer will be replaced with the returned buffer.
+ *
+ * The last buffer returned by gst_buffer_list_iterator_next() will be replaced
+ * with the buffer returned from the function. The function takes ownership of
+ * @buffer and if a different value than @buffer is returned, @buffer must be
+ * unreffed. If NULL is returned, the buffer will be removed from the list. The
+ * list must be writable.
+ *
+ * Returns: the buffer to replace @buffer in the list, or NULL to remove @buffer
+ * from the list
+ */
+typedef GstBuffer* (*GstBufferListDoFunction) (GstBuffer * buffer);
+
+/**
+ * GstBufferListDoDataFunction:
+ * @buffer: the #GstBuffer
+ * @data: the gpointer to optional user data.
+ *
+ * A function for accessing the last buffer returned by
+ * gst_buffer_list_iterator_next(). The function can leave @buffer in the list,
+ * replace @buffer in the list or remove @buffer from the list, depending on
+ * the return value. If the function returns NULL, @buffer will be removed from
+ * the list, otherwise @buffer will be replaced with the returned buffer.
+ *
+ * The last buffer returned by gst_buffer_list_iterator_next() will be replaced
+ * with the buffer returned from the function. The function takes ownership of
+ * @buffer and if a different value than @buffer is returned, @buffer must be
+ * unreffed. If NULL is returned, the buffer will be removed from the list. The
+ * list must be writable.
+ *
+ * Returns: the buffer to replace @buffer in the list, or NULL to remove @buffer
+ * from the list
+ */
+typedef GstBuffer* (*GstBufferListDoDataFunction) (GstBuffer * buffer, gpointer data);
+
+/**
+ * GstBufferList:
+ * @mini_object: the parent structure
+ *
+ * List of grouped buffers.
+ */
+struct _GstBufferList {
+ GstMiniObject mini_object;
+
+ /*< private >*/
+ GList *buffers;
+
+ gpointer _gst_reserved[GST_PADDING];
+};
+
+struct _GstBufferListClass {
+ GstMiniObjectClass mini_object_class;
+};
+
+GType gst_buffer_list_get_type (void);
+
+/* allocation */
+GstBufferList *gst_buffer_list_new (void);
+
+/* refcounting */
+/**
+ * gst_buffer_list_ref:
+ * @list: a #GstBufferList
+ *
+ * Increases the refcount of the given buffer list by one.
+ *
+ * Note that the refcount affects the writeability of @list and its data, see
+ * gst_buffer_list_make_writable(). It is important to note that keeping
+ * additional references to GstBufferList instances can potentially increase
+ * the number of memcpy operations in a pipeline.
+ *
+ * Returns: @list
+ */
+#ifdef _FOOL_GTK_DOC_
+G_INLINE_FUNC GstBufferList * gst_buffer_list_ref (GstBufferList * list);
+#endif
+
+static inline GstBufferList *
+gst_buffer_list_ref (GstBufferList * list)
+{
+ return GST_BUFFER_LIST_CAST (gst_mini_object_ref (GST_MINI_OBJECT_CAST (
+ list)));
+}
+
+/**
+ * gst_buffer_list_unref:
+ * @list: a #GstBufferList
+ *
+ * Decreases the refcount of the buffer list. If the refcount reaches 0, the
+ * buffer list will be freed.
+ */
+#ifdef _FOOL_GTK_DOC_
+G_INLINE_FUNC void gst_buffer_list_unref (GstBufferList * list);
+#endif
+
+static inline void
+gst_buffer_list_unref (GstBufferList * list)
+{
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (list));
+}
+
+/* copy */
+/**
+ * gst_buffer_list_copy:
+ * @list: a #GstBufferList
+ *
+ * Create a shallow copy of the given buffer list. This will make a newly
+ * allocated copy of the source list with copies of buffer pointers. The
+ * refcount of buffers pointed to will be increased by one.
+ *
+ * Returns: a new copy of @list.
+ */
+#ifdef _FOOL_GTK_DOC_
+G_INLINE_FUNC GstBufferList * gst_buffer_list_copy (const GstBufferList * list);
+#endif
+
+static inline GstBufferList *
+gst_buffer_list_copy (const GstBufferList * list)
+{
+ return GST_BUFFER_LIST (gst_mini_object_copy (GST_MINI_OBJECT_CAST (list)));
+}
+
+/**
+ * gst_buffer_list_is_writable:
+ * @list: a #GstBufferList
+ *
+ * Tests if you can safely add buffers and groups into a buffer list.
+ */
+#define gst_buffer_list_is_writable(list) gst_mini_object_is_writable (GST_MINI_OBJECT_CAST (list))
+
+/**
+ * gst_buffer_list_make_writable:
+ * @list: a #GstBufferList
+ *
+ * Makes a writable buffer list from the given buffer list. If the source buffer
+ * list is already writable, this will simply return the same buffer list. A
+ * copy will otherwise be made using gst_buffer_list_copy().
+ */
+#define gst_buffer_list_make_writable(list) GST_BUFFER_LIST_CAST (gst_mini_object_make_writable (GST_MINI_OBJECT_CAST (list)))
+
+guint gst_buffer_list_n_groups (GstBufferList *list);
+
+/* iterator */
+GstBufferListIterator * gst_buffer_list_iterate (GstBufferList *list);
+void gst_buffer_list_iterator_free (GstBufferListIterator *it);
+
+guint gst_buffer_list_iterator_n_buffers (const GstBufferListIterator *it);
+GstBuffer * gst_buffer_list_iterator_next (GstBufferListIterator *it);
+gboolean gst_buffer_list_iterator_next_group (GstBufferListIterator *it);
+
+void gst_buffer_list_iterator_add (GstBufferListIterator *it, GstBuffer *buffer);
+void gst_buffer_list_iterator_add_group (GstBufferListIterator *it);
+void gst_buffer_list_iterator_remove (GstBufferListIterator *it);
+GstBuffer * gst_buffer_list_iterator_steal (GstBufferListIterator *it);
+void gst_buffer_list_iterator_take (GstBufferListIterator *it, GstBuffer *buffer);
+
+GstBuffer * gst_buffer_list_iterator_do (GstBufferListIterator *it, GstBufferListDoFunction do_func);
+GstBuffer * gst_buffer_list_iterator_do_data (GstBufferListIterator *it, GstBufferListDoDataFunction do_func,
+ gpointer data, GDestroyNotify data_notify);
+
+/* conversion */
+GstBuffer * gst_buffer_list_iterator_merge_group (const GstBufferListIterator *it);
+
+G_END_DECLS
+
+#endif /* __GST_BUFFER_LIST_H__ */