GStreamer中filesink是否存储GstMeta?自定义元数据读写异常
GStreamer自定义Meta文件读写问题解决思路
核心问题先点明:GStreamer的标准filesink本身不负责存储自定义Meta,它只是把上游传来的字节直接写入文件。如果用的是无容器的裸流(比如raw H.264),根本没地方存Meta;就算用容器(如MKV、MP4),自定义Meta也不会自动被muxer识别存储,得手动做映射或序列化。
一、先确认是不是真没存进去
- 先看你输出的文件格式:如果是裸流(比如直接写
x264enc ! filesink),放弃,换MKV容器(x264enc ! matroskamux ! filesink),MKV支持自定义标签和私有数据。 - 用
gst-discoverer-1.0 your_output_file.mkv查文件元数据,如果是转成标签的自定义Meta,这里能看到;如果是私有Meta,得看容器的私有块。
二、录制端:让Meta能被存进文件
方案1:把自定义Meta转成容器标签(最简单)
自定义Meta不会被muxer自动处理,你可以在添加Meta的同时,把内容塞进GStreamer的TagList,muxer会把Tag写到容器里。
代码片段(在添加MyExampleMeta的地方加):
// 提取自定义Meta的内容,转成Tag GstTagList *tags = gst_tag_list_new(); gst_tag_list_add(tags, GST_TAG_MERGE_REPLACE, "my-custom-meta", my_meta->data, NULL); gst_buffer_add_tag_list(buffer, tags); // 把Tag附加到buffer上 gst_tag_list_unref(tags);
然后用matroskamux(或支持Tag的muxer),它会自动把Tag写入文件。
方案2:实现Meta的序列化/反序列化(存原始Meta结构)
如果要完整保存自定义Meta的结构,得给你的MetaInfo加序列化和反序列化函数,把Meta转成字节流,再通过muxer的私有数据接口写入文件。
示例代码:
// 序列化:把MyExampleMeta转成字节流 static gboolean my_example_meta_serialize(GstMeta *meta, GstBuffer *buffer, GstMetaSerializeFlags flags, GstBuffer *serialized) { MyExampleMeta *m = (MyExampleMeta *)meta; // 先写长度,再写内容(简单示例,实际要考虑字节序) guint32 len = strlen(m->data); guint8 *data = g_malloc0(sizeof(len) + len); memcpy(data, &len, sizeof(len)); memcpy(data + sizeof(len), m->data, len); gst_buffer_append_memory(serialized, gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY, data, sizeof(len)+len, 0, sizeof(len)+len, data, g_free)); return TRUE; } // 反序列化:从字节流恢复MyExampleMeta static GstMeta *my_example_meta_deserialize(GstMetaInfo *info, GstBuffer *buffer, GstMetaSerializeFlags flags) { MyExampleMeta *m = gst_buffer_add_meta(buffer, MY_EXAMPLE_META_INFO, NULL); guint32 len; guint8 *content; gst_buffer_extract(buffer, 0, &len, sizeof(len)); content = g_malloc0(len + 1); gst_buffer_extract(buffer, sizeof(len), content, len); m->data = content; return (GstMeta *)m; } // 更新MetaInfo,添加上序列化反序列化函数 static const GstMetaInfo my_example_meta_info = { "MyExampleMeta", "Custom example meta", sizeof(MyExampleMeta), NULL, NULL, my_example_meta_serialize, my_example_meta_deserialize };
之后要在muxer中配置允许私有Meta存储,比如matroskamux的streamable设为FALSE,再通过对应的接口把序列化后的Meta写入容器私有块。
三、读取端:从文件里恢复Meta
对应方案1(标签方式)
读取管道用filesrc ! matroskademux ! ...,然后监听bus的TAG消息,把标签转成自定义Meta:
// 在bus消息处理回调里 case GST_MESSAGE_TAG: { GstTagList *tags; gst_message_parse_tag(msg, &tags); const gchar *meta_content; if (gst_tag_list_get_string(tags, "my-custom-meta", &meta_content)) { // 注意:要在合适的时机获取当前buffer(比如demux后的pad probe里) MyExampleMeta *m = gst_buffer_add_meta(current_buffer, MY_EXAMPLE_META_INFO, NULL); m->data = g_strdup(meta_content); } gst_tag_list_unref(tags); break; }
对应方案2(序列化方式)
在demux后的pad probe中,读取私有数据块,调用反序列化函数恢复Meta:
static GstPadProbeReturn demux_src_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) { GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info); // 假设私有数据存在buffer的某个内存块里,读取后调用反序列化 MyExampleMeta *m = my_example_meta_deserialize(MY_EXAMPLE_META_INFO, buffer, 0); // 处理meta... return GST_PAD_PROBE_OK; }
四、快速排查小技巧
- 录制端在filesink前加
identity dump=1,打印buffer的Meta信息,确认Meta确实被添加到buffer上了。 - 读取端在demux后加
identity dump=1,查看buffer是否带有标签或私有数据,排除是读取时解析代码的问题。
内容的提问来源于stack exchange,提问作者MALPY
相关产品推荐
相关产品推荐

