gstmemory.c 17.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
/**
 * 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.
 *
30 31
 * Memory is created by allocators.
 *
Wim Taymans's avatar
Wim Taymans committed
32
 * New memory can be created with gst_memory_new_wrapped() that wraps the memory
33
 * allocated elsewhere.
Wim Taymans's avatar
Wim Taymans committed
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
 *
 * 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)
 */
54

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

Wim Taymans's avatar
Wim Taymans committed
59

60
struct _GstMemoryAllocator
61 62 63 64 65 66
{
  GQuark name;

  GstMemoryInfo info;
};

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

79 80 81 82 83 84
/* the default allocator */
static const GstMemoryAllocator *_default_allocator;

/* our predefined allocators */
static const GstMemoryAllocator *_default_mem_impl;
static const GstMemoryAllocator *_default_share_impl;
Wim Taymans's avatar
Wim Taymans committed
85

Wim Taymans's avatar
Wim Taymans committed
86
/* initialize the fields */
Wim Taymans's avatar
Wim Taymans committed
87
static void
88 89 90
_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
91
{
92
  mem->mem.allocator = data ? _default_mem_impl : _default_share_impl;
93
  mem->mem.flags = flags;
Wim Taymans's avatar
Wim Taymans committed
94
  mem->mem.refcount = 1;
Wim Taymans's avatar
Wim Taymans committed
95 96 97 98 99 100 101 102 103
  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
104
/* create a new memory block that manages the given memory */
Wim Taymans's avatar
Wim Taymans committed
105
static GstMemoryDefault *
106
_default_mem_new (GstMemoryFlags flags, GstMemory * parent, gpointer data,
Wim Taymans's avatar
Wim Taymans committed
107 108 109
    GFreeFunc free_func, gsize maxsize, gsize offset, gsize size)
{
  GstMemoryDefault *mem;
Wim Taymans's avatar
Wim Taymans committed
110
  gsize slice_size;
Wim Taymans's avatar
Wim Taymans committed
111

Wim Taymans's avatar
Wim Taymans committed
112 113 114
  slice_size = sizeof (GstMemoryDefault);

  mem = g_slice_alloc (slice_size);
115
  _default_mem_init (mem, flags, parent, slice_size,
Wim Taymans's avatar
Wim Taymans committed
116 117 118 119
      data, free_func, maxsize, offset, size);

  return mem;
}
120

Wim Taymans's avatar
Wim Taymans committed
121
/* allocate the memory and structure in one block */
Wim Taymans's avatar
Wim Taymans committed
122 123 124 125 126 127 128
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
129 130
  /* allocate more to compensate for alignment */
  maxsize += align;
Wim Taymans's avatar
Wim Taymans committed
131
  /* alloc header and data in one block */
Wim Taymans's avatar
Wim Taymans committed
132
  slice_size = sizeof (GstMemoryDefault) + maxsize;
Wim Taymans's avatar
Wim Taymans committed
133 134 135 136 137 138 139 140

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

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

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

Wim Taymans's avatar
Wim Taymans committed
143
  _default_mem_init (mem, 0, NULL, slice_size, data, NULL, maxsize,
Wim Taymans's avatar
Wim Taymans committed
144 145 146 147 148
      aoffset + offset, size);

  return mem;
}

149 150 151 152 153 154 155
static GstMemory *
_default_mem_alloc (const GstMemoryAllocator * allocator, gsize maxsize,
    gsize align)
{
  return (GstMemory *) _default_mem_new_block (maxsize, align, 0, maxsize);
}

156
static gsize
Wim Taymans's avatar
Wim Taymans committed
157
_default_mem_get_sizes (GstMemoryDefault * mem, gsize * maxsize)
158
{
Wim Taymans's avatar
Wim Taymans committed
159 160
  if (maxsize)
    *maxsize = mem->maxsize;
161

Wim Taymans's avatar
Wim Taymans committed
162 163 164 165
  return mem->size;
}

static void
Wim Taymans's avatar
Wim Taymans committed
166
_default_mem_resize (GstMemoryDefault * mem, gsize offset, gsize size)
Wim Taymans's avatar
Wim Taymans committed
167
{
Wim Taymans's avatar
Wim Taymans committed
168
  g_return_if_fail (size + mem->offset + offset <= mem->maxsize);
Wim Taymans's avatar
Wim Taymans committed
169 170 171 172 173 174 175 176 177 178 179

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

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

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

static gpointer
Wim Taymans's avatar
Wim Taymans committed
187
_default_share_map (GstMemoryDefault * mem, gsize * size, gsize * maxsize,
Wim Taymans's avatar
Wim Taymans committed
188
    GstMapFlags flags)
189
{
Wim Taymans's avatar
Wim Taymans committed
190 191 192
  guint8 *data;

  data = gst_memory_map (mem->mem.parent, size, maxsize, flags);
193 194

  if (size)
Wim Taymans's avatar
Wim Taymans committed
195
    *size = mem->size;
196
  if (maxsize)
Wim Taymans's avatar
Wim Taymans committed
197
    *maxsize -= mem->offset;
198

Wim Taymans's avatar
Wim Taymans committed
199
  return data + mem->offset;
200 201 202
}

static gboolean
Wim Taymans's avatar
Wim Taymans committed
203
_default_mem_unmap (GstMemoryDefault * mem, gpointer data, gsize size)
204
{
Wim Taymans's avatar
Wim Taymans committed
205 206
  if (size != -1)
    mem->size = size;
Wim Taymans's avatar
Wim Taymans committed
207 208
  return TRUE;
}
209

Wim Taymans's avatar
Wim Taymans committed
210
static gboolean
Wim Taymans's avatar
Wim Taymans committed
211
_default_share_unmap (GstMemoryDefault * mem, gpointer data, gsize size)
Wim Taymans's avatar
Wim Taymans committed
212 213 214
{
  gboolean res;
  guint8 *ptr = data;
215

Wim Taymans's avatar
Wim Taymans committed
216 217 218 219
  if (size != -1)
    mem->size = size;
  else
    size = mem->size - mem->offset;
Wim Taymans's avatar
Wim Taymans committed
220 221 222 223 224

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

  return res;
225 226 227
}

static void
Wim Taymans's avatar
Wim Taymans committed
228
_default_mem_free (GstMemoryDefault * mem)
229
{
Wim Taymans's avatar
Wim Taymans committed
230 231 232 233 234
  if (mem->mem.parent)
    gst_memory_unref (mem->mem.parent);

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

Wim Taymans's avatar
Wim Taymans committed
236
  g_slice_free1 (mem->slice_size, mem);
237 238
}

Wim Taymans's avatar
Wim Taymans committed
239
static GstMemoryDefault *
240
_default_mem_copy (GstMemoryDefault * mem, gsize offset, gsize size)
241 242 243
{
  GstMemoryDefault *copy;

Wim Taymans's avatar
Wim Taymans committed
244 245
  if (size == -1)
    size = mem->size > offset ? mem->size - offset : 0;
Wim Taymans's avatar
Wim Taymans committed
246

247 248
  copy = _default_mem_new_block (mem->maxsize, 0, mem->offset + offset, size);
  memcpy (copy->data, mem->data, mem->maxsize);
249

Wim Taymans's avatar
Wim Taymans committed
250
  return copy;
251 252
}

Wim Taymans's avatar
Wim Taymans committed
253
static GstMemoryDefault *
Wim Taymans's avatar
Wim Taymans committed
254
_default_mem_share (GstMemoryDefault * mem, gsize offset, gsize size)
Wim Taymans's avatar
Wim Taymans committed
255 256 257 258 259 260 261 262
{
  GstMemoryDefault *sub;
  GstMemory *parent;

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

263 264 265
  if (size == -1)
    size = mem->size - offset;

266
  sub = _default_mem_new (parent->flags, parent, mem->data, NULL, mem->maxsize,
Wim Taymans's avatar
Wim Taymans committed
267 268 269
      mem->offset + offset, size);

  return sub;
270 271
}

Wim Taymans's avatar
Wim Taymans committed
272
static gboolean
Wim Taymans's avatar
Wim Taymans committed
273 274
_default_mem_is_span (GstMemoryDefault * mem1, GstMemoryDefault * mem2,
    gsize * offset)
275
{
Wim Taymans's avatar
Wim Taymans committed
276 277
  if (offset)
    *offset = mem1->offset;
278

Wim Taymans's avatar
Wim Taymans committed
279
  /* and memory is contiguous */
Wim Taymans's avatar
Wim Taymans committed
280
  return mem1->data + mem1->offset + mem1->size == mem2->data + mem2->offset;
281 282 283
}

static GstMemory *
284
_fallback_copy (GstMemory * mem, gsize offset, gsize size)
285
{
Wim Taymans's avatar
Wim Taymans committed
286
  GstMemoryDefault *copy;
287 288
  guint8 *data;
  gsize msize;
289

290
  data = gst_memory_map (mem, &msize, NULL, GST_MAP_READ);
Wim Taymans's avatar
Wim Taymans committed
291 292
  if (size == -1)
    size = msize > offset ? msize - offset : 0;
Wim Taymans's avatar
Wim Taymans committed
293
  copy = _default_mem_new_block (size, 0, 0, size);
294 295
  memcpy (copy->data, data + offset, size);
  gst_memory_unmap (mem, data, msize);
296

Wim Taymans's avatar
Wim Taymans committed
297
  return (GstMemory *) copy;
298 299 300
}

static GstMemory *
Wim Taymans's avatar
Wim Taymans committed
301
_fallback_share (GstMemory * mem, gsize offset, gsize size)
302 303 304
{
  GstMemoryDefault *sub;

305
  sub = _default_mem_new (0, mem, NULL, NULL, size, offset, size);
306 307 308 309 310

  return (GstMemory *) sub;
}

static gboolean
Wim Taymans's avatar
Wim Taymans committed
311
_fallback_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
312 313 314 315
{
  return FALSE;
}

316 317 318
static GStaticRWLock lock = G_STATIC_RW_LOCK_INIT;
static GHashTable *memoryimpl;

Wim Taymans's avatar
Wim Taymans committed
319 320 321 322
void
_gst_memory_init (void)
{
  static const GstMemoryInfo _mem_info = {
323
    (GstMemoryAllocFunction) _default_mem_alloc,
Wim Taymans's avatar
Wim Taymans committed
324
    (GstMemoryGetSizesFunction) _default_mem_get_sizes,
Wim Taymans's avatar
Wim Taymans committed
325
    (GstMemoryResizeFunction) _default_mem_resize,
Wim Taymans's avatar
Wim Taymans committed
326 327 328 329
    (GstMemoryMapFunction) _default_mem_map,
    (GstMemoryUnmapFunction) _default_mem_unmap,
    (GstMemoryFreeFunction) _default_mem_free,
    (GstMemoryCopyFunction) _default_mem_copy,
Wim Taymans's avatar
Wim Taymans committed
330
    (GstMemoryShareFunction) _default_mem_share,
331 332
    (GstMemoryIsSpanFunction) _default_mem_is_span,
    NULL
Wim Taymans's avatar
Wim Taymans committed
333
  };
Wim Taymans's avatar
Wim Taymans committed
334
  static const GstMemoryInfo _share_info = {
335
    (GstMemoryAllocFunction) _default_mem_alloc,
Wim Taymans's avatar
Wim Taymans committed
336
    (GstMemoryGetSizesFunction) _default_mem_get_sizes,
Wim Taymans's avatar
Wim Taymans committed
337 338 339
    (GstMemoryResizeFunction) _default_mem_resize,
    (GstMemoryMapFunction) _default_share_map,
    (GstMemoryUnmapFunction) _default_share_unmap,
Wim Taymans's avatar
Wim Taymans committed
340 341 342
    (GstMemoryFreeFunction) _default_mem_free,
    NULL,
    NULL,
343
    NULL,
Wim Taymans's avatar
Wim Taymans committed
344 345 346
    NULL
  };

347
  memoryimpl = g_hash_table_new (g_str_hash, g_str_equal);
348

349 350 351 352
  _default_mem_impl =
      gst_memory_allocator_register ("GstMemoryDefault", &_mem_info);
  _default_share_impl =
      gst_memory_allocator_register ("GstMemorySharebuffer", &_share_info);
353

354
  _default_allocator = _default_mem_impl;
355 356
}

Wim Taymans's avatar
Wim Taymans committed
357 358 359 360 361 362 363 364 365 366 367 368 369
/**
 * 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
370 371 372
GstMemory *
gst_memory_new_wrapped (GstMemoryFlags flags, gpointer data,
    GFreeFunc free_func, gsize maxsize, gsize offset, gsize size)
373
{
Wim Taymans's avatar
Wim Taymans committed
374
  GstMemoryDefault *mem;
Wim Taymans's avatar
Wim Taymans committed
375

Wim Taymans's avatar
Wim Taymans committed
376 377 378
  g_return_val_if_fail (data != NULL, NULL);
  g_return_val_if_fail (offset + size <= maxsize, NULL);

Wim Taymans's avatar
Wim Taymans committed
379 380 381 382 383 384 385 386 387
  mem = _default_mem_new (flags, NULL, data, free_func, maxsize, offset, size);

  return (GstMemory *) mem;
}

/**
 * gst_memory_ref:
 * @mem: a #GstMemory
 *
Wim Taymans's avatar
Wim Taymans committed
388 389
 * Increases the refcount of @mem.
 *
Wim Taymans's avatar
Wim Taymans committed
390 391
 * Returns: @mem with increased refcount
 */
392 393 394 395 396 397 398 399 400 401
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
402 403 404
/**
 * gst_memory_unref:
 * @mem: a #GstMemory
Wim Taymans's avatar
Wim Taymans committed
405 406 407
 *
 * 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
408
 */
409 410 411 412
void
gst_memory_unref (GstMemory * mem)
{
  g_return_if_fail (mem != NULL);
413
  g_return_if_fail (mem->allocator != NULL);
414 415

  if (g_atomic_int_dec_and_test (&mem->refcount))
416
    mem->allocator->info.free (mem);
417 418
}

Wim Taymans's avatar
Wim Taymans committed
419 420 421 422 423
/**
 * gst_memory_get_sizes:
 * @mem: a #GstMemory
 * @maxsize: pointer to maxsize
 *
Wim Taymans's avatar
Wim Taymans committed
424 425 426
 * Get the current @size and @maxsize of @mem.
 *
 * Returns: the current sizes of @mem
Wim Taymans's avatar
Wim Taymans committed
427
 */
428 429 430 431 432
gsize
gst_memory_get_sizes (GstMemory * mem, gsize * maxsize)
{
  g_return_val_if_fail (mem != NULL, 0);

433
  return mem->allocator->info.get_sizes (mem, maxsize);
434 435
}

Wim Taymans's avatar
Wim Taymans committed
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
/**
 * 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));

451
  mem->allocator->info.resize (mem, offset, size);
Wim Taymans's avatar
Wim Taymans committed
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
}

/**
 * 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.
 */
468 469 470 471 472
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
473 474
  g_return_val_if_fail (!(flags & GST_MAP_WRITE) ||
      GST_MEMORY_IS_WRITABLE (mem), NULL);
475

476
  return mem->allocator->info.map (mem, size, maxsize, flags);
477 478
}

