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