filesink 是否将 GstMeta 存储到文件中?

问题描述 投票:0回答:1

我正在尝试使用 c 中的 GStreamer 将元数据添加到某些录音中,然后将录音与元数据一起读回。

为此,我正在实施 GstMeta。我从文档中复制了确切的示例(在问题末尾添加了实现):https://gstreamer.freedesktop.org/documentation/plugin-development/advanced/allocation.html?gi-language=c# gstmeta.
另请参阅GstMeta

在同一管道中添加/检索 GstMeta 是可行的(请参阅编码管道中的“queueProbe”)。
但是从记录的文件中检索相同的 GstMeta 不起作用(在“getMeta”探针中,meta 为空)。

这是最小的复制品。简而言之:

  • 编码管道:videotestsrc!队列 !文件接收器
    探测源元素的 src pad 添加 GstMeta
    并且在编码管道中探测队列以获取 GstMeta。
  • 解码管道:filesrc!原始视频解析!自动视频接收器
    解析器的 src pad 被探测以读取 GstMeta。

编码.c

#include <gst/gst.h>
#include <gst/gstmeta.h>
#include "my-example-meta.h"

GstPadProbeReturn addMeta(GstPad *pad, GstPadProbeInfo *info, gpointer *data) {
    GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
    gst_buffer_add_my_example_meta(buffer,2,"john");
    return GST_PAD_PROBE_OK;
}

GstPadProbeReturn queueProbe(GstPad *pad, GstPadProbeInfo *info, gpointer *data) {
    GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
    MyExampleMeta *meta;
    meta=gst_buffer_get_my_example_meta(buffer);
    g_print("%d\n",meta->age);
    return GST_PAD_PROBE_OK;
}

int main(){
    gst_init(NULL,NULL);
    GstElement *src, *queue, *sink;
    GstElement *pipeline;
    src=gst_element_factory_make("videotestsrc",NULL);
    queue=gst_element_factory_make("queue",NULL);
    sink=gst_element_factory_make("filesink",NULL);
    pipeline=gst_pipeline_new("pipeline");

    g_object_set(src, "is-live", TRUE, NULL);
    g_object_set(sink, "location", "test", NULL);

    gst_bin_add_many(GST_BIN(pipeline),src,queue,sink,NULL);
    if(!gst_element_link_many(src,queue, sink, NULL))
    {
        g_print("Elements not linked.\n");
    }

    gst_pad_add_probe (gst_element_get_static_pad (src, "src"), GST_PAD_PROBE_TYPE_BUFFER,
    (GstPadProbeCallback) addMeta, NULL, NULL);

    gst_pad_add_probe (gst_element_get_static_pad (queue, "src"), GST_PAD_PROBE_TYPE_BUFFER,
    (GstPadProbeCallback) queueProbe, NULL, NULL);
    
    gst_element_set_state(pipeline, GST_STATE_PLAYING);
    g_usleep(2 * 1000000);
    gst_element_set_state(pipeline, GST_STATE_NULL);
}

解码.c

#include <gst/gst.h>
#include <gst/gstmeta.h>
#include "my-example-meta.h"

GstPadProbeReturn getMeta(GstPad *pad, GstPadProbeInfo *info, gpointer *data) {
    GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);

    MyExampleMeta *meta;
    meta=gst_buffer_get_my_example_meta(buffer);

    //Assert that the meta api was inialized correctly
    const GstMetaInfo* metaInfo = my_example_meta_get_info();
    const gchar *const *array = gst_meta_api_type_get_tags(metaInfo->api);
    for (int i = 0; array[i] != NULL; i++) {
        g_print("%s\t", array[i]);
    }

    if(!meta) g_print("No meta\n");
    else g_print("%d\n",meta->age);

    return GST_PAD_PROBE_OK;
}

int main(){
    gst_init(NULL,NULL);
    GstElement *src,*parser, *sink;
    GstElement *pipeline;
    src=gst_element_factory_make("filesrc",NULL);
    parser=gst_element_factory_make("rawvideoparse",NULL);
    sink=gst_element_factory_make("autovideosink",NULL);
    pipeline=gst_pipeline_new("pipeline");

    g_object_set(src, "location", "test", NULL);

    gst_bin_add_many(GST_BIN(pipeline),src,parser,sink,NULL);
    if(!gst_element_link_many(src, parser, sink, NULL))
    {
        g_print("link failed\n");
    }

    gst_pad_add_probe (gst_element_get_static_pad(parser,"src"), GST_PAD_PROBE_TYPE_BUFFER,
    (GstPadProbeCallback) getMeta, NULL, NULL);
    
    gst_element_set_state(pipeline, GST_STATE_PLAYING);
    g_usleep(5 * 1000000);
    gst_element_set_state(pipeline, GST_STATE_NULL);
}