Wim Taymans's avatar
Wim Taymans committed
479 480 481 482 483 484 485 486 487 488 489 490
/**
 * 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.
 */
491 492 493 494 495
gboolean
gst_memory_unmap (GstMemory * mem, gpointer data, gsize size)
{
  g_return_val_if_fail (mem != NULL, FALSE);

496
  return mem->allocator->info.unmap (mem, data, size);
497 498
}

Wim Taymans's avatar
Wim Taymans committed
499 500 501 502 503 504 505 506 507 508 509 510
/**
 * 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.
 */
511
GstMemory *
512
gst_memory_copy (GstMemory * mem, gsize offset, gsize size)
513 514 515
{
  g_return_val_if_fail (mem != NULL, NULL);

516
  return mem->allocator->info.copy (mem, offset, size);
517 518
}

Wim Taymans's avatar
Wim Taymans committed
519 520 521 522 523 524 525 526 527 528 529 530 531
/**
 * 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.
 */
532
GstMemory *
Wim Taymans's avatar
Wim Taymans committed
533
gst_memory_share (GstMemory * mem, gsize offset, gsize size)
534 535 536
{
  g_return_val_if_fail (mem != NULL, NULL);

537
  return mem->allocator->info.share (mem, offset, size);
538 539
}

Wim Taymans's avatar
Wim Taymans committed
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
/**
 * 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
555
gboolean
556
gst_memory_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
Wim Taymans's avatar
Wim Taymans committed
557 558 559 560
{
  g_return_val_if_fail (mem1 != NULL, FALSE);
  g_return_val_if_fail (mem2 != NULL, FALSE);

561 562
  /* need to have the same allocators */
  if (mem1->allocator != mem2->allocator)
