caps: keep ANY caps empty internally

Keep the ANY caps empty internally when appending and merging
caps/structures. Previously, an ANY caps could end up containing
internal structures, which could be fetched by the user, and gave the
caps a non-zero length.

Also, made sure that `gst_caps_set_features_simple` frees the features
if caps is empty.
This commit is contained in:
Henry Wilkes 2020-01-27 11:58:57 +00:00 committed by Jan Schmidt
parent 407e32588d
commit 412e97beb4
2 changed files with 147 additions and 9 deletions

View file

@ -510,6 +510,20 @@ gst_caps_remove_and_get_structure (GstCaps * caps, guint idx)
return s;
}
static void
gst_caps_make_any (GstCaps * caps)
{
guint i;
GstStructure *s;
/* empty out residual structures */
for (i = GST_CAPS_LEN (caps); i; i--) {
s = gst_caps_remove_and_get_structure (caps, 0);
gst_structure_free (s);
}
GST_CAPS_FLAGS (caps) |= GST_CAPS_FLAG_ANY;
}
/**
* gst_caps_steal_structure:
* @caps: the #GstCaps to retrieve from
@ -554,7 +568,7 @@ gst_caps_append (GstCaps * caps1, GstCaps * caps2)
g_return_if_fail (IS_WRITABLE (caps1));
if (G_UNLIKELY (CAPS_IS_ANY (caps1) || CAPS_IS_ANY (caps2))) {
GST_CAPS_FLAGS (caps1) |= GST_CAPS_FLAG_ANY;
gst_caps_make_any (caps1);
gst_caps_unref (caps2);
} else {
caps2 = gst_caps_make_writable (caps2);
@ -636,6 +650,13 @@ gst_caps_append_structure (GstCaps * caps, GstStructure * structure)
g_return_if_fail (GST_IS_CAPS (caps));
g_return_if_fail (IS_WRITABLE (caps));
if (CAPS_IS_ANY (caps)) {
/* ANY caps will stay as ANY caps */
if (structure)
gst_structure_free (structure);
return;
}
if (G_LIKELY (structure)) {
gst_caps_append_structure_unchecked (caps, structure, NULL);
}
@ -659,6 +680,15 @@ gst_caps_append_structure_full (GstCaps * caps, GstStructure * structure,
g_return_if_fail (GST_IS_CAPS (caps));
g_return_if_fail (IS_WRITABLE (caps));
if (CAPS_IS_ANY (caps)) {
/* ANY caps will stay as ANY caps */
if (structure)
gst_structure_free (structure);
if (features)
gst_caps_features_free (features);
return;
}
if (G_LIKELY (structure)) {
gst_caps_append_structure_unchecked (caps, structure, features);
}
@ -707,6 +737,12 @@ gst_caps_merge_structure (GstCaps * caps, GstStructure * structure)
if (G_UNLIKELY (structure == NULL))
return caps;
if (CAPS_IS_ANY (caps)) {
/* ANY caps will stay as ANY caps */
gst_structure_free (structure);
return caps;
}
/* check each structure */
for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) {
structure1 = gst_caps_get_structure_unchecked (caps, i);
@ -758,6 +794,14 @@ gst_caps_merge_structure_full (GstCaps * caps, GstStructure * structure,
if (G_UNLIKELY (structure == NULL))
return caps;
if (CAPS_IS_ANY (caps)) {
/* ANY caps will stay as ANY caps */
gst_structure_free (structure);
if (features)
gst_caps_features_free (features);
return caps;
}
/* To make comparisons easier below */
features_tmp = features ? features : GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
@ -951,6 +995,13 @@ gst_caps_set_features_simple (GstCaps * caps, GstCapsFeatures * features)
n = gst_caps_get_size (caps);
if (n == 0) {
/* features will not be set on any structure */
if (features)
gst_caps_features_free (features);
return;
}
for (i = 0; i < n; i++) {
GstCapsFeatures *f;
@ -1182,9 +1233,7 @@ gst_caps_is_fixed (const GstCaps * caps)
if (GST_CAPS_LEN (caps) != 1)
return FALSE;
/* an ANY caps can have length 1 (rather than the usual 0) if it
* has had a structure appended, or if it was created from a merge
* or append of caps */
/* double check not ANY, even though ANY caps should have 0 length */
if (CAPS_IS_ANY (caps))
return FALSE;
@ -1433,9 +1482,7 @@ gst_caps_is_strictly_equal (const GstCaps * caps1, const GstCaps * caps2)
if (G_UNLIKELY (caps1 == caps2))
return TRUE;
/* if both are ANY caps, consider them strictly equal, even if
* internally they contain differing structures from
* gst_caps_append, gst_caps_merge or gst_caps_append_structure */
/* if both are ANY caps, consider them strictly equal */
if (CAPS_IS_ANY (caps1))
return (CAPS_IS_ANY (caps2));
else if (CAPS_IS_ANY (caps2))

View file

@ -60,7 +60,7 @@ GST_START_TEST (test_double_append)
GstStructure *s1;
GstCaps *c1;
c1 = gst_caps_new_any ();
c1 = gst_caps_new_empty ();
s1 = gst_structure_from_string ("audio/x-raw,rate=44100", NULL);
gst_caps_append_structure (c1, s1);
ASSERT_CRITICAL (gst_caps_append_structure (c1, s1));
@ -76,7 +76,7 @@ GST_START_TEST (test_mutability)
GstCaps *c1;
gint ret;
c1 = gst_caps_new_any ();
c1 = gst_caps_new_empty ();
s1 = gst_structure_from_string ("audio/x-raw,rate=44100", NULL);
gst_structure_set (s1, "rate", G_TYPE_INT, 48000, NULL);
gst_caps_append_structure (c1, s1);
@ -1259,6 +1259,18 @@ GST_START_TEST (test_features)
fail_unless (gst_caps_features_is_equal (f1, f2));
gst_caps_unref (c1);
c1 = gst_caps_new_any ();
fail_unless_equals_int (gst_caps_get_size (c1), 0);
f1 = gst_caps_features_new ("memory:EGLImage", NULL);
/* Nothing to set the features on, but method should still take
* ownership of the given features */
gst_caps_set_features_simple (c1, f1);
fail_unless_equals_int (gst_caps_get_size (c1), 0);
fail_unless (gst_caps_is_any (c1));
gst_caps_unref (c1);
}
GST_END_TEST;
@ -1425,6 +1437,7 @@ GST_START_TEST (test_equality)
G_TYPE_FLOAT, 5.7, NULL);
fail_unless (s);
gst_caps_append_structure (any2, s);
/* should still be ANY after append */
caps1 = gst_caps_new_simple ("structure", "int", G_TYPE_INT, 4, "float",
G_TYPE_FLOAT, 5.7, NULL);
@ -1603,6 +1616,83 @@ GST_START_TEST (test_equality)
GST_END_TEST;
GST_START_TEST (test_remains_any)
{
GstCaps *any, *caps;
GstStructure *s;
/* test append structure to ANY */
any = gst_caps_new_any ();
fail_unless (gst_caps_is_any (any));
fail_if (gst_caps_get_size (any));
s = gst_structure_new ("structure", "int", G_TYPE_INT, 4, NULL);
fail_unless (s);
gst_caps_append_structure (any, s);
fail_unless (gst_caps_is_any (any));
fail_if (gst_caps_get_size (any));
ASSERT_CRITICAL (gst_caps_get_structure (any, 0));
s = gst_structure_new ("structure", "int", G_TYPE_INT, 4, NULL);
fail_unless (s);
gst_caps_append_structure_full (any, s, gst_caps_features_new_any ());
fail_unless (gst_caps_is_any (any));
fail_if (gst_caps_get_size (any));
ASSERT_CRITICAL (gst_caps_get_structure (any, 0));
/* test merge structure with ANY */
s = gst_structure_new ("structure", "int", G_TYPE_INT, 4, NULL);
fail_unless (s);
any = gst_caps_merge_structure (any, s);
fail_unless (gst_caps_is_any (any));
fail_if (gst_caps_get_size (any));
ASSERT_CRITICAL (gst_caps_get_structure (any, 0));
s = gst_structure_new ("structure", "int", G_TYPE_INT, 4, NULL);
fail_unless (s);
any = gst_caps_merge_structure_full (any, s, gst_caps_features_new_any ());
fail_unless (gst_caps_is_any (any));
fail_if (gst_caps_get_size (any));
ASSERT_CRITICAL (gst_caps_get_structure (any, 0));
/* test appending non-ANY to ANY */
caps = gst_caps_new_simple ("structure", "int", G_TYPE_INT, 4, NULL);
fail_unless (caps);
gst_caps_append (any, caps);
fail_unless (gst_caps_is_any (any));
fail_if (gst_caps_get_size (any));
ASSERT_CRITICAL (gst_caps_get_structure (any, 0));
/* test merging non-ANY with ANY */
caps = gst_caps_new_simple ("structure", "int", G_TYPE_INT, 4, NULL);
fail_unless (caps);
any = gst_caps_merge (any, caps);
fail_unless (gst_caps_is_any (any));
fail_if (gst_caps_get_size (any));
ASSERT_CRITICAL (gst_caps_get_structure (any, 0));
caps = gst_caps_new_simple ("structure", "int", G_TYPE_INT, 4, NULL);
fail_unless (caps);
any = gst_caps_merge (caps, any);
fail_unless (gst_caps_is_any (any));
fail_if (gst_caps_get_size (any));
ASSERT_CRITICAL (gst_caps_get_structure (any, 0));
gst_caps_unref (any);
/* test appending ANY to non-ANY */
caps = gst_caps_new_simple ("structure", "int", G_TYPE_INT, 4, NULL);
fail_unless (caps);
fail_unless_equals_int (gst_caps_get_size (caps), 1);
fail_unless (gst_caps_get_structure (caps, 0));
gst_caps_append (caps, gst_caps_new_any ());
fail_unless (gst_caps_is_any (caps));
fail_if (gst_caps_get_size (caps));
ASSERT_CRITICAL (gst_caps_get_structure (caps, 0));
gst_caps_unref (caps);
}
GST_END_TEST;
static Suite *
gst_caps_suite (void)
@ -1639,6 +1729,7 @@ gst_caps_suite (void)
tcase_add_test (tc_chain, test_map_in_place);
tcase_add_test (tc_chain, test_filter_and_map_in_place);
tcase_add_test (tc_chain, test_equality);
tcase_add_test (tc_chain, test_remains_any);
return s;
}