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