diff -r 4b0c6ed43234 -r 8e837d1bf446 gstreamer_core/gst/gsttaglist.c --- a/gstreamer_core/gst/gsttaglist.c Wed Mar 24 17:58:42 2010 -0500 +++ b/gstreamer_core/gst/gsttaglist.c Wed Mar 24 18:04:17 2010 -0500 @@ -25,7 +25,9 @@ * * List of tags and values used to describe media metadata. * - * Last reviewed on 2005-11-23 (0.9.5) + * Strings must be in ASCII or UTF-8 encoding. No other encodings are allowed. + * + * Last reviewed on 2009-06-09 (0.10.23) */ #ifdef HAVE_CONFIG_H @@ -38,6 +40,7 @@ #include "gstinfo.h" #include "gstvalue.h" #include "gstbuffer.h" +#include "gstquark.h" #include #include @@ -64,9 +67,8 @@ } GstTagInfo; -#define TAGLIST "taglist" -static GQuark gst_tag_list_quark; static GMutex *__tag_mutex; + static GHashTable *__tags; #define TAG_LOCK g_mutex_lock (__tag_mutex) @@ -75,6 +77,7 @@ #ifdef __SYMBIAN32__ EXPORT_C #endif + GType gst_tag_list_get_type (void) { @@ -100,7 +103,6 @@ void _gst_tag_initialize (void) { - gst_tag_list_quark = g_quark_from_static_string (TAGLIST); __tag_mutex = g_mutex_new (); __tags = g_hash_table_new (g_direct_hash, g_direct_equal); gst_tag_register (GST_TAG_TITLE, GST_TAG_FLAG_META, @@ -162,18 +164,21 @@ gst_tag_register (GST_TAG_LOCATION, GST_TAG_FLAG_META, G_TYPE_STRING, _("location"), - _("original location of file as a URI"), + _ + ("Origin of media as a URI (location, where the original of the file or stream is hosted)"), gst_tag_merge_strings_with_comma); - gst_tag_register (GST_TAG_DESCRIPTION, GST_TAG_FLAG_META, + gst_tag_register (GST_TAG_HOMEPAGE, GST_TAG_FLAG_META, G_TYPE_STRING, - _("description"), - _("short text describing the content of the data"), + _("homepage"), + _ + ("Homepage for this media (i.e. artist or movie homepage)"), gst_tag_merge_strings_with_comma); - gst_tag_register (GST_TAG_VERSION, GST_TAG_FLAG_META, - G_TYPE_STRING, _("version"), _("version of this data"), NULL); - gst_tag_register (GST_TAG_ISRC, GST_TAG_FLAG_META, - G_TYPE_STRING, - _("ISRC"), + gst_tag_register (GST_TAG_DESCRIPTION, GST_TAG_FLAG_META, G_TYPE_STRING, + _("description"), _("short text describing the content of the data"), + gst_tag_merge_strings_with_comma); + gst_tag_register (GST_TAG_VERSION, GST_TAG_FLAG_META, G_TYPE_STRING, + _("version"), _("version of this data"), NULL); + gst_tag_register (GST_TAG_ISRC, GST_TAG_FLAG_META, G_TYPE_STRING, _("ISRC"), _ ("International Standard Recording Code - see http://www.ifpi.org/isrc/"), NULL); @@ -214,6 +219,12 @@ gst_tag_register (GST_TAG_AUDIO_CODEC, GST_TAG_FLAG_ENCODED, G_TYPE_STRING, _("audio codec"), _("codec the audio data is stored in"), NULL); + gst_tag_register (GST_TAG_SUBTITLE_CODEC, GST_TAG_FLAG_ENCODED, + G_TYPE_STRING, + _("subtitle codec"), _("codec the subtitle data is stored in"), NULL); + gst_tag_register (GST_TAG_CONTAINER_FORMAT, GST_TAG_FLAG_ENCODED, + G_TYPE_STRING, _("container format"), + _("container format the data is stored in"), NULL); gst_tag_register (GST_TAG_BITRATE, GST_TAG_FLAG_ENCODED, G_TYPE_UINT, _("bitrate"), _("exact or average bitrate in bits/s"), NULL); gst_tag_register (GST_TAG_NOMINAL_BITRATE, GST_TAG_FLAG_ENCODED, @@ -249,9 +260,34 @@ _("image"), _("image related to this stream"), gst_tag_merge_use_first); gst_tag_register (GST_TAG_PREVIEW_IMAGE, GST_TAG_FLAG_META, GST_TYPE_BUFFER, _("preview image"), _("preview image related to this stream"), NULL); + gst_tag_register (GST_TAG_ATTACHMENT, GST_TAG_FLAG_META, GST_TYPE_BUFFER, + _("attachment"), _("file attached to this stream"), + gst_tag_merge_use_first); gst_tag_register (GST_TAG_BEATS_PER_MINUTE, GST_TAG_FLAG_META, G_TYPE_DOUBLE, _("beats per minute"), _("number of beats per minute in audio"), NULL); - + gst_tag_register (GST_TAG_KEYWORDS, GST_TAG_FLAG_META, G_TYPE_STRING, + _("keywords"), _("comma separated keywords describing the content"), + gst_tag_merge_strings_with_comma); + gst_tag_register (GST_TAG_GEO_LOCATION_NAME, GST_TAG_FLAG_META, G_TYPE_STRING, + _("geo location name"), + _ + ("human readable descriptive location of where the media has been recorded or produced"), + NULL); + gst_tag_register (GST_TAG_GEO_LOCATION_LATITUDE, GST_TAG_FLAG_META, + G_TYPE_DOUBLE, _("geo location latitude"), + _ + ("geo latitude location of where the media has been recorded or produced in degrees according to WGS84 (zero at the equator, negative values for southern latitudes)"), + NULL); + gst_tag_register (GST_TAG_GEO_LOCATION_LONGITUDE, GST_TAG_FLAG_META, + G_TYPE_DOUBLE, _("geo location longitude"), + _ + ("geo longitude location of where the media has been recorded or produced in degrees according to WGS84 (zero at the prime meridian in Greenwich/UK, negative values for western longitudes)"), + NULL); + gst_tag_register (GST_TAG_GEO_LOCATION_ELEVATION, GST_TAG_FLAG_META, + G_TYPE_DOUBLE, _("geo location elevation"), + _ + ("geo elevation of where the media has been recorded or produced in meters according to WGS84 (zero is average sea level)"), + NULL); } /** @@ -292,6 +328,7 @@ gst_tag_merge_strings_with_comma (GValue * dest, const GValue * src) { GString *str; + gint i, count; count = gst_value_list_get_size (src); @@ -305,9 +342,10 @@ } g_value_init (dest, G_TYPE_STRING); - g_value_set_string_take_ownership (dest, str->str); + g_value_take_string (dest, str->str); g_string_free (str, FALSE); } + static GstTagInfo * gst_tag_lookup (GQuark entry) { @@ -360,6 +398,7 @@ const gchar * nick, const gchar * blurb, GstTagMergeFunc func) { GQuark key; + GstTagInfo *info; g_return_if_fail (name != NULL); @@ -544,7 +583,76 @@ GstTagList * gst_tag_list_new (void) { - return GST_TAG_LIST (gst_structure_new (TAGLIST, NULL)); + return GST_TAG_LIST (gst_structure_id_empty_new (GST_QUARK (TAGLIST))); +} + +/** + * gst_tag_list_new_full: + * @tag: tag + * @...: NULL-terminated list of values to set + * + * Creates a new taglist and appends the values for the given tags. It expects + * tag-value pairs like gst_tag_list_add(), and a NULL terminator after the + * last pair. The type of the values is implicit and is documented in the API + * reference, but can also be queried at runtime with gst_tag_get_type(). It + * is an error to pass a value of a type not matching the tag type into this + * function. The tag list will make copies of any arguments passed + * (e.g. strings, buffers). + * + * Returns: a new #GstTagList. Free with gst_tag_list_free() when no longer + * needed. + * + * Since: 0.10.24 + */ +/* FIXME 0.11: rename gst_tag_list_new_full to _new and _new to _new_empty */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +GstTagList * +gst_tag_list_new_full (const gchar * tag, ...) +{ + GstTagList *list; + va_list args; + + g_return_val_if_fail (tag != NULL, NULL); + + list = gst_tag_list_new (); + va_start (args, tag); + gst_tag_list_add_valist (list, GST_TAG_MERGE_APPEND, tag, args); + va_end (args); + + return list; +} + +/** + * gst_tag_list_new_full_valist: + * @var_args: tag / value pairs to set + * + * Just like gst_tag_list_new_full(), only that it takes a va_list argument. + * Useful mostly for language bindings. + * + * Returns: a new #GstTagList. Free with gst_tag_list_free() when no longer + * needed. + * + * Since: 0.10.24 + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +GstTagList * +gst_tag_list_new_full_valist (va_list var_args) +{ + GstTagList *list; + const gchar *tag; + + list = gst_tag_list_new (); + + tag = va_arg (var_args, gchar *); + gst_tag_list_add_valist (list, GST_TAG_MERGE_APPEND, tag, var_args); + + return list; } /** @@ -589,19 +697,22 @@ g_return_val_if_fail (p != NULL, FALSE); - return (GST_IS_STRUCTURE (s) && s->name == gst_tag_list_quark); + return (GST_IS_STRUCTURE (s) && s->name == GST_QUARK (TAGLIST)); } + typedef struct { GstStructure *list; GstTagMergeMode mode; } GstTagCopyData; + static void gst_tag_list_add_value_internal (GstStructure * list, GstTagMergeMode mode, GQuark tag, const GValue * value) { GstTagInfo *info = gst_tag_lookup (tag); + const GValue *value2; g_assert (info != NULL); @@ -652,6 +763,7 @@ } } } + static gboolean gst_tag_list_copy_foreach (GQuark tag, const GValue * value, gpointer user_data) { @@ -668,7 +780,7 @@ * @from: list to merge from * @mode: the mode to use * - * Inserts the tags of the second list into the first list using the given mode. + * Inserts the tags of the @from list into the first list using the given mode. */ #ifdef __SYMBIAN32__ EXPORT_C @@ -732,23 +844,28 @@ gst_tag_list_merge (const GstTagList * list1, const GstTagList * list2, GstTagMergeMode mode) { + GstTagList *list1_cp; + const GstTagList *list2_cp; + g_return_val_if_fail (list1 == NULL || GST_IS_TAG_LIST (list1), NULL); g_return_val_if_fail (list2 == NULL || GST_IS_TAG_LIST (list2), NULL); g_return_val_if_fail (GST_TAG_MODE_IS_VALID (mode), NULL); + /* nothing to merge */ if (!list1 && !list2) { return NULL; - } else if (!list1) { - return gst_tag_list_copy (list2); - } else if (!list2) { - return gst_tag_list_copy (list1); - } else { - GstTagList *ret; + } + + /* create empty list, we need to do this to correctly handling merge modes */ + list1_cp = (list1) ? gst_tag_list_copy (list1) : gst_tag_list_new (); + list2_cp = (list2) ? list2 : gst_tag_list_new (); - ret = gst_tag_list_copy (list1); - gst_tag_list_insert (ret, list2, mode); - return ret; - } + gst_tag_list_insert (list1_cp, list2_cp, mode); + + if (!list2) + gst_tag_list_free ((GstTagList *) list2_cp); + + return list1_cp; } /** @@ -878,6 +995,10 @@ g_return_if_fail (GST_TAG_MODE_IS_VALID (mode)); g_return_if_fail (tag != NULL); + if (mode == GST_TAG_MERGE_REPLACE_ALL) { + gst_structure_remove_all_fields (list); + } + while (tag != NULL) { GValue value = { 0, }; @@ -919,17 +1040,19 @@ gst_tag_list_add_valist_values (GstTagList * list, GstTagMergeMode mode, const gchar * tag, va_list var_args) { - GstTagInfo *info; GQuark quark; g_return_if_fail (GST_IS_TAG_LIST (list)); g_return_if_fail (GST_TAG_MODE_IS_VALID (mode)); g_return_if_fail (tag != NULL); + if (mode == GST_TAG_MERGE_REPLACE_ALL) { + gst_structure_remove_all_fields (list); + } + while (tag != NULL) { quark = g_quark_from_string (tag); - info = gst_tag_lookup (quark); - g_return_if_fail (info != NULL); + g_return_if_fail (gst_tag_lookup (quark) != NULL); gst_tag_list_add_value_internal (list, mode, quark, va_arg (var_args, GValue *)); tag = va_arg (var_args, gchar *); @@ -937,6 +1060,33 @@ } /** + * gst_tag_list_add_value: + * @list: list to set tags in + * @mode: the mode to use + * @tag: tag + * @value: GValue for this tag + * + * Sets the GValue for a given tag using the specified mode. + * + * Since: 0.10.24 + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +void +gst_tag_list_add_value (GstTagList * list, GstTagMergeMode mode, + const gchar * tag, const GValue * value) +{ + g_return_if_fail (GST_IS_TAG_LIST (list)); + g_return_if_fail (GST_TAG_MODE_IS_VALID (mode)); + g_return_if_fail (tag != NULL); + + gst_tag_list_add_value_internal (list, mode, g_quark_from_string (tag), + value); +} + +/** * gst_tag_list_remove_tag: * @list: list to remove tag from * @tag: tag to remove @@ -955,6 +1105,7 @@ gst_structure_remove_field ((GstStructure *) list, tag); } + typedef struct { GstTagForeachFunc func; @@ -962,6 +1113,7 @@ gpointer data; } TagForeachData; + static int structure_foreach_wrapper (GQuark field_id, const GValue * value, gpointer user_data) @@ -1077,6 +1229,9 @@ if (G_VALUE_TYPE (src) == GST_TYPE_LIST) { GstTagInfo *info = gst_tag_lookup (g_quark_from_string (tag)); + if (!info) + return FALSE; + /* must be there or lists aren't allowed */ g_assert (info->merge_func); info->merge_func (dest, src); @@ -1098,7 +1253,7 @@ /***** evil macros to get all the gst_tag_list_get_*() functions right *****/ -#define TAG_MERGE_FUNCS(name,type) \ +#define TAG_MERGE_FUNCS(name,type,ret) \ gboolean \ __declspec(dllexport) gst_tag_list_get_ ## name (const GstTagList *list, const gchar *tag, \ type *value) \ @@ -1113,7 +1268,7 @@ return FALSE; \ *value = COPY_FUNC (g_value_get_ ## name (&v)); \ g_value_unset (&v); \ - return TRUE; \ + return ret; \ } \ \ __declspec(dllexport) gboolean \ @@ -1130,7 +1285,7 @@ if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL) \ return FALSE; \ *value = COPY_FUNC (g_value_get_ ## name (v)); \ - return TRUE; \ + return ret; \ } /* FIXME 0.11: maybe get rid of _get_char*(), _get_uchar*(), _get_long*(), @@ -1163,7 +1318,7 @@ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. */ -TAG_MERGE_FUNCS (char, gchar) +TAG_MERGE_FUNCS (char, gchar, TRUE) /** * gst_tag_list_get_uchar: * @list: a #GstTagList to get the tag from @@ -1189,7 +1344,7 @@ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. */ -TAG_MERGE_FUNCS (uchar, guchar) +TAG_MERGE_FUNCS (uchar, guchar, TRUE) /** * gst_tag_list_get_boolean: * @list: a #GstTagList to get the tag from @@ -1215,7 +1370,7 @@ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. */ -TAG_MERGE_FUNCS (boolean, gboolean) +TAG_MERGE_FUNCS (boolean, gboolean, TRUE) /** * gst_tag_list_get_int: * @list: a #GstTagList to get the tag from @@ -1241,7 +1396,7 @@ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. */ -TAG_MERGE_FUNCS (int, gint) +TAG_MERGE_FUNCS (int, gint, TRUE) /** * gst_tag_list_get_uint: * @list: a #GstTagList to get the tag from @@ -1267,7 +1422,7 @@ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. */ -TAG_MERGE_FUNCS (uint, guint) +TAG_MERGE_FUNCS (uint, guint, TRUE) /** * gst_tag_list_get_long: * @list: a #GstTagList to get the tag from @@ -1293,7 +1448,7 @@ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. */ -TAG_MERGE_FUNCS (long, glong) +TAG_MERGE_FUNCS (long, glong, TRUE) /** * gst_tag_list_get_ulong: * @list: a #GstTagList to get the tag from @@ -1319,7 +1474,7 @@ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. */ -TAG_MERGE_FUNCS (ulong, gulong) +TAG_MERGE_FUNCS (ulong, gulong, TRUE) /** * gst_tag_list_get_int64: * @list: a #GstTagList to get the tag from @@ -1345,7 +1500,7 @@ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. */ -TAG_MERGE_FUNCS (int64, gint64) +TAG_MERGE_FUNCS (int64, gint64, TRUE) /** * gst_tag_list_get_uint64: * @list: a #GstTagList to get the tag from @@ -1371,7 +1526,7 @@ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. */ -TAG_MERGE_FUNCS (uint64, guint64) +TAG_MERGE_FUNCS (uint64, guint64, TRUE) /** * gst_tag_list_get_float: * @list: a #GstTagList to get the tag from @@ -1397,7 +1552,7 @@ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. */ -TAG_MERGE_FUNCS (float, gfloat) +TAG_MERGE_FUNCS (float, gfloat, TRUE) /** * gst_tag_list_get_double: * @list: a #GstTagList to get the tag from @@ -1423,7 +1578,7 @@ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. */ -TAG_MERGE_FUNCS (double, gdouble) +TAG_MERGE_FUNCS (double, gdouble, TRUE) /** * gst_tag_list_get_pointer: * @list: a #GstTagList to get the tag from @@ -1449,7 +1604,7 @@ * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. */ -TAG_MERGE_FUNCS (pointer, gpointer) +TAG_MERGE_FUNCS (pointer, gpointer, (*value != NULL)) #undef COPY_FUNC #define COPY_FUNC g_strdup /** @@ -1465,7 +1620,8 @@ * to retrieve the first string associated with this tag unmodified. * * The resulting string in @value will be in UTF-8 encoding and should be - * freed by the caller using g_free when no longer needed. + * freed by the caller using g_free when no longer needed. Since 0.10.24 the + * returned string is also guaranteed to be non-NULL and non-empty. * * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. @@ -1481,23 +1637,25 @@ * list. * * The resulting string in @value will be in UTF-8 encoding and should be - * freed by the caller using g_free when no longer needed. + * freed by the caller using g_free when no longer needed. Since 0.10.24 the + * returned string is also guaranteed to be non-NULL and non-empty. * * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list. */ -TAG_MERGE_FUNCS (string, gchar *) +TAG_MERGE_FUNCS (string, gchar *, (*value != NULL && **value != '\0')) /** * gst_tag_list_get_date: * @list: a #GstTagList to get the tag from * @tag: tag to read out - * @value: location for the result + * @value: address of a GDate pointer variable to store the result into * - * Copies the contents for the given tag into the value, merging multiple values - * into one if multiple values are associated with the tag. + * Copies the first date for the given tag in the taglist into the variable + * pointed to by @value. Free the date with g_date_free() when it is no longer + * needed. * - * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the + * Returns: TRUE, if a date was copied, FALSE if the tag didn't exist in the * given list or if it was #NULL. */ #ifdef __SYMBIAN32__ @@ -1528,8 +1686,9 @@ * @index: number of entry to read out * @value: location for the result * - * Gets the value that is at the given index for the given tag in the given - * list. + * Gets the date that is at the given index for the given tag in the given + * list and copies it into the variable pointed to by @value. Free the date + * with g_date_free() when it is no longer needed. * * Returns: TRUE, if a value was copied, FALSE if the tag didn't exist in the * given list or if it was #NULL. @@ -1553,3 +1712,75 @@ *value = (GDate *) g_value_dup_boxed (v); return (*value != NULL); } + +/** + * gst_tag_list_get_buffer: + * @list: a #GstTagList to get the tag from + * @tag: tag to read out + * @value: address of a GstBuffer pointer variable to store the result into + * + * Copies the first buffer for the given tag in the taglist into the variable + * pointed to by @value. Free the buffer with gst_buffer_unref() when it is + * no longer needed. + * + * Returns: TRUE, if a buffer was copied, FALSE if the tag didn't exist in the + * given list or if it was #NULL. + * + * Since: 0.10.23 + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +gboolean +gst_tag_list_get_buffer (const GstTagList * list, const gchar * tag, + GstBuffer ** value) +{ + GValue v = { 0, }; + + g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); + g_return_val_if_fail (tag != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + if (!gst_tag_list_copy_value (&v, list, tag)) + return FALSE; + *value = (GstBuffer *) gst_value_dup_mini_object (&v); + g_value_unset (&v); + return (*value != NULL); +} + +/** + * gst_tag_list_get_buffer_index: + * @list: a #GstTagList to get the tag from + * @tag: tag to read out + * @index: number of entry to read out + * @value: address of a GstBuffer pointer variable to store the result into + * + * Gets the buffer that is at the given index for the given tag in the given + * list and copies it into the variable pointed to by @value. Free the buffer + * with gst_buffer_unref() when it is no longer needed. + * + * Returns: TRUE, if a buffer was copied, FALSE if the tag didn't exist in the + * given list or if it was #NULL. + * + * Since: 0.10.23 + */ +#ifdef __SYMBIAN32__ +EXPORT_C +#endif + +gboolean +gst_tag_list_get_buffer_index (const GstTagList * list, + const gchar * tag, guint index, GstBuffer ** value) +{ + const GValue *v; + + g_return_val_if_fail (GST_IS_TAG_LIST (list), FALSE); + g_return_val_if_fail (tag != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + if ((v = gst_tag_list_get_value_index (list, tag, index)) == NULL) + return FALSE; + *value = (GstBuffer *) gst_value_dup_mini_object (v); + return (*value != NULL); +}