编译

gcc -o encode encode.c my-example-meta.c ` pkg-config --cflags --libs gstreamer-1.0 gstreamer-app-1.0 `
gcc -o decode decode.c my-example-meta.c ` pkg-config --cflags --libs gstreamer-1.0 gstreamer-app-1.0 `

奔跑

./encode

./decode

输出

  • 编码: 一系列“2”,表示 GstMeta 的读取正确。
  • 解码: 一系列“foo bar No meta”,表示正确的初始化,但没有实际的元数据。

预期产量
我希望 GstMeta 与缓冲区数据一起存储到文件中。
在解码方面,我期望“2”而不是“无元”。
我很难确定元数据是否确实不存在于文件中(这意味着 GstMeta 被遗忘在 filesink 元素中),或者元数据是否存在于文件中但未正确解释。

我为

my-example-meta.c
中的每个函数添加了断点,并且函数按预期顺序调用。

我的示例-meta.h

#include <gst/gst.h>

typedef struct _MyExampleMeta MyExampleMeta;

struct _MyExampleMeta {
  GstMeta       meta;

  gint          age;
  gchar        *name;
};

GType my_example_meta_api_get_type (void);
#define MY_EXAMPLE_META_API_TYPE (my_example_meta_api_get_type())

#define gst_buffer_get_my_example_meta(b) \
  ((MyExampleMeta*)gst_buffer_get_meta((b),MY_EXAMPLE_META_API_TYPE))

/* implementation */
const GstMetaInfo *my_example_meta_get_info (void);
#define MY_EXAMPLE_META_INFO (my_example_meta_get_info())

MyExampleMeta * gst_buffer_add_my_example_meta (GstBuffer      *buffer,
                                                gint            age,
                                                const gchar    *name);

我的示例-meta.c

#include "my-example-meta.h"

GType
my_example_meta_api_get_type (void)
{
  static GType type;
  static const gchar *tags[] = { "foo", "bar", NULL };

  if (g_once_init_enter (&type)) {
    GType _type = gst_meta_api_type_register ("MyExampleMetaAPI", tags);
    g_once_init_leave (&type, _type);
  }
  return type;
}

static gboolean
my_example_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
{
  MyExampleMeta *emeta = (MyExampleMeta *) meta;

  emeta->age = 0;
  emeta->name = NULL;

  return TRUE;
}

static gboolean
my_example_meta_transform (GstBuffer * transbuf, GstMeta * meta,
    GstBuffer * buffer, GQuark type, gpointer data)
{
  MyExampleMeta *emeta = (MyExampleMeta *) meta;

  /* we always copy no matter what transform */
  gst_buffer_add_my_example_meta (transbuf, emeta->age, emeta->name);

  return TRUE;
}

static void
my_example_meta_free (GstMeta * meta, GstBuffer * buffer)
{
  MyExampleMeta *emeta = (MyExampleMeta *) meta;

  g_free (emeta->name);
  emeta->name = NULL;
}

const GstMetaInfo *
my_example_meta_get_info (void)
{
  static const GstMetaInfo *meta_info = NULL;

  if (g_once_init_enter (&meta_info)) {
    const GstMetaInfo *mi = gst_meta_register (MY_EXAMPLE_META_API_TYPE,
        "MyExampleMeta",
        sizeof (MyExampleMeta),
        my_example_meta_init,
        my_example_meta_free,
        my_example_meta_transform);
    g_once_init_leave (&meta_info, mi);
  }
  return meta_info;
}

MyExampleMeta *
gst_buffer_add_my_example_meta (GstBuffer   *buffer,
                                gint         age,
                                const gchar *name)
{
  MyExampleMeta *meta;

  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);

  meta = (MyExampleMeta *) gst_buffer_add_meta (buffer,
      MY_EXAMPLE_META_INFO, NULL);

  meta->age = age;
  meta->name = g_strdup (name);

  return meta;
}
c gstreamer
1个回答
0
投票

元数据不会被文件接收器保存到磁盘。以下是一些替代方案:

  • 序列化元并手动将其附加为缓冲区内容的一部分。您还需要在解码器端手动加载它。
  • 使用容器来存储自定义信息。例如,EXIF 允许您在
    MakerNote
    UserComment
    标签中添加自定义信息。
  • H264 和 H265 允许您添加自定义信息作为 SEI NAL 单位。这个有点复杂。
© www.soinside.com 2019 - 2024. All rights reserved.