gstreamer提供了一个数据存储结构GstBuffer ,这是所有数据传递的基础。
下面是接头体定义:
/**
* GstBuffer:
* @mini_object: the parent structure
* @pool: pointer to the pool owner of the buffer
* @pts: presentation timestamp of the buffer, can be #GST_CLOCK_TIME_NONE when the
* pts is not known or relevant. The pts contains the timestamp when the
* media should be presented to the user.
* @dts: decoding timestamp of the buffer, can be #GST_CLOCK_TIME_NONE when the
* dts is not known or relevant. The dts contains the timestamp when the
* media should be processed.
* @duration: duration in time of the buffer data, can be #GST_CLOCK_TIME_NONE
* when the duration is not known or relevant.
* @offset: a media specific offset for the buffer data.
* For video frames, this is the frame number of this buffer.
* For audio samples, this is the offset of the first sample in this buffer.
* For file data or compressed data this is the byte offset of the first
* byte in this buffer.
* @offset_end: the last offset contained in this buffer. It has the same
* format as @offset.
*
* The structure of a #GstBuffer. Use the associated macros to access the public
* variables.
*/
struct _GstBuffer {
GstMiniObject mini_object;
/*< public >*/ /* with COW */
GstBufferPool *pool;
/* timestamp */
GstClockTime pts;
GstClockTime dts;
GstClockTime duration;
/* media specific offset */
guint64 offset;
guint64 offset_end;
};
//其实真正使用的是这个,数据就在这里,GstBufferImpl继承了GstBuffer
typedef struct
{
GstBuffer buffer;
gsize slice_size;
/* the memory blocks */
guint len;
GstMemory *mem[GST_BUFFER_MEM_MAX];
/* memory of the buffer when allocated from 1 chunk */
GstMemory *bufmem;
/* FIXME, make metadata allocation more efficient by using part of the
* GstBufferImpl */
GstMetaItem *item;
GstMetaItem *tail_item;
} GstBufferImpl;
//还有很多宏来获取上面的成员变量
#define GST_BUFFER_SLICE_SIZE(b) (((GstBufferImpl *)(b))->slice_size)
#define GST_BUFFER_MEM_LEN(b) (((GstBufferImpl *)(b))->len)
#define GST_BUFFER_MEM_ARRAY(b) (((GstBufferImpl *)(b))->mem)
#define GST_BUFFER_MEM_PTR(b,i) (((GstBufferImpl *)(b))->mem[i])
#define GST_BUFFER_BUFMEM(b) (((GstBufferImpl *)(b))->bufmem)
#define GST_BUFFER_META(b) (((GstBufferImpl *)(b))->item)
#define GST_BUFFER_TAIL_META(b) (((GstBufferImpl *)(b))->tail_item)
具体不解释了,看注释很清楚,现在的问题是数据存储在哪里,比如至少有void * data,size_t size吧?
这个我们先看具体用法,根据代码来看:
GstBuffer *buffer;
GstMemory *memory;
gint size, width, height, bpp;
...
size = width * height * bpp;
//创建buf
buffer = gst_buffer_new ();
//分配内存
memory = gst_allocator_alloc (NULL, size, NULL);
//内存给到buf中
gst_buffer_insert_memory (buffer, -1, memory);
GstMapInfo map;
guint8 *raw;
//获取buffer中的数据指针
gst_buffer_map(buffer, &map, GST_MAP_WRITE);
raw = (guint8 *)map.data;
gint lSize = 0;
data->size > CHUNK_SIZE ? lSize = CHUNK_SIZE : lSize = data->size;
gint result = fread(raw, 1, data->size, data->pFile);
data->size -= result;
g_print("read size=%d\n", result);
gst_buffer_unmap(buffer, &map);
...
分析代码gst_buffer_new ()
GstBuffer *
gst_buffer_new (void)
{
GstBufferImpl *newbuf;
//这里是创建了一个GstBufferImpl
newbuf = g_slice_new (GstBufferImpl);
GST_CAT_LOG (GST_CAT_BUFFER, "new %p", newbuf);
gst_buffer_init (newbuf, sizeof (GstBufferImpl));
//这里返回了GstBufferImpl,当然是强转之后的
return GST_BUFFER_CAST (newbuf);
}
static void
gst_buffer_init (GstBufferImpl * buffer, gsize size)
{
gst_mini_object_init (GST_MINI_OBJECT_CAST (buffer), 0, _gst_buffer_type,
(GstMiniObjectCopyFunction) _gst_buffer_copy,
(GstMiniObjectDisposeFunction) _gst_buffer_dispose,
(GstMiniObjectFreeFunction) _gst_buffer_free);
GST_BUFFER_SLICE_SIZE (buffer) = size;
GST_BUFFER (buffer)->pool = NULL;
GST_BUFFER_PTS (buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (buffer) = GST_BUFFER_OFFSET_NONE;
GST_BUFFER_OFFSET_END (buffer) = GST_BUFFER_OFFSET_NONE;
GST_BUFFER_MEM_LEN (buffer) = 0;
GST_BUFFER_META (buffer) = NULL;
}
从上面可以看到,在实际使用的时候真正用的是GstBufferImpl,这个结构体。
接着看如何分配内存的gst_allocator_alloc()
:
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);
if (aclass->alloc)
//分配器分配了内存GstMemory,从这里获悉,所有内存都是GstMemory这个对象管理
mem = aclass->alloc (allocator, size, params);
else
mem = NULL;
return mem;
}
然后将mem插入到buf中去:
void
gst_buffer_insert_memory (GstBuffer * buffer, gint idx, GstMemory * mem)
{
GstMemory *tmp;
g_return_if_fail (GST_IS_BUFFER (buffer));
g_return_if_fail (gst_buffer_is_writable (buffer));
g_return_if_fail (mem != NULL);
g_return_if_fail (idx == -1 ||
(idx >= 0 && idx <= GST_BUFFER_MEM_LEN (buffer)));
//这里获取引用
tmp = _memory_get_exclusive_reference (mem);
g_return_if_fail (tmp != NULL);
gst_memory_unref (mem);
//这里插入到buf中去
_memory_add (buffer, idx, tmp);
}
static inline void
_memory_add (GstBuffer * buffer, gint idx, GstMemory * mem)
{
guint i, len = GST_BUFFER_MEM_LEN (buffer);
GST_CAT_LOG (GST_CAT_BUFFER, "buffer %p, idx %d, mem %p", buffer, idx, mem);
if (G_UNLIKELY (len >= GST_BUFFER_MEM_MAX)) {
/* too many buffer, span them. */
/* FIXME, there is room for improvement here: We could only try to merge
* 2 buffers to make some room. If we can't efficiently merge 2 buffers we
* could try to only merge the two smallest buffers to avoid memcpy, etc. */
GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "memory array overflow in buffer %p",
buffer);
_replace_memory (buffer, len, 0, len, _get_merged_memory (buffer, 0, len));
/* we now have 1 single spanned buffer */
len = 1;
}
if (idx == -1)
idx = len;
for (i = len; i > idx; i--) {
/* move buffers to insert, FIXME, we need to insert first and then merge */
GST_BUFFER_MEM_PTR (buffer, i) = GST_BUFFER_MEM_PTR (buffer, i - 1);
}
/* and insert the new buffer */
//核心在这里,就是将mem放入到buffer的mem数组中
GST_BUFFER_MEM_PTR (buffer, idx) = mem;
//对应的数据大小增加1
GST_BUFFER_MEM_LEN (buffer) = len + 1;
gst_mini_object_add_parent (GST_MINI_OBJECT_CAST (mem),
GST_MINI_OBJECT_CAST (buffer));
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
}
这里就是如何获取到buf中mem的数据指针了gst_buffer_map
:
gboolean
gst_buffer_map (GstBuffer * buffer, GstMapInfo * info, GstMapFlags flags)
{
return gst_buffer_map_range (buffer, 0, -1, info, flags);
}
这里又有了一个非常重要的结构体GstMapInfo
:
/**
* GstMapInfo:
* @memory: a pointer to the mapped memory
* @flags: flags used when mapping the memory
* @data: (array length=size): a pointer to the mapped data
* @size: the valid size in @data
* @maxsize: the maximum bytes in @data
* @user_data: extra private user_data that the implementation of the memory
* can use to store extra info.
*
* A structure containing the result of a map operation such as
* gst_memory_map(). It contains the data and size.
*/
typedef struct {
GstMemory *memory;
GstMapFlags flags;
//这里就是数据的指针
guint8 *data;
//数据大小
gsize size;
gsize maxsize;
/*< protected >*/
gpointer user_data[4];
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
} GstMapInfo;
接着看gst_buffer_map_range()
:
gboolean
gst_buffer_map_range (GstBuffer * buffer, guint idx, gint length,
GstMapInfo * info, GstMapFlags flags)
{
GstMemory *mem, *nmem;
gboolean write, writable;
gsize len;
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
g_return_val_if_fail (info != NULL, FALSE);
len = GST_BUFFER_MEM_LEN (buffer);
g_return_val_if_fail ((len == 0 && idx == 0 && length == -1) ||
(length == -1 && idx < len) || (length > 0
&& length + idx <= len), FALSE);
GST_CAT_LOG (GST_CAT_BUFFER, "buffer %p, idx %u, length %d, flags %04x",
buffer, idx, length, flags);
write = (flags & GST_MAP_WRITE) != 0;
writable = gst_buffer_is_writable (buffer);
/* check if we can write when asked for write access */
if (G_UNLIKELY (write && !writable))
goto not_writable;
if (length == -1)
length = len - idx;
mem = _get_merged_memory (buffer, idx, length);
if (G_UNLIKELY (mem == NULL))
goto no_memory;
/* now try to map */
nmem = gst_memory_make_mapped (mem, info, flags);
if (G_UNLIKELY (nmem == NULL))
goto cannot_map;
/* if we merged or when the map returned a different memory, we try to replace
* the memory in the buffer */
if (G_UNLIKELY (length > 1 || nmem != mem)) {
/* if the buffer is writable, replace the memory */
if (writable) {
_replace_memory (buffer, len, idx, length, gst_memory_ref (nmem));
} else {
if (len > 1) {
GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
"temporary mapping for memory %p in buffer %p", nmem, buffer);
}
}
}
return TRUE;
}
static inline GstMemory *
_get_merged_memory (GstBuffer * buffer, guint idx, guint length)
{
GST_CAT_LOG (GST_CAT_BUFFER, "buffer %p, idx %u, length %u", buffer, idx,
length);
if (G_UNLIKELY (length == 0))
return NULL;
//就是返回buf中mem数组中的指定index的指针
if (G_LIKELY (length == 1))
return gst_memory_ref (GST_BUFFER_MEM_PTR (buffer, idx));
return _actual_merged_memory (buffer, idx, length);
}
GstMemory *
gst_memory_make_mapped (GstMemory * mem, GstMapInfo * info, GstMapFlags flags)
{
GstMemory *result;
if (gst_memory_map (mem, info, flags)) {
result = mem;
} else {
result = gst_memory_copy (mem, 0, -1);
gst_memory_unref (mem);
if (result == NULL)
goto cannot_copy;
if (!gst_memory_map (result, info, flags))
goto cannot_map;
}
return result;
}
gboolean
gst_memory_map (GstMemory * mem, GstMapInfo * info, GstMapFlags flags)
{
g_return_val_if_fail (mem != NULL, FALSE);
g_return_val_if_fail (info != NULL, FALSE);
if (!gst_memory_lock (mem, (GstLockFlags) flags))
goto lock_failed;
info->flags = flags;
info->memory = mem;
info->size = mem->size;
info->maxsize = mem->maxsize - mem->offset;
//下面是通过allocator来获取到指定的info
if (mem->allocator->mem_map_full)
info->data = mem->allocator->mem_map_full (mem, info, mem->maxsize);
else
info->data = mem->allocator->mem_map (mem, mem->maxsize, flags);
if (G_UNLIKELY (info->data == NULL))
goto error;
info->data = info->data + mem->offset;
return TRUE;
}
到这里其实也结束了,具体allocator以下可以暂时不用考虑。后期有时间继续看。
(待续)