gstbuffer.c 43.8 KB
Newer Older
1 2 3 4 5
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2000 Wim Taymans <wtay@chello.be>
 *
 * gstbuffer.c: Buffer operations
Erik Walthinsen's avatar
Erik Walthinsen committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
22

23 24 25 26 27
/**
 * SECTION:gstbuffer
 * @short_description: Data-passing buffer type, supporting sub-buffers.
 * @see_also: #GstPad, #GstMiniObject
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
28
 * Buffers are the basic unit of data transfer in GStreamer.  The #GstBuffer
Wim Taymans's avatar
Wim Taymans committed
29 30 31 32
 * type provides all the state necessary to define the regions of memory as
 * part of a stream. Region copies are also supported, allowing a smaller
 * region of a buffer to become its own buffer, with mechanisms in place to
 * ensure that neither memory space goes away prematurely.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
33 34 35
 *
 * Buffers are usually created with gst_buffer_new(). After a buffer has been
 * created one will typically allocate memory for it and set the size of the
36 37 38 39 40 41 42 43 44 45 46
 * buffer data.  The following example creates a buffer that can hold a given
 * video frame with a given width, height and bits per plane.
 * <example>
 * <title>Creating a buffer for a video frame</title>
 *   <programlisting>
 *   GstBuffer *buffer;
 *   gint size, width, height, bpp;
 *   ...
 *   size = width * height * bpp;
 *   buffer = gst_buffer_new ();
 *   GST_BUFFER_SIZE (buffer) = size;
47
 *   GST_BUFFER_MALLOCDATA (buffer) = g_malloc (size);
48 49 50 51
 *   GST_BUFFER_DATA (buffer) = GST_BUFFER_MALLOCDATA (buffer);
 *   ...
 *   </programlisting>
 * </example>
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
52 53
 *
 * Alternatively, use gst_buffer_new_and_alloc()
54
 * to create a buffer with preallocated data of a given size.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
55
 *
Wim Taymans's avatar
Wim Taymans committed
56 57 58 59
 * The data pointed to by the buffer can be retrieved with the GST_BUFFER_DATA()
 * macro. The size of the data can be found with GST_BUFFER_SIZE(). For buffers
 * of size 0, the data pointer is undefined (usually NULL) and should never be used.
 *
60 61 62
 * If an element knows what pad you will push the buffer out on, it should use
 * gst_pad_alloc_buffer() instead to create a buffer.  This allows downstream
 * elements to provide special buffers to write in, like hardware buffers.
Wim Taymans's avatar
Wim Taymans committed
63 64 65 66 67
 *
 * A buffer has a pointer to a #GstCaps describing the media type of the data
 * in the buffer. Attach caps to the buffer with gst_buffer_set_caps(); this
 * is typically done before pushing out a buffer using gst_pad_push() so that
 * the downstream element knows the type of the buffer.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
68
 *
69
 * A buffer will usually have a timestamp, and a duration, but neither of these
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
70 71 72 73
 * are guaranteed (they may be set to #GST_CLOCK_TIME_NONE). Whenever a
 * meaningful value can be given for these, they should be set. The timestamp
 * and duration are measured in nanoseconds (they are #GstClockTime values).
 *
74 75
 * A buffer can also have one or both of a start and an end offset. These are
 * media-type specific. For video buffers, the start offset will generally be
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
76 77
 * the frame number. For audio buffers, it will be the number of samples
 * produced so far. For compressed data, it could be the byte offset in a
78 79 80
 * source or destination file. Likewise, the end offset will be the offset of
 * the end of the buffer. These can only be meaningfully interpreted if you
 * know the media type of the buffer (the #GstCaps set on it). Either or both
81
 * can be set to #GST_BUFFER_OFFSET_NONE.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
82
 *
83 84 85
 * gst_buffer_ref() is used to increase the refcount of a buffer. This must be
 * done when you want to keep a handle to the buffer after pushing it to the
 * next element.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
86
 *
87
 * To efficiently create a smaller buffer out of an existing one, you can
Wim Taymans's avatar
Wim Taymans committed
88
 * use gst_buffer_copy_region().
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
89
 *
Wim Taymans's avatar
Wim Taymans committed
90 91 92 93
 * If a plug-in wants to modify the buffer data or metadata in-place, it should
 * first obtain a buffer that is safe to modify by using
 * gst_buffer_make_writable().  This function is optimized so that a copy will
 * only be made when it is necessary.
94
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
95 96
 * Several flags of the buffer can be set and unset with the
 * GST_BUFFER_FLAG_SET() and GST_BUFFER_FLAG_UNSET() macros. Use
97
 * GST_BUFFER_FLAG_IS_SET() to test if a certain #GstBufferFlag is set.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
98
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
99
 * Buffers can be efficiently merged into a larger buffer with
Wim Taymans's avatar
Wim Taymans committed
100
 * gst_buffer_span(), which avoids memory copies when the gst_buffer_is_span_fast()
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
101
 * function returns TRUE.
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
102
 *
103 104
 * An element should either unref the buffer or push it out on a src pad
 * using gst_pad_push() (see #GstPad).
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
105
 *
106
 * Buffers are usually freed by unreffing them with gst_buffer_unref(). When
Wim Taymans's avatar
Wim Taymans committed
107 108
 * the refcount drops to 0, any data pointed to by the buffer is unreffed as
 * well.
109
 *
Wim Taymans's avatar
Wim Taymans committed
110
 * Last reviewed on March 30, 2011 (0.11.0)
111
 */
112
#include "gst_private.h"
Erik Walthinsen's avatar
Erik Walthinsen committed
113

114 115 116 117 118 119 120
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

121
#include "gstbuffer.h"
122
#include "gstbufferpool.h"
123
#include "gstinfo.h"
124
#include "gstutils.h"
125
#include "gstminiobject.h"
Benjamin Otte's avatar
Benjamin Otte committed
126
#include "gstversion.h"
127

Wim Taymans's avatar
Wim Taymans committed
128
GType _gst_buffer_type = 0;
129

