blob: c6a71c0137bb01dc3500491568169b0487f26ddb [file] [log] [blame]
Quoting iain <>:
> If you could write a small thing about how to use the tagging, it'd be
> appreciated. I think MArlin is going to be using it pretty extensivly,
> and so it'd be nice to get it in there and tested quickly.
Ok. A short writeup.
Oh! Intro - Jellyman, offspring. Offspring, Jellyman.
GStreamer manages tags in the form of GstTagList objects. A GstTagList (named
taglist from now on) consists of zero or more different tags (this will be
what I mean when I say tag) where each tag has one or more values attached to
it. A tag is registered via gst_tag_register with it's name, translated name
(glib calls that nick), a translated description, the GType values for this
tag must have and an optional merge function.
GStreamer provides default caps which are registered in gsttag.c. You can look
them up there.
You've got serious thrill issues, dude.
A taglist is primarily thought about as a 1:1 tag:value mapping. Sometimes it
is useful to have multiple values for the same tag however. (Multiple artists
performing a song). If a merge function is provided at tag registration time,
you can attach multiple values to a tag. These values are handled as an
ordered list, so you can access each of them with an index. The merge function
allows to merge all of them back into a single value.
If no merge function is provided, only a single value is kept.
Tell me, Dory, do you see anything? - Yeah, I see a light.
There's a whole lot of API provided to change taglists. see gsttag.h for the
whole glory. Most of that should be self explaining. Foreach functions, number
of values per tag, getting tags and so on. The gst-launch code shows a usage
example. The only thing that might be of interest is the merge mode. If you
merge two tag lists (via _merge or _insert or even when only adding values via
_add_tag) you have to provide a merge mode. The merge mode decides how to
handle the merging of caps. If you merge new_tags into old_tags, the different
merge modes do this:
GST_TAG_MERGE_MODE_REPLACE_ALL: Remove all tags from old_tags, use only
GST_TAG_MERGE_MODE_REPLACE: Remove all tags from old_tags where tags from
new_tags are available. Keep the others. Insert everything from new_tags.
GST_TAG_MERGE_MODE_PREPEND: Prepend values from new_tags to the values from
old_tags. For single value tags when both are set, use the new_tags tag.
and old_tags swapped.
old_tags swapped.
new_tags and old_tags swapped.
This allows some powerful usage of taglists. I'll describe further down where
it really makes sense.
Now what?
There are supposed to be two "producers" of taglists. The first are
applications, the second are plugins. (In my tag world domination plans I
simply assumed Rhythmbox would start using taglists internally.) Applications
can easily create and access them with the API shown above. It should even be
reasonably easy to put their values inside gtk objects via foreach loops and
similar. Especially because they're all just GValues internally.
Plugins extract tag lists from the GstBuffer data. They'll have to convert it
to taglists obviously. (If you write plugins, please make sure to use the same
mapping than other plugins that use the same format. Mappings and plugins for
common tagging formats are kept in gst-plugins/gst/tags/* ) Once they have
extracted the taglist, they signal they have found tags via the "found-tag"
signal. After that they create a tag event and send that down the pipeline.
There are convenience functions for this. See code that implements this.
Oh, look at me, I'm a flippy little dolphin, let me flip for you!
There are also supposed to be two "consumers" of taglists. Applications and -
you guessed it - plugins. Applications obviously want to show the tags of the
playing pipeline or store tags for a given file, use them as the basis for
editing or whatever.
Plugins that can set tags implement the GstTagSetter interface. Don't let
yourself be fooled by the fact that this interface is an empty interface. Your
plugin still has to do something. ;) The interface provides a way to attach
tags to elements implementing the interface. Whenever the interface wants to
write tags it has to do the following:
1) Get the tags from the pipeline that you want to write. (This obviously
includes storing tags that came in via tag events.)
2) Merge the user set tags into these tags with the user set merge mode. This
is the place where the merge mode allows all te flexibility you may want:
adding tags, adding values to tags, overwriting all tags or overwriting only
some tags.
3) Write these tags to the buffer.
Hey! You guys made me ink!
I hope this exciting little intro answered some of your questions. If not, ask
more specific questions next time, please. :)