gstmemory.c 15.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/* GStreamer
 * Copyright (C) 2011 Wim Taymans <wim.taymans@gmail.be>
 *
 * gstmemory.c: memory block handling
 *
 * 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.
 */

Wim Taymans's avatar
Wim Taymans committed
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
/**
 * SECTION:gstmemory
 * @short_description: refcounted wrapper for memory blocks
 * @see_also: #GstBuffer
 *
 * GstMemory is a lightweight refcounted object that wraps a region of memory.
 * They are typically used to manage the data of a #GstBuffer.
 *
 * New memory can be created with gst_memory_new_wrapped() that wraps the memory
 * allocated elsewhere and gst_memory_new_alloc() that creates a new GstMemory
 * and the memory inside it.
 *
 * Refcounting of the memory block is performed with gst_memory_ref() and
 * gst_memory_unref().
 *
 * The size of the memory can be retrieved and changed with
 * gst_memory_get_sizes() and gst_memory_resize() respectively.
 *
 * Getting access to the data of the memory is performed with gst_memory_map().
 * After the memory access is completed, gst_memory_unmap() should be called.
 *
 * Memory can be copied with gst_memory_copy(), which will returnn a writable
 * copy. gst_memory_share() will create a new memory block that shares the
 * memory with an existing memory block at a custom offset and with a custom
 * size.
 *
 * Memory can be efficiently merged when gst_memory_is_span() returns TRUE and
 * with the function gst_memory_span().
 *
 * Last reviewed on 2011-03-30 (0.11.0)
 */
53

Wim Taymans's avatar
Wim Taymans committed
54
#include "config.h"
55 56 57
#include "gst_private.h"
#include "gstmemory.h"

Wim Taymans's avatar
Wim Taymans committed
58

59 60 61 62 63 64 65
struct _GstMemoryImpl
{
  GQuark name;

  GstMemoryInfo info;
};

Wim Taymans's avatar
Wim Taymans committed
66
/* default memory implementation */
67 68 69
typedef struct
{
  GstMemory mem;
Wim Taymans's avatar
Wim Taymans committed
70
  gsize slice_size;
71 72 73 74 75 76 77
  guint8 *data;
  GFreeFunc free_func;
  gsize maxsize;
  gsize offset;
  gsize size;
} GstMemoryDefault;

Wim Taymans's avatar
Wim Taymans committed
78
static const GstMemoryImpl *_default_mem_impl;
Wim Taymans's avatar
Wim Taymans committed
79
static const GstMemoryImpl *_default_share_impl;
Wim Taymans's avatar
Wim Taymans committed
80

Wim Taymans's avatar
Wim Taymans committed
81
/* initialize the fields */
Wim Taymans's avatar
Wim Taymans committed
82
static void
83 84 85
_default_mem_init (GstMemoryDefault * mem, GstMemoryFlags flags,
    GstMemory * parent, gsize slice_size, gpointer data,
    GFreeFunc free_func, gsize maxsize, gsize offset, gsize size)
Wim Taymans's avatar
Wim Taymans committed
86
{
Wim Taymans's avatar
Wim Taymans committed
87
  mem->mem.impl = data ? _default_mem_impl : _default_share_impl;
88
  mem->mem.flags = flags;
Wim Taymans's avatar
Wim Taymans committed
89
  mem->mem.refcount = 1;
Wim Taymans's avatar
Wim Taymans committed
90 91 92 93 94 95 96 97 98
  mem->mem.parent = parent ? gst_memory_ref (parent) : NULL;
  mem->slice_size = slice_size;
  mem->data = data;
  mem->free_func = free_func;
  mem->maxsize = maxsize;
  mem->offset = offset;
  mem->size = size;
}

