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