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