diff --git a/gst/gstmemory.c b/gst/gstmemory.c index b645343f1d..da93ecea8e 100644 --- a/gst/gstmemory.c +++ b/gst/gstmemory.c @@ -127,47 +127,83 @@ static GstAllocator *_default_mem_impl; static GstMemory * _gst_memory_copy (GstMemory * mem) { + GST_CAT_DEBUG (GST_CAT_MEMORY, "copy memory %p", mem); return gst_memory_copy (mem, 0, -1); } static void _gst_memory_free (GstMemory * mem) { + GST_CAT_DEBUG (GST_CAT_MEMORY, "free memory %p", mem); + + if (mem->parent) { + gst_memory_unlock (mem->parent, GST_LOCK_FLAG_EXCLUSIVE); + gst_memory_unref (mem->parent); + } + mem->allocator->info.mem_free (mem); } -/* initialize the fields */ -static void -_default_mem_init (GstMemoryDefault * mem, GstMemoryFlags flags, - GstMemory * parent, gsize slice_size, gpointer data, - gsize maxsize, gsize offset, gsize size, gsize align, - gpointer user_data, GDestroyNotify notify) +/** + * gst_memory_init: (skip) + * @mem: a #GstMemory + * @flags: #GstMemoryFlags + * @allocator: the #GstAllocator + * @parent: the parent of @mem + * @maxsize: the total size of the memory + * @align: the alignment of the memory + * @offset: The offset in the memory + * @size: the size of valid data in the memory + + * Initializes a newly allocated @mem with the given parameters. This function + * will call gst_mini_object_init() with the default memory parameters. + */ +void +gst_memory_init (GstMemory * mem, GstMemoryFlags flags, + GstAllocator * allocator, GstMemory * parent, gsize maxsize, gsize align, + gsize offset, gsize size) { gst_mini_object_init (GST_MINI_OBJECT_CAST (mem), flags | GST_MINI_OBJECT_FLAG_LOCKABLE, GST_TYPE_MEMORY, (GstMiniObjectCopyFunction) _gst_memory_copy, NULL, (GstMiniObjectFreeFunction) _gst_memory_free); - mem->mem.allocator = _default_mem_impl; - mem->mem.parent = parent ? gst_memory_ref (parent) : NULL; - mem->mem.maxsize = maxsize; - mem->mem.align = align; - mem->mem.offset = offset; - mem->mem.size = size; - mem->slice_size = slice_size; - mem->data = data; - mem->user_data = user_data; - mem->notify = notify; + mem->allocator = allocator; + if (parent) { + gst_memory_lock (parent, GST_LOCK_FLAG_EXCLUSIVE); + gst_memory_ref (parent); + } + mem->parent = parent; + mem->maxsize = maxsize; + mem->align = align; + mem->offset = offset; + mem->size = size; GST_CAT_DEBUG (GST_CAT_MEMORY, "new memory %p, maxsize:%" G_GSIZE_FORMAT " offset:%" G_GSIZE_FORMAT " size:%" G_GSIZE_FORMAT, mem, maxsize, offset, size); } +/* initialize the fields */ +static inline void +_default_mem_init (GstMemoryDefault * mem, GstMemoryFlags flags, + GstMemory * parent, gsize slice_size, gpointer data, + gsize maxsize, gsize align, gsize offset, gsize size, + gpointer user_data, GDestroyNotify notify) +{ + gst_memory_init (GST_MEMORY_CAST (mem), + flags, _default_mem_impl, parent, maxsize, align, offset, size); + + mem->slice_size = slice_size; + mem->data = data; + mem->user_data = user_data; + mem->notify = notify; +} + /* create a new memory block that manages the given memory */ -static GstMemoryDefault * +static inline GstMemoryDefault * _default_mem_new (GstMemoryFlags flags, GstMemory * parent, gpointer data, - gsize maxsize, gsize offset, gsize size, gsize align, gpointer user_data, + gsize maxsize, gsize align, gsize offset, gsize size, gpointer user_data, GDestroyNotify notify) { GstMemoryDefault *mem; @@ -177,7 +213,7 @@ _default_mem_new (GstMemoryFlags flags, GstMemory * parent, gpointer data, mem = g_slice_alloc (slice_size); _default_mem_init (mem, flags, parent, slice_size, - data, maxsize, offset, size, align, user_data, notify); + data, maxsize, align, offset, size, user_data, notify); return mem; } @@ -219,7 +255,7 @@ _default_mem_new_block (GstMemoryFlags flags, gsize maxsize, gsize align, memset (data + offset + size, 0, padding); _default_mem_init (mem, flags, NULL, slice_size, data, maxsize, - offset, size, align, NULL, NULL); + align, offset, size, NULL, NULL); return mem; } @@ -249,11 +285,6 @@ _default_mem_unmap (GstMemoryDefault * mem) static void _default_mem_free (GstMemoryDefault * mem) { - GST_CAT_DEBUG (GST_CAT_MEMORY, "free memory %p", mem); - - if (mem->mem.parent) - gst_memory_unref (mem->mem.parent); - if (mem->notify) mem->notify (mem->user_data); @@ -292,10 +323,11 @@ _default_mem_share (GstMemoryDefault * mem, gssize offset, gsize size) if (size == -1) size = mem->mem.size - offset; + /* the shared memory is always readonly */ sub = - _default_mem_new (GST_MINI_OBJECT_FLAGS (parent), parent, mem->data, - mem->mem.maxsize, mem->mem.offset + offset, size, mem->mem.align, NULL, - NULL); + _default_mem_new (GST_MINI_OBJECT_FLAGS (parent) | + GST_MINI_OBJECT_FLAG_LOCK_READONLY, parent, mem->data, mem->mem.maxsize, + mem->mem.align, mem->mem.offset + offset, size, NULL, NULL); return sub; } @@ -424,7 +456,7 @@ gst_memory_new_wrapped (GstMemoryFlags flags, gpointer data, g_return_val_if_fail (offset + size <= maxsize, NULL); mem = - _default_mem_new (flags, NULL, data, maxsize, offset, size, 0, user_data, + _default_mem_new (flags, NULL, data, maxsize, 0, offset, size, user_data, notify); return (GstMemory *) mem; @@ -586,7 +618,7 @@ lock_failed: error: { /* something went wrong, restore the orginal state again */ - GST_CAT_ERROR (GST_CAT_MEMORY, "mem %p: map failed", mem); + GST_CAT_ERROR (GST_CAT_MEMORY, "mem %p: subclass map failed", mem); gst_memory_unlock (mem, flags); return FALSE; } diff --git a/gst/gstmemory.h b/gst/gstmemory.h index d2e6b0ee2f..f23da2a0ad 100644 --- a/gst/gstmemory.h +++ b/gst/gstmemory.h @@ -414,10 +414,10 @@ GstAllocator * gst_allocator_find (const gchar *name); void gst_allocator_set_default (GstAllocator * allocator); /* allocating memory blocks */ -void gst_allocation_params_init (GstAllocationParams *params); +void gst_allocation_params_init (GstAllocationParams *params); GstAllocationParams * - gst_allocation_params_copy (const GstAllocationParams *params) G_GNUC_MALLOC; -void gst_allocation_params_free (GstAllocationParams *params); + gst_allocation_params_copy (const GstAllocationParams *params) G_GNUC_MALLOC; +void gst_allocation_params_free (GstAllocationParams *params); GstMemory * gst_allocator_alloc (GstAllocator * allocator, gsize size, GstAllocationParams *params); @@ -426,6 +426,11 @@ GstMemory * gst_memory_new_wrapped (GstMemoryFlags flags, gpointer data, gsi gsize offset, gsize size, gpointer user_data, GDestroyNotify notify); +void gst_memory_init (GstMemory *mem, GstMemoryFlags flags, + GstAllocator *allocator, GstMemory *parent, + gsize maxsize, gsize align, + gsize offset, gsize size); + /* refcounting */ /** * gst_memory_ref: diff --git a/tests/examples/memory/Makefile.am b/tests/examples/memory/Makefile.am index a8af2ea815..5611d3ea8a 100644 --- a/tests/examples/memory/Makefile.am +++ b/tests/examples/memory/Makefile.am @@ -1,4 +1,5 @@ noinst_PROGRAMS = memory_test +memory_test_SOURCES = memory_test.c my-memory.c my-memory.h memory_test_LDADD = $(GST_OBJ_LIBS) memory_test_CFLAGS = $(GST_OBJ_CFLAGS) diff --git a/tests/examples/memory/memory_test.c b/tests/examples/memory/memory_test.c index d63291b448..5290344cda 100644 --- a/tests/examples/memory/memory_test.c +++ b/tests/examples/memory/memory_test.c @@ -5,10 +5,29 @@ #include +#include "my-memory.h" + int main (int argc, char **argv) { + GstAllocator *alloc; + GstMemory *mem; + GstAllocationParams params; + GstMapInfo info; + gst_init (&argc, &argv); + my_memory_init (); + + alloc = gst_allocator_find ("MyMemory"); + + gst_allocation_params_init (¶ms); + mem = gst_allocator_alloc (alloc, 1024, ¶ms); + + gst_memory_map (mem, &info, GST_MAP_READ); + gst_memory_unmap (mem, &info); + + gst_memory_unref (mem); + return 0; } diff --git a/tests/examples/memory/my-memory.c b/tests/examples/memory/my-memory.c new file mode 100644 index 0000000000..6e3e89f34f --- /dev/null +++ b/tests/examples/memory/my-memory.c @@ -0,0 +1,133 @@ +/* GStreamer + * Copyright (C) 2012 Wim Taymans + * + * 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. + */ + +#include "my-memory.h" + +static GstAllocator *_my_allocator; + +typedef struct +{ + GstMemory mem; + + gpointer data; + +} MyMemory; + + +static GstMemory * +_my_alloc_alloc (GstAllocator * allocator, gsize size, + GstAllocationParams * params, gpointer user_data) +{ + MyMemory *mem; + gsize maxsize = size + params->prefix + params->padding; + + GST_DEBUG ("alloc from allocator %p", allocator); + + mem = g_slice_new (MyMemory); + + gst_memory_init (GST_MEMORY_CAST (mem), params->flags, allocator, NULL, + maxsize, params->align, params->prefix, size); + + mem->data = NULL; + + return (GstMemory *) mem; +} + +static gpointer +_my_mem_map (MyMemory * mem, gsize maxsize, GstMapFlags flags) +{ + gpointer res; + + while (TRUE) { + if ((res = g_atomic_pointer_get (&mem->data)) != NULL) + break; + + res = g_malloc (maxsize); + + if (g_atomic_pointer_compare_and_exchange (&mem->data, NULL, res)) + break; + + g_free (res); + } + + GST_DEBUG ("%p: mapped %p", mem, res); + + return res; +} + +static gboolean +_my_mem_unmap (MyMemory * mem) +{ + GST_DEBUG ("%p: unmapped", mem); + return TRUE; +} + +static void +_my_mem_free (MyMemory * mem) +{ + g_free (mem->data); + g_slice_free (MyMemory, mem); + GST_DEBUG ("%p: freed", mem); +} + +static MyMemory * +_my_mem_share (MyMemory * mem, gssize offset, gsize size) +{ + MyMemory *sub; + GstMemory *parent; + + GST_DEBUG ("%p: share %" G_GSSIZE_FORMAT, G_GSIZE_FORMAT, mem, offset, size); + + /* find the real parent */ + if ((parent = mem->mem.parent) == NULL) + parent = (GstMemory *) mem; + + if (size == -1) + size = mem->mem.size - offset; + + sub = g_slice_new (MyMemory); + /* the shared memory is always readonly */ + gst_memory_init (GST_MEMORY_CAST (sub), GST_MINI_OBJECT_FLAGS (parent) | + GST_MINI_OBJECT_FLAG_LOCK_READONLY, mem->mem.allocator, parent, + mem->mem.maxsize, mem->mem.align, mem->mem.offset + offset, size); + + /* install pointer */ + sub->data = _my_mem_map (mem, mem->mem.maxsize, GST_MAP_READ); + + return sub; +} + +void +my_memory_init (void) +{ + static const GstMemoryInfo info = { + "MyMemory", + (GstAllocatorAllocFunction) _my_alloc_alloc, + (GstMemoryMapFunction) _my_mem_map, + (GstMemoryUnmapFunction) _my_mem_unmap, + (GstMemoryFreeFunction) _my_mem_free, + (GstMemoryCopyFunction) NULL, + (GstMemoryShareFunction) _my_mem_share, + (GstMemoryIsSpanFunction) NULL, + }; + + _my_allocator = gst_allocator_new (&info, NULL, NULL); + + gst_allocator_register ("MyMemory", gst_allocator_ref (_my_allocator)); +} diff --git a/tests/examples/memory/my-memory.h b/tests/examples/memory/my-memory.h new file mode 100644 index 0000000000..84a6d8ce4a --- /dev/null +++ b/tests/examples/memory/my-memory.h @@ -0,0 +1,23 @@ +/* GStreamer + * Copyright (C) 2012 Wim Taymans + * + * 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. + */ + +#include + +void my_memory_init (void); +