2 * Copyright (C) 2009 Axis Communications <dev-gstreamer at axis dot com>
3 * @author Jonas Holmberg <jonas dot holmberg at axis dot com>
5 * gstbufferlist.c: Buffer list
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 * SECTION:gstbufferlist
25 * @short_description: Grouped scatter data buffer type for data-passing
26 * @see_also: #GstPad, #GstMiniObject
28 * Buffer lists are units of grouped scatter/gather data transfer in
31 * Buffer lists are created with gst_buffer_list_new() and filled with data
32 * using a #GstBufferListIterator. The iterator has no current buffer; its
33 * cursor position lies between buffers, immediately before the buffer that
34 * would be returned by gst_buffer_list_iterator_next(). After iterating to the
35 * end of a group the iterator must be advanced to the next group by a call to
36 * gst_buffer_list_iterator_next_group() before any further calls to
37 * gst_buffer_list_iterator_next() can return buffers again. The cursor position
38 * of a newly created iterator lies before the first group; a call to
39 * gst_buffer_list_iterator_next_group() is necessary before calls to
40 * gst_buffer_list_iterator_next() can return buffers.
44 * +--- group0 ----------------------+--- group1 ------------+
45 * | buffer0 buffer1 buffer2 | buffer3 buffer4 |
47 * Iterator positions between buffers
51 * The gst_buffer_list_iterator_remove(), gst_buffer_list_iterator_steal(),
52 * gst_buffer_list_iterator_take() and gst_buffer_list_iterator_do() functions
53 * are not defined in terms of the cursor position; they operate on the last
54 * element returned from gst_buffer_list_iterator_next().
56 * The basic use pattern of creating a buffer list with an iterator is as
60 * <title>Creating a buffer list</title>
62 * GstBufferList *list;
63 * GstBufferListIterator *it;
65 * list = gst_buffer_list_new ();
66 * it = gst_buffer_list_iterate (list);
67 * gst_buffer_list_iterator_add_group (it);
68 * gst_buffer_list_iterator_add (it, header1);
69 * gst_buffer_list_iterator_add (it, data1);
70 * gst_buffer_list_iterator_add_group (it);
71 * gst_buffer_list_iterator_add (it, header2);
72 * gst_buffer_list_iterator_add (it, data2);
73 * gst_buffer_list_iterator_add_group (it);
74 * gst_buffer_list_iterator_add (it, header3);
75 * gst_buffer_list_iterator_add (it, data3);
77 * gst_buffer_list_iterator_free (it);
81 * The basic use pattern of iterating over a buffer list is as follows:
84 * <title>Iterating a buffer list</title>
86 * GstBufferListIterator *it;
88 * it = gst_buffer_list_iterate (list);
89 * while (gst_buffer_list_iterator_next_group (it)) {
90 * while ((buffer = gst_buffer_list_iterator_next (it)) != NULL) {
91 * do_something_with_buffer (buffer);
94 * gst_buffer_list_iterator_free (it);
98 * The basic use pattern of modifying a buffer in a list is as follows:
101 * <title>Modifying the data of the first buffer in a list</title>
103 * GstBufferListIterator *it;
105 * list = gst_buffer_list_make_writable (list);
106 * it = gst_buffer_list_iterate (list);
107 * if (gst_buffer_list_iterator_next_group (it)) {
110 * buf = gst_buffer_list_iterator_next (it);
112 * buf = gst_buffer_list_iterator_do (it,
113 * (GstBufferListDoFunction) gst_mini_object_make_writable, NULL);
114 * modify_data (GST_BUFFER_DATA (buf));
117 * gst_buffer_list_iterator_free (it);
123 #include "gst_private.h"
125 #include "gstbuffer.h"
126 #include "gstbufferlist.h"
128 #define GST_CAT_DEFAULT GST_CAT_BUFFER_LIST
130 #define GROUP_START NULL
131 static const gpointer STOLEN = "";
135 * @mini_object: the parent structure
137 * Opaque list of grouped buffers.
141 struct _GstBufferList
143 GstMiniObject mini_object;
148 struct _GstBufferListClass
150 GstMiniObjectClass mini_object_class;
154 * GstBufferListIterator:
156 * Opaque iterator for a #GstBufferList.
160 struct _GstBufferListIterator
164 GList *last_returned;
167 static GType _gst_buffer_list_type = 0;
168 static GstMiniObjectClass *parent_class = NULL;
171 _gst_buffer_list_initialize (void)
173 g_type_class_ref (gst_buffer_list_get_type ());
177 gst_buffer_list_init (GTypeInstance * instance, gpointer g_class)
181 list = (GstBufferList *) instance;
182 list->buffers = NULL;
184 GST_LOG ("init %p", list);
188 gst_buffer_list_finalize (GstBufferList * list)
192 g_return_if_fail (list != NULL);
194 GST_LOG ("finalize %p", list);
198 if (tmp->data != GROUP_START && tmp->data != STOLEN) {
199 gst_buffer_unref (GST_BUFFER_CAST (tmp->data));
203 g_list_free (list->buffers);
205 parent_class->finalize (GST_MINI_OBJECT_CAST (list));
208 static GstBufferList *
209 _gst_buffer_list_copy (GstBufferList * list)
211 GstBufferList *list_copy;
214 g_return_val_if_fail (list != NULL, NULL);
216 list_copy = gst_buffer_list_new ();
218 /* shallow copy of list and pointers */
219 list_copy->buffers = g_list_copy (list->buffers);
221 /* ref all buffers in the list */
222 tmp = list_copy->buffers;
224 if (tmp->data != GROUP_START && tmp->data != STOLEN) {
225 tmp->data = gst_buffer_ref (GST_BUFFER_CAST (tmp->data));
227 tmp = g_list_next (tmp);
234 gst_buffer_list_class_init (gpointer g_class, gpointer class_data)
236 GstBufferListClass *list_class = GST_BUFFER_LIST_CLASS (g_class);
238 parent_class = g_type_class_peek_parent (g_class);
240 list_class->mini_object_class.copy =
241 (GstMiniObjectCopyFunction) _gst_buffer_list_copy;
242 list_class->mini_object_class.finalize =
243 (GstMiniObjectFinalizeFunction) gst_buffer_list_finalize;
247 * gst_buffer_list_new:
249 * Creates a new, empty #GstBufferList. The caller is responsible for unreffing
250 * the returned #GstBufferList.
252 * Returns: the new #GstBufferList. gst_buffer_list_unref() after usage.
257 gst_buffer_list_new (void)
261 list = (GstBufferList *) gst_mini_object_new (_gst_buffer_list_type);
263 GST_LOG ("new %p", list);
269 * gst_buffer_list_n_groups:
270 * @list: a #GstBufferList
272 * Returns the number of groups in @list.
274 * Returns: the number of groups in the buffer list
279 gst_buffer_list_n_groups (GstBufferList * list)
284 g_return_val_if_fail (list != NULL, 0);
289 if (tmp->data == GROUP_START) {
292 tmp = g_list_next (tmp);
299 * gst_buffer_list_foreach:
300 * @list: a #GstBufferList
301 * @func: a #GstBufferListFunc to call
302 * @user_data: user data passed to @func
304 * Call @func with @data for each buffer in @list.
306 * @func can modify the passed buffer pointer or its contents. The return value
307 * of @func define if this function returns or if the remaining buffers in a
308 * group should be skipped.
313 gst_buffer_list_foreach (GstBufferList * list, GstBufferListFunc func,
318 GstBufferListItem res;
320 g_return_if_fail (list != NULL);
321 g_return_if_fail (func != NULL);
323 next = list->buffers;
329 next = g_list_next (tmp);
333 if (buffer == GROUP_START) {
337 } else if (buffer == STOLEN)
342 /* need to decrement the indices */
343 res = func (&buffer, group - 1, idx - 1, user_data);
345 if (G_UNLIKELY (buffer != tmp->data)) {
346 /* the function changed the buffer */
347 if (buffer == NULL) {
348 /* we were asked to remove the item */
349 list->buffers = g_list_delete_link (list->buffers, tmp);
352 /* change the buffer */
358 case GST_BUFFER_LIST_CONTINUE:
360 case GST_BUFFER_LIST_SKIP_GROUP:
361 while (next && next->data != GROUP_START)
362 next = g_list_next (next);
364 case GST_BUFFER_LIST_END:
371 * gst_buffer_list_get:
372 * @list: a #GstBufferList
374 * @idx: the index in @group
376 * Get the buffer at @idx in @group.
378 * Note that this function is not efficient for iterating over the entire list.
379 * Use an iterator or gst_buffer_list_foreach() instead.
381 * Returns: the buffer at @idx in @group or NULL when there is no buffer. The
382 * buffer remains valid as long as @list is valid.
387 gst_buffer_list_get (GstBufferList * list, guint group, guint idx)
392 g_return_val_if_fail (list != NULL, NULL);
397 if (tmp->data == GROUP_START) {
398 if (cgroup == group) {
399 /* we found the group */
400 tmp = g_list_next (tmp);
402 while (tmp && tmp->data != GROUP_START) {
403 if (tmp->data != STOLEN) {
405 return GST_BUFFER_CAST (tmp->data);
409 tmp = g_list_next (tmp);
418 tmp = g_list_next (tmp);
424 gst_buffer_list_get_type (void)
426 if (G_UNLIKELY (_gst_buffer_list_type == 0)) {
427 static const GTypeInfo buffer_list_info = {
428 sizeof (GstBufferListClass),
431 gst_buffer_list_class_init,
434 sizeof (GstBufferList),
436 gst_buffer_list_init,
440 _gst_buffer_list_type = g_type_register_static (GST_TYPE_MINI_OBJECT,
441 "GstBufferList", &buffer_list_info, 0);
444 return _gst_buffer_list_type;
448 * gst_buffer_list_iterate:
449 * @list: a #GstBufferList
451 * Iterate the buffers in @list. The owner of the iterator must also be the
452 * owner of a reference to @list while the returned iterator is in use.
454 * Returns: a new #GstBufferListIterator of the buffers in @list.
455 * gst_buffer_list_iterator_free() after usage
459 GstBufferListIterator *
460 gst_buffer_list_iterate (GstBufferList * list)
462 GstBufferListIterator *it;
464 g_return_val_if_fail (list != NULL, NULL);
466 it = g_slice_new (GstBufferListIterator);
468 it->next = list->buffers;
469 it->last_returned = NULL;
475 * gst_buffer_list_iterator_free:
476 * @it: the #GstBufferListIterator to free
483 gst_buffer_list_iterator_free (GstBufferListIterator * it)
485 g_return_if_fail (it != NULL);
487 g_slice_free (GstBufferListIterator, it);
491 * gst_buffer_list_iterator_n_buffers:
492 * @it: a #GstBufferListIterator
494 * Returns the number of buffers left to iterate in the current group. I.e. the
495 * number of calls that can be made to gst_buffer_list_iterator_next() before
498 * This function will not move the implicit cursor or in any other way affect
499 * the state of the iterator @it.
501 * Returns: the number of buffers left to iterate in the current group
506 gst_buffer_list_iterator_n_buffers (const GstBufferListIterator * it)
511 g_return_val_if_fail (it != NULL, 0);
515 while (tmp && tmp->data != GROUP_START) {
516 if (tmp->data != STOLEN) {
519 tmp = g_list_next (tmp);
526 * gst_buffer_list_iterator_add:
527 * @it: a #GstBufferListIterator
528 * @buffer: a #GstBuffer
530 * Inserts @buffer into the #GstBufferList iterated with @it. The buffer is
531 * inserted into the current group, immediately before the buffer that would be
532 * returned by gst_buffer_list_iterator_next(). The buffer is inserted before
533 * the implicit cursor, a subsequent call to gst_buffer_list_iterator_next()
534 * will return the buffer after the inserted buffer, if any.
536 * This function takes ownership of @buffer.
541 gst_buffer_list_iterator_add (GstBufferListIterator * it, GstBuffer * buffer)
543 g_return_if_fail (it != NULL);
544 g_return_if_fail (buffer != NULL);
546 /* adding before the first group start is not allowed */
547 g_return_if_fail (it->next != it->list->buffers);
549 /* cheap insert into the GList */
550 it->list->buffers = g_list_insert_before (it->list->buffers, it->next,
555 * gst_buffer_list_iterator_add_group:
556 * @it: a #GstBufferListIterator
558 * Inserts a new, empty group into the #GstBufferList iterated with @it. The
559 * group is inserted immediately before the group that would be returned by
560 * gst_buffer_list_iterator_next_group(). A subsequent call to
561 * gst_buffer_list_iterator_next_group() will advance the iterator to the group
562 * after the inserted group, if any.
567 gst_buffer_list_iterator_add_group (GstBufferListIterator * it)
569 g_return_if_fail (it != NULL);
571 /* advance iterator to next group start */
572 while (it->next != NULL && it->next->data != GROUP_START) {
573 it->next = g_list_next (it->next);
576 /* cheap insert of a group start into the GList */
577 it->list->buffers = g_list_insert_before (it->list->buffers, it->next,
582 * gst_buffer_list_iterator_next:
583 * @it: a #GstBufferListIterator
585 * Returns the next buffer in the list iterated with @it. If the iterator is at
586 * the end of a group, NULL will be returned. This function may be called
587 * repeatedly to iterate through the current group.
589 * The caller will not get a new ref to the returned #GstBuffer and must not
592 * Returns: the next buffer in the current group of the buffer list, or NULL
597 gst_buffer_list_iterator_next (GstBufferListIterator * it)
601 g_return_val_if_fail (it != NULL, NULL);
603 while (it->next != NULL && it->next->data != GROUP_START &&
604 it->next->data == STOLEN) {
605 it->next = g_list_next (it->next);
608 if (it->next == NULL || it->next->data == GROUP_START) {
612 buffer = GST_BUFFER_CAST (it->next->data);
614 it->last_returned = it->next;
615 it->next = g_list_next (it->next);
621 it->last_returned = NULL;
627 * gst_buffer_list_iterator_next_group:
628 * @it: a #GstBufferListIterator
630 * Advance the iterator @it to the first buffer in the next group. If the
631 * iterator is at the last group, FALSE will be returned. This function may be
632 * called repeatedly to iterate through the groups in a buffer list.
634 * Returns: TRUE if the iterator could be advanced to the next group, FALSE if
635 * the iterator was already at the last group
640 gst_buffer_list_iterator_next_group (GstBufferListIterator * it)
642 g_return_val_if_fail (it != NULL, FALSE);
644 /* advance iterator to next group start */
645 while (it->next != NULL && it->next->data != GROUP_START) {
646 it->next = g_list_next (it->next);
650 /* move one step beyond the group start */
651 it->next = g_list_next (it->next);
654 it->last_returned = NULL;
656 return (it->next != NULL);
660 * gst_buffer_list_iterator_remove:
661 * @it: a #GstBufferListIterator
663 * Removes the last buffer returned by gst_buffer_list_iterator_next() from
664 * the #GstBufferList iterated with @it. gst_buffer_list_iterator_next() must
665 * have been called on @it before this function is called. This function can
666 * only be called once per call to gst_buffer_list_iterator_next().
668 * The removed buffer is unreffed.
673 gst_buffer_list_iterator_remove (GstBufferListIterator * it)
675 g_return_if_fail (it != NULL);
676 g_return_if_fail (it->last_returned != NULL);
677 g_assert (it->last_returned->data != GROUP_START);
679 if (it->last_returned->data != STOLEN) {
680 gst_buffer_unref (it->last_returned->data);
682 it->list->buffers = g_list_delete_link (it->list->buffers, it->last_returned);
683 it->last_returned = NULL;
687 * gst_buffer_list_iterator_take:
688 * @it: a #GstBufferListIterator
689 * @buffer: a #GstBuffer
691 * Replaces the last buffer returned by gst_buffer_list_iterator_next() with
692 * @buffer in the #GstBufferList iterated with @it and takes ownership of
693 * @buffer. gst_buffer_list_iterator_next() must have been called on @it before
694 * this function is called. gst_buffer_list_iterator_remove() must not have been
695 * called since the last call to gst_buffer_list_iterator_next().
697 * This function unrefs the replaced buffer if it has not been stolen with
698 * gst_buffer_list_iterator_steal() and takes ownership of @buffer (i.e. the
699 * refcount of @buffer is not increased).
704 gst_buffer_list_iterator_take (GstBufferListIterator * it, GstBuffer * buffer)
706 g_return_if_fail (it != NULL);
707 g_return_if_fail (it->last_returned != NULL);
708 g_return_if_fail (buffer != NULL);
709 g_assert (it->last_returned->data != GROUP_START);
711 if (it->last_returned->data != STOLEN) {
712 gst_buffer_unref (it->last_returned->data);
714 it->last_returned->data = buffer;
718 * gst_buffer_list_iterator_steal:
719 * @it: a #GstBufferListIterator
721 * Returns the last buffer returned by gst_buffer_list_iterator_next() without
722 * modifying the refcount of the buffer.
724 * Returns: the last buffer returned by gst_buffer_list_iterator_next()
729 gst_buffer_list_iterator_steal (GstBufferListIterator * it)
733 g_return_val_if_fail (it != NULL, NULL);
734 g_return_val_if_fail (it->last_returned != NULL, NULL);
735 g_return_val_if_fail (it->last_returned->data != STOLEN, NULL);
736 g_assert (it->last_returned->data != GROUP_START);
738 buffer = it->last_returned->data;
739 it->last_returned->data = STOLEN;
745 * gst_buffer_list_iterator_do:
746 * @it: a #GstBufferListIterator
747 * @do_func: the function to be called
748 * @user_data: the gpointer to optional user data.
750 * Calls the given function for the last buffer returned by
751 * gst_buffer_list_iterator_next(). gst_buffer_list_iterator_next() must have
752 * been called on @it before this function is called.
753 * gst_buffer_list_iterator_remove() and gst_buffer_list_iterator_steal() must
754 * not have been called since the last call to gst_buffer_list_iterator_next().
756 * See #GstBufferListDoFunction for more details.
758 * Returns: the return value from @do_func
763 gst_buffer_list_iterator_do (GstBufferListIterator * it,
764 GstBufferListDoFunction do_func, gpointer user_data)
768 g_return_val_if_fail (it != NULL, NULL);
769 g_return_val_if_fail (it->last_returned != NULL, NULL);
770 g_return_val_if_fail (it->last_returned->data != STOLEN, NULL);
771 g_return_val_if_fail (do_func != NULL, NULL);
772 g_return_val_if_fail (gst_buffer_list_is_writable (it->list), NULL);
773 g_assert (it->last_returned->data != GROUP_START);
775 buffer = gst_buffer_list_iterator_steal (it);
776 buffer = do_func (buffer, user_data);
777 if (buffer == NULL) {
778 gst_buffer_list_iterator_remove (it);
780 gst_buffer_list_iterator_take (it, buffer);
787 * gst_buffer_list_iterator_merge_group:
788 * @it: a #GstBufferListIterator
790 * Merge a buffer list group into a normal #GstBuffer by copying its metadata
791 * and memcpying its data into consecutive memory. All buffers in the current
792 * group after the implicit cursor will be merged into one new buffer. The
793 * metadata of the new buffer will be a copy of the metadata of the buffer that
794 * would be returned by gst_buffer_list_iterator_next(). If there is no buffer
795 * in the current group after the implicit cursor, NULL will be returned.
797 * This function will not move the implicit cursor or in any other way affect
798 * the state of the iterator @it or the list.
800 * Returns: a new #GstBuffer, gst_buffer_unref() after usage, or NULL
805 gst_buffer_list_iterator_merge_group (const GstBufferListIterator * it)
812 g_return_val_if_fail (it != NULL, NULL);
814 /* calculate size of merged buffer */
817 while (tmp && tmp->data != GROUP_START) {
818 if (tmp->data != STOLEN) {
819 size += GST_BUFFER_SIZE (tmp->data);
821 tmp = g_list_next (tmp);
828 /* allocate a new buffer */
829 buf = gst_buffer_new_and_alloc (size);
831 /* copy metadata from the next buffer after the implicit cursor */
832 gst_buffer_copy_metadata (buf, GST_BUFFER_CAST (it->next->data),
833 GST_BUFFER_COPY_ALL);
835 /* copy data of all buffers before the next group start into the new buffer */
836 ptr = GST_BUFFER_DATA (buf);
839 if (tmp->data != STOLEN) {
840 memcpy (ptr, GST_BUFFER_DATA (tmp->data), GST_BUFFER_SIZE (tmp->data));
841 ptr += GST_BUFFER_SIZE (tmp->data);
843 tmp = g_list_next (tmp);
844 } while (tmp && tmp->data != GROUP_START);