diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index c29ac0531a..5373972e84 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -2368,6 +2368,7 @@ gst_tag_list_new_full gst_tag_list_new_full_valist gst_is_tag_list gst_tag_list_is_empty +gst_tag_list_is_equal gst_tag_list_copy gst_tag_list_insert gst_tag_list_merge diff --git a/gst/gsttaglist.c b/gst/gsttaglist.c index 385e3b0198..b46a962110 100644 --- a/gst/gsttaglist.c +++ b/gst/gsttaglist.c @@ -35,6 +35,7 @@ #endif #include "gst_private.h" +#include "math-compat.h" #include "gst-i18n-lib.h" #include "gsttaglist.h" #include "gstinfo.h" @@ -709,6 +710,77 @@ gst_tag_list_is_empty (const GstTagList * list) 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: * @p: Object that might be a taglist diff --git a/gst/gsttaglist.h b/gst/gsttaglist.h index e40d52ab0e..cc0601fd9f 100644 --- a/gst/gsttaglist.h +++ b/gst/gsttaglist.h @@ -218,6 +218,8 @@ GstTagList * gst_tag_list_new_full_valist (va_list var_args); gboolean gst_is_tag_list (gconstpointer p); GstTagList * gst_tag_list_copy (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, const GstTagList * from, GstTagMergeMode mode); diff --git a/tests/check/gst/gsttag.c b/tests/check/gst/gsttag.c index ecf8223da7..7efcf2cd60 100644 --- a/tests/check/gst/gsttag.c +++ b/tests/check/gst/gsttag.c @@ -281,6 +281,7 @@ GST_START_TEST (test_date_tags) tag_list2 = gst_structure_from_string (str, NULL); fail_if (tag_list2 == NULL); 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); g_free (str); @@ -452,6 +453,43 @@ GST_START_TEST (test_merge_strings_with_comma) 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 * 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_empty_tags); tcase_add_test (tc_chain, test_new_full); + tcase_add_test (tc_chain, test_equal); return s; } diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index a15e0e9cee..e0f60af128 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -1083,6 +1083,7 @@ EXPORTS gst_tag_list_get_value_index gst_tag_list_insert gst_tag_list_is_empty + gst_tag_list_is_equal gst_tag_list_merge gst_tag_list_new gst_tag_list_new_full