diff --git a/gst/gstbufferlist.c b/gst/gstbufferlist.c new file mode 100644 index 0000000000..7bc2d9c42e --- /dev/null +++ b/gst/gstbufferlist.c @@ -0,0 +1,717 @@ +/* GStreamer + * Copyright (C) 2009 Axis Communications + * @author Jonas Holmberg + * + * 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. + * + * + * + * +--- group0 ----------------------+--- group1 ------------+ + * | buffer0 buffer1 buffer2 | buffer3 buffer4 | + * ^ ^ ^ ^ ^ ^ ^ ^ + * Iterator positions + * + * + * + * 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: + * + * + * Creating a buffer list + * + * 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); + * + * + * + * The basic use pattern of iterating over a buffer list is as follows: + * + * + * Iterating a buffer list + * + * 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); + * + * + * + * The basic use pattern of modifying a buffer in a list is as follows: + * + * + * Modifying the data of the first buffer in a list + * + * 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); + * + * + * + * 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; +} diff --git a/gst/gstbufferlist.h b/gst/gstbufferlist.h new file mode 100644 index 0000000000..c27f388ef3 --- /dev/null +++ b/gst/gstbufferlist.h @@ -0,0 +1,215 @@ +/* GStreamer + * Copyright (C) 2009 Axis Communications + * @author Jonas Holmberg + * + * 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 + +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__ */