Wim Taymans's avatar
Wim Taymans committed
563 564
    return FALSE;

565 566 567
  /* need to have the same parent */
  if (mem1->parent == NULL || mem1->parent != mem2->parent)
    return FALSE;
Wim Taymans's avatar
Wim Taymans committed
568

569
  /* and memory is contiguous */
570
  if (!mem1->allocator->info.is_span (mem1, mem2, offset))
571 572 573
    return FALSE;

  return TRUE;
Wim Taymans's avatar
Wim Taymans committed
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 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693

/**
 * gst_memory_allocator_register:
 * @name: the name of the allocator
 * @info: #GstMemoryInfo
 *
 * Registers the memory allocator with @name and implementation functions
 * @info.
 *
 * Returns: a new #GstMemoryAllocator.
 */
const GstMemoryAllocator *
gst_memory_allocator_register (const gchar * name, const GstMemoryInfo * info)
{
  GstMemoryAllocator *allocator;

#define INSTALL_FALLBACK(_t) \
  if (allocator->info._t == NULL) allocator->info._t = _fallback_ ##_t;

  g_return_val_if_fail (name != NULL, NULL);
  g_return_val_if_fail (info != NULL, NULL);
  g_return_val_if_fail (info->get_sizes != NULL, NULL);
  g_return_val_if_fail (info->resize != NULL, NULL);
  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);

  allocator = g_slice_new (GstMemoryAllocator);
  allocator->name = g_quark_from_string (name);
  allocator->info = *info;
  INSTALL_FALLBACK (copy);
  INSTALL_FALLBACK (share);
  INSTALL_FALLBACK (is_span);