130
static GstMemory *_gst_buffer_arr_span (GstMemory ** mem[], gsize len[],
Wim Taymans's avatar
Wim Taymans committed
131
    guint n, gsize offset, gsize size, gboolean writable);
132

Wim Taymans's avatar
Wim Taymans committed
133
typedef struct _GstMetaItem GstMetaItem;
134

Wim Taymans's avatar
Wim Taymans committed
135
struct _GstMetaItem
136
{
Wim Taymans's avatar
Wim Taymans committed
137 138
  GstMetaItem *next;
  GstMeta meta;
139
};
Wim Taymans's avatar
Wim Taymans committed
140 141 142
#define ITEM_SIZE(info) ((info)->size + sizeof (GstMetaItem))

#define GST_BUFFER_MEM_MAX         16
143

Wim Taymans's avatar
Wim Taymans committed
144 145 146
#define GST_BUFFER_MEM_LEN(b)      (((GstBufferImpl *)(b))->len)
#define GST_BUFFER_MEM_ARRAY(b)    (((GstBufferImpl *)(b))->mem)
#define GST_BUFFER_MEM_PTR(b,i)    (((GstBufferImpl *)(b))->mem[i])
147
#define GST_BUFFER_BUFMEM(b)       (((GstBufferImpl *)(b))->bufmem)
Wim Taymans's avatar
Wim Taymans committed
148
#define GST_BUFFER_META(b)         (((GstBufferImpl *)(b))->item)
149 150 151 152 153

typedef struct
{
  GstBuffer buffer;

Wim Taymans's avatar
Wim Taymans committed
154
  /* the memory blocks */
Wim Taymans's avatar
Wim Taymans committed
155 156 157
  guint len;
  GstMemory *mem[GST_BUFFER_MEM_MAX];

158 159 160
  /* memory of the buffer when allocated from 1 chunk */
  GstMemory *bufmem;

Wim Taymans's avatar
Wim Taymans committed
161 162
  /* FIXME, make metadata allocation more efficient by using part of the
   * GstBufferImpl */
163 164 165
  GstMetaItem *item;
} GstBufferImpl;

Wim Taymans's avatar
Wim Taymans committed
166 167
static GstMemory *
_span_memory (GstBuffer * buffer, gsize offset, gsize size, gboolean writable)
168 169
{
  GstMemory *span, **mem[1];
Wim Taymans's avatar
Wim Taymans committed
170
  gsize len[1];
171 172 173 174

  /* not enough room, span buffers */
  mem[0] = GST_BUFFER_MEM_ARRAY (buffer);
  len[0] = GST_BUFFER_MEM_LEN (buffer);
Wim Taymans's avatar
Wim Taymans committed
175

Wim Taymans's avatar
Wim Taymans committed
176 177 178 179 180 181 182 183 184 185 186 187
  if (size == -1)
    size = gst_buffer_get_size (buffer);

  span = _gst_buffer_arr_span (mem, len, 1, offset, size, writable);

  return span;
}

static void
_replace_memory (GstBuffer * buffer, GstMemory * mem)
{
  gsize len, i;
188 189

  /* unref old buffers */
Wim Taymans's avatar
Wim Taymans committed
190 191 192
  len = GST_BUFFER_MEM_LEN (buffer);
  for (i = 0; i < len; i++)
    gst_memory_unref (GST_BUFFER_MEM_PTR (buffer, i));
193 194

  /* replace with single spanned buffer */
Wim Taymans's avatar
Wim Taymans committed
195
  GST_BUFFER_MEM_PTR (buffer, 0) = mem;
196 197 198
  GST_BUFFER_MEM_LEN (buffer) = 1;
}

Wim Taymans's avatar
Wim Taymans committed
199
static inline void
200
_memory_add (GstBuffer * buffer, guint idx, GstMemory * mem)
Wim Taymans's avatar
Wim Taymans committed
201
{
202
  guint i, len = GST_BUFFER_MEM_LEN (buffer);
203 204

  if (G_UNLIKELY (len >= GST_BUFFER_MEM_MAX)) {
Wim Taymans's avatar
Wim Taymans committed
205 206 207 208
    /* too many buffer, span them. */
    /* FIXME, there is room for improvement here: We could only try to merge
     * 2 buffers to make some room. If we can't efficiently merge 2 buffers we
     * could try to only merge the two smallest buffers to avoid memcpy, etc. */
Wim Taymans's avatar
Wim Taymans committed
209
    _replace_memory (buffer, _span_memory (buffer, 0, -1, FALSE));
210 211 212
    /* we now have 1 single spanned buffer */
    len = 1;
  }
213 214 215 216 217 218 219 220 221 222

  if (idx == -1)
    idx = len;

  for (i = len; i > idx; i--) {
    /* move buffers to insert, FIXME, we need to insert first and then merge */
    GST_BUFFER_MEM_PTR (buffer, i) = GST_BUFFER_MEM_PTR (buffer, i - 1);
  }
  /* and insert the new buffer */
  GST_BUFFER_MEM_PTR (buffer, idx) = mem;
Wim Taymans's avatar
Wim Taymans committed
223 224
  GST_BUFFER_MEM_LEN (buffer) = len + 1;
}
225

Wim Taymans's avatar
Wim Taymans committed
226 227
GST_DEFINE_MINI_OBJECT (GstBuffer, gst_buffer);

228
void
229
_priv_gst_buffer_initialize (void)
Wim Taymans's avatar
Wim Taymans committed
230
{
Wim Taymans's avatar
Wim Taymans committed
231
  _gst_buffer_type = gst_buffer_get_type ();
232 233
}

