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