source: trunk/third/gstreamer/gst/gsttag.c @ 21448

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