buffer: don't over-allocate internal GstMeta items
[platform/upstream/gstreamer.git] / gst / gstbuffer.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstbuffer.c: Buffer operations
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., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 /**
24  * SECTION:gstbuffer
25  * @title: GstBuffer
26  * @short_description: Data-passing buffer type
27  * @see_also: #GstPad, #GstMiniObject, #GstMemory, #GstMeta, #GstBufferPool
28  *
29  * Buffers are the basic unit of data transfer in GStreamer. They contain the
30  * timing and offset along with other arbitrary metadata that is associated
31  * with the #GstMemory blocks that the buffer contains.
32  *
33  * Buffers are usually created with gst_buffer_new(). After a buffer has been
34  * created one will typically allocate memory for it and add it to the buffer.
35  * The following example creates a buffer that can hold a given video frame
36  * with a given width, height and bits per plane.
37  * |[<!-- language="C" -->
38  *   GstBuffer *buffer;
39  *   GstMemory *memory;
40  *   gint size, width, height, bpp;
41  *   ...
42  *   size = width * height * bpp;
43  *   buffer = gst_buffer_new ();
44  *   memory = gst_allocator_alloc (NULL, size, NULL);
45  *   gst_buffer_insert_memory (buffer, -1, memory);
46  *   ...
47  * ]|
48  *
49  * Alternatively, use gst_buffer_new_allocate() to create a buffer with
50  * preallocated data of a given size.
51  *
52  * Buffers can contain a list of #GstMemory objects. You can retrieve how many
53  * memory objects with gst_buffer_n_memory() and you can get a pointer
54  * to memory with gst_buffer_peek_memory()
55  *
56  * A buffer will usually have timestamps, and a duration, but neither of these
57  * are guaranteed (they may be set to #GST_CLOCK_TIME_NONE). Whenever a
58  * meaningful value can be given for these, they should be set. The timestamps
59  * and duration are measured in nanoseconds (they are #GstClockTime values).
60  *
61  * The buffer DTS refers to the timestamp when the buffer should be decoded and
62  * is usually monotonically increasing. The buffer PTS refers to the timestamp when
63  * the buffer content should be presented to the user and is not always
64  * monotonically increasing.
65  *
66  * A buffer can also have one or both of a start and an end offset. These are
67  * media-type specific. For video buffers, the start offset will generally be
68  * the frame number. For audio buffers, it will be the number of samples
69  * produced so far. For compressed data, it could be the byte offset in a
70  * source or destination file. Likewise, the end offset will be the offset of
71  * the end of the buffer. These can only be meaningfully interpreted if you
72  * know the media type of the buffer (the preceding CAPS event). Either or both
73  * can be set to #GST_BUFFER_OFFSET_NONE.
74  *
75  * gst_buffer_ref() is used to increase the refcount of a buffer. This must be
76  * done when you want to keep a handle to the buffer after pushing it to the
77  * next element. The buffer refcount determines the writability of the buffer, a
78  * buffer is only writable when the refcount is exactly 1, i.e. when the caller
79  * has the only reference to the buffer.
80  *
81  * To efficiently create a smaller buffer out of an existing one, you can
82  * use gst_buffer_copy_region(). This method tries to share the memory objects
83  * between the two buffers.
84  *
85  * If a plug-in wants to modify the buffer data or metadata in-place, it should
86  * first obtain a buffer that is safe to modify by using
87  * gst_buffer_make_writable().  This function is optimized so that a copy will
88  * only be made when it is necessary.
89  *
90  * Several flags of the buffer can be set and unset with the
91  * GST_BUFFER_FLAG_SET() and GST_BUFFER_FLAG_UNSET() macros. Use
92  * GST_BUFFER_FLAG_IS_SET() to test if a certain #GstBufferFlags flag is set.
93  *
94  * Buffers can be efficiently merged into a larger buffer with
95  * gst_buffer_append(). Copying of memory will only be done when absolutely
96  * needed.
97  *
98  * Arbitrary extra metadata can be set on a buffer with gst_buffer_add_meta().
99  * Metadata can be retrieved with gst_buffer_get_meta(). See also #GstMeta
100  *
101  * An element should either unref the buffer or push it out on a src pad
102  * using gst_pad_push() (see #GstPad).
103  *
104  * Buffers are usually freed by unreffing them with gst_buffer_unref(). When
105  * the refcount drops to 0, any memory and metadata pointed to by the buffer is
106  * unreffed as well. Buffers allocated from a #GstBufferPool will be returned to
107  * the pool when the refcount drops to 0.
108  *
109  * The #GstParentBufferMeta is a meta which can be attached to a #GstBuffer
110  * to hold a reference to another buffer that is only released when the child
111  * #GstBuffer is released.
112  *
113  * Typically, #GstParentBufferMeta is used when the child buffer is directly
114  * using the #GstMemory of the parent buffer, and wants to prevent the parent
115  * buffer from being returned to a buffer pool until the #GstMemory is available
116  * for re-use. (Since 1.6)
117  *
118  */
119 #include "gst_private.h"
120
121 #ifdef HAVE_UNISTD_H
122 #include <unistd.h>
123 #endif
124 #ifdef HAVE_STDLIB_H
125 #include <stdlib.h>
126 #endif
127
128 #include "gstbuffer.h"
129 #include "gstbufferpool.h"
130 #include "gstinfo.h"
131 #include "gstutils.h"
132 #include "gstversion.h"
133
134 GType _gst_buffer_type = 0;
135
136 typedef struct _GstMetaItem GstMetaItem;
137
138 struct _GstMetaItem
139 {
140   GstMetaItem *next;
141   GstMeta meta;
142 };
143
144 /* info->size will be sizeof(FooMeta) which contains a GstMeta at the beginning
145  * too, and then there is again a GstMeta in GstMetaItem, so subtract one. */
146 #define ITEM_SIZE(info) ((info)->size + sizeof (GstMetaItem) - sizeof (GstMeta))
147
148 #define GST_BUFFER_MEM_MAX         16
149
150 #define GST_BUFFER_SLICE_SIZE(b)   (((GstBufferImpl *)(b))->slice_size)
151 #define GST_BUFFER_MEM_LEN(b)      (((GstBufferImpl *)(b))->len)
152 #define GST_BUFFER_MEM_ARRAY(b)    (((GstBufferImpl *)(b))->mem)
153 #define GST_BUFFER_MEM_PTR(b,i)    (((GstBufferImpl *)(b))->mem[i])
154 #define GST_BUFFER_BUFMEM(b)       (((GstBufferImpl *)(b))->bufmem)
155 #define GST_BUFFER_META(b)         (((GstBufferImpl *)(b))->item)
156
157 typedef struct
158 {
159   GstBuffer buffer;
160
161   gsize slice_size;
162
163   /* the memory blocks */
164   guint len;
165   GstMemory *mem[GST_BUFFER_MEM_MAX];
166
167   /* memory of the buffer when allocated from 1 chunk */
168   GstMemory *bufmem;
169
170   /* FIXME, make metadata allocation more efficient by using part of the
171    * GstBufferImpl */
172   GstMetaItem *item;
173 } GstBufferImpl;
174
175
176 static gboolean
177 _is_span (GstMemory ** mem, gsize len, gsize * poffset, GstMemory ** parent)
178 {
179   GstMemory *mcur, *mprv;
180   gboolean have_offset = FALSE;
181   gsize i;
182
183   mcur = mprv = NULL;
184
185   for (i = 0; i < len; i++) {
186     if (mcur)
187       mprv = mcur;
188     mcur = mem[i];
189
190     if (mprv && mcur) {
191       gsize poffs;
192
193       /* check if memory is contiguous */
194       if (!gst_memory_is_span (mprv, mcur, &poffs))
195         return FALSE;
196
197       if (!have_offset) {
198         if (poffset)
199           *poffset = poffs;
200         if (parent)
201           *parent = mprv->parent;
202
203         have_offset = TRUE;
204       }
205     }
206   }
207   return have_offset;
208 }
209
210 static GstMemory *
211 _get_merged_memory (GstBuffer * buffer, guint idx, guint length)
212 {
213   GstMemory **mem, *result = NULL;
214
215   GST_CAT_LOG (GST_CAT_BUFFER, "buffer %p, idx %u, length %u", buffer, idx,
216       length);
217
218   mem = GST_BUFFER_MEM_ARRAY (buffer);
219
220   if (G_UNLIKELY (length == 0)) {
221     result = NULL;
222   } else if (G_LIKELY (length == 1)) {
223     result = gst_memory_ref (mem[idx]);
224   } else {
225     GstMemory *parent = NULL;
226     gsize size, poffset = 0;
227
228     size = gst_buffer_get_sizes_range (buffer, idx, length, NULL, NULL);
229
230     if (G_UNLIKELY (_is_span (mem + idx, length, &poffset, &parent))) {
231       if (!GST_MEMORY_IS_NO_SHARE (parent))
232         result = gst_memory_share (parent, poffset, size);
233       if (!result) {
234         GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy for merge %p", parent);
235         result = gst_memory_copy (parent, poffset, size);
236       }
237     } else {
238       gsize i, tocopy, left;
239       GstMapInfo sinfo, dinfo;
240       guint8 *ptr;
241
242       result = gst_allocator_alloc (NULL, size, NULL);
243       if (result == NULL || !gst_memory_map (result, &dinfo, GST_MAP_WRITE)) {
244         GST_CAT_ERROR (GST_CAT_BUFFER, "Failed to map memory writable");
245         if (result)
246           gst_memory_unref (result);
247         return NULL;
248       }
249
250       ptr = dinfo.data;
251       left = size;
252
253       for (i = idx; i < (idx + length) && left > 0; i++) {
254         if (!gst_memory_map (mem[i], &sinfo, GST_MAP_READ)) {
255           GST_CAT_ERROR (GST_CAT_BUFFER,
256               "buffer %p, idx %u, length %u failed to map readable", buffer,
257               idx, length);
258           gst_memory_unmap (result, &dinfo);
259           gst_memory_unref (result);
260           return NULL;
261         }
262         tocopy = MIN (sinfo.size, left);
263         GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
264             "memcpy %" G_GSIZE_FORMAT " bytes for merge %p from memory %p",
265             tocopy, result, mem[i]);
266         memcpy (ptr, (guint8 *) sinfo.data, tocopy);
267         left -= tocopy;
268         ptr += tocopy;
269         gst_memory_unmap (mem[i], &sinfo);
270       }
271       gst_memory_unmap (result, &dinfo);
272     }
273   }
274   return result;
275 }
276
277 static void
278 _replace_memory (GstBuffer * buffer, guint len, guint idx, guint length,
279     GstMemory * mem)
280 {
281   gsize end, i;
282
283   end = idx + length;
284
285   GST_CAT_LOG (GST_CAT_BUFFER,
286       "buffer %p replace %u-%" G_GSIZE_FORMAT " with memory %p", buffer, idx,
287       end, mem);
288
289   /* unref old memory */
290   for (i = idx; i < end; i++) {
291     GstMemory *old = GST_BUFFER_MEM_PTR (buffer, i);
292
293     gst_memory_unlock (old, GST_LOCK_FLAG_EXCLUSIVE);
294     gst_memory_unref (old);
295   }
296
297   if (mem != NULL) {
298     /* replace with single memory */
299     gst_memory_lock (mem, GST_LOCK_FLAG_EXCLUSIVE);
300     GST_BUFFER_MEM_PTR (buffer, idx) = mem;
301     idx++;
302     length--;
303   }
304
305   if (end < len) {
306     memmove (&GST_BUFFER_MEM_PTR (buffer, idx),
307         &GST_BUFFER_MEM_PTR (buffer, end), (len - end) * sizeof (gpointer));
308   }
309   GST_BUFFER_MEM_LEN (buffer) = len - length;
310   GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
311 }
312
313 /**
314  * gst_buffer_get_flags:
315  * @buffer: a #GstBuffer
316  *
317  * Get the #GstBufferFlags flags set on this buffer.
318  *
319  * Returns: the flags set on this buffer.
320  *
321  * Since: 1.10
322  */
323 GstBufferFlags
324 gst_buffer_get_flags (GstBuffer * buffer)
325 {
326   return (GstBufferFlags) GST_BUFFER_FLAGS (buffer);
327 }
328
329 /**
330  * gst_buffer_flag_is_set:
331  * @buffer: a #GstBuffer
332  * @flags: the #GstBufferFlags flag to check.
333  *
334  * Gives the status of a specific flag on a buffer.
335  *
336  * Returns: %TRUE if all flags in @flags are found on @buffer.
337  *
338  * Since: 1.10
339  */
340 gboolean
341 gst_buffer_has_flags (GstBuffer * buffer, GstBufferFlags flags)
342 {
343   return GST_BUFFER_FLAG_IS_SET (buffer, flags);
344 }
345
346 /**
347  * gst_buffer_set_flags:
348  * @buffer: a #GstBuffer
349  * @flags: the #GstBufferFlags to set.
350  *
351  * Sets one or more buffer flags on a buffer.
352  *
353  * Returns: %TRUE if @flags were successfully set on buffer.
354  *
355  * Since: 1.10
356  */
357 gboolean
358 gst_buffer_set_flags (GstBuffer * buffer, GstBufferFlags flags)
359 {
360   GST_BUFFER_FLAG_SET (buffer, flags);
361   return TRUE;
362 }
363
364 /**
365  * gst_buffer_unset_flags:
366  * @buffer: a #GstBuffer
367  * @flags: the #GstBufferFlags to clear
368  *
369  * Clears one or more buffer flags.
370  *
371  * Returns: true if @flags is successfully cleared from buffer.
372  *
373  * Since: 1.10
374  */
375 gboolean
376 gst_buffer_unset_flags (GstBuffer * buffer, GstBufferFlags flags)
377 {
378   GST_BUFFER_FLAG_UNSET (buffer, flags);
379   return TRUE;
380 }
381
382
383
384 /* transfer full for return and transfer none for @mem */
385 static inline GstMemory *
386 _memory_get_exclusive_reference (GstMemory * mem)
387 {
388   GstMemory *ret = NULL;
389
390   if (gst_memory_lock (mem, GST_LOCK_FLAG_EXCLUSIVE)) {
391     ret = gst_memory_ref (mem);
392   } else {
393     /* we cannot take another exclusive lock as the memory is already
394      * locked WRITE + EXCLUSIVE according to part-miniobject.txt */
395     ret = gst_memory_copy (mem, 0, -1);
396
397     if (ret) {
398       if (!gst_memory_lock (ret, GST_LOCK_FLAG_EXCLUSIVE)) {
399         gst_memory_unref (ret);
400         ret = NULL;
401       }
402     }
403   }
404
405   if (!ret)
406     GST_CAT_WARNING (GST_CAT_BUFFER, "Failed to acquire an exclusive lock for "
407         "memory %p", mem);
408
409   return ret;
410 }
411
412 static inline void
413 _memory_add (GstBuffer * buffer, gint idx, GstMemory * mem)
414 {
415   guint i, len = GST_BUFFER_MEM_LEN (buffer);
416
417   GST_CAT_LOG (GST_CAT_BUFFER, "buffer %p, idx %d, mem %p", buffer, idx, mem);
418
419   if (G_UNLIKELY (len >= GST_BUFFER_MEM_MAX)) {
420     /* too many buffer, span them. */
421     /* FIXME, there is room for improvement here: We could only try to merge
422      * 2 buffers to make some room. If we can't efficiently merge 2 buffers we
423      * could try to only merge the two smallest buffers to avoid memcpy, etc. */
424     GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "memory array overflow in buffer %p",
425         buffer);
426     _replace_memory (buffer, len, 0, len, _get_merged_memory (buffer, 0, len));
427     /* we now have 1 single spanned buffer */
428     len = 1;
429   }
430
431   if (idx == -1)
432     idx = len;
433
434   for (i = len; i > idx; i--) {
435     /* move buffers to insert, FIXME, we need to insert first and then merge */
436     GST_BUFFER_MEM_PTR (buffer, i) = GST_BUFFER_MEM_PTR (buffer, i - 1);
437   }
438   /* and insert the new buffer */
439   GST_BUFFER_MEM_PTR (buffer, idx) = mem;
440   GST_BUFFER_MEM_LEN (buffer) = len + 1;
441
442   GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
443 }
444
445 GST_DEFINE_MINI_OBJECT_TYPE (GstBuffer, gst_buffer);
446
447 void
448 _priv_gst_buffer_initialize (void)
449 {
450   _gst_buffer_type = gst_buffer_get_type ();
451 }
452
453 /**
454  * gst_buffer_get_max_memory:
455  *
456  * Get the maximum amount of memory blocks that a buffer can hold. This is a
457  * compile time constant that can be queried with the function.
458  *
459  * When more memory blocks are added, existing memory blocks will be merged
460  * together to make room for the new block.
461  *
462  * Returns: the maximum amount of memory blocks that a buffer can hold.
463  *
464  * Since: 1.2
465  */
466 guint
467 gst_buffer_get_max_memory (void)
468 {
469   return GST_BUFFER_MEM_MAX;
470 }
471
472 /**
473  * gst_buffer_copy_into:
474  * @dest: a destination #GstBuffer
475  * @src: a source #GstBuffer
476  * @flags: flags indicating what metadata fields should be copied.
477  * @offset: offset to copy from
478  * @size: total size to copy. If -1, all data is copied.
479  *
480  * Copies the information from @src into @dest.
481  *
482  * If @dest already contains memory and @flags contains GST_BUFFER_COPY_MEMORY,
483  * the memory from @src will be appended to @dest.
484  *
485  * @flags indicate which fields will be copied.
486  *
487  * Returns: %TRUE if the copying succeeded, %FALSE otherwise.
488  */
489 gboolean
490 gst_buffer_copy_into (GstBuffer * dest, GstBuffer * src,
491     GstBufferCopyFlags flags, gsize offset, gsize size)
492 {
493   GstMetaItem *walk;
494   gsize bufsize;
495   gboolean region = FALSE;
496
497   g_return_val_if_fail (dest != NULL, FALSE);
498   g_return_val_if_fail (src != NULL, FALSE);
499
500   /* nothing to copy if the buffers are the same */
501   if (G_UNLIKELY (dest == src))
502     return TRUE;
503
504   g_return_val_if_fail (gst_buffer_is_writable (dest), FALSE);
505
506   bufsize = gst_buffer_get_size (src);
507   g_return_val_if_fail (bufsize >= offset, FALSE);
508   if (offset > 0)
509     region = TRUE;
510   if (size == -1)
511     size = bufsize - offset;
512   if (size < bufsize)
513     region = TRUE;
514   g_return_val_if_fail (bufsize >= offset + size, FALSE);
515
516   GST_CAT_LOG (GST_CAT_BUFFER, "copy %p to %p, offset %" G_GSIZE_FORMAT
517       "-%" G_GSIZE_FORMAT "/%" G_GSIZE_FORMAT, src, dest, offset, size,
518       bufsize);
519
520   if (flags & GST_BUFFER_COPY_FLAGS) {
521     /* copy flags */
522     guint flags_mask = ~GST_BUFFER_FLAG_TAG_MEMORY;
523
524     GST_MINI_OBJECT_FLAGS (dest) =
525         (GST_MINI_OBJECT_FLAGS (src) & flags_mask) |
526         (GST_MINI_OBJECT_FLAGS (dest) & ~flags_mask);
527   }
528
529   if (flags & GST_BUFFER_COPY_TIMESTAMPS) {
530     if (offset == 0) {
531       GST_BUFFER_PTS (dest) = GST_BUFFER_PTS (src);
532       GST_BUFFER_DTS (dest) = GST_BUFFER_DTS (src);
533       GST_BUFFER_OFFSET (dest) = GST_BUFFER_OFFSET (src);
534       if (size == bufsize) {
535         GST_BUFFER_DURATION (dest) = GST_BUFFER_DURATION (src);
536         GST_BUFFER_OFFSET_END (dest) = GST_BUFFER_OFFSET_END (src);
537       }
538     } else {
539       GST_BUFFER_PTS (dest) = GST_CLOCK_TIME_NONE;
540       GST_BUFFER_DTS (dest) = GST_CLOCK_TIME_NONE;
541       GST_BUFFER_DURATION (dest) = GST_CLOCK_TIME_NONE;
542       GST_BUFFER_OFFSET (dest) = GST_BUFFER_OFFSET_NONE;
543       GST_BUFFER_OFFSET_END (dest) = GST_BUFFER_OFFSET_NONE;
544     }
545   }
546
547   if (flags & GST_BUFFER_COPY_MEMORY) {
548     gsize skip, left, len, dest_len, i, bsize;
549     gboolean deep;
550
551     deep = flags & GST_BUFFER_COPY_DEEP;
552
553     len = GST_BUFFER_MEM_LEN (src);
554     dest_len = GST_BUFFER_MEM_LEN (dest);
555     left = size;
556     skip = offset;
557
558     /* copy and make regions of the memory */
559     for (i = 0; i < len && left > 0; i++) {
560       GstMemory *mem = GST_BUFFER_MEM_PTR (src, i);
561
562       bsize = gst_memory_get_sizes (mem, NULL, NULL);
563
564       if (bsize <= skip) {
565         /* don't copy buffer */
566         skip -= bsize;
567       } else {
568         GstMemory *newmem = NULL;
569         gsize tocopy;
570
571         tocopy = MIN (bsize - skip, left);
572
573         if (tocopy < bsize && !deep && !GST_MEMORY_IS_NO_SHARE (mem)) {
574           /* we need to clip something */
575           newmem = gst_memory_share (mem, skip, tocopy);
576           if (newmem) {
577             gst_memory_lock (newmem, GST_LOCK_FLAG_EXCLUSIVE);
578             skip = 0;
579           }
580         }
581
582         if (deep || GST_MEMORY_IS_NO_SHARE (mem) || (!newmem && tocopy < bsize)) {
583           /* deep copy or we're not allowed to share this memory
584            * between buffers, always copy then */
585           newmem = gst_memory_copy (mem, skip, tocopy);
586           if (newmem) {
587             gst_memory_lock (newmem, GST_LOCK_FLAG_EXCLUSIVE);
588             skip = 0;
589           }
590         } else if (!newmem) {
591           newmem = _memory_get_exclusive_reference (mem);
592         }
593
594         if (!newmem) {
595           gst_buffer_remove_memory_range (dest, dest_len, -1);
596           return FALSE;
597         }
598
599         _memory_add (dest, -1, newmem);
600         left -= tocopy;
601       }
602     }
603     if (flags & GST_BUFFER_COPY_MERGE) {
604       GstMemory *mem;
605
606       len = GST_BUFFER_MEM_LEN (dest);
607       mem = _get_merged_memory (dest, 0, len);
608       if (!mem) {
609         gst_buffer_remove_memory_range (dest, dest_len, -1);
610         return FALSE;
611       }
612       _replace_memory (dest, len, 0, len, mem);
613     }
614   }
615
616   if (flags & GST_BUFFER_COPY_META) {
617     /* NOTE: GstGLSyncMeta copying relies on the meta
618      *       being copied now, after the buffer data,
619      *       so this has to happen last */
620     for (walk = GST_BUFFER_META (src); walk; walk = walk->next) {
621       GstMeta *meta = &walk->meta;
622       const GstMetaInfo *info = meta->info;
623
624       /* Don't copy memory metas if we only copied part of the buffer, didn't
625        * copy memories or merged memories. In all these cases the memory
626        * structure has changed and the memory meta becomes meaningless.
627        */
628       if ((region || !(flags & GST_BUFFER_COPY_MEMORY)
629               || (flags & GST_BUFFER_COPY_MERGE))
630           && gst_meta_api_type_has_tag (info->api, _gst_meta_tag_memory)) {
631         GST_CAT_DEBUG (GST_CAT_BUFFER,
632             "don't copy memory meta %p of API type %s", meta,
633             g_type_name (info->api));
634       } else if (info->transform_func) {
635         GstMetaTransformCopy copy_data;
636
637         copy_data.region = region;
638         copy_data.offset = offset;
639         copy_data.size = size;
640
641         if (!info->transform_func (dest, meta, src,
642                 _gst_meta_transform_copy, &copy_data)) {
643           GST_CAT_ERROR (GST_CAT_BUFFER,
644               "failed to copy meta %p of API type %s", meta,
645               g_type_name (info->api));
646         }
647       }
648     }
649   }
650
651   return TRUE;
652 }
653
654 static GstBuffer *
655 gst_buffer_copy_with_flags (const GstBuffer * buffer, GstBufferCopyFlags flags)
656 {
657   GstBuffer *copy;
658
659   g_return_val_if_fail (buffer != NULL, NULL);
660
661   /* create a fresh new buffer */
662   copy = gst_buffer_new ();
663
664   /* copy what the 'flags' want from our parent */
665   /* FIXME why we can't pass const to gst_buffer_copy_into() ? */
666   if (!gst_buffer_copy_into (copy, (GstBuffer *) buffer, flags, 0, -1))
667     gst_buffer_replace (&copy, NULL);
668
669   if (copy)
670     GST_BUFFER_FLAG_UNSET (copy, GST_BUFFER_FLAG_TAG_MEMORY);
671
672   return copy;
673 }
674
675 static GstBuffer *
676 _gst_buffer_copy (const GstBuffer * buffer)
677 {
678   return gst_buffer_copy_with_flags (buffer, GST_BUFFER_COPY_ALL);
679 }
680
681 /**
682  * gst_buffer_copy_deep:
683  * @buf: a #GstBuffer.
684  *
685  * Create a copy of the given buffer. This will make a newly allocated
686  * copy of the data the source buffer contains.
687  *
688  * Returns: (transfer full): a new copy of @buf.
689  *
690  * Since: 1.6
691  */
692 GstBuffer *
693 gst_buffer_copy_deep (const GstBuffer * buffer)
694 {
695   return gst_buffer_copy_with_flags (buffer,
696       GST_BUFFER_COPY_ALL | GST_BUFFER_COPY_DEEP);
697 }
698
699 /* the default dispose function revives the buffer and returns it to the
700  * pool when there is a pool */
701 static gboolean
702 _gst_buffer_dispose (GstBuffer * buffer)
703 {
704   GstBufferPool *pool;
705
706   /* no pool, do free */
707   if ((pool = buffer->pool) == NULL)
708     return TRUE;
709
710   /* keep the buffer alive */
711   gst_buffer_ref (buffer);
712   /* return the buffer to the pool */
713   GST_CAT_LOG (GST_CAT_BUFFER, "release %p to pool %p", buffer, pool);
714   gst_buffer_pool_release_buffer (pool, buffer);
715
716   return FALSE;
717 }
718
719 static void
720 _gst_buffer_free (GstBuffer * buffer)
721 {
722   GstMetaItem *walk, *next;
723   guint i, len;
724   gsize msize;
725
726   g_return_if_fail (buffer != NULL);
727
728   GST_CAT_LOG (GST_CAT_BUFFER, "finalize %p", buffer);
729
730   /* free metadata */
731   for (walk = GST_BUFFER_META (buffer); walk; walk = next) {
732     GstMeta *meta = &walk->meta;
733     const GstMetaInfo *info = meta->info;
734
735     /* call free_func if any */
736     if (info->free_func)
737       info->free_func (meta, buffer);
738
739     next = walk->next;
740     /* and free the slice */
741     g_slice_free1 (ITEM_SIZE (info), walk);
742   }
743
744   /* get the size, when unreffing the memory, we could also unref the buffer
745    * itself */
746   msize = GST_BUFFER_SLICE_SIZE (buffer);
747
748   /* free our memory */
749   len = GST_BUFFER_MEM_LEN (buffer);
750   for (i = 0; i < len; i++) {
751     gst_memory_unlock (GST_BUFFER_MEM_PTR (buffer, i), GST_LOCK_FLAG_EXCLUSIVE);
752     gst_memory_unref (GST_BUFFER_MEM_PTR (buffer, i));
753   }
754
755   /* we set msize to 0 when the buffer is part of the memory block */
756   if (msize) {
757 #ifdef USE_POISONING
758     memset (buffer, 0xff, msize);
759 #endif
760     g_slice_free1 (msize, buffer);
761   } else {
762     gst_memory_unref (GST_BUFFER_BUFMEM (buffer));
763   }
764 }
765
766 static void
767 gst_buffer_init (GstBufferImpl * buffer, gsize size)
768 {
769   gst_mini_object_init (GST_MINI_OBJECT_CAST (buffer), 0, _gst_buffer_type,
770       (GstMiniObjectCopyFunction) _gst_buffer_copy,
771       (GstMiniObjectDisposeFunction) _gst_buffer_dispose,
772       (GstMiniObjectFreeFunction) _gst_buffer_free);
773
774   GST_BUFFER_SLICE_SIZE (buffer) = size;
775
776   GST_BUFFER (buffer)->pool = NULL;
777   GST_BUFFER_PTS (buffer) = GST_CLOCK_TIME_NONE;
778   GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE;
779   GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
780   GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
781   GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE;
782
783   GST_BUFFER_MEM_LEN (buffer) = 0;
784   GST_BUFFER_META (buffer) = NULL;
785 }
786
787 /**
788  * gst_buffer_new:
789  *
790  * Creates a newly allocated buffer without any data.
791  *
792  * MT safe.
793  *
794  * Returns: (transfer full): the new #GstBuffer.
795  */
796 GstBuffer *
797 gst_buffer_new (void)
798 {
799   GstBufferImpl *newbuf;
800
801   newbuf = g_slice_new (GstBufferImpl);
802   GST_CAT_LOG (GST_CAT_BUFFER, "new %p", newbuf);
803
804   gst_buffer_init (newbuf, sizeof (GstBufferImpl));
805
806   return GST_BUFFER_CAST (newbuf);
807 }
808
809 /**
810  * gst_buffer_new_allocate:
811  * @allocator: (transfer none) (allow-none): the #GstAllocator to use, or %NULL to use the
812  *     default allocator
813  * @size: the size in bytes of the new buffer's data.
814  * @params: (transfer none) (allow-none): optional parameters
815  *
816  * Tries to create a newly allocated buffer with data of the given size and
817  * extra parameters from @allocator. If the requested amount of memory can't be
818  * allocated, %NULL will be returned. The allocated buffer memory is not cleared.
819  *
820  * When @allocator is %NULL, the default memory allocator will be used.
821  *
822  * Note that when @size == 0, the buffer will not have memory associated with it.
823  *
824  * MT safe.
825  *
826  * Returns: (transfer full) (nullable): a new #GstBuffer, or %NULL if
827  *     the memory couldn't be allocated.
828  */
829 GstBuffer *
830 gst_buffer_new_allocate (GstAllocator * allocator, gsize size,
831     GstAllocationParams * params)
832 {
833   GstBuffer *newbuf;
834   GstMemory *mem;
835 #if 0
836   guint8 *data;
837   gsize asize;
838 #endif
839
840 #if 1
841   if (size > 0) {
842     mem = gst_allocator_alloc (allocator, size, params);
843     if (G_UNLIKELY (mem == NULL))
844       goto no_memory;
845   } else {
846     mem = NULL;
847   }
848
849   newbuf = gst_buffer_new ();
850
851   if (mem != NULL) {
852     gst_memory_lock (mem, GST_LOCK_FLAG_EXCLUSIVE);
853     _memory_add (newbuf, -1, mem);
854   }
855
856   GST_CAT_LOG (GST_CAT_BUFFER,
857       "new buffer %p of size %" G_GSIZE_FORMAT " from allocator %p", newbuf,
858       size, allocator);
859 #endif
860
861 #if 0
862   asize = sizeof (GstBufferImpl) + size;
863   data = g_slice_alloc (asize);
864   if (G_UNLIKELY (data == NULL))
865     goto no_memory;
866
867   newbuf = GST_BUFFER_CAST (data);
868
869   gst_buffer_init ((GstBufferImpl *) data, asize);
870   if (size > 0) {
871     mem = gst_memory_new_wrapped (0, data + sizeof (GstBufferImpl), NULL,
872         size, 0, size);
873     _memory_add (newbuf, -1, mem, TRUE);
874   }
875 #endif
876
877 #if 0
878   /* allocate memory and buffer, it might be interesting to do this but there
879    * are many complications. We need to keep the memory mapped to access the
880    * buffer fields and the memory for the buffer might be just very slow. We
881    * also need to do some more magic to get the alignment right. */
882   asize = sizeof (GstBufferImpl) + size;
883   mem = gst_allocator_alloc (allocator, asize, align);
884   if (G_UNLIKELY (mem == NULL))
885     goto no_memory;
886
887   /* map the data part and init the buffer in it, set the buffer size to 0 so
888    * that a finalize won't free the buffer */
889   data = gst_memory_map (mem, &asize, NULL, GST_MAP_WRITE);
890   gst_buffer_init ((GstBufferImpl *) data, 0);
891   gst_memory_unmap (mem);
892
893   /* strip off the buffer */
894   gst_memory_resize (mem, sizeof (GstBufferImpl), size);
895
896   newbuf = GST_BUFFER_CAST (data);
897   GST_BUFFER_BUFMEM (newbuf) = mem;
898
899   if (size > 0)
900     _memory_add (newbuf, -1, gst_memory_ref (mem), TRUE);
901 #endif
902   GST_BUFFER_FLAG_UNSET (newbuf, GST_BUFFER_FLAG_TAG_MEMORY);
903
904   return newbuf;
905
906   /* ERRORS */
907 no_memory:
908   {
909     GST_CAT_WARNING (GST_CAT_BUFFER,
910         "failed to allocate %" G_GSIZE_FORMAT " bytes", size);
911     return NULL;
912   }
913 }
914
915 /**
916  * gst_buffer_new_wrapped_full:
917  * @flags: #GstMemoryFlags
918  * @data: (array length=size) (element-type guint8) (transfer none): data to wrap
919  * @maxsize: allocated size of @data
920  * @offset: offset in @data
921  * @size: size of valid data
922  * @user_data: (allow-none): user_data
923  * @notify: (allow-none) (scope async) (closure user_data): called with @user_data when the memory is freed
924  *
925  * Allocate a new buffer that wraps the given memory. @data must point to
926  * @maxsize of memory, the wrapped buffer will have the region from @offset and
927  * @size visible.
928  *
929  * When the buffer is destroyed, @notify will be called with @user_data.
930  *
931  * The prefix/padding must be filled with 0 if @flags contains
932  * #GST_MEMORY_FLAG_ZERO_PREFIXED and #GST_MEMORY_FLAG_ZERO_PADDED respectively.
933  *
934  * Returns: (transfer full): a new #GstBuffer
935  */
936 GstBuffer *
937 gst_buffer_new_wrapped_full (GstMemoryFlags flags, gpointer data,
938     gsize maxsize, gsize offset, gsize size, gpointer user_data,
939     GDestroyNotify notify)
940 {
941   GstMemory *mem;
942   GstBuffer *newbuf;
943
944   newbuf = gst_buffer_new ();
945   mem =
946       gst_memory_new_wrapped (flags, data, maxsize, offset, size, user_data,
947       notify);
948   gst_memory_lock (mem, GST_LOCK_FLAG_EXCLUSIVE);
949   _memory_add (newbuf, -1, mem);
950   GST_BUFFER_FLAG_UNSET (newbuf, GST_BUFFER_FLAG_TAG_MEMORY);
951
952   return newbuf;
953 }
954
955 /**
956  * gst_buffer_new_wrapped:
957  * @data: (array length=size) (element-type guint8) (transfer full): data to wrap
958  * @size: allocated size of @data
959  *
960  * Creates a new buffer that wraps the given @data. The memory will be freed
961  * with g_free and will be marked writable.
962  *
963  * MT safe.
964  *
965  * Returns: (transfer full): a new #GstBuffer
966  */
967 GstBuffer *
968 gst_buffer_new_wrapped (gpointer data, gsize size)
969 {
970   return gst_buffer_new_wrapped_full (0, data, size, 0, size, data, g_free);
971 }
972
973 /**
974  * gst_buffer_n_memory:
975  * @buffer: a #GstBuffer.
976  *
977  * Get the amount of memory blocks that this buffer has. This amount is never
978  * larger than what gst_buffer_get_max_memory() returns.
979  *
980  * Returns: the number of memory blocks this buffer is made of.
981  */
982 guint
983 gst_buffer_n_memory (GstBuffer * buffer)
984 {
985   g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
986
987   return GST_BUFFER_MEM_LEN (buffer);
988 }
989
990 /**
991  * gst_buffer_prepend_memory:
992  * @buffer: a #GstBuffer.
993  * @mem: (transfer full): a #GstMemory.
994  *
995  * Prepend the memory block @mem to @buffer. This function takes
996  * ownership of @mem and thus doesn't increase its refcount.
997  *
998  * This function is identical to gst_buffer_insert_memory() with an index of 0.
999  * See gst_buffer_insert_memory() for more details.
1000  */
1001 void
1002 gst_buffer_prepend_memory (GstBuffer * buffer, GstMemory * mem)
1003 {
1004   gst_buffer_insert_memory (buffer, 0, mem);
1005 }
1006
1007 /**
1008  * gst_buffer_append_memory:
1009  * @buffer: a #GstBuffer.
1010  * @mem: (transfer full): a #GstMemory.
1011  *
1012  * Append the memory block @mem to @buffer. This function takes
1013  * ownership of @mem and thus doesn't increase its refcount.
1014  *
1015  * This function is identical to gst_buffer_insert_memory() with an index of -1.
1016  * See gst_buffer_insert_memory() for more details.
1017  */
1018 void
1019 gst_buffer_append_memory (GstBuffer * buffer, GstMemory * mem)
1020 {
1021   gst_buffer_insert_memory (buffer, -1, mem);
1022 }
1023
1024 /**
1025  * gst_buffer_insert_memory:
1026  * @buffer: a #GstBuffer.
1027  * @idx: the index to add the memory at, or -1 to append it to the end
1028  * @mem: (transfer full): a #GstMemory.
1029  *
1030  * Insert the memory block @mem to @buffer at @idx. This function takes ownership
1031  * of @mem and thus doesn't increase its refcount.
1032  *
1033  * Only gst_buffer_get_max_memory() can be added to a buffer. If more memory is
1034  * added, existing memory blocks will automatically be merged to make room for
1035  * the new memory.
1036  */
1037 void
1038 gst_buffer_insert_memory (GstBuffer * buffer, gint idx, GstMemory * mem)
1039 {
1040   GstMemory *tmp;
1041
1042   g_return_if_fail (GST_IS_BUFFER (buffer));
1043   g_return_if_fail (gst_buffer_is_writable (buffer));
1044   g_return_if_fail (mem != NULL);
1045   g_return_if_fail (idx == -1 ||
1046       (idx >= 0 && idx <= GST_BUFFER_MEM_LEN (buffer)));
1047
1048   tmp = _memory_get_exclusive_reference (mem);
1049   g_return_if_fail (tmp != NULL);
1050   gst_memory_unref (mem);
1051   _memory_add (buffer, idx, tmp);
1052 }
1053
1054 static GstMemory *
1055 _get_mapped (GstBuffer * buffer, guint idx, GstMapInfo * info,
1056     GstMapFlags flags)
1057 {
1058   GstMemory *mem, *mapped;
1059
1060   mem = gst_memory_ref (GST_BUFFER_MEM_PTR (buffer, idx));
1061
1062   mapped = gst_memory_make_mapped (mem, info, flags);
1063
1064   if (mapped != mem) {
1065     /* memory changed, lock new memory */
1066     gst_memory_lock (mapped, GST_LOCK_FLAG_EXCLUSIVE);
1067     GST_BUFFER_MEM_PTR (buffer, idx) = mapped;
1068     /* unlock old memory */
1069     gst_memory_unlock (mem, GST_LOCK_FLAG_EXCLUSIVE);
1070     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
1071   }
1072   gst_memory_unref (mem);
1073
1074   return mapped;
1075 }
1076
1077 /**
1078  * gst_buffer_peek_memory:
1079  * @buffer: a #GstBuffer.
1080  * @idx: an index
1081  *
1082  * Get the memory block at @idx in @buffer. The memory block stays valid until
1083  * the memory block in @buffer is removed, replaced or merged, typically with
1084  * any call that modifies the memory in @buffer.
1085  *
1086  * Returns: (transfer none) (nullable): the #GstMemory at @idx.
1087  */
1088 GstMemory *
1089 gst_buffer_peek_memory (GstBuffer * buffer, guint idx)
1090 {
1091   guint len;
1092
1093   g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
1094   len = GST_BUFFER_MEM_LEN (buffer);
1095   g_return_val_if_fail (idx < len, NULL);
1096
1097   return GST_BUFFER_MEM_PTR (buffer, idx);
1098 }
1099
1100 /**
1101  * gst_buffer_get_memory:
1102  * @buffer: a #GstBuffer.
1103  * @idx: an index
1104  *
1105  * Get the memory block at index @idx in @buffer.
1106  *
1107  * Returns: (transfer full) (nullable): a #GstMemory that contains the data of the
1108  * memory block at @idx. Use gst_memory_unref () after usage.
1109  */
1110 GstMemory *
1111 gst_buffer_get_memory (GstBuffer * buffer, guint idx)
1112 {
1113   return gst_buffer_get_memory_range (buffer, idx, 1);
1114 }
1115
1116 /**
1117  * gst_buffer_get_all_memory:
1118  * @buffer: a #GstBuffer.
1119  *
1120  * Get all the memory block in @buffer. The memory blocks will be merged
1121  * into one large #GstMemory.
1122  *
1123  * Returns: (transfer full) (nullable): a #GstMemory that contains the merged memory.
1124  * Use gst_memory_unref () after usage.
1125  */
1126 GstMemory *
1127 gst_buffer_get_all_memory (GstBuffer * buffer)
1128 {
1129   return gst_buffer_get_memory_range (buffer, 0, -1);
1130 }
1131
1132 /**
1133  * gst_buffer_get_memory_range:
1134  * @buffer: a #GstBuffer.
1135  * @idx: an index
1136  * @length: a length
1137  *
1138  * Get @length memory blocks in @buffer starting at @idx. The memory blocks will
1139  * be merged into one large #GstMemory.
1140  *
1141  * If @length is -1, all memory starting from @idx is merged.
1142  *
1143  * Returns: (transfer full) (nullable): a #GstMemory that contains the merged data of @length
1144  *    blocks starting at @idx. Use gst_memory_unref () after usage.
1145  */
1146 GstMemory *
1147 gst_buffer_get_memory_range (GstBuffer * buffer, guint idx, gint length)
1148 {
1149   guint len;
1150
1151   GST_CAT_DEBUG (GST_CAT_BUFFER, "idx %u, length %d", idx, length);
1152
1153   g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
1154   len = GST_BUFFER_MEM_LEN (buffer);
1155   g_return_val_if_fail ((len == 0 && idx == 0 && length == -1) ||
1156       (length == -1 && idx < len) || (length > 0 && length + idx <= len), NULL);
1157
1158   if (length == -1)
1159     length = len - idx;
1160
1161   return _get_merged_memory (buffer, idx, length);
1162 }
1163
1164 /**
1165  * gst_buffer_replace_memory:
1166  * @buffer: a #GstBuffer.
1167  * @idx: an index
1168  * @mem: (transfer full): a #GstMemory
1169  *
1170  * Replaces the memory block at index @idx in @buffer with @mem.
1171  */
1172 void
1173 gst_buffer_replace_memory (GstBuffer * buffer, guint idx, GstMemory * mem)
1174 {
1175   gst_buffer_replace_memory_range (buffer, idx, 1, mem);
1176 }
1177
1178 /**
1179  * gst_buffer_replace_all_memory:
1180  * @buffer: a #GstBuffer.
1181  * @mem: (transfer full): a #GstMemory
1182  *
1183  * Replaces all memory in @buffer with @mem.
1184  */
1185 void
1186 gst_buffer_replace_all_memory (GstBuffer * buffer, GstMemory * mem)
1187 {
1188   gst_buffer_replace_memory_range (buffer, 0, -1, mem);
1189 }
1190
1191 /**
1192  * gst_buffer_replace_memory_range:
1193  * @buffer: a #GstBuffer.
1194  * @idx: an index
1195  * @length: a length should not be 0
1196  * @mem: (transfer full): a #GstMemory
1197  *
1198  * Replaces @length memory blocks in @buffer starting at @idx with @mem.
1199  *
1200  * If @length is -1, all memory starting from @idx will be removed and
1201  * replaced with @mem.
1202  *
1203  * @buffer should be writable.
1204  */
1205 void
1206 gst_buffer_replace_memory_range (GstBuffer * buffer, guint idx, gint length,
1207     GstMemory * mem)
1208 {
1209   guint len;
1210
1211   g_return_if_fail (GST_IS_BUFFER (buffer));
1212   g_return_if_fail (gst_buffer_is_writable (buffer));
1213
1214   GST_CAT_DEBUG (GST_CAT_BUFFER, "idx %u, length %d, %p", idx, length, mem);
1215
1216   len = GST_BUFFER_MEM_LEN (buffer);
1217   g_return_if_fail ((len == 0 && idx == 0 && length == -1) ||
1218       (length == -1 && idx < len) || (length > 0 && length + idx <= len));
1219
1220   if (length == -1)
1221     length = len - idx;
1222
1223   _replace_memory (buffer, len, idx, length, mem);
1224 }
1225
1226 /**
1227  * gst_buffer_remove_memory:
1228  * @buffer: a #GstBuffer.
1229  * @idx: an index
1230  *
1231  * Remove the memory block in @b at index @i.
1232  */
1233 void
1234 gst_buffer_remove_memory (GstBuffer * buffer, guint idx)
1235 {
1236   gst_buffer_remove_memory_range (buffer, idx, 1);
1237 }
1238
1239 /**
1240  * gst_buffer_remove_all_memory:
1241  * @buffer: a #GstBuffer.
1242  *
1243  * Remove all the memory blocks in @buffer.
1244  */
1245 void
1246 gst_buffer_remove_all_memory (GstBuffer * buffer)
1247 {
1248   gst_buffer_remove_memory_range (buffer, 0, -1);
1249 }
1250
1251 /**
1252  * gst_buffer_remove_memory_range:
1253  * @buffer: a #GstBuffer.
1254  * @idx: an index
1255  * @length: a length
1256  *
1257  * Remove @length memory blocks in @buffer starting from @idx.
1258  *
1259  * @length can be -1, in which case all memory starting from @idx is removed.
1260  */
1261 void
1262 gst_buffer_remove_memory_range (GstBuffer * buffer, guint idx, gint length)
1263 {
1264   guint len;
1265
1266   g_return_if_fail (GST_IS_BUFFER (buffer));
1267   g_return_if_fail (gst_buffer_is_writable (buffer));
1268
1269   GST_CAT_DEBUG (GST_CAT_BUFFER, "idx %u, length %d", idx, length);
1270
1271   len = GST_BUFFER_MEM_LEN (buffer);
1272   g_return_if_fail ((len == 0 && idx == 0 && length == -1) ||
1273       (length == -1 && idx < len) || length + idx <= len);
1274
1275   if (length == -1)
1276     length = len - idx;
1277
1278   _replace_memory (buffer, len, idx, length, NULL);
1279 }
1280
1281 /**
1282  * gst_buffer_find_memory:
1283  * @buffer: a #GstBuffer.
1284  * @offset: an offset
1285  * @size: a size
1286  * @idx: (out): pointer to index
1287  * @length: (out): pointer to length
1288  * @skip: (out): pointer to skip
1289  *
1290  * Find the memory blocks that span @size bytes starting from @offset
1291  * in @buffer.
1292  *
1293  * When this function returns %TRUE, @idx will contain the index of the first
1294  * memory block where the byte for @offset can be found and @length contains the
1295  * number of memory blocks containing the @size remaining bytes. @skip contains
1296  * the number of bytes to skip in the memory block at @idx to get to the byte
1297  * for @offset.
1298  *
1299  * @size can be -1 to get all the memory blocks after @idx.
1300  *
1301  * Returns: %TRUE when @size bytes starting from @offset could be found in
1302  * @buffer and @idx, @length and @skip will be filled.
1303  */
1304 gboolean
1305 gst_buffer_find_memory (GstBuffer * buffer, gsize offset, gsize size,
1306     guint * idx, guint * length, gsize * skip)
1307 {
1308   guint i, len, found;
1309
1310   g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
1311   g_return_val_if_fail (idx != NULL, FALSE);
1312   g_return_val_if_fail (length != NULL, FALSE);
1313   g_return_val_if_fail (skip != NULL, FALSE);
1314
1315   len = GST_BUFFER_MEM_LEN (buffer);
1316
1317   found = 0;
1318   for (i = 0; i < len; i++) {
1319     GstMemory *mem;
1320     gsize s;
1321
1322     mem = GST_BUFFER_MEM_PTR (buffer, i);
1323     s = gst_memory_get_sizes (mem, NULL, NULL);
1324
1325     if (s <= offset) {
1326       /* block before offset, or empty block, skip */
1327       offset -= s;
1328     } else {
1329       /* block after offset */
1330       if (found == 0) {
1331         /* first block, remember index and offset */
1332         *idx = i;
1333         *skip = offset;
1334         if (size == -1) {
1335           /* return remaining blocks */
1336           *length = len - i;
1337           return TRUE;
1338         }
1339         s -= offset;
1340         offset = 0;
1341       }
1342       /* count the amount of found bytes */
1343       found += s;
1344       if (found >= size) {
1345         /* we have enough bytes */
1346         *length = i - *idx + 1;
1347         return TRUE;
1348       }
1349     }
1350   }
1351   return FALSE;
1352 }
1353
1354 /**
1355  * gst_buffer_is_memory_range_writable:
1356  * @buffer: a #GstBuffer.
1357  * @idx: an index
1358  * @length: a length should not be 0
1359  *
1360  * Check if @length memory blocks in @buffer starting from @idx are writable.
1361  *
1362  * @length can be -1 to check all the memory blocks after @idx.
1363  *
1364  * Note that this function does not check if @buffer is writable, use
1365  * gst_buffer_is_writable() to check that if needed.
1366  *
1367  * Returns: %TRUE if the memory range is writable
1368  *
1369  * Since: 1.4
1370  */
1371 gboolean
1372 gst_buffer_is_memory_range_writable (GstBuffer * buffer, guint idx, gint length)
1373 {
1374   guint i, len;
1375
1376   g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
1377
1378   GST_CAT_DEBUG (GST_CAT_BUFFER, "idx %u, length %d", idx, length);
1379
1380   len = GST_BUFFER_MEM_LEN (buffer);
1381   g_return_val_if_fail ((len == 0 && idx == 0 && length == -1) ||
1382       (length == -1 && idx < len) || (length > 0 && length + idx <= len),
1383       FALSE);
1384
1385   if (length == -1)
1386     len -= idx;
1387   else
1388     len = length;
1389
1390   for (i = 0; i < len; i++) {
1391     if (!gst_memory_is_writable (GST_BUFFER_MEM_PTR (buffer, i + idx)))
1392       return FALSE;
1393   }
1394   return TRUE;
1395 }
1396
1397 /**
1398  * gst_buffer_is_all_memory_writable:
1399  * @buffer: a #GstBuffer.
1400  *
1401  * Check if all memory blocks in @buffer are writable.
1402  *
1403  * Note that this function does not check if @buffer is writable, use
1404  * gst_buffer_is_writable() to check that if needed.
1405  *
1406  * Returns: %TRUE if all memory blocks in @buffer are writable
1407  *
1408  * Since: 1.4
1409  */
1410 gboolean
1411 gst_buffer_is_all_memory_writable (GstBuffer * buffer)
1412 {
1413   return gst_buffer_is_memory_range_writable (buffer, 0, -1);
1414 }
1415
1416 /**
1417  * gst_buffer_get_sizes:
1418  * @buffer: a #GstBuffer.
1419  * @offset: (out) (allow-none): a pointer to the offset
1420  * @maxsize: (out) (allow-none): a pointer to the maxsize
1421  *
1422  * Get the total size of the memory blocks in @b.
1423  *
1424  * When not %NULL, @offset will contain the offset of the data in the
1425  * first memory block in @buffer and @maxsize will contain the sum of
1426  * the size and @offset and the amount of extra padding on the last
1427  * memory block.  @offset and @maxsize can be used to resize the
1428  * buffer memory blocks with gst_buffer_resize().
1429  *
1430  * Returns: total size of the memory blocks in @buffer.
1431  */
1432 gsize
1433 gst_buffer_get_sizes (GstBuffer * buffer, gsize * offset, gsize * maxsize)
1434 {
1435   return gst_buffer_get_sizes_range (buffer, 0, -1, offset, maxsize);
1436 }
1437
1438 /**
1439  * gst_buffer_get_size:
1440  * @buffer: a #GstBuffer.
1441  *
1442  * Get the total size of the memory blocks in @buffer.
1443  *
1444  * Returns: total size of the memory blocks in @buffer.
1445  */
1446 gsize
1447 gst_buffer_get_size (GstBuffer * buffer)
1448 {
1449   return gst_buffer_get_sizes_range (buffer, 0, -1, NULL, NULL);
1450 }
1451
1452 /**
1453  * gst_buffer_get_sizes_range:
1454  * @buffer: a #GstBuffer.
1455  * @idx: an index
1456  * @length: a length
1457  * @offset: (out) (allow-none): a pointer to the offset
1458  * @maxsize: (out) (allow-none): a pointer to the maxsize
1459  *
1460  * Get the total size of @length memory blocks stating from @idx in @buffer.
1461  *
1462  * When not %NULL, @offset will contain the offset of the data in the
1463  * memory block in @buffer at @idx and @maxsize will contain the sum of the size
1464  * and @offset and the amount of extra padding on the memory block at @idx +
1465  * @length -1.
1466  * @offset and @maxsize can be used to resize the buffer memory blocks with
1467  * gst_buffer_resize_range().
1468  *
1469  * Returns: total size of @length memory blocks starting at @idx in @buffer.
1470  */
1471 gsize
1472 gst_buffer_get_sizes_range (GstBuffer * buffer, guint idx, gint length,
1473     gsize * offset, gsize * maxsize)
1474 {
1475   guint len;
1476   gsize size;
1477   GstMemory *mem;
1478
1479   g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
1480   len = GST_BUFFER_MEM_LEN (buffer);
1481   g_return_val_if_fail ((len == 0 && idx == 0 && length == -1) ||
1482       (length == -1 && idx < len) || (length + idx <= len), 0);
1483
1484   if (length == -1)
1485     length = len - idx;
1486
1487   if (G_LIKELY (length == 1)) {
1488     /* common case */
1489     mem = GST_BUFFER_MEM_PTR (buffer, idx);
1490     size = gst_memory_get_sizes (mem, offset, maxsize);
1491   } else {
1492     guint i, end;
1493     gsize extra, offs;
1494
1495     end = idx + length;
1496     size = offs = extra = 0;
1497     for (i = idx; i < end; i++) {
1498       gsize s, o, ms;
1499
1500       mem = GST_BUFFER_MEM_PTR (buffer, i);
1501       s = gst_memory_get_sizes (mem, &o, &ms);
1502
1503       if (s) {
1504         if (size == 0)
1505           /* first size, take accumulated data before as the offset */
1506           offs = extra + o;
1507         /* add sizes */
1508         size += s;
1509         /* save the amount of data after this block */
1510         extra = ms - (o + s);
1511       } else {
1512         /* empty block, add as extra */
1513         extra += ms;
1514       }
1515     }
1516     if (offset)
1517       *offset = offs;
1518     if (maxsize)
1519       *maxsize = offs + size + extra;
1520   }
1521   return size;
1522 }
1523
1524 /**
1525  * gst_buffer_resize:
1526  * @buffer: a #GstBuffer.
1527  * @offset: the offset adjustment
1528  * @size: the new size or -1 to just adjust the offset
1529  *
1530  * Set the offset and total size of the memory blocks in @buffer.
1531  */
1532 void
1533 gst_buffer_resize (GstBuffer * buffer, gssize offset, gssize size)
1534 {
1535   gst_buffer_resize_range (buffer, 0, -1, offset, size);
1536 }
1537
1538 /**
1539  * gst_buffer_set_size:
1540  * @buffer: a #GstBuffer.
1541  * @size: the new size
1542  *
1543  * Set the total size of the memory blocks in @buffer.
1544  */
1545 void
1546 gst_buffer_set_size (GstBuffer * buffer, gssize size)
1547 {
1548   gst_buffer_resize_range (buffer, 0, -1, 0, size);
1549 }
1550
1551 /**
1552  * gst_buffer_resize_range:
1553  * @buffer: a #GstBuffer.
1554  * @idx: an index
1555  * @length: a length
1556  * @offset: the offset adjustment
1557  * @size: the new size or -1 to just adjust the offset
1558  *
1559  * Set the total size of the @length memory blocks starting at @idx in
1560  * @buffer
1561  *
1562  * Returns: %TRUE if resizing succeeded, %FALSE otherwise.
1563  */
1564 gboolean
1565 gst_buffer_resize_range (GstBuffer * buffer, guint idx, gint length,
1566     gssize offset, gssize size)
1567 {
1568   guint i, len, end;
1569   gsize bsize, bufsize, bufoffs, bufmax;
1570
1571   g_return_val_if_fail (gst_buffer_is_writable (buffer), FALSE);
1572   g_return_val_if_fail (size >= -1, FALSE);
1573
1574   len = GST_BUFFER_MEM_LEN (buffer);
1575   g_return_val_if_fail ((len == 0 && idx == 0 && length == -1) ||
1576       (length == -1 && idx < len) || (length + idx <= len), FALSE);
1577
1578   if (length == -1)
1579     length = len - idx;
1580
1581   bufsize = gst_buffer_get_sizes_range (buffer, idx, length, &bufoffs, &bufmax);
1582
1583   GST_CAT_LOG (GST_CAT_BUFFER, "trim %p %" G_GSSIZE_FORMAT "-%" G_GSSIZE_FORMAT
1584       " size:%" G_GSIZE_FORMAT " offs:%" G_GSIZE_FORMAT " max:%"
1585       G_GSIZE_FORMAT, buffer, offset, size, bufsize, bufoffs, bufmax);
1586
1587   /* we can't go back further than the current offset or past the end of the
1588    * buffer */
1589   g_return_val_if_fail ((offset < 0 && bufoffs >= -offset) || (offset >= 0
1590           && bufoffs + offset <= bufmax), FALSE);
1591   if (size == -1) {
1592     g_return_val_if_fail (bufsize >= offset, FALSE);
1593     size = bufsize - offset;
1594   }
1595   g_return_val_if_fail (bufmax >= bufoffs + offset + size, FALSE);
1596
1597   /* no change */
1598   if (offset == 0 && size == bufsize)
1599     return TRUE;
1600
1601   end = idx + length;
1602   /* copy and trim */
1603   for (i = idx; i < end; i++) {
1604     GstMemory *mem;
1605     gsize left, noffs;
1606
1607     mem = GST_BUFFER_MEM_PTR (buffer, i);
1608     bsize = gst_memory_get_sizes (mem, NULL, NULL);
1609
1610     noffs = 0;
1611     /* last buffer always gets resized to the remaining size */
1612     if (i + 1 == end)
1613       left = size;
1614     /* shrink buffers before the offset */
1615     else if ((gssize) bsize <= offset) {
1616       left = 0;
1617       noffs = offset - bsize;
1618       offset = 0;
1619     }
1620     /* clip other buffers */
1621     else
1622       left = MIN (bsize - offset, size);
1623
1624     if (offset != 0 || left != bsize) {
1625       if (gst_memory_is_writable (mem)) {
1626         gst_memory_resize (mem, offset, left);
1627       } else {
1628         GstMemory *newmem = NULL;
1629
1630         if (!GST_MEMORY_IS_NO_SHARE (mem))
1631           newmem = gst_memory_share (mem, offset, left);
1632
1633         if (!newmem)
1634           newmem = gst_memory_copy (mem, offset, left);
1635
1636         if (newmem == NULL)
1637           return FALSE;
1638
1639         gst_memory_lock (newmem, GST_LOCK_FLAG_EXCLUSIVE);
1640         GST_BUFFER_MEM_PTR (buffer, i) = newmem;
1641         gst_memory_unlock (mem, GST_LOCK_FLAG_EXCLUSIVE);
1642         gst_memory_unref (mem);
1643
1644         GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
1645       }
1646     }
1647
1648     offset = noffs;
1649     size -= left;
1650   }
1651
1652   return TRUE;
1653 }
1654
1655 /**
1656  * gst_buffer_map:
1657  * @buffer: a #GstBuffer.
1658  * @info: (out): info about the mapping
1659  * @flags: flags for the mapping
1660  *
1661  * This function fills @info with the #GstMapInfo of all merged memory
1662  * blocks in @buffer.
1663  *
1664  * @flags describe the desired access of the memory. When @flags is
1665  * #GST_MAP_WRITE, @buffer should be writable (as returned from
1666  * gst_buffer_is_writable()).
1667  *
1668  * When @buffer is writable but the memory isn't, a writable copy will
1669  * automatically be created and returned. The readonly copy of the
1670  * buffer memory will then also be replaced with this writable copy.
1671  *
1672  * The memory in @info should be unmapped with gst_buffer_unmap() after
1673  * usage.
1674  *
1675  * Returns: %TRUE if the map succeeded and @info contains valid data.
1676  */
1677 gboolean
1678 gst_buffer_map (GstBuffer * buffer, GstMapInfo * info, GstMapFlags flags)
1679 {
1680   return gst_buffer_map_range (buffer, 0, -1, info, flags);
1681 }
1682
1683 /**
1684  * gst_buffer_map_range:
1685  * @buffer: a #GstBuffer.
1686  * @idx: an index
1687  * @length: a length
1688  * @info: (out): info about the mapping
1689  * @flags: flags for the mapping
1690  *
1691  * This function fills @info with the #GstMapInfo of @length merged memory blocks
1692  * starting at @idx in @buffer. When @length is -1, all memory blocks starting
1693  * from @idx are merged and mapped.
1694  *
1695  * @flags describe the desired access of the memory. When @flags is
1696  * #GST_MAP_WRITE, @buffer should be writable (as returned from
1697  * gst_buffer_is_writable()).
1698  *
1699  * When @buffer is writable but the memory isn't, a writable copy will
1700  * automatically be created and returned. The readonly copy of the buffer memory
1701  * will then also be replaced with this writable copy.
1702  *
1703  * The memory in @info should be unmapped with gst_buffer_unmap() after usage.
1704  *
1705  * Returns: %TRUE if the map succeeded and @info contains valid
1706  * data.
1707  */
1708 gboolean
1709 gst_buffer_map_range (GstBuffer * buffer, guint idx, gint length,
1710     GstMapInfo * info, GstMapFlags flags)
1711 {
1712   GstMemory *mem, *nmem;
1713   gboolean write, writable;
1714   gsize len;
1715
1716   g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
1717   g_return_val_if_fail (info != NULL, FALSE);
1718   len = GST_BUFFER_MEM_LEN (buffer);
1719   g_return_val_if_fail ((len == 0 && idx == 0 && length == -1) ||
1720       (length == -1 && idx < len) || (length > 0
1721           && length + idx <= len), FALSE);
1722
1723   GST_CAT_LOG (GST_CAT_BUFFER, "buffer %p, idx %u, length %d, flags %04x",
1724       buffer, idx, length, flags);
1725
1726   write = (flags & GST_MAP_WRITE) != 0;
1727   writable = gst_buffer_is_writable (buffer);
1728
1729   /* check if we can write when asked for write access */
1730   if (G_UNLIKELY (write && !writable))
1731     goto not_writable;
1732
1733   if (length == -1)
1734     length = len - idx;
1735
1736   mem = _get_merged_memory (buffer, idx, length);
1737   if (G_UNLIKELY (mem == NULL))
1738     goto no_memory;
1739
1740   /* now try to map */
1741   nmem = gst_memory_make_mapped (mem, info, flags);
1742   if (G_UNLIKELY (nmem == NULL))
1743     goto cannot_map;
1744
1745   /* if we merged or when the map returned a different memory, we try to replace
1746    * the memory in the buffer */
1747   if (G_UNLIKELY (length > 1 || nmem != mem)) {
1748     /* if the buffer is writable, replace the memory */
1749     if (writable) {
1750       _replace_memory (buffer, len, idx, length, gst_memory_ref (nmem));
1751     } else {
1752       if (len > 1) {
1753         GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
1754             "temporary mapping for memory %p in buffer %p", nmem, buffer);
1755       }
1756     }
1757   }
1758   return TRUE;
1759
1760   /* ERROR */
1761 not_writable:
1762   {
1763     GST_WARNING_OBJECT (buffer, "write map requested on non-writable buffer");
1764     g_critical ("write map requested on non-writable buffer");
1765     memset (info, 0, sizeof (GstMapInfo));
1766     return FALSE;
1767   }
1768 no_memory:
1769   {
1770     /* empty buffer, we need to return NULL */
1771     GST_DEBUG_OBJECT (buffer, "can't get buffer memory");
1772     memset (info, 0, sizeof (GstMapInfo));
1773     return TRUE;
1774   }
1775 cannot_map:
1776   {
1777     GST_DEBUG_OBJECT (buffer, "cannot map memory");
1778     memset (info, 0, sizeof (GstMapInfo));
1779     return FALSE;
1780   }
1781 }
1782
1783 /**
1784  * gst_buffer_unmap:
1785  * @buffer: a #GstBuffer.
1786  * @info: a #GstMapInfo
1787  *
1788  * Release the memory previously mapped with gst_buffer_map().
1789  */
1790 void
1791 gst_buffer_unmap (GstBuffer * buffer, GstMapInfo * info)
1792 {
1793   g_return_if_fail (GST_IS_BUFFER (buffer));
1794   g_return_if_fail (info != NULL);
1795
1796   /* we need to check for NULL, it is possible that we tried to map a buffer
1797    * without memory and we should be able to unmap that fine */
1798   if (G_LIKELY (info->memory)) {
1799     gst_memory_unmap (info->memory, info);
1800     gst_memory_unref (info->memory);
1801   }
1802 }
1803
1804 /**
1805  * gst_buffer_fill:
1806  * @buffer: a #GstBuffer.
1807  * @offset: the offset to fill
1808  * @src: (array length=size) (element-type guint8): the source address
1809  * @size: the size to fill
1810  *
1811  * Copy @size bytes from @src to @buffer at @offset.
1812  *
1813  * Returns: The amount of bytes copied. This value can be lower than @size
1814  *    when @buffer did not contain enough data.
1815  */
1816 gsize
1817 gst_buffer_fill (GstBuffer * buffer, gsize offset, gconstpointer src,
1818     gsize size)
1819 {
1820   gsize i, len, left;
1821   const guint8 *ptr = src;
1822
1823   g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
1824   g_return_val_if_fail (gst_buffer_is_writable (buffer), 0);
1825   g_return_val_if_fail (src != NULL || size == 0, 0);
1826
1827   GST_CAT_LOG (GST_CAT_BUFFER,
1828       "buffer %p, offset %" G_GSIZE_FORMAT ", size %" G_GSIZE_FORMAT, buffer,
1829       offset, size);
1830
1831   len = GST_BUFFER_MEM_LEN (buffer);
1832   left = size;
1833
1834   for (i = 0; i < len && left > 0; i++) {
1835     GstMapInfo info;
1836     gsize tocopy;
1837     GstMemory *mem;
1838
1839     mem = _get_mapped (buffer, i, &info, GST_MAP_WRITE);
1840     if (info.size > offset) {
1841       /* we have enough */
1842       tocopy = MIN (info.size - offset, left);
1843       memcpy ((guint8 *) info.data + offset, ptr, tocopy);
1844       left -= tocopy;
1845       ptr += tocopy;
1846       offset = 0;
1847     } else {
1848       /* offset past buffer, skip */
1849       offset -= info.size;
1850     }
1851     gst_memory_unmap (mem, &info);
1852   }
1853   return size - left;
1854 }
1855
1856 /**
1857  * gst_buffer_extract:
1858  * @buffer: a #GstBuffer.
1859  * @offset: the offset to extract
1860  * @dest: (out caller-allocates) (array length=size) (element-type guint8):
1861  *     the destination address
1862  * @size: the size to extract
1863  *
1864  * Copy @size bytes starting from @offset in @buffer to @dest.
1865  *
1866  * Returns: The amount of bytes extracted. This value can be lower than @size
1867  *    when @buffer did not contain enough data.
1868  */
1869 gsize
1870 gst_buffer_extract (GstBuffer * buffer, gsize offset, gpointer dest, gsize size)
1871 {
1872   gsize i, len, left;
1873   guint8 *ptr = dest;
1874
1875   g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
1876   g_return_val_if_fail (dest != NULL, 0);
1877
1878   GST_CAT_LOG (GST_CAT_BUFFER,
1879       "buffer %p, offset %" G_GSIZE_FORMAT ", size %" G_GSIZE_FORMAT, buffer,
1880       offset, size);
1881
1882   len = GST_BUFFER_MEM_LEN (buffer);
1883   left = size;
1884
1885   for (i = 0; i < len && left > 0; i++) {
1886     GstMapInfo info;
1887     gsize tocopy;
1888     GstMemory *mem;
1889
1890     mem = _get_mapped (buffer, i, &info, GST_MAP_READ);
1891     if (info.size > offset) {
1892       /* we have enough */
1893       tocopy = MIN (info.size - offset, left);
1894       memcpy (ptr, (guint8 *) info.data + offset, tocopy);
1895       left -= tocopy;
1896       ptr += tocopy;
1897       offset = 0;
1898     } else {
1899       /* offset past buffer, skip */
1900       offset -= info.size;
1901     }
1902     gst_memory_unmap (mem, &info);
1903   }
1904   return size - left;
1905 }
1906
1907 /**
1908  * gst_buffer_memcmp:
1909  * @buffer: a #GstBuffer.
1910  * @offset: the offset in @buffer
1911  * @mem: (array length=size) (element-type guint8): the memory to compare
1912  * @size: the size to compare
1913  *
1914  * Compare @size bytes starting from @offset in @buffer with the memory in @mem.
1915  *
1916  * Returns: 0 if the memory is equal.
1917  */
1918 gint
1919 gst_buffer_memcmp (GstBuffer * buffer, gsize offset, gconstpointer mem,
1920     gsize size)
1921 {
1922   gsize i, len;
1923   const guint8 *ptr = mem;
1924   gint res = 0;
1925
1926   g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
1927   g_return_val_if_fail (mem != NULL, 0);
1928
1929   GST_CAT_LOG (GST_CAT_BUFFER,
1930       "buffer %p, offset %" G_GSIZE_FORMAT ", size %" G_GSIZE_FORMAT, buffer,
1931       offset, size);
1932
1933   if (G_UNLIKELY (gst_buffer_get_size (buffer) < offset + size))
1934     return -1;
1935
1936   len = GST_BUFFER_MEM_LEN (buffer);
1937
1938   for (i = 0; i < len && size > 0 && res == 0; i++) {
1939     GstMapInfo info;
1940     gsize tocmp;
1941     GstMemory *mem;
1942
1943     mem = _get_mapped (buffer, i, &info, GST_MAP_READ);
1944     if (info.size > offset) {
1945       /* we have enough */
1946       tocmp = MIN (info.size - offset, size);
1947       res = memcmp (ptr, (guint8 *) info.data + offset, tocmp);
1948       size -= tocmp;
1949       ptr += tocmp;
1950       offset = 0;
1951     } else {
1952       /* offset past buffer, skip */
1953       offset -= info.size;
1954     }
1955     gst_memory_unmap (mem, &info);
1956   }
1957   return res;
1958 }
1959
1960 /**
1961  * gst_buffer_memset:
1962  * @buffer: a #GstBuffer.
1963  * @offset: the offset in @buffer
1964  * @val: the value to set
1965  * @size: the size to set
1966  *
1967  * Fill @buf with @size bytes with @val starting from @offset.
1968  *
1969  * Returns: The amount of bytes filled. This value can be lower than @size
1970  *    when @buffer did not contain enough data.
1971  */
1972 gsize
1973 gst_buffer_memset (GstBuffer * buffer, gsize offset, guint8 val, gsize size)
1974 {
1975   gsize i, len, left;
1976
1977   g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
1978   g_return_val_if_fail (gst_buffer_is_writable (buffer), 0);
1979
1980   GST_CAT_LOG (GST_CAT_BUFFER,
1981       "buffer %p, offset %" G_GSIZE_FORMAT ", val %02x, size %" G_GSIZE_FORMAT,
1982       buffer, offset, val, size);
1983
1984   len = GST_BUFFER_MEM_LEN (buffer);
1985   left = size;
1986
1987   for (i = 0; i < len && left > 0; i++) {
1988     GstMapInfo info;
1989     gsize toset;
1990     GstMemory *mem;
1991
1992     mem = _get_mapped (buffer, i, &info, GST_MAP_WRITE);
1993     if (info.size > offset) {
1994       /* we have enough */
1995       toset = MIN (info.size - offset, left);
1996       memset ((guint8 *) info.data + offset, val, toset);
1997       left -= toset;
1998       offset = 0;
1999     } else {
2000       /* offset past buffer, skip */
2001       offset -= info.size;
2002     }
2003     gst_memory_unmap (mem, &info);
2004   }
2005   return size - left;
2006 }
2007
2008 /**
2009  * gst_buffer_copy_region:
2010  * @parent: a #GstBuffer.
2011  * @flags: the #GstBufferCopyFlags
2012  * @offset: the offset into parent #GstBuffer at which the new sub-buffer
2013  *          begins.
2014  * @size: the size of the new #GstBuffer sub-buffer, in bytes. If -1, all
2015  *        data is copied.
2016  *
2017  * Creates a sub-buffer from @parent at @offset and @size.
2018  * This sub-buffer uses the actual memory space of the parent buffer.
2019  * This function will copy the offset and timestamp fields when the
2020  * offset is 0. If not, they will be set to #GST_CLOCK_TIME_NONE and
2021  * #GST_BUFFER_OFFSET_NONE.
2022  * If @offset equals 0 and @size equals the total size of @buffer, the
2023  * duration and offset end fields are also copied. If not they will be set
2024  * to #GST_CLOCK_TIME_NONE and #GST_BUFFER_OFFSET_NONE.
2025  *
2026  * MT safe.
2027  *
2028  * Returns: (transfer full): the new #GstBuffer or %NULL if the arguments were
2029  *     invalid.
2030  */
2031 GstBuffer *
2032 gst_buffer_copy_region (GstBuffer * buffer, GstBufferCopyFlags flags,
2033     gsize offset, gsize size)
2034 {
2035   GstBuffer *copy;
2036
2037   g_return_val_if_fail (buffer != NULL, NULL);
2038
2039   /* create the new buffer */
2040   copy = gst_buffer_new ();
2041
2042   GST_CAT_LOG (GST_CAT_BUFFER, "new region copy %p of %p %" G_GSIZE_FORMAT
2043       "-%" G_GSIZE_FORMAT, copy, buffer, offset, size);
2044
2045   if (!gst_buffer_copy_into (copy, buffer, flags, offset, size))
2046     gst_buffer_replace (&copy, NULL);
2047
2048   return copy;
2049 }
2050
2051 /**
2052  * gst_buffer_append:
2053  * @buf1: (transfer full): the first source #GstBuffer to append.
2054  * @buf2: (transfer full): the second source #GstBuffer to append.
2055  *
2056  * Append all the memory from @buf2 to @buf1. The result buffer will contain a
2057  * concatenation of the memory of @buf1 and @buf2.
2058  *
2059  * Returns: (transfer full): the new #GstBuffer that contains the memory
2060  *     of the two source buffers.
2061  */
2062 GstBuffer *
2063 gst_buffer_append (GstBuffer * buf1, GstBuffer * buf2)
2064 {
2065   return gst_buffer_append_region (buf1, buf2, 0, -1);
2066 }
2067
2068 /**
2069  * gst_buffer_append_region:
2070  * @buf1: (transfer full): the first source #GstBuffer to append.
2071  * @buf2: (transfer full): the second source #GstBuffer to append.
2072  * @offset: the offset in @buf2
2073  * @size: the size or -1 of @buf2
2074  *
2075  * Append @size bytes at @offset from @buf2 to @buf1. The result buffer will
2076  * contain a concatenation of the memory of @buf1 and the requested region of
2077  * @buf2.
2078  *
2079  * Returns: (transfer full): the new #GstBuffer that contains the memory
2080  *     of the two source buffers.
2081  */
2082 GstBuffer *
2083 gst_buffer_append_region (GstBuffer * buf1, GstBuffer * buf2, gssize offset,
2084     gssize size)
2085 {
2086   gsize i, len;
2087
2088   g_return_val_if_fail (GST_IS_BUFFER (buf1), NULL);
2089   g_return_val_if_fail (GST_IS_BUFFER (buf2), NULL);
2090
2091   buf1 = gst_buffer_make_writable (buf1);
2092   buf2 = gst_buffer_make_writable (buf2);
2093
2094   gst_buffer_resize (buf2, offset, size);
2095
2096   len = GST_BUFFER_MEM_LEN (buf2);
2097   for (i = 0; i < len; i++) {
2098     GstMemory *mem;
2099
2100     mem = GST_BUFFER_MEM_PTR (buf2, i);
2101     GST_BUFFER_MEM_PTR (buf2, i) = NULL;
2102     _memory_add (buf1, -1, mem);
2103   }
2104
2105   GST_BUFFER_MEM_LEN (buf2) = 0;
2106   GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_TAG_MEMORY);
2107   gst_buffer_unref (buf2);
2108
2109   return buf1;
2110 }
2111
2112 /**
2113  * gst_buffer_get_meta:
2114  * @buffer: a #GstBuffer
2115  * @api: the #GType of an API
2116  *
2117  * Get the metadata for @api on buffer. When there is no such metadata, %NULL is
2118  * returned. If multiple metadata with the given @api are attached to this
2119  * buffer only the first one is returned.  To handle multiple metadata with a
2120  * given API use gst_buffer_iterate_meta() or gst_buffer_foreach_meta() instead
2121  * and check the meta->info.api member for the API type.
2122  *
2123  * Returns: (transfer none) (nullable): the metadata for @api on
2124  * @buffer.
2125  */
2126 GstMeta *
2127 gst_buffer_get_meta (GstBuffer * buffer, GType api)
2128 {
2129   GstMetaItem *item;
2130   GstMeta *result = NULL;
2131
2132   g_return_val_if_fail (buffer != NULL, NULL);
2133   g_return_val_if_fail (api != 0, NULL);
2134
2135   /* find GstMeta of the requested API */
2136   for (item = GST_BUFFER_META (buffer); item; item = item->next) {
2137     GstMeta *meta = &item->meta;
2138     if (meta->info->api == api) {
2139       result = meta;
2140       break;
2141     }
2142   }
2143   return result;
2144 }
2145
2146 /**
2147  * gst_buffer_get_n_meta:
2148  * @buffer: a #GstBuffer
2149  * @api_type: the #GType of an API
2150  *
2151  * Returns: number of metas of type @api_type on @buffer.
2152  *
2153  * Since: 1.14
2154  */
2155 guint
2156 gst_buffer_get_n_meta (GstBuffer * buffer, GType api_type)
2157 {
2158   gpointer state = NULL;
2159   GstMeta *meta;
2160   guint n = 0;
2161
2162   while ((meta = gst_buffer_iterate_meta_filtered (buffer, &state, api_type)))
2163     ++n;
2164
2165   return n;
2166 }
2167
2168 /**
2169  * gst_buffer_add_meta:
2170  * @buffer: a #GstBuffer
2171  * @info: a #GstMetaInfo
2172  * @params: params for @info
2173  *
2174  * Add metadata for @info to @buffer using the parameters in @params.
2175  *
2176  * Returns: (transfer none) (nullable): the metadata for the api in @info on @buffer.
2177  */
2178 GstMeta *
2179 gst_buffer_add_meta (GstBuffer * buffer, const GstMetaInfo * info,
2180     gpointer params)
2181 {
2182   GstMetaItem *item;
2183   GstMeta *result = NULL;
2184   gsize size;
2185
2186   g_return_val_if_fail (buffer != NULL, NULL);
2187   g_return_val_if_fail (info != NULL, NULL);
2188   g_return_val_if_fail (gst_buffer_is_writable (buffer), NULL);
2189
2190   /* create a new slice */
2191   size = ITEM_SIZE (info);
2192   /* We warn in gst_meta_register() about metas without
2193    * init function but let's play safe here and prevent
2194    * uninitialized memory
2195    */
2196   if (!info->init_func)
2197     item = g_slice_alloc0 (size);
2198   else
2199     item = g_slice_alloc (size);
2200   result = &item->meta;
2201   result->info = info;
2202   result->flags = GST_META_FLAG_NONE;
2203   GST_CAT_DEBUG (GST_CAT_BUFFER,
2204       "alloc metadata %p (%s) of size %" G_GSIZE_FORMAT, result,
2205       g_type_name (info->type), info->size);
2206
2207   /* call the init_func when needed */
2208   if (info->init_func)
2209     if (!info->init_func (result, params, buffer))
2210       goto init_failed;
2211
2212   /* and add to the list of metadata */
2213   item->next = GST_BUFFER_META (buffer);
2214   GST_BUFFER_META (buffer) = item;
2215
2216   return result;
2217
2218 init_failed:
2219   {
2220     g_slice_free1 (size, item);
2221     return NULL;
2222   }
2223 }
2224
2225 /**
2226  * gst_buffer_remove_meta:
2227  * @buffer: a #GstBuffer
2228  * @meta: a #GstMeta
2229  *
2230  * Remove the metadata for @meta on @buffer.
2231  *
2232  * Returns: %TRUE if the metadata existed and was removed, %FALSE if no such
2233  * metadata was on @buffer.
2234  */
2235 gboolean
2236 gst_buffer_remove_meta (GstBuffer * buffer, GstMeta * meta)
2237 {
2238   GstMetaItem *walk, *prev;
2239
2240   g_return_val_if_fail (buffer != NULL, FALSE);
2241   g_return_val_if_fail (meta != NULL, FALSE);
2242   g_return_val_if_fail (gst_buffer_is_writable (buffer), FALSE);
2243   g_return_val_if_fail (!GST_META_FLAG_IS_SET (meta, GST_META_FLAG_LOCKED),
2244       FALSE);
2245
2246   /* find the metadata and delete */
2247   prev = GST_BUFFER_META (buffer);
2248   for (walk = prev; walk; walk = walk->next) {
2249     GstMeta *m = &walk->meta;
2250     if (m == meta) {
2251       const GstMetaInfo *info = meta->info;
2252
2253       /* remove from list */
2254       if (GST_BUFFER_META (buffer) == walk)
2255         GST_BUFFER_META (buffer) = walk->next;
2256       else
2257         prev->next = walk->next;
2258       /* call free_func if any */
2259       if (info->free_func)
2260         info->free_func (m, buffer);
2261
2262       /* and free the slice */
2263       g_slice_free1 (ITEM_SIZE (info), walk);
2264       break;
2265     }
2266     prev = walk;
2267   }
2268   return walk != NULL;
2269 }
2270
2271 /**
2272  * gst_buffer_iterate_meta: (skip)
2273  * @buffer: a #GstBuffer
2274  * @state: (out caller-allocates): an opaque state pointer
2275  *
2276  * Retrieve the next #GstMeta after @current. If @state points
2277  * to %NULL, the first metadata is returned.
2278  *
2279  * @state will be updated with an opaque state pointer
2280  *
2281  * Returns: (transfer none) (nullable): The next #GstMeta or %NULL
2282  * when there are no more items.
2283  */
2284 GstMeta *
2285 gst_buffer_iterate_meta (GstBuffer * buffer, gpointer * state)
2286 {
2287   GstMetaItem **meta;
2288
2289   g_return_val_if_fail (buffer != NULL, NULL);
2290   g_return_val_if_fail (state != NULL, NULL);
2291
2292   meta = (GstMetaItem **) state;
2293   if (*meta == NULL)
2294     /* state NULL, move to first item */
2295     *meta = GST_BUFFER_META (buffer);
2296   else
2297     /* state !NULL, move to next item in list */
2298     *meta = (*meta)->next;
2299
2300   if (*meta)
2301     return &(*meta)->meta;
2302   else
2303     return NULL;
2304 }
2305
2306 /**
2307  * gst_buffer_iterate_meta_filtered: (skip)
2308  * @buffer: a #GstBuffer
2309  * @state: (out caller-allocates): an opaque state pointer
2310  * @meta_api_type: only return #GstMeta of this type
2311  *
2312  * Retrieve the next #GstMeta of type @meta_api_type after the current one
2313  * according to @state. If @state points to %NULL, the first metadata of
2314  * type @meta_api_type is returned.
2315  *
2316  * @state will be updated with an opaque state pointer
2317  *
2318  * Returns: (transfer none) (nullable): The next #GstMeta of type
2319  * @meta_api_type or %NULL when there are no more items.
2320  *
2321  * Since: 1.12
2322  */
2323 GstMeta *
2324 gst_buffer_iterate_meta_filtered (GstBuffer * buffer, gpointer * state,
2325     GType meta_api_type)
2326 {
2327   GstMetaItem **meta;
2328
2329   g_return_val_if_fail (buffer != NULL, NULL);
2330   g_return_val_if_fail (state != NULL, NULL);
2331
2332   meta = (GstMetaItem **) state;
2333   if (*meta == NULL)
2334     /* state NULL, move to first item */
2335     *meta = GST_BUFFER_META (buffer);
2336   else
2337     /* state !NULL, move to next item in list */
2338     *meta = (*meta)->next;
2339
2340   while (*meta != NULL && (*meta)->meta.info->api != meta_api_type)
2341     *meta = (*meta)->next;
2342
2343   if (*meta)
2344     return &(*meta)->meta;
2345   else
2346     return NULL;
2347 }
2348
2349 /**
2350  * gst_buffer_foreach_meta:
2351  * @buffer: a #GstBuffer
2352  * @func: (scope call): a #GstBufferForeachMetaFunc to call
2353  * @user_data: (closure): user data passed to @func
2354  *
2355  * Call @func with @user_data for each meta in @buffer.
2356  *
2357  * @func can modify the passed meta pointer or its contents. The return value
2358  * of @func define if this function returns or if the remaining metadata items
2359  * in the buffer should be skipped.
2360  *
2361  * Returns: %FALSE when @func returned %FALSE for one of the metadata.
2362  */
2363 gboolean
2364 gst_buffer_foreach_meta (GstBuffer * buffer, GstBufferForeachMetaFunc func,
2365     gpointer user_data)
2366 {
2367   GstMetaItem *walk, *prev, *next;
2368   gboolean res = TRUE;
2369
2370   g_return_val_if_fail (buffer != NULL, FALSE);
2371   g_return_val_if_fail (func != NULL, FALSE);
2372
2373   /* find the metadata and delete */
2374   prev = GST_BUFFER_META (buffer);
2375   for (walk = prev; walk; walk = next) {
2376     GstMeta *m, *new;
2377
2378     m = new = &walk->meta;
2379     next = walk->next;
2380
2381     res = func (buffer, &new, user_data);
2382
2383     if (new == NULL) {
2384       const GstMetaInfo *info = m->info;
2385
2386       GST_CAT_DEBUG (GST_CAT_BUFFER, "remove metadata %p (%s)", m,
2387           g_type_name (info->type));
2388
2389       g_return_val_if_fail (gst_buffer_is_writable (buffer), FALSE);
2390       g_return_val_if_fail (!GST_META_FLAG_IS_SET (m, GST_META_FLAG_LOCKED),
2391           FALSE);
2392
2393       /* remove from list */
2394       if (GST_BUFFER_META (buffer) == walk)
2395         GST_BUFFER_META (buffer) = next;
2396       else
2397         prev->next = next;
2398
2399       prev = next;
2400
2401       /* call free_func if any */
2402       if (info->free_func)
2403         info->free_func (m, buffer);
2404
2405       /* and free the slice */
2406       g_slice_free1 (ITEM_SIZE (info), walk);
2407     } else {
2408       prev = walk;
2409     }
2410     if (!res)
2411       break;
2412   }
2413   return res;
2414 }
2415
2416 /**
2417  * gst_buffer_extract_dup:
2418  * @buffer: a #GstBuffer
2419  * @offset: the offset to extract
2420  * @size: the size to extract
2421  * @dest: (array length=dest_size) (element-type guint8) (out): A pointer where
2422  *  the destination array will be written. Might be %NULL if the size is 0.
2423  * @dest_size: (out): A location where the size of @dest can be written
2424  *
2425  * Extracts a copy of at most @size bytes the data at @offset into
2426  * newly-allocated memory. @dest must be freed using g_free() when done.
2427  *
2428  * Since: 1.0.10
2429  */
2430
2431 void
2432 gst_buffer_extract_dup (GstBuffer * buffer, gsize offset, gsize size,
2433     gpointer * dest, gsize * dest_size)
2434 {
2435   gsize real_size, alloc_size;
2436
2437   real_size = gst_buffer_get_size (buffer);
2438
2439   alloc_size = MIN (real_size - offset, size);
2440   if (alloc_size == 0) {
2441     *dest = NULL;
2442     *dest_size = 0;
2443   } else {
2444     *dest = g_malloc (alloc_size);
2445     *dest_size = gst_buffer_extract (buffer, offset, *dest, size);
2446   }
2447 }
2448
2449 GST_DEBUG_CATEGORY_STATIC (gst_parent_buffer_meta_debug);
2450
2451 /**
2452  * gst_buffer_add_parent_buffer_meta:
2453  * @buffer: (transfer none): a #GstBuffer
2454  * @ref: (transfer none): a #GstBuffer to ref
2455  *
2456  * Add a #GstParentBufferMeta to @buffer that holds a reference on
2457  * @ref until the buffer is freed.
2458  *
2459  * Returns: (transfer none) (nullable): The #GstParentBufferMeta that was added to the buffer
2460  *
2461  * Since: 1.6
2462  */
2463 GstParentBufferMeta *
2464 gst_buffer_add_parent_buffer_meta (GstBuffer * buffer, GstBuffer * ref)
2465 {
2466   GstParentBufferMeta *meta;
2467
2468   g_return_val_if_fail (GST_IS_BUFFER (ref), NULL);
2469
2470   meta =
2471       (GstParentBufferMeta *) gst_buffer_add_meta (buffer,
2472       GST_PARENT_BUFFER_META_INFO, NULL);
2473
2474   if (!meta)
2475     return NULL;
2476
2477   meta->buffer = gst_buffer_ref (ref);
2478
2479   return meta;
2480 }
2481
2482 static gboolean
2483 _gst_parent_buffer_meta_transform (GstBuffer * dest, GstMeta * meta,
2484     GstBuffer * buffer, GQuark type, gpointer data)
2485 {
2486   GstParentBufferMeta *dmeta, *smeta;
2487
2488   smeta = (GstParentBufferMeta *) meta;
2489
2490   if (GST_META_TRANSFORM_IS_COPY (type)) {
2491     /* copy over the reference to the parent buffer.
2492      * Usually, this meta means we need to keep the parent buffer
2493      * alive because one of the child memories is in use, which
2494      * might not be the case if memory is deep copied or sub-regioned,
2495      * but we can't tell, so keep the meta */
2496     dmeta = gst_buffer_add_parent_buffer_meta (dest, smeta->buffer);
2497     if (!dmeta)
2498       return FALSE;
2499
2500     GST_CAT_DEBUG (gst_parent_buffer_meta_debug,
2501         "copy buffer reference metadata");
2502   } else {
2503     /* return FALSE, if transform type is not supported */
2504     return FALSE;
2505   }
2506   return TRUE;
2507 }
2508
2509 static void
2510 _gst_parent_buffer_meta_free (GstParentBufferMeta * parent_meta,
2511     GstBuffer * buffer)
2512 {
2513   GST_CAT_DEBUG (gst_parent_buffer_meta_debug,
2514       "Dropping reference on buffer %p", parent_meta->buffer);
2515   gst_buffer_unref (parent_meta->buffer);
2516 }
2517
2518 static gboolean
2519 _gst_parent_buffer_meta_init (GstParentBufferMeta * parent_meta,
2520     gpointer params, GstBuffer * buffer)
2521 {
2522   static volatile gsize _init;
2523
2524   if (g_once_init_enter (&_init)) {
2525     GST_DEBUG_CATEGORY_INIT (gst_parent_buffer_meta_debug, "parentbuffermeta",
2526         0, "parentbuffermeta");
2527     g_once_init_leave (&_init, 1);
2528   }
2529
2530   parent_meta->buffer = NULL;
2531
2532   return TRUE;
2533 }
2534
2535 GType
2536 gst_parent_buffer_meta_api_get_type (void)
2537 {
2538   static volatile GType type = 0;
2539   static const gchar *tags[] = { NULL };
2540
2541   if (g_once_init_enter (&type)) {
2542     GType _type = gst_meta_api_type_register ("GstParentBufferMetaAPI", tags);
2543     g_once_init_leave (&type, _type);
2544   }
2545
2546   return type;
2547 }
2548
2549 /**
2550  * gst_parent_buffer_meta_get_info:
2551  *
2552  * Get the global #GstMetaInfo describing  the #GstParentBufferMeta meta.
2553  *
2554  * Returns: (transfer none): The #GstMetaInfo
2555  *
2556  * Since: 1.6
2557  */
2558 const GstMetaInfo *
2559 gst_parent_buffer_meta_get_info (void)
2560 {
2561   static const GstMetaInfo *meta_info = NULL;
2562
2563   if (g_once_init_enter ((GstMetaInfo **) & meta_info)) {
2564     const GstMetaInfo *meta =
2565         gst_meta_register (gst_parent_buffer_meta_api_get_type (),
2566         "GstParentBufferMeta",
2567         sizeof (GstParentBufferMeta),
2568         (GstMetaInitFunction) _gst_parent_buffer_meta_init,
2569         (GstMetaFreeFunction) _gst_parent_buffer_meta_free,
2570         _gst_parent_buffer_meta_transform);
2571     g_once_init_leave ((GstMetaInfo **) & meta_info, (GstMetaInfo *) meta);
2572   }
2573
2574   return meta_info;
2575 }
2576
2577 GST_DEBUG_CATEGORY_STATIC (gst_reference_timestamp_meta_debug);
2578
2579 /**
2580  * gst_buffer_add_reference_timestamp_meta:
2581  * @buffer: (transfer none): a #GstBuffer
2582  * @reference: (transfer none): identifier for the timestamp reference.
2583  * @timestamp: timestamp
2584  * @duration: duration, or %GST_CLOCK_TIME_NONE
2585  *
2586  * Add a #GstReferenceTimestampMeta to @buffer that holds a @timestamp and
2587  * optionally @duration based on a specific timestamp @reference. See the
2588  * documentation of #GstReferenceTimestampMeta for details.
2589  *
2590  * Returns: (transfer none) (nullable): The #GstReferenceTimestampMeta that was added to the buffer
2591  *
2592  * Since: 1.14
2593  */
2594 GstReferenceTimestampMeta *
2595 gst_buffer_add_reference_timestamp_meta (GstBuffer * buffer,
2596     GstCaps * reference, GstClockTime timestamp, GstClockTime duration)
2597 {
2598   GstReferenceTimestampMeta *meta;
2599
2600   g_return_val_if_fail (GST_IS_CAPS (reference), NULL);
2601   g_return_val_if_fail (timestamp != GST_CLOCK_TIME_NONE, NULL);
2602
2603   meta =
2604       (GstReferenceTimestampMeta *) gst_buffer_add_meta (buffer,
2605       GST_REFERENCE_TIMESTAMP_META_INFO, NULL);
2606
2607   if (!meta)
2608     return NULL;
2609
2610   meta->reference = gst_caps_ref (reference);
2611   meta->timestamp = timestamp;
2612   meta->duration = duration;
2613
2614   return meta;
2615 }
2616
2617 /**
2618  * gst_buffer_get_reference_timestamp_meta:
2619  * @buffer: a #GstBuffer
2620  * @reference: (allow-none): a reference #GstCaps
2621  *
2622  * Find the first #GstReferenceTimestampMeta on @buffer that conforms to
2623  * @reference. Conformance is tested by checking if the meta's reference is a
2624  * subset of @reference.
2625  *
2626  * Buffers can contain multiple #GstReferenceTimestampMeta metadata items.
2627  *
2628  * Returns: (transfer none) (nullable): the #GstReferenceTimestampMeta or %NULL when there
2629  * is no such metadata on @buffer.
2630  *
2631  * Since: 1.14
2632  */
2633 GstReferenceTimestampMeta *
2634 gst_buffer_get_reference_timestamp_meta (GstBuffer * buffer,
2635     GstCaps * reference)
2636 {
2637   gpointer state = NULL;
2638   GstMeta *meta;
2639   const GstMetaInfo *info = GST_REFERENCE_TIMESTAMP_META_INFO;
2640
2641   while ((meta = gst_buffer_iterate_meta (buffer, &state))) {
2642     if (meta->info->api == info->api) {
2643       GstReferenceTimestampMeta *rmeta = (GstReferenceTimestampMeta *) meta;
2644
2645       if (!reference)
2646         return rmeta;
2647       if (gst_caps_is_subset (rmeta->reference, reference))
2648         return rmeta;
2649     }
2650   }
2651   return NULL;
2652 }
2653
2654 static gboolean
2655 _gst_reference_timestamp_meta_transform (GstBuffer * dest, GstMeta * meta,
2656     GstBuffer * buffer, GQuark type, gpointer data)
2657 {
2658   GstReferenceTimestampMeta *dmeta, *smeta;
2659
2660   /* we copy over the reference timestamp meta, independent of transformation
2661    * that happens. If it applied to the original buffer, it still applies to
2662    * the new buffer as it refers to the time when the media was captured */
2663   smeta = (GstReferenceTimestampMeta *) meta;
2664   dmeta =
2665       gst_buffer_add_reference_timestamp_meta (dest, smeta->reference,
2666       smeta->timestamp, smeta->duration);
2667   if (!dmeta)
2668     return FALSE;
2669
2670   GST_CAT_DEBUG (gst_reference_timestamp_meta_debug,
2671       "copy reference timestamp metadata from buffer %p to %p", buffer, dest);
2672
2673   return TRUE;
2674 }
2675
2676 static void
2677 _gst_reference_timestamp_meta_free (GstReferenceTimestampMeta * meta,
2678     GstBuffer * buffer)
2679 {
2680   if (meta->reference)
2681     gst_caps_unref (meta->reference);
2682 }
2683
2684 static gboolean
2685 _gst_reference_timestamp_meta_init (GstReferenceTimestampMeta * meta,
2686     gpointer params, GstBuffer * buffer)
2687 {
2688   static volatile gsize _init;
2689
2690   if (g_once_init_enter (&_init)) {
2691     GST_DEBUG_CATEGORY_INIT (gst_reference_timestamp_meta_debug,
2692         "referencetimestampmeta", 0, "referencetimestampmeta");
2693     g_once_init_leave (&_init, 1);
2694   }
2695
2696   meta->reference = NULL;
2697   meta->timestamp = GST_CLOCK_TIME_NONE;
2698   meta->duration = GST_CLOCK_TIME_NONE;
2699
2700   return TRUE;
2701 }
2702
2703 GType
2704 gst_reference_timestamp_meta_api_get_type (void)
2705 {
2706   static volatile GType type = 0;
2707   static const gchar *tags[] = { NULL };
2708
2709   if (g_once_init_enter (&type)) {
2710     GType _type =
2711         gst_meta_api_type_register ("GstReferenceTimestampMetaAPI", tags);
2712     g_once_init_leave (&type, _type);
2713   }
2714
2715   return type;
2716 }
2717
2718 /**
2719  * gst_reference_timestamp_meta_get_info:
2720  *
2721  * Get the global #GstMetaInfo describing  the #GstReferenceTimestampMeta meta.
2722  *
2723  * Returns: (transfer none): The #GstMetaInfo
2724  *
2725  * Since: 1.14
2726  */
2727 const GstMetaInfo *
2728 gst_reference_timestamp_meta_get_info (void)
2729 {
2730   static const GstMetaInfo *meta_info = NULL;
2731
2732   if (g_once_init_enter ((GstMetaInfo **) & meta_info)) {
2733     const GstMetaInfo *meta =
2734         gst_meta_register (gst_reference_timestamp_meta_api_get_type (),
2735         "GstReferenceTimestampMeta",
2736         sizeof (GstReferenceTimestampMeta),
2737         (GstMetaInitFunction) _gst_reference_timestamp_meta_init,
2738         (GstMetaFreeFunction) _gst_reference_timestamp_meta_free,
2739         _gst_reference_timestamp_meta_transform);
2740     g_once_init_leave ((GstMetaInfo **) & meta_info, (GstMetaInfo *) meta);
2741   }
2742
2743   return meta_info;
2744 }