Wim Taymans's avatar
Wim Taymans committed
99
/* create a new memory block that manages the given memory */
Wim Taymans's avatar
Wim Taymans committed
100
static GstMemoryDefault *
101
_default_mem_new (GstMemoryFlags flags, GstMemory * parent, gpointer data,
Wim Taymans's avatar
Wim Taymans committed
102 103 104
    GFreeFunc free_func, gsize maxsize, gsize offset, gsize size)
{
  GstMemoryDefault *mem;
Wim Taymans's avatar
Wim Taymans committed
105
  gsize slice_size;
Wim Taymans's avatar
Wim Taymans committed
106

Wim Taymans's avatar
Wim Taymans committed
107 108 109
  slice_size = sizeof (GstMemoryDefault);

  mem = g_slice_alloc (slice_size);
110
  _default_mem_init (mem, flags, parent, slice_size,
Wim Taymans's avatar
Wim Taymans committed
111 112 113 114
      data, free_func, maxsize, offset, size);

  return mem;
}
115

Wim Taymans's avatar
Wim Taymans committed
116
/* allocate the memory and structure in one block */
Wim Taymans's avatar
Wim Taymans committed
117 118 119 120 121 122 123
static GstMemoryDefault *
_default_mem_new_block (gsize maxsize, gsize align, gsize offset, gsize size)
{
  GstMemoryDefault *mem;
  gsize aoffset, slice_size;
  guint8 *data;

Wim Taymans's avatar
Wim Taymans committed
124 125
  /* allocate more to compensate for alignment */
  maxsize += align;
Wim Taymans's avatar
Wim Taymans committed
126
  /* alloc header and data in one block */
Wim Taymans's avatar
Wim Taymans committed
127
  slice_size = sizeof (GstMemoryDefault) + maxsize;
Wim Taymans's avatar
Wim Taymans committed
128 129 130 131 132 133 134 135

  mem = g_slice_alloc (slice_size);
  if (mem == NULL)
    return NULL;

  data = (guint8 *) mem + sizeof (GstMemoryDefault);

  if ((aoffset = ((guintptr) data & align)))
136
    aoffset = (align + 1) - aoffset;
Wim Taymans's avatar
Wim Taymans committed
137

Wim Taymans's avatar
Wim Taymans committed
138
  _default_mem_init (mem, 0, NULL, slice_size, data, NULL, maxsize,
Wim Taymans's avatar
Wim Taymans committed
139 140 141 142 143
      aoffset + offset, size);

  return mem;
}

144
static gsize
Wim Taymans's avatar
Wim Taymans committed
145
_default_mem_get_sizes (GstMemoryDefault * mem, gsize * maxsize)
146
{
Wim Taymans's avatar
Wim Taymans committed
147 148
  if (maxsize)
    *maxsize = mem->maxsize;
149

Wim Taymans's avatar
Wim Taymans committed
150 151 152 153
  return mem->size;
}

static void
Wim Taymans's avatar
Wim Taymans committed
154
_default_mem_resize (GstMemoryDefault * mem, gsize offset, gsize size)
Wim Taymans's avatar
Wim Taymans committed
155
{
Wim Taymans's avatar
Wim Taymans committed
156
  g_return_if_fail (size + mem->offset + offset <= mem->maxsize);
Wim Taymans's avatar
Wim Taymans committed
157 158 159 160 161 162 163 164 165 166 167

  mem->offset += offset;
  mem->size = size;
}

static gpointer
_default_mem_map (GstMemoryDefault * mem, gsize * size, gsize * maxsize,
    GstMapFlags flags)
{
  if (size)
    *size = mem->size;
168
  if (maxsize)
Wim Taymans's avatar
Wim Taymans committed
169
    *maxsize = mem->maxsize;
170

Wim Taymans's avatar
Wim Taymans committed
171
  return mem->data + mem->offset;
172 173 174
}

static gpointer
Wim Taymans's avatar
Wim Taymans committed
175
_default_share_map (GstMemoryDefault * mem, gsize * size, gsize * maxsize,
Wim Taymans's avatar
Wim Taymans committed
176
    GstMapFlags flags)
177
{
Wim Taymans's avatar
Wim Taymans committed
178 179 180
  guint8 *data;

  data = gst_memory_map (mem->mem.parent, size, maxsize, flags);
181 182

  if (size)
Wim Taymans's avatar
Wim Taymans committed
183
    *size = mem->size;
184
  if (maxsize)
Wim Taymans's avatar
Wim Taymans committed
185
    *maxsize -= mem->offset;
186

Wim Taymans's avatar
Wim Taymans committed
187
  return data + mem->offset;
188 189 190
}

static gboolean
Wim Taymans's avatar
Wim Taymans committed
191
_default_mem_unmap (GstMemoryDefault * mem, gpointer data, gsize size)
192
{
Wim Taymans's avatar
Wim Taymans committed
193 194
  if (size != -1)
    mem->size = size;
Wim Taymans's avatar
Wim Taymans committed
195 196
  return TRUE;
}
197

Wim Taymans's avatar
Wim Taymans committed
198
static gboolean
Wim Taymans's avatar
Wim Taymans committed
199
_default_share_unmap (GstMemoryDefault * mem, gpointer data, gsize size)
Wim Taymans's avatar
Wim Taymans committed
200 201 202
{
  gboolean res;
  guint8 *ptr = data;
203

Wim Taymans's avatar
Wim Taymans committed
204 205 206 207
  if (size != -1)
    mem->size = size;
  else
    size = mem->size - mem->offset;
Wim Taymans's avatar
Wim Taymans committed
208 209 210 211 212

  res =
      gst_memory_unmap (mem->mem.parent, ptr - mem->offset, size + mem->offset);

  return res;
213 214 215
}

static void
Wim Taymans's avatar
Wim Taymans committed
216
_default_mem_free (GstMemoryDefault * mem)
217
{
Wim Taymans's avatar
Wim Taymans committed
218 219 220 221 222
  if (mem->mem.parent)
    gst_memory_unref (mem->mem.parent);

  if (mem->free_func)
    mem->free_func (mem->data);
223

Wim Taymans's avatar
Wim Taymans committed
224
  g_slice_free1 (mem->slice_size, mem);
225 226
}

Wim Taymans's avatar
Wim Taymans committed
227
static GstMemoryDefault *
228
_default_mem_copy (GstMemoryDefault * mem, gsize offset, gsize size)
229 230 231
{
  GstMemoryDefault *copy;

Wim Taymans's avatar
Wim Taymans committed
232 233
  if (size == -1)
    size = mem->size > offset ? mem->size - offset : 0;
Wim Taymans's avatar
Wim Taymans committed
234

235 236
  copy = _default_mem_new_block (mem->maxsize, 0, mem->offset + offset, size);
  memcpy (copy->data, mem->data, mem->maxsize);
237

Wim Taymans's avatar
Wim Taymans committed
238
  return copy;
239 240
}

Wim Taymans's avatar
Wim Taymans committed
241
static GstMemoryDefault *
Wim Taymans's avatar
Wim Taymans committed
242
_default_mem_share (GstMemoryDefault * mem, gsize offset, gsize size)
Wim Taymans's avatar
Wim Taymans committed
243 244 245 246 247 248 249 250
{
  GstMemoryDefault *sub;
  GstMemory *parent;

  /* find the real parent */
  if ((parent = mem->mem.parent) == NULL)
    parent = (GstMemory *) mem;

251 252 253
  if (size == -1)
    size = mem->size - offset;

254
  sub = _default_mem_new (parent->flags, parent, mem->data, NULL, mem->maxsize,
Wim Taymans's avatar
Wim Taymans committed
255 256 257
      mem->offset + offset, size);

  return sub;
258 259
}

Wim Taymans's avatar
Wim Taymans committed
260
static gboolean
Wim Taymans's avatar
Wim Taymans committed
261 262
_default_mem_is_span (GstMemoryDefault * mem1, GstMemoryDefault * mem2,
    gsize * offset)
