implement caps merging (fixes #352580)
authorStefan Kost <ensonic@users.sourceforge.net>
Thu, 24 Aug 2006 10:40:31 +0000 (10:40 +0000)
committerStefan Kost <ensonic@users.sourceforge.net>
Thu, 24 Aug 2006 10:40:31 +0000 (10:40 +0000)
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)

ChangeLog
docs/gst/gstreamer-sections.txt
gst/gstcaps.c
gst/gstcaps.h
libs/gst/base/gstbasetransform.c
tests/check/gst/gstcaps.c

index d44e23f..0139ede 100644 (file)
--- 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:
index ea691f9..faf54b9 100644 (file)
@@ -223,6 +223,7 @@ gst_caps_append
 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
index 7b3720e..11c291e 100644 (file)
@@ -480,6 +480,75 @@ gst_structure_is_equal_foreach (GQuark field_id, const GValue * val2,
   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 @@ gst_caps_append (GstCaps * caps1, GstCaps * caps2)
  * @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 @@ gst_caps_merge (GstCaps * caps1, GstCaps * caps2)
 #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_remove_structure (GstCaps * caps, guint idx)
 }
 
 /**
+ * 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
  *
index 668dfc7..628afba 100644 (file)
@@ -199,6 +199,8 @@ void              gst_caps_merge                   (GstCaps       *caps1,
 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);
index 48c1d68..cd3a849 100644 (file)
@@ -453,10 +453,11 @@ gst_base_transform_transform_caps (GstBaseTransform * trans,
         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));
index 20e4b24..fc0d7d4 100644 (file)
@@ -348,6 +348,95 @@ GST_START_TEST (test_truncate)
 
 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 @@ gst_caps_suite (void)
   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;
 }