taglist: remove some outdated FIXMEs and comments
[platform/upstream/gstreamer.git] / gst / gsttaglist.c
1 /* GStreamer
2  * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
3  *
4  * gsttaglist.c: tag support (aka metadata)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:gsttaglist
24  * @short_description: List of tags and values used to describe media metadata
25  *
26  * List of tags and values used to describe media metadata.
27  *
28  * Strings must be in ASCII or UTF-8 encoding. No other encodings are allowed.
29  *
30  * Last reviewed on 2009-06-09 (0.10.23)
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #  include "config.h"
35 #endif
36
37 #include "gst_private.h"
38 #include "math-compat.h"
39 #include "gst-i18n-lib.h"
40 #include "gsttaglist.h"
41 #include "gstinfo.h"
42 #include "gstvalue.h"
43 #include "gstbuffer.h"
44 #include "gstquark.h"
45 #include "gststructure.h"
46
47 #include <gobject/gvaluecollector.h>
48 #include <string.h>
49
50 /* FIXME: add category for tags */
51 #define GST_CAT_TAGS GST_CAT_DEFAULT
52
53 #define GST_TAG_IS_VALID(tag)           (gst_tag_get_info (tag) != NULL)
54
55 typedef struct _GstTagListImpl
56 {
57   GstTagList taglist;
58
59   GstStructure *structure;
60 } GstTagListImpl;
61
62 #define GST_TAG_LIST_STRUCTURE(taglist)  ((GstTagListImpl*)(taglist))->structure
63
64 typedef struct
65 {
66   GType type;                   /* type the data is in */
67
68   const gchar *nick;            /* translated short description */
69   const gchar *blurb;           /* translated long description  */
70
71   GstTagMergeFunc merge_func;   /* functions to merge the values */
72   GstTagFlag flag;              /* type of tag */
73   GQuark name_quark;            /* quark for the name */
74 }
75 GstTagInfo;
76
77 #define g_value_get_char g_value_get_schar
78
79 static GMutex __tag_mutex;
80 #define TAG_LOCK g_mutex_lock (&__tag_mutex)
81 #define TAG_UNLOCK g_mutex_unlock (&__tag_mutex)
82
83 /* tags hash table: maps tag name string => GstTagInfo */
84 static GHashTable *__tags;
85
86 GST_DEFINE_MINI_OBJECT_TYPE (GstTagList, gst_tag_list);
87
88 static void __gst_tag_list_free (GstTagList * list);
89 static GstTagList *__gst_tag_list_copy (const GstTagList * list);
90
91 /* FIXME: had code:
92  *    g_value_register_transform_func (_gst_tag_list_type, G_TYPE_STRING,
93  *      _gst_structure_transform_to_string);
94  */
95 void
96 _priv_gst_tag_initialize (void)
97 {
98   g_mutex_init (&__tag_mutex);
99
100   __tags = g_hash_table_new (g_str_hash, g_str_equal);
101   gst_tag_register_static (GST_TAG_TITLE, GST_TAG_FLAG_META,
102       G_TYPE_STRING,
103       _("title"), _("commonly used title"), gst_tag_merge_strings_with_comma);
104   gst_tag_register_static (GST_TAG_TITLE_SORTNAME, GST_TAG_FLAG_META,
105       G_TYPE_STRING,
106       _("title sortname"), _("commonly used title for sorting purposes"), NULL);
107   gst_tag_register_static (GST_TAG_ARTIST, GST_TAG_FLAG_META,
108       G_TYPE_STRING,
109       _("artist"),
110       _("person(s) responsible for the recording"),
111       gst_tag_merge_strings_with_comma);
112   gst_tag_register_static (GST_TAG_ARTIST_SORTNAME, GST_TAG_FLAG_META,
113       G_TYPE_STRING,
114       _("artist sortname"),
115       _("person(s) responsible for the recording for sorting purposes"), NULL);
116   gst_tag_register_static (GST_TAG_ALBUM, GST_TAG_FLAG_META,
117       G_TYPE_STRING,
118       _("album"),
119       _("album containing this data"), gst_tag_merge_strings_with_comma);
120   gst_tag_register_static (GST_TAG_ALBUM_SORTNAME, GST_TAG_FLAG_META,
121       G_TYPE_STRING,
122       _("album sortname"),
123       _("album containing this data for sorting purposes"), NULL);
124   gst_tag_register_static (GST_TAG_ALBUM_ARTIST, GST_TAG_FLAG_META,
125       G_TYPE_STRING,
126       _("album artist"),
127       _("The artist of the entire album, as it should be displayed"),
128       gst_tag_merge_strings_with_comma);
129   gst_tag_register_static (GST_TAG_ALBUM_ARTIST_SORTNAME, GST_TAG_FLAG_META,
130       G_TYPE_STRING,
131       _("album artist sortname"),
132       _("The artist of the entire album, as it should be sorted"), NULL);
133   gst_tag_register_static (GST_TAG_DATE, GST_TAG_FLAG_META, G_TYPE_DATE,
134       _("date"), _("date the data was created (as a GDate structure)"), NULL);
135   gst_tag_register_static (GST_TAG_DATE_TIME, GST_TAG_FLAG_META,
136       GST_TYPE_DATE_TIME, _("datetime"),
137       _("date and time the data was created (as a GstDateTime structure)"),
138       NULL);
139   gst_tag_register_static (GST_TAG_GENRE, GST_TAG_FLAG_META,
140       G_TYPE_STRING,
141       _("genre"),
142       _("genre this data belongs to"), gst_tag_merge_strings_with_comma);
143   gst_tag_register_static (GST_TAG_COMMENT, GST_TAG_FLAG_META,
144       G_TYPE_STRING,
145       _("comment"),
146       _("free text commenting the data"), gst_tag_merge_use_first);
147   gst_tag_register_static (GST_TAG_EXTENDED_COMMENT, GST_TAG_FLAG_META,
148       G_TYPE_STRING,
149       _("extended comment"),
150       _("free text commenting the data in key=value or key[en]=comment form"),
151       gst_tag_merge_use_first);
152   gst_tag_register_static (GST_TAG_TRACK_NUMBER, GST_TAG_FLAG_META,
153       G_TYPE_UINT,
154       _("track number"),
155       _("track number inside a collection"), gst_tag_merge_use_first);
156   gst_tag_register_static (GST_TAG_TRACK_COUNT, GST_TAG_FLAG_META,
157       G_TYPE_UINT,
158       _("track count"),
159       _("count of tracks inside collection this track belongs to"),
160       gst_tag_merge_use_first);
161   gst_tag_register_static (GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_FLAG_META,
162       G_TYPE_UINT,
163       _("disc number"),
164       _("disc number inside a collection"), gst_tag_merge_use_first);
165   gst_tag_register_static (GST_TAG_ALBUM_VOLUME_COUNT, GST_TAG_FLAG_META,
166       G_TYPE_UINT,
167       _("disc count"),
168       _("count of discs inside collection this disc belongs to"),
169       gst_tag_merge_use_first);
170   gst_tag_register_static (GST_TAG_LOCATION, GST_TAG_FLAG_META,
171       G_TYPE_STRING,
172       _("location"), _("Origin of media as a URI (location, where the "
173           "original of the file or stream is hosted)"),
174       gst_tag_merge_strings_with_comma);
175   gst_tag_register_static (GST_TAG_HOMEPAGE, GST_TAG_FLAG_META,
176       G_TYPE_STRING,
177       _("homepage"),
178       _("Homepage for this media (i.e. artist or movie homepage)"),
179       gst_tag_merge_strings_with_comma);
180   gst_tag_register_static (GST_TAG_DESCRIPTION, GST_TAG_FLAG_META,
181       G_TYPE_STRING, _("description"),
182       _("short text describing the content of the data"),
183       gst_tag_merge_strings_with_comma);
184   gst_tag_register_static (GST_TAG_VERSION, GST_TAG_FLAG_META, G_TYPE_STRING,
185       _("version"), _("version of this data"), NULL);
186   gst_tag_register_static (GST_TAG_ISRC, GST_TAG_FLAG_META, G_TYPE_STRING,
187       _("ISRC"),
188       _
189       ("International Standard Recording Code - see http://www.ifpi.org/isrc/"),
190       NULL);
191   /* FIXME: organization (fix what? tpm) */
192   gst_tag_register_static (GST_TAG_ORGANIZATION, GST_TAG_FLAG_META,
193       G_TYPE_STRING, _("organization"), _("organization"),
194       gst_tag_merge_strings_with_comma);
195   gst_tag_register_static (GST_TAG_COPYRIGHT, GST_TAG_FLAG_META,
196       G_TYPE_STRING, _("copyright"), _("copyright notice of the data"), NULL);
197   gst_tag_register_static (GST_TAG_COPYRIGHT_URI, GST_TAG_FLAG_META,
198       G_TYPE_STRING, _("copyright uri"),
199       _("URI to the copyright notice of the data"), NULL);
200   gst_tag_register_static (GST_TAG_ENCODED_BY, GST_TAG_FLAG_META, G_TYPE_STRING,
201       _("encoded by"), _("name of the encoding person or organization"),
202       gst_tag_merge_strings_with_comma);
203   gst_tag_register_static (GST_TAG_CONTACT, GST_TAG_FLAG_META,
204       G_TYPE_STRING,
205       _("contact"), _("contact information"), gst_tag_merge_strings_with_comma);
206   gst_tag_register_static (GST_TAG_LICENSE, GST_TAG_FLAG_META,
207       G_TYPE_STRING, _("license"), _("license of data"), NULL);
208   gst_tag_register_static (GST_TAG_LICENSE_URI, GST_TAG_FLAG_META,
209       G_TYPE_STRING, _("license uri"),
210       _("URI to the license of the data"), NULL);
211   gst_tag_register_static (GST_TAG_PERFORMER, GST_TAG_FLAG_META,
212       G_TYPE_STRING,
213       _("performer"),
214       _("person(s) performing"), gst_tag_merge_strings_with_comma);
215   gst_tag_register_static (GST_TAG_COMPOSER, GST_TAG_FLAG_META,
216       G_TYPE_STRING,
217       _("composer"),
218       _("person(s) who composed the recording"),
219       gst_tag_merge_strings_with_comma);
220   gst_tag_register_static (GST_TAG_DURATION, GST_TAG_FLAG_DECODED,
221       G_TYPE_UINT64,
222       _("duration"), _("length in GStreamer time units (nanoseconds)"), NULL);
223   gst_tag_register_static (GST_TAG_CODEC, GST_TAG_FLAG_ENCODED,
224       G_TYPE_STRING,
225       _("codec"),
226       _("codec the data is stored in"), gst_tag_merge_strings_with_comma);
227   gst_tag_register_static (GST_TAG_VIDEO_CODEC, GST_TAG_FLAG_ENCODED,
228       G_TYPE_STRING,
229       _("video codec"), _("codec the video data is stored in"), NULL);
230   gst_tag_register_static (GST_TAG_AUDIO_CODEC, GST_TAG_FLAG_ENCODED,
231       G_TYPE_STRING,
232       _("audio codec"), _("codec the audio data is stored in"), NULL);
233   gst_tag_register_static (GST_TAG_SUBTITLE_CODEC, GST_TAG_FLAG_ENCODED,
234       G_TYPE_STRING,
235       _("subtitle codec"), _("codec the subtitle data is stored in"), NULL);
236   gst_tag_register_static (GST_TAG_CONTAINER_FORMAT, GST_TAG_FLAG_ENCODED,
237       G_TYPE_STRING, _("container format"),
238       _("container format the data is stored in"), NULL);
239   gst_tag_register_static (GST_TAG_BITRATE, GST_TAG_FLAG_ENCODED,
240       G_TYPE_UINT, _("bitrate"), _("exact or average bitrate in bits/s"), NULL);
241   gst_tag_register_static (GST_TAG_NOMINAL_BITRATE, GST_TAG_FLAG_ENCODED,
242       G_TYPE_UINT, _("nominal bitrate"), _("nominal bitrate in bits/s"), NULL);
243   gst_tag_register_static (GST_TAG_MINIMUM_BITRATE, GST_TAG_FLAG_ENCODED,
244       G_TYPE_UINT, _("minimum bitrate"), _("minimum bitrate in bits/s"), NULL);
245   gst_tag_register_static (GST_TAG_MAXIMUM_BITRATE, GST_TAG_FLAG_ENCODED,
246       G_TYPE_UINT, _("maximum bitrate"), _("maximum bitrate in bits/s"), NULL);
247   gst_tag_register_static (GST_TAG_ENCODER, GST_TAG_FLAG_ENCODED,
248       G_TYPE_STRING,
249       _("encoder"), _("encoder used to encode this stream"), NULL);
250   gst_tag_register_static (GST_TAG_ENCODER_VERSION, GST_TAG_FLAG_ENCODED,
251       G_TYPE_UINT,
252       _("encoder version"),
253       _("version of the encoder used to encode this stream"), NULL);
254   gst_tag_register_static (GST_TAG_SERIAL, GST_TAG_FLAG_ENCODED,
255       G_TYPE_UINT, _("serial"), _("serial number of track"), NULL);
256   gst_tag_register_static (GST_TAG_TRACK_GAIN, GST_TAG_FLAG_META,
257       G_TYPE_DOUBLE, _("replaygain track gain"), _("track gain in db"), NULL);
258   gst_tag_register_static (GST_TAG_TRACK_PEAK, GST_TAG_FLAG_META,
259       G_TYPE_DOUBLE, _("replaygain track peak"), _("peak of the track"), NULL);
260   gst_tag_register_static (GST_TAG_ALBUM_GAIN, GST_TAG_FLAG_META,
261       G_TYPE_DOUBLE, _("replaygain album gain"), _("album gain in db"), NULL);
262   gst_tag_register_static (GST_TAG_ALBUM_PEAK, GST_TAG_FLAG_META,
263       G_TYPE_DOUBLE, _("replaygain album peak"), _("peak of the album"), NULL);
264   gst_tag_register_static (GST_TAG_REFERENCE_LEVEL, GST_TAG_FLAG_META,
265       G_TYPE_DOUBLE, _("replaygain reference level"),
266       _("reference level of track and album gain values"), NULL);
267   gst_tag_register_static (GST_TAG_LANGUAGE_CODE, GST_TAG_FLAG_META,
268       G_TYPE_STRING, _("language code"),
269       _("language code for this stream, conforming to ISO-639-1 or ISO-639-2"),
270       NULL);
271   gst_tag_register_static (GST_TAG_LANGUAGE_NAME, GST_TAG_FLAG_META,
272       G_TYPE_STRING, _("language name"),
273       _("freeform name of the language this stream is in"), NULL);
274   gst_tag_register_static (GST_TAG_IMAGE, GST_TAG_FLAG_META, GST_TYPE_SAMPLE,
275       _("image"), _("image related to this stream"), gst_tag_merge_use_first);
276   gst_tag_register_static (GST_TAG_PREVIEW_IMAGE, GST_TAG_FLAG_META,
277       GST_TYPE_SAMPLE,
278       /* TRANSLATORS: 'preview image' = image that shows a preview of the full image */
279       _("preview image"), _("preview image related to this stream"), NULL);
280   gst_tag_register_static (GST_TAG_ATTACHMENT, GST_TAG_FLAG_META,
281       GST_TYPE_SAMPLE, _("attachment"), _("file attached to this stream"),
282       gst_tag_merge_use_first);
283   gst_tag_register_static (GST_TAG_BEATS_PER_MINUTE, GST_TAG_FLAG_META,
284       G_TYPE_DOUBLE, _("beats per minute"),
285       _("number of beats per minute in audio"), NULL);
286   gst_tag_register_static (GST_TAG_KEYWORDS, GST_TAG_FLAG_META, G_TYPE_STRING,
287       _("keywords"), _("comma separated keywords describing the content"),
288       gst_tag_merge_strings_with_comma);
289   gst_tag_register_static (GST_TAG_GEO_LOCATION_NAME, GST_TAG_FLAG_META,
290       G_TYPE_STRING, _("geo location name"),
291       _("human readable descriptive location of where "
292           "the media has been recorded or produced"), NULL);
293   gst_tag_register_static (GST_TAG_GEO_LOCATION_LATITUDE, GST_TAG_FLAG_META,
294       G_TYPE_DOUBLE, _("geo location latitude"),
295       _("geo latitude location of where the media has been recorded or "
296           "produced in degrees according to WGS84 (zero at the equator, "
297           "negative values for southern latitudes)"), NULL);
298   gst_tag_register_static (GST_TAG_GEO_LOCATION_LONGITUDE, GST_TAG_FLAG_META,
299       G_TYPE_DOUBLE, _("geo location longitude"),
300       _("geo longitude location of where the media has been recorded or "
301           "produced in degrees according to WGS84 (zero at the prime meridian "
302           "in Greenwich/UK,  negative values for western longitudes)"), NULL);
303   gst_tag_register_static (GST_TAG_GEO_LOCATION_ELEVATION, GST_TAG_FLAG_META,
304       G_TYPE_DOUBLE, _("geo location elevation"),
305       _("geo elevation of where the media has been recorded or produced in "
306           "meters according to WGS84 (zero is average sea level)"), NULL);
307   gst_tag_register_static (GST_TAG_GEO_LOCATION_COUNTRY, GST_TAG_FLAG_META,
308       G_TYPE_STRING, _("geo location country"),
309       _("country (english name) where the media has been recorded "
310           "or produced"), NULL);
311   gst_tag_register_static (GST_TAG_GEO_LOCATION_CITY, GST_TAG_FLAG_META,
312       G_TYPE_STRING, _("geo location city"),
313       _("city (english name) where the media has been recorded "
314           "or produced"), NULL);
315   gst_tag_register_static (GST_TAG_GEO_LOCATION_SUBLOCATION, GST_TAG_FLAG_META,
316       G_TYPE_STRING, _("geo location sublocation"),
317       _("a location whithin a city where the media has been produced "
318           "or created (e.g. the neighborhood)"), NULL);
319   gst_tag_register_static (GST_TAG_GEO_LOCATION_HORIZONTAL_ERROR,
320       GST_TAG_FLAG_META, G_TYPE_DOUBLE, _("geo location horizontal error"),
321       _("expected error of the horizontal positioning measures (in meters)"),
322       NULL);
323   gst_tag_register_static (GST_TAG_GEO_LOCATION_MOVEMENT_SPEED,
324       GST_TAG_FLAG_META, G_TYPE_DOUBLE, _("geo location movement speed"),
325       _("movement speed of the capturing device while performing the capture "
326           "in m/s"), NULL);
327   gst_tag_register_static (GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION,
328       GST_TAG_FLAG_META, G_TYPE_DOUBLE, _("geo location movement direction"),
329       _("indicates the movement direction of the device performing the capture"
330           " of a media. It is represented as degrees in floating point "
331           "representation, 0 means the geographic north, and increases "
332           "clockwise"), NULL);
333   gst_tag_register_static (GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION,
334       GST_TAG_FLAG_META, G_TYPE_DOUBLE, _("geo location capture direction"),
335       _("indicates the direction the device is pointing to when capturing "
336           " a media. It is represented as degrees in floating point "
337           " representation, 0 means the geographic north, and increases "
338           "clockwise"), NULL);
339   gst_tag_register_static (GST_TAG_SHOW_NAME, GST_TAG_FLAG_META, G_TYPE_STRING,
340       /* TRANSLATORS: 'show name' = 'TV/radio/podcast show name' here */
341       _("show name"),
342       _("Name of the tv/podcast/series show the media is from"),
343       gst_tag_merge_strings_with_comma);
344   gst_tag_register_static (GST_TAG_SHOW_SORTNAME, GST_TAG_FLAG_META,
345       G_TYPE_STRING,
346       /* TRANSLATORS: 'show sortname' = 'TV/radio/podcast show name as used for sorting purposes' here */
347       _("show sortname"),
348       _("Name of the tv/podcast/series show the media is from, for sorting "
349           "purposes"), NULL);
350   gst_tag_register_static (GST_TAG_SHOW_EPISODE_NUMBER, GST_TAG_FLAG_META,
351       G_TYPE_UINT, _("episode number"),
352       _("The episode number in the season the media is part of"),
353       gst_tag_merge_use_first);
354   gst_tag_register_static (GST_TAG_SHOW_SEASON_NUMBER, GST_TAG_FLAG_META,
355       G_TYPE_UINT, _("season number"),
356       _("The season number of the show the media is part of"),
357       gst_tag_merge_use_first);
358   gst_tag_register_static (GST_TAG_LYRICS, GST_TAG_FLAG_META, G_TYPE_STRING,
359       _("lyrics"), _("The lyrics of the media, commonly used for songs"),
360       gst_tag_merge_strings_with_comma);
361   gst_tag_register_static (GST_TAG_COMPOSER_SORTNAME, GST_TAG_FLAG_META,
362       G_TYPE_STRING, _("composer sortname"),
363       _("person(s) who composed the recording, for sorting purposes"), NULL);
364   gst_tag_register_static (GST_TAG_GROUPING, GST_TAG_FLAG_META, G_TYPE_STRING,
365       _("grouping"),
366       _("Groups related media that spans multiple tracks, like the different "
367           "pieces of a concerto. It is a higher level than a track, "
368           "but lower than an album"), NULL);
369   gst_tag_register_static (GST_TAG_USER_RATING, GST_TAG_FLAG_META, G_TYPE_UINT,
370       _("user rating"),
371       _("Rating attributed by a user. The higher the rank, "
372           "the more the user likes this media"), NULL);
373   gst_tag_register_static (GST_TAG_DEVICE_MANUFACTURER, GST_TAG_FLAG_META,
374       G_TYPE_STRING, _("device manufacturer"),
375       _("Manufacturer of the device used to create this media"), NULL);
376   gst_tag_register_static (GST_TAG_DEVICE_MODEL, GST_TAG_FLAG_META,
377       G_TYPE_STRING, _("device model"),
378       _("Model of the device used to create this media"), NULL);
379   gst_tag_register_static (GST_TAG_APPLICATION_NAME, GST_TAG_FLAG_META,
380       G_TYPE_STRING, _("application name"),
381       _("Application used to create the media"), NULL);
382   gst_tag_register_static (GST_TAG_APPLICATION_DATA, GST_TAG_FLAG_META,
383       GST_TYPE_BUFFER, _("application data"),
384       _("Arbitrary application data to be serialized into the media"), NULL);
385   gst_tag_register_static (GST_TAG_IMAGE_ORIENTATION, GST_TAG_FLAG_META,
386       G_TYPE_STRING, _("image orientation"),
387       _("How the image should be rotated or flipped before display"), NULL);
388 }
389
390 /**
391  * gst_tag_merge_use_first:
392  * @dest: (out caller-allocates): uninitialized GValue to store result in
393  * @src: GValue to copy from
394  *
395  * This is a convenience function for the func argument of gst_tag_register().
396  * It creates a copy of the first value from the list.
397  */
398 void
399 gst_tag_merge_use_first (GValue * dest, const GValue * src)
400 {
401   const GValue *ret = gst_value_list_get_value (src, 0);
402
403   g_value_init (dest, G_VALUE_TYPE (ret));
404   g_value_copy (ret, dest);
405 }
406
407 /**
408  * gst_tag_merge_strings_with_comma:
409  * @dest: (out caller-allocates): uninitialized GValue to store result in
410  * @src: GValue to copy from
411  *
412  * This is a convenience function for the func argument of gst_tag_register().
413  * It concatenates all given strings using a comma. The tag must be registered
414  * as a G_TYPE_STRING or this function will fail.
415  */
416 void
417 gst_tag_merge_strings_with_comma (GValue * dest, const GValue * src)
418 {
419   GString *str;
420   gint i, count;
421
422   count = gst_value_list_get_size (src);
423   str = g_string_new (g_value_get_string (gst_value_list_get_value (src, 0)));
424   for (i = 1; i < count; i++) {
425     /* separator between two strings */
426     g_string_append (str, _(", "));
427     g_string_append (str,
428         g_value_get_string (gst_value_list_get_value (src, i)));
429   }
430
431   g_value_init (dest, G_TYPE_STRING);
432   g_value_take_string (dest, str->str);
433   g_string_free (str, FALSE);
434 }
435
436 static GstTagInfo *
437 gst_tag_lookup (const gchar * tag_name)
438 {
439   GstTagInfo *ret;
440
441   TAG_LOCK;
442   ret = g_hash_table_lookup (__tags, (gpointer) tag_name);
443   TAG_UNLOCK;
444
445   return ret;
446 }
447
448 /**
449  * gst_tag_register:
450  * @name: the name or identifier string
451  * @flag: a flag describing the type of tag info
452  * @type: the type this data is in
453  * @nick: human-readable name
454  * @blurb: a human-readable description about this tag
455  * @func: function for merging multiple values of this tag, or NULL
456  *
457  * Registers a new tag type for the use with GStreamer's type system. If a type
458  * with that name is already registered, that one is used.
459  * The old registration may have used a different type however. So don't rely
460  * on your supplied values.
461  *
462  * Important: if you do not supply a merge function the implication will be
463  * that there can only be one single value for this tag in a tag list and
464  * any additional values will silenty be discarded when being added (unless
465  * #GST_TAG_MERGE_REPLACE, #GST_TAG_MERGE_REPLACE_ALL, or
466  * #GST_TAG_MERGE_PREPEND is used as merge mode, in which case the new
467  * value will replace the old one in the list).
468  *
469  * The merge function will be called from gst_tag_list_copy_value() when
470  * it is required that one or more values for a tag be condensed into
471  * one single value. This may happen from gst_tag_list_get_string(),
472  * gst_tag_list_get_int(), gst_tag_list_get_double() etc. What will happen
473  * exactly in that case depends on how the tag was registered and if a
474  * merge function was supplied and if so which one.
475  *
476  * Two default merge functions are provided: gst_tag_merge_use_first() and
477  * gst_tag_merge_strings_with_comma().
478  */
479 void
480 gst_tag_register (const gchar * name, GstTagFlag flag, GType type,
481     const gchar * nick, const gchar * blurb, GstTagMergeFunc func)
482 {
483   g_return_if_fail (name != NULL);
484   g_return_if_fail (nick != NULL);
485   g_return_if_fail (blurb != NULL);
486   g_return_if_fail (type != 0 && type != GST_TYPE_LIST);
487
488   return gst_tag_register_static (g_intern_string (name), flag, type,
489       g_intern_string (nick), g_intern_string (blurb), func);
490 }
491
492 /**
493  * gst_tag_register_static:
494  * @name: the name or identifier string (string constant)
495  * @flag: a flag describing the type of tag info
496  * @type: the type this data is in
497  * @nick: human-readable name or short description (string constant)
498  * @blurb: a human-readable description for this tag (string constant)
499  * @func: function for merging multiple values of this tag, or NULL
500  *
501  * Registers a new tag type for the use with GStreamer's type system.
502  *
503  * Same as gst_tag_register(), but @name, @nick, and @blurb must be
504  * static strings or inlined strings, as they will not be copied. (GStreamer
505  * plugins will be made resident once loaded, so this function can be used
506  * even from dynamically loaded plugins.)
507  */
508 void
509 gst_tag_register_static (const gchar * name, GstTagFlag flag, GType type,
510     const gchar * nick, const gchar * blurb, GstTagMergeFunc func)
511 {
512   GstTagInfo *info;
513
514   g_return_if_fail (name != NULL);
515   g_return_if_fail (nick != NULL);
516   g_return_if_fail (blurb != NULL);
517   g_return_if_fail (type != 0 && type != GST_TYPE_LIST);
518
519   info = gst_tag_lookup (name);
520
521   if (info) {
522     g_return_if_fail (info->type == type);
523     return;
524   }
525
526   info = g_slice_new (GstTagInfo);
527   info->flag = flag;
528   info->type = type;
529   info->name_quark = g_quark_from_static_string (name);
530   info->nick = nick;
531   info->blurb = blurb;
532   info->merge_func = func;
533
534   TAG_LOCK;
535   g_hash_table_insert (__tags, (gpointer) name, info);
536   TAG_UNLOCK;
537 }
538
539 /**
540  * gst_tag_exists:
541  * @tag: name of the tag
542  *
543  * Checks if the given type is already registered.
544  *
545  * Returns: TRUE if the type is already registered
546  */
547 gboolean
548 gst_tag_exists (const gchar * tag)
549 {
550   g_return_val_if_fail (tag != NULL, FALSE);
551
552   return gst_tag_lookup (tag) != NULL;
553 }
554
555 /**
556  * gst_tag_get_type:
557  * @tag: the tag
558  *
559  * Gets the #GType used for this tag.
560  *
561  * Returns: the #GType of this tag
562  */
563 GType
564 gst_tag_get_type (const gchar * tag)
565 {
566   GstTagInfo *info;
567
568   g_return_val_if_fail (tag != NULL, 0);
569   info = gst_tag_lookup (tag);
570   g_return_val_if_fail (info != NULL, 0);
571
572   return info->type;
573 }
574
575 /**
576  * gst_tag_get_nick:
577  * @tag: the tag
578  *
579  * Returns the human-readable name of this tag, You must not change or free
580  * this string.
581  *
582  * Returns: the human-readable name of this tag
583  */
584 const gchar *
585 gst_tag_get_nick (const gchar * tag)
586 {
587   GstTagInfo *info;
588
589   g_return_val_if_fail (tag != NULL, NULL);
590   info = gst_tag_lookup (tag);
591   g_return_val_if_fail (info != NULL, NULL);
592
593   return info->nick;
594 }
595
596 /**
597  * gst_tag_get_description:
598  * @tag: the tag
599  *
600  * Returns the human-readable description of this tag, You must not change or
601  * free this string.
602  *
603  * Returns: the human-readable description of this tag
604  */
605 const gchar *
606 gst_tag_get_description (const gchar * tag)
607 {
608   GstTagInfo *info;
609
610   g_return_val_if_fail (tag != NULL, NULL);
611   info = gst_tag_lookup (tag);
612   g_return_val_if_fail (info != NULL, NULL);
613
614   return info->blurb;
615 }
616
617 /**
618  * gst_tag_get_flag:
619  * @tag: the tag
620  *
621  * Gets the flag of @tag.
622  *
623  * Returns: the flag of this tag.
624  */
625 GstTagFlag
626 gst_tag_get_flag (const gchar * tag)
627 {
628   GstTagInfo *info;
629
630   g_return_val_if_fail (tag != NULL, GST_TAG_FLAG_UNDEFINED);
631   info = gst_tag_lookup (tag);
632   g_return_val_if_fail (info != NULL, GST_TAG_FLAG_UNDEFINED);
633
634   return info->flag;
635 }
636
637 /**
638  * gst_tag_is_fixed:
639  * @tag: tag to check
640  *
641  * Checks if the given tag is fixed. A fixed tag can only contain one value.
642  * Unfixed tags can contain lists of values.
643  *
644  * Returns: TRUE, if the given tag is fixed.
645  */
646 gboolean
647 gst_tag_is_fixed (const gchar * tag)
648 {
649   GstTagInfo *info;
650
651   g_return_val_if_fail (tag != NULL, FALSE);
652   info = gst_tag_lookup (tag);
653   g_return_val_if_fail (info != NULL, FALSE);
654
655   return info->merge_func == NULL;
656 }
657
658 static void
659 gst_tag_list_init (GstTagList * taglist)
660 {
661   gst_mini_object_init (GST_MINI_OBJECT_CAST (taglist),
662       gst_tag_list_get_type ());
663
664   taglist->mini_object.copy = (GstMiniObjectCopyFunction) __gst_tag_list_copy;
665   taglist->mini_object.dispose = NULL;
666   taglist->mini_object.free = (GstMiniObjectFreeFunction) __gst_tag_list_free;
667 }
668
669 /* takes ownership of the structure */
670 static GstTagList *
671 gst_tag_list_new_internal (GstStructure * s)
672 {
673   GstTagList *tag_list;
674
675   g_assert (s != NULL);
676
677   tag_list = (GstTagList *) g_slice_new (GstTagListImpl);
678
679   gst_tag_list_init (tag_list);
680
681   GST_TAG_LIST_STRUCTURE (tag_list) = s;
682
683 #ifdef DEBUG_REFCOUNT
684   GST_CAT_TRACE (GST_CAT_TAGS, "created taglist %p", tag_list);
685 #endif
686
687   return tag_list;
688 }
689
690 static void
691 __gst_tag_list_free (GstTagList * list)
692 {
693   g_return_if_fail (GST_IS_TAG_LIST (list));
694
695 #ifdef DEBUG_REFCOUNT
696   GST_CAT_TRACE (GST_CAT_TAGS, "freeing caps %p", list);
697 #endif
698
699   gst_structure_free (GST_TAG_LIST_STRUCTURE (list));
700
701   g_slice_free1 (sizeof (GstTagListImpl), list);
702 }
703
704 static GstTagList *
705 __gst_tag_list_copy (const GstTagList * list)
706 {
707   const GstStructure *s;
708
709   g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
710
711   s = GST_TAG_LIST_STRUCTURE (list);
712   return gst_tag_list_new_internal (gst_structure_copy (s));
713 }
714
715 /**
716  * gst_tag_list_new_empty:
717  *
718  * Creates a new empty GstTagList.
719  *
720  * Free-function: gst_tag_list_unref
721  *
722  * Returns: (transfer full): An empty tag list
723  */
724 GstTagList *
725 gst_tag_list_new_empty (void)
726 {
727   GstStructure *s;
728   GstTagList *tag_list;
729
730   s = gst_structure_new_id_empty (GST_QUARK (TAGLIST));
731   tag_list = gst_tag_list_new_internal (s);
732   return tag_list;
733 }
734
735 /**
736  * gst_tag_list_new:
737  * @tag: tag
738  * @...: NULL-terminated list of values to set
739  *
740  * Creates a new taglist and appends the values for the given tags. It expects
741  * tag-value pairs like gst_tag_list_add(), and a NULL terminator after the
742  * last pair. The type of the values is implicit and is documented in the API
743  * reference, but can also be queried at runtime with gst_tag_get_type(). It
744  * is an error to pass a value of a type not matching the tag type into this
745  * function. The tag list will make copies of any arguments passed
746  * (e.g. strings, buffers).
747  *
748  * Free-function: gst_tag_list_unref
749  *
750  * Returns: (transfer full): a new #GstTagList. Free with gst_tag_list_unref()
751  *     when no longer needed.
752  *
753  * Since: 0.10.24
754  */
755 GstTagList *
756 gst_tag_list_new (const gchar * tag, ...)
757 {
758   GstTagList *list;
759   va_list args;
760
761   g_return_val_if_fail (tag != NULL, NULL);
762
763   list = gst_tag_list_new_empty ();
764   va_start (args, tag);
765   gst_tag_list_add_valist (list, GST_TAG_MERGE_APPEND, tag, args);
766   va_end (args);
767
768   return list;
769 }
770
771 /**
772  * gst_tag_list_new_valist:
773  * @var_args: tag / value pairs to set
774  *
775  * Just like gst_tag_list_new(), only that it takes a va_list argument.
776  * Useful mostly for language bindings.
777  *
778  * Free-function: gst_tag_list_unref
779  *
780  * Returns: (transfer full): a new #GstTagList. Free with gst_tag_list_unref()
781  *     when no longer needed.
782  *
783  * Since: 0.10.24
784  */
785 GstTagList *
786 gst_tag_list_new_valist (va_list var_args)
787 {
788   GstTagList *list;
789   const gchar *tag;
790
791   list = gst_tag_list_new_empty ();
792
793   tag = va_arg (var_args, gchar *);
794   gst_tag_list_add_valist (list, GST_TAG_MERGE_APPEND, tag, var_args);
795
796   return list;
797 }
798
799 /**
800  * gst_tag_list_to_string:
801  * @list: a #GstTagList
802  *
803  * Serializes a tag list to a string.
804  *
805  * Returns: a newly-allocated string, or NULL in case of an error. The
806  *    string must be freed with g_free() when no longer needed.
807  *
808  * Since: 0.10.36
809  */
810 gchar *
811 gst_tag_list_to_string (const GstTagList * list)
812 {
813   g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
814
815   return gst_structure_to_string (GST_TAG_LIST_STRUCTURE (list));
816 }
817
818 /**
819  * gst_tag_list_new_from_string:
820  * @str: a string created with gst_tag_list_to_string()
821  *
822  * Deserializes a tag list.
823  *
824  * Returns: a new #GstTagList, or NULL in case of an error.
825  *
826  * Since: 0.10.36
827  */
828 GstTagList *
829 gst_tag_list_new_from_string (const gchar * str)
830 {
831   GstTagList *tag_list;
832
833   g_return_val_if_fail (str != NULL, NULL);
834   g_return_val_if_fail (g_str_has_prefix (str, "taglist"), NULL);
835
836   tag_list = gst_tag_list_new_internal (gst_structure_from_string (str, NULL));
837   return tag_list;
838 }
839
840 /**
841  * gst_tag_list_n_tags:
842  * @list: A #GstTagList.
843  *
844  * Get the number of tags in @list.
845  *
846  * Returns: The number of tags in @list.
847  */
848 gint
849 gst_tag_list_n_tags (const GstTagList * list)
850 {
851   g_return_val_if_fail (list != NULL, 0);
852   g_return_val_if_fail (GST_IS_TAG_LIST (list), 0);
853
854   return gst_structure_n_fields (GST_TAG_LIST_STRUCTURE (list));
855 }
856
857 /**
858  * gst_tag_list_nth_tag_name:
859  * @list: A #GstTagList.
860  * @index: the index
861  *
862  * Get the name of the tag in @list at @index.
863  *
864  * Returns: The name of the tag at @index.
865  */
866 const gchar *
867 gst_tag_list_nth_tag_name (const GstTagList * list, guint index)
868 {
869   g_return_val_if_fail (list != NULL, 0);
870   g_return_val_if_fail (GST_IS_TAG_LIST (list), 0);
871
872   return gst_structure_nth_field_name (GST_TAG_LIST_STRUCTURE (list), index);
873 }
874
875 /**
876  * gst_tag_list_is_empty:
877  * @list: A #GstTagList.
878  *
879  * Checks if the given taglist is empty.
880  *
881  * Returns: TRUE if the taglist is empty, otherwise FALSE.
882  *
883  * Since: 0.10.11
884  */
885 gboolean
886 gst_tag_list_is_empty (const GstTagList * list)
887 {
888   g_return_val_if_fail (list != NULL, FALSE);
889   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
890
891   return (gst_structure_n_fields (GST_TAG_LIST_STRUCTURE (list)) == 0);
892 }
893
894 static gboolean
895 gst_tag_list_fields_equal (const GValue * value1, const GValue * value2)
896 {
897   gdouble d1, d2;
898
899   if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL)
900     return TRUE;
901
902   /* fields not equal: add some tolerance for doubles, otherwise bail out */
903   if (!G_VALUE_HOLDS_DOUBLE (value1) || !G_VALUE_HOLDS_DOUBLE (value2))
904     return FALSE;
905
906   d1 = g_value_get_double (value1);
907   d2 = g_value_get_double (value2);
908
909   /* This will only work for 'normal' values and values around 0,
910    * which should be good enough for our purposes here
911    * FIXME: maybe add this to gst_value_compare_double() ? */
912   return (fabs (d1 - d2) < 0.0000001);
913 }
914
915 /**
916  * gst_tag_list_is_equal:
917  * @list1: a #GstTagList.
918  * @list2: a #GstTagList.
919  *
920  * Checks if the two given taglists are equal.
921  *
922  * Returns: TRUE if the taglists are equal, otherwise FALSE
923  *
924  * Since: 0.10.36
925  */
926 gboolean
927 gst_tag_list_is_equal (const GstTagList * list1, const GstTagList * list2)
928 {
929   const GstStructure *s1, *s2;
930   gint num_fields1, num_fields2, i;
931
932   g_return_val_if_fail (GST_IS_TAG_LIST (list1), FALSE);
933   g_return_val_if_fail (GST_IS_TAG_LIST (list2), FALSE);
934
935   /* we don't just use gst_structure_is_equal() here so we can add some
936    * tolerance for doubles, though maybe we should just add that to
937    * gst_value_compare_double() as well? */
938   s1 = GST_TAG_LIST_STRUCTURE (list1);
939   s2 = GST_TAG_LIST_STRUCTURE (list2);
940
941   num_fields1 = gst_structure_n_fields (s1);
942   num_fields2 = gst_structure_n_fields (s2);
943
944   if (num_fields1 != num_fields2)
945     return FALSE;
946
947   for (i = 0; i < num_fields1; i++) {
948     const GValue *value1, *value2;
949     const gchar *tag_name;
950
951     tag_name = gst_structure_nth_field_name (s1, i);
952     value1 = gst_structure_get_value (s1, tag_name);
953     value2 = gst_structure_get_value (s2, tag_name);
954
955     if (value2 == NULL)
956       return FALSE;
957
958     if (!gst_tag_list_fields_equal (value1, value2))
959       return FALSE;
960   }
961
962   return TRUE;
963 }
964
965 typedef struct
966 {
967   GstTagList *list;
968   GstTagMergeMode mode;
969 }
970 GstTagCopyData;
971
972 static void
973 gst_tag_list_add_value_internal (GstTagList * tag_list, GstTagMergeMode mode,
974     const gchar * tag, const GValue * value, GstTagInfo * info)
975 {
976   GstStructure *list = GST_TAG_LIST_STRUCTURE (tag_list);
977   const GValue *value2;
978   GQuark tag_quark;
979
980   if (info == NULL) {
981     info = gst_tag_lookup (tag);
982     if (G_UNLIKELY (info == NULL)) {
983       g_warning ("unknown tag '%s'", tag);
984       return;
985     }
986   }
987
988   tag_quark = info->name_quark;
989
990   if (info->merge_func
991       && (value2 = gst_structure_id_get_value (list, tag_quark)) != NULL) {
992     GValue dest = { 0, };
993
994     switch (mode) {
995       case GST_TAG_MERGE_REPLACE_ALL:
996       case GST_TAG_MERGE_REPLACE:
997         gst_structure_id_set_value (list, tag_quark, value);
998         break;
999       case GST_TAG_MERGE_PREPEND:
1000         gst_value_list_merge (&dest, value, value2);
1001         gst_structure_id_set_value (list, tag_quark, &dest);
1002         g_value_unset (&dest);
1003         break;
1004       case GST_TAG_MERGE_APPEND:
1005         gst_value_list_merge (&dest, value2, value);
1006         gst_structure_id_set_value (list, tag_quark, &dest);
1007         g_value_unset (&dest);
1008         break;
1009       case GST_TAG_MERGE_KEEP:
1010       case GST_TAG_MERGE_KEEP_ALL:
1011         break;
1012       default:
1013         g_assert_not_reached ();
1014         break;
1015     }
1016   } else {
1017     switch (mode) {
1018       case GST_TAG_MERGE_APPEND:
1019       case GST_TAG_MERGE_KEEP:
1020         if (gst_structure_id_get_value (list, tag_quark) != NULL)
1021           break;
1022         /* fall through */
1023       case GST_TAG_MERGE_REPLACE_ALL:
1024       case GST_TAG_MERGE_REPLACE:
1025       case GST_TAG_MERGE_PREPEND:
1026         gst_structure_id_set_value (list, tag_quark, value);
1027         break;
1028       case GST_TAG_MERGE_KEEP_ALL:
1029         break;
1030       default:
1031         g_assert_not_reached ();
1032         break;
1033     }
1034   }
1035 }
1036
1037 static gboolean
1038 gst_tag_list_copy_foreach (GQuark tag_quark, const GValue * value,
1039     gpointer user_data)
1040 {
1041   GstTagCopyData *copy = (GstTagCopyData *) user_data;
1042   const gchar *tag;
1043
1044   tag = g_quark_to_string (tag_quark);
1045   gst_tag_list_add_value_internal (copy->list, copy->mode, tag, value, NULL);
1046
1047   return TRUE;
1048 }
1049
1050 /**
1051  * gst_tag_list_insert:
1052  * @into: list to merge into
1053  * @from: list to merge from
1054  * @mode: the mode to use
1055  *
1056  * Inserts the tags of the @from list into the first list using the given mode.
1057  */
1058 void
1059 gst_tag_list_insert (GstTagList * into, const GstTagList * from,
1060     GstTagMergeMode mode)
1061 {
1062   GstTagCopyData data;
1063
1064   g_return_if_fail (GST_IS_TAG_LIST (into));
1065   g_return_if_fail (gst_tag_list_is_writable (into));
1066   g_return_if_fail (GST_IS_TAG_LIST (from));
1067   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
1068
1069   data.list = into;
1070   data.mode = mode;
1071   if (mode == GST_TAG_MERGE_REPLACE_ALL) {
1072     gst_structure_remove_all_fields (GST_TAG_LIST_STRUCTURE (into));
1073   }
1074   gst_structure_foreach (GST_TAG_LIST_STRUCTURE (from),
1075       gst_tag_list_copy_foreach, &data);
1076 }
1077
1078 /**
1079  * gst_tag_list_merge:
1080  * @list1: first list to merge
1081  * @list2: second list to merge
1082  * @mode: the mode to use
1083  *
1084  * Merges the two given lists into a new list. If one of the lists is NULL, a
1085  * copy of the other is returned. If both lists are NULL, NULL is returned.
1086  *
1087  * Free-function: gst_tag_list_unref
1088  *
1089  * Returns: (transfer full): the new list
1090  */
1091 GstTagList *
1092 gst_tag_list_merge (const GstTagList * list1, const GstTagList * list2,
1093     GstTagMergeMode mode)
1094 {
1095   GstTagList *list1_cp;
1096   const GstTagList *list2_cp;
1097
1098   g_return_val_if_fail (list1 == NULL || GST_IS_TAG_LIST (list1), NULL);
1099   g_return_val_if_fail (list2 == NULL || GST_IS_TAG_LIST (list2), NULL);
1100   g_return_val_if_fail (GST_TAG_MODE_IS_VALID (mode), NULL);
1101
1102   /* nothing to merge */
1103   if (!list1 && !list2) {
1104     return NULL;
1105   }
1106
1107   /* create empty list, we need to do this to correctly handling merge modes */
1108   list1_cp = (list1) ? gst_tag_list_copy (list1) : gst_tag_list_new_empty ();
1109   list2_cp = (list2) ? list2 : gst_tag_list_new_empty ();
1110
1111   gst_tag_list_insert (list1_cp, list2_cp, mode);
1112
1113   if (!list2)
1114     gst_tag_list_unref ((GstTagList *) list2_cp);
1115
1116   return list1_cp;
1117 }
1118
1119 /**
1120  * gst_tag_list_get_tag_size:
1121  * @list: a taglist
1122  * @tag: the tag to query
1123  *
1124  * Checks how many value are stored in this tag list for the given tag.
1125  *
1126  * Returns: The number of tags stored
1127  */
1128 guint
1129 gst_tag_list_get_tag_size (const GstTagList * list, const gchar * tag)
1130 {
1131   const GValue *value;
1132
1133   g_return_val_if_fail (GST_IS_TAG_LIST (list), 0);
1134
1135   value = gst_structure_get_value (GST_TAG_LIST_STRUCTURE (list), tag);
1136   if (value == NULL)
1137     return 0;
1138   if (G_VALUE_TYPE (value) != GST_TYPE_LIST)
1139     return 1;
1140
1141   return gst_value_list_get_size (value);
1142 }
1143
1144 /**
1145  * gst_tag_list_add:
1146  * @list: list to set tags in
1147  * @mode: the mode to use
1148  * @tag: tag
1149  * @...: NULL-terminated list of values to set
1150  *
1151  * Sets the values for the given tags using the specified mode.
1152  */
1153 void
1154 gst_tag_list_add (GstTagList * list, GstTagMergeMode mode, const gchar * tag,
1155     ...)
1156 {
1157   va_list args;
1158
1159   g_return_if_fail (GST_IS_TAG_LIST (list));
1160   g_return_if_fail (gst_tag_list_is_writable (list));
1161   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
1162   g_return_if_fail (tag != NULL);
1163
1164   va_start (args, tag);
1165   gst_tag_list_add_valist (list, mode, tag, args);
1166   va_end (args);
1167 }
1168
1169 /**
1170  * gst_tag_list_add_values:
1171  * @list: list to set tags in
1172  * @mode: the mode to use
1173  * @tag: tag
1174  * @...: GValues to set
1175  *
1176  * Sets the GValues for the given tags using the specified mode.
1177  */
1178 void
1179 gst_tag_list_add_values (GstTagList * list, GstTagMergeMode mode,
1180     const gchar * tag, ...)
1181 {
1182   va_list args;
1183
1184   g_return_if_fail (GST_IS_TAG_LIST (list));
1185   g_return_if_fail (gst_tag_list_is_writable (list));
1186   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
1187   g_return_if_fail (tag != NULL);
1188
1189   va_start (args, tag);
1190   gst_tag_list_add_valist_values (list, mode, tag, args);
1191   va_end (args);
1192 }
1193
1194 /**
1195  * gst_tag_list_add_valist:
1196  * @list: list to set tags in
1197  * @mode: the mode to use
1198  * @tag: tag
1199  * @var_args: tag / value pairs to set
1200  *
1201  * Sets the values for the given tags using the specified mode.
1202  */
1203 void
1204 gst_tag_list_add_valist (GstTagList * list, GstTagMergeMode mode,
1205     const gchar * tag, va_list var_args)
1206 {
1207   GstTagInfo *info;
1208   gchar *error = NULL;
1209
1210   g_return_if_fail (GST_IS_TAG_LIST (list));
1211   g_return_if_fail (gst_tag_list_is_writable (list));
1212   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
1213   g_return_if_fail (tag != NULL);
1214
1215   if (mode == GST_TAG_MERGE_REPLACE_ALL) {
1216     gst_structure_remove_all_fields (GST_TAG_LIST_STRUCTURE (list));
1217   }
1218
1219   while (tag != NULL) {
1220     GValue value = { 0, };
1221
1222     info = gst_tag_lookup (tag);
1223     if (G_UNLIKELY (info == NULL)) {
1224       g_warning ("unknown tag '%s'", tag);
1225       return;
1226     }
1227     G_VALUE_COLLECT_INIT (&value, info->type, var_args, 0, &error);
1228     if (error) {
1229       g_warning ("%s: %s", G_STRLOC, error);
1230       g_free (error);
1231       /* we purposely leak the value here, it might not be
1232        * in a sane state if an error condition occoured
1233        */
1234       return;
1235     }
1236     gst_tag_list_add_value_internal (list, mode, tag, &value, info);
1237     g_value_unset (&value);
1238     tag = va_arg (var_args, gchar *);
1239   }
1240 }
1241
1242 /**
1243  * gst_tag_list_add_valist_values:
1244  * @list: list to set tags in
1245  * @mode: the mode to use
1246  * @tag: tag
1247  * @var_args: tag / GValue pairs to set
1248  *
1249  * Sets the GValues for the given tags using the specified mode.
1250  */
1251 void
1252 gst_tag_list_add_valist_values (GstTagList * list, GstTagMergeMode mode,
1253     const gchar * tag, va_list var_args)
1254 {
1255   g_return_if_fail (GST_IS_TAG_LIST (list));
1256   g_return_if_fail (gst_tag_list_is_writable (list));
1257   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
1258   g_return_if_fail (tag != NULL);
1259
1260   if (mode == GST_TAG_MERGE_REPLACE_ALL) {
1261     gst_structure_remove_all_fields (GST_TAG_LIST_STRUCTURE (list));
1262   }
1263
1264   while (tag != NULL) {
1265     GstTagInfo *info;
1266
1267     info = gst_tag_lookup (tag);
1268     if (G_UNLIKELY (info == NULL)) {
1269       g_warning ("unknown tag '%s'", tag);
1270       return;
1271     }
1272     gst_tag_list_add_value_internal (list, mode, tag, va_arg (var_args,
1273             GValue *), info);
1274     tag = va_arg (var_args, gchar *);
1275   }
1276 }
1277
1278 /**
1279  * gst_tag_list_add_value:
1280  * @list: list to set tags in
1281  * @mode: the mode to use
1282  * @tag: tag
1283  * @value: GValue for this tag
1284  *
1285  * Sets the GValue for a given tag using the specified mode.
1286  *
1287  * Since: 0.10.24
1288  */
1289 void
1290 gst_tag_list_add_value (GstTagList * list, GstTagMergeMode mode,
1291     const gchar * tag, const GValue * value)
1292 {
1293   g_return_if_fail (GST_IS_TAG_LIST (list));
1294   g_return_if_fail (gst_tag_list_is_writable (list));
1295   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
1296   g_return_if_fail (tag != NULL);
1297
1298   gst_tag_list_add_value_internal (list, mode, tag, value, NULL);
1299 }
1300
1301 /**
1302  * gst_tag_list_remove_tag:
1303  * @list: list to remove tag from
1304  * @tag: tag to remove
1305  *
1306  * Removes the given tag from the taglist.
1307  */
1308 void
1309 gst_tag_list_remove_tag (GstTagList * list, const gchar * tag)
1310 {
1311   g_return_if_fail (GST_IS_TAG_LIST (list));
1312   g_return_if_fail (tag != NULL);
1313
1314   gst_structure_remove_field (GST_TAG_LIST_STRUCTURE (list), tag);
1315 }
1316
1317 typedef struct
1318 {
1319   GstTagForeachFunc func;
1320   const GstTagList *tag_list;
1321   gpointer data;
1322 }
1323 TagForeachData;
1324
1325 static int
1326 structure_foreach_wrapper (GQuark field_id, const GValue * value,
1327     gpointer user_data)
1328 {
1329   TagForeachData *data = (TagForeachData *) user_data;
1330
1331   data->func (data->tag_list, g_quark_to_string (field_id), data->data);
1332   return TRUE;
1333 }
1334
1335 /**
1336  * gst_tag_list_foreach:
1337  * @list: list to iterate over
1338  * @func: (scope call): function to be called for each tag
1339  * @user_data: (closure): user specified data
1340  *
1341  * Calls the given function for each tag inside the tag list. Note that if there
1342  * is no tag, the function won't be called at all.
1343  */
1344 void
1345 gst_tag_list_foreach (const GstTagList * list, GstTagForeachFunc func,
1346     gpointer user_data)
1347 {
1348   TagForeachData data;
1349
1350   g_return_if_fail (GST_IS_TAG_LIST (list));
1351   g_return_if_fail (func != NULL);
1352
1353   data.func = func;
1354   data.tag_list = list;
1355   data.data = user_data;
1356   gst_structure_foreach (GST_TAG_LIST_STRUCTURE (list),
1357       structure_foreach_wrapper, &data);
1358 }
1359
1360 /**
1361  * gst_tag_list_get_value_index:
1362  * @list: a #GstTagList
1363  * @tag: tag to read out
1364  * @index: number of entry to read out
1365  *
1366  * Gets the value that is at the given index for the given tag in the given
1367  * list.
1368  *
1369  * Returns: (transfer none): The GValue for the specified entry or NULL if the
1370  *          tag wasn't available or the tag doesn't have as many entries
1371  */
1372 const GValue *
1373 gst_tag_list_get_value_index (const GstTagList * list, const gchar * tag,
1374     guint index)
1375 {
1376   const GValue *value;
1377
1378   g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
1379   g_return_val_if_fail (tag != NULL, NULL);
1380
1381   value = gst_structure_get_value (GST_TAG_LIST_STRUCTURE (list), tag);
1382   if (value == NULL)
1383     return NULL;
1384
1385   if (GST_VALUE_HOLDS_LIST (value)) {
1386     if (index >= gst_value_list_get_size (value))
1387       return NULL;
1388     return gst_value_list_get_value (value, index);
1389   } else {
1390     if (index > 0)
1391       return NULL;
1392     return value;
1393   }
1394 }
1395
1396 /**
1397  * gst_tag_list_copy_value:
1398  * @dest: (out caller-allocates): uninitialized #GValue to copy into
1399  * @list: list to get the tag from
1400  * @tag: tag to read out
1401  *
1402  * Copies the contents for the given tag into the value,
1403  * merging multiple values into one if multiple values are associated
1404  * with the tag.
1405  * You must g_value_unset() the value after use.
1406  *
1407  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1408  *          given list.
1409  */
1410 gboolean
1411 gst_tag_list_copy_value (GValue * dest, const GstTagList * list,
1412     const gchar * tag)
1413 {
1414   const GValue *src;
1415
1416   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
1417   g_return_val_if_fail (tag != NULL, FALSE);
1418   g_return_val_if_fail (dest != NULL, FALSE);
1419   g_return_val_if_fail (G_VALUE_TYPE (dest) == 0, FALSE);
1420
1421   src = gst_structure_get_value (GST_TAG_LIST_STRUCTURE (list), tag);
1422   if (!src)
1423     return FALSE;
1424
1425   if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
1426     GstTagInfo *info = gst_tag_lookup (tag);
1427
1428     if (!info)
1429       return FALSE;
1430
1431     /* must be there or lists aren't allowed */
1432     g_assert (info->merge_func);
1433     info->merge_func (dest, src);
1434   } else {
1435     g_value_init (dest, G_VALUE_TYPE (src));
1436     g_value_copy (src, dest);
1437   }
1438   return TRUE;
1439 }
1440
1441 /* FIXME 0.11: this whole merge function business is overdesigned, and the
1442  * _get_foo() API is misleading as well - how many application developers will
1443  * expect gst_tag_list_get_string (list, GST_TAG_ARTIST, &val) might return a
1444  * string with multiple comma-separated artists? _get_foo() should just be
1445  * a convenience wrapper around _get_foo_index (list, tag, 0, &val),
1446  * supplemented by a special _tag_list_get_string_merged() function if needed
1447  * (unless someone can actually think of real use cases where the merge
1448  * function is not 'use first' for non-strings and merge for strings) */
1449
1450 /***** evil macros to get all the gst_tag_list_get_*() functions right *****/
1451
1452 #define TAG_MERGE_FUNCS(name,type,ret)                                  \
1453 gboolean                                                                \
1454 gst_tag_list_get_ ## name (const GstTagList *list, const gchar *tag,    \
1455                            type *value)                                 \
1456 {                                                                       \
1457   GValue v = { 0, };                                                    \
1458                                                                         \
1459   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);                 \
1460   g_return_val_if_fail (tag != NULL, FALSE);                            \
1461   g_return_val_if_fail (value != NULL, FALSE);                          \
1462                                                                         \
1463   if (!gst_tag_list_copy_value (&v, list, tag))                         \
1464       return FALSE;                                                     \
1465   *value = COPY_FUNC (g_value_get_ ## name (&v));                       \
1466   g_value_unset (&v);                                                   \
1467   return ret;                                                           \
1468 }                                                                       \
1469                                                                         \
1470 gboolean                                                                \
1471 gst_tag_list_get_ ## name ## _index (const GstTagList *list,            \
1472                                      const gchar *tag,                  \
1473                                      guint index, type *value)          \
1474 {                                                                       \
1475   const GValue *v;                                                      \
1476                                                                         \
1477   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);                 \
1478   g_return_val_if_fail (tag != NULL, FALSE);                            \
1479   g_return_val_if_fail (value != NULL, FALSE);                          \
1480                                                                         \
1481   if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL)    \
1482       return FALSE;                                                     \
1483   *value = COPY_FUNC (g_value_get_ ## name (v));                        \
1484   return ret;                                                           \
1485 }
1486
1487 #define COPY_FUNC /**/
1488 /**
1489  * gst_tag_list_get_boolean:
1490  * @list: a #GstTagList to get the tag from
1491  * @tag: tag to read out
1492  * @value: (out): location for the result
1493  *
1494  * Copies the contents for the given tag into the value, merging multiple values
1495  * into one if multiple values are associated with the tag.
1496  *
1497  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1498  *              given list.
1499  */
1500 /**
1501  * gst_tag_list_get_boolean_index:
1502  * @list: a #GstTagList to get the tag from
1503  * @tag: tag to read out
1504  * @index: number of entry to read out
1505  * @value: (out): location for the result
1506  *
1507  * Gets the value that is at the given index for the given tag in the given
1508  * list.
1509  *
1510  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1511  *              given list.
1512  */
1513 TAG_MERGE_FUNCS (boolean, gboolean, TRUE);
1514 /**
1515  * gst_tag_list_get_int:
1516  * @list: a #GstTagList to get the tag from
1517  * @tag: tag to read out
1518  * @value: (out): location for the result
1519  *
1520  * Copies the contents for the given tag into the value, merging multiple values
1521  * into one if multiple values are associated with the tag.
1522  *
1523  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1524  *              given list.
1525  */
1526 /**
1527  * gst_tag_list_get_int_index:
1528  * @list: a #GstTagList to get the tag from
1529  * @tag: tag to read out
1530  * @index: number of entry to read out
1531  * @value: (out): location for the result
1532  *
1533  * Gets the value that is at the given index for the given tag in the given
1534  * list.
1535  *
1536  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1537  *              given list.
1538  */
1539 TAG_MERGE_FUNCS (int, gint, TRUE);
1540 /**
1541  * gst_tag_list_get_uint:
1542  * @list: a #GstTagList to get the tag from
1543  * @tag: tag to read out
1544  * @value: (out): location for the result
1545  *
1546  * Copies the contents for the given tag into the value, merging multiple values
1547  * into one if multiple values are associated with the tag.
1548  *
1549  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1550  *              given list.
1551  */
1552 /**
1553  * gst_tag_list_get_uint_index:
1554  * @list: a #GstTagList to get the tag from
1555  * @tag: tag to read out
1556  * @index: number of entry to read out
1557  * @value: (out): location for the result
1558  *
1559  * Gets the value that is at the given index for the given tag in the given
1560  * list.
1561  *
1562  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1563  *              given list.
1564  */
1565 TAG_MERGE_FUNCS (uint, guint, TRUE);
1566 /**
1567  * gst_tag_list_get_int64_index:
1568  * @list: a #GstTagList to get the tag from
1569  * @tag: tag to read out
1570  * @index: number of entry to read out
1571  * @value: (out): location for the result
1572  *
1573  * Gets the value that is at the given index for the given tag in the given
1574  * list.
1575  *
1576  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1577  *              given list.
1578  */
1579 TAG_MERGE_FUNCS (int64, gint64, TRUE);
1580 /**
1581  * gst_tag_list_get_uint64:
1582  * @list: a #GstTagList to get the tag from
1583  * @tag: tag to read out
1584  * @value: (out): location for the result
1585  *
1586  * Copies the contents for the given tag into the value, merging multiple values
1587  * into one if multiple values are associated with the tag.
1588  *
1589  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1590  *              given list.
1591  */
1592 /**
1593  * gst_tag_list_get_uint64_index:
1594  * @list: a #GstTagList to get the tag from
1595  * @tag: tag to read out
1596  * @index: number of entry to read out
1597  * @value: (out): location for the result
1598  *
1599  * Gets the value that is at the given index for the given tag in the given
1600  * list.
1601  *
1602  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1603  *              given list.
1604  */
1605 TAG_MERGE_FUNCS (uint64, guint64, TRUE);
1606 /**
1607  * gst_tag_list_get_float:
1608  * @list: a #GstTagList to get the tag from
1609  * @tag: tag to read out
1610  * @value: (out): location for the result
1611  *
1612  * Copies the contents for the given tag into the value, merging multiple values
1613  * into one if multiple values are associated with the tag.
1614  *
1615  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1616  *              given list.
1617  */
1618 /**
1619  * gst_tag_list_get_float_index:
1620  * @list: a #GstTagList to get the tag from
1621  * @tag: tag to read out
1622  * @index: number of entry to read out
1623  * @value: (out): location for the result
1624  *
1625  * Gets the value that is at the given index for the given tag in the given
1626  * list.
1627  *
1628  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1629  *              given list.
1630  */
1631 TAG_MERGE_FUNCS (float, gfloat, TRUE);
1632 /**
1633  * gst_tag_list_get_double:
1634  * @list: a #GstTagList to get the tag from
1635  * @tag: tag to read out
1636  * @value: (out): location for the result
1637  *
1638  * Copies the contents for the given tag into the value, merging multiple values
1639  * into one if multiple values are associated with the tag.
1640  *
1641  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1642  *              given list.
1643  */
1644 /**
1645  * gst_tag_list_get_double_index:
1646  * @list: a #GstTagList to get the tag from
1647  * @tag: tag to read out
1648  * @index: number of entry to read out
1649  * @value: (out): location for the result
1650  *
1651  * Gets the value that is at the given index for the given tag in the given
1652  * list.
1653  *
1654  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1655  *              given list.
1656  */
1657 TAG_MERGE_FUNCS (double, gdouble, TRUE);
1658 /**
1659  * gst_tag_list_get_pointer:
1660  * @list: a #GstTagList to get the tag from
1661  * @tag: tag to read out
1662  * @value: (out) (transfer none): location for the result
1663  *
1664  * Copies the contents for the given tag into the value, merging multiple values
1665  * into one if multiple values are associated with the tag.
1666  *
1667  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1668  *              given list.
1669  */
1670 /**
1671  * gst_tag_list_get_pointer_index:
1672  * @list: a #GstTagList to get the tag from
1673  * @tag: tag to read out
1674  * @index: number of entry to read out
1675  * @value: (out) (transfer none): location for the result
1676  *
1677  * Gets the value that is at the given index for the given tag in the given
1678  * list.
1679  *
1680  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1681  *              given list.
1682  */
1683 TAG_MERGE_FUNCS (pointer, gpointer, (*value != NULL));
1684
1685 static inline gchar *
1686 _gst_strdup0 (const gchar * s)
1687 {
1688   if (s == NULL || *s == '\0')
1689     return NULL;
1690
1691   return g_strdup (s);
1692 }
1693
1694 #undef COPY_FUNC
1695 #define COPY_FUNC _gst_strdup0
1696
1697 /**
1698  * gst_tag_list_get_string:
1699  * @list: a #GstTagList to get the tag from
1700  * @tag: tag to read out
1701  * @value: (out callee-allocates) (transfer full): location for the result
1702  *
1703  * Copies the contents for the given tag into the value, possibly merging
1704  * multiple values into one if multiple values are associated with the tag.
1705  *
1706  * Use gst_tag_list_get_string_index (list, tag, 0, value) if you want
1707  * to retrieve the first string associated with this tag unmodified.
1708  *
1709  * The resulting string in @value will be in UTF-8 encoding and should be
1710  * freed by the caller using g_free when no longer needed. Since 0.10.24 the
1711  * returned string is also guaranteed to be non-NULL and non-empty.
1712  *
1713  * Free-function: g_free
1714  *
1715  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1716  *              given list.
1717  */
1718 /**
1719  * gst_tag_list_get_string_index:
1720  * @list: a #GstTagList to get the tag from
1721  * @tag: tag to read out
1722  * @index: number of entry to read out
1723  * @value: (out callee-allocates) (transfer full): location for the result
1724  *
1725  * Gets the value that is at the given index for the given tag in the given
1726  * list.
1727  *
1728  * The resulting string in @value will be in UTF-8 encoding and should be
1729  * freed by the caller using g_free when no longer needed. Since 0.10.24 the
1730  * returned string is also guaranteed to be non-NULL and non-empty.
1731  *
1732  * Free-function: g_free
1733  *
1734  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1735  *              given list.
1736  */
1737 TAG_MERGE_FUNCS (string, gchar *, (*value != NULL));
1738
1739 /*
1740  *FIXME 0.11: Instead of _peek (non-copy) and _get (copy), we could have
1741  *            _get (non-copy) and _dup (copy) for strings, seems more
1742  *            widely used
1743  */
1744 /**
1745  * gst_tag_list_peek_string_index:
1746  * @list: a #GstTagList to get the tag from
1747  * @tag: tag to read out
1748  * @index: number of entry to read out
1749  * @value: (out) (transfer none): location for the result
1750  *
1751  * Peeks at the value that is at the given index for the given tag in the given
1752  * list.
1753  *
1754  * The resulting string in @value will be in UTF-8 encoding and doesn't need
1755  * to be freed by the caller. The returned string is also guaranteed to
1756  * be non-NULL and non-empty.
1757  *
1758  * Returns: TRUE, if a value was set, FALSE if the tag didn't exist in the
1759  *              given list.
1760  */
1761 gboolean
1762 gst_tag_list_peek_string_index (const GstTagList * list,
1763     const gchar * tag, guint index, const gchar ** value)
1764 {
1765   const GValue *v;
1766
1767   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
1768   g_return_val_if_fail (tag != NULL, FALSE);
1769   g_return_val_if_fail (value != NULL, FALSE);
1770
1771   if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL)
1772     return FALSE;
1773   *value = g_value_get_string (v);
1774   return *value != NULL && **value != '\0';
1775 }
1776
1777 /**
1778  * gst_tag_list_get_date:
1779  * @list: a #GstTagList to get the tag from
1780  * @tag: tag to read out
1781  * @value: (out callee-allocates) (transfer full): address of a GDate pointer
1782  *     variable to store the result into
1783  *
1784  * Copies the first date for the given tag in the taglist into the variable
1785  * pointed to by @value. Free the date with g_date_free() when it is no longer
1786  * needed.
1787  *
1788  * Free-function: g_date_free
1789  *
1790  * Returns: TRUE, if a date was copied, FALSE if the tag didn't exist in the
1791  *              given list or if it was #NULL.
1792  */
1793 gboolean
1794 gst_tag_list_get_date (const GstTagList * list, const gchar * tag,
1795     GDate ** value)
1796 {
1797   GValue v = { 0, };
1798
1799   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
1800   g_return_val_if_fail (tag != NULL, FALSE);
1801   g_return_val_if_fail (value != NULL, FALSE);
1802
1803   if (!gst_tag_list_copy_value (&v, list, tag))
1804     return FALSE;
1805   *value = (GDate *) g_value_dup_boxed (&v);
1806   g_value_unset (&v);
1807   return (*value != NULL);
1808 }
1809
1810 /**
1811  * gst_tag_list_get_date_index:
1812  * @list: a #GstTagList to get the tag from
1813  * @tag: tag to read out
1814  * @index: number of entry to read out
1815  * @value: (out callee-allocates) (transfer full): location for the result
1816  *
1817  * Gets the date that is at the given index for the given tag in the given
1818  * list and copies it into the variable pointed to by @value. Free the date
1819  * with g_date_free() when it is no longer needed.
1820  *
1821  * Free-function: g_date_free
1822  *
1823  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1824  *              given list or if it was #NULL.
1825  */
1826 gboolean
1827 gst_tag_list_get_date_index (const GstTagList * list,
1828     const gchar * tag, guint index, GDate ** value)
1829 {
1830   const GValue *v;
1831
1832   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
1833   g_return_val_if_fail (tag != NULL, FALSE);
1834   g_return_val_if_fail (value != NULL, FALSE);
1835
1836   if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL)
1837     return FALSE;
1838   *value = (GDate *) g_value_dup_boxed (v);
1839   return (*value != NULL);
1840 }
1841
1842 /**
1843  * gst_tag_list_get_date_time:
1844  * @list: a #GstTagList to get the tag from
1845  * @tag: tag to read out
1846  * @value: (out callee-allocates) (transfer full): address of a #GstDateTime
1847  *     pointer variable to store the result into
1848  *
1849  * Copies the first datetime for the given tag in the taglist into the variable
1850  * pointed to by @value. Unref the date with gst_date_time_unref() when
1851  * it is no longer needed.
1852  *
1853  * Free-function: gst_date_time_unref
1854  *
1855  * Returns: TRUE, if a datetime was copied, FALSE if the tag didn't exist in
1856  *              thegiven list or if it was #NULL.
1857  *
1858  * Since: 0.10.31
1859  */
1860 gboolean
1861 gst_tag_list_get_date_time (const GstTagList * list, const gchar * tag,
1862     GstDateTime ** value)
1863 {
1864   GValue v = { 0, };
1865
1866   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
1867   g_return_val_if_fail (tag != NULL, FALSE);
1868   g_return_val_if_fail (value != NULL, FALSE);
1869
1870   if (!gst_tag_list_copy_value (&v, list, tag))
1871     return FALSE;
1872
1873   g_return_val_if_fail (GST_VALUE_HOLDS_DATE_TIME (&v), FALSE);
1874
1875   *value = (GstDateTime *) g_value_dup_boxed (&v);
1876   g_value_unset (&v);
1877   return (*value != NULL);
1878 }
1879
1880 /**
1881  * gst_tag_list_get_date_time_index:
1882  * @list: a #GstTagList to get the tag from
1883  * @tag: tag to read out
1884  * @index: number of entry to read out
1885  * @value: (out callee-allocates) (transfer full): location for the result
1886  *
1887  * Gets the datetime that is at the given index for the given tag in the given
1888  * list and copies it into the variable pointed to by @value. Unref the datetime
1889  * with gst_date_time_unref() when it is no longer needed.
1890  *
1891  * Free-function: gst_date_time_unref
1892  *
1893  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the
1894  *              given list or if it was #NULL.
1895  *
1896  * Since: 0.10.31
1897  */
1898 gboolean
1899 gst_tag_list_get_date_time_index (const GstTagList * list,
1900     const gchar * tag, guint index, GstDateTime ** value)
1901 {
1902   const GValue *v;
1903
1904   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
1905   g_return_val_if_fail (tag != NULL, FALSE);
1906   g_return_val_if_fail (value != NULL, FALSE);
1907
1908   if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL)
1909     return FALSE;
1910   *value = (GstDateTime *) g_value_dup_boxed (v);
1911   return (*value != NULL);
1912 }
1913
1914 /**
1915  * gst_tag_list_get_buffer:
1916  * @list: a #GstTagList to get the tag from
1917  * @tag: tag to read out
1918  * @value: (out callee-allocates) (transfer full): address of a GstBuffer
1919  *     pointer variable to store the result into
1920  *
1921  * Copies the first buffer for the given tag in the taglist into the variable
1922  * pointed to by @value. Free the buffer with gst_buffer_unref() when it is
1923  * no longer needed.
1924  *
1925  * Free-function: gst_buffer_unref
1926  *
1927  * Returns: TRUE, if a buffer was copied, FALSE if the tag didn't exist in the
1928  *              given list or if it was #NULL.
1929  *
1930  * Since: 0.10.23
1931  */
1932 gboolean
1933 gst_tag_list_get_buffer (const GstTagList * list, const gchar * tag,
1934     GstBuffer ** value)
1935 {
1936   GValue v = { 0, };
1937
1938   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
1939   g_return_val_if_fail (tag != NULL, FALSE);
1940   g_return_val_if_fail (value != NULL, FALSE);
1941
1942   if (!gst_tag_list_copy_value (&v, list, tag))
1943     return FALSE;
1944   *value = g_value_dup_boxed (&v);
1945   g_value_unset (&v);
1946   return (*value != NULL);
1947 }
1948
1949 /**
1950  * gst_tag_list_get_buffer_index:
1951  * @list: a #GstTagList to get the tag from
1952  * @tag: tag to read out
1953  * @index: number of entry to read out
1954  * @value: (out callee-allocates) (transfer full): address of a GstBuffer
1955  *     pointer variable to store the result into
1956  *
1957  * Gets the buffer that is at the given index for the given tag in the given
1958  * list and copies it into the variable pointed to by @value. Free the buffer
1959  * with gst_buffer_unref() when it is no longer needed.
1960  *
1961  * Free-function: gst_buffer_unref
1962  *
1963  * Returns: TRUE, if a buffer was copied, FALSE if the tag didn't exist in the
1964  *              given list or if it was #NULL.
1965  *
1966  * Since: 0.10.23
1967  */
1968 gboolean
1969 gst_tag_list_get_buffer_index (const GstTagList * list,
1970     const gchar * tag, guint index, GstBuffer ** value)
1971 {
1972   const GValue *v;
1973
1974   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
1975   g_return_val_if_fail (tag != NULL, FALSE);
1976   g_return_val_if_fail (value != NULL, FALSE);
1977
1978   if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL)
1979     return FALSE;
1980   *value = g_value_dup_boxed (v);
1981   return (*value != NULL);
1982 }