IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> gstBuffer的 data 和 meta -> 正文阅读

[C++知识库]gstBuffer的 data 和 meta

本文主要分析gsbuffer怎么读写内存,怎么添加删除meta,仅供参考。

GstMeta

typedef struct _GstMeta GstMeta;
struct _GstMeta {
? GstMetaFlags ? ? ? flags;
? const GstMetaInfo *info;
};

typedef struct _GstMetaItem GstMetaItem;

struct _GstMetaItem {

? GstMetaItem *next;

? guint64 seq_num;? ?//编号

? GstMeta meta;

};

可以看到GstMetaItem是一个GstMeta的链表。

GstMemory

struct _GstMemory {

? GstMiniObject ? mini_object;

? GstAllocator ? *allocator;

? GstMemory ? ? ?*parent;

? gsize ? ? ? ? ? maxsize;

? gsize ? ? ? ? ? align;

? gsize ? ? ? ? ? offset;

? gsize ? ? ? ? ? size;

};

看起来_GstMemory包含了内存的大小size,以及分配者allocator。

/* default memory implementation */

typedef struct

{

? GstMemory mem;

? gsize slice_size;

? guint8 *data;

? gpointer user_data;

? GDestroyNotify notify;

} GstMemorySystem;

GstMemorySystem会对GstMemory再进行封装,真正的包含了内存的指针data,可以参考_sysmem_new。

GstMemory相关的重要函数有:

Getting access to the data of the memory is performed with?gst_memory_map. The call will return a pointer to offset bytes into the region of memory. After the memory access is completed,?gst_memory_unmap?should be called.

gst_buffer_append_memory (GstBuffer * buffer, GstMemory * mem)->gst_buffer_insert_memory->_memory_add-> GST_BUFFER_MEM_PTR (buffer, idx) = mem;

GstMemory 的例子,?gst_rtp_rtx_buffer_new的片段:

? /* copy extension if any */
? if (rtp.size[1]) {
? ? mem = gst_allocator_alloc (NULL, rtp.size[1], NULL);
? ? gst_memory_map (mem, &map, GST_MAP_WRITE);? ?//得到GstMemory的内存指针

? ? memcpy (map.data, rtp.data[1], rtp.size[1]);
? ? gst_memory_unmap (mem, &map);
? ? gst_buffer_append_memory (new_buffer, mem);? //写完,关闭
? }

gst_allocator_alloc的定义在gstallocator.c中,如果第一个参数为空,会调用_default_allocator类的alloc函数,那_default_allocator从哪里来呢?gstallocator.c中定义了一个类GstAllocatorSysmem,G_DEFINE_TYPE (GstAllocatorSysmem, gst_allocator_sysmem, GST_TYPE_ALLOCATOR);

在初始化函数_priv_gst_allocator_initialize (void)中,创建了GstAllocatorSysmem的对象_sysmem_allocator(?_default_allocator = gst_object_ref (_sysmem_allocator);),然后赋给了_default_allocator,所以_default_allocator是GstAllocatorSysmem对象的指针。GstAllocatorSysmem类的alloc函数是default_alloc,最终调用的顺序是:

GstMemory * gst_allocator_alloc(gstallocator.c)->default_alloc->_sysmem_new_block->g_slice_alloc(gslice.c)->调g_malloc,slab

gstBuffer

typedef struct _GstBuffer GstBuffer;

struct _GstBuffer {

? GstMiniObject ? ? ? ? ?mini_object;

? /* timestamp */

? GstClockTime ? ? ? ? ? pts;? ? //时间戳

? GstClockTime ? ? ? ? ? dts;

.....

};

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;

可以看到GstBuffer包含时间戳等成员。GstBufferImpl继承自GstBuffer,包含GstMemory,?GstMetaItem等成员,GstMetaItem是个链表,可以为GstBuffer添加,删除GstMeta。

这里有一些操作的宏:

#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)

gst_buffer_new

GstBuffer *? ?gst_buffer_new (void)

{

? GstBufferImpl *newbuf;

? newbuf = g_slice_new (GstBufferImpl);

? GST_CAT_LOG (GST_CAT_BUFFER, "new %p", newbuf);

? gst_buffer_init (newbuf, sizeof (GstBufferImpl));

? return GST_BUFFER_CAST (newbuf);

}

可以看到创建一个GstBuffer,就是创建一个GstBufferImpl。

gst_buffer_add_meta

Arbitrary extra metadata can be set on a buffer with?gst_buffer_add_meta. Metadata can be retrieved with?gst_buffer_get_meta. See also?GstMeta.

GstMeta *gst_buffer_add_meta (GstBuffer * buffer, const GstMetaInfo * info,??gpointer params)

{

? GstMetaItem *item;

? GstMeta *result = NULL;

? gsize size;

? g_return_val_if_fail (buffer != NULL, NULL);

? g_return_val_if_fail (info != NULL, NULL);

? g_return_val_if_fail (gst_buffer_is_writable (buffer), NULL);

? /* create a new slice */

? size = ITEM_SIZE (info);

? /* We warn in gst_meta_register() about metas without

? ?* init function but let's play safe here and prevent

? ?* uninitialized memory

? ?*/

? if (!info->init_func)

? ? item = g_slice_alloc0 (size);

? else

? ? item = g_slice_alloc (size);

? result = &item->meta;

? result->info = info;

? result->flags = GST_META_FLAG_NONE;

。。。。。

? /* call the init_func when needed */

? if (info->init_func)

? ? if (!info->init_func (result, params, buffer))

? ? ? goto init_failed;

? item->seq_num = gst_atomic_int64_inc (&meta_seq);

? item->next = NULL;

? if (!GST_BUFFER_META (buffer)) {? ? //插入到链表尾部

? ? GST_BUFFER_META (buffer) = item;

? ? GST_BUFFER_TAIL_META (buffer) = item;

? } else {

? ? GST_BUFFER_TAIL_META (buffer)->next = item;

? ? GST_BUFFER_TAIL_META (buffer) = item;

? }

。。。。。。

}

关键是第二个参数,传入GstMetaInfo类型,返回GstMetaInfo对应meta,例如注册一个GstParentBufferMeta名称的的GstMetaInfo。

const GstMetaInfo *

gst_parent_buffer_meta_get_info (void) {

? static const GstMetaInfo *meta_info = NULL;

? if (g_once_init_enter ((GstMetaInfo **) & meta_info)) {

? ? const GstMetaInfo *meta =

? ? ? ? gst_meta_register (gst_parent_buffer_meta_api_get_type (),

? ? ? ? "GstParentBufferMeta",

? ? ? ? sizeof (GstParentBufferMeta),

? ? ? ? (GstMetaInitFunction) _gst_parent_buffer_meta_init,

? ? ? ? (GstMetaFreeFunction) _gst_parent_buffer_meta_free,

? ? ? ? _gst_parent_buffer_meta_transform);

? ? g_once_init_leave ((GstMetaInfo **) & meta_info, (GstMetaInfo *) meta);

? }

? return meta_info;

}

GstParentBufferMeta *

gst_buffer_add_parent_buffer_meta (GstBuffer * buffer, GstBuffer * ref)

{

? GstParentBufferMeta *meta;

? g_return_val_if_fail (GST_IS_BUFFER (ref), NULL);

? meta =

? ? ? (GstParentBufferMeta *) gst_buffer_add_meta (buffer,

? ? ? GST_PARENT_BUFFER_META_INFO, NULL);

? if (!meta)

? ? return NULL;

? meta->buffer = gst_buffer_ref (ref);

? return meta;

}

第三方库的应用(deepstream

deepstream用于AI推理,比如输入交通上的视频,推理得出汽车的位置,车牌的位置等,这些推理后的数据都存放在meta当中。deepstream有个streammux插件,在mux之前,meta绑定在GstBuffer上,如用户加一些自定义的meta ,streammux之后,所有数据打成一个batch,之前所有的meta数据都会挂到batch meta的链表下。以deepstream_gst_metadata.c为例,pipeline是?file-source -> h264-parser -> nvh264-decoder -> nvinfer -> nvvidconv -> nvosd -> video-renderer,

用户添加的meta:

/* nvdecoder_src_pad_buffer_probe() will attach decoder metadata to gstreamer

?* buffer on src pad. The decoder can not attach to NvDsBatchMeta metadata because

?* batch level metadata is created by nvstreammux component. The decoder

?* component is present is before nvstreammmux. So it attached the metadata

?* using gstnvdsmeta API's.?*/

static GstPadProbeReturn

nvdecoder_src_pad_buffer_probe (GstPad * pad, GstPadProbeInfo * info,

? ? gpointer u_data)

{

? GstBuffer *buf = (GstBuffer *) info->data;

? NvDsMeta *meta = NULL;

? NvDecoderMeta *decoder_meta = (NvDecoderMeta *)g_malloc0(sizeof(NvDecoderMeta));

? if(decoder_meta == NULL)

? {

? ? return GST_FLOW_ERROR;

? }

? /* Add dummy metadata */

? decoder_meta->frame_type = (frame_number % 3);

? decoder_meta->frame_num = frame_number++;

? decoder_meta->dec_err = ((frame_number % 4) / 3);

? /* Attach decoder metadata to gst buffer using gst_buffer_add_nvds_meta() */

? meta = gst_buffer_add_nvds_meta (buf, decoder_meta, NULL,

? ? ? decoder_meta_copy_func, decoder_meta_release_func);

? /* Set metadata type */

? meta->meta_type = (GstNvDsMetaType)NVDS_DECODER_GST_META_EXAMPLE;

? /* Set transform function to transform decoder metadata from Gst meta to

? ?* nvds meta */

? meta->gst_to_nvds_meta_transform_func = decoder_gst_to_nvds_meta_transform_func;

需要设置转换函数,streammux之后,meta会转到bachmeta下的链表下。

? /* Set release function to release the transformed nvds metadata */

? meta->gst_to_nvds_meta_release_func = decoder_gst_nvds_meta_release_func;

? g_print("GST Dec Meta attached with gst decoder output buffer for Frame_Num = %d\n",

? ? ? decoder_meta->frame_num);

? g_print("Attached decoder Metadata: frame type = %d, frame_num = %d decode_error_status = %d\n\n",

? ? ? decoder_meta->frame_type, decoder_meta->frame_num,

? ? ? decoder_meta->dec_err);

? return GST_PAD_PROBE_OK;

}

infer过后,读取用户之前添加的meta,

/* nvinfer_src_pad_buffer_probe() will extract the metadata received on nvinfer

?* src pad.

?* It explains the mechanism to extract the decoder metadata (which is attached

?* using gstnvdsmeta API's in nvdecoder_src_pad_buffer_probe()),

?* now transformed into nvdsmeta. Decoder meta, attached to gst buffer

?* is set as user data at NvDsFrameMeta level

?* It also extracts metadata attached on src pad of h264parse element.?*/

static GstPadProbeReturn

nvinfer_src_pad_buffer_probe (GstPad * pad, GstPadProbeInfo * info,

? ? gpointer u_data)

{

? GstBuffer *buf = (GstBuffer *) info->data;

? NvDsMetaList * l_frame = NULL;

? NvDsUserMeta *user_meta = NULL;

? NvDecoderMeta * decoder_meta = NULL;

? H264parseMeta * h264parse_meta = NULL;

? NvDsMetaList * l_user_meta = NULL;

? NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta (buf);

? ? for (l_frame = batch_meta->frame_meta_list; l_frame != NULL;

? ? ? l_frame = l_frame->next) {

? ? ? ? NvDsFrameMeta *frame_meta = (NvDsFrameMeta *) (l_frame->data);

? ? ? ? for (l_user_meta = frame_meta->frame_user_meta_list; l_user_meta != NULL;

? ? ? ? ? ? l_user_meta = l_user_meta->next) {

? ? ? ? ? user_meta = (NvDsUserMeta *) (l_user_meta->data);

? ? ? ? ? if(user_meta->base_meta.meta_type == NVDS_DECODER_GST_META_EXAMPLE)

? ? ? ? ? {

? ? ? ? ? ? decoder_meta = (NvDecoderMeta *)user_meta->user_meta_data;

? ? ? ? ? ? g_print("Dec Meta retrieved as NVDS USER METADTA For Frame_Num = %d ?\n",

? ? ? ? ? ? ? ? decoder_meta->frame_num);

? ? ? ? ? ? g_print("Retrieved Decoder Metadata: frame type = %d, frame_num = %d decode_error_status = %d\n\n",

? ? ? ? ? ? ? ? decoder_meta->frame_type, decoder_meta->frame_num,

? ? ? ? ? ? ? ? decoder_meta->dec_err);

? ? ? ? ? }

? ? ? ? }

? ? }

? ? return GST_PAD_PROBE_OK;

}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 17:22:53  更:2022-04-18 17:25:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:13:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码