17.2. Reading Tags from Streams

The basic object for tags is a GstTagList . An element that is reading tags from a stream should create an empty taglist and fill this with individual tags. Empty tag lists can be created with gst_tag_list_new (). Then, the element can fill the list using gst_tag_list_add () or gst_tag_list_add_values (). Note that elements often read metadata as strings, but the values in the taglist might not necessarily be strings - they need to be of the type the tag was registered as (the API documentation for each predefined tag should contain the type). Be sure to use functions like gst_value_transform () to make sure that your data is of the right type. After data reading, the application can be notified of the new taglist by calling gst_element_found_tags () or gst_element_found_tags_for_pad () (if they only refer to a specific sub-stream). These functions will post a tag message on the pipeline's GstBus for the application to pick up, but also send tag events downstream, either over all source pad or the pad specified.

The following example program will parse a file and parse the data as metadata/tags rather than as actual content-data. It will parse each line as "name:value", where name is the type of metadata (title, author, ...) and value is the metadata value. The _getline () is the same as the one given in Sometimes pads.


static void
gst_my_filter_task_func (GstElement *element)
{
  GstMyFilter *filter = GST_MY_FILTER (element);
  GstBuffer *buf;
  GstTagList *taglist = gst_tag_list_new ();

  /* get each line and parse as metadata */
  while ((buf = gst_my_filter_getline (filter))) {
    gchar *line = GST_BUFFER_DATA (buf), *colon_pos, *type = NULL;a

    /* get the position of the ':' and go beyond it */
    if (!(colon_pos = strchr (line, ':')))
      goto next:

    /* get the string before that as type of metadata */
    type = g_strndup (line, colon_pos - line);

    /* content is one character beyond the ':' */
    colon_pos = &colon_pos[1];
    if (*colon_pos == '\0')
      goto next;

    /* get the metadata category, it's value type, store it in that
     * type and add it to the taglist. */
    if (gst_tag_exists (type)) {
      GValue from = { 0 }, to = { 0 };
      GType to_type;

      to_type = gst_tag_get_type (type);
      g_value_init (&from, G_TYPE_STRING);
      g_value_set_string (&from, colon_pos);
      g_value_init (&to, to_type);
      g_value_transform (&from, &to);
      g_value_unset (&from);
      gst_tag_list_add_values (taglist, GST_TAG_MERGE_APPEND,
			       type, &to, NULL);
      g_value_unset (&to);
    }

next:
    g_free (type);
    gst_buffer_unref (buf);
  }

  /* signal metadata */
  gst_element_found_tags_for_pad (element, filter->srcpad, 0, taglist);
  gst_tag_list_free (taglist);

  /* send EOS */
  gst_pad_send_event (filter->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
  gst_element_set_eos (element);
}

    

We currently assume the core to already know the mimetype (gst_tag_exists ()). You can add new tags to the list of known tags using gst_tag_register (). If you think the tag will be useful in more cases than just your own element, it might be a good idea to add it to gsttag.c instead. That's up to you to decide. If you want to do it in your own element, it's easiest to register the tag in one of your class init functions, preferrably _class_init ().


static void
gst_my_filter_class_init (GstMyFilterClass *klass)
{
[..]
  gst_tag_register ("my_tag_name", GST_TAG_FLAG_META,
		    G_TYPE_STRING,
		    _("my own tag"),
		    _("a tag that is specific to my own element"),
		    NULL);
[..]
}