0. 背景介绍
deepstream-gst-metadata-test例子向我们展示了如何在streammux插件之前添加用户自定义的metadata数据到GstBuffer中,并在nvinfer插件的src pad上添加probe回调函数解析这个自定义的metadata。
总的来说,该sample向我们展示了如何使用deepstream metadata extension中类和函数。具体实现:
- 在h264parse插件的src pad中添加回调函数h264parse_src_pad_buffer_probe来向GstBuffer中添加H264parseMeta数据
- 在nvv4l2decoder插件的src pad中添加回调函数nvdecoder_src_pad_buffer_probe来向GstBuffer中添加NvDecoderMeta数据
- 在nvinfer插件的src pad中添加回调函数nvinfer_src_pad_buffer_probe来分别解析H264parseMeta和NvDecoderMeta数据
pipeline的具体工作流程如下图所示:
1. 向GstBuffer中添加自定义的 DeepSteam metadata
在element的probe回调函数中添加自定义的NvDsMeta类型数据,大体流程可分为如下几步:
- 定义用户自定义的deepstream metadata
- 编写NvDsMetaCopyFunc和NvDsMetaReleaseFunc两个函数
- 调用gst_buffer_add_nvds_meta函数将用户自定义的metadata,返回NvDsMeta的对象指针
- 完成NvDsMeta的相关属性
1.1 h264parse element中添加H264parseMeta数据
1.1.1 定义metadata结构
通常情况下,我们只需要将帧数据相关的属性添加到GstBuffer中,例如:文件名,当前帧数等等。因此,我们只需要构建一个结构体将相关的信息添加到结构体中,即可在后续的element中访问这些数据做相应的操作。
typedef struct _H264parseMeta
{
guint parser_frame_num;
} H264parseMeta;
1.1.2 编写copy和destroy函数
copy函数是在metadata拷贝时调用,release函数是在metadata销毁时调用。
/* gst meta copy function set by user */
static gpointer h264parse_meta_copy_func(gpointer data, gpointer user_data)
{
H264parseMeta *src_h264parse_meta = (H264parseMeta *)data;
H264parseMeta *dst_h264parse_meta = (H264parseMeta*)g_malloc0(
sizeof(H264parseMeta));
memcpy(dst_h264parse_meta, src_h264parse_meta, sizeof(H264parseMeta));
return (gpointer)dst_h264parse_meta;
}
/* gst meta release function set by user */
static void h264parse_meta_release_func(gpointer data, gpointer user_data)
{
H264parseMeta *h264parse_meta = (H264parseMeta *)data;
if(h264parse_meta) {
g_free(h264parse_meta);
h264parse_meta = NULL;
}
}
1.1.3 向gstbuffer中添加H264parseMeta数据
gst_buffer_add_nvds_meta函数的作用是:将用户自定义的metadata添加到GstBuffer中,并返回一个NvDsMeta对象。
/* Attach decoder metadata to gst buffer using gst_buffer_add_nvds_meta() */
meta = gst_buffer_add_nvds_meta (buf, h264parse_meta, NULL,
h264parse_meta_copy_func, h264parse_meta_release_func);
NvDsMeta 是一个deepstream metadata, 应该是deep stream框架中自定义的一个custom metadata数据。下述为NvDsMeta的定义,相应的我们需要完善其属性。
1.1.4 完善 NvDsMeta相关属性
/* Set metadata type */
meta->meta_type = (GstNvDsMetaType)NVDS_GST_META_BEFORE_DECODER_EXAMPLE;
/* Set transform function to transform decoder metadata from Gst meta to
* nvds meta */
meta->gst_to_nvds_meta_transform_func = h264parse_gst_to_nvds_meta_transform_func;
/* Set release function to release the transformed nvds metadata */
meta->gst_to_nvds_meta_release_func = h264parse_gst_nvds_meta_release_func;
nvds_get_user_meta_type函数的作用是基于一个给定的string字符串生成一个unique的user metadata类型来描述用户自定义的metadata。而string字符串的命名格式是:ORG_NAME.COMPONENT_NAME.METADATA_DESCRIPTION。例如:NVIDIA.NVINFER.TENSOR_METADATA。
#define NVDS_GST_META_BEFORE_DECODER_EXAMPLE
(nvds_get_user_meta_type("NVIDIA.DECODER.GST_META_BEFORE_DECODER"))
/* Set metadata type */
meta->meta_type = (GstNvDsMetaType)NVDS_GST_META_BEFORE_DECODER_EXAMPLE;
g_print("H264parse GstNvDsMetaType:%d\n", meta->meta_type);
- gst_to_nvds_meta_transform_func函数当 meta_data 转换为 NvDsUserMeta 时调用(这个应该有问题),代码中实现的时NvDsUserMeta转meta_data
- gst_to_nvds_meta_release_func函数用来销毁NvDsUserMeta,通过将其转换为meta_data 然后调用freefunc函数销毁
/* gst to nvds transform function set by user. "data" holds a pointer to NvDsUserMeta */
static gpointer h264parse_gst_to_nvds_meta_transform_func(gpointer data, gpointer user_data)
{
NvDsUserMeta *user_meta = (NvDsUserMeta *)data;
H264parseMeta *src_h264parse_meta =
(H264parseMeta*)user_meta->user_meta_data;
H264parseMeta *dst_h264parse_meta =
(H264parseMeta *)h264parse_meta_copy_func(src_h264parse_meta, NULL);
return (gpointer)dst_h264parse_meta;
}
/* release function set by user to release gst to nvds transformed metadata.
* "data" holds a pointer to NvDsUserMeta */
static void h264parse_gst_nvds_meta_release_func(gpointer data, gpointer user_data)
{
NvDsUserMeta *user_meta = (NvDsUserMeta *) data;
H264parseMeta *h264parse_meta = (H264parseMeta *)user_meta->user_meta_data;
h264parse_meta_release_func(h264parse_meta, NULL);
}
1.2 nvv4l2decoder element中添加NvDecoderMeta数据
1.2.1 定义metadata结构
typedef struct _NvDecoderMeta
{
guint frame_type;
guint frame_num;
gboolean dec_err;
} NvDecoderMeta;
1.2.2 编写copy和destroy函数
/* gst meta copy function set by user */
static gpointer decoder_meta_copy_func(gpointer data, gpointer user_data)
{
NvDecoderMeta *src_decoder_meta = (NvDecoderMeta *)data;
NvDecoderMeta *dst_decoder_meta = (NvDecoderMeta*)g_malloc0(
sizeof(NvDecoderMeta));
memcpy(dst_decoder_meta, src_decoder_meta, sizeof(NvDecoderMeta));
return (gpointer)dst_decoder_meta;
}
/* gst meta release function set by user */
static void decoder_meta_release_func(gpointer data, gpointer user_data)
{
NvDecoderMeta *decoder_meta = (NvDecoderMeta *)data;
if(decoder_meta) {
g_free(decoder_meta);
decoder_meta = NULL;
}
}
1.2.3 向gstbuffer中添加H264parseMeta数据
/* 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);
1.2.4 完善 NvDsMeta相关属性
/* 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;
/* Set release function to release the transformed nvds metadata */
meta->gst_to_nvds_meta_release_func = decoder_gst_nvds_meta_release_func;
#define NVDS_DECODER_GST_META_EXAMPLE
(nvds_get_user_meta_type("NVIDIA.DECODER.GST_USER_META"))
/* Set metadata type */
meta->meta_type = (GstNvDsMetaType)NVDS_DECODER_GST_META_EXAMPLE;
/* gst to nvds transform function set by user. "data" holds a pointer to NvDsUserMeta */
static gpointer decoder_gst_to_nvds_meta_transform_func(gpointer data, gpointer user_data)
{
NvDsUserMeta *user_meta = (NvDsUserMeta *)data;
NvDecoderMeta *src_decoder_meta =
(NvDecoderMeta*)user_meta->user_meta_data;
NvDecoderMeta *dst_decoder_meta =
(NvDecoderMeta *)decoder_meta_copy_func(src_decoder_meta, NULL);
return (gpointer)dst_decoder_meta;
}
/* release function set by user to release gst to nvds transformed metadata.
* "data" holds a pointer to NvDsUserMeta */
static void decoder_gst_nvds_meta_release_func(gpointer data, gpointer user_data)
{
NvDsUserMeta *user_meta = (NvDsUserMeta *) data;
NvDecoderMeta *decoder_meta = (NvDecoderMeta *)user_meta->user_meta_data;
decoder_meta_release_func(decoder_meta, NULL);
}
2. 读取自定义的metadata数据
该sample中在nvinfer element的src pad中调用probe回调函数nvinfer_src_pad_buffer_probe来分别解析H264parseMeta和NvDecoderMeta数据。
下面的代码向我们解释了如何提取使用gstnvdsmeta API加入的decoder metadata和 h264parse metadata数据。此时,decoder metadata被设置为user data包含在NvDsFrameMeta下面。
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
{
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);
}
if(user_meta->base_meta.meta_type == NVDS_GST_META_BEFORE_DECODER_EXAMPLE) // parser
{
h264parse_meta = (H264parseMeta *)user_meta->user_meta_data;
g_print("Parser Meta retrieved For Frame_Num = %d \n",
h264parse_meta->parser_frame_num);
g_print("Retrieved Metadata attached before decoder: parsed frame_num = %d\n\n",
h264parse_meta->parser_frame_num);
}
}