263
{
Wim Taymans's avatar
Wim Taymans committed
264 265
  if (offset)
    *offset = mem1->offset;
266

Wim Taymans's avatar
Wim Taymans committed
267
  /* and memory is contiguous */
Wim Taymans's avatar
Wim Taymans committed
268
  return mem1->data + mem1->offset + mem1->size == mem2->data + mem2->offset;
269 270 271
}

static GstMemory *
272
_fallback_copy (GstMemory * mem, gsize offset, gsize size)
273
{
Wim Taymans's avatar
Wim Taymans committed
274
  GstMemoryDefault *copy;
275 276
  guint8 *data;
  gsize msize;
277

278
  data = gst_memory_map (mem, &msize, NULL, GST_MAP_READ);
Wim Taymans's avatar
Wim Taymans committed
279 280
  if (size == -1)
    size = msize > offset ? msize - offset : 0;
Wim Taymans's avatar
Wim Taymans committed
281
  copy = _default_mem_new_block (size, 0, 0, size);
282 283
  memcpy (copy->data, data + offset, size);
  gst_memory_unmap (mem, data, msize);
284

Wim Taymans's avatar
Wim Taymans committed
285
  return (GstMemory *) copy;
286 287 288
}

static GstMemory *
Wim Taymans's avatar
Wim Taymans committed
289
_fallback_share (GstMemory * mem, gsize offset, gsize size)
290 291 292
{
  GstMemoryDefault *sub;

293
  sub = _default_mem_new (0, mem, NULL, NULL, size, offset, size);
294 295 296 297 298

  return (GstMemory *) sub;
}

static gboolean
Wim Taymans's avatar
Wim Taymans committed
299
_fallback_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
300 301 302 303
{
  return FALSE;
}

Wim Taymans's avatar
Wim Taymans committed
304 305 306 307 308
void
_gst_memory_init (void)
{
  static const GstMemoryInfo _mem_info = {
    (GstMemoryGetSizesFunction) _default_mem_get_sizes,
Wim Taymans's avatar
Wim Taymans committed
309
    (GstMemoryResizeFunction) _default_mem_resize,
Wim Taymans's avatar
Wim Taymans committed
310 311 312 313
    (GstMemoryMapFunction) _default_mem_map,
    (GstMemoryUnmapFunction) _default_mem_unmap,
    (GstMemoryFreeFunction) _default_mem_free,
    (GstMemoryCopyFunction) _default_mem_copy,
Wim Taymans's avatar
Wim Taymans committed
314
    (GstMemoryShareFunction) _default_mem_share,
Wim Taymans's avatar
Wim Taymans committed
315 316
    (GstMemoryIsSpanFunction) _default_mem_is_span
  };
Wim Taymans's avatar
Wim Taymans committed
317
  static const GstMemoryInfo _share_info = {
Wim Taymans's avatar
Wim Taymans committed
318
    (GstMemoryGetSizesFunction) _default_mem_get_sizes,
Wim Taymans's avatar
Wim Taymans committed
319 320 321
    (GstMemoryResizeFunction) _default_mem_resize,
    (GstMemoryMapFunction) _default_share_map,
    (GstMemoryUnmapFunction) _default_share_unmap,
Wim Taymans's avatar
Wim Taymans committed
322 323 324 325 326 327 328
    (GstMemoryFreeFunction) _default_mem_free,
    NULL,
    NULL,
    NULL
  };

  _default_mem_impl = gst_memory_register ("GstMemoryDefault", &_mem_info);
Wim Taymans's avatar
Wim Taymans committed
329 330
  _default_share_impl =
      gst_memory_register ("GstMemorySharebuffer", &_share_info);
Wim Taymans's avatar
Wim Taymans committed
331 332 333 334
}

/**
 * gst_memory_register:
Wim Taymans's avatar
Wim Taymans committed
335 336 337 338 339
 * @name: the name of the implementation
 * @info: #GstMemoryInfo
 *
 * Registers the memory implementation with @name and implementation functions
 * @info.
Wim Taymans's avatar
Wim Taymans committed
340
 *
Wim Taymans's avatar
Wim Taymans committed
341
 * Returns: a new #GstMemoryImpl.
Wim Taymans's avatar
Wim Taymans committed
342
 */
343 344 345 346 347
const GstMemoryImpl *
gst_memory_register (const gchar * name, const GstMemoryInfo * info)
{
  GstMemoryImpl *impl;

348 349 350
#define INSTALL_FALLBACK(_t) \
  if (impl->info._t == NULL) impl->info._t = _fallback_ ##_t;

351 352
  g_return_val_if_fail (name != NULL, NULL);
  g_return_val_if_fail (info != NULL, NULL);
353
  g_return_val_if_fail (info->get_sizes != NULL, NULL);
Wim Taymans's avatar
Wim Taymans committed
354
  g_return_val_if_fail (info->resize != NULL, NULL);
355 356 357
  g_return_val_if_fail (info->map != NULL, NULL);
  g_return_val_if_fail (info->unmap != NULL, NULL);
  g_return_val_if_fail (info->free != NULL, NULL);
358 359 360 361

  impl = g_slice_new (GstMemoryImpl);
  impl->name = g_quark_from_string (name);
  impl->info = *info;
362
  INSTALL_FALLBACK (copy);
Wim Taymans's avatar
Wim Taymans committed
363
  INSTALL_FALLBACK (share);
364
  INSTALL_FALLBACK (is_span);
365 366 367 368 369 370 371 372

  GST_DEBUG ("register \"%s\" of size %" G_GSIZE_FORMAT, name);

#if 0
  g_static_rw_lock_writer_lock (&lock);
  g_hash_table_insert (memoryimpl, (gpointer) name, (gpointer) impl);
  g_static_rw_lock_writer_unlock (&lock);
#endif
373
#undef INSTALL_FALLBACK
374 375 376 377

  return impl;
}

Wim Taymans's avatar
Wim Taymans committed
378 379 380 381 382 383 384 385 386 387 388 389 390
/**
 * gst_memory_new_wrapped:
 * @flags: #GstMemoryFlags
 * @data: data to wrap
 * @free_func: function to free @data
 * @maxsize: allocated size of @data
 * @offset: offset in @data
 * @size: size of valid data
 *
 * Allocate a new memory block that wraps the given @data.
 *
 * Returns: a new #GstMemory.
 */
Wim Taymans's avatar
Wim Taymans committed
391 392 393
GstMemory *
gst_memory_new_wrapped (GstMemoryFlags flags, gpointer data,
    GFreeFunc free_func, gsize maxsize, gsize offset, gsize size)
394
{
Wim Taymans's avatar
Wim Taymans committed
395
  GstMemoryDefault *mem;
Wim Taymans's avatar
Wim Taymans committed
396

Wim Taymans's avatar
Wim Taymans committed
397 398 399
  g_return_val_if_fail (data != NULL, NULL);
  g_return_val_if_fail (offset + size <= maxsize, NULL);

Wim Taymans's avatar
Wim Taymans committed
400 401 402 403 404
  mem = _default_mem_new (flags, NULL, data, free_func, maxsize, offset, size);

  return (GstMemory *) mem;
}

Wim Taymans's avatar
Wim Taymans committed
405 406 407 408 409
/**
 * gst_memory_new_alloc:
 * @maxsize: allocated size of @data
 * @align: alignment for the data
 *
410
 * Allocate a new memory block with memory that is at least @maxsize big and has
Wim Taymans's avatar
Wim Taymans committed
411 412
 * the given alignment.
 *
413 414 415
 * @align is given as a bitmask so that @align + 1 equals the amount of bytes to
 * align to. For example, to align to 8 bytes, use an alignment of 7.
 *
Wim Taymans's avatar
Wim Taymans committed
416 417
 * Returns: a new #GstMemory.
 */