234
/**
Wim Taymans's avatar
Wim Taymans committed
235
 * gst_buffer_copy_into:
236 237 238
 * @dest: a destination #GstBuffer
 * @src: a source #GstBuffer
 * @flags: flags indicating what metadata fields should be copied.
Wim Taymans's avatar
Wim Taymans committed
239
 * @offset: offset to copy from
Edward Hervey's avatar
Edward Hervey committed
240
 * @size: total size to copy. If -1, all data is copied.
241
 *
Wim Taymans's avatar
Wim Taymans committed
242
 * Copies the information from @src into @dest.
243
 *
Wim Taymans's avatar
Wim Taymans committed
244
 * @flags indicate which fields will be copied.
245 246
 */
void
Wim Taymans's avatar
Wim Taymans committed
247
gst_buffer_copy_into (GstBuffer * dest, GstBuffer * src,
Wim Taymans's avatar
Wim Taymans committed
248
    GstBufferCopyFlags flags, gsize offset, gsize size)
249
{
Wim Taymans's avatar
Wim Taymans committed
250
  GstMetaItem *walk;
Wim Taymans's avatar
Wim Taymans committed
251
  gsize bufsize;
252

253 254 255
  g_return_if_fail (dest != NULL);
  g_return_if_fail (src != NULL);

Wim Taymans's avatar
Wim Taymans committed
256 257 258 259
  /* nothing to copy if the buffers are the same */
  if (G_UNLIKELY (dest == src))
    return;

260 261
  g_return_if_fail (gst_buffer_is_writable (dest));

Wim Taymans's avatar
Wim Taymans committed
262
  bufsize = gst_buffer_get_size (src);
263
  g_return_if_fail (bufsize >= offset);
Wim Taymans's avatar
Wim Taymans committed
264 265
  if (size == -1)
    size = bufsize - offset;
Wim Taymans's avatar
Wim Taymans committed
266
  g_return_if_fail (bufsize >= offset + size);
267

Wim Taymans's avatar
Wim Taymans committed
268 269 270
  GST_CAT_LOG (GST_CAT_BUFFER, "copy %p to %p, offset %" G_GSIZE_FORMAT
      "-%" G_GSIZE_FORMAT "/%" G_GSIZE_FORMAT, src, dest, offset, size,
      bufsize);
271 272

  if (flags & GST_BUFFER_COPY_FLAGS) {
273 274
    /* copy flags */
    GST_MINI_OBJECT_FLAGS (dest) = GST_MINI_OBJECT_FLAGS (src);
275 276 277
  }

  if (flags & GST_BUFFER_COPY_TIMESTAMPS) {
Wim Taymans's avatar
Wim Taymans committed
278 279 280
    if (offset == 0) {
      GST_BUFFER_TIMESTAMP (dest) = GST_BUFFER_TIMESTAMP (src);
      GST_BUFFER_OFFSET (dest) = GST_BUFFER_OFFSET (src);
Wim Taymans's avatar
Wim Taymans committed
281
      if (size == bufsize) {
Wim Taymans's avatar
Wim Taymans committed
282 283 284 285 286 287 288 289 290
        GST_BUFFER_DURATION (dest) = GST_BUFFER_DURATION (src);
        GST_BUFFER_OFFSET_END (dest) = GST_BUFFER_OFFSET_END (src);
      }
    } else {
      GST_BUFFER_TIMESTAMP (dest) = GST_CLOCK_TIME_NONE;
      GST_BUFFER_DURATION (dest) = GST_CLOCK_TIME_NONE;
      GST_BUFFER_OFFSET (dest) = GST_BUFFER_OFFSET_NONE;
      GST_BUFFER_OFFSET_END (dest) = GST_BUFFER_OFFSET_NONE;
    }
291
  }
292

Wim Taymans's avatar
Wim Taymans committed
293
  if (flags & GST_BUFFER_COPY_MEMORY) {
Wim Taymans's avatar
Wim Taymans committed
294
    GstMemory *mem;
295
    gsize skip, left, len, i, bsize;
Wim Taymans's avatar
Wim Taymans committed
296

Wim Taymans's avatar
Wim Taymans committed
297
    len = GST_BUFFER_MEM_LEN (src);
Wim Taymans's avatar
Wim Taymans committed
298
    left = size;
299
    skip = offset;
Wim Taymans's avatar
Wim Taymans committed
300

Wim Taymans's avatar
Wim Taymans committed
301
    /* copy and make regions of the memory */
Wim Taymans's avatar
Wim Taymans committed
302
    for (i = 0; i < len && left > 0; i++) {
Wim Taymans's avatar
Wim Taymans committed
303
      mem = GST_BUFFER_MEM_PTR (src, i);
304
      bsize = gst_memory_get_sizes (mem, NULL, NULL);
Wim Taymans's avatar
Wim Taymans committed
305

306
      if (bsize <= skip) {
Wim Taymans's avatar
Wim Taymans committed
307
        /* don't copy buffer */
308
        skip -= bsize;
Wim Taymans's avatar
Wim Taymans committed
309 310 311
      } else {
        gsize tocopy;

312 313 314 315 316 317
        tocopy = MIN (bsize - skip, left);
        if (mem->flags & GST_MEMORY_FLAG_NO_SHARE) {
          /* no share, always copy then */
          mem = gst_memory_copy (mem, skip, tocopy);
          skip = 0;
        } else if (tocopy < bsize) {
Wim Taymans's avatar
Wim Taymans committed
318
          /* we need to clip something */
319 320
          mem = gst_memory_share (mem, skip, tocopy);
          skip = 0;
Wim Taymans's avatar
Wim Taymans committed
321
        } else {
Wim Taymans's avatar
Wim Taymans committed
322
          mem = gst_memory_ref (mem);
Wim Taymans's avatar
Wim Taymans committed
323
        }
324
        _memory_add (dest, -1, mem);
Wim Taymans's avatar
Wim Taymans committed
325 326
        left -= tocopy;
      }
Wim Taymans's avatar
Wim Taymans committed
327
    }
Wim Taymans's avatar
Wim Taymans committed
328
    if (flags & GST_BUFFER_COPY_MERGE) {
Wim Taymans's avatar
Wim Taymans committed
329
      _replace_memory (dest, _span_memory (dest, 0, size, FALSE));
Wim Taymans's avatar
Wim Taymans committed
330
    }
Wim Taymans's avatar
Wim Taymans committed
331 332
  }

333
  for (walk = GST_BUFFER_META (src); walk; walk = walk->next) {
Wim Taymans's avatar
Wim Taymans committed
334 335
    GstMeta *meta = &walk->meta;
    const GstMetaInfo *info = meta->info;
336

Wim Taymans's avatar
Wim Taymans committed
337
    if (info->copy_func)
338
      info->copy_func (dest, meta, src, offset, size);
339
  }
340 341
}

