You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

四、快速排查小技巧

  1. 录制端在filesink前加identity dump=1,打印buffer的Meta信息,确认Meta确实被添加到buffer上了。
  2. 读取端在demux后加identity dump=1,查看buffer是否带有标签或私有数据,排除是读取时解析代码的问题。

内容的提问来源于stack exchange,提问作者MALPY

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 20:18:26