gstmemory.c 15.3 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 124 125 126 127 128 129 130 131 132 133 134 135
static GstMemoryDefault *
_default_mem_new_block (gsize maxsize, gsize align, gsize offset, gsize size)
{
  GstMemoryDefault *mem;
  gsize aoffset, slice_size;
  guint8 *data;

  /* alloc header and data in one block */
  slice_size = sizeof (GstMemoryDefault) + maxsize + align;

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

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

  if ((aoffset = ((guintptr) data & align)))
    aoffset = align - aoffset;

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

  return mem;
}

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

Wim Taymans's avatar
Wim Taymans committed
148 149 150 151
  return mem->size;
}

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

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

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

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

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

  data = gst_memory_map (mem->mem.parent, size, maxsize, flags);
179 180

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

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

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

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

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

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

  return res;
211 212 213
}

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

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

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

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

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

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

Wim Taymans's avatar
Wim Taymans committed
236
  return copy;
237 238
}

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

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

249 250 251
  if (size == -1)
    size = mem->size - offset;

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

  return sub;
256 257
}

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

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

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

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

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

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

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

  return (GstMemory *) sub;
}

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

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

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

/**
 * gst_memory_register:
Wim Taymans's avatar
Wim Taymans committed
333 334 335 336 337
 * @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
338
 *
Wim Taymans's avatar
Wim Taymans committed
339
 * Returns: a new #GstMemoryImpl.
Wim Taymans's avatar
Wim Taymans committed
340
 */
341 342 343 344 345
const GstMemoryImpl *
gst_memory_register (const gchar * name, const GstMemoryInfo * info)
{
  GstMemoryImpl *impl;

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

349 350
  g_return_val_if_fail (name != NULL, NULL);
  g_return_val_if_fail (info != NULL, NULL);
351
  g_return_val_if_fail (info->get_sizes != NULL, NULL);
Wim Taymans's avatar
Wim Taymans committed
352
  g_return_val_if_fail (info->resize != NULL, NULL);
353 354 355
  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);
356 357 358 359

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

  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
371
#undef INSTALL_FALLBACK
372 373 374 375

  return impl;
}

Wim Taymans's avatar
Wim Taymans committed
376 377 378 379 380 381 382 383 384 385 386 387 388
/**
 * 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
389 390 391
GstMemory *
gst_memory_new_wrapped (GstMemoryFlags flags, gpointer data,
    GFreeFunc free_func, gsize maxsize, gsize offset, gsize size)
392
{
Wim Taymans's avatar
Wim Taymans committed
393
  GstMemoryDefault *mem;
Wim Taymans's avatar
Wim Taymans committed
394

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

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

  return (GstMemory *) mem;
}

Wim Taymans's avatar
Wim Taymans committed
403 404 405 406 407 408 409 410 411 412
/**
 * gst_memory_new_alloc:
 * @maxsize: allocated size of @data
 * @align: alignment for the data
 *
 * Allocate a new memory block with memory that is at least @maxsize big and las
 * the given alignment.
 *
 * Returns: a new #GstMemory.
 */
Wim Taymans's avatar
Wim Taymans committed
413 414 415 416 417 418 419 420
GstMemory *
gst_memory_new_alloc (gsize maxsize, gsize align)
{
  GstMemoryDefault *mem;

  mem = _default_mem_new_block (maxsize, align, 0, maxsize);

  return (GstMemory *) mem;
421 422
}

Wim Taymans's avatar
Wim Taymans committed
423 424 425 426
/**
 * gst_memory_ref:
 * @mem: a #GstMemory
 *
Wim Taymans's avatar
Wim Taymans committed
427 428
 * Increases the refcount of @mem.
 *
Wim Taymans's avatar
Wim Taymans committed
429 430
 * Returns: @mem with increased refcount
 */
431 432 433 434 435 436 437 438 439 440
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
441 442 443
/**
 * gst_memory_unref:
 * @mem: a #GstMemory
Wim Taymans's avatar
Wim Taymans committed
444 445 446
 *
 * 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
447
 */
448 449 450 451
void
gst_memory_unref (GstMemory * mem)
{
  g_return_if_fail (mem != NULL);
452
  g_return_if_fail (mem->impl != NULL);
453 454 455 456 457

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

Wim Taymans's avatar
Wim Taymans committed
458 459 460 461 462
/**
 * gst_memory_get_sizes:
 * @mem: a #GstMemory
 * @maxsize: pointer to maxsize
 *
Wim Taymans's avatar
Wim Taymans committed
463 464 465
 * Get the current @size and @maxsize of @mem.
 *
 * Returns: the current sizes of @mem
Wim Taymans's avatar
Wim Taymans committed
466
 */
467 468 469 470 471 472 473 474
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
475 476 477 478 479 480 481 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
/**
 * 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.
 */
507 508 509 510 511
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
512 513
  g_return_val_if_fail (!(flags & GST_MAP_WRITE) ||
      GST_MEMORY_IS_WRITABLE (mem), NULL);
514 515 516 517

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

Wim Taymans's avatar
Wim Taymans committed
518 519 520 521 522 523 524 525 526 527 528 529
/**
 * 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.
 */
530 531 532 533 534 535 536 537
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
538 539 540 541 542 543 544 545 546 547 548 549
/**
 * 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.
 */
550
GstMemory *
551
gst_memory_copy (GstMemory * mem, gsize offset, gsize size)
552 553 554
{
  g_return_val_if_fail (mem != NULL, NULL);

555
  return mem->impl->info.copy (mem, offset, size);
556 557
}

Wim Taymans's avatar
Wim Taymans committed
558 559 560 561 562 563 564 565 566 567 568 569 570
/**
 * 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.
 */
571
GstMemory *
Wim Taymans's avatar
Wim Taymans committed
572
gst_memory_share (GstMemory * mem, gsize offset, gsize size)
573 574 575
{
  g_return_val_if_fail (mem != NULL, NULL);

Wim Taymans's avatar
Wim Taymans committed
576
  return mem->impl->info.share (mem, offset, size);
577 578
}

Wim Taymans's avatar
Wim Taymans committed
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
/**
 * 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
594
gboolean
595
gst_memory_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
Wim Taymans's avatar
Wim Taymans committed
596 597 598 599
{
  g_return_val_if_fail (mem1 != NULL, FALSE);
  g_return_val_if_fail (mem2 != NULL, FALSE);

600 601
  /* need to have the same implementation */
  if (mem1->impl != mem2->impl)
Wim Taymans's avatar
Wim Taymans committed
602 603
    return FALSE;

604 605 606
  /* need to have the same parent */
  if (mem1->parent == NULL || mem1->parent != mem2->parent)
    return FALSE;
Wim Taymans's avatar
Wim Taymans committed
607

608 609 610 611 612
  /* and memory is contiguous */
  if (!mem1->impl->info.is_span (mem1, mem2, offset))
    return FALSE;

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