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