Merge remote-tracking branch 'origin/master' into 0.11

This commit is contained in:
Tim-Philipp Müller 2011-10-30 09:31:39 +00:00
commit 002446820e
6 changed files with 165 additions and 35 deletions

View file

@ -2448,6 +2448,7 @@ gst_tag_list_new_full
gst_tag_list_new_full_valist gst_tag_list_new_full_valist
gst_is_tag_list gst_is_tag_list
gst_tag_list_is_empty gst_tag_list_is_empty
gst_tag_list_is_equal
gst_tag_list_copy gst_tag_list_copy
gst_tag_list_insert gst_tag_list_insert
gst_tag_list_merge gst_tag_list_merge

View file

@ -2964,6 +2964,9 @@ gst_structure_is_equal (const GstStructure * structure1,
g_return_val_if_fail (GST_IS_STRUCTURE (structure1), FALSE); g_return_val_if_fail (GST_IS_STRUCTURE (structure1), FALSE);
g_return_val_if_fail (GST_IS_STRUCTURE (structure2), FALSE); g_return_val_if_fail (GST_IS_STRUCTURE (structure2), FALSE);
if (G_UNLIKELY (structure1 == structure2))
return TRUE;
if (structure1->name != structure2->name) { if (structure1->name != structure2->name) {
return FALSE; return FALSE;
} }

View file

@ -35,6 +35,7 @@
#endif #endif
#include "gst_private.h" #include "gst_private.h"
#include "math-compat.h"
#include "gst-i18n-lib.h" #include "gst-i18n-lib.h"
#include "gsttaglist.h" #include "gsttaglist.h"
#include "gstinfo.h" #include "gstinfo.h"
@ -60,11 +61,13 @@ typedef struct
GstTagMergeFunc merge_func; /* functions to merge the values */ GstTagMergeFunc merge_func; /* functions to merge the values */
GstTagFlag flag; /* type of tag */ GstTagFlag flag; /* type of tag */
GQuark name_quark; /* quark for the name */
} }
GstTagInfo; GstTagInfo;
static GMutex *__tag_mutex; static GMutex *__tag_mutex;
/* tags hash table: maps tag name string => GstTagInfo */
static GHashTable *__tags; static GHashTable *__tags;
#define TAG_LOCK g_mutex_lock (__tag_mutex) #define TAG_LOCK g_mutex_lock (__tag_mutex)
@ -92,7 +95,7 @@ void
_priv_gst_tag_initialize (void) _priv_gst_tag_initialize (void)
{ {
__tag_mutex = g_mutex_new (); __tag_mutex = g_mutex_new ();
__tags = g_hash_table_new (g_direct_hash, g_direct_equal); __tags = g_hash_table_new (g_str_hash, g_str_equal);
gst_tag_register (GST_TAG_TITLE, GST_TAG_FLAG_META, gst_tag_register (GST_TAG_TITLE, GST_TAG_FLAG_META,
G_TYPE_STRING, G_TYPE_STRING,
_("title"), _("commonly used title"), gst_tag_merge_strings_with_comma); _("title"), _("commonly used title"), gst_tag_merge_strings_with_comma);
@ -417,12 +420,12 @@ gst_tag_merge_strings_with_comma (GValue * dest, const GValue * src)
} }
static GstTagInfo * static GstTagInfo *
gst_tag_lookup (GQuark entry) gst_tag_lookup (const gchar * tag_name)
{ {
GstTagInfo *ret; GstTagInfo *ret;
TAG_LOCK; TAG_LOCK;
ret = g_hash_table_lookup (__tags, GUINT_TO_POINTER (entry)); ret = g_hash_table_lookup (__tags, (gpointer) tag_name);
TAG_UNLOCK; TAG_UNLOCK;
return ret; return ret;
@ -463,16 +466,15 @@ void
gst_tag_register (const gchar * name, GstTagFlag flag, GType type, gst_tag_register (const gchar * name, GstTagFlag flag, GType type,
const gchar * nick, const gchar * blurb, GstTagMergeFunc func) const gchar * nick, const gchar * blurb, GstTagMergeFunc func)
{ {
GQuark key;
GstTagInfo *info; GstTagInfo *info;
gchar *name_dup;
g_return_if_fail (name != NULL); g_return_if_fail (name != NULL);
g_return_if_fail (nick != NULL); g_return_if_fail (nick != NULL);
g_return_if_fail (blurb != NULL); g_return_if_fail (blurb != NULL);
g_return_if_fail (type != 0 && type != GST_TYPE_LIST); g_return_if_fail (type != 0 && type != GST_TYPE_LIST);
key = g_quark_from_string (name); info = gst_tag_lookup (name);
info = gst_tag_lookup (key);
if (info) { if (info) {
g_return_if_fail (info->type == type); g_return_if_fail (info->type == type);
@ -486,8 +488,13 @@ gst_tag_register (const gchar * name, GstTagFlag flag, GType type,
info->blurb = g_strdup (blurb); info->blurb = g_strdup (blurb);
info->merge_func = func; info->merge_func = func;
/* we make a copy for the hash table anyway, which will stay around, so
* can use that for the quark table too */
name_dup = g_strdup (name);
info->name_quark = g_quark_from_static_string (name_dup);
TAG_LOCK; TAG_LOCK;
g_hash_table_insert (__tags, GUINT_TO_POINTER (key), info); g_hash_table_insert (__tags, (gpointer) name_dup, info);
TAG_UNLOCK; TAG_UNLOCK;
} }
@ -504,7 +511,7 @@ gst_tag_exists (const gchar * tag)
{ {
g_return_val_if_fail (tag != NULL, FALSE); g_return_val_if_fail (tag != NULL, FALSE);
return gst_tag_lookup (g_quark_from_string (tag)) != NULL; return gst_tag_lookup (tag) != NULL;
} }
/** /**
@ -521,7 +528,7 @@ gst_tag_get_type (const gchar * tag)
GstTagInfo *info; GstTagInfo *info;
g_return_val_if_fail (tag != NULL, 0); g_return_val_if_fail (tag != NULL, 0);
info = gst_tag_lookup (g_quark_from_string (tag)); info = gst_tag_lookup (tag);
g_return_val_if_fail (info != NULL, 0); g_return_val_if_fail (info != NULL, 0);
return info->type; return info->type;
@ -542,7 +549,7 @@ gst_tag_get_nick (const gchar * tag)
GstTagInfo *info; GstTagInfo *info;
g_return_val_if_fail (tag != NULL, NULL); g_return_val_if_fail (tag != NULL, NULL);
info = gst_tag_lookup (g_quark_from_string (tag)); info = gst_tag_lookup (tag);
g_return_val_if_fail (info != NULL, NULL); g_return_val_if_fail (info != NULL, NULL);
return info->nick; return info->nick;
@ -563,7 +570,7 @@ gst_tag_get_description (const gchar * tag)
GstTagInfo *info; GstTagInfo *info;
g_return_val_if_fail (tag != NULL, NULL); g_return_val_if_fail (tag != NULL, NULL);
info = gst_tag_lookup (g_quark_from_string (tag)); info = gst_tag_lookup (tag);
g_return_val_if_fail (info != NULL, NULL); g_return_val_if_fail (info != NULL, NULL);
return info->blurb; return info->blurb;
@ -583,7 +590,7 @@ gst_tag_get_flag (const gchar * tag)
GstTagInfo *info; GstTagInfo *info;
g_return_val_if_fail (tag != NULL, GST_TAG_FLAG_UNDEFINED); g_return_val_if_fail (tag != NULL, GST_TAG_FLAG_UNDEFINED);
info = gst_tag_lookup (g_quark_from_string (tag)); info = gst_tag_lookup (tag);
g_return_val_if_fail (info != NULL, GST_TAG_FLAG_UNDEFINED); g_return_val_if_fail (info != NULL, GST_TAG_FLAG_UNDEFINED);
return info->flag; return info->flag;
@ -604,7 +611,7 @@ gst_tag_is_fixed (const gchar * tag)
GstTagInfo *info; GstTagInfo *info;
g_return_val_if_fail (tag != NULL, FALSE); g_return_val_if_fail (tag != NULL, FALSE);
info = gst_tag_lookup (g_quark_from_string (tag)); info = gst_tag_lookup (tag);
g_return_val_if_fail (info != NULL, FALSE); g_return_val_if_fail (info != NULL, FALSE);
return info->merge_func == NULL; return info->merge_func == NULL;
@ -709,6 +716,77 @@ gst_tag_list_is_empty (const GstTagList * list)
return (gst_structure_n_fields ((GstStructure *) list) == 0); return (gst_structure_n_fields ((GstStructure *) list) == 0);
} }
static gboolean
gst_tag_list_fields_equal (const GValue * value1, const GValue * value2)
{
gdouble d1, d2;
if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL)
return TRUE;
/* fields not equal: add some tolerance for doubles, otherwise bail out */
if (!G_VALUE_HOLDS_DOUBLE (value1) || !G_VALUE_HOLDS_DOUBLE (value2))
return FALSE;
d1 = g_value_get_double (value1);
d2 = g_value_get_double (value2);
/* This will only work for 'normal' values and values around 0,
* which should be good enough for our purposes here
* FIXME: maybe add this to gst_value_compare_double() ? */
return (fabs (d1 - d2) < 0.0000001);
}
/**
* gst_tag_list_is_equal:
* @list1: a #GstTagList.
* @list2: a #GstTagList.
*
* Checks if the two given taglists are equal.
*
* Returns: TRUE if the taglists are equal, otherwise FALSE
*
* Since: 0.10.36
*/
gboolean
gst_tag_list_is_equal (const GstTagList * list1, const GstTagList * list2)
{
const GstStructure *s1, *s2;
gint num_fields1, num_fields2, i;
g_return_val_if_fail (GST_IS_TAG_LIST (list1), FALSE);
g_return_val_if_fail (GST_IS_TAG_LIST (list2), FALSE);
/* we don't just use gst_structure_is_equal() here so we can add some
* tolerance for doubles, though maybe we should just add that to
* gst_value_compare_double() as well? */
s1 = (const GstStructure *) list1;
s2 = (const GstStructure *) list2;
num_fields1 = gst_structure_n_fields (s1);
num_fields2 = gst_structure_n_fields (s2);
if (num_fields1 != num_fields2)
return FALSE;
for (i = 0; i < num_fields1; i++) {
const GValue *value1, *value2;
const gchar *tag_name;
tag_name = gst_structure_nth_field_name (s1, i);
value1 = gst_structure_get_value (s1, tag_name);
value2 = gst_structure_get_value (s2, tag_name);
if (value2 == NULL)
return FALSE;
if (!gst_tag_list_fields_equal (value1, value2))
return FALSE;
}
return TRUE;
}
/** /**
* gst_is_tag_list: * gst_is_tag_list:
* @p: Object that might be a taglist * @p: Object that might be a taglist
@ -736,35 +814,38 @@ GstTagCopyData;
static void static void
gst_tag_list_add_value_internal (GstStructure * list, GstTagMergeMode mode, gst_tag_list_add_value_internal (GstStructure * list, GstTagMergeMode mode,
GQuark tag, const GValue * value, GstTagInfo * info) const gchar * tag, const GValue * value, GstTagInfo * info)
{ {
const GValue *value2; const GValue *value2;
GQuark tag_quark;
if (info == NULL) { if (info == NULL) {
info = gst_tag_lookup (tag); info = gst_tag_lookup (tag);
if (G_UNLIKELY (info == NULL)) { if (G_UNLIKELY (info == NULL)) {
g_warning ("unknown tag '%s'", g_quark_to_string (tag)); g_warning ("unknown tag '%s'", tag);
return; return;
} }
} }
tag_quark = info->name_quark;
if (info->merge_func if (info->merge_func
&& (value2 = gst_structure_id_get_value (list, tag)) != NULL) { && (value2 = gst_structure_id_get_value (list, tag_quark)) != NULL) {
GValue dest = { 0, }; GValue dest = { 0, };
switch (mode) { switch (mode) {
case GST_TAG_MERGE_REPLACE_ALL: case GST_TAG_MERGE_REPLACE_ALL:
case GST_TAG_MERGE_REPLACE: case GST_TAG_MERGE_REPLACE:
gst_structure_id_set_value (list, tag, value); gst_structure_id_set_value (list, tag_quark, value);
break; break;
case GST_TAG_MERGE_PREPEND: case GST_TAG_MERGE_PREPEND:
gst_value_list_merge (&dest, value, value2); gst_value_list_merge (&dest, value, value2);
gst_structure_id_set_value (list, tag, &dest); gst_structure_id_set_value (list, tag_quark, &dest);
g_value_unset (&dest); g_value_unset (&dest);
break; break;
case GST_TAG_MERGE_APPEND: case GST_TAG_MERGE_APPEND:
gst_value_list_merge (&dest, value2, value); gst_value_list_merge (&dest, value2, value);
gst_structure_id_set_value (list, tag, &dest); gst_structure_id_set_value (list, tag_quark, &dest);
g_value_unset (&dest); g_value_unset (&dest);
break; break;
case GST_TAG_MERGE_KEEP: case GST_TAG_MERGE_KEEP:
@ -778,13 +859,13 @@ gst_tag_list_add_value_internal (GstStructure * list, GstTagMergeMode mode,
switch (mode) { switch (mode) {
case GST_TAG_MERGE_APPEND: case GST_TAG_MERGE_APPEND:
case GST_TAG_MERGE_KEEP: case GST_TAG_MERGE_KEEP:
if (gst_structure_id_get_value (list, tag) != NULL) if (gst_structure_id_get_value (list, tag_quark) != NULL)
break; break;
/* fall through */ /* fall through */
case GST_TAG_MERGE_REPLACE_ALL: case GST_TAG_MERGE_REPLACE_ALL:
case GST_TAG_MERGE_REPLACE: case GST_TAG_MERGE_REPLACE:
case GST_TAG_MERGE_PREPEND: case GST_TAG_MERGE_PREPEND:
gst_structure_id_set_value (list, tag, value); gst_structure_id_set_value (list, tag_quark, value);
break; break;
case GST_TAG_MERGE_KEEP_ALL: case GST_TAG_MERGE_KEEP_ALL:
break; break;
@ -796,10 +877,13 @@ gst_tag_list_add_value_internal (GstStructure * list, GstTagMergeMode mode,
} }
static gboolean static gboolean
gst_tag_list_copy_foreach (GQuark tag, const GValue * value, gpointer user_data) gst_tag_list_copy_foreach (GQuark tag_quark, const GValue * value,
gpointer user_data)
{ {
GstTagCopyData *copy = (GstTagCopyData *) user_data; GstTagCopyData *copy = (GstTagCopyData *) user_data;
const gchar *tag;
tag = g_quark_to_string (tag_quark);
gst_tag_list_add_value_internal (copy->list, copy->mode, tag, value, NULL); gst_tag_list_add_value_internal (copy->list, copy->mode, tag, value, NULL);
return TRUE; return TRUE;
@ -991,7 +1075,6 @@ gst_tag_list_add_valist (GstTagList * list, GstTagMergeMode mode,
const gchar * tag, va_list var_args) const gchar * tag, va_list var_args)
{ {
GstTagInfo *info; GstTagInfo *info;
GQuark quark;
gchar *error = NULL; gchar *error = NULL;
g_return_if_fail (GST_IS_TAG_LIST (list)); g_return_if_fail (GST_IS_TAG_LIST (list));
@ -1005,8 +1088,7 @@ gst_tag_list_add_valist (GstTagList * list, GstTagMergeMode mode,
while (tag != NULL) { while (tag != NULL) {
GValue value = { 0, }; GValue value = { 0, };
quark = g_quark_from_string (tag); info = gst_tag_lookup (tag);
info = gst_tag_lookup (quark);
if (G_UNLIKELY (info == NULL)) { if (G_UNLIKELY (info == NULL)) {
g_warning ("unknown tag '%s'", tag); g_warning ("unknown tag '%s'", tag);
return; return;
@ -1020,7 +1102,7 @@ gst_tag_list_add_valist (GstTagList * list, GstTagMergeMode mode,
*/ */
return; return;
} }
gst_tag_list_add_value_internal (list, mode, quark, &value, info); gst_tag_list_add_value_internal (list, mode, tag, &value, info);
g_value_unset (&value); g_value_unset (&value);
tag = va_arg (var_args, gchar *); tag = va_arg (var_args, gchar *);
} }
@ -1039,8 +1121,6 @@ void
gst_tag_list_add_valist_values (GstTagList * list, GstTagMergeMode mode, gst_tag_list_add_valist_values (GstTagList * list, GstTagMergeMode mode,
const gchar * tag, va_list var_args) const gchar * tag, va_list var_args)
{ {
GQuark quark;
g_return_if_fail (GST_IS_TAG_LIST (list)); g_return_if_fail (GST_IS_TAG_LIST (list));
g_return_if_fail (GST_TAG_MODE_IS_VALID (mode)); g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
g_return_if_fail (tag != NULL); g_return_if_fail (tag != NULL);
@ -1050,10 +1130,15 @@ gst_tag_list_add_valist_values (GstTagList * list, GstTagMergeMode mode,
} }
while (tag != NULL) { while (tag != NULL) {
quark = g_quark_from_string (tag); GstTagInfo *info;
g_return_if_fail (gst_tag_lookup (quark) != NULL);
gst_tag_list_add_value_internal (list, mode, quark, va_arg (var_args, info = gst_tag_lookup (tag);
GValue *), NULL); if (G_UNLIKELY (info == NULL)) {
g_warning ("unknown tag '%s'", tag);
return;
}
gst_tag_list_add_value_internal (list, mode, tag, va_arg (var_args,
GValue *), info);
tag = va_arg (var_args, gchar *); tag = va_arg (var_args, gchar *);
} }
} }
@ -1077,8 +1162,7 @@ gst_tag_list_add_value (GstTagList * list, GstTagMergeMode mode,
g_return_if_fail (GST_TAG_MODE_IS_VALID (mode)); g_return_if_fail (GST_TAG_MODE_IS_VALID (mode));
g_return_if_fail (tag != NULL); g_return_if_fail (tag != NULL);
gst_tag_list_add_value_internal (list, mode, g_quark_from_string (tag), gst_tag_list_add_value_internal (list, mode, tag, value, NULL);
value, NULL);
} }
/** /**
@ -1206,7 +1290,7 @@ gst_tag_list_copy_value (GValue * dest, const GstTagList * list,
return FALSE; return FALSE;
if (G_VALUE_TYPE (src) == GST_TYPE_LIST) { if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
GstTagInfo *info = gst_tag_lookup (g_quark_from_string (tag)); GstTagInfo *info = gst_tag_lookup (tag);
if (!info) if (!info)
return FALSE; return FALSE;

View file

@ -218,6 +218,8 @@ GstTagList * gst_tag_list_new_full_valist (va_list var_args);
gboolean gst_is_tag_list (gconstpointer p); gboolean gst_is_tag_list (gconstpointer p);
GstTagList * gst_tag_list_copy (const GstTagList * list); GstTagList * gst_tag_list_copy (const GstTagList * list);
gboolean gst_tag_list_is_empty (const GstTagList * list); gboolean gst_tag_list_is_empty (const GstTagList * list);
gboolean gst_tag_list_is_equal (const GstTagList * list1,
const GstTagList * list2);
void gst_tag_list_insert (GstTagList * into, void gst_tag_list_insert (GstTagList * into,
const GstTagList * from, const GstTagList * from,
GstTagMergeMode mode); GstTagMergeMode mode);

View file

@ -281,6 +281,7 @@ GST_START_TEST (test_date_tags)
tag_list2 = gst_structure_from_string (str, NULL); tag_list2 = gst_structure_from_string (str, NULL);
fail_if (tag_list2 == NULL); fail_if (tag_list2 == NULL);
fail_if (!gst_tag_list_get_date (tag_list2, GST_TAG_DATE, &date2)); fail_if (!gst_tag_list_get_date (tag_list2, GST_TAG_DATE, &date2));
fail_unless (gst_tag_list_is_equal (tag_list2, tag_list));
gst_tag_list_free (tag_list2); gst_tag_list_free (tag_list2);
g_free (str); g_free (str);
@ -452,6 +453,43 @@ GST_START_TEST (test_merge_strings_with_comma)
GST_END_TEST; GST_END_TEST;
GST_START_TEST (test_equal)
{
GstTagList *tags, *tags2;
tags = gst_tag_list_new ();
gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_ARTIST, "Foo", NULL);
gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_ARTIST, "Bar", NULL);
gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_ARTIST, "Yay", NULL);
tags2 = gst_tag_list_new ();
fail_unless (!gst_tag_list_is_equal (tags2, tags));
gst_tag_list_add (tags2, GST_TAG_MERGE_APPEND, GST_TAG_ARTIST, "Yay", NULL);
fail_unless (!gst_tag_list_is_equal (tags2, tags));
gst_tag_list_add (tags2, GST_TAG_MERGE_APPEND, GST_TAG_ARTIST, "Bar", NULL);
fail_unless (!gst_tag_list_is_equal (tags2, tags));
gst_tag_list_add (tags2, GST_TAG_MERGE_APPEND, GST_TAG_ARTIST, "Foo", NULL);
fail_unless (gst_tag_list_is_equal (tags2, tags));
gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_REFERENCE_LEVEL,
9.87654321, NULL);
fail_unless (!gst_tag_list_is_equal (tags2, tags));
gst_tag_list_add (tags2, GST_TAG_MERGE_APPEND, GST_TAG_REFERENCE_LEVEL,
9.87654320, NULL);
/* want these two double values to be equal despite minor differences */
fail_unless (gst_tag_list_is_equal (tags2, tags));
/* want this to be unequal though, difference too large */
gst_tag_list_add (tags2, GST_TAG_MERGE_REPLACE, GST_TAG_REFERENCE_LEVEL,
9.87654310, NULL);
fail_unless (!gst_tag_list_is_equal (tags2, tags));
gst_tag_list_free (tags);
gst_tag_list_free (tags2);
}
GST_END_TEST;
static Suite * static Suite *
gst_tag_suite (void) gst_tag_suite (void)
{ {
@ -469,6 +507,7 @@ gst_tag_suite (void)
tcase_add_test (tc_chain, test_buffer_tags); tcase_add_test (tc_chain, test_buffer_tags);
tcase_add_test (tc_chain, test_empty_tags); tcase_add_test (tc_chain, test_empty_tags);
tcase_add_test (tc_chain, test_new_full); tcase_add_test (tc_chain, test_new_full);
tcase_add_test (tc_chain, test_equal);
return s; return s;
} }

View file

@ -1083,6 +1083,7 @@ EXPORTS
gst_tag_list_get_value_index gst_tag_list_get_value_index
gst_tag_list_insert gst_tag_list_insert
gst_tag_list_is_empty gst_tag_list_is_empty
gst_tag_list_is_equal
gst_tag_list_merge gst_tag_list_merge
gst_tag_list_new gst_tag_list_new
gst_tag_list_new_full gst_tag_list_new_full