Wim Taymans's avatar
Wim Taymans committed
418 419 420 421 422
GstMemory *
gst_memory_new_alloc (gsize maxsize, gsize align)
{
  GstMemoryDefault *mem;

423 424
  g_return_val_if_fail (((align + 1) & align) == 0, NULL);

Wim Taymans's avatar
Wim Taymans committed
425 426 427
  mem = _default_mem_new_block (maxsize, align, 0, maxsize);

  return (GstMemory *) mem;
428 429
}

Wim Taymans's avatar
Wim Taymans committed
430 431 432 433
/**
 * gst_memory_ref:
 * @mem: a #GstMemory
 *
Wim Taymans's avatar
Wim Taymans committed
434 435
 * Increases the refcount of @mem.
 *
Wim Taymans's avatar
Wim Taymans committed
436 437
 * Returns: @mem with increased refcount
 */
438 439 440 441 442 443 444 445 446 447
GstMemory *
gst_memory_ref (GstMemory * mem)
{
  g_return_val_if_fail (mem != NULL, NULL);

  g_atomic_int_inc (&mem->refcount);

  return mem;
}

Wim Taymans's avatar
Wim Taymans committed
448 449 450
/**
 * gst_memory_unref:
 * @mem: a #GstMemory
Wim Taymans's avatar
Wim Taymans committed
451 452 453
 *
 * Decreases the refcount of @mem. When the refcount reaches 0, the free
 * function of @mem will be called.
Wim Taymans's avatar
Wim Taymans committed
454
 */
455 456 457 458
void
gst_memory_unref (GstMemory * mem)
{
  g_return_if_fail (mem != NULL);
459
  g_return_if_fail (mem->impl != NULL);
460 461 462 463 464

  if (g_atomic_int_dec_and_test (&mem->refcount))
    mem->impl->info.free (mem);
}

Wim Taymans's avatar
Wim Taymans committed
465 466 467 468 469
/**
 * gst_memory_get_sizes:
 * @mem: a #GstMemory
 * @maxsize: pointer to maxsize
 *
Wim Taymans's avatar
Wim Taymans committed
470 471 472
 * Get the current @size and @maxsize of @mem.
 *
 * Returns: the current sizes of @mem
Wim Taymans's avatar
Wim Taymans committed
473
 */
474 475 476 477 478 479 480 481
gsize
gst_memory_get_sizes (GstMemory * mem, gsize * maxsize)
{
  g_return_val_if_fail (mem != NULL, 0);

  return mem->impl->info.get_sizes (mem, maxsize);
}

Wim Taymans's avatar
Wim Taymans committed
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
/**
 * gst_memory_resize:
 * @mem: a #GstMemory
 * @offset: a new offset
 * @size: a new size
 *
 * Resize the memory region. @mem should be writable and offset + size should be
 * less than the maxsize of @mem.
 */
void
gst_memory_resize (GstMemory * mem, gsize offset, gsize size)
{
  g_return_if_fail (mem != NULL);
  g_return_if_fail (GST_MEMORY_IS_WRITABLE (mem));

  mem->impl->info.resize (mem, offset, size);
}

/**
 * gst_memory_map:
 * @mem: a #GstMemory
 * @size: pointer for size
 * @maxsize: pointer for maxsize
 * @flags: mapping flags
 *
 * Get a pointer to the memory of @mem that can be accessed according to @flags.
 *
 * @size and @maxsize will contain the size of the memory and the maximum
 * allocated memory of @mem respectively. They can be set to NULL.
 *
 * Returns: a pointer to the memory of @mem.
 */
514 515 516 517 518
gpointer
gst_memory_map (GstMemory * mem, gsize * size, gsize * maxsize,
    GstMapFlags flags)
{
  g_return_val_if_fail (mem != NULL, NULL);
Wim Taymans's avatar
Wim Taymans committed
519 520
  g_return_val_if_fail (!(flags & GST_MAP_WRITE) ||
      GST_MEMORY_IS_WRITABLE (mem), NULL);
521 522 523 524

  return mem->impl->info.map (mem, size, maxsize, flags);
}

