Add replaygain tag
[platform/upstream/gstreamer.git] / gst / gsttag.c
1 /* GStreamer
2  * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
3  *
4  * gsttag.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 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25
26 #include "gst_private.h"
27 #include "gst-i18n-lib.h"
28 #include "gsttag.h"
29 #include "gstinfo.h"
30 #include "gstvalue.h"
31
32 #include <gobject/gvaluecollector.h>
33 #include <string.h>
34
35 #define GST_TAG_IS_VALID(tag)           (gst_tag_get_info (tag) != NULL)
36
37 typedef struct {
38   GType                 type;           /* type the data is in */
39
40   gchar *               nick;           /* translated name */
41   gchar *               blurb;          /* translated description of type */
42
43   GstTagMergeFunc       merge_func;     /* functions to merge the values */
44 } GstTagInfo;
45
46 #define TAGLIST "taglist"
47 static GQuark gst_tag_list_quark;
48 static GMutex *__tag_mutex;
49 static GHashTable *__tags;
50 #define TAG_LOCK g_mutex_lock (__tag_mutex)
51 #define TAG_UNLOCK g_mutex_unlock (__tag_mutex)
52
53 void
54 _gst_tag_initialize (void)
55 {
56   gst_tag_list_quark = g_quark_from_static_string (TAGLIST);
57   __tag_mutex = g_mutex_new ();
58   __tags = g_hash_table_new (g_direct_hash, g_direct_equal);
59   gst_tag_register (GST_TAG_TITLE,            
60                     G_TYPE_STRING,
61                     _("title"),
62                     _("commonly used title"),
63                     gst_tag_merge_strings_with_comma);
64   gst_tag_register (GST_TAG_ARTIST,
65                     G_TYPE_STRING,
66                     _("artist"),
67                     _("person(s) responsible for the recording"),
68                     gst_tag_merge_strings_with_comma);
69   gst_tag_register (GST_TAG_ALBUM,
70                     G_TYPE_STRING,
71                     _("album"),
72                     _("album containing this data"),
73                     gst_tag_merge_strings_with_comma);
74   gst_tag_register (GST_TAG_DATE,
75                     G_TYPE_UINT, /* FIXME: own data type for dates? */
76                     _("date"),
77                     _("date the data was created (in Julian calendar days)"),
78                     NULL);
79   gst_tag_register (GST_TAG_GENRE,
80                     G_TYPE_STRING,
81                     _("genre"), 
82                     _("genre this data belongs to"),
83                     gst_tag_merge_strings_with_comma);
84   gst_tag_register (GST_TAG_COMMENT,
85                     G_TYPE_STRING,
86                     _("comment"),
87                     _("free text commenting the data"),
88                     gst_tag_merge_strings_with_comma);
89   gst_tag_register (GST_TAG_TRACK_NUMBER,
90                     G_TYPE_UINT,
91                     _("track number"),
92                     _("track number inside a collection"),
93                     gst_tag_merge_use_first);
94   gst_tag_register (GST_TAG_TRACK_COUNT,
95                     G_TYPE_UINT,
96                     _("track count"),
97                     _("count of tracks inside collection this track belongs to"), 
98                     gst_tag_merge_use_first);
99   gst_tag_register (GST_TAG_LOCATION,
100                     G_TYPE_STRING,
101                     _("location"),
102                     _("original location of file as a URI"),
103                     gst_tag_merge_strings_with_comma);
104   gst_tag_register (GST_TAG_DESCRIPTION,
105                     G_TYPE_STRING,
106                     _("description"),
107                     _("short text describing the content of the data"),
108                     gst_tag_merge_strings_with_comma);
109   gst_tag_register (GST_TAG_VERSION,
110                     G_TYPE_STRING,
111                     _("version"),
112                     _("version of this data"),
113                     NULL);
114   gst_tag_register (GST_TAG_ISRC,
115                     G_TYPE_STRING,
116                     _("ISRC"),
117                     _("International Standard Recording Code - see http://www.ifpi.org/isrc/"),
118                     NULL);
119   gst_tag_register (GST_TAG_ORGANIZATION,
120                     G_TYPE_STRING,
121                     _("organization"),
122                     _("organization"), /* FIXME */
123                     gst_tag_merge_strings_with_comma);
124   gst_tag_register (GST_TAG_COPYRIGHT,
125                     G_TYPE_STRING,
126                     _("copyright"),
127                     _("copyright notice of the data"),
128                     NULL);
129   gst_tag_register (GST_TAG_CONTACT,
130                     G_TYPE_STRING,
131                     _("contact"),
132                     _("contact information"),
133                     gst_tag_merge_strings_with_comma);
134   gst_tag_register (GST_TAG_LICENSE,    
135                     G_TYPE_STRING,
136                     _("license"),
137                     _("license of data"),
138                     NULL);
139   gst_tag_register (GST_TAG_PERFORMER,
140                     G_TYPE_STRING,
141                     _("performer"),
142                     _("person(s) performing"),
143                     gst_tag_merge_strings_with_comma);
144   gst_tag_register (GST_TAG_DURATION,
145                     G_TYPE_UINT64,
146                     _("duration"),
147                     _("length in GStreamer time units (nanoseconds)"),
148                     NULL);
149   gst_tag_register (GST_TAG_CODEC,
150                     G_TYPE_STRING,
151                     _("codec"),
152                     _("codec the data is stored in"),
153                     gst_tag_merge_strings_with_comma);
154   gst_tag_register (GST_TAG_MINIMUM_BITRATE,
155                     G_TYPE_UINT,
156                     _("minimum bitrate"),
157                     _("minimum bitrate in bits/s"),
158                     NULL);
159   gst_tag_register (GST_TAG_BITRATE,
160                     G_TYPE_UINT,
161                     _("bitrate"),
162                     _("exact or average bitrate in bits/s"),
163                     NULL);
164   gst_tag_register (GST_TAG_MAXIMUM_BITRATE,
165                     G_TYPE_UINT,
166                     _("maximum bitrate"),
167                     _("maximum bitrate in bits/s"),
168                     NULL);
169   gst_tag_register (GST_TAG_TRACK_GAIN,
170                     G_TYPE_DOUBLE,
171                     _("replaygain track gain"),
172                     _("track gain in db"),
173                     NULL);
174   gst_tag_register (GST_TAG_TRACK_PEAK,
175                     G_TYPE_DOUBLE,
176                     _("replaygain track peak"),
177                     _("peak of the track"),
178                     NULL);
179   gst_tag_register (GST_TAG_ALBUM_GAIN,
180                     G_TYPE_DOUBLE,
181                     _("replaygain album gain"),
182                     _("album gain in db"),
183                     NULL);
184   gst_tag_register (GST_TAG_ALBUM_PEAK,
185                     G_TYPE_DOUBLE,
186                     _("replaygain album peak"),
187                     _("peak of the album"),
188                     NULL);
189 }
190 /**
191  * gst_tag_merge_use_first:
192  * @dest: uninitialized GValue to store result in
193  * @src: GValue to copy from
194  *
195  * This is a convenience function for the func argument of gst_tag_register(). 
196  * It creates a copy of the first value from the list.
197  */
198 void
199 gst_tag_merge_use_first (GValue *dest, const GValue *src)
200 {
201   const GValue *ret = gst_value_list_get_value (src, 0);
202
203   g_value_init (dest, G_VALUE_TYPE (ret));
204   g_value_copy (ret, dest);
205 }
206 /**
207  * gst_tag_merge_strings_with_comma:
208  * @dest: uninitialized GValue to store result in
209  * @src: GValue to copy from
210  * 
211  * This is a convenience function for the func argument of gst_tag_register().
212  * It concatenates all given strings using a comma. The tag must be registered
213  * as a G_TYPE_STRING or this function will fail.
214  */
215 void
216 gst_tag_merge_strings_with_comma (GValue *dest, const GValue *src)
217 {
218   GString *str;
219   gint i, count;
220
221   count = gst_value_list_get_size (src);
222   str = g_string_new (g_value_get_string (gst_value_list_get_value (src, 0)));
223   for (i = 1; i < count; i++) {
224     /* seperator between two string */
225     str = g_string_append (str, _(", "));
226     str = g_string_append (str, g_value_get_string (gst_value_list_get_value (src, 1)));
227   }
228
229   g_value_init (dest, G_TYPE_STRING);
230   g_value_set_string_take_ownership (dest, str->str);
231   g_string_free (str, FALSE);
232 }
233 static GstTagInfo *
234 gst_tag_lookup (GQuark entry)
235 {
236   GstTagInfo *ret;
237   
238   TAG_LOCK;
239   ret = g_hash_table_lookup (__tags, GUINT_TO_POINTER (entry));
240   TAG_UNLOCK;
241
242   return ret;
243 }
244 /**
245  * gst_tag_register:
246  * @name: the name or identifier string
247  * @type: the type this data is in
248  * @nick: human-readable name
249  * @blurb: a human-readable description about this tag
250  * @func: function for merging multiple values of this tag
251  *
252  * Registers a new tag type for the use with GStreamer's type system. If a type
253  * with that name is already registered, that one is used.
254  * The old registration may have used a different type however. So don't rely
255  * on youre supplied values.
256  * If you know the type is already registered, use gst_tag_lookup instead.
257  * This function takes ownership of all supplied variables.
258  */
259 void
260 gst_tag_register (gchar *name, GType type, gchar *nick, gchar *blurb,
261                   GstTagMergeFunc func)
262 {
263   GQuark key;
264   GstTagInfo *info;
265
266   g_return_if_fail (name != NULL);
267   g_return_if_fail (nick != NULL);
268   g_return_if_fail (blurb != NULL);
269   g_return_if_fail (type != 0 && type != GST_TYPE_LIST);
270   
271   key = g_quark_from_string (name);
272   info = gst_tag_lookup (key);
273   g_return_if_fail (info == NULL);
274   
275   info = g_new (GstTagInfo, 1);
276   info->type = type;
277   info->nick = nick;
278   info->blurb = blurb;
279   info->merge_func = func;
280     
281   TAG_LOCK;
282   g_hash_table_insert (__tags, GUINT_TO_POINTER (key), info);
283   TAG_UNLOCK;
284 }
285 /**
286  * gst_tag_exists:
287  * @tag: name of the tag
288  *
289  * Checks if the given type is already registered.
290  *
291  * Returns: TRUE if the type is already registered
292  */
293 gboolean
294 gst_tag_exists (const gchar *tag)
295 {
296   g_return_val_if_fail (tag != NULL, FALSE);
297   
298   return gst_tag_lookup (g_quark_from_string (tag)) != NULL;
299 }
300 /**
301  * gst_tag_get_type:
302  * @tag: the tag
303  *
304  * Gets the #GType used for this tag.
305  *
306  * Returns: the #GType of this tag
307  */
308 GType
309 gst_tag_get_type (const gchar *tag)
310 {
311   GstTagInfo *info;
312   
313   g_return_val_if_fail (tag != NULL, 0);
314   info = gst_tag_lookup (g_quark_from_string (tag));
315   g_return_val_if_fail (info != NULL, 0);
316   
317   return info->type;
318 }
319 /**
320  * gst_tag_get_nick
321  * @tag: the tag
322  *
323  * Returns the human-readable name of this tag, You must not change or free 
324  * this string.
325  *
326  * Returns: the human-readable name of this tag
327  */
328 const gchar *
329 gst_tag_get_nick (const gchar *tag)
330 {
331   GstTagInfo *info;
332   
333   g_return_val_if_fail (tag != NULL, NULL);
334   info = gst_tag_lookup (g_quark_from_string (tag));
335   g_return_val_if_fail (info != NULL, NULL);
336   
337   return info->nick;
338 }
339 /**
340  * gst_tag_get_description:
341  * @tag: the tag
342  *
343  * Returns the human-readable description of this tag, You must not change or 
344  * free this string.
345  *
346  * Return the human-readable description of this tag
347  */
348 const gchar *
349 gst_tag_get_description (const gchar *tag)
350 {
351   GstTagInfo *info;
352   
353   g_return_val_if_fail (tag != NULL, NULL);
354   info = gst_tag_lookup (g_quark_from_string (tag));
355   g_return_val_if_fail (info != NULL, NULL);
356   
357   return info->blurb;
358 }
359 /**
360  * gst_tag_list_is_fixed:
361  * @tag: tag to check
362  *
363  * Checks if the given tag is fixed. A fixed tag can only contain one value.
364  * Unfixed tags can contain lists of values.
365  *
366  * Returns: TRUE, if the given tag is fixed.
367  */
368 gboolean
369 gst_tag_is_fixed (const gchar *tag)
370 {
371   GstTagInfo *info;
372   
373   g_return_val_if_fail (tag != NULL, FALSE);
374   info = gst_tag_lookup (g_quark_from_string (tag));
375   g_return_val_if_fail (info != NULL, FALSE);
376   
377   return info->merge_func == NULL;
378 }
379 /**
380  * gst_tag_list_new:
381  *
382  * Creates a new empty GstTagList.
383  *
384  * Returns: An empty tag list
385  */
386 GstTagList *
387 gst_tag_list_new (void)
388 {
389   return GST_TAG_LIST (gst_structure_new (TAGLIST, NULL));
390 }
391 /**
392  * gst_is_tag_list:
393  * @p: Object that might be a taglist
394  *
395  * Checks if the given pointer is a taglist.
396  *
397  * Returns: TRUE, if the given pointer is a taglist
398  */
399 gboolean
400 gst_is_tag_list (gconstpointer p)
401 {
402   g_return_val_if_fail (p != NULL, FALSE); 
403
404   return ((GstStructure *) p)->name == gst_tag_list_quark;
405 }
406 typedef struct {
407   GstStructure *        list;
408   GstTagMergeMode       mode;
409 } GstTagCopyData;
410 static void
411 gst_tag_list_add_value_internal (GstStructure *list, GstTagMergeMode mode, GQuark tag, GValue *value)
412 {
413   GstTagInfo *info = gst_tag_lookup (tag);
414   const GValue *value2;
415   
416   g_assert (info != NULL);
417
418   if (info->merge_func && (value2 = gst_structure_id_get_value (list, tag)) != NULL) {
419     GValue dest = { 0, };
420     switch (mode) {
421       case GST_TAG_MERGE_REPLACE_ALL:
422       case GST_TAG_MERGE_REPLACE:
423         gst_structure_id_set_value (list, tag, value);
424         break;
425       case GST_TAG_MERGE_PREPEND:
426         gst_value_list_concat (&dest, value, value2);
427         gst_structure_id_set_value (list, tag, &dest);
428         g_value_unset (&dest);
429         break;
430       case GST_TAG_MERGE_APPEND:
431         gst_value_list_concat (&dest, value2, value);
432         gst_structure_id_set_value (list, tag, &dest);
433         g_value_unset (&dest);
434         break;
435       case GST_TAG_MERGE_KEEP:
436       case GST_TAG_MERGE_KEEP_ALL:
437         break;
438       default:
439         g_assert_not_reached ();
440         break;
441     }
442   } else {
443     switch (mode) {
444       case GST_TAG_MERGE_APPEND:
445       case GST_TAG_MERGE_KEEP:
446         if (gst_structure_id_get_value (list, tag) != NULL)
447           break;
448         /* fall through */
449       case GST_TAG_MERGE_REPLACE_ALL:
450       case GST_TAG_MERGE_REPLACE:
451       case GST_TAG_MERGE_PREPEND:
452         gst_structure_id_set_value (list, tag, value);
453         break;
454       case GST_TAG_MERGE_KEEP_ALL:
455         break;
456       default:
457         g_assert_not_reached ();
458         break;
459     }
460   }
461 }
462 static gboolean
463 gst_tag_list_copy_foreach (GQuark tag, GValue *value, gpointer user_data)
464 {
465   GstTagCopyData *copy = (GstTagCopyData *) user_data;
466
467   gst_tag_list_add_value_internal (copy->list, copy->mode, tag, value);
468
469   return TRUE;
470 }
471 /**
472  * gst_tag_list_insert:
473  * @into: list to merge into
474  * @from: list to merge from
475  * @mode: the mode to use
476  * 
477  * Inserts the tags of the second list into the first list using the given mode.
478  */
479 void
480 gst_tag_list_insert (GstTagList *into, const GstTagList *from, GstTagMergeMode mode)
481 {
482   GstTagCopyData data;
483   
484   g_return_if_fail (GST_IS_TAG_LIST (into));
485   g_return_if_fail (GST_IS_TAG_LIST (from));
486   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
487
488   data.list = (GstStructure *) into;
489   data.mode = mode;
490   if (mode == GST_TAG_MERGE_REPLACE_ALL) {
491     gst_structure_remove_all_fields (data.list);
492   }
493   gst_structure_foreach ((GstStructure *) from, gst_tag_list_copy_foreach, &data);
494 }
495 /**
496  * gst_tag_list_copy:
497  * @list: list to copy
498  *
499  * Copies a given #GstTagList.
500  *
501  * Returns: copy of the given list
502  */
503 GstTagList *
504 gst_tag_list_copy (const GstTagList *list)
505 {
506   g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
507   
508   return GST_TAG_LIST (gst_structure_copy ((GstStructure *) list));
509 }
510 /**
511  * gst_tag_list_merge:
512  * @list1: first list to merge
513  * @list2: second list to merge
514  * @mode: the mode to use
515  * 
516  * Merges the two given lists into a new list. If one of the lists is NULL, a
517  * copy of the other is returned. If both lists are NULL, NULL is returned.
518  *
519  * Returns: the new list
520  */
521 GstTagList *
522 gst_tag_list_merge (const GstTagList *list1, const GstTagList *list2, GstTagMergeMode mode)
523 {
524   g_return_val_if_fail (list1 == NULL || GST_IS_TAG_LIST (list1), NULL);
525   g_return_val_if_fail (list2 == NULL || GST_IS_TAG_LIST (list2), NULL);
526   g_return_val_if_fail (GST_TAG_MODE_IS_VALID (mode), NULL);
527
528   if (!list1 && !list2) {
529     return NULL;
530   } else if (!list1) {
531     return gst_tag_list_copy (list2);
532   } else if (!list2) {
533     return gst_tag_list_copy (list1);
534   } else {
535     GstTagList *ret;
536
537     ret = gst_tag_list_copy (list1);
538     gst_tag_list_insert (ret, list2, mode);
539     return ret;
540   }
541 }
542 /**
543  * gst_tag_list_free:
544  * @list: the list to free
545  *
546  * Frees the given list and all associated values.
547  */
548 void
549 gst_tag_list_free (GstTagList *list)
550 {
551   g_return_if_fail (GST_IS_TAG_LIST (list));
552   gst_structure_free ((GstStructure *) list);
553 }
554 /**
555  * gst_tag_list_get_tag_size:
556  * @list: a taglist
557  * @tag: the tag to query
558  *
559  * Checks how many value are stored in this tag list for the given tag.
560  *
561  * Returns: The number of tags stored
562  */
563 guint
564 gst_tag_list_get_tag_size (const GstTagList *list, const gchar *tag)
565 {
566   const GValue *value;
567
568   g_return_val_if_fail (GST_IS_TAG_LIST (list), 0);
569
570   value = gst_structure_get_value ((GstStructure *) list, tag);
571   if (value == NULL)
572     return 0;
573   if (G_VALUE_TYPE (value) != GST_TYPE_LIST)
574     return 1;
575
576   return gst_value_list_get_size (value);
577 }
578 /**
579  * gst_tag_list_add:
580  * @list: list to set tags in
581  * @mode: the mode to use
582  * @tag: tag
583  * @...: NULL-terminated list of values to set
584  *
585  * Sets the values for the given tags using the specified mode.
586  */
587 void
588 gst_tag_list_add (GstTagList *list, GstTagMergeMode mode, const gchar *tag, ...)
589 {
590   va_list args;
591
592   g_return_if_fail (GST_IS_TAG_LIST (list));
593   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
594   g_return_if_fail (tag != NULL);
595   
596   va_start (args, tag);
597   gst_tag_list_add_valist (list, mode, tag, args);
598   va_end (args);
599 }
600 /**
601  * gst_tag_list_add_values:
602  * @list: list to set tags in
603  * @mode: the mode to use
604  * @tag: tag
605  * @...: GValues to set
606  *
607  * Sets the GValues for the given tags using the specified mode.
608  */
609 void
610 gst_tag_list_add_values (GstTagList *list, GstTagMergeMode mode, const gchar *tag, ...)
611 {
612   va_list args;
613
614   g_return_if_fail (GST_IS_TAG_LIST (list));
615   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
616   g_return_if_fail (tag != NULL);
617   
618   va_start (args, tag);
619   gst_tag_list_add_valist_values (list, mode, tag, args);
620   va_end (args);
621 }
622 /**
623  * gst_tag_list_add_valist:
624  * @list: list to set tags in
625  * @mode: the mode to use
626  * @tag: tag
627  * @var_args: tag / value pairs to set
628  *
629  * Sets the values for the given tags using the specified mode.
630  */
631 void
632 gst_tag_list_add_valist (GstTagList *list, GstTagMergeMode mode, const gchar *tag, va_list var_args)
633 {
634   GstTagInfo *info;
635   GQuark quark;
636   gchar *error = NULL;
637   
638   g_return_if_fail (GST_IS_TAG_LIST (list));
639   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
640   g_return_if_fail (tag != NULL);
641   
642   while (tag != NULL) {
643     GValue value = { 0, };
644     quark = g_quark_from_string (tag);
645     info = gst_tag_lookup (quark);
646     g_return_if_fail (info != NULL);
647     g_value_init (&value, info->type);
648     G_VALUE_COLLECT (&value, var_args, 0, &error);
649     if (error) {
650       g_warning ("%s: %s", G_STRLOC, error);
651       g_free (error);
652       /* we purposely leak the value here, it might not be
653        * in a sane state if an error condition occoured
654        */
655       return;
656     }
657     gst_tag_list_add_value_internal (list, mode, quark, &value);
658     g_value_unset (&value);
659     tag = va_arg (var_args, gchar *);
660   }
661 }
662 /**
663  * gst_tag_list_add_valist_values:
664  * @list: list to set tags in
665  * @mode: the mode to use
666  * @tag: tag
667  * @var_args: tag / GValue pairs to set
668  *
669  * Sets the GValues for the given tags using the specified mode.
670  */
671 void
672 gst_tag_list_add_valist_values (GstTagList *list, GstTagMergeMode mode, const gchar *tag, va_list var_args)
673 {
674   GstTagInfo *info;
675   GQuark quark;
676   
677   g_return_if_fail (GST_IS_TAG_LIST (list));
678   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
679   g_return_if_fail (tag != NULL);
680   
681   while (tag != NULL) {
682     quark = g_quark_from_string (tag);
683     info = gst_tag_lookup (quark);
684     g_return_if_fail (info != NULL);
685     gst_tag_list_add_value_internal (list, mode, quark, va_arg (var_args, GValue *));
686     tag = va_arg (var_args, gchar *);
687   }
688 }
689 /**
690  * gst_tag_list_remove_tag:
691  * @list: list to remove tag from
692  * @tag: tag to remove
693  *
694  * Removes the goven tag from the taglist.
695  */
696 void
697 gst_tag_list_remove_tag (GstTagList *list, const gchar *tag)
698 {
699   g_return_if_fail (GST_IS_TAG_LIST (list));
700   g_return_if_fail (tag != NULL);
701
702   gst_structure_remove_field ((GstStructure *) list, tag);
703 }
704 typedef struct {
705   GstTagForeachFunc     func;
706   GstTagList *          tag_list;
707   gpointer              data;
708 } TagForeachData;
709 static int
710 structure_foreach_wrapper (GQuark field_id, 
711         GValue *value, gpointer user_data)
712 {
713   TagForeachData *data = (TagForeachData *) user_data;
714   data->func (data->tag_list, g_quark_to_string (field_id), data->data);
715   return TRUE;
716 }
717 /**
718  * gst_tag_list_foreach:
719  * @list: list to iterate over
720  * @func: function to be called for each tag
721  * @user_data: user specified data
722  *
723  * Calls the given function for each tag inside the tag list. Note that if there
724  * is no tag, the function won't be called at all.
725  */
726 void
727 gst_tag_list_foreach (GstTagList *list, GstTagForeachFunc func, gpointer user_data)
728 {
729   TagForeachData data;
730
731   g_return_if_fail (GST_IS_TAG_LIST (list));
732   g_return_if_fail (func != NULL);
733   
734   data.func = func;
735   data.tag_list = list;
736   data.data = user_data;
737   gst_structure_foreach ((GstStructure *) list, structure_foreach_wrapper, &data);
738 }
739
740 /***** tag events *****/
741
742 /**
743  * gst_event_new_tag:
744  * @list: the tag list to put into the event or NULL for an empty list
745  *
746  * Creates a new tag event with the given list and takes ownership of it.
747  *
748  * Returns: a new tag event
749  */
750 GstEvent *
751 gst_event_new_tag (GstTagList *list)
752 {
753   GstEvent *ret;
754   
755   g_return_val_if_fail (list == NULL || GST_IS_TAG_LIST (list), NULL);
756
757   ret = gst_event_new (GST_EVENT_TAG);
758   if (!list)
759     list = gst_tag_list_new ();
760   ret->event_data.structure.structure = (GstStructure *) list;
761   
762   return ret;
763 }
764 /**
765  * get_event_tag_get_list:
766  * @tag_event: a tagging #GstEvent
767  *
768  * Gets the taglist from a given tagging event.
769  * 
770  * Returns: The #GstTagList of the event
771  */
772 GstTagList *
773 gst_event_tag_get_list (GstEvent *tag_event)
774 {
775   g_return_val_if_fail (GST_IS_EVENT (tag_event), NULL);
776   g_return_val_if_fail (GST_EVENT_TYPE (tag_event) == GST_EVENT_TAG, NULL);
777
778   return GST_TAG_LIST (tag_event->event_data.structure.structure);
779 }
780
781 /**
782  * gst_tag_list_get_value_index:
783  * @list: a #GStTagList
784  * @tag: tag to read out
785  * @index: number of entry to read out
786  *
787  * Gets the value that is at the given index for the given tag in the given 
788  * list.
789  * 
790  * Returns: The GValue for the specified entry or NULL if the tag wasn't available
791  *          or the tag doesn't have as many entries
792  */
793 G_CONST_RETURN GValue *
794 gst_tag_list_get_value_index (const GstTagList *list, const gchar *tag, guint index)
795 {
796   const GValue *value;
797
798   g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
799   g_return_val_if_fail (tag != NULL, NULL);
800   
801   value = gst_structure_get_value ((GstStructure *) list, tag);
802   if (value == NULL) return  NULL;
803   
804   if (GST_VALUE_HOLDS_LIST (value)) {
805     if (index >= gst_value_list_get_size (value)) return NULL;
806     return gst_value_list_get_value (value, index);
807   } else {
808     if (index > 0) return NULL;
809     return value;
810   }
811 }
812
813 /**
814  * gst_tag_list_copy_value:
815  * @dest: uninitialized #GValue to copy into
816  * @list: list to get the tag from
817  * @tag: tag to read out
818  *
819  * Copies the contents for the given tag into the value, merging multiple values 
820  * into one if multiple values are associated with the tag.
821  * You must g_value_unset() the value after use.
822  *
823  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the 
824  *          given list.
825  */
826 gboolean
827 gst_tag_list_copy_value (GValue *dest, const GstTagList *list, const gchar *tag)
828 {
829   const GValue *src;
830   
831   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
832   g_return_val_if_fail (tag != NULL, FALSE);
833   g_return_val_if_fail (dest != NULL, FALSE);
834   g_return_val_if_fail (G_VALUE_TYPE (dest) == 0, FALSE);
835   
836   src = gst_structure_get_value ((GstStructure *) list, tag);
837   if (!src) return FALSE;
838   
839   if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {    
840     GstTagInfo *info = gst_tag_lookup (g_quark_from_string (tag));
841     /* must be there or lists aren't allowed */
842     g_assert (info->merge_func);
843     info->merge_func (dest, src);
844   } else {
845     g_value_init (dest, G_VALUE_TYPE (src));
846     g_value_copy (src, dest);
847   }
848   return TRUE;
849 }
850
851 /***** evil macros to get all the gst_tag_list_get_*() functions right *****/
852
853 #define TAG_MERGE_FUNCS(name,type)                                              \
854 gboolean                                                                        \
855 gst_tag_list_get_ ## name (const GstTagList *list, const gchar *tag,            \
856                            type *value)                                         \
857 {                                                                               \
858   GValue v = { 0, };                                                            \
859                                                                                 \
860   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);                         \
861   g_return_val_if_fail (tag != NULL, FALSE);                                    \
862   g_return_val_if_fail (value != NULL, FALSE);                                  \
863                                                                                 \
864   if (!gst_tag_list_copy_value (&v, list, tag))                                 \
865       return FALSE;                                                             \
866   *value = COPY_FUNC (g_value_get_ ## name (&v));                               \
867   g_value_unset (&v);                                                           \
868   return TRUE;                                                                  \
869 }                                                                               \
870                                                                                 \
871 gboolean                                                                        \
872 gst_tag_list_get_ ## name ## _index (const GstTagList *list, const gchar *tag,  \
873                            guint index, type *value)                            \
874 {                                                                               \
875   const GValue *v;                                                              \
876                                                                                 \
877   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);                         \
878   g_return_val_if_fail (tag != NULL, FALSE);                                    \
879   g_return_val_if_fail (value != NULL, FALSE);                                  \
880                                                                                 \
881   if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL)            \
882       return FALSE;                                                             \
883   *value = COPY_FUNC (g_value_get_ ## name (v));                                \
884   return TRUE;                                                                  \
885 }
886
887 #define COPY_FUNC /**/
888 TAG_MERGE_FUNCS (char, gchar)
889 TAG_MERGE_FUNCS (uchar, guchar)
890 TAG_MERGE_FUNCS (boolean, gboolean)
891 TAG_MERGE_FUNCS (int, gint)
892 TAG_MERGE_FUNCS (uint, guint)
893 TAG_MERGE_FUNCS (long, glong)
894 TAG_MERGE_FUNCS (ulong, gulong)
895 TAG_MERGE_FUNCS (int64, gint64)
896 TAG_MERGE_FUNCS (uint64, guint64)
897 TAG_MERGE_FUNCS (float, gfloat)
898 TAG_MERGE_FUNCS (double, gdouble)
899 #undef COPY_FUNC
900   
901 #define COPY_FUNC g_strdup
902 TAG_MERGE_FUNCS (string, gchar *)
903
904
905
906