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 |
51 * The gst_buffer_list_iterator_remove(), gst_buffer_list_iterator_steal(),
52 * gst_buffer_list_iterator_take(), gst_buffer_list_iterator_do() and
53 * gst_buffer_list_iterator_do_data() functions are not defined in terms of the
54 * cursor position; they operate on the last element returned from
55 * gst_buffer_list_iterator_next().
57 * The basic use pattern of creating a buffer list with an iterator is as
61 * <title>Creating a buffer list</title>
63 * GstBufferList *list;
64 * GstBufferListIterator *it;
66 * list = gst_buffer_list_new ();
67 * it = gst_buffer_list_iterate (list);
68 * gst_buffer_list_iterator_add_group (it);
69 * gst_buffer_list_iterator_add (it, header1);
70 * gst_buffer_list_iterator_add (it, data1);
71 * gst_buffer_list_iterator_add_group (it);
72 * gst_buffer_list_iterator_add (it, header2);
73 * gst_buffer_list_iterator_add (it, data2);
74 * gst_buffer_list_iterator_add_group (it);
75 * gst_buffer_list_iterator_add (it, header3);
76 * gst_buffer_list_iterator_add (it, data3);
78 * gst_buffer_list_iterator_free (it);
82 * The basic use pattern of iterating over a buffer list is as follows:
85 * <title>Iterating a buffer list</title>
87 * GstBufferListIterator *it;
89 * it = gst_buffer_list_iterate (list);
90 * while (gst_buffer_list_iterator_next_group (it)) {
91 * while ((buffer = gst_buffer_list_iterator_next (it)) != NULL) {
92 * do_something_with_buffer (buffer);
95 * gst_buffer_list_iterator_free (it);
99 * The basic use pattern of modifying a buffer in a list is as follows:
102 * <title>Modifying the data of the first buffer in a list</title>
104 * GstBufferListIterator *it;
106 * list = gst_buffer_list_make_writable (list);
107 * it = gst_buffer_list_iterate (list);
108 * if (gst_buffer_list_iterator_next_group (it)) {
111 * buf = gst_buffer_list_iterator_next (it);
113 * buf = gst_buffer_list_iterator_do (it,
114 * (GstBufferListDoFunction) gst_mini_object_make_writable);
115 * modify_data (GST_BUFFER_DATA (buf));
118 * gst_buffer_list_iterator_free (it);
124 #include "gst_private.h"
126 #include "gstbuffer.h"
127 #include "gstbufferlist.h"
129 #define GST_CAT_DEFAULT GST_CAT_BUFFER_LIST
131 #define GROUP_START NULL
132 static const gpointer STOLEN = "";
135 * GstBufferListIterator:
137 * Iterator for a #GstBufferList.
139 struct _GstBufferListIterator
143 GList *last_returned;
146 static GType _gst_buffer_list_type = 0;
147 static GstMiniObjectClass *parent_class = NULL;
150 _gst_buffer_list_initialize (void)
152 g_type_class_ref (gst_buffer_list_get_type ());
156 gst_buffer_list_init (GTypeInstance * instance, gpointer g_class)
160 list = (GstBufferList *) instance;
161 list->buffers = NULL;
163 GST_LOG ("init %p", list);
167 gst_buffer_list_finalize (GstBufferList * list)
171 g_return_if_fail (list != NULL);
173 GST_LOG ("finalize %p", list);
177 if (tmp->data != GROUP_START && tmp->data != STOLEN) {
178 gst_buffer_unref (GST_BUFFER_CAST (tmp->data));
182 g_list_free (list->buffers);
184 parent_class->finalize (GST_MINI_OBJECT_CAST (list));
187 static GstBufferList *
188 _gst_buffer_list_copy (GstBufferList * list)
190 GstBufferList *list_copy;
193 g_return_val_if_fail (list != NULL, NULL);
195 list_copy = gst_buffer_list_new ();
197 /* shallow copy of list and pointers */
198 list_copy->buffers = g_list_copy (list->buffers);
200 /* ref all buffers in the list */
201 tmp = list_copy->buffers;
203 if (tmp->data != GROUP_START && tmp->data != STOLEN) {
204 tmp->data = gst_buffer_ref (GST_BUFFER_CAST (tmp->data));
206 tmp = g_list_next (tmp);
213 gst_buffer_list_class_init (gpointer g_class, gpointer class_data)
215 GstBufferListClass *list_class = GST_BUFFER_LIST_CLASS (g_class);
217 parent_class = g_type_class_peek_parent (g_class);
219 list_class->mini_object_class.copy =
220 (GstMiniObjectCopyFunction) _gst_buffer_list_copy;
221 list_class->mini_object_class.finalize =
222 (GstMiniObjectFinalizeFunction) gst_buffer_list_finalize;
226 * gst_buffer_list_new:
228 * Creates a new, empty #GstBufferList. The caller is responsible for unreffing
229 * the returned #GstBufferList.
231 * Returns: the new #GstBufferList. gst_buffer_list_unref() after usage.
234 gst_buffer_list_new (void)
238 list = (GstBufferList *) gst_mini_object_new (_gst_buffer_list_type);
240 GST_LOG ("new %p", list);
246 * gst_buffer_list_n_groups:
247 * @list: a #GstBufferList
249 * Returns the number of groups in @list.
251 * Returns: the number of groups in the buffer list
254 gst_buffer_list_n_groups (GstBufferList * list)
259 g_return_val_if_fail (list != NULL, 0);
264 if (tmp->data == GROUP_START) {
267 tmp = g_list_next (tmp);
274 gst_buffer_list_get_type (void)
276 if (G_UNLIKELY (_gst_buffer_list_type == 0)) {
277 static const GTypeInfo buffer_list_info = {
278 sizeof (GstBufferListClass),
281 gst_buffer_list_class_init,
284 sizeof (GstBufferList),
286 gst_buffer_list_init,
290 _gst_buffer_list_type = g_type_register_static (GST_TYPE_MINI_OBJECT,
291 "GstBufferList", &buffer_list_info, 0);
294 return _gst_buffer_list_type;
298 * gst_buffer_list_iterate:
299 * @list: a #GstBufferList
301 * Iterate the buffers in @list. The owner of the iterator must also be the
302 * owner of a reference to @list while the returned iterator is in use.
304 * Returns: a new #GstBufferListIterator of the buffers in @list.
305 * gst_buffer_list_iterator_free() after usage
307 GstBufferListIterator *
308 gst_buffer_list_iterate (GstBufferList * list)
310 GstBufferListIterator *it;
312 g_return_val_if_fail (list != NULL, NULL);
314 it = g_slice_new (GstBufferListIterator);
316 it->next = list->buffers;
317 it->last_returned = NULL;
323 * gst_buffer_list_iterator_free:
324 * @it: the #GstBufferListIterator to free
329 gst_buffer_list_iterator_free (GstBufferListIterator * it)
331 g_return_if_fail (it != NULL);
333 g_slice_free (GstBufferListIterator, it);
337 * gst_buffer_list_iterator_n_buffers:
338 * @it: a #GstBufferListIterator
340 * Returns the number of buffers left to iterate in the current group. I.e. the
341 * number of calls that can be made to gst_buffer_list_iterator_next() before
344 * This function will not move the implicit cursor or in any other way affect
345 * the state of the iterator @it.
347 * Returns: the number of buffers left to iterate in the current group
350 gst_buffer_list_iterator_n_buffers (const GstBufferListIterator * it)
355 g_return_val_if_fail (it != NULL, 0);
359 while (tmp && tmp->data != GROUP_START) {
360 if (tmp->data != STOLEN) {
363 tmp = g_list_next (tmp);
370 * gst_buffer_list_iterator_add:
371 * @it: a #GstBufferListIterator
372 * @buffer: a #GstBuffer
374 * Inserts @buffer into the #GstBufferList iterated with @it. The buffer is
375 * inserted into the current group, immediately before the buffer that would be
376 * returned by gst_buffer_list_iterator_next(). The buffer is inserted before
377 * the implicit cursor, a subsequent call to gst_buffer_list_iterator_next()
378 * will return the buffer after the inserted buffer, if any.
380 * This function takes ownership of @buffer.
383 gst_buffer_list_iterator_add (GstBufferListIterator * it, GstBuffer * buffer)
385 g_return_if_fail (it != NULL);
386 g_return_if_fail (buffer != NULL);
388 /* adding before the first group start is not allowed */
389 g_return_if_fail (it->next != it->list->buffers);
391 /* cheap insert into the GList */
392 it->list->buffers = g_list_insert_before (it->list->buffers, it->next,
397 * gst_buffer_list_iterator_add_group:
398 * @it: a #GstBufferListIterator
400 * Inserts a new, empty group into the #GstBufferList iterated with @it. The
401 * group is inserted immediately before the group that would be returned by
402 * gst_buffer_list_iterator_next_group(). A subsequent call to
403 * gst_buffer_list_iterator_next_group() will advance the iterator to the group
404 * after the inserted group, if any.
407 gst_buffer_list_iterator_add_group (GstBufferListIterator * it)
409 g_return_if_fail (it != NULL);
411 /* advance iterator to next group start */
412 while (it->next != NULL && it->next->data != GROUP_START) {
413 it->next = g_list_next (it->next);
416 /* cheap insert of a group start into the GList */
417 it->list->buffers = g_list_insert_before (it->list->buffers, it->next,
422 * gst_buffer_list_iterator_next:
423 * @it: a #GstBufferListIterator
425 * Returns the next buffer in the list iterated with @it. If the iterator is at
426 * the end of a group, NULL will be returned. This function may be called
427 * repeatedly to iterate through the current group.
429 * The caller will not get a new ref to the returned #GstBuffer and must not
432 * Returns: the next buffer in the current group of the buffer list, or NULL
435 gst_buffer_list_iterator_next (GstBufferListIterator * it)
439 g_return_val_if_fail (it != NULL, NULL);
441 while (it->next != NULL && it->next->data != GROUP_START &&
442 it->next->data == STOLEN) {
443 it->next = g_list_next (it->next);
446 if (it->next == NULL || it->next->data == GROUP_START) {
450 buffer = GST_BUFFER_CAST (it->next->data);
452 it->last_returned = it->next;
453 it->next = g_list_next (it->next);
458 it->last_returned = NULL;
464 * gst_buffer_list_iterator_next_group:
465 * @it: a #GstBufferListIterator
467 * Advance the iterator @it to the first buffer in the next group. If the
468 * iterator is at the last group, FALSE will be returned. This function may be
469 * called repeatedly to iterate through the groups in a buffer list.
471 * Returns: TRUE if the iterator could be advanced to the next group, FALSE if
472 * the iterator was already at the last group
475 gst_buffer_list_iterator_next_group (GstBufferListIterator * it)
477 g_return_val_if_fail (it != NULL, FALSE);
479 /* advance iterator to next group start */
480 while (it->next != NULL && it->next->data != GROUP_START) {
481 it->next = g_list_next (it->next);
485 /* move one step beyond the group start */
486 it->next = g_list_next (it->next);
489 it->last_returned = NULL;
491 return (it->next != NULL);
495 * gst_buffer_list_iterator_remove:
496 * @it: a #GstBufferListIterator
498 * Removes the last buffer returned by gst_buffer_list_iterator_next() from
499 * the #GstBufferList iterated with @it. gst_buffer_list_iterator_next() must
500 * have been called on @it before this function is called. This function can
501 * only be called once per call to gst_buffer_list_iterator_next().
503 * The removed buffer is unreffed.
506 gst_buffer_list_iterator_remove (GstBufferListIterator * it)
508 g_return_if_fail (it != NULL);
509 g_return_if_fail (it->last_returned != NULL);
510 g_assert (it->last_returned->data != GROUP_START);
512 if (it->last_returned->data != STOLEN) {
513 gst_buffer_unref (it->last_returned->data);
515 it->list->buffers = g_list_delete_link (it->list->buffers, it->last_returned);
516 it->last_returned = NULL;
520 * gst_buffer_list_iterator_take:
521 * @it: a #GstBufferListIterator
522 * @buffer: a #GstBuffer
524 * Replaces the last buffer returned by gst_buffer_list_iterator_next() with
525 * @buffer in the #GstBufferList iterated with @it and takes ownership of
526 * @buffer. gst_buffer_list_iterator_next() must have been called on @it before
527 * this function is called. gst_buffer_list_iterator_remove() must not have been
528 * called since the last call to gst_buffer_list_iterator_next().
530 * This function unrefs the replaced buffer if it has not been stolen with
531 * gst_buffer_list_iterator_steal() and takes ownership of @buffer (i.e. the
532 * refcount of @buffer is not increased).
535 gst_buffer_list_iterator_take (GstBufferListIterator * it, GstBuffer * buffer)
537 g_return_if_fail (it != NULL);
538 g_return_if_fail (it->last_returned != NULL);
539 g_return_if_fail (buffer != NULL);
540 g_assert (it->last_returned->data != GROUP_START);
542 if (it->last_returned->data != STOLEN) {
543 gst_buffer_unref (it->last_returned->data);
545 it->last_returned->data = buffer;
549 * gst_buffer_list_iterator_steal:
550 * @it: a #GstBufferListIterator
552 * Returns the last buffer returned by gst_buffer_list_iterator_next() without
553 * modifying the refcount of the buffer.
555 * Returns: the last buffer returned by gst_buffer_list_iterator_next()
558 gst_buffer_list_iterator_steal (GstBufferListIterator * it)
562 g_return_val_if_fail (it != NULL, NULL);
563 g_return_val_if_fail (it->last_returned != NULL, NULL);
564 g_return_val_if_fail (it->last_returned->data != STOLEN, NULL);
565 g_assert (it->last_returned->data != GROUP_START);
567 buffer = it->last_returned->data;
568 it->last_returned->data = STOLEN;
574 * gst_buffer_list_iterator_do_data:
575 * @it: a #GstBufferListIterator
576 * @do_func: the function to be called
577 * @data: the gpointer to optional user data.
578 * @data_notify: function to be called when @data is no longer used
580 * Calls the given function for the last buffer returned by
581 * gst_buffer_list_iterator_next(). gst_buffer_list_iterator_next() must have
582 * been called on @it before this function is called.
583 * gst_buffer_list_iterator_remove() and gst_buffer_list_iterator_steal() must
584 * not have been called since the last call to gst_buffer_list_iterator_next().
586 * See #GstBufferListDoFunction for more details.
588 * The @data_notify function is called after @do_func has returned, before this
589 * function returns, usually used to free @data.
591 * Returns: the return value from @do_func
594 gst_buffer_list_iterator_do_data (GstBufferListIterator * it,
595 GstBufferListDoDataFunction do_func, gpointer data,
596 GDestroyNotify data_notify)
600 g_return_val_if_fail (it != NULL, NULL);
601 g_return_val_if_fail (it->last_returned != NULL, NULL);
602 g_return_val_if_fail (it->last_returned->data != STOLEN, NULL);
603 g_return_val_if_fail (do_func != NULL, NULL);
604 g_return_val_if_fail (gst_buffer_list_is_writable (it->list), NULL);
605 g_assert (it->last_returned->data != GROUP_START);
607 buffer = gst_buffer_list_iterator_steal (it);
608 buffer = do_func (buffer, data);
609 if (buffer == NULL) {
610 gst_buffer_list_iterator_remove (it);
612 gst_buffer_list_iterator_take (it, buffer);
615 if (data_notify != NULL) {
623 do_func_no_data (GstBuffer * buffer, GstBufferListDoFunction do_func)
625 return do_func (buffer);
629 * gst_buffer_list_iterator_do:
630 * @it: a #GstBufferListIterator
631 * @do_func: the function to be called
633 * Calls the given function for the last buffer returned by
634 * gst_buffer_list_iterator_next(). gst_buffer_list_iterator_next() must have
635 * been called on @it before this function is called.
636 * gst_buffer_list_iterator_remove() or gst_buffer_list_iterator_steal() must
637 * not have been called since the last call to gst_buffer_list_iterator_next().
639 * See #GstBufferListDoFunction for more details.
641 * Returns: the return value from @do_func
644 gst_buffer_list_iterator_do (GstBufferListIterator * it,
645 GstBufferListDoFunction do_func)
647 g_return_val_if_fail (it != NULL, NULL);
648 g_return_val_if_fail (it->last_returned != NULL, NULL);
649 g_return_val_if_fail (it->last_returned->data != STOLEN, NULL);
650 g_return_val_if_fail (do_func != NULL, NULL);
651 g_return_val_if_fail (gst_buffer_list_is_writable (it->list), NULL);
652 g_assert (it->last_returned->data != GROUP_START);
654 return gst_buffer_list_iterator_do_data (it,
655 (GstBufferListDoDataFunction) do_func_no_data, do_func, NULL);
659 * gst_buffer_list_iterator_merge_group:
660 * @it: a #GstBufferListIterator
662 * Merge a buffer list group into a normal #GstBuffer by copying its metadata
663 * and memcpying its data into consecutive memory. All buffers in the current
664 * group after the implicit cursor will be merged into one new buffer. The
665 * metadata of the new buffer will be a copy of the metadata of the buffer that
666 * would be returned by gst_buffer_list_iterator_next(). If there is no buffer
667 * in the current group after the implicit cursor, NULL will be returned.
669 * This function will not move the implicit cursor or in any other way affect
670 * the state of the iterator @it or the list.
672 * Returns: a new #GstBuffer, gst_buffer_unref() after usage, or NULL
675 gst_buffer_list_iterator_merge_group (const GstBufferListIterator * it)
682 g_return_val_if_fail (it != NULL, NULL);
684 /* calculate size of merged buffer */
687 while (tmp && tmp->data != GROUP_START) {
688 if (tmp->data != STOLEN) {
689 size += GST_BUFFER_SIZE (tmp->data);
691 tmp = g_list_next (tmp);
698 /* allocate a new buffer */
699 buf = gst_buffer_new_and_alloc (size);
701 /* copy metadata from the next buffer after the implicit cursor */
702 gst_buffer_copy_metadata (buf, GST_BUFFER_CAST (it->next->data),
703 GST_BUFFER_COPY_ALL);
705 /* copy data of all buffers before the next group start into the new buffer */
706 ptr = GST_BUFFER_DATA (buf);
709 if (tmp->data != STOLEN) {
710 memcpy (ptr, GST_BUFFER_DATA (tmp->data), GST_BUFFER_SIZE (tmp->data));
711 ptr += GST_BUFFER_SIZE (tmp->data);
713 tmp = g_list_next (tmp);
714 } while (tmp && tmp->data != GROUP_START);