remove deprecated functions add two tag prototypes to docs add accessor function
[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 /**
422  * gst_tag_get_flag:
423  * @tag: the tag
424  *
425  * Returns the flag of this tag.
426  */
427 GstTagFlag
428 gst_tag_get_flag (const gchar *tag)
429 {
430   GstTagInfo *info;
431
432   g_return_val_if_fail (tag != NULL, GST_TAG_FLAG_UNDEFINED);
433   info = gst_tag_lookup (g_quark_from_string (tag));
434   g_return_val_if_fail (info != NULL, GST_TAG_FLAG_UNDEFINED);
435
436   return info->flag;
437 }
438
439 /**
440  * gst_tag_list_is_fixed:
441  * @tag: tag to check
442  *
443  * Checks if the given tag is fixed. A fixed tag can only contain one value.
444  * Unfixed tags can contain lists of values.
445  *
446  * Returns: TRUE, if the given tag is fixed.
447  */
448 gboolean
449 gst_tag_is_fixed (const gchar *tag)
450 {
451   GstTagInfo *info;
452   
453   g_return_val_if_fail (tag != NULL, FALSE);
454   info = gst_tag_lookup (g_quark_from_string (tag));
455   g_return_val_if_fail (info != NULL, FALSE);
456   
457   return info->merge_func == NULL;
458 }
459 /**
460  * gst_tag_list_new:
461  *
462  * Creates a new empty GstTagList.
463  *
464  * Returns: An empty tag list
465  */
466 GstTagList *
467 gst_tag_list_new (void)
468 {
469   return GST_TAG_LIST (gst_structure_new (TAGLIST, NULL));
470 }
471 /**
472  * gst_is_tag_list:
473  * @p: Object that might be a taglist
474  *
475  * Checks if the given pointer is a taglist.
476  *
477  * Returns: TRUE, if the given pointer is a taglist
478  */
479 gboolean
480 gst_is_tag_list (gconstpointer p)
481 {
482   g_return_val_if_fail (p != NULL, FALSE); 
483
484   return ((GstStructure *) p)->name == gst_tag_list_quark;
485 }
486 typedef struct {
487   GstStructure *        list;
488   GstTagMergeMode       mode;
489 } GstTagCopyData;
490 static void
491 gst_tag_list_add_value_internal (GstStructure *list, GstTagMergeMode mode, GQuark tag, GValue *value)
492 {
493   GstTagInfo *info = gst_tag_lookup (tag);
494   const GValue *value2;
495   
496   g_assert (info != NULL);
497
498   if (info->merge_func && (value2 = gst_structure_id_get_value (list, tag)) != NULL) {
499     GValue dest = { 0, };
500     switch (mode) {
501       case GST_TAG_MERGE_REPLACE_ALL:
502       case GST_TAG_MERGE_REPLACE:
503         gst_structure_id_set_value (list, tag, value);
504         break;
505       case GST_TAG_MERGE_PREPEND:
506         gst_value_list_concat (&dest, value, value2);
507         gst_structure_id_set_value (list, tag, &dest);
508         g_value_unset (&dest);
509         break;
510       case GST_TAG_MERGE_APPEND:
511         gst_value_list_concat (&dest, value2, value);
512         gst_structure_id_set_value (list, tag, &dest);
513         g_value_unset (&dest);
514         break;
515       case GST_TAG_MERGE_KEEP:
516       case GST_TAG_MERGE_KEEP_ALL:
517         break;
518       default:
519         g_assert_not_reached ();
520         break;
521     }
522   } else {
523     switch (mode) {
524       case GST_TAG_MERGE_APPEND:
525       case GST_TAG_MERGE_KEEP:
526         if (gst_structure_id_get_value (list, tag) != NULL)
527           break;
528         /* fall through */
529       case GST_TAG_MERGE_REPLACE_ALL:
530       case GST_TAG_MERGE_REPLACE:
531       case GST_TAG_MERGE_PREPEND:
532         gst_structure_id_set_value (list, tag, value);
533         break;
534       case GST_TAG_MERGE_KEEP_ALL:
535         break;
536       default:
537         g_assert_not_reached ();
538         break;
539     }
540   }
541 }
542 static gboolean
543 gst_tag_list_copy_foreach (GQuark tag, GValue *value, gpointer user_data)
544 {
545   GstTagCopyData *copy = (GstTagCopyData *) user_data;
546
547   gst_tag_list_add_value_internal (copy->list, copy->mode, tag, value);
548
549   return TRUE;
550 }
551 /**
552  * gst_tag_list_insert:
553  * @into: list to merge into
554  * @from: list to merge from
555  * @mode: the mode to use
556  * 
557  * Inserts the tags of the second list into the first list using the given mode.
558  */
559 void
560 gst_tag_list_insert (GstTagList *into, const GstTagList *from, GstTagMergeMode mode)
561 {
562   GstTagCopyData data;
563   
564   g_return_if_fail (GST_IS_TAG_LIST (into));
565   g_return_if_fail (GST_IS_TAG_LIST (from));
566   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
567
568   data.list = (GstStructure *) into;
569   data.mode = mode;
570   if (mode == GST_TAG_MERGE_REPLACE_ALL) {
571     gst_structure_remove_all_fields (data.list);
572   }
573   gst_structure_foreach ((GstStructure *) from, gst_tag_list_copy_foreach, &data);
574 }
575 /**
576  * gst_tag_list_copy:
577  * @list: list to copy
578  *
579  * Copies a given #GstTagList.
580  *
581  * Returns: copy of the given list
582  */
583 GstTagList *
584 gst_tag_list_copy (const GstTagList *list)
585 {
586   g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
587   
588   return GST_TAG_LIST (gst_structure_copy ((GstStructure *) list));
589 }
590 /**
591  * gst_tag_list_merge:
592  * @list1: first list to merge
593  * @list2: second list to merge
594  * @mode: the mode to use
595  * 
596  * Merges the two given lists into a new list. If one of the lists is NULL, a
597  * copy of the other is returned. If both lists are NULL, NULL is returned.
598  *
599  * Returns: the new list
600  */
601 GstTagList *
602 gst_tag_list_merge (const GstTagList *list1, const GstTagList *list2, GstTagMergeMode mode)
603 {
604   g_return_val_if_fail (list1 == NULL || GST_IS_TAG_LIST (list1), NULL);
605   g_return_val_if_fail (list2 == NULL || GST_IS_TAG_LIST (list2), NULL);
606   g_return_val_if_fail (GST_TAG_MODE_IS_VALID (mode), NULL);
607
608   if (!list1 && !list2) {
609     return NULL;
610   } else if (!list1) {
611     return gst_tag_list_copy (list2);
612   } else if (!list2) {
613     return gst_tag_list_copy (list1);
614   } else {
615     GstTagList *ret;
616
617     ret = gst_tag_list_copy (list1);
618     gst_tag_list_insert (ret, list2, mode);
619     return ret;
620   }
621 }
622 /**
623  * gst_tag_list_free:
624  * @list: the list to free
625  *
626  * Frees the given list and all associated values.
627  */
628 void
629 gst_tag_list_free (GstTagList *list)
630 {
631   g_return_if_fail (GST_IS_TAG_LIST (list));
632   gst_structure_free ((GstStructure *) list);
633 }
634 /**
635  * gst_tag_list_get_tag_size:
636  * @list: a taglist
637  * @tag: the tag to query
638  *
639  * Checks how many value are stored in this tag list for the given tag.
640  *
641  * Returns: The number of tags stored
642  */
643 guint
644 gst_tag_list_get_tag_size (const GstTagList *list, const gchar *tag)
645 {
646   const GValue *value;
647
648   g_return_val_if_fail (GST_IS_TAG_LIST (list), 0);
649
650   value = gst_structure_get_value ((GstStructure *) list, tag);
651   if (value == NULL)
652     return 0;
653   if (G_VALUE_TYPE (value) != GST_TYPE_LIST)
654     return 1;
655
656   return gst_value_list_get_size (value);
657 }
658 /**
659  * gst_tag_list_add:
660  * @list: list to set tags in
661  * @mode: the mode to use
662  * @tag: tag
663  * @...: NULL-terminated list of values to set
664  *
665  * Sets the values for the given tags using the specified mode.
666  */
667 void
668 gst_tag_list_add (GstTagList *list, GstTagMergeMode mode, const gchar *tag, ...)
669 {
670   va_list args;
671
672   g_return_if_fail (GST_IS_TAG_LIST (list));
673   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
674   g_return_if_fail (tag != NULL);
675   
676   va_start (args, tag);
677   gst_tag_list_add_valist (list, mode, tag, args);
678   va_end (args);
679 }
680 /**
681  * gst_tag_list_add_values:
682  * @list: list to set tags in
683  * @mode: the mode to use
684  * @tag: tag
685  * @...: GValues to set
686  *
687  * Sets the GValues for the given tags using the specified mode.
688  */
689 void
690 gst_tag_list_add_values (GstTagList *list, GstTagMergeMode mode, const gchar *tag, ...)
691 {
692   va_list args;
693
694   g_return_if_fail (GST_IS_TAG_LIST (list));
695   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
696   g_return_if_fail (tag != NULL);
697   
698   va_start (args, tag);
699   gst_tag_list_add_valist_values (list, mode, tag, args);
700   va_end (args);
701 }
702 /**
703  * gst_tag_list_add_valist:
704  * @list: list to set tags in
705  * @mode: the mode to use
706  * @tag: tag
707  * @var_args: tag / value pairs to set
708  *
709  * Sets the values for the given tags using the specified mode.
710  */
711 void
712 gst_tag_list_add_valist (GstTagList *list, GstTagMergeMode mode, const gchar *tag, va_list var_args)
713 {
714   GstTagInfo *info;
715   GQuark quark;
716   gchar *error = NULL;
717   
718   g_return_if_fail (GST_IS_TAG_LIST (list));
719   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
720   g_return_if_fail (tag != NULL);
721   
722   while (tag != NULL) {
723     GValue value = { 0, };
724     quark = g_quark_from_string (tag);
725     info = gst_tag_lookup (quark);
726     if (info == NULL)
727       g_warning ("no GstTag for %s", tag);
728     g_return_if_fail (info != NULL);
729     g_value_init (&value, info->type);
730     G_VALUE_COLLECT (&value, var_args, 0, &error);
731     if (error) {
732       g_warning ("%s: %s", G_STRLOC, error);
733       g_free (error);
734       /* we purposely leak the value here, it might not be
735        * in a sane state if an error condition occoured
736        */
737       return;
738     }
739     gst_tag_list_add_value_internal (list, mode, quark, &value);
740     g_value_unset (&value);
741     tag = va_arg (var_args, gchar *);
742   }
743 }
744 /**
745  * gst_tag_list_add_valist_values:
746  * @list: list to set tags in
747  * @mode: the mode to use
748  * @tag: tag
749  * @var_args: tag / GValue pairs to set
750  *
751  * Sets the GValues for the given tags using the specified mode.
752  */
753 void
754 gst_tag_list_add_valist_values (GstTagList *list, GstTagMergeMode mode, const gchar *tag, va_list var_args)
755 {
756   GstTagInfo *info;
757   GQuark quark;
758   
759   g_return_if_fail (GST_IS_TAG_LIST (list));
760   g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
761   g_return_if_fail (tag != NULL);
762   
763   while (tag != NULL) {
764     quark = g_quark_from_string (tag);
765     info = gst_tag_lookup (quark);
766     g_return_if_fail (info != NULL);
767     gst_tag_list_add_value_internal (list, mode, quark, va_arg (var_args, GValue *));
768     tag = va_arg (var_args, gchar *);
769   }
770 }
771 /**
772  * gst_tag_list_remove_tag:
773  * @list: list to remove tag from
774  * @tag: tag to remove
775  *
776  * Removes the goven tag from the taglist.
777  */
778 void
779 gst_tag_list_remove_tag (GstTagList *list, const gchar *tag)
780 {
781   g_return_if_fail (GST_IS_TAG_LIST (list));
782   g_return_if_fail (tag != NULL);
783
784   gst_structure_remove_field ((GstStructure *) list, tag);
785 }
786 typedef struct {
787   GstTagForeachFunc     func;
788   GstTagList *          tag_list;
789   gpointer              data;
790 } TagForeachData;
791 static int
792 structure_foreach_wrapper (GQuark field_id, 
793         GValue *value, gpointer user_data)
794 {
795   TagForeachData *data = (TagForeachData *) user_data;
796   data->func (data->tag_list, g_quark_to_string (field_id), data->data);
797   return TRUE;
798 }
799 /**
800  * gst_tag_list_foreach:
801  * @list: list to iterate over
802  * @func: function to be called for each tag
803  * @user_data: user specified data
804  *
805  * Calls the given function for each tag inside the tag list. Note that if there
806  * is no tag, the function won't be called at all.
807  */
808 void
809 gst_tag_list_foreach (GstTagList *list, GstTagForeachFunc func, gpointer user_data)
810 {
811   TagForeachData data;
812
813   g_return_if_fail (GST_IS_TAG_LIST (list));
814   g_return_if_fail (func != NULL);
815   
816   data.func = func;
817   data.tag_list = list;
818   data.data = user_data;
819   gst_structure_foreach ((GstStructure *) list, structure_foreach_wrapper, &data);
820 }
821
822 /***** tag events *****/
823
824 /**
825  * gst_event_new_tag:
826  * @list: the tag list to put into the event or NULL for an empty list
827  *
828  * Creates a new tag event with the given list and takes ownership of it.
829  *
830  * Returns: a new tag event
831  */
832 GstEvent *
833 gst_event_new_tag (GstTagList *list)
834 {
835   GstEvent *ret;
836   
837   g_return_val_if_fail (list == NULL || GST_IS_TAG_LIST (list), NULL);
838
839   ret = gst_event_new (GST_EVENT_TAG);
840   if (!list)
841     list = gst_tag_list_new ();
842   ret->event_data.structure.structure = (GstStructure *) list;
843   
844   return ret;
845 }
846 /**
847  * get_event_tag_get_list:
848  * @tag_event: a tagging #GstEvent
849  *
850  * Gets the taglist from a given tagging event.
851  * 
852  * Returns: The #GstTagList of the event
853  */
854 GstTagList *
855 gst_event_tag_get_list (GstEvent *tag_event)
856 {
857   g_return_val_if_fail (GST_IS_EVENT (tag_event), NULL);
858   g_return_val_if_fail (GST_EVENT_TYPE (tag_event) == GST_EVENT_TAG, NULL);
859
860   return GST_TAG_LIST (tag_event->event_data.structure.structure);
861 }
862
863 /**
864  * gst_tag_list_get_value_index:
865  * @list: a #GStTagList
866  * @tag: tag to read out
867  * @index: number of entry to read out
868  *
869  * Gets the value that is at the given index for the given tag in the given 
870  * list.
871  * 
872  * Returns: The GValue for the specified entry or NULL if the tag wasn't available
873  *          or the tag doesn't have as many entries
874  */
875 G_CONST_RETURN GValue *
876 gst_tag_list_get_value_index (const GstTagList *list, const gchar *tag, guint index)
877 {
878   const GValue *value;
879
880   g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
881   g_return_val_if_fail (tag != NULL, NULL);
882   
883   value = gst_structure_get_value ((GstStructure *) list, tag);
884   if (value == NULL) return  NULL;
885   
886   if (GST_VALUE_HOLDS_LIST (value)) {
887     if (index >= gst_value_list_get_size (value)) return NULL;
888     return gst_value_list_get_value (value, index);
889   } else {
890     if (index > 0) return NULL;
891     return value;
892   }
893 }
894
895 /**
896  * gst_tag_list_copy_value:
897  * @dest: uninitialized #GValue to copy into
898  * @list: list to get the tag from
899  * @tag: tag to read out
900  *
901  * Copies the contents for the given tag into the value, merging multiple values 
902  * into one if multiple values are associated with the tag.
903  * You must g_value_unset() the value after use.
904  *
905  * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the 
906  *          given list.
907  */
908 gboolean
909 gst_tag_list_copy_value (GValue *dest, const GstTagList *list, const gchar *tag)
910 {
911   const GValue *src;
912   
913   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);
914   g_return_val_if_fail (tag != NULL, FALSE);
915   g_return_val_if_fail (dest != NULL, FALSE);
916   g_return_val_if_fail (G_VALUE_TYPE (dest) == 0, FALSE);
917   
918   src = gst_structure_get_value ((GstStructure *) list, tag);
919   if (!src) return FALSE;
920   
921   if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {    
922     GstTagInfo *info = gst_tag_lookup (g_quark_from_string (tag));
923     /* must be there or lists aren't allowed */
924     g_assert (info->merge_func);
925     info->merge_func (dest, src);
926   } else {
927     g_value_init (dest, G_VALUE_TYPE (src));
928     g_value_copy (src, dest);
929   }
930   return TRUE;
931 }
932
933 /***** evil macros to get all the gst_tag_list_get_*() functions right *****/
934
935 #define TAG_MERGE_FUNCS(name,type)                                              \
936 gboolean                                                                        \
937 gst_tag_list_get_ ## name (const GstTagList *list, const gchar *tag,            \
938                            type *value)                                         \
939 {                                                                               \
940   GValue v = { 0, };                                                            \
941                                                                                 \
942   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);                         \
943   g_return_val_if_fail (tag != NULL, FALSE);                                    \
944   g_return_val_if_fail (value != NULL, FALSE);                                  \
945                                                                                 \
946   if (!gst_tag_list_copy_value (&v, list, tag))                                 \
947       return FALSE;                                                             \
948   *value = COPY_FUNC (g_value_get_ ## name (&v));                               \
949   g_value_unset (&v);                                                           \
950   return TRUE;                                                                  \
951 }                                                                               \
952                                                                                 \
953 gboolean                                                                        \
954 gst_tag_list_get_ ## name ## _index (const GstTagList *list, const gchar *tag,  \
955                            guint index, type *value)                            \
956 {                                                                               \
957   const GValue *v;                                                              \
958                                                                                 \
959   g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE);                         \
960   g_return_val_if_fail (tag != NULL, FALSE);                                    \
961   g_return_val_if_fail (value != NULL, FALSE);                                  \
962                                                                                 \
963   if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL)            \
964       return FALSE;                                                             \
965   *value = COPY_FUNC (g_value_get_ ## name (v));                                \
966   return TRUE;                                                                  \
967 }
968
969 #define COPY_FUNC /**/
970 TAG_MERGE_FUNCS (char, gchar)
971 TAG_MERGE_FUNCS (uchar, guchar)
972 TAG_MERGE_FUNCS (boolean, gboolean)
973 TAG_MERGE_FUNCS (int, gint)
974 TAG_MERGE_FUNCS (uint, guint)
975 TAG_MERGE_FUNCS (long, glong)
976 TAG_MERGE_FUNCS (ulong, gulong)
977 TAG_MERGE_FUNCS (int64, gint64)
978 TAG_MERGE_FUNCS (uint64, guint64)
979 TAG_MERGE_FUNCS (float, gfloat)
980 TAG_MERGE_FUNCS (double, gdouble)
981 #undef COPY_FUNC
982   
983 #define COPY_FUNC g_strdup
984 TAG_MERGE_FUNCS (string, gchar *)