Wim Taymans's avatar
Wim Taymans committed
525 526 527 528 529 530 531 532 533 534 535 536
/**
 * gst_memory_unmap:
 * @mem: a #GstMemory
 * @data: data to unmap
 * @size: new size of @mem
 *
 * Release the memory pointer obtained with gst_memory_map() and set the size of
 * the memory to @size. @size can be set to -1 when the size should not be
 * updated.
 *
 * Returns: TRUE when the memory was release successfully.
 */
537 538 539 540 541 542 543 544
gboolean
gst_memory_unmap (GstMemory * mem, gpointer data, gsize size)
{
  g_return_val_if_fail (mem != NULL, FALSE);

  return mem->impl->info.unmap (mem, data, size);
}

Wim Taymans's avatar
Wim Taymans committed
545 546 547 548 549 550 551 552 553 554 555 556
/**
 * gst_memory_copy:
 * @mem: a #GstMemory
 * @offset: an offset to copy
 * @size: size to copy
 *
 * Return a copy of @size bytes from @mem starting from @offset. This copy is
 * guaranteed to be writable. @size can be set to -1 to return a copy all bytes
 * from @offset.
 *
 * Returns: a new #GstMemory.
 */
557
GstMemory *
558
gst_memory_copy (GstMemory * mem, gsize offset, gsize size)
559 560 561
{
  g_return_val_if_fail (mem != NULL, NULL);

562
  return mem->impl->info.copy (mem, offset, size);
563 564
}

Wim Taymans's avatar
Wim Taymans committed
565 566 567 568 569 570 571 572 573 574 575 576 577
/**
 * gst_memory_share:
 * @mem: a #GstMemory
 * @offset: an offset to share
 * @size: size to share
 *
 * Return a shared copy of @size bytes from @mem starting from @offset. No memory
 * copy is performed and the memory region is simply shared. The result is
 * guaranteed to be not-writable. @size can be set to -1 to return a share all bytes
 * from @offset.
 *
 * Returns: a new #GstMemory.
 */
578
GstMemory *
Wim Taymans's avatar
Wim Taymans committed
579
gst_memory_share (GstMemory * mem, gsize offset, gsize size)
580 581 582
{
  g_return_val_if_fail (mem != NULL, NULL);

Wim Taymans's avatar
Wim Taymans committed
583
  return mem->impl->info.share (mem, offset, size);
584 585
}

Wim Taymans's avatar
Wim Taymans committed
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
/**
 * gst_memory_is_span:
 * @mem1: a #GstMemory
 * @mem2: a #GstMemory
 * @offset: a pointer to a result offset
 *
 * Check if @mem1 and mem2 share the memory with a common parent memory object
 * and that the memory is contiguous.
 *
 * If this is the case, the memory of @mem1 and @mem2 can be merged
 * efficiently by performing gst_memory_share() on the parent object from
 * the returned @offset.
 *
 * Returns: %TRUE if the memory is contiguous and of a common parent.
 */
Wim Taymans's avatar
Wim Taymans committed
601
gboolean
602
gst_memory_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
Wim Taymans's avatar
Wim Taymans committed
603 604 605 606
{
  g_return_val_if_fail (mem1 != NULL, FALSE);
  g_return_val_if_fail (mem2 != NULL, FALSE);

607 608
  /* need to have the same implementation */
  if (mem1->impl != mem2->impl)
Wim Taymans's avatar
Wim Taymans committed
609 610
    return FALSE;

611 612 613
  /* need to have the same parent */
  if (mem1->parent == NULL || mem1->parent != mem2->parent)
    return FALSE;
Wim Taymans's avatar
Wim Taymans committed
614

615 616 617 618 619
  /* and memory is contiguous */
  if (!mem1->impl->info.is_span (mem1, mem2, offset))
    return FALSE;

  return TRUE;
Wim Taymans's avatar
Wim Taymans committed
620
}