342 343
static GstBuffer *
_gst_buffer_copy (GstBuffer * buffer)
Wim Taymans's avatar
Wim Taymans committed
344
{
345
  GstBuffer *copy;
Erik Walthinsen's avatar
Erik Walthinsen committed
346

Wim Taymans's avatar
Wim Taymans committed
347 348
  g_return_val_if_fail (buffer != NULL, NULL);

349
  /* create a fresh new buffer */
350
  copy = gst_buffer_new ();
351

352
  /* we simply copy everything from our parent */
Wim Taymans's avatar
Wim Taymans committed
353
  gst_buffer_copy_into (copy, buffer, GST_BUFFER_COPY_ALL, 0, -1);
Erik Walthinsen's avatar
Erik Walthinsen committed
354

355 356
  return copy;
}
357

358 359
/* the default dispose function revives the buffer and returns it to the
 * pool when there is a pool */
360
static gboolean
361 362 363 364
_gst_buffer_dispose (GstBuffer * buffer)
{
  GstBufferPool *pool;

365 366 367 368 369 370 371 372 373 374 375
  /* no pool, do free */
  if ((pool = buffer->pool) == NULL)
    return TRUE;

  /* keep the buffer alive */
  gst_buffer_ref (buffer);
  /* return the buffer to the pool */
  GST_CAT_LOG (GST_CAT_BUFFER, "release %p to pool %p", buffer, pool);
  gst_buffer_pool_release_buffer (pool, buffer);

  return FALSE;
376 377
}

378
static void
379
_gst_buffer_free (GstBuffer * buffer)
380
{
Wim Taymans's avatar
Wim Taymans committed
381
  GstMetaItem *walk, *next;
Wim Taymans's avatar
Wim Taymans committed
382 383
  guint i, len;
  gsize msize;
384

385 386 387
  g_return_if_fail (buffer != NULL);

  GST_CAT_LOG (GST_CAT_BUFFER, "finalize %p", buffer);
388

389
  /* free metadata */
390
  for (walk = GST_BUFFER_META (buffer); walk; walk = next) {
Wim Taymans's avatar
Wim Taymans committed
391 392
    GstMeta *meta = &walk->meta;
    const GstMetaInfo *info = meta->info;
393 394 395 396

    /* call free_func if any */
    if (info->free_func)
      info->free_func (meta, buffer);
397

398
    next = walk->next;
399 400
    /* and free the slice */
    g_slice_free1 (ITEM_SIZE (info), walk);
401 402
  }

Wim Taymans's avatar
Wim Taymans committed
403 404 405 406 407 408 409 410
  /* get the size, when unreffing the memory, we could also unref the buffer
   * itself */
  msize = GST_MINI_OBJECT_SIZE (buffer);

  /* free our memory */
  len = GST_BUFFER_MEM_LEN (buffer);
  for (i = 0; i < len; i++)
    gst_memory_unref (GST_BUFFER_MEM_PTR (buffer, i));
Wim Taymans's avatar
Wim Taymans committed
411

412
  /* we set msize to 0 when the buffer is part of the memory block */
Wim Taymans's avatar
Wim Taymans committed
413 414
  if (msize)
    g_slice_free1 (msize, buffer);
415 416
  else
    gst_memory_unref (GST_BUFFER_BUFMEM (buffer));
Wim Taymans's avatar
Wim Taymans committed
417 418 419
}

static void
420
gst_buffer_init (GstBufferImpl * buffer, gsize size)
Wim Taymans's avatar
Wim Taymans committed
421 422 423
{
  gst_mini_object_init (GST_MINI_OBJECT_CAST (buffer), _gst_buffer_type, size);

424 425 426
  buffer->buffer.mini_object.copy =
      (GstMiniObjectCopyFunction) _gst_buffer_copy;
  buffer->buffer.mini_object.dispose =
427
      (GstMiniObjectDisposeFunction) _gst_buffer_dispose;
428 429
  buffer->buffer.mini_object.free =
      (GstMiniObjectFreeFunction) _gst_buffer_free;
Wim Taymans's avatar
Wim Taymans committed
430

Wim Taymans's avatar
Wim Taymans committed
431
  GST_BUFFER (buffer)->pool = NULL;
Wim Taymans's avatar
Wim Taymans committed
432 433 434 435
  GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
  GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
  GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
  GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE;
Wim Taymans's avatar
Wim Taymans committed
436

Wim Taymans's avatar
Wim Taymans committed
437 438
  GST_BUFFER_MEM_LEN (buffer) = 0;
  GST_BUFFER_META (buffer) = NULL;
439 440
}

441
/**
442
 * gst_buffer_new:
443
 *
444
 * Creates a newly allocated buffer without any data.
445
 *
446
 * MT safe.
447 448
 *
 * Returns: (transfer full): the new #GstBuffer.
449
 */
450
GstBuffer *
451
gst_buffer_new (void)
Wim Taymans's avatar
Wim Taymans committed
452
{
453
  GstBufferImpl *newbuf;
454

Wim Taymans's avatar
Wim Taymans committed
455
  newbuf = g_slice_new (GstBufferImpl);
456
  GST_CAT_LOG (GST_CAT_BUFFER, "new %p", newbuf);
457

458
  gst_buffer_init (newbuf, sizeof (GstBufferImpl));
459

460
  return GST_BUFFER_CAST (newbuf);
Erik Walthinsen's avatar
Erik Walthinsen committed
461 462
}

