2 * Copyright (C) 2011 Wim Taymans <wim.taymans@gmail.be>
4 * gstmemory.c: memory block handling
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
24 #include "gst_private.h"
26 #include "gstmemory.h"
46 static const GstMemoryImpl *_default_mem_impl;
47 static const GstMemoryImpl *_default_sub_impl;
50 _default_mem_init (GstMemoryDefault * mem, GstMemory * parent,
51 gsize slice_size, gpointer data, GFreeFunc free_func,
52 gsize maxsize, gsize offset, gsize size)
54 mem->mem.impl = data ? _default_mem_impl : _default_sub_impl;
56 mem->mem.refcount = 1;
57 mem->mem.parent = parent ? gst_memory_ref (parent) : NULL;
58 mem->slice_size = slice_size;
60 mem->free_func = free_func;
61 mem->maxsize = maxsize;
66 static GstMemoryDefault *
67 _default_mem_new (GstMemory * parent, gpointer data,
68 GFreeFunc free_func, gsize maxsize, gsize offset, gsize size)
70 GstMemoryDefault *mem;
73 slice_size = sizeof (GstMemoryDefault);
75 mem = g_slice_alloc (slice_size);
76 _default_mem_init (mem, parent, slice_size,
77 data, free_func, maxsize, offset, size);
82 static GstMemoryDefault *
83 _default_mem_new_block (gsize maxsize, gsize align, gsize offset, gsize size)
85 GstMemoryDefault *mem;
86 gsize aoffset, slice_size;
89 /* alloc header and data in one block */
90 slice_size = sizeof (GstMemoryDefault) + maxsize + align;
92 mem = g_slice_alloc (slice_size);
96 data = (guint8 *) mem + sizeof (GstMemoryDefault);
98 if ((aoffset = ((guintptr) data & align)))
99 aoffset = align - aoffset;
101 _default_mem_init (mem, NULL, slice_size, data, NULL, maxsize + align,
102 aoffset + offset, size);
108 _default_mem_get_sizes (GstMemoryDefault * mem, gsize * maxsize)
111 *maxsize = mem->maxsize;
117 _default_mem_trim (GstMemoryDefault * mem, gsize offset, gsize size)
119 g_return_if_fail (size + mem->offset + offset > mem->maxsize);
121 mem->offset += offset;
126 _default_mem_map (GstMemoryDefault * mem, gsize * size, gsize * maxsize,
132 *maxsize = mem->maxsize;
134 return mem->data + mem->offset;
138 _default_sub_map (GstMemoryDefault * mem, gsize * size, gsize * maxsize,
143 data = gst_memory_map (mem->mem.parent, size, maxsize, flags);
148 *maxsize -= mem->offset;
150 return data + mem->offset;
154 _default_mem_unmap (GstMemoryDefault * mem, gpointer data, gsize size)
161 _default_sub_unmap (GstMemoryDefault * mem, gpointer data, gsize size)
169 gst_memory_unmap (mem->mem.parent, ptr - mem->offset, size + mem->offset);
175 _default_mem_free (GstMemoryDefault * mem)
178 gst_memory_unref (mem->mem.parent);
181 mem->free_func (mem->data);
183 g_slice_free1 (mem->slice_size, mem);
186 static GstMemoryDefault *
187 _default_mem_copy (GstMemoryDefault * mem)
189 GstMemoryDefault *copy;
191 copy = _default_mem_new_block (mem->maxsize, 0, mem->offset, mem->size);
192 memcpy (copy->data + copy->offset, mem->data, mem->maxsize);
198 _default_mem_extract (GstMemoryDefault * mem, gsize offset, gpointer dest,
201 g_return_if_fail (size + mem->offset + offset > mem->maxsize);
203 memcpy (dest, mem->data + mem->offset + offset, size);
206 static GstMemoryDefault *
207 _default_mem_sub (GstMemoryDefault * mem, gsize offset, gsize size)
209 GstMemoryDefault *sub;
212 /* find the real parent */
213 if ((parent = mem->mem.parent) == NULL)
214 parent = (GstMemory *) mem;
216 sub = _default_mem_new (parent, mem->data, NULL, mem->maxsize,
217 mem->offset + offset, size);
223 _default_mem_is_span (GstMemoryDefault * mem1, GstMemoryDefault * mem2,
227 *offset = mem1->offset;
229 /* and memory is contiguous */
230 return mem1->data + mem1->offset + mem1->size == mem2->data + mem2->offset;
234 _fallback_extract (GstMemory * mem, gsize offset, gpointer dest, gsize size)
239 data = gst_memory_map (mem, &msize, NULL, GST_MAP_READ);
240 memcpy (dest, data + offset, size);
241 gst_memory_unmap (mem, data, msize);
245 _fallback_copy (GstMemory * mem)
247 GstMemoryDefault *copy;
251 data = gst_memory_map (mem, &size, NULL, GST_MAP_READ);
252 copy = _default_mem_new_block (size, 0, 0, size);
253 memcpy (copy->data, data, size);
254 gst_memory_unmap (mem, data, size);
256 return (GstMemory *) copy;
260 _fallback_sub (GstMemory * mem, gsize offset, gsize size)
262 GstMemoryDefault *sub;
265 /* find the real parent */
266 parent = mem->parent ? mem->parent : mem;
268 sub = _default_mem_new (parent, NULL, NULL, size, offset, size);
270 return (GstMemory *) sub;
274 _fallback_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
279 const GstMemoryImpl *
280 gst_memory_register (const gchar * name, const GstMemoryInfo * info)
284 #define INSTALL_FALLBACK(_t) \
285 if (impl->info._t == NULL) impl->info._t = _fallback_ ##_t;
287 g_return_val_if_fail (name != NULL, NULL);
288 g_return_val_if_fail (info != NULL, NULL);
289 g_return_val_if_fail (info->get_sizes != NULL, NULL);
290 g_return_val_if_fail (info->trim != NULL, NULL);
291 g_return_val_if_fail (info->map != NULL, NULL);
292 g_return_val_if_fail (info->unmap != NULL, NULL);
293 g_return_val_if_fail (info->free != NULL, NULL);
295 impl = g_slice_new (GstMemoryImpl);
296 impl->name = g_quark_from_string (name);
298 INSTALL_FALLBACK (copy);
299 INSTALL_FALLBACK (extract);
300 INSTALL_FALLBACK (sub);
301 INSTALL_FALLBACK (is_span);
303 GST_DEBUG ("register \"%s\" of size %" G_GSIZE_FORMAT, name);
306 g_static_rw_lock_writer_lock (&lock);
307 g_hash_table_insert (memoryimpl, (gpointer) name, (gpointer) impl);
308 g_static_rw_lock_writer_unlock (&lock);
310 #undef INSTALL_FALLBACK
316 _gst_memory_init (void)
318 static const GstMemoryInfo _mem_info = {
319 (GstMemoryGetSizesFunction) _default_mem_get_sizes,
320 (GstMemoryTrimFunction) _default_mem_trim,
321 (GstMemoryMapFunction) _default_mem_map,
322 (GstMemoryUnmapFunction) _default_mem_unmap,
323 (GstMemoryFreeFunction) _default_mem_free,
324 (GstMemoryCopyFunction) _default_mem_copy,
325 (GstMemoryExtractFunction) _default_mem_extract,
326 (GstMemorySubFunction) _default_mem_sub,
327 (GstMemoryIsSpanFunction) _default_mem_is_span
329 static const GstMemoryInfo _sub_info = {
330 (GstMemoryGetSizesFunction) _default_mem_get_sizes,
331 (GstMemoryTrimFunction) _default_mem_trim,
332 (GstMemoryMapFunction) _default_sub_map,
333 (GstMemoryUnmapFunction) _default_sub_unmap,
334 (GstMemoryFreeFunction) _default_mem_free,
341 _default_mem_impl = gst_memory_register ("GstMemoryDefault", &_mem_info);
342 _default_sub_impl = gst_memory_register ("GstMemorySubbuffer", &_sub_info);
346 gst_memory_ref (GstMemory * mem)
348 g_return_val_if_fail (mem != NULL, NULL);
350 g_atomic_int_inc (&mem->refcount);
356 gst_memory_unref (GstMemory * mem)
358 g_return_if_fail (mem != NULL);
360 if (g_atomic_int_dec_and_test (&mem->refcount))
361 mem->impl->info.free (mem);
365 gst_memory_get_sizes (GstMemory * mem, gsize * maxsize)
367 g_return_val_if_fail (mem != NULL, 0);
369 return mem->impl->info.get_sizes (mem, maxsize);
373 gst_memory_map (GstMemory * mem, gsize * size, gsize * maxsize,
376 g_return_val_if_fail (mem != NULL, NULL);
378 return mem->impl->info.map (mem, size, maxsize, flags);
382 gst_memory_unmap (GstMemory * mem, gpointer data, gsize size)
384 g_return_val_if_fail (mem != NULL, FALSE);
386 return mem->impl->info.unmap (mem, data, size);
390 gst_memory_copy (GstMemory * mem)
392 g_return_val_if_fail (mem != NULL, NULL);
394 return mem->impl->info.copy (mem);
398 gst_memory_extract (GstMemory * mem, gsize offset, gpointer dest, gsize size)
400 g_return_if_fail (mem != NULL);
401 g_return_if_fail (dest != NULL);
403 return mem->impl->info.extract (mem, offset, dest, size);
407 gst_memory_trim (GstMemory * mem, gsize offset, gsize size)
409 g_return_if_fail (mem != NULL);
411 mem->impl->info.trim (mem, offset, size);
415 gst_memory_sub (GstMemory * mem, gsize offset, gsize size)
417 g_return_val_if_fail (mem != NULL, NULL);
419 return mem->impl->info.sub (mem, offset, size);
423 gst_memory_is_span (GstMemory ** mem1, gsize len1, GstMemory ** mem2,
424 gsize len2, GstMemory ** parent, gsize * offset)
426 GstMemory *m1, *m2, **arr;
429 gboolean have_offset = FALSE;
431 g_return_val_if_fail (mem1 != NULL, FALSE);
432 g_return_val_if_fail (mem2 != NULL, FALSE);
438 for (count = 0; count < 2; count++) {
441 for (i = 0; i < len; i++) {
447 /* need to have the same implementation */
448 if (m1->impl != m2->impl)
451 /* need to have the same parent */
452 if (m1->parent == NULL || m1->parent != m2->parent)
455 /* and memory is contiguous */
456 if (!m1->impl->info.is_span (m1, m2, &offs))
475 gst_memory_span (GstMemory ** mem1, gsize len1, gsize offset, GstMemory ** mem2,
476 gsize len2, gsize size)
478 GstMemory *span, **mem, *parent;
480 gsize count, ssize, tocopy, len, poffset, i;
482 g_return_val_if_fail (mem1 != NULL, NULL);
483 g_return_val_if_fail (mem2 != NULL, NULL);
485 if (gst_memory_is_span (mem1, len1, mem2, len2, &parent, &poffset)) {
486 span = gst_memory_sub (parent, offset + poffset, size);
488 GstMemoryDefault *tspan;
490 tspan = _default_mem_new_block (size, 0, 0, size);
496 for (count = 0; count < 2; count++) {
497 for (i = 0; i < len && size > 0; i++) {
498 data = gst_memory_map (mem[i], &ssize, NULL, GST_MAP_READ);
499 tocopy = MIN (ssize, size);
500 if (tocopy > offset) {
501 memcpy (dest, data + offset, tocopy - offset);
508 gst_memory_unmap (mem[i], data, ssize);
513 span = (GstMemory *) tspan;
519 gst_memory_new_wrapped (gpointer data, GFreeFunc free_func,
520 gsize maxsize, gsize offset, gsize size)
522 GstMemoryDefault *mem;
524 mem = _default_mem_new (NULL, data, free_func, maxsize, offset, size);
526 return (GstMemory *) mem;
530 gst_memory_new_alloc (gsize maxsize, gsize align)
532 GstMemoryDefault *mem;
534 mem = _default_mem_new_block (maxsize, align, 0, 0);
536 return (GstMemory *) mem;
540 gst_memory_new_copy (gsize maxsize, gsize align, gpointer data,
541 gsize offset, gsize size)
543 GstMemoryDefault *mem;
545 mem = _default_mem_new_block (maxsize, align, offset, size);
546 memcpy (mem->data, data, maxsize);
548 return (GstMemory *) mem;