1 <chapter id="chapter-metadata">
2 <title>Metadata</title>
5 &GStreamer; makes a clear distinction between two types of metadata, and
6 has support for both types. The first is stream tags, which describe the
7 content of a stream in a non-technical way. Examples include the author
8 of a song, the title of that very same song or the album it is a part of.
9 The other type of metadata is stream-info, which is a somewhat technical
10 description of the properties of a stream. This can include video size,
11 audio samplerate, codecs used and so on. Tags are handled using the
12 &GStreamer; tagging system. Stream-info can be retrieved from a
13 <classname>GstPad</classname> by getting the current (negotiated)
14 <classname>GstCaps</classname> for that pad.
17 <sect1 id="section-tags-read">
18 <title>Metadata reading</title>
21 Stream information can most easily be read by reading it from a
22 <classname>GstPad</classname>. This has already been discussed before
23 in <xref linkend="section-caps-metadata"/>. Therefore, we will skip
24 it here. Note that this requires access to all pads of which you
25 want stream information.
29 Tag reading is done through a bus in &GStreamer;, which has been
30 discussed previously in <xref linkend="chapter-bus"/>. You can
31 listen for <classname>GST_MESSAGE_TAG</classname> messages and handle
35 Note, however, that the <classname>GST_MESSAGE_TAG</classname>
36 message may be fired multiple times in the pipeline. It is the
37 application's responsibility to put all those tags together and
38 display them to the user in a nice, coherent way. Usually, using
39 <function>gst_tag_list_merge ()</function> is a good enough way
40 of doing this; make sure to empty the cache when loading a new song,
41 or after every few minutes when listening to internet radio. Also,
42 make sure you use <classname>GST_TAG_MERGE_PREPEND</classname> as
43 merging mode, so that a new title (which came in later) has a
44 preference over the old one for display.
47 The following example will extract tags from a file and print them:
51 * gcc -o tags tags.c `pkg-config --cflags --libs gstreamer-1.0` */
52 #include <gst/gst.h>
55 print_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
59 num = gst_tag_list_get_tag_size (list, tag);
60 for (i = 0; i < num; ++i) {
63 /* Note: when looking for specific tags, use the gst_tag_list_get_xyz() API,
64 * we only use the GValue approach here because it is more generic */
65 val = gst_tag_list_get_value_index (list, tag, i);
66 if (G_VALUE_HOLDS_STRING (val)) {
67 g_print ("\t%20s : %s\n", tag, g_value_get_string (val));
68 } else if (G_VALUE_HOLDS_UINT (val)) {
69 g_print ("\t%20s : %u\n", tag, g_value_get_uint (val));
70 } else if (G_VALUE_HOLDS_DOUBLE (val)) {
71 g_print ("\t%20s : %g\n", tag, g_value_get_double (val));
72 } else if (G_VALUE_HOLDS_BOOLEAN (val)) {
73 g_print ("\t%20s : %s\n", tag,
74 (g_value_get_boolean (val)) ? "true" : "false");
75 } else if (GST_VALUE_HOLDS_BUFFER (val)) {
76 GstBuffer *buf = gst_value_get_buffer (val);
77 guint buffer_size = gst_buffer_get_size (buf);
79 g_print ("\t%20s : buffer of size %u\n", tag, buffer_size);
80 } else if (GST_VALUE_HOLDS_DATE_TIME (val)) {
81 GstDateTime *dt = g_value_get_boxed (val);
82 gchar *dt_str = gst_date_time_to_iso8601_string (dt);
84 g_print ("\t%20s : %s\n", tag, dt_str);
87 g_print ("\t%20s : tag of type '%s'\n", tag, G_VALUE_TYPE_NAME (val));
93 on_new_pad (GstElement * dec, GstPad * pad, GstElement * fakesink)
97 sinkpad = gst_element_get_static_pad (fakesink, "sink");
98 if (!gst_pad_is_linked (sinkpad)) {
99 if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
100 g_error ("Failed to link pads!");
102 gst_object_unref (sinkpad);
106 main (int argc, char ** argv)
108 GstElement *pipe, *dec, *sink;
112 gst_init (&argc, &argv);
115 g_error ("Usage: %s FILE or URI", argv[0]);
117 if (gst_uri_is_valid (argv[1])) {
118 uri = g_strdup (argv[1]);
120 uri = gst_filename_to_uri (argv[1], NULL);
123 pipe = gst_pipeline_new ("pipeline");
125 dec = gst_element_factory_make ("uridecodebin", NULL);
126 g_object_set (dec, "uri", uri, NULL);
127 gst_bin_add (GST_BIN (pipe), dec);
129 sink = gst_element_factory_make ("fakesink", NULL);
130 gst_bin_add (GST_BIN (pipe), sink);
132 g_signal_connect (dec, "pad-added", G_CALLBACK (on_new_pad), sink);
134 gst_element_set_state (pipe, GST_STATE_PAUSED);
137 GstTagList *tags = NULL;
139 msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipe),
141 GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_TAG | GST_MESSAGE_ERROR);
143 if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_TAG) /* error or async_done */
146 gst_message_parse_tag (msg, &tags);
148 g_print ("Got tags from element %s:\n", GST_OBJECT_NAME (msg->src));
149 gst_tag_list_foreach (tags, print_one_tag, NULL);
151 gst_tag_list_unref (tags);
153 gst_message_unref (msg);
156 if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
159 gst_message_parse_error (msg, &err, NULL);
160 g_printerr ("Got error: %s\n", err->message);
164 gst_message_unref (msg);
165 gst_element_set_state (pipe, GST_STATE_NULL);
166 gst_object_unref (pipe);
173 <sect1 id="section-tags-write">
174 <title>Tag writing</title>
177 Tag writing is done using the <ulink type="http"
178 url="&URLAPI;GstTagSetter.html"><classname>GstTagSetter</classname></ulink>
179 interface. All that's required is a tag-set-supporting element in
180 your pipeline. In order to see if any of the elements in your
181 pipeline supports tag writing, you can use the function
182 <function>gst_bin_iterate_all_by_interface (pipeline,
183 GST_TYPE_TAG_SETTER)</function>. On the resulting element, usually
184 an encoder or muxer, you can use <function>gst_tag_setter_merge
185 ()</function> (with a taglist) or <function>gst_tag_setter_add
186 ()</function> (with individual tags) to set tags on it.
189 A nice extra feature in &GStreamer; tag support is that tags are
190 preserved in pipelines. This means that if you transcode one file
191 containing tags into another media type, and that new media type
192 supports tags too, then the tags will be handled as part of the
193 data stream and be merged into the newly written media file, too.