/* our fundamental types that are certainly not fixed */
if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE ||
type == GST_TYPE_INT64_RANGE ||
- type == GST_TYPE_LIST || type == GST_TYPE_FRACTION_RANGE) {
+ type == GST_TYPE_LIST || type == GST_TYPE_FRACTION_RANGE ||
+ type == GST_TYPE_STRUCTURE) {
return FALSE;
}
/* other (boxed) types that are fixed */
return TRUE;
}
+static gboolean
+gst_value_is_subset_structure_structure (const GValue * value1,
+ const GValue * value2)
+{
+ const GstStructure *s1, *s2;
+
+ g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (value1), FALSE);
+ g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (value2), FALSE);
+
+ s1 = gst_value_get_structure (value1);
+ s2 = gst_value_get_structure (value2);
+
+ return gst_structure_is_subset (s1, s2);
+}
+
/**
* gst_value_is_subset:
* @value1: a #GValue
} else if (GST_VALUE_HOLDS_FLAG_SET (value1) &&
GST_VALUE_HOLDS_FLAG_SET (value2)) {
return gst_value_is_subset_flagset_flagset (value1, value2);
+ } else if (GST_VALUE_HOLDS_STRUCTURE (value1)
+ && GST_VALUE_HOLDS_STRUCTURE (value2)) {
+ return gst_value_is_subset_structure_structure (value1, value2);
}
/*
return TRUE;
}
+/* iterating over the result taking the union with the other structure's value */
+static gboolean
+structure_field_union_into (GQuark field_id, GValue * val, gpointer user_data)
+{
+ GstStructure *other = user_data;
+ const GValue *other_value;
+ GValue res_value = G_VALUE_INIT;
+
+ other_value = gst_structure_id_get_value (other, field_id);
+ /* no value in the other struct, just keep this value */
+ if (!other_value)
+ return TRUE;
+
+ if (!gst_value_union (&res_value, val, other_value))
+ return FALSE;
+
+ g_value_unset (val);
+ gst_value_init_and_copy (val, &res_value);
+ return TRUE;
+}
+
+/* iterating over the other source structure adding missing values */
+static gboolean
+structure_field_union_from (GQuark field_id, const GValue * other_val,
+ gpointer user_data)
+{
+ GstStructure *result = user_data;
+ const GValue *result_value;
+
+ result_value = gst_structure_id_get_value (result, field_id);
+ if (!result_value)
+ gst_structure_id_set_value (result, field_id, other_val);
+
+ return TRUE;
+}
+
+static gboolean
+gst_value_union_structure_structure (GValue * dest, const GValue * src1,
+ const GValue * src2)
+{
+ const GstStructure *s1, *s2;
+ GstStructure *result;
+ gboolean ret;
+
+ g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (src1), FALSE);
+ g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (src2), FALSE);
+
+ s1 = gst_value_get_structure (src1);
+ s2 = gst_value_get_structure (src2);
+
+ /* Can't join two structures with different names into a single structure */
+ if (!gst_structure_has_name (s1, gst_structure_get_name (s2))) {
+ gst_value_list_concat (dest, src1, src2);
+ return TRUE;
+ }
+
+ result = gst_structure_copy (s1);
+ ret =
+ gst_structure_map_in_place (result, structure_field_union_into,
+ (gpointer) s2);
+ if (!ret)
+ goto out;
+ ret =
+ gst_structure_foreach (s2, structure_field_union_from, (gpointer) result);
+
+ if (ret) {
+ g_value_init (dest, GST_TYPE_STRUCTURE);
+ gst_value_set_structure (dest, result);
+ }
+
+out:
+ gst_structure_free (result);
+ return ret;
+}
+
/****************
* intersection *
****************/
return TRUE;
}
+static gboolean
+gst_value_intersect_structure_structure (GValue * dest,
+ const GValue * src1, const GValue * src2)
+{
+ const GstStructure *s1, *s2;
+ GstStructure *d1;
+
+ s1 = gst_value_get_structure (src1);
+ s2 = gst_value_get_structure (src2);
+
+ d1 = gst_structure_intersect (s1, s2);
+ if (!d1)
+ return FALSE;
+
+ if (dest) {
+ g_value_init (dest, GST_TYPE_STRUCTURE);
+ gst_value_set_structure (dest, d1);
+ }
+
+ gst_structure_free (d1);
+ return TRUE;
+}
+
/***************
* subtraction *
***************/
return TRUE;
}
-
/**************
* comparison *
**************/
/* special cases */
if (mtype == GST_TYPE_LIST || stype == GST_TYPE_LIST)
return TRUE;
+ if (mtype == GST_TYPE_STRUCTURE || stype == GST_TYPE_STRUCTURE)
+ return FALSE;
len = gst_value_subtract_funcs->len;
for (i = 0; i < len; i++) {
return FALSE;
}
+static gboolean
+structure_field_is_fixed (GQuark field_id, const GValue * val,
+ gpointer user_data)
+{
+ return gst_value_is_fixed (val);
+}
+
/**
* gst_value_is_fixed:
* @value: the #GValue to check
} else if (GST_VALUE_HOLDS_FLAG_SET (value)) {
/* Flagsets are only fixed if there are no 'don't care' bits */
return (gst_value_get_flagset_mask (value) == GST_FLAG_SET_MASK_EXACT);
+ } else if (GST_VALUE_HOLDS_STRUCTURE (value)) {
+ return gst_structure_foreach (gst_value_get_structure (value),
+ structure_field_is_fixed, NULL);
}
return gst_type_is_fixed (type);
}
g_value_init (dest, G_VALUE_TYPE (src));
gst_value_set_flagset (dest, flags, GST_FLAG_SET_MASK_EXACT);
return TRUE;
+ } else if (GST_VALUE_HOLDS_STRUCTURE (src)) {
+ const GstStructure *str = (GstStructure *) gst_value_get_structure (src);
+ GstStructure *kid;
+
+ if (!str)
+ return FALSE;
+
+ kid = gst_structure_copy (str);
+ gst_structure_fixate (kid);
+ g_value_init (dest, GST_TYPE_STRUCTURE);
+ gst_value_set_structure (dest, kid);
+ gst_structure_free (kid);
+ return TRUE;
} else {
return FALSE;
}
/* These initial sizes are used for the tables
* below, and save a couple of reallocs at startup */
+
static const gint GST_VALUE_TABLE_DEFAULT_SIZE = 35;
-static const gint GST_VALUE_UNION_TABLE_DEFAULT_SIZE = 3;
-static const gint GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE = 10;
+static const gint GST_VALUE_UNION_TABLE_DEFAULT_SIZE = 4;
+static const gint GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE = 11;
static const gint GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE = 12;
void
gst_value_intersect_fraction_range_fraction_range);
gst_value_register_intersect_func (GST_TYPE_FLAG_SET, GST_TYPE_FLAG_SET,
gst_value_intersect_flagset_flagset);
+ gst_value_register_intersect_func (GST_TYPE_STRUCTURE, GST_TYPE_STRUCTURE,
+ gst_value_intersect_structure_structure);
gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
gst_value_subtract_int_int_range);
gst_value_union_int_range_int_range);
gst_value_register_union_func (GST_TYPE_FLAG_SET, GST_TYPE_FLAG_SET,
gst_value_union_flagset_flagset);
+ gst_value_register_union_func (GST_TYPE_STRUCTURE, GST_TYPE_STRUCTURE,
+ gst_value_union_structure_structure);
#if GST_VERSION_NANO == 1
/* If building from git master, check starting array sizes matched actual size
GST_END_TEST;
+GST_START_TEST (test_structure_basic)
+{
+ GstStructure *s1, *s2;
+ GValue v1 = G_VALUE_INIT, v2 = G_VALUE_INIT;
+
+ /* sanity test */
+ s1 = gst_structure_from_string ("foo,bar=1", NULL);
+ g_value_init (&v1, GST_TYPE_STRUCTURE);
+ gst_value_set_structure (&v1, s1);
+ fail_unless (gst_structure_is_equal (s1, gst_value_get_structure (&v1)));
+
+ s2 = gst_structure_copy (s1);
+ g_value_init (&v2, GST_TYPE_STRUCTURE);
+ gst_value_set_structure (&v2, s2);
+
+ /* can do everything but subtract */
+ fail_unless (gst_value_can_compare (&v1, &v2));
+ fail_unless (gst_value_can_intersect (&v1, &v2));
+ fail_unless (!gst_value_can_subtract (&v1, &v2));
+ fail_unless (gst_value_can_union (&v1, &v2));
+
+ gst_structure_free (s1);
+ gst_structure_free (s2);
+ g_value_unset (&v1);
+ g_value_unset (&v2);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_structure_single_ops)
+{
+ static const struct
+ {
+ const gchar *str1;
+ gboolean is_fixed;
+ gboolean can_fixate;
+ } single_struct[] = {
+ {
+ "foo,bar=(int)1", TRUE, TRUE}, {
+ "foo,bar=(int)[1,2]", FALSE, TRUE},};
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (single_struct); i++) {
+ GstStructure *s1 = gst_structure_from_string (single_struct[i].str1, NULL);
+ GValue v1 = G_VALUE_INIT;
+ GValue v2 = G_VALUE_INIT;
+
+ fail_unless (s1 != NULL);
+
+ GST_DEBUG ("checking structure %" GST_PTR_FORMAT, s1);
+
+ g_value_init (&v1, GST_TYPE_STRUCTURE);
+ gst_value_set_structure (&v1, s1);
+
+ fail_unless (gst_value_is_fixed (&v1) == single_struct[i].is_fixed);
+ fail_unless (gst_value_fixate (&v2, &v1) == single_struct[i].can_fixate);
+ if (single_struct[i].can_fixate)
+ g_value_unset (&v2);
+
+ g_value_unset (&v1);
+ gst_structure_free (s1);
+ }
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_structure_ops)
+{
+ struct
+ {
+ const gchar *str1;
+ const gchar *str2;
+ const gchar *op;
+ gint ret;
+ GType str_type;
+ const gchar *str_result;
+ } comparisons[] = {
+ /* *INDENT-OFF* */
+ {"foo,bar=(int)1", "foo,bar=(int)1", "compare", GST_VALUE_EQUAL, 0, NULL},
+ {"foo,bar=(int)1", "foo,bar=(int)1", "is_subset", TRUE, 0, NULL},
+ {"foo,bar=(int)1", "foo,bar=(int)1", "intersect", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)1"},
+ {"foo,bar=(int)1", "foo,bar=(int)1", "union", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)1"},
+ {"foo,bar=(int)[1,2]", "foo,bar=(int)1", "compare", GST_VALUE_UNORDERED, 0, NULL},
+ {"foo,bar=(int)[1,2]", "foo,bar=(int)1", "is_subset", FALSE, 0, NULL},
+ {"foo,bar=(int)[1,2]", "foo,bar=(int)1", "intersect", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)1"},
+ {"foo,bar=(int)[1,2]", "foo,bar=(int)1", "union", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)[1,2]"},
+ {"foo,bar=(int)1", "foo,bar=(int)[1,2]", "compare", GST_VALUE_UNORDERED, 0, NULL},
+ {"foo,bar=(int)1", "foo,bar=(int)[1,2]", "is_subset", TRUE, 0, NULL},
+ {"foo,bar=(int)1", "foo,bar=(int)[1,2]", "intersect", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)1"},
+ {"foo,bar=(int)1", "foo,bar=(int)[1,2]", "union", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)[1,2]"},
+ {"foo,bar=(int)1", "foo,bar=(int)2", "compare", GST_VALUE_UNORDERED, 0, NULL},
+ {"foo,bar=(int)1", "foo,bar=(int)2", "is_subset", FALSE, 0, NULL},
+ {"foo,bar=(int)1", "foo,bar=(int)2", "intersect", FALSE, 0, NULL},
+ {"foo,bar=(int)1", "foo,bar=(int)2", "union", TRUE, GST_TYPE_STRUCTURE, "foo,bar=(int)[1,2]"},
+ {"foo,bar=(int)1", "baz,bar=(int)1", "compare", GST_VALUE_UNORDERED, 0, NULL},
+ {"foo,bar=(int)1", "baz,bar=(int)1", "is_subset", FALSE, 0, NULL},
+ {"foo,bar=(int)1", "baz,bar=(int)1", "intersect", FALSE, 0, NULL},
+#if 0
+ /* deserializing lists is not implemented (but this should still work!) */
+ {"foo,bar=(int)1", "baz,bar=(int)1", "union", TRUE, G_TYPE_LIST, "{foo,bar=(int)1;, baz,bar=(int)1;}"},
+#endif
+ /* *INDENT-ON* */
+ };
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (comparisons); i++) {
+ GstStructure *s1 = gst_structure_from_string (comparisons[i].str1, NULL);
+ GstStructure *s2 = gst_structure_from_string (comparisons[i].str2, NULL);
+ GValue v1 = G_VALUE_INIT, v2 = G_VALUE_INIT, v3 = G_VALUE_INIT;
+
+ fail_unless (s1 != NULL);
+ fail_unless (s2 != NULL);
+
+ GST_DEBUG ("checking %s with structure1 %" GST_PTR_FORMAT " structure2 %"
+ GST_PTR_FORMAT " is %d, %s", comparisons[i].op, s1, s2,
+ comparisons[i].ret, comparisons[i].str_result);
+
+ g_value_init (&v1, GST_TYPE_STRUCTURE);
+ gst_value_set_structure (&v1, s1);
+ g_value_init (&v2, GST_TYPE_STRUCTURE);
+ gst_value_set_structure (&v2, s2);
+
+ if (g_strcmp0 (comparisons[i].op, "compare") == 0) {
+ fail_unless (gst_value_compare (&v1, &v2) == comparisons[i].ret);
+ } else if (g_strcmp0 (comparisons[i].op, "is_subset") == 0) {
+ fail_unless (gst_value_is_subset (&v1, &v2) == comparisons[i].ret);
+ } else {
+ if (g_strcmp0 (comparisons[i].op, "intersect") == 0) {
+ fail_unless (gst_value_intersect (&v3, &v1, &v2) == comparisons[i].ret);
+ } else if (g_strcmp0 (comparisons[i].op, "union") == 0) {
+ fail_unless (gst_value_union (&v3, &v1, &v2) == comparisons[i].ret);
+ }
+ if (comparisons[i].ret) {
+ GValue result = G_VALUE_INIT;
+ gchar *str;
+
+ str = gst_value_serialize (&v3);
+ GST_LOG ("result %s", str);
+ g_free (str);
+
+ g_value_init (&result, comparisons[i].str_type);
+ fail_unless (gst_value_deserialize (&result,
+ comparisons[i].str_result));
+ fail_unless (gst_value_compare (&result, &v3) == GST_VALUE_EQUAL);
+ g_value_unset (&v3);
+ g_value_unset (&result);
+ }
+ }
+
+ gst_structure_free (s1);
+ gst_structure_free (s2);
+ g_value_unset (&v1);
+ g_value_unset (&v2);
+ }
+}
+
+GST_END_TEST;
+
static Suite *
gst_value_suite (void)
{
tcase_add_test (tc_chain, test_stepped_int_range_parsing);
tcase_add_test (tc_chain, test_stepped_int_range_ops);
tcase_add_test (tc_chain, test_flagset);
+ tcase_add_test (tc_chain, test_structure_basic);
+ tcase_add_test (tc_chain, test_structure_single_ops);
+ tcase_add_test (tc_chain, test_structure_ops);
return s;
}