#undef INSTALL_FALLBACK

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

  g_static_rw_lock_writer_lock (&lock);
  g_hash_table_insert (memoryimpl, (gpointer) name, (gpointer) allocator);
  g_static_rw_lock_writer_unlock (&lock);

  return allocator;
}

/**
 * gst_memory_allocator_find:
 * @name: the name of the allocator
 *
 * Find a previously registered allocator with @name.
 *
 * Returns: a #GstMemoryAllocator or NULL when the allocator with @name was not
 * registered.
 */
const GstMemoryAllocator *
gst_memory_allocator_find (const gchar * name)
{
  GstMemoryAllocator *allocator;

  g_return_val_if_fail (name != NULL, NULL);

  g_static_rw_lock_writer_lock (&lock);
  allocator = g_hash_table_lookup (memoryimpl, (gconstpointer) name);
  g_static_rw_lock_writer_unlock (&lock);

  return allocator;
}

/**
 * gst_memory_allocator_get_default:
 *
 * Get the default allocator.
 *
 * Returns: the default #GstMemoryAllocator
 */
const GstMemoryAllocator *
gst_memory_allocator_get_default (void)
{
  return _default_allocator;
}

/**
 * gst_memory_allocator_set_default:
 * @allocator: a ##GstMemoryAllocator
 *
 * Set the default allocator.
 */
void
gst_memory_allocator_set_default (const GstMemoryAllocator * allocator)
{
  g_return_if_fail (allocator != NULL);

  _default_allocator = allocator;
}

/**
 * gst_memory_allocator_alloc:
 * @allocator: a #GstMemoryAllocator to use
 * @maxsize: allocated size of @data
 * @align: alignment for the data
 *
 * Use @allocator to allocate a new memory block with memory that is at least
 * @maxsize big and has the given alignment.
 *
 * @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.
 *
 * Returns: a new #GstMemory.
 */
GstMemory *
gst_memory_allocator_alloc (const GstMemoryAllocator * allocator,
    gsize maxsize, gsize align)
{
  g_return_val_if_fail (allocator == NULL
      || allocator->info.alloc != NULL, NULL);
  g_return_val_if_fail (((align + 1) & align) == 0, NULL);

  if (allocator == NULL)
    allocator = _default_allocator;

694 695
  return allocator->info.alloc (allocator, maxsize, align,
      allocator->info.user_data);
696
}