目录
- 1.GstAllocator
- 1.1 查找分配器(gst_allocator_find)
- 1.2 初始化分配器(gst_allocator_init)
- 1.2.1 通用初始化(gst_allocator_init)
- 1.2.2 sysmem初始化(gst_allocator_sysmem_init)
- 1.2.3 初始化sysmem分配器的类(gst_allocator_sysmem_class_init)
- 1.2.3.1 default_alloc()
- 1.2.3.2 default_free()
- 1.4 通用内存分配(gst_allocator_alloc)
- 1.5 内存释放(gst_allocator_free)
1.GstAllocator
在GStreamer中,GstAllocator用于管理和分配内存,创建和管理的对象是GstMemory,GstMemory是一个引用计数对象,对一块内存区域进行了封装。GstAllocator实现的功能类似于malloc和free,只是底层调用的是GLib中的内存分配函数g_malloc和g_free
// GstAllocator的继承关系
GObject╰──GInitiallyUnowned╰──GstObject╰──GstAllocator/*** GstAllocator:* @mem_map: the implementation of the GstMemoryMapFunction* @mem_unmap: the implementation of the GstMemoryUnmapFunction* @mem_copy: the implementation of the GstMemoryCopyFunction* @mem_share: the implementation of the GstMemoryShareFunction* @mem_is_span: the implementation of the GstMemoryIsSpanFunction* @mem_map_full: the implementation of the GstMemoryMapFullFunction.* Will be used instead of @mem_map if present. (Since: 1.6)* @mem_unmap_full: the implementation of the GstMemoryUnmapFullFunction.* Will be used instead of @mem_unmap if present. (Since: 1.6)** The #GstAllocator is used to create new memory.*/
// GstAllocator的定义
struct _GstAllocator
{GstObject object;/** mem_type的类型包括:* (1) GST_ALLOCATOR_SYSTEM : 系统内存分配器* (2) GST_ALLOCATOR_DMABUF : DMA缓冲区分配器* (3) GST_ALLOCATOR_FD : 文件描述符分配器* (4) GST_ALLOCATOR_DRM_DUMB : DRM Dumb Buffer分配器* 也可以自定义分配器,使用gst_allocator_register()来注册*/const gchar *mem_type;/*< public >*/ // 公有成员// 内存映射函数GstMemoryMapFunction mem_map;// 内存取消映射函数GstMemoryUnmapFunction mem_unmap;// 内存拷贝函数GstMemoryCopyFunction mem_copy;// 内存共享函数GstMemoryShareFunction mem_share;// 检查内存是否连续GstMemoryIsSpanFunction mem_is_span;// 包含更多参数的映射GstMemoryMapFullFunction mem_map_full;// 包含更多参数的取消映射GstMemoryUnmapFullFunction mem_unmap_full;/*< private >*/ // 私有成员gpointer _gst_reserved[GST_PADDING - 2];GstAllocatorPrivate *priv;
};/*** GstAllocatorClass:* @object_class: Object parent class* @alloc: implementation that acquires memory* @free: implementation that releases memory** The #GstAllocator is used to create new memory.*/
struct _GstAllocatorClass {GstObjectClass object_class;/*< public >*/ // 共有成员// 内存分配GstMemory * (*alloc) (GstAllocator *allocator, gsize size,GstAllocationParams *params);// 内存释放void (*free) (GstAllocator *allocator, GstMemory *memory);/*< private >*/gpointer _gst_reserved[GST_PADDING];
};
从上面类的定义来看,GstAllocator中声明了内存类型(由什么样的内存器分配),内存相关函数(访问,取消访问,拷贝,共享等),GstAllocatorClass中声明了具体的内存分配和内存释放函数。GstAllocator可以看作是GstAllocatorClass的一个实例,其中也包括了alloc和free的函数。使用GstAllocatorClass中的alloc和free函数之前,需要先将GstAllocator转换成GstAllocatorClass类,使用GST_ALLOCATOR_GET_CLASS这个宏可以实现这个功能。
GstAllocator的使用流程大致为:
- 查找分配器(gst_allocator_find)
- 初始化分配器(gst_allocator_init)
- 内存分配(gst_allocator_alloc)
- 内存使用
- 内存释放(gst_allocator_free)
在GStreamer中,可以根据情况使用不同的内存分配器,包括GST_ALLOCATOR_SYSTEM(系统内存分配器)、GST_ALLOCATOR_DMABUF(DMA缓冲区分配器)、GST_ALLOCATOR_FD(文件描述符分配器)、GST_ALLOCATOR_DRM_DUMB(DRM Dumb Buffer分配器)。如果不指定内存分配器,默认会使用sysmem,sysmem内存相关定义位于gstreamer/subprojects/gstreamer/gst/gstallocator.c中,下面以sysmem做一下分析。另外,DMA缓冲区分配器、文件描述符分配器、和DRM Dumb Buffer分配器具体实现方式在各自的文件中,例如DMA缓冲区分配器相关的代码定义在gstreamer/subprojects/gst-plugins-base/gst-libs/gst/allocators/gstdmabuf.c中
1.1 查找分配器(gst_allocator_find)
/*** gst_allocator_find:* @name: (nullable): the name of the allocator** Find a previously registered allocator with @name. When @name is %NULL, the* default allocator will be returned.** Returns: (transfer full) (nullable): a #GstAllocator or %NULL when* the allocator with @name was not registered.*/
GstAllocator *
gst_allocator_find (const gchar * name)
{GstAllocator *allocator;g_rw_lock_reader_lock (&lock);// 从哈希表中寻找可用的allocator,如果找不到则使用_default_allocatorif (name) {allocator = g_hash_table_lookup (allocators, (gconstpointer) name);} else {allocator = _default_allocator;}if (allocator)gst_object_ref (allocator);g_rw_lock_reader_unlock (&lock);return allocator;
}
_default_allocator表示使用GStreamer内部的默认内存分配器,即sysmem内存分配器,在_priv_gst_allocator_initialize()中获取,这里的前缀priv表示内部函数,外部无法调用
void
_priv_gst_allocator_initialize (void)
{g_rw_lock_init (&lock);// 创建allocators的哈希表allocators = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,gst_object_unref);#ifdef HAVE_GETPAGESIZE
#ifdef MEMORY_ALIGNMENT_PAGESIZEgst_memory_alignment = getpagesize () - 1;
#endif
#endifGST_CAT_DEBUG (GST_CAT_MEMORY, "memory alignment: %" G_GSIZE_FORMAT,gst_memory_alignment);// 创建sysmem分配器_sysmem_allocator = g_object_new (gst_allocator_sysmem_get_type (), NULL);/* Clear floating flag */// 添加引用计数gst_object_ref_sink (_sysmem_allocator);// 将_sysmem_allocator注册为GST_ALLOCATOR_SYSTEM类型// 注册会将_sysmem_allocator插入到哈希表当中gst_allocator_register (GST_ALLOCATOR_SYSMEM,gst_object_ref (_sysmem_allocator));// 默认分配器为sysmem,也就是GST_ALLOCATOR_SYSTEM_default_allocator = gst_object_ref (_sysmem_allocator);
}
1.2 初始化分配器(gst_allocator_init)
1.2.1 通用初始化(gst_allocator_init)
static void
gst_allocator_init (GstAllocator * allocator)
{allocator->priv = gst_allocator_get_instance_private (allocator);// 内存拷贝allocator->mem_copy = _fallback_mem_copy;// 检查内存是否连续allocator->mem_is_span = _fallback_mem_is_span;
}
其中_fallback_mem_copy()为内存拷贝函数
static GstMemory *
_fallback_mem_copy (GstMemory * mem, gssize offset, gssize size)
{GstMemory *copy;GstMapInfo sinfo, dinfo;GstAllocationParams params = { 0, mem->align, 0, 0, };GstAllocator *allocator;// 检查源内存块是否可读if (!gst_memory_map (mem, &sinfo, GST_MAP_READ))return NULL;if (size == -1)size = sinfo.size > offset ? sinfo.size - offset : 0;/* use the same allocator as the memory we copy */allocator = mem->allocator;if (GST_OBJECT_FLAG_IS_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC) ||GST_OBJECT_FLAG_IS_SET (allocator, GST_ALLOCATOR_FLAG_NO_COPY))allocator = NULL;// 使用相同的内存分配器和参数,分配内存copy = gst_allocator_alloc (allocator, size, ¶ms);// 检查目标内存块是否可写if (!gst_memory_map (copy, &dinfo, GST_MAP_WRITE)) {GST_CAT_WARNING (GST_CAT_MEMORY, "could not write map memory %p", copy);gst_allocator_free (copy->allocator, copy);gst_memory_unmap (mem, &sinfo);return NULL;}GST_CAT_DEBUG (GST_CAT_PERFORMANCE,"memcpy %" G_GSSIZE_FORMAT " memory %p -> %p", size, mem, copy);// 将源地址中数据拷贝到目标地址中memcpy (dinfo.data, sinfo.data + offset, size);gst_memory_unmap (copy, &dinfo);gst_memory_unmap (mem, &sinfo);return copy;
}
_fallback_mem_is_span()还没有实现
static gboolean
_fallback_mem_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
{return FALSE;
}
1.2.2 sysmem初始化(gst_allocator_sysmem_init)
如果使用的是sysmem分配器,会调用gst_allocator_sysmem_init()进行初始化,该函数定义了内存处理的函数指针,包含内存映射(_sysmem_map)、内存拷贝(_sysmem_copy)、内存共享(_sysmem_share)等
static void
gst_allocator_sysmem_init (GstAllocatorSysmem * allocator)
{GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);GST_CAT_DEBUG (GST_CAT_MEMORY, "init allocator %p", allocator);alloc->mem_type = GST_ALLOCATOR_SYSMEM;alloc->mem_map = (GstMemoryMapFunction) _sysmem_map;alloc->mem_unmap = (GstMemoryUnmapFunction) _sysmem_unmap;alloc->mem_copy = (GstMemoryCopyFunction) _sysmem_copy;alloc->mem_share = (GstMemoryShareFunction) _sysmem_share;alloc->mem_is_span = (GstMemoryIsSpanFunction) _sysmem_is_span;
}
(1)内存映射(_sysmem_map)
static gpointer
_sysmem_map (GstMemorySystem * mem, gsize maxsize, GstMapFlags flags)
{return mem->data;
}
(2)取消内存映射(_sysmem_unmap)
static gboolean
_sysmem_unmap (GstMemorySystem * mem)
{return TRUE;
}
(3)内存拷贝(_sysmem_copy)
static GstMemorySystem *
_sysmem_copy (GstMemorySystem * mem, gssize offset, gsize size)
{GstMemorySystem *copy;if (size == -1)size = mem->mem.size > offset ? mem->mem.size - offset : 0;// 创建新内存块copy = _sysmem_new_block (0, size, mem->mem.align, 0, size);if (!copy)return NULL;GST_CAT_DEBUG (GST_CAT_PERFORMANCE,"memcpy %" G_GSIZE_FORMAT " memory %p -> %p", size, mem, copy);memcpy (copy->data, mem->data + mem->mem.offset + offset, size);return copy;
}
_sysmem_new_block()是GStreamer底层的分配函数,根据输入参数,分配一块内存,返回一个GstMemory对象来封装这块内存
/* allocate the memory and structure in one block */
static GstMemorySystem *
_sysmem_new_block (GstMemoryFlags flags,gsize maxsize, gsize align, gsize offset, gsize size)
{GstMemorySystem *mem;gsize aoffset, slice_size, padding;guint8 *data;/* ensure configured alignment */// 确保对齐align |= gst_memory_alignment;/* allocate more to compensate for alignment */if (align > G_MAXSIZE || maxsize > G_MAXSIZE - align) {GST_CAT_WARNING (GST_CAT_MEMORY,"Allocating %" G_GSIZE_FORMAT " bytes with alignment %" G_GSIZE_FORMAT"x overflows", maxsize, align);return NULL;}maxsize += align;/* alloc header and data in one block */if (maxsize > G_MAXSIZE - sizeof (GstMemorySystem)) {GST_CAT_WARNING (GST_CAT_MEMORY,"Allocating %" G_GSIZE_FORMAT " bytes with alignment %" G_GSIZE_FORMAT"x overflows", maxsize, align);return NULL;}slice_size = sizeof (GstMemorySystem) + maxsize;// 分配大小为slice_size的内存,使用GLib中的g_malloc函数mem = g_malloc (slice_size);if (mem == NULL)return NULL;// 计算数据指针的位置data = (guint8 *) mem + sizeof (GstMemorySystem);/* do alignment */// 对齐数据指针if ((aoffset = ((guintptr) data & align))) {aoffset = (align + 1) - aoffset;data += aoffset;maxsize -= aoffset;}// 检查是否需要进行零填充if (offset && (flags & GST_MEMORY_FLAG_ZERO_PREFIXED))memset (data, 0, offset);padding = maxsize - (offset + size);if (padding && (flags & GST_MEMORY_FLAG_ZERO_PADDED))memset (data + offset + size, 0, padding);// 初始化内存对象_sysmem_init (mem, flags, NULL, data, maxsize,align, offset, size, NULL, NULL);return mem;
}
(4)内存共享(_sysmem_share)
static GstMemorySystem *
_sysmem_share (GstMemorySystem * mem, gssize offset, gsize size)
{GstMemorySystem *sub;GstMemory *parent;/* find the real parent */if ((parent = mem->mem.parent) == NULL)parent = (GstMemory *) mem;if (size == -1)size = mem->mem.size - offset;/* the shared memory is always readonly */// 分配新的内存空间sub =_sysmem_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;
}
_sysmem_new()的定义如下,与_sysmem_new_block()区别在于,_sysmem_new_block()会处理内存对齐,将内存分配到一个连续的内存块之中,减少内存碎片并提高访问效率,
/* create a new memory block that manages the given memory */
static inline GstMemorySystem *
_sysmem_new (GstMemoryFlags flags,GstMemory * parent, gpointer data, gsize maxsize, gsize align, gsize offset,gsize size, gpointer user_data, GDestroyNotify notify)
{GstMemorySystem *mem;mem = g_new (GstMemorySystem, 1);// 初始化分配的memory_sysmem_init (mem, flags, parent,data, maxsize, align, offset, size, user_data, notify);return mem;
}
_sysmem_init()是一个内联函数,作用是初始化内存对象GstMemorySystem
/* initialize the fields */
static inline void
_sysmem_init (GstMemorySystem * mem, GstMemoryFlags flags,GstMemory * parent,gpointer data, gsize maxsize, gsize align, gsize offset, gsize size,gpointer user_data, GDestroyNotify notify)
{// 初始化memory// gst_memory_init()定义在gstmemory.c中gst_memory_init (GST_MEMORY_CAST (mem),flags, _sysmem_allocator, parent, maxsize, align, offset, size);// 初始化GstMemorySystem的字段mem->data = data;mem->user_data = user_data;mem->notify = notify;
}
(5)检查内存连续(_sysmem_is_span)
static gboolean
_sysmem_is_span (GstMemorySystem * mem1, GstMemorySystem * mem2, gsize * offset)
{if (offset) {GstMemorySystem *parent;parent = (GstMemorySystem *) mem1->mem.parent;*offset = mem1->mem.offset - parent->mem.offset;}/* and memory is contiguous */return mem1->data + mem1->mem.offset + mem1->mem.size ==mem2->data + mem2->mem.offset;
}
1.2.3 初始化sysmem分配器的类(gst_allocator_sysmem_class_init)
前面初始化了sysmem的函数,这里还需要初始化sysmem_class的函数,也就是sysmem的基类。使用的函数是gst_allocator_sysmem_class_init(),主要作用是初始化内存分配函数alloc()内存释放函数free()
static void
gst_allocator_sysmem_class_init (GstAllocatorSysmemClass * klass)
{GObjectClass *gobject_class;GstAllocatorClass *allocator_class;gobject_class = (GObjectClass *) klass;allocator_class = (GstAllocatorClass *) klass;gobject_class->finalize = gst_allocator_sysmem_finalize;// 默认内存分配allocator_class->alloc = default_alloc;// 默认内存释放allocator_class->free = default_free;
}
1.2.3.1 default_alloc()
default_alloc()的作用是sysmem的内存分配
static GstMemory *
default_alloc (GstAllocator * allocator, gsize size,GstAllocationParams * params)
{gsize maxsize = size + params->prefix + params->padding;return (GstMemory *) _sysmem_new_block (params->flags,maxsize, params->align, params->prefix, size);
}
1.2.3.2 default_free()
函数的作用是释放内存
static void
default_free (GstAllocator * allocator, GstMemory * mem)
{GstMemorySystem *dmem = (GstMemorySystem *) mem;if (dmem->notify)dmem->notify (dmem->user_data);#ifdef USE_POISONING/* just poison the structs, not all the data */memset (mem, 0xff, sizeof (GstMemorySystem));
#endif// Glib中的g_free函数g_free (mem);
}
1.4 通用内存分配(gst_allocator_alloc)
gst_allocator_alloc()用于内存分配,会接受入参allocator,指定内存分配器,并使用这个分配器的内存分配函数执行任务。
/*** gst_allocator_alloc:* @allocator: (transfer none) (nullable): a #GstAllocator to use* @size: size of the visible memory area* @params: (transfer none) (nullable): optional parameters** Use @allocator to allocate a new memory block with memory that is at least* @size big.** The optional @params can specify the prefix and padding for the memory. If* %NULL is passed, no flags, no extra prefix/padding and a default alignment is* used.** The prefix/padding will be filled with 0 if flags contains* #GST_MEMORY_FLAG_ZERO_PREFIXED and #GST_MEMORY_FLAG_ZERO_PADDED respectively.** When @allocator is %NULL, the default allocator will be used.** The alignment in @params 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: (transfer full) (nullable): a new #GstMemory.*/
GstMemory *
gst_allocator_alloc (GstAllocator * allocator, gsize size,GstAllocationParams * params)
{GstMemory *mem;static GstAllocationParams defparams = { 0, 0, 0, 0, };GstAllocatorClass *aclass;if (params) {g_return_val_if_fail (((params->align + 1) & params->align) == 0, NULL);} else {params = &defparams;}if (allocator == NULL)allocator = _default_allocator;aclass = GST_ALLOCATOR_GET_CLASS (allocator);// 根据内存分配器进行内存分配// 如果入参是sysmem的allocator,aclass->alloc()调用的函数就是_default_alloc()if (aclass->alloc)mem = aclass->alloc (allocator, size, params);elsemem = NULL;return mem;
}
1.5 内存释放(gst_allocator_free)
/*** gst_allocator_free:* @allocator: (transfer none): a #GstAllocator to use* @memory: (transfer full): the memory to free** Free @memory that was previously allocated with gst_allocator_alloc().*/
void
gst_allocator_free (GstAllocator * allocator, GstMemory * memory)
{GstAllocatorClass *aclass;g_return_if_fail (GST_IS_ALLOCATOR (allocator));g_return_if_fail (memory != NULL);g_return_if_fail (memory->allocator == allocator);// 内存释放aclass = GST_ALLOCATOR_GET_CLASS (allocator);if (aclass->free)aclass->free (allocator, memory);
}