adding vorbis tags fixing replaygain tag names
[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_BITRATE,
155                     G_TYPE_UINT,
156                     _("bitrate"),
157                     _("exact or average bitrate in bits/s"),
158                     NULL);
159   gst_tag_register (GST_TAG_NOMINAL_BITRATE,
160                     G_TYPE_UINT,
161                     _("nominal bitrate"),
162                     _("nominal bitrate in bits/s"),
163                     NULL);
164   gst_tag_register (GST_TAG_MINIMUM_BITRATE,
165                     G_TYPE_UINT,
166                     _("minimum bitrate"),
167                     _("minimum bitrate in bits/s"),
168                     NULL);
169   gst_tag_register (GST_TAG_MAXIMUM_BITRATE,
170                     G_TYPE_UINT,
171                     _("maximum bitrate"),
172                     _("maximum bitrate in bits/s"),
173                     NULL);
174   gst_tag_register (GST_TAG_ENCODER_VERSION,
175                     G_TYPE_UINT,
176                     _("encoder version"),
177                     _("version of the encoder used to encode this stream"),
178                     NULL);
179   gst_tag_register (GST_TAG_SERIAL,
180                     G_TYPE_UINT,
181                     _("serial"),
182                     _("serial number of track"),
183                     NULL);
184   gst_tag_register (GST_TAG_TRACK_GAIN,
185                     G_TYPE_DOUBLE,
186                     _("replaygain track gain"),
187                     _("track gain in db"),
188                     NULL);
189   gst_tag_register (GST_TAG_TRACK_PEAK,
190                     G_TYPE_DOUBLE,
191                     _("replaygain track peak"),
192                     _("peak of the track"),
193                     NULL);
194   gst_tag_register (GST_TAG_ALBUM_GAIN,
195                     G_TYPE_DOUBLE,
196                     _("replaygain album gain"),
197                     _("album gain in db"),
198                     NULL);
199   gst_tag_register (GST_TAG_ALBUM_PEAK,
200                     G_TYPE_DOUBLE,
201                     _("replaygain album peak"),
202                     _("peak of the album"),
203                     NULL);
204 }
205 /**
206  * gst_tag_merge_use_first:
207  * @dest: uninitialized GValue to store result in
208  * @src: GValue to copy from
209  *
210  * This is a convenience function for the func argument of gst_tag_register(). 
211  * It creates a copy of the first value from the list.
212  */
213 void
214 gst_tag_merge_use_first (GValue *dest, const GValue *src)
215 {
216   const GValue *ret = gst_value_list_get_value (src, 0);
217
218   g_value_init (dest, G_VALUE_TYPE (ret));
219   g_value_copy (ret, dest);
220 }
221 /**
222  * gst_tag_merge_strings_with_comma:
223  * @dest: uninitialized GValue to store result in
224  * @src: GValue to copy from
225  * 
226  * This is a convenience function for the func argument of gst_tag_register().
227  * It concatenates all given strings using a comma. The tag must be registered
228  * as a G_TYPE_STRING or this function will fail.
229  */
230 void
231 gst_tag_merge_strings_with_comma (GValue *dest, const GValue *src)
232 {
233   GString *str;
234   gint i, count;
235
236   count = gst_value_list_get_size (src);
237   str = g_string_new (g_value_get_string (gst_value_list_get_value (src, 0)));
238   for (i = 1; i < count; i++) {
239     /* seperator between two string */
240     str = g_string_append (str, _(", "));
241     str = g_string_append (str, g_value_get_string (gst_value_list_get_value (src, 1)));
242   }
243
244   g_value_init (dest, G_TYPE_STRING);
245   g_value_set_string_take_ownership (dest, str->str);
246   g_string_free (str, FALSE);
247 }
248 static GstTagInfo *
249 gst_tag_lookup (GQuark entry)
250 {
251   GstTagInfo *ret;
252   
253   TAG_LOCK;
254   ret = g_hash_table_lookup (__tags, GUINT_TO_POINTER (entry));
255   TAG_UNLOCK;
256
257   return ret;
258 }
259 /**
260  * gst_tag_register:
261  * @name: the name or identifier string
262  * @type: the type this data is in
263  * @nick: human-readable name
264  * @blurb: a human-readable description about this tag
265  * @func: function for merging multiple values of this tag
266  *
267  * Registers a new tag type for the use with GStreamer's type system. If a type
268  * with that name is already registered, that one is used.
269  * The old registration may have used a different type however. So don't rely
270  * on youre supplied values.
271  * If you know the type is already registered, use gst_tag_lookup instead.
272  * This function takes ownership of all supplied variables.
273  */
274 void
275 gst_tag_register (gchar *name, GType type, gchar *nick, gchar *blurb,
276                   GstTagMergeFunc func)
277 {
278   GQuark key;
279   GstTagInfo *info;
280
281   g_return_if_fail (name != NULL);
282   g_return_if_fail (nick != NULL);
283   g_return_if_fail (blurb != NULL);
284   g_return_if_fail (type != 0 && type != GST_TYPE_LIST);
285   
286   key = g_quark_from_string (name);
287   info = gst_tag_lookup (key);
288   g_return_if_fail (info == NULL);
289   
290   info = g_new (GstTagInfo, 1);
291   info->type = type;
292   info->nick = nick;
293   info->blurb = blurb;
294   info->merge_func = func;
295     
296   TAG_LOCK;
297   g_hash_table_insert (__tags, GUINT_TO_POINTER (key), info);
298   TAG_UNLOCK;
299 }
300 /**
301  * gst_tag_exists:
302  * @tag: name of the tag
303  *
304  * Checks if the given type is already registered.
305  *
306  * Returns: TRUE if the type is already registered
307  */
308 gboolean
309 gst_tag_exists (const gchar *tag)
310 {
311   g_return_val_if_fail (tag != NULL, FALSE);
312   
313   return gst_tag_lookup (g_quark_from_string (tag)) != NULL;
314 }
315 /**
316  * gst_tag_get_type:
317  * @tag: the tag
318  *
319  * Gets the #GType used for this tag.
320  *
321  * Returns: the #GType of this tag
322  */
323 GType
324 gst_tag_get_type (const gchar *tag)
325 {
326   GstTagInfo *info;
327   
328   g_return_val_if_fail (tag != NULL, 0);
329   info = gst_tag_lookup (g_quark_from_string (tag));
330   g_return_val_if_fail (info != NULL, 0);
331   
332   return info->type;
333 }
334 /**
335  * gst_tag_get_nick
336  * @tag: the tag
337  *
338  * Returns the human-readable name of this tag, You must not change or free 
339  * this string.
340  *
341  * Returns: the human-readable name of this tag
342  */
343 const gchar *
344 gst_tag_get_nick (const gchar *tag)
345 {
346   GstTagInfo *info;
347   
348   g_return_val_if_fail (tag != NULL, NULL);
349   info = gst_tag_lookup (g_quark_from_string (tag));
350   g_return_val_if_fail (info != NULL, NULL);
351   
352   return info->nick;
353 }
354 /**
355  * gst_tag_get_description:
356  * @tag: the tag
357  *
358  * Returns the human-readable description of this tag, You must not change or 
359  * free this string.
360  *
361  * Return the human-readable description of this tag
362  */
363 const gchar *
364 gst_tag_get_description (const gchar *tag)
365 {
366   GstTagInfo *info;
367   
368   g_return_val_if_fail (tag != NULL, NULL);
369   info = gst_tag_lookup (g_quark_from_string (tag));
370   g_return_val_if_fail (info != NULL, NULL);
371   
372   return info->blurb;
373 }
374 /**
375  * gst_tag_list_is_fixed:
376  * @tag: tag to check
377  *
378  * Checks if the given tag is fixed. A fixed tag can only contain one value.
379  * Unfixed tags can contain lists of values.
380  *
381  * Returns: TRUE, if the given tag is fixed.
382  */
383 gboolean
384 gst_tag_is_fixed (const gchar *tag)
385 {
386   GstTagInfo *info;
387   
388   g_return_val_if_fail (tag != NULL, FALSE);
389   info = gst_tag_lookup (g_quark_from_string (tag));
390   g_return_val_if_fail (info != NULL, FALSE);
391   
392   return info->merge_func == NULL;
393 }
394 /**
395  * gst_tag_list_new:
396  *
397  * Creates a new empty GstTagList.
398  *
399  * Returns: An empty tag list
400  */
401 GstTagList *
402 gst_tag_list_new (void)
403 {
404   return GST_TAG_LIST (gst_structure_new (TAGLIST, NULL));
405 }
406 /**
407  * gst_is_tag_list:
408  * @p: Object that might be a taglist
409  *
410  * Checks if the given pointer is a taglist.
411  *
412  * Returns: TRUE, if the given pointer is a taglist
413  */
414 gboolean
415 gst_is_tag_list (gconstpointer p)
416 {
417   g_return_val_if_fail (p != NULL, FALSE); 
418
419   return ((GstStructure *) p)->name == gst_tag_list_quark;
420 }
421 typedef struct {
422   GstStructure *        list;
423   GstTagMergeMode       mode;
424 } GstTagCopyData;
425 static void
426 gst_tag_list_add_value_internal (GstStructure *list, GstTagMergeMode mode, GQuark tag, GValue *value)
427 {
428   GstTagInfo *info = gst_tag_lookup (tag);
429   const GValue *value2;
430   
431   g_assert (info != NULL);
432
433   if (info->merge_func && (value2 = gst_structure_id_get_value (list, tag)) != NULL) {
434     GValue dest = { 0, };
435     switch (mode) {
436       case GST_TAG_MERGE_REPLACE_ALL:
437       case GST_TAG_MERGE_REPLACE:
438         gst_structure_id_set_value (list, tag, value);
439         break;
440       case GST_TAG_MERGE_PREPEND:
441         gst_value_list_concat (&dest, value, value2);
442         gst_structure_id_set_value (list, tag, &dest);
443         g_value_unset (&dest);
444         break;
445       case GST_TAG_MERGE_APPEND:
446         gst_value_list_concat (&dest, value2, value);
447         gst_structure_id_set_value (list, tag, &dest);
448         g_value_unset (&dest);
449         break;
450       case GST_TAG_MERGE_KEEP:
451       case GST_TAG_MERGE_KEEP_ALL:
452         break;
453       default:
454         g_assert_not_reached ();
455         break;
456     }
457   } else {
458     switch (mode) {
459       case GST_TAG_MERGE_APPEND:
460       case GST_TAG_MERGE_KEEP:
461         if (gst_structure_id_get_value (list, tag) != NULL)
462           break;
463         /* fall through */
464       case GST_TAG_MERGE_REPLACE_ALL:
465       case GST_TAG_MERGE_REPLACE:
466       case GST_TAG_MERGE_PREPEND:
467         gst_structure_id_set_value (list, tag, value);
468         break;
469       case GST_TAG_MERGE_KEEP_ALL:
470         break;
471       default:
472         g_assert_not_reached ();
473         break;
474     }
475   }
476 }
477 static gboolean
478 gst_tag_list_copy_foreach (GQuark tag, GValue *value, gpointer user_data)
479 {
480   GstTagCopyData *copy = (GstTagCopyData *) user_data;
481
482   gst_tag_list_add_value_internal (copy->list, copy->mode, tag, value);
483
484   return TRUE;
485 }
486 /**
487  * gst_tag_list_insert:
488  * @into: list to merge into
489  * @from: list to merge from
490  * @mode: the mode to use
491  * 
492  * Inserts the tags of the second list into the first list using the given mode.
493  */
494 void
495 gst_tag_list_insert (GstTagList *into, const GstTagList *from, GstTagMergeMode mode)
496 {
497   GstTagCopyData data;
498   
499   g_return_if_fail (GST_IS_TAG_LIST (into));
500   g_return_if_fail (GST_IS_TAG_LIST (from));
501   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
502
503   data.list = (GstStructure *) into;
504   data.mode = mode;
505   if (mode == GST_TAG_MERGE_REPLACE_ALL) {
506     gst_structure_remove_all_fields (data.list);
507   }
508   gst_structure_foreach ((GstStructure *) from, gst_tag_list_copy_foreach, &data);
509 }
510 /**
511  * gst_tag_list_copy:
512  * @list: list to copy
513  *
514  * Copies a given #GstTagList.
515  *
516  * Returns: copy of the given list
517  */
518 GstTagList *
519 gst_tag_list_copy (const GstTagList *list)
520 {
521   g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
522   
523   return GST_TAG_LIST (gst_structure_copy ((GstStructure *) list));
524 }
525 /**
526  * gst_tag_list_merge:
527  * @list1: first list to merge
528  * @list2: second list to merge
529  * @mode: the mode to use
530  * 
531  * Merges the two given lists into a new list. If one of the lists is NULL, a
532  * copy of the other is returned. If both lists are NULL, NULL is returned.
533  *
534  * Returns: the new list
535  */
536 GstTagList *
537 gst_tag_list_merge (const GstTagList *list1, const GstTagList *list2, GstTagMergeMode mode)
538 {
539   g_return_val_if_fail (list1 == NULL || GST_IS_TAG_LIST (list1), NULL);
540   g_return_val_if_fail (list2 == NULL || GST_IS_TAG_LIST (list2), NULL);
541   g_return_val_if_fail (GST_TAG_MODE_IS_VALID (mode), NULL);
542
543   if (!list1 && !list2) {
544     return NULL;
545   } else if (!list1) {
546     return gst_tag_list_copy (list2);
547   } else if (!list2) {
548     return gst_tag_list_copy (list1);
549   } else {
550     GstTagList *ret;
551
552     ret = gst_tag_list_copy (list1);
553     gst_tag_list_insert (ret, list2, mode);
554     return ret;
555   }
556 }
557 /**
558  * gst_tag_list_free:
559  * @list: the list to free
560  *
561  * Frees the given list and all associated values.
562  */
563 void
564 gst_tag_list_free (GstTagList *list)
565 {
566   g_return_if_fail (GST_IS_TAG_LIST (list));
567   gst_structure_free ((GstStructure *) list);
568 }
569 /**
570  * gst_tag_list_get_tag_size:
571  * @list: a taglist
572  * @tag: the tag to query
573  *
574  * Checks how many value are stored in this tag list for the given tag.
575  *
576  * Returns: The number of tags stored
577  */
578 guint
579 gst_tag_list_get_tag_size (const GstTagList *list, const gchar *tag)
580 {
581   const GValue *value;
582
583   g_return_val_if_fail (GST_IS_TAG_LIST (list), 0);
584
585   value = gst_structure_get_value ((GstStructure *) list, tag);
586   if (value == NULL)
587     return 0;
588   if (G_VALUE_TYPE (value) != GST_TYPE_LIST)
589     return 1;
590
591   return gst_value_list_get_size (value);
592 }
593 /**
594  * gst_tag_list_add:
595  * @list: list to set tags in
596  * @mode: the mode to use
597  * @tag: tag
598  * @...: NULL-terminated list of values to set
599  *
600  * Sets the values for the given tags using the specified mode.
601  */
602 void
603 gst_tag_list_add (GstTagList *list, GstTagMergeMode mode, const gchar *tag, ...)
604 {
605   va_list args;
606
607   g_return_if_fail (GST_IS_TAG_LIST (list));
608   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
609   g_return_if_fail (tag != NULL);
610   
611   va_start (args, tag);
612   gst_tag_list_add_valist (list, mode, tag, args);
613   va_end (args);
614 }
615 /**
616  * gst_tag_list_add_values:
617  * @list: list to set tags in
618  * @mode: the mode to use
619  * @tag: tag
620  * @...: GValues to set
621  *
622  * Sets the GValues for the given tags using the specified mode.
623  */
624 void
625 gst_tag_list_add_values (GstTagList *list, GstTagMergeMode mode, const gchar *tag, ...)
626 {
627   va_list args;
628
629   g_return_if_fail (GST_IS_TAG_LIST (list));
630   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
631   g_return_if_fail (tag != NULL);
632   
633   va_start (args, tag);
634   gst_tag_list_add_valist_values (list, mode, tag, args);
635   va_end (args);
636 }
637 /**
638  * gst_tag_list_add_valist:
639  * @list: list to set tags in
640  * @mode: the mode to use
641  * @tag: tag
642  * @var_args: tag / value pairs to set
643  *
644  * Sets the values for the given tags using the specified mode.
645  */
646 void
647 gst_tag_list_add_valist (GstTagList *list, GstTagMergeMode mode, const gchar *tag, va_list var_args)
648 {
649   GstTagInfo *info;
650   GQuark quark;
651   gchar *error = NULL;
652   
653   g_return_if_fail (GST_IS_TAG_LIST (list));
654   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
655   g_return_if_fail (tag != NULL);
656   
657   while (tag != NULL) {
658     GValue value = { 0, };
659     quark = g_quark_from_string (tag);
660     info = gst_tag_lookup (quark);
661     if (info == NULL)
662       g_warning ("no GstTag for %s", tag);
663     g_return_if_fail (info != NULL);
664     g_value_init (&value, info->type);
665     G_VALUE_COLLECT (&value, var_args, 0, &error);
666     if (error) {
667       g_warning ("%s: %s", G_STRLOC, error);
668       g_free (error);
669       /* we purposely leak the value here, it might not be
670        * in a sane state if an error condition occoured
671        */
672       return;
673     }
674     gst_tag_list_add_value_internal (list, mode, quark, &value);
675     g_value_unset (&value);
676     tag = va_arg (var_args, gchar *);
677   }
678 }
679 /**
680  * gst_tag_list_add_valist_values:
681  * @list: list to set tags in
682  * @mode: the mode to use
683  * @tag: tag
684  * @var_args: tag / GValue pairs to set
685  *
686  * Sets the GValues for the given tags using the specified mode.
687  */
688 void
689 gst_tag_list_add_valist_values (GstTagList *list, GstTagMergeMode mode, const gchar *tag, va_list var_args)
690 {
691   GstTagInfo *info;
692   GQuark quark;
693   
694   g_return_if_fail (GST_IS_TAG_LIST (list));
695   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
696   g_return_if_fail (tag != NULL);
697   
698   while (tag != NULL) {
699     quark = g_quark_from_string (tag);
700     info = gst_tag_lookup (quark);
701     g_return_if_fail (info != NULL);
702     gst_tag_list_add_value_internal (list, mode, quark, va_arg (var_args, GValue *));
703     tag = va_arg (var_args, gchar *);
704   }
705 }
706 /**
707  * gst_tag_list_remove_tag:
708  * @list: list to remove tag from
709  * @tag: tag to remove
710  *
711  * Removes the goven tag from the taglist.
712  */
713 void
714 gst_tag_list_remove_tag (GstTagList *list, const gchar *tag)
715 {
716   g_return_if_fail (GST_IS_TAG_LIST (list));
717   g_return_if_fail (tag != NULL);
718
719   gst_structure_remove_field ((GstStructure *) list, tag);
720 }
721 typedef struct {
722   GstTagForeachFunc     func;
723   GstTagList *          tag_list;
724   gpointer              data;
725 } TagForeachData;
726 static int
727 structure_foreach_wrapper (GQuark field_id, 
728         GValue *value, gpointer user_data)
729 {
730   TagForeachData *data = (TagForeachData *) user_data;
731   data->func (data->tag_list, g_quark_to_string (field_id), data->data);
732   return TRUE;
733 }
734 /**
735  * gst_tag_list_foreach:
736  * @list: list to iterate over
737  * @func: function to be called for each tag
738  * @user_data: user specified data
739  *
740  * Calls the given function for each tag inside the tag list. Note that if there
741  * is no tag, the function won't be called at all.
742  */
743 void
744 gst_tag_list_foreach (GstTagList *list, GstTagForeachFunc func, gpointer user_data)
745 {
746   TagForeachData data;
747
748   g_return_if_fail (GST_IS_TAG_LIST (list));
749   g_return_if_fail (func != NULL);
750   
751   data.func = func;
752   data.tag_list = list;
753   data.data = user_data;
754   gst_structure_foreach ((GstStructure *) list, structure_foreach_wrapper, &data);
755 }
756
757 /***** tag events *****/
758
759 /**
760  * gst_event_new_tag:
761  * @list: the tag list to put into the event or NULL for an empty list
762  *
763  * Creates a new tag event with the given list and takes ownership of it.
764  *
765  * Returns: a new tag event
766  */
767 GstEvent *
768 gst_event_new_tag (GstTagList *list)
769 {
770   GstEvent *ret;
771   
772   g_return_val_if_fail (list == NULL || GST_IS_TAG_LIST (list), NULL);
773
774   ret = gst_event_new (GST_EVENT_TAG);
775   if (!list)
776     list = gst_tag_list_new ();
777   ret->event_data.structure.structure = (GstStructure *) list;
778   
779   return ret;
780 }
781 /**
782  * get_event_tag_get_list:
783  * @tag_event: a tagging #GstEvent
784  *
785  * Gets the taglist from a given tagging event.
786  * 
787  * Returns: The #GstTagList of the event
788  */
789 GstTagList *
790 gst_event_tag_get_list (GstEvent *tag_event)
791 {
792   g_return_val_if_fail (GST_IS_EVENT (tag_event), NULL);
793   g_return_val_if_fail (GST_EVENT_TYPE (tag_event) == GST_EVENT_TAG, NULL);
794
795   return GST_TAG_LIST (tag_event->event_data.structure.structure);
796 }
797
798 /**
799  * gst_tag_list_get_value_index:
800  * @list: a #GStTagList
801  * @tag: tag to read out
802  * @index: number of entry to read out
803  *
804  * Gets the value that is at the given index for the given tag in the given 
805  * list.
806  * 
807  * Returns: The GValue for the specified entry or NULL if the tag wasn't available
808  *          or the tag doesn't have as many entries
809  */
810 G_CONST_RETURN GValue *
811 gst_tag_list_get_value_index (const GstTagList *list, const gchar *tag, guint index)
812 {
813   const GValue *value;
814
815   g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
816   g_return_val_if_fail (tag != NULL, NULL);
817   
818   value = gst_structure_get_value ((GstStructure *) list, tag);
819   if (value == NULL) return  NULL;
820   
821   if (GST_VALUE_HOLDS_LIST (value)) {
822     if (index >= gst_value_list_get_size (value)) return NULL;
823     return gst_value_list_get_value (value, index);
824   } else {
825     if (index > 0) return NULL;
826     return value;
827   }
828 }
829
830 /**
831  * gst_tag_list_copy_value:
832  * @dest: uninitialized #GValue to copy into
833  * @list: list to get the tag from
834  * @tag: tag to read out
835  *
836  * Copies the contents for the given tag into the value, merging multiple values 
837  * into one if multiple values are associated with the tag.
838  * You must g_value_unset() the value after use.
839  *
840  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the 
841  *          given list.
842  */
843 gboolean
844 gst_tag_list_copy_value (GValue *dest, const GstTagList *list, const gchar *tag)
845 {
846   const GValue *src;
847   
848   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
849   g_return_val_if_fail (tag != NULL, FALSE);
850   g_return_val_if_fail (dest != NULL, FALSE);
851   g_return_val_if_fail (G_VALUE_TYPE (dest) == 0, FALSE);
852   
853   src = gst_structure_get_value ((GstStructure *) list, tag);
854   if (!src) return FALSE;
855   
856   if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {    
857     GstTagInfo *info = gst_tag_lookup (g_quark_from_string (tag));
858     /* must be there or lists aren't allowed */
859     g_assert (info->merge_func);
860     info->merge_func (dest, src);
861   } else {
862     g_value_init (dest, G_VALUE_TYPE (src));
863     g_value_copy (src, dest);
864   }
865   return TRUE;
866 }
867
868 /***** evil macros to get all the gst_tag_list_get_*() functions right *****/
869
870 #define TAG_MERGE_FUNCS(name,type)                                              \
871 gboolean                                                                        \
872 gst_tag_list_get_ ## name (const GstTagList *list, const gchar *tag,            \
873                            type *value)                                         \
874 {                                                                               \
875   GValue v = { 0, };                                                            \
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 (!gst_tag_list_copy_value (&v, list, tag))                                 \
882       return FALSE;                                                             \
883   *value = COPY_FUNC (g_value_get_ ## name (&v));                               \
884   g_value_unset (&v);                                                           \
885   return TRUE;                                                                  \
886 }                                                                               \
887                                                                                 \
888 gboolean                                                                        \
889 gst_tag_list_get_ ## name ## _index (const GstTagList *list, const gchar *tag,  \
890                            guint index, type *value)                            \
891 {                                                                               \
892   const GValue *v;                                                              \
893                                                                                 \
894   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);                         \
895   g_return_val_if_fail (tag != NULL, FALSE);                                    \
896   g_return_val_if_fail (value != NULL, FALSE);                                  \
897                                                                                 \
898   if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL)            \
899       return FALSE;                                                             \
900   *value = COPY_FUNC (g_value_get_ ## name (v));                                \
901   return TRUE;                                                                  \
902 }
903
904 #define COPY_FUNC /**/
905 TAG_MERGE_FUNCS (char, gchar)
906 TAG_MERGE_FUNCS (uchar, guchar)
907 TAG_MERGE_FUNCS (boolean, gboolean)
908 TAG_MERGE_FUNCS (int, gint)
909 TAG_MERGE_FUNCS (uint, guint)
910 TAG_MERGE_FUNCS (long, glong)
911 TAG_MERGE_FUNCS (ulong, gulong)
912 TAG_MERGE_FUNCS (int64, gint64)
913 TAG_MERGE_FUNCS (uint64, guint64)
914 TAG_MERGE_FUNCS (float, gfloat)
915 TAG_MERGE_FUNCS (double, gdouble)
916 #undef COPY_FUNC
917   
918 #define COPY_FUNC g_strdup
919 TAG_MERGE_FUNCS (string, gchar *)
920
921
922
923