463
/**
464
 * gst_buffer_new_allocate:
465
 * @allocator: the #GstAllocator to use
Wim Taymans's avatar
Wim Taymans committed
466
 * @size: the size in bytes of the new buffer's data.
467 468 469 470 471 472 473
 * @align: the alignment of the buffer memory
 *
 * Tries to create a newly allocated buffer with data of the given size and
 * alignment from @allocator. If the requested amount of memory can't be
 * allocated, NULL will be returned. The allocated buffer memory is not cleared.
 *
 * When @allocator is NULL, the default memory allocator will be used.
474
 *
475
 * Allocator buffer memory will be aligned to multiples of (@align + 1) bytes.
476
 *
Wim Taymans's avatar
Wim Taymans committed
477
 * Note that when @size == 0, the buffer will not have memory associated with it.
478 479 480
 *
 * MT safe.
 *
481 482
 * Returns: (transfer full): a new #GstBuffer, or NULL if the memory couldn't
 *     be allocated.
483 484
 */
GstBuffer *
485
gst_buffer_new_allocate (const GstAllocator * allocator, gsize size,
486
    gsize align)
487 488
{
  GstBuffer *newbuf;
Wim Taymans's avatar
Wim Taymans committed
489
  GstMemory *mem;
Wim Taymans's avatar
Wim Taymans committed
490 491 492 493
#if 0
  guint8 *data;
  gsize asize;
#endif
494

Wim Taymans's avatar
Wim Taymans committed
495
#if 1
496
  if (size > 0) {
497
    mem = gst_allocator_alloc (allocator, size, align);
498 499 500 501
    if (G_UNLIKELY (mem == NULL))
      goto no_memory;
  } else {
    mem = NULL;
502
  }
Wim Taymans's avatar
Wim Taymans committed
503 504

  newbuf = gst_buffer_new ();
505 506

  if (mem != NULL)
507
    _memory_add (newbuf, -1, mem);
508

Josep Torra's avatar
Josep Torra committed
509 510
  GST_CAT_LOG (GST_CAT_BUFFER,
      "new buffer %p of size %" G_GSIZE_FORMAT " from allocator %p", newbuf,
Wim Taymans's avatar
Wim Taymans committed
511
      size, allocator);
Wim Taymans's avatar
Wim Taymans committed
512 513 514 515 516 517 518 519 520 521 522 523 524 525
#endif

#if 0
  asize = sizeof (GstBufferImpl) + size;
  data = g_slice_alloc (asize);
  if (G_UNLIKELY (data == NULL))
    goto no_memory;

  newbuf = GST_BUFFER_CAST (data);

  gst_buffer_init ((GstBufferImpl *) data, asize);
  if (size > 0) {
    mem = gst_memory_new_wrapped (0, data + sizeof (GstBufferImpl), NULL,
        size, 0, size);
526
    _memory_add (newbuf, -1, mem);
Wim Taymans's avatar
Wim Taymans committed
527 528 529 530
  }
#endif

#if 0
531 532 533 534
  /* allocate memory and buffer, it might be interesting to do this but there
   * are many complications. We need to keep the memory mapped to access the
   * buffer fields and the memory for the buffer might be just very slow. We
   * also need to do some more magic to get the alignment right. */
Wim Taymans's avatar
Wim Taymans committed
535
  asize = sizeof (GstBufferImpl) + size;
536
  mem = gst_allocator_alloc (allocator, asize, align);
Wim Taymans's avatar
Wim Taymans committed
537 538 539 540 541 542 543 544 545 546
  if (G_UNLIKELY (mem == NULL))
    goto no_memory;

  /* map the data part and init the buffer in it, set the buffer size to 0 so
   * that a finalize won't free the buffer */
  data = gst_memory_map (mem, &asize, NULL, GST_MAP_WRITE);
  gst_buffer_init ((GstBufferImpl *) data, 0);
  gst_memory_unmap (mem, data, asize);

  /* strip off the buffer */
Wim Taymans's avatar
Wim Taymans committed
547
  gst_memory_resize (mem, sizeof (GstBufferImpl), size);
Wim Taymans's avatar
Wim Taymans committed
548 549

  newbuf = GST_BUFFER_CAST (data);
550
  GST_BUFFER_BUFMEM (newbuf) = mem;
Wim Taymans's avatar
Wim Taymans committed
551 552

  if (size > 0)
553
    _memory_add (newbuf, -1, gst_memory_ref (mem));
Wim Taymans's avatar
Wim Taymans committed
554 555 556
#endif

  return newbuf;
557 558 559 560

  /* ERRORS */
no_memory:
  {
Josep Torra's avatar
Josep Torra committed
561 562
    GST_CAT_WARNING (GST_CAT_BUFFER,
        "failed to allocate %" G_GSIZE_FORMAT " bytes", size);
563 564
    return NULL;
  }
Erik Walthinsen's avatar
Erik Walthinsen committed
565 566
}

567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
/**
 * gst_buffer_new_wrapped_full:
 * @data: data to wrap
 * @free_func: function to free @data
 * @offset: offset in @data of valid data
 * @size: size of valid data in @data starting at @offset
 *
 * Creates a new buffer that wraps the given @data.  Valid data is set
 * to start at @offset and up to @size.  If no @free_func is provided,
 * buffer memory is marked READONLY.
 *
 * MT safe.
 *
 * Returns: (transfer full): a new #GstBuffer
 */
GstBuffer *
gst_buffer_new_wrapped_full (gpointer data, GFreeFunc free_func, gsize offset,
    gsize size)
{
  GstBuffer *newbuf;

  g_return_val_if_fail (offset <= size, NULL);

  newbuf = gst_buffer_new ();
  gst_buffer_take_memory (newbuf, -1,
      gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
          data, free_func, offset + size, offset, size));

  return newbuf;
}

/**
 * gst_buffer_new_wrapped:
 * @data: data to wrap
 * @size: allocated size of @data
 *
 * Creates a new buffer that wraps the given @data.
 *
 * MT safe.
 *
 * Returns: (transfer full): a new #GstBuffer
 */
