Metadata
GStreamer 明确区分了它支持的两种类型的元数据: 流标签,以非技术方式描述流的内容;和 Stream-info,这是对流属性的某种技术性描述。流标签示例包括歌曲的作者、歌曲的标题或它所属的专辑。流信息的示例包括视频大小、音频采样率、使用的编解码器等。
tags使用GStreamer标签系统进行处理。
Stream-info可以从一个已经协商过的GstCaps中检索到.这个GstCaps从GstPad中获取到。
Metadata 读取
stream-info 从GstPad中获取最容易。请注意,这需要访问您想要流式传输信息的所有的pad。
Tag读取是监听GST_MESSAGE_TAG消息,这些消息来自于bus。
但是请注意,GST_MESSAGE_TAG
消息可能会被多次发出,应用程序有责任以一致的方式聚合和显示标签。这可以使用gst_tag_list_merge ()
但确保在加载新歌曲时清空缓存,或者每隔几分钟在收听网络广播时清空缓存。此外,请确保您使用GST_TAG_MERGE_PREPEND
合并模式,以便新标题(稍后出现)优先于旧标题。
以下示例显示了如何从文件中提取标签并打印它们:
/* compile with:
* gcc -o tags tags.c `pkg-config --cflags --libs gstreamer-1.0` */
#include <gst/gst.h>
static void
print_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
{
int i, num;
num = gst_tag_list_get_tag_size (list, tag);
for (i = 0; i < num; ++i) {
const GValue *val;
/* Note: when looking for specific tags, use the gst_tag_list_get_xyz() API,
* we only use the GValue approach here because it is more generic */
val = gst_tag_list_get_value_index (list, tag, i);
if (G_VALUE_HOLDS_STRING (val)) {
g_print ("\t%20s : %s\n", tag, g_value_get_string (val));
} else if (G_VALUE_HOLDS_UINT (val)) {
g_print ("\t%20s : %u\n", tag, g_value_get_uint (val));
} else if (G_VALUE_HOLDS_DOUBLE (val)) {
g_print ("\t%20s : %g\n", tag, g_value_get_double (val));
} else if (G_VALUE_HOLDS_BOOLEAN (val)) {
g_print ("\t%20s : %s\n", tag,
(g_value_get_boolean (val)) ? "true" : "false");
} else if (GST_VALUE_HOLDS_BUFFER (val)) {
GstBuffer *buf = gst_value_get_buffer (val);
guint buffer_size = gst_buffer_get_size (buf);
g_print ("\t%20s : buffer of size %u\n", tag, buffer_size);
} else if (GST_VALUE_HOLDS_DATE_TIME (val)) {
GstDateTime *dt = g_value_get_boxed (val);
gchar *dt_str = gst_date_time_to_iso8601_string (dt);
g_print ("\t%20s : %s\n", tag, dt_str);
g_free (dt_str);
} else {
g_print ("\t%20s : tag of type '%s'\n", tag, G_VALUE_TYPE_NAME (val));
}
}
}
static void
on_new_pad (GstElement * dec, GstPad * pad, GstElement * fakesink)
{
GstPad *sinkpad;
sinkpad = gst_element_get_static_pad (fakesink, "sink");
if (!gst_pad_is_linked (sinkpad)) {
if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
g_error ("Failed to link pads!");
}
gst_object_unref (sinkpad);
}
int
main (int argc, char ** argv)
{
GstElement *pipe, *dec, *sink;
GstMessage *msg;
gchar *uri;
gst_init (&argc, &argv);
if (argc < 2)
g_error ("Usage: %s FILE or URI", argv[0]);
if (gst_uri_is_valid (argv[1])) {
uri = g_strdup (argv[1]);
} else {
uri = gst_filename_to_uri (argv[1], NULL);
}
pipe = gst_pipeline_new ("pipeline");
dec = gst_element_factory_make ("uridecodebin", NULL);
g_object_set (dec, "uri", uri, NULL);
gst_bin_add (GST_BIN (pipe), dec);
sink = gst_element_factory_make ("fakesink", NULL);
gst_bin_add (GST_BIN (pipe), sink);
g_signal_connect (dec, "pad-added", G_CALLBACK (on_new_pad), sink);
gst_element_set_state (pipe, GST_STATE_PAUSED);
while (TRUE) {
GstTagList *tags = NULL;
msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipe),
GST_CLOCK_TIME_NONE,
GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_TAG | GST_MESSAGE_ERROR);
if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_TAG) /* error or async_done */
break;
gst_message_parse_tag (msg, &tags);
g_print ("Got tags from element %s:\n", GST_OBJECT_NAME (msg->src));
gst_tag_list_foreach (tags, print_one_tag, NULL);
g_print ("\n");
gst_tag_list_unref (tags);
gst_message_unref (msg);
}
if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
GError *err = NULL;
gst_message_parse_error (msg, &err, NULL);
g_printerr ("Got error: %s\n", err->message);
g_error_free (err);
}
gst_message_unref (msg);
gst_element_set_state (pipe, GST_STATE_NULL);
gst_object_unref (pipe);
g_free (uri);
return 0;
}
Tag 写入
标签写入是使用GstTagSetter
界面完成的 。所需要的只是管道中的标签集支持元素。
为了查看管道中的任何元素是否支持标记写入,您可以使用函数gst_bin_iterate_all_by_interface (pipeline, GST_TYPE_TAG_SETTER)
. 在结果元素上,通常是编码器或多路复用器,您可以使用 标签列表gst_tag_setter_merge_tags ()
或gst_tag_setter_add_tags ()
单独的标签,在其上设置标签。
GStreamer 标签支持的一个很好的额外功能是标签保留在管道中。这意味着,如果您将一个包含标签的文件转码为另一种支持标签的媒体类型,那么这些标签将作为数据流的一部分进行处理,并将合并到新写入的媒体文件中。