bufferlist: fix a comment
[platform/upstream/gstreamer.git] / gst / gstbufferlist.c
1 /* GStreamer
2  * Copyright (C) 2009 Axis Communications <dev-gstreamer at axis dot com>
3  * @author Jonas Holmberg <jonas dot holmberg at axis dot com>
4  *
5  * gstbufferlist.c: Buffer list
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 /**
24  * SECTION:gstbufferlist
25  * @short_description: Grouped scatter data buffer type for data-passing
26  * @see_also: #GstPad, #GstMiniObject
27  *
28  * Buffer lists are units of grouped scatter/gather data transfer in
29  * GStreamer.
30  *
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.
41  *
42  * <informalexample>
43  *   <programlisting>
44  *      +--- group0 ----------------------+--- group1 ------------+
45  *      |   buffer0   buffer1   buffer2   |   buffer3   buffer4   |
46  *    ^   ^         ^         ^         ^   ^         ^         ^
47  *    Iterator positions
48  *   </programlisting>
49  * </informalexample>
50  *
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().
56  *
57  * The basic use pattern of creating a buffer list with an iterator is as
58  * follows:
59  *
60  * <example>
61  * <title>Creating a buffer list</title>
62  *   <programlisting>
63  *    GstBufferList *list;
64  *    GstBufferListIterator *it;
65  *
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);
77  *    ...
78  *    gst_buffer_list_iterator_free (it);
79  *   </programlisting>
80  * </example>
81  *
82  * The basic use pattern of iterating over a buffer list is as follows:
83  *
84  * <example>
85  * <title>Iterating a buffer list</title>
86  *   <programlisting>
87  *    GstBufferListIterator *it;
88  *
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);
93  *      }
94  *    }
95  *    gst_buffer_list_iterator_free (it);
96  *   </programlisting>
97  * </example>
98  *
99  * The basic use pattern of modifying a buffer in a list is as follows:
100  *
101  * <example>
102  * <title>Modifying the data of the first buffer in a list</title>
103  *   <programlisting>
104  *    GstBufferListIterator *it;
105  *
106  *    list = gst_buffer_list_make_writable (list);
107  *    it = gst_buffer_list_iterate (list);
108  *    if (gst_buffer_list_iterator_next_group (it)) {
109  *      GstBuffer *buf
110  *
111  *      buf = gst_buffer_list_iterator_next (it);
112  *      if (buf != NULL) {
113  *        buf = gst_buffer_list_iterator_do (it,
114  *            (GstBufferListDoFunction) gst_mini_object_make_writable);
115  *        modify_data (GST_BUFFER_DATA (buf));
116  *      }
117  *    }
118  *    gst_buffer_list_iterator_free (it);
119  *   </programlisting>
120  * </example>
121  *
122  * Since: 0.10.24
123  */
124 #include "gst_private.h"
125
126 #include "gstbuffer.h"
127 #include "gstbufferlist.h"
128
129 #define GST_CAT_DEFAULT GST_CAT_BUFFER_LIST
130
131 #define GROUP_START NULL
132 static const gpointer STOLEN = "";
133
134 /**
135  * GstBufferListIterator:
136  *
137  * Iterator for a #GstBufferList.
138  */
139 struct _GstBufferListIterator
140 {
141   GstBufferList *list;
142   GList *next;
143   GList *last_returned;
144 };
145
146 static GType _gst_buffer_list_type = 0;
147 static GstMiniObjectClass *parent_class = NULL;
148
149 void
150 _gst_buffer_list_initialize (void)
151 {
152   g_type_class_ref (gst_buffer_list_get_type ());
153 }
154
155 static void
156 gst_buffer_list_init (GTypeInstance * instance, gpointer g_class)
157 {
158   GstBufferList *list;
159
160   list = (GstBufferList *) instance;
161   list->buffers = NULL;
162
163   GST_LOG ("init %p", list);
164 }
165
166 static void
167 gst_buffer_list_finalize (GstBufferList * list)
168 {
169   GList *tmp;
170
171   g_return_if_fail (list != NULL);
172
173   GST_LOG ("finalize %p", list);
174
175   tmp = list->buffers;
176   while (tmp) {
177     if (tmp->data != GROUP_START && tmp->data != STOLEN) {
178       gst_buffer_unref (GST_BUFFER_CAST (tmp->data));
179     }
180     tmp = tmp->next;
181   }
182   g_list_free (list->buffers);
183
184   parent_class->finalize (GST_MINI_OBJECT_CAST (list));
185 }
186
187 static GstBufferList *
188 _gst_buffer_list_copy (GstBufferList * list)
189 {
190   GstBufferList *list_copy;
191   GList *tmp;
192
193   g_return_val_if_fail (list != NULL, NULL);
194
195   list_copy = gst_buffer_list_new ();
196
197   /* shallow copy of list and pointers */
198   list_copy->buffers = g_list_copy (list->buffers);
199
200   /* ref all buffers in the list */
201   tmp = list_copy->buffers;
202   while (tmp) {
203     if (tmp->data != GROUP_START && tmp->data != STOLEN) {
204       tmp->data = gst_buffer_ref (GST_BUFFER_CAST (tmp->data));
205     }
206     tmp = g_list_next (tmp);
207   }
208
209   return list_copy;
210 }
211
212 static void
213 gst_buffer_list_class_init (gpointer g_class, gpointer class_data)
214 {
215   GstBufferListClass *list_class = GST_BUFFER_LIST_CLASS (g_class);
216
217   parent_class = g_type_class_peek_parent (g_class);
218
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;
223 }
224
225 /**
226  * gst_buffer_list_new:
227  *
228  * Creates a new, empty #GstBufferList. The caller is responsible for unreffing
229  * the returned #GstBufferList.
230  *
231  * Returns: the new #GstBufferList. gst_buffer_list_unref() after usage.
232  */
233 GstBufferList *
234 gst_buffer_list_new (void)
235 {
236   GstBufferList *list;
237
238   list = (GstBufferList *) gst_mini_object_new (_gst_buffer_list_type);
239
240   GST_LOG ("new %p", list);
241
242   return list;
243 }
244
245 /**
246  * gst_buffer_list_n_groups:
247  * @list: a #GstBufferList
248  *
249  * Returns the number of groups in @list.
250  *
251  * Returns: the number of groups in the buffer list
252  */
253 guint
254 gst_buffer_list_n_groups (GstBufferList * list)
255 {
256   GList *tmp;
257   guint n;
258
259   g_return_val_if_fail (list != NULL, 0);
260
261   tmp = list->buffers;
262   n = 0;
263   while (tmp) {
264     if (tmp->data == GROUP_START) {
265       n++;
266     }
267     tmp = g_list_next (tmp);
268   }
269
270   return n;
271 }
272
273 GType
274 gst_buffer_list_get_type (void)
275 {
276   if (G_UNLIKELY (_gst_buffer_list_type == 0)) {
277     static const GTypeInfo buffer_list_info = {
278       sizeof (GstBufferListClass),
279       NULL,
280       NULL,
281       gst_buffer_list_class_init,
282       NULL,
283       NULL,
284       sizeof (GstBufferList),
285       0,
286       gst_buffer_list_init,
287       NULL
288     };
289
290     _gst_buffer_list_type = g_type_register_static (GST_TYPE_MINI_OBJECT,
291         "GstBufferList", &buffer_list_info, 0);
292   }
293
294   return _gst_buffer_list_type;
295 }
296
297 /**
298  * gst_buffer_list_iterate:
299  * @list: a #GstBufferList
300  *
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.
303  *
304  * Returns: a new #GstBufferListIterator of the buffers in @list.
305  * gst_buffer_list_iterator_free() after usage
306  */
307 GstBufferListIterator *
308 gst_buffer_list_iterate (GstBufferList * list)
309 {
310   GstBufferListIterator *it;
311
312   g_return_val_if_fail (list != NULL, NULL);
313
314   it = g_slice_new (GstBufferListIterator);
315   it->list = list;
316   it->next = list->buffers;
317   it->last_returned = NULL;
318
319   return it;
320 }
321
322 /**
323  * gst_buffer_list_iterator_free:
324  * @it: the #GstBufferListIterator to free
325  *
326  * Free the iterator.
327  */
328 void
329 gst_buffer_list_iterator_free (GstBufferListIterator * it)
330 {
331   g_return_if_fail (it != NULL);
332
333   g_slice_free (GstBufferListIterator, it);
334 }
335
336 /**
337  * gst_buffer_list_iterator_n_buffers:
338  * @it: a #GstBufferListIterator
339  *
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
342  * it returns NULL.
343  *
344  * This function will not move the implicit cursor or in any other way affect
345  * the state of the iterator @it.
346  *
347  * Returns: the number of buffers left to iterate in the current group
348  */
349 guint
350 gst_buffer_list_iterator_n_buffers (const GstBufferListIterator * it)
351 {
352   GList *tmp;
353   guint n;
354
355   g_return_val_if_fail (it != NULL, 0);
356
357   tmp = it->next;
358   n = 0;
359   while (tmp && tmp->data != GROUP_START) {
360     if (tmp->data != STOLEN) {
361       n++;
362     }
363     tmp = g_list_next (tmp);
364   }
365
366   return n;
367 }
368
369 /**
370  * gst_buffer_list_iterator_add:
371  * @it: a #GstBufferListIterator
372  * @buffer: a #GstBuffer
373  *
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.
379  *
380  * This function takes ownership of @buffer.
381  */
382 void
383 gst_buffer_list_iterator_add (GstBufferListIterator * it, GstBuffer * buffer)
384 {
385   g_return_if_fail (it != NULL);
386   g_return_if_fail (buffer != NULL);
387
388   /* adding before the first group start is not allowed */
389   g_return_if_fail (it->next != it->list->buffers);
390
391   /* cheap insert into the GList */
392   it->list->buffers = g_list_insert_before (it->list->buffers, it->next,
393       buffer);
394 }
395
396 /**
397  * gst_buffer_list_iterator_add_group:
398  * @it: a #GstBufferListIterator
399  *
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.
405  */
406 void
407 gst_buffer_list_iterator_add_group (GstBufferListIterator * it)
408 {
409   g_return_if_fail (it != NULL);
410
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);
414   }
415
416   /* cheap insert of a group start into the GList */
417   it->list->buffers = g_list_insert_before (it->list->buffers, it->next,
418       GROUP_START);
419 }
420
421 /**
422  * gst_buffer_list_iterator_next:
423  * @it: a #GstBufferListIterator
424  *
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.
428  *
429  * The caller will not get a new ref to the returned #GstBuffer and must not
430  * unref it.
431  *
432  * Returns: the next buffer in the current group of the buffer list, or NULL
433  */
434 GstBuffer *
435 gst_buffer_list_iterator_next (GstBufferListIterator * it)
436 {
437   GstBuffer *buffer;
438
439   g_return_val_if_fail (it != NULL, NULL);
440
441   while (it->next != NULL && it->next->data != GROUP_START &&
442       it->next->data == STOLEN) {
443     it->next = g_list_next (it->next);
444   }
445
446   if (it->next == NULL || it->next->data == GROUP_START) {
447     goto no_buffer;
448   }
449
450   buffer = GST_BUFFER_CAST (it->next->data);
451
452   it->last_returned = it->next;
453   it->next = g_list_next (it->next);
454
455   return buffer;
456
457 no_buffer:
458   it->last_returned = NULL;
459
460   return NULL;
461 }
462
463 /**
464  * gst_buffer_list_iterator_next_group:
465  * @it: a #GstBufferListIterator
466  *
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.
470  *
471  * Returns: TRUE if the iterator could be advanced to the next group, FALSE if
472  * the iterator was already at the last group
473  */
474 gboolean
475 gst_buffer_list_iterator_next_group (GstBufferListIterator * it)
476 {
477   g_return_val_if_fail (it != NULL, FALSE);
478
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);
482   }
483
484   if (it->next) {
485     /* move one step beyond the group start */
486     it->next = g_list_next (it->next);
487   }
488
489   it->last_returned = NULL;
490
491   return (it->next != NULL);
492 }
493
494 /**
495  * gst_buffer_list_iterator_remove:
496  * @it: a #GstBufferListIterator
497  *
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().
502  *
503  * The removed buffer is unreffed.
504  */
505 void
506 gst_buffer_list_iterator_remove (GstBufferListIterator * it)
507 {
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);
511
512   if (it->last_returned->data != STOLEN) {
513     gst_buffer_unref (it->last_returned->data);
514   }
515   it->list->buffers = g_list_delete_link (it->list->buffers, it->last_returned);
516   it->last_returned = NULL;
517 }
518
519 /**
520  * gst_buffer_list_iterator_take:
521  * @it: a #GstBufferListIterator
522  * @buffer: a #GstBuffer
523  *
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().
529  *
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).
533  */
534 void
535 gst_buffer_list_iterator_take (GstBufferListIterator * it, GstBuffer * buffer)
536 {
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);
541
542   if (it->last_returned->data != STOLEN) {
543     gst_buffer_unref (it->last_returned->data);
544   }
545   it->last_returned->data = buffer;
546 }
547
548 /**
549  * gst_buffer_list_iterator_steal:
550  * @it: a #GstBufferListIterator
551  *
552  * Returns the last buffer returned by gst_buffer_list_iterator_next() without
553  * modifying the refcount of the buffer.
554  *
555  * Returns: the last buffer returned by gst_buffer_list_iterator_next()
556  */
557 GstBuffer *
558 gst_buffer_list_iterator_steal (GstBufferListIterator * it)
559 {
560   GstBuffer *buffer;
561
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);
566
567   buffer = it->last_returned->data;
568   it->last_returned->data = STOLEN;
569
570   return buffer;
571 }
572
573 /**
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
579  *
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().
585  *
586  * See #GstBufferListDoFunction for more details.
587  *
588  * The @data_notify function is called after @do_func has returned, before this
589  * function returns, usually used to free @data.
590  *
591  * Returns: the return value from @do_func
592  */
593 GstBuffer *
594 gst_buffer_list_iterator_do_data (GstBufferListIterator * it,
595     GstBufferListDoDataFunction do_func, gpointer data,
596     GDestroyNotify data_notify)
597 {
598   GstBuffer *buffer;
599
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);
606
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);
611   } else {
612     gst_buffer_list_iterator_take (it, buffer);
613   }
614
615   if (data_notify != NULL) {
616     data_notify (data);
617   }
618
619   return buffer;
620 }
621
622 static GstBuffer *
623 do_func_no_data (GstBuffer * buffer, GstBufferListDoFunction do_func)
624 {
625   return do_func (buffer);
626 }
627
628 /**
629  * gst_buffer_list_iterator_do:
630  * @it: a #GstBufferListIterator
631  * @do_func: the function to be called
632  *
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().
638  *
639  * See #GstBufferListDoFunction for more details.
640  *
641  * Returns: the return value from @do_func
642  */
643 GstBuffer *
644 gst_buffer_list_iterator_do (GstBufferListIterator * it,
645     GstBufferListDoFunction do_func)
646 {
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);
653
654   return gst_buffer_list_iterator_do_data (it,
655       (GstBufferListDoDataFunction) do_func_no_data, do_func, NULL);
656 }
657
658 /**
659  * gst_buffer_list_iterator_merge_group:
660  * @it: a #GstBufferListIterator
661  *
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.
668  *
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.
671  *
672  * Returns: a new #GstBuffer, gst_buffer_unref() after usage, or NULL
673  */
674 GstBuffer *
675 gst_buffer_list_iterator_merge_group (const GstBufferListIterator * it)
676 {
677   GList *tmp;
678   guint size;
679   GstBuffer *buf;
680   guint8 *ptr;
681
682   g_return_val_if_fail (it != NULL, NULL);
683
684   /* calculate size of merged buffer */
685   size = 0;
686   tmp = it->next;
687   while (tmp && tmp->data != GROUP_START) {
688     if (tmp->data != STOLEN) {
689       size += GST_BUFFER_SIZE (tmp->data);
690     }
691     tmp = g_list_next (tmp);
692   }
693
694   if (size == 0) {
695     return NULL;
696   }
697
698   /* allocate a new buffer */
699   buf = gst_buffer_new_and_alloc (size);
700
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);
704
705   /* copy data of all buffers before the next group start into the new buffer */
706   ptr = GST_BUFFER_DATA (buf);
707   tmp = it->next;
708   do {
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);
712     }
713     tmp = g_list_next (tmp);
714   } while (tmp && tmp->data != GROUP_START);
715
716   return buf;
717 }