GstBuffer *
gst_buffer_new_wrapped (gpointer data, gsize size)
{
  return gst_buffer_new_wrapped_full (data, g_free, 0, size);
}

Wim Taymans's avatar
Wim Taymans committed
615 616 617 618 619 620 621 622
/**
 * gst_buffer_n_memory:
 * @buffer: a #GstBuffer.
 *
 * Get the amount of memory blocks that this buffer has.
 *
 * Returns: (transfer full): the amount of memory block in this buffer.
 */
Wim Taymans's avatar
Wim Taymans committed
623 624 625
guint
gst_buffer_n_memory (GstBuffer * buffer)
{
626 627
  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);

Wim Taymans's avatar
Wim Taymans committed
628
  return GST_BUFFER_MEM_LEN (buffer);
Wim Taymans's avatar
Wim Taymans committed
629 630
}

Wim Taymans's avatar
Wim Taymans committed
631 632 633
/**
 * gst_buffer_take_memory:
 * @buffer: a #GstBuffer.
634 635
 * @idx: the index to add the memory at, or -1 to append it to the end
 * @mem: (transfer: full): a #GstMemory.
Wim Taymans's avatar
Wim Taymans committed
636
 *
637 638
 * Add the memory block @mem to @buffer at @idx. This function takes ownership
 * of @mem and thus doesn't increase its refcount.
Wim Taymans's avatar
Wim Taymans committed
639
 */
Wim Taymans's avatar
Wim Taymans committed
640
void
641
gst_buffer_take_memory (GstBuffer * buffer, gint idx, GstMemory * mem)
Wim Taymans's avatar
Wim Taymans committed
642
{
643 644 645
  g_return_if_fail (GST_IS_BUFFER (buffer));
  g_return_if_fail (gst_buffer_is_writable (buffer));
  g_return_if_fail (mem != NULL);
646 647
  g_return_if_fail (idx == -1 ||
      (idx >= 0 && idx <= GST_BUFFER_MEM_LEN (buffer)));
648

649
  _memory_add (buffer, idx, mem);
Wim Taymans's avatar
Wim Taymans committed
650 651
}

652 653 654 655 656 657 658 659 660
static GstMemory *
_get_memory (GstBuffer * buffer, guint idx, gboolean write)
{
  GstMemory *mem;

  mem = GST_BUFFER_MEM_PTR (buffer, idx);

  if (G_UNLIKELY (write && !GST_MEMORY_IS_WRITABLE (mem))) {
    GstMemory *copy;
661 662
    GST_CAT_LOG (GST_CAT_BUFFER,
        "making writable copy of memory %p in buffer %p", mem, buffer);
663 664 665 666 667 668 669 670 671
    /* replace with a writable copy */
    copy = gst_memory_copy (mem, 0, -1);
    GST_BUFFER_MEM_PTR (buffer, idx) = copy;
    gst_memory_unref (mem);
    mem = copy;
  }
  return mem;
}

Wim Taymans's avatar
Wim Taymans committed
672 673 674 675 676 677 678 679 680 681 682
/**
 * gst_buffer_peek_memory:
 * @buffer: a #GstBuffer.
 * @idx: an index
 *
 * Get the memory block in @buffer at @idx. This function does not return a
 * refcount to the memory block. The memory block stays valid for as long as the
 * caller has a valid reference to @buffer.
 *
 * Returns: a #GstMemory at @idx.
 */
Wim Taymans's avatar
Wim Taymans committed
683
GstMemory *
Wim Taymans's avatar
Wim Taymans committed
684
gst_buffer_peek_memory (GstBuffer * buffer, guint idx, GstMapFlags flags)
Wim Taymans's avatar
Wim Taymans committed
685 686
{
  GstMemory *mem;
Wim Taymans's avatar
Wim Taymans committed
687 688 689
  gboolean write;

  write = (flags & GST_MAP_WRITE) != 0;
690 691

  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
Wim Taymans's avatar
Wim Taymans committed
692
  g_return_val_if_fail (idx < GST_BUFFER_MEM_LEN (buffer), NULL);
Wim Taymans's avatar
Wim Taymans committed
693

Wim Taymans's avatar
Wim Taymans committed
694 695 696 697
  /* check if we can write when asked for write access */
  if (G_UNLIKELY (write && !gst_buffer_is_writable (buffer)))
    goto not_writable;

698
  mem = _get_memory (buffer, idx, write);
Wim Taymans's avatar
Wim Taymans committed
699 700

  return mem;
Wim Taymans's avatar
Wim Taymans committed
701 702 703 704 705 706 707

  /* ERRORS */
not_writable:
  {
    g_return_val_if_fail (gst_buffer_is_writable (buffer), NULL);
    return NULL;
  }
Wim Taymans's avatar
Wim Taymans committed
708 709
}

Wim Taymans's avatar
Wim Taymans committed
710
/**
Wim Taymans's avatar
Wim Taymans committed
711
 * gst_buffer_remove_memory_range:
Wim Taymans's avatar
Wim Taymans committed
712 713
 * @buffer: a #GstBuffer.
 * @idx: an index
Wim Taymans's avatar
Wim Taymans committed
714
 * @length: a length
Wim Taymans's avatar
Wim Taymans committed
715
 *
Wim Taymans's avatar
Wim Taymans committed
716 717 718
 * Remove @len memory blocks in @buffer starting from @idx.
 *
 * @length can be -1, in which case all memory starting from @idx is removed.
Wim Taymans's avatar
Wim Taymans committed
719
 */
