implement caps merging (fixes #352580)
Original commit message from CVS:
* docs/gst/gstreamer-sections.txt:
* gst/gstcaps.c: (gst_caps_structure_is_subset_field),
(gst_caps_structure_is_subset), (gst_caps_merge),
(gst_caps_merge_structure):
* gst/gstcaps.h:
* libs/gst/base/gstbasetransform.c:
(gst_base_transform_transform_caps):
* tests/check/gst/gstcaps.c: (GST_START_TEST), (gst_caps_suite):
implement caps merging (fixes #352580)
diff --git a/ChangeLog b/ChangeLog
index d44e23f..0139ede 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2006-08-24 Stefan Kost <ensonic@users.sf.net>
+
+ * docs/gst/gstreamer-sections.txt:
+ * gst/gstcaps.c: (gst_caps_structure_is_subset_field),
+ (gst_caps_structure_is_subset), (gst_caps_merge),
+ (gst_caps_merge_structure):
+ * gst/gstcaps.h:
+ * libs/gst/base/gstbasetransform.c:
+ (gst_base_transform_transform_caps):
+ * tests/check/gst/gstcaps.c: (GST_START_TEST), (gst_caps_suite):
+ implement caps merging (fixes #352580)
+
2006-08-23 Stefan Kost <ensonic@users.sf.net>
* tools/Makefile.am:
diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt
index ea691f9..faf54b9 100644
--- a/docs/gst/gstreamer-sections.txt
+++ b/docs/gst/gstreamer-sections.txt
@@ -223,6 +223,7 @@
gst_caps_merge
gst_caps_append_structure
gst_caps_remove_structure
+gst_caps_merge_structure
gst_caps_get_size
gst_caps_get_structure
gst_caps_set_simple
diff --git a/gst/gstcaps.c b/gst/gstcaps.c
index 7b3720e..11c291e 100644
--- a/gst/gstcaps.c
+++ b/gst/gstcaps.c
@@ -480,6 +480,75 @@
return FALSE;
}
+static gboolean
+gst_caps_structure_is_subset_field (GQuark field_id, const GValue * value,
+ gpointer user_data)
+{
+ GstStructure *subtract_from = user_data;
+ GValue subtraction = { 0, };
+ const GValue *other;
+ gint res;
+
+ other = gst_structure_id_get_value (subtract_from, field_id);
+ if (!other) {
+ /* field is missing in one set */
+ return FALSE;
+ }
+ /*{
+ gchar *str = g_strdup_value_contents (value);
+ GST_DEBUG (" value: '%s'", str);
+ g_free (str);
+ str = g_strdup_value_contents (other);
+ GST_DEBUG (" other: '%s'", str);
+ g_free (str);
+ } */
+ /*
+ [1,2] - 1 = 2
+ 1 - [1,2] = � ???
+ */
+ if (!gst_value_subtract (&subtraction, other, value)) {
+ /* empty result -> values are the same, or first was a value and
+ * second was a list
+ */
+ /* verify that result is empty by swapping args */
+ if (!gst_value_subtract (&subtraction, value, other)) {
+ /*GST_DEBUG (" values are the same"); */
+ return TRUE;
+ }
+ g_value_unset (&subtraction);
+ return FALSE;
+ }
+ /*{
+ gchar *str = g_strdup_value_contents (&subtraction);
+ GST_DEBUG (" diff: '%s'", str);
+ g_free (str);
+ } */
+ res = gst_value_compare (&subtraction, other);
+ if (res == GST_VALUE_EQUAL) {
+ /* value was empty ? */
+ g_value_unset (&subtraction);
+ /*GST_DEBUG (" compare = equal (%d)",res); */
+ return FALSE;
+ } else {
+ /*GST_DEBUG (" compare = unequal/unordered (%d)",res); */
+ return TRUE;
+ }
+}
+
+static gboolean
+gst_caps_structure_is_subset (const GstStructure * minuend,
+ const GstStructure * subtrahend)
+{
+ if ((minuend->name != subtrahend->name) ||
+ (gst_structure_n_fields (minuend) !=
+ gst_structure_n_fields (subtrahend))) {
+ return FALSE;
+ }
+
+ return gst_structure_foreach ((GstStructure *) subtrahend,
+ gst_caps_structure_is_subset_field, (gpointer) minuend);
+}
+
/**
* gst_caps_append:
* @caps1: the #GstCaps that will be appended to
@@ -526,9 +595,9 @@
* @caps1: the #GstCaps that will take the new entries
* @caps2: the #GstCaps to merge in
*
- * Appends the structures contained in @caps2 to @caps1 if they are not yet in
- * @caps1. The structures in @caps2 are not copied -- they are transferred to
- * @caps1, and then @caps2 is freed.
+ * Appends the structures contained in @caps2 to @caps1 if they are not yet
+ * expressed by @caps1. The structures in @caps2 are not copied -- they are
+ * transferred to @caps1, and then @caps2 is freed.
* If either caps is ANY, the resulting caps will be ANY.
*/
void
@@ -545,23 +614,33 @@
#ifdef USE_POISONING
CAPS_POISON (caps2);
#endif
- if (gst_caps_is_any (caps1) || gst_caps_is_any (caps2)) {
- /* FIXME: this leaks */
- caps1->flags |= GST_CAPS_FLAGS_ANY;
+ if (gst_caps_is_any (caps1)) {
for (i = caps2->structs->len - 1; i >= 0; i--) {
structure = gst_caps_remove_and_get_structure (caps2, i);
gst_structure_free (structure);
}
+ } else if (gst_caps_is_any (caps2)) {
+ caps1->flags |= GST_CAPS_FLAGS_ANY;
+ for (i = caps1->structs->len - 1; i >= 0; i--) {
+ structure = gst_caps_remove_and_get_structure (caps1, i);
+ gst_structure_free (structure);
+ }
} else {
- GstCaps *com = gst_caps_intersect (caps1, caps2);
- GstCaps *add = gst_caps_subtract (caps2, com);
+ int len = caps2->structs->len;
- /*
+ for (i = 0; i < len; i++) {
+ structure = gst_caps_remove_and_get_structure (caps2, 0);
+ gst_caps_merge_structure (caps1, structure);
+ }
+ /* this is too naive
+ GstCaps *com = gst_caps_intersect (caps1, caps2);
+ GstCaps *add = gst_caps_subtract (caps2, com);
+
GST_DEBUG ("common : %d", gst_caps_get_size (com));
GST_DEBUG ("adding : %d", gst_caps_get_size (add));
+ gst_caps_append (caps1, add);
+ gst_caps_unref (com);
*/
- gst_caps_append (caps1, add);
- gst_caps_unref (com);
}
gst_caps_unref (caps2); /* guaranteed to free it */
}
@@ -614,6 +693,54 @@
}
/**
+ * gst_caps_merge_structure:
+ * @caps: the #GstCaps that will the the new structure
+ * @structure: the #GstStructure to merge
+ *
+ * Appends @structure to @caps if its not already expressed by @caps. The
+ * structure is not copied; @caps becomes the owner of @structure.
+ */
+void
+gst_caps_merge_structure (GstCaps * caps, GstStructure * structure2)
+{
+ g_return_if_fail (GST_IS_CAPS (caps));
+ g_return_if_fail (IS_WRITABLE (caps));
+
+ if (G_LIKELY (structure2)) {
+ GstStructure *structure1;
+ int i;
+ gboolean unique = TRUE;
+
+ g_return_if_fail (structure2->parent_refcount == NULL);
+#if 0
+#ifdef USE_POISONING
+ STRUCTURE_POISON (structure2);
+#endif
+#endif
+ /*GST_DEBUG ("merge ?: %" GST_PTR_FORMAT, structure2); */
+ /* check each structure */
+ for (i = caps->structs->len - 1; i >= 0; i--) {
+ structure1 = gst_caps_get_structure (caps, i);
+ /*GST_DEBUG (" with: %" GST_PTR_FORMAT, structure1); */
+ /* if structure2 is a subset of structure1, then skip it */
+ if (gst_caps_structure_is_subset (structure1, structure2)) {
+ /*GST_DEBUG (" no"); */
+ unique = FALSE;
+ break;
+ }
+ }
+ if (unique) {
+ /*GST_DEBUG (" yes"); */
+ gst_structure_set_parent_refcount (structure2, &caps->refcount);
+ g_ptr_array_add (caps->structs, structure2);
+ } else {
+ gst_structure_free (structure2);
+ }
+ }
+}
+
+
+/**
* gst_caps_get_size:
* @caps: a #GstCaps
*
diff --git a/gst/gstcaps.h b/gst/gstcaps.h
index 668dfc7..628afba 100644
--- a/gst/gstcaps.h
+++ b/gst/gstcaps.h
@@ -199,6 +199,8 @@
void gst_caps_append_structure (GstCaps *caps,
GstStructure *structure);
void gst_caps_remove_structure (GstCaps * caps, guint idx);
+void gst_caps_merge_structure (GstCaps * caps1,
+ GstStructure * structure2);
guint gst_caps_get_size (const GstCaps *caps);
GstStructure * gst_caps_get_structure (const GstCaps *caps,
guint index);
diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c
index 48c1d68..cd3a849 100644
--- a/libs/gst/base/gstbasetransform.c
+++ b/libs/gst/base/gstbasetransform.c
@@ -453,10 +453,11 @@
gst_caps_unref (nth);
GST_DEBUG_OBJECT (trans, " to[%d]: %" GST_PTR_FORMAT, i, temp);
- /* FIXME: here we need to only append those structures, that are not yet
- * in there */
temp = gst_caps_make_writable (temp);
- /*gst_caps_append (ret, temp); */
+ /* FIXME: here we need to only append those structures, that are not yet
+ * in there
+ * gst_caps_append (ret, temp);
+ */
gst_caps_merge (ret, temp);
}
GST_DEBUG_OBJECT (trans, "merged: (%d)", gst_caps_get_size (ret));
diff --git a/tests/check/gst/gstcaps.c b/tests/check/gst/gstcaps.c
index 20e4b24..fc0d7d4 100644
--- a/tests/check/gst/gstcaps.c
+++ b/tests/check/gst/gstcaps.c
@@ -348,6 +348,95 @@
GST_END_TEST;
+GST_START_TEST (test_merge_fundamental)
+{
+ GstCaps *c1, *c2;
+
+ /* ANY + specific = ANY */
+ c1 = gst_caps_from_string ("audio/x-raw-int,rate=44100");
+ c2 = gst_caps_new_any ();
+ gst_caps_merge (c2, c1);
+ GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
+ fail_unless (gst_caps_get_size (c2) == 0, NULL);
+ fail_unless (gst_caps_is_any (c2), NULL);
+ gst_caps_unref (c2);
+
+ /* specific + ANY = ANY */
+ c2 = gst_caps_from_string ("audio/x-raw-int,rate=44100");
+ c1 = gst_caps_new_any ();
+ gst_caps_merge (c2, c1);
+ GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
+ fail_unless (gst_caps_get_size (c2) == 0, NULL);
+ fail_unless (gst_caps_is_any (c2), NULL);
+ gst_caps_unref (c2);
+
+ /* EMPTY + specific = specific */
+ c1 = gst_caps_from_string ("audio/x-raw-int,rate=44100");
+ c2 = gst_caps_new_empty ();
+ gst_caps_merge (c2, c1);
+ GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
+ fail_unless (gst_caps_get_size (c2) == 1, NULL);
+ fail_if (gst_caps_is_empty (c2), NULL);
+ gst_caps_unref (c2);
+
+ /* specific + EMPTY = specific */
+ c2 = gst_caps_from_string ("audio/x-raw-int,rate=44100");
+ c1 = gst_caps_new_empty ();
+ gst_caps_merge (c2, c1);
+ GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
+ fail_unless (gst_caps_get_size (c2) == 1, NULL);
+ fail_if (gst_caps_is_empty (c2), NULL);
+ gst_caps_unref (c2);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_merge_same)
+{
+ GstCaps *c1, *c2;
+
+ /* this is the same */
+ c1 = gst_caps_from_string ("audio/x-raw-int,rate=44100,channels=1");
+ c2 = gst_caps_from_string ("audio/x-raw-int,rate=44100,channels=1");
+ gst_caps_merge (c2, c1);
+ GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
+ fail_unless (gst_caps_get_size (c2) == 1, NULL);
+
+ /* and so is this */
+ c1 = gst_caps_from_string ("audio/x-raw-int,rate=44100,channels=1");
+ c2 = gst_caps_from_string ("audio/x-raw-int,channels=1,rate=44100");
+ gst_caps_merge (c2, c1);
+ GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
+ fail_unless (gst_caps_get_size (c2) == 1, NULL);
+
+ gst_caps_unref (c2);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_merge_subset)
+{
+ GstCaps *c1, *c2;
+
+ /* the 2nd is already covered */
+ c2 = gst_caps_from_string ("audio/x-raw-int,channels=[1,2]");
+ c1 = gst_caps_from_string ("audio/x-raw-int,channels=1");
+ gst_caps_merge (c2, c1);
+ GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
+ fail_unless (gst_caps_get_size (c2) == 1, NULL);
+
+ /* here it is not */
+ c2 = gst_caps_from_string ("audio/x-raw-int,channels=1,rate=44100");
+ c1 = gst_caps_from_string ("audio/x-raw-int,channels=[1,2],rate=44100");
+ gst_caps_merge (c2, c1);
+ GST_DEBUG ("merged: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (c2), c2);
+ fail_unless (gst_caps_get_size (c2) == 2, NULL);
+
+ gst_caps_unref (c2);
+}
+
+GST_END_TEST;
+
Suite *
gst_caps_suite (void)
@@ -363,6 +452,9 @@
tcase_add_test (tc_chain, test_static_caps);
tcase_add_test (tc_chain, test_simplify);
tcase_add_test (tc_chain, test_truncate);
+ tcase_add_test (tc_chain, test_merge_fundamental);
+ tcase_add_test (tc_chain, test_merge_same);
+ tcase_add_test (tc_chain, test_merge_subset);
return s;
}