我正在尝试使用 c 中的 GStreamer 将元数据添加到某些录音中,然后将录音与元数据一起读回。
为此,我正在实施 GstMeta。我从文档中复制了确切的示例(在问题末尾添加了实现):https://gstreamer.freedesktop.org/documentation/plugin-development/advanced/allocation.html?gi-language=c# gstmeta.
另请参阅GstMeta。
在同一管道中添加/检索 GstMeta 是可行的(请参阅编码管道中的“queueProbe”)。
但是从记录的文件中检索相同的 GstMeta 不起作用(在“getMeta”探针中,meta 为空)。
这是最小的复制品。简而言之:
编码.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
输出
预期产量
我希望 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;
}
元数据不会被文件接收器保存到磁盘。以下是一些替代方案:
MakerNote
和 UserComment
标签中添加自定义信息。