Wim Taymans's avatar
Wim Taymans committed
720
void
Wim Taymans's avatar
Wim Taymans committed
721
gst_buffer_remove_memory_range (GstBuffer * buffer, guint idx, guint length)
Wim Taymans's avatar
Wim Taymans committed
722
{
Wim Taymans's avatar
Wim Taymans committed
723
  guint len, i, end;
724 725 726

  g_return_if_fail (GST_IS_BUFFER (buffer));
  g_return_if_fail (gst_buffer_is_writable (buffer));
Wim Taymans's avatar
Wim Taymans committed
727 728

  len = GST_BUFFER_MEM_LEN (buffer);
Wim Taymans's avatar
Wim Taymans committed
729
  if (length == -1) {
Wim Taymans's avatar
Wim Taymans committed
730 731 732 733 734 735 736 737 738 739 740
    g_return_if_fail (idx < len);
    length = len - idx;
  }

  end = idx + length;
  for (i = idx; i < end; i++)
    gst_memory_unref (GST_BUFFER_MEM_PTR (buffer, i));

  if (end != len) {
    g_memmove (&GST_BUFFER_MEM_PTR (buffer, idx),
        &GST_BUFFER_MEM_PTR (buffer, end), (len - end) * sizeof (gpointer));
Wim Taymans's avatar
Wim Taymans committed
741
  }
Wim Taymans's avatar
Wim Taymans committed
742
  GST_BUFFER_MEM_LEN (buffer) = len - length;
Wim Taymans's avatar
Wim Taymans committed
743 744
}

Wim Taymans's avatar
Wim Taymans committed
745
/**
746
 * gst_buffer_get_sizes:
Wim Taymans's avatar
Wim Taymans committed
747
 * @buffer: a #GstBuffer.
748 749
 * @offset: a pointer to the offset
 * @maxsize: a pointer to the maxsize
Wim Taymans's avatar
Wim Taymans committed
750 751 752
 *
 * Get the total size of all memory blocks in @buffer.
 *
753 754 755 756 757 758
 * When not %NULL, @offset will contain the offset of the data in the first
 * memory block in @buffer and @maxsize will contain the sum of the size
 * and @offset and the amount of extra padding on the last memory block.
 * @offset and @maxsize can be used to resize the buffer with
 * gst_buffer_resize().
 *
Wim Taymans's avatar
Wim Taymans committed
759 760
 * Returns: the total size of the memory in @buffer.
 */
Wim Taymans's avatar
Wim Taymans committed
761
gsize
762
gst_buffer_get_sizes (GstBuffer * buffer, gsize * offset, gsize * maxsize)
Wim Taymans's avatar
Wim Taymans committed
763
{
764 765 766
  guint len;
  gsize size;
  GstMemory *mem;
Wim Taymans's avatar
Wim Taymans committed
767

768 769
  g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);

Wim Taymans's avatar
Wim Taymans committed
770
  len = GST_BUFFER_MEM_LEN (buffer);
Wim Taymans's avatar
Wim Taymans committed
771

772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
  if (G_LIKELY (len == 1)) {
    /* common case */
    mem = GST_BUFFER_MEM_PTR (buffer, 0);
    size = gst_memory_get_sizes (mem, offset, maxsize);
  } else {
    guint i;
    gsize extra, offs;

    size = offs = extra = 0;
    for (i = 0; i < len; i++) {
      gsize s, o, ms;

      mem = GST_BUFFER_MEM_PTR (buffer, i);
      s = gst_memory_get_sizes (mem, &o, &ms);

Wim Taymans's avatar
Wim Taymans committed
787 788 789 790 791 792 793
      if (s) {
        if (size == 0)
          /* first size, take accumulated data before as the offset */
          offs = extra + o;
        /* add sizes */
        size += s;
        /* save the amount of data after this block */
794
        extra = ms - (o + s);
Wim Taymans's avatar
Wim Taymans committed
795 796 797 798
      } else {
        /* empty block, add as extra */
        extra += ms;
      }
799 800 801 802 803
    }
    if (offset)
      *offset = offs;
    if (maxsize)
      *maxsize = offs + size + extra;
Wim Taymans's avatar
Wim Taymans committed
804 805 806 807
  }
  return size;
}

808
/**
Wim Taymans's avatar
Wim Taymans committed
809
 * gst_buffer_resize:
810
 * @buffer: a #GstBuffer.
811
 * @offset: the offset adjustement
812 813 814 815 816
 * @size: the new size
 *
 * Set the total size of the buffer
 */
void
817
gst_buffer_resize (GstBuffer * buffer, gssize offset, gsize size)
818 819
{
  guint len;
820
  guint i;
821
  gsize bsize, bufsize, bufoffs, bufmax;
822 823 824 825
  GstMemory *mem;

  g_return_if_fail (gst_buffer_is_writable (buffer));

826 827
  bufsize = gst_buffer_get_sizes (buffer, &bufoffs, &bufmax);

Wim Taymans's avatar
Wim Taymans committed
828 829 830 831
  GST_CAT_LOG (GST_CAT_BUFFER, "trim %p %" G_GSSIZE_FORMAT "-%" G_GSIZE_FORMAT
      " size:%" G_GSIZE_FORMAT " offs:%" G_GSIZE_FORMAT " max:%" G_GSIZE_FORMAT,
      buffer, offset, size, bufsize, bufoffs, bufmax);

Wim Taymans's avatar
Wim Taymans committed
832 833 834 835 836 837
  /* we can't go back further than the current offset or past the end of the
   * buffer */
  g_return_if_fail ((offset < 0 && bufoffs >= -offset) || (offset >= 0
          && bufoffs + offset <= bufmax));
  if (size == -1) {
    g_return_if_fail (bufsize >= offset);
838
    size = bufsize - offset;
Wim Taymans's avatar
Wim Taymans committed
839 840
  }
  g_return_if_fail (bufmax >= bufoffs + offset + size);
841

Wim Taymans's avatar
Wim Taymans committed
842
  len = GST_BUFFER_MEM_LEN (buffer);
843 844

  /* copy and trim */
845 846 847 848
  for (i = 0; i < len; i++) {
    gsize left, noffs;

    mem = GST_BUFFER_MEM_PTR (buffer, i);
849
    bsize = gst_memory_get_sizes (mem, NULL, NULL);
850

851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
    noffs = 0;
    /* last buffer always gets resized to the remaining size */
    if (i + 1 == len)
      left = size;
    /* shrink buffers before the offset */
    else if ((gssize) bsize <= offset) {
      left = 0;
      noffs = offset - bsize;
      offset = 0;
    }
    /* clip other buffers */
    else
      left = MIN (bsize - offset, size);

    if (offset != 0 || left != bsize) {
      /* we need to clip something */
      if (GST_MEMORY_IS_WRITABLE (mem)) {
        gst_memory_resize (mem, offset, left);
      } else {
        GstMemory *tmp;
871

872 873 874 875
        if (mem->flags & GST_MEMORY_FLAG_NO_SHARE)
          tmp = gst_memory_copy (mem, offset, left);
        else
          tmp = gst_memory_share (mem, offset, left);
876

877 878
        gst_memory_unref (mem);
        mem = tmp;
879 880
      }
    }
881 882 883 884
    offset = noffs;
    size -= left;

    GST_BUFFER_MEM_PTR (buffer, i) = mem;
885 886 887
  }
}

Wim Taymans's avatar
Wim Taymans committed
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
/**
 * gst_buffer_map:
 * @buffer: a #GstBuffer.
 * @size: a location for the size
 * @maxsize: a location for the max size
 * @flags: flags for the mapping
 *
 * This function return a pointer to the memory in @buffer. @flags describe the
 * desired access of the memory. When @flags is #GST_MAP_WRITE, @buffer should
 * be writable (as returned from gst_buffer_is_writable()).
 *
 * @size and @maxsize will contain the current valid number of bytes in the
 * returned memory area and the total maximum mount of bytes available in the
 * returned memory area respectively.
 *
 * When @buffer is writable but the memory isn't, a writable copy will
 * automatically be created and returned. The readonly copy of the buffer memory
 * will then also be replaced with this writable copy.
 *
 * When the buffer contains multiple memory blocks, the returned pointer will be
 * a concatenation of the memory blocks.
 *
 * Returns: a pointer to the memory for the buffer.
 */
Wim Taymans's avatar
Wim Taymans committed
912 913 914 915
gpointer
gst_buffer_map (GstBuffer * buffer, gsize * size, gsize * maxsize,
    GstMapFlags flags)
{
Wim Taymans's avatar
Wim Taymans committed
916 917
  guint len;
  gpointer data;
Wim Taymans's avatar
Wim Taymans committed
918 919
  GstMemory *mem;
  gboolean write, writable;
Wim Taymans's avatar
Wim Taymans committed
920

921 922
  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);

Wim Taymans's avatar
Wim Taymans committed
923 924
  write = (flags & GST_MAP_WRITE) != 0;
  writable = gst_buffer_is_writable (buffer);
Wim Taymans's avatar
Wim Taymans committed
925

Wim Taymans's avatar
Wim Taymans committed
926 927
  /* check if we can write when asked for write access */
  if (G_UNLIKELY (write && !writable))
928 929
    goto not_writable;

Wim Taymans's avatar
Wim Taymans committed
930
  len = GST_BUFFER_MEM_LEN (buffer);
Wim Taymans's avatar
Wim Taymans committed
931

Wim Taymans's avatar
Wim Taymans committed
932 933 934 935 936 937 938 939
  if (G_UNLIKELY (len == 0)) {
    /* no memory, return immediately */
    if (size)
      *size = 0;
    if (maxsize)
      *maxsize = 0;
    return NULL;
  }
Wim Taymans's avatar
Wim Taymans committed
940

Wim Taymans's avatar
Wim Taymans committed
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963
  if (G_LIKELY (len == 1)) {
    /* we can take the first one */
    mem = GST_BUFFER_MEM_PTR (buffer, 0);
  } else {
    /* we need to span memory */
    if (writable) {
      /* if we can write, we can change the memory with the spanned
       * memory */
      mem = _span_memory (buffer, 0, -1, write);
      _replace_memory (buffer, mem);
    } else {
      gsize bsize;

      /* extract all data in new memory, FIXME slow!! */
      bsize = gst_buffer_get_size (buffer);

      data = g_malloc (bsize);
      gst_buffer_extract (buffer, 0, data, bsize);
      if (size)
        *size = bsize;
      if (maxsize)
        *maxsize = bsize;
      return data;
964
    }
Wim Taymans's avatar
Wim Taymans committed
965
  }
966

Wim Taymans's avatar
Wim Taymans committed
967 968 969 970 971 972 973
  if (G_UNLIKELY (write && !GST_MEMORY_IS_WRITABLE (mem))) {
    GstMemory *copy;
    /* replace with a writable copy */
    copy = gst_memory_copy (mem, 0, -1);
    GST_BUFFER_MEM_PTR (buffer, 0) = copy;
    gst_memory_unref (mem);
    mem = copy;
Wim Taymans's avatar
Wim Taymans committed
974
  }
Wim Taymans's avatar
Wim Taymans committed
975 976 977

  data = gst_memory_map (mem, size, maxsize, flags);

Wim Taymans's avatar
Wim Taymans committed
978
  return data;
979 980 981 982 983 984 985

  /* ERROR */
not_writable:
  {
    g_return_val_if_fail (gst_buffer_is_writable (buffer), NULL);
    return NULL;
  }
Wim Taymans's avatar
Wim Taymans committed
986 987
}

Wim Taymans's avatar
Wim Taymans committed
988 989 990 991 992 993 994 995 996 997 998
/**
 * gst_buffer_unmap:
 * @buffer: a #GstBuffer.
 * @data: the previously mapped data
 * @size: the size of @data
 *
 * Release the memory previously mapped with gst_buffer_map().
 *
 * Returns: #TRUE on success. #FALSE can be returned when the new size is larger
 * than the maxsize of the memory.
 */
Wim Taymans's avatar
Wim Taymans committed
999 1000 1001
gboolean
gst_buffer_unmap (GstBuffer * buffer, gpointer data, gsize size)
{
Wim Taymans's avatar
Wim Taymans committed
1002 1003 1004
  gboolean result;
  guint len;

1005 1006
  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);