| |
|
开发:
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; 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 */ ? ? memcpy (map.data, rtp.data[1], rtp.size[1]); 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语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
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- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |