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