structure/caps: Add gst_{structure,caps}_filter_and_map_in_place()
[platform/upstream/gstreamer.git] / gst / gstcaps.c
index 4b6350d..147b32c 100644 (file)
  * handle or produce at runtime.
  *
  * A #GstCaps can be constructed with the following code fragment:
- *
- * <example>
- *  <title>Creating caps</title>
- *  <programlisting>
- *  GstCaps *caps;
- *  caps = gst_caps_new_simple ("video/x-raw",
- *       "format", G_TYPE_STRING, "I420",
- *       "framerate", GST_TYPE_FRACTION, 25, 1,
- *       "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
- *       "width", G_TYPE_INT, 320,
- *       "height", G_TYPE_INT, 240,
- *       NULL);
- *  </programlisting>
- * </example>
+ * |[
+ *   GstCaps *caps = gst_caps_new_simple ("video/x-raw",
+ *      "format", G_TYPE_STRING, "I420",
+ *      "framerate", GST_TYPE_FRACTION, 25, 1,
+ *      "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
+ *      "width", G_TYPE_INT, 320,
+ *      "height", G_TYPE_INT, 240,
+ *      NULL);
+ * ]|
  *
  * A #GstCaps is fixed when it has no properties with ranges or lists. Use
  * gst_caps_is_fixed() to test for fixed caps. Fixed caps can be used in a
  * Various methods exist to work with the media types such as subtracting
  * or intersecting.
  *
- * Last reviewed on 2011-03-28 (0.11.3)
+ * Be aware that the current #GstCaps / #GstStructure serialization into string
+ * has limited support for nested #GstCaps / #GstStructure fields. It can only
+ * support one level of nesting. Using more levels will lead to unexpected
+ * behavior when using serialization features, such as gst_caps_to_string() or
+ * gst_value_serialize() and their counterparts.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -93,7 +92,7 @@ typedef struct _GstCapsImpl
 
 /* same as gst_caps_is_any () */
 #define CAPS_IS_ANY(caps)                              \
-  (GST_CAPS_FLAGS(caps) & GST_CAPS_FLAG_ANY)
+  (!!(GST_CAPS_FLAGS(caps) & GST_CAPS_FLAG_ANY))
 
 /* same as gst_caps_is_empty () */
 #define CAPS_IS_EMPTY(caps)                            \
@@ -102,21 +101,19 @@ typedef struct _GstCapsImpl
 #define CAPS_IS_EMPTY_SIMPLE(caps)                                     \
   ((GST_CAPS_ARRAY (caps) == NULL) || (GST_CAPS_LEN (caps) == 0))
 
-#define gst_caps_features_copy_conditional(f) ((f && !gst_caps_features_is_equal (f, GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)) ? gst_caps_features_copy (f) : NULL)
+#define gst_caps_features_copy_conditional(f) ((f && (gst_caps_features_is_any (f) || !gst_caps_features_is_equal (f, GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY))) ? gst_caps_features_copy (f) : NULL)
 
 /* quick way to get a caps structure at an index without doing a type or array
  * length check */
 #define gst_caps_get_structure_unchecked(caps, index) \
      (g_array_index (GST_CAPS_ARRAY (caps), GstCapsArrayElement, (index)).structure)
+#define gst_caps_get_features_storage_unchecked(caps, index) \
+     (&g_array_index (GST_CAPS_ARRAY (caps), GstCapsArrayElement, (index)).features)
 #define gst_caps_get_features_unchecked(caps, index) \
-     (g_array_index (GST_CAPS_ARRAY (caps), GstCapsArrayElement, (index)).features)
+     (g_atomic_pointer_get (gst_caps_get_features_storage_unchecked (caps, index)))
 /* quick way to append a structure without checking the args */
 #define gst_caps_append_structure_unchecked(caps, s, f) G_STMT_START{\
   GstCapsArrayElement __e={s, f};                                      \
-  if (__e.features && gst_caps_features_is_equal (GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY, __e.features)) { \
-    gst_caps_features_free (__e.features); \
-    __e.features = NULL; \
-  } \
   if (gst_structure_set_parent_refcount (__e.structure, &GST_MINI_OBJECT_REFCOUNT(caps)) && \
       (!__e.features || gst_caps_features_set_parent_refcount (__e.features, &GST_MINI_OBJECT_REFCOUNT(caps))))         \
     g_array_append_val (GST_CAPS_ARRAY (caps), __e);                             \
@@ -330,7 +327,7 @@ gst_caps_new_simple (const char *media_type, const char *fieldname, ...)
  * @...: additional structures to add
  *
  * Creates a new #GstCaps and adds all the structures listed as
- * arguments.  The list must be NULL-terminated.  The structures
+ * arguments.  The list must be %NULL-terminated.  The structures
  * are not copied; the returned #GstCaps owns the structures.
  *
  * Returns: (transfer full): the new #GstCaps
@@ -354,7 +351,7 @@ gst_caps_new_full (GstStructure * struct1, ...)
  * @var_args: additional structures to add
  *
  * Creates a new #GstCaps and adds all the structures listed as
- * arguments.  The list must be NULL-terminated.  The structures
+ * arguments.  The list must be %NULL-terminated.  The structures
  * are not copied; the returned #GstCaps owns the structures.
  *
  * Returns: (transfer full): the new #GstCaps
@@ -487,8 +484,6 @@ gst_caps_remove_and_get_structure (GstCaps * caps, guint idx)
   return s;
 }
 
-
-
 /**
  * gst_caps_steal_structure:
  * @caps: the #GstCaps to retrieve from
@@ -628,6 +623,8 @@ gst_caps_append_structure (GstCaps * caps, GstStructure * structure)
  *
  * Appends @structure with @features to @caps.  The structure is not copied; @caps
  * becomes the owner of @structure.
+ *
+ * Since: 1.2
  */
 void
 gst_caps_append_structure_full (GstCaps * caps, GstStructure * structure,
@@ -646,7 +643,7 @@ gst_caps_append_structure_full (GstCaps * caps, GstStructure * structure,
  * @caps: the #GstCaps to remove from
  * @idx: Index of the structure to remove
  *
- * removes the stucture with the given index from the list of structures
+ * removes the structure with the given index from the list of structures
  * contained in @caps.
  */
 void
@@ -693,9 +690,9 @@ gst_caps_merge_structure (GstCaps * caps, GstStructure * structure)
 
     /* if structure is a subset of structure1 and the
      * there are no existing features, then skip it */
-    if (gst_structure_is_subset (structure, structure1) &&
-        gst_caps_features_is_equal (features1,
-            GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)) {
+    if (gst_caps_features_is_equal (features1,
+            GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)
+        && gst_structure_is_subset (structure, structure1)) {
       unique = FALSE;
       break;
     }
@@ -718,6 +715,8 @@ gst_caps_merge_structure (GstCaps * caps, GstStructure * structure)
  * Appends @structure with @features to @caps if its not already expressed by @caps.
  *
  * Returns: (transfer full): the merged caps.
+ *
+ * Since: 1.2
  */
 GstCaps *
 gst_caps_merge_structure_full (GstCaps * caps, GstStructure * structure,
@@ -744,8 +743,15 @@ gst_caps_merge_structure_full (GstCaps * caps, GstStructure * structure,
       features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
     /* if structure is a subset of structure1 and the
      * the features are a subset, then skip it */
-    if (gst_structure_is_subset (structure, structure1) &&
-        gst_caps_features_is_equal (features_tmp, features1)) {
+    /* FIXME: We only skip if none of the features are
+     * ANY and are still equal. That way all ANY structures
+     * show up in the caps and no non-ANY structures are
+     * swallowed by ANY structures
+     */
+    if (((!gst_caps_features_is_any (features_tmp)
+                || gst_caps_features_is_any (features1))
+            && gst_caps_features_is_equal (features_tmp, features1))
+        && gst_structure_is_subset (structure, structure1)) {
       unique = FALSE;
       break;
     }
@@ -831,6 +837,8 @@ gst_caps_get_structure (const GstCaps * caps, guint index)
  *
  * Returns: (transfer none): a pointer to the #GstCapsFeatures corresponding
  *     to @index
+ *
+ * Since: 1.2
  */
 GstCapsFeatures *
 gst_caps_get_features (const GstCaps * caps, guint index)
@@ -841,8 +849,25 @@ gst_caps_get_features (const GstCaps * caps, guint index)
   g_return_val_if_fail (index < GST_CAPS_LEN (caps), NULL);
 
   features = gst_caps_get_features_unchecked (caps, index);
-  if (!features)
+  if (!features) {
+    GstCapsFeatures **storage;
+
+    /* We have to do some atomic pointer magic here as the caps
+     * might not be writable and someone else calls this function
+     * at the very same time */
     features = gst_caps_features_copy (GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY);
+    gst_caps_features_set_parent_refcount (features, &GST_CAPS_REFCOUNT (caps));
+
+    storage = gst_caps_get_features_storage_unchecked (caps, index);
+    if (!g_atomic_pointer_compare_and_exchange (storage, NULL, features)) {
+      /* Someone did the same we just tried in the meantime */
+      gst_caps_features_set_parent_refcount (features, NULL);
+      gst_caps_features_free (features);
+
+      features = gst_caps_get_features_unchecked (caps, index);
+      g_assert (features != NULL);
+    }
+  }
 
   return features;
 }
@@ -851,9 +876,11 @@ gst_caps_get_features (const GstCaps * caps, guint index)
  * gst_caps_set_features:
  * @caps: a #GstCaps
  * @index: the index of the structure
- * @features: (allow-none) (transfer full): the #GstFeatures to set
+ * @features: (allow-none) (transfer full): the #GstCapsFeatures to set
  *
  * Sets the #GstCapsFeatures @features for the structure at @index.
+ *
+ * Since: 1.2
  */
 void
 gst_caps_set_features (GstCaps * caps, guint index, GstCapsFeatures * features)
@@ -864,11 +891,18 @@ gst_caps_set_features (GstCaps * caps, guint index, GstCapsFeatures * features)
   g_return_if_fail (index <= gst_caps_get_size (caps));
   g_return_if_fail (IS_WRITABLE (caps));
 
-  storage = &gst_caps_get_features_unchecked (caps, index);
-  old = *storage;
-  *storage = features;
-  if (old)
+  storage = gst_caps_get_features_storage_unchecked (caps, index);
+  /* Not much problem here as caps are writable */
+  old = g_atomic_pointer_get (storage);
+  g_atomic_pointer_set (storage, features);
+
+  if (features)
+    gst_caps_features_set_parent_refcount (features, &GST_CAPS_REFCOUNT (caps));
+
+  if (old) {
+    gst_caps_features_set_parent_refcount (old, NULL);
     gst_caps_features_free (old);
+  }
 }
 
 /**
@@ -965,7 +999,7 @@ gst_caps_set_value (GstCaps * caps, const char *field, const GValue * value)
  * @varargs: additional parameters
  *
  * Sets fields in a #GstCaps.  The arguments must be passed in the same
- * manner as gst_structure_set(), and be NULL-terminated.
+ * manner as gst_structure_set(), and be %NULL-terminated.
  */
 void
 gst_caps_set_simple_valist (GstCaps * caps, const char *field, va_list varargs)
@@ -1002,7 +1036,7 @@ gst_caps_set_simple_valist (GstCaps * caps, const char *field, va_list varargs)
  * @...: additional parameters
  *
  * Sets fields in a #GstCaps.  The arguments must be passed in the same
- * manner as gst_structure_set(), and be NULL-terminated.
+ * manner as gst_structure_set(), and be %NULL-terminated.
  */
 void
 gst_caps_set_simple (GstCaps * caps, const char *field, ...)
@@ -1025,7 +1059,7 @@ gst_caps_set_simple (GstCaps * caps, const char *field, ...)
  *
  * Determines if @caps represents any media format.
  *
- * Returns: TRUE if @caps represents any format.
+ * Returns: %TRUE if @caps represents any format.
  */
 gboolean
 gst_caps_is_any (const GstCaps * caps)
@@ -1041,7 +1075,7 @@ gst_caps_is_any (const GstCaps * caps)
  *
  * Determines if @caps represents no media formats.
  *
- * Returns: TRUE if @caps represents no formats.
+ * Returns: %TRUE if @caps represents no formats.
  */
 gboolean
 gst_caps_is_empty (const GstCaps * caps)
@@ -1069,18 +1103,23 @@ gst_caps_is_fixed_foreach (GQuark field_id, const GValue * value,
  * one structure, and each field in the structure describes a fixed type.
  * Examples of non-fixed types are GST_TYPE_INT_RANGE and GST_TYPE_LIST.
  *
- * Returns: TRUE if @caps is fixed
+ * Returns: %TRUE if @caps is fixed
  */
 gboolean
 gst_caps_is_fixed (const GstCaps * caps)
 {
   GstStructure *structure;
+  GstCapsFeatures *features;
 
   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
 
   if (GST_CAPS_LEN (caps) != 1)
     return FALSE;
 
+  features = gst_caps_get_features_unchecked (caps, 0);
+  if (features && gst_caps_features_is_any (features))
+    return FALSE;
+
   structure = gst_caps_get_structure_unchecked (caps, 0);
 
   return gst_structure_foreach (structure, gst_caps_is_fixed_foreach, NULL);
@@ -1094,7 +1133,7 @@ gst_caps_is_fixed (const GstCaps * caps)
  * Tests if two #GstCaps are equal.  This function only works on fixed
  * #GstCaps.
  *
- * Returns: TRUE if the arguments represent the same format
+ * Returns: %TRUE if the arguments represent the same format
  */
 gboolean
 gst_caps_is_equal_fixed (const GstCaps * caps1, const GstCaps * caps2)
@@ -1127,7 +1166,7 @@ gst_caps_is_equal_fixed (const GstCaps * caps1, const GstCaps * caps2)
  * every media format that is in the first is also contained in the
  * second.  That is, @caps1 is a subset of @caps2.
  *
- * Returns: TRUE if @caps1 is a subset of @caps2.
+ * Returns: %TRUE if @caps1 is a subset of @caps2.
  */
 gboolean
 gst_caps_is_always_compatible (const GstCaps * caps1, const GstCaps * caps2)
@@ -1144,8 +1183,6 @@ gst_caps_is_always_compatible (const GstCaps * caps1, const GstCaps * caps2)
  * @superset: a potentially greater #GstCaps
  *
  * Checks if all caps represented by @subset are also represented by @superset.
- * <note>This function does not work reliably if optional properties for caps
- * are included on one caps and omitted on the other.</note>
  *
  * Returns: %TRUE if @subset is a subset of @superset
  */
@@ -1175,8 +1212,9 @@ gst_caps_is_subset (const GstCaps * subset, const GstCaps * superset)
       f2 = gst_caps_get_features_unchecked (superset, j);
       if (!f2)
         f2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
-      if (gst_structure_is_subset (s1, s2) &&
-          gst_caps_features_is_equal (f1, f2)) {
+      if ((!gst_caps_features_is_any (f1) || gst_caps_features_is_any (f2)) &&
+          gst_caps_features_is_equal (f1, f2)
+          && gst_structure_is_subset (s1, s2)) {
         /* If we found a superset, continue with the next
          * subset structure */
         break;
@@ -1239,6 +1277,8 @@ gst_caps_is_subset_structure (const GstCaps * caps,
  * for more information.
  *
  * Returns: %TRUE if @structure is a subset of @caps
+ *
+ * Since: 1.2
  */
 gboolean
 gst_caps_is_subset_structure_full (const GstCaps * caps,
@@ -1264,8 +1304,9 @@ gst_caps_is_subset_structure_full (const GstCaps * caps,
     f = gst_caps_get_features_unchecked (caps, i);
     if (!f)
       f = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
-    if (gst_structure_is_subset (structure, s) &&
-        gst_caps_features_is_equal (features, f)) {
+    if ((!gst_caps_features_is_any (features) || gst_caps_features_is_any (f))
+        && gst_caps_features_is_equal (features, f)
+        && gst_structure_is_subset (structure, s)) {
       /* If we found a superset return TRUE */
       return TRUE;
     }
@@ -1280,10 +1321,8 @@ gst_caps_is_subset_structure_full (const GstCaps * caps,
  * @caps2: another #GstCaps
  *
  * Checks if the given caps represent the same set of caps.
- * <note>This function does not work reliably if optional properties for caps
- * are included on one caps and omitted on the other.</note>
  *
- * Returns: TRUE if both caps are equal.
+ * Returns: %TRUE if both caps are equal.
  */
 gboolean
 gst_caps_is_equal (const GstCaps * caps1, const GstCaps * caps2)
@@ -1307,7 +1346,7 @@ gst_caps_is_equal (const GstCaps * caps1, const GstCaps * caps2)
  *
  * Checks if the given caps are exactly the same set of caps.
  *
- * Returns: TRUE if both caps are strictly equal.
+ * Returns: %TRUE if both caps are strictly equal.
  */
 gboolean
 gst_caps_is_strictly_equal (const GstCaps * caps1, const GstCaps * caps2)
@@ -1335,8 +1374,9 @@ gst_caps_is_strictly_equal (const GstCaps * caps1, const GstCaps * caps2)
     if (!f2)
       f2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
 
-    if (!gst_structure_is_equal (s1, s2)
-        || !gst_caps_features_is_equal (f1, f2))
+    if (gst_caps_features_is_any (f1) != gst_caps_features_is_any (f2) ||
+        !gst_caps_features_is_equal (f1, f2) ||
+        !gst_structure_is_equal (s1, s2))
       return FALSE;
   }
 
@@ -1416,8 +1456,8 @@ gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2)
       features2 = gst_caps_get_features_unchecked (caps2, k);
       if (!features2)
         features2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
-      if (gst_structure_can_intersect (struct1, struct2) &&
-          gst_caps_features_is_equal (features1, features2)) {
+      if (gst_caps_features_is_equal (features1, features2) &&
+          gst_structure_can_intersect (struct1, struct2)) {
         return TRUE;
       }
       /* move down left */
@@ -1494,11 +1534,19 @@ gst_caps_intersect_zig_zag (GstCaps * caps1, GstCaps * caps2)
       features2 = gst_caps_get_features_unchecked (caps2, k);
       if (!features2)
         features2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
-      istruct = gst_structure_intersect (struct1, struct2);
-      if (istruct && gst_caps_features_is_equal (features1, features2))
-        dest =
-            gst_caps_merge_structure_full (dest, istruct,
-            gst_caps_features_copy_conditional (features1));
+      if (gst_caps_features_is_equal (features1, features2)) {
+        istruct = gst_structure_intersect (struct1, struct2);
+        if (istruct) {
+          if (gst_caps_features_is_any (features1))
+            dest =
+                gst_caps_merge_structure_full (dest, istruct,
+                gst_caps_features_copy_conditional (features2));
+          else
+            dest =
+                gst_caps_merge_structure_full (dest, istruct,
+                gst_caps_features_copy_conditional (features1));
+        }
+      }
       /* move down left */
       k++;
       if (G_UNLIKELY (j == 0))
@@ -1562,9 +1610,19 @@ gst_caps_intersect_first (GstCaps * caps1, GstCaps * caps2)
       features2 = gst_caps_get_features_unchecked (caps2, j);
       if (!features2)
         features2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
-      istruct = gst_structure_intersect (struct1, struct2);
-      if (istruct && gst_caps_features_is_equal (features1, features2))
-        dest = gst_caps_merge_structure (dest, istruct);
+      if (gst_caps_features_is_equal (features1, features2)) {
+        istruct = gst_structure_intersect (struct1, struct2);
+        if (istruct) {
+          if (gst_caps_features_is_any (features1))
+            dest =
+                gst_caps_merge_structure_full (dest, istruct,
+                gst_caps_features_copy_conditional (features2));
+          else
+            dest =
+                gst_caps_merge_structure_full (dest, istruct,
+                gst_caps_features_copy_conditional (features1));
+        }
+      }
     }
   }
 
@@ -1739,6 +1797,10 @@ gst_caps_subtract (GstCaps * minuend, GstCaps * subtrahend)
       min_f = gst_caps_get_features_unchecked (src, j);
       if (!min_f)
         min_f = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY;
+
+      /* Same reason as above for ANY caps */
+      g_return_val_if_fail (!gst_caps_features_is_any (min_f), NULL);
+
       if (gst_structure_get_name_id (min) == gst_structure_get_name_id (sub) &&
           gst_caps_features_is_equal (min_f, sub_f)) {
         GSList *list;
@@ -2051,6 +2113,7 @@ GstCaps *
 gst_caps_fixate (GstCaps * caps)
 {
   GstStructure *s;
+  GstCapsFeatures *f;
 
   g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
 
@@ -2060,6 +2123,13 @@ gst_caps_fixate (GstCaps * caps)
   s = gst_caps_get_structure (caps, 0);
   gst_structure_fixate (s);
 
+  /* Set features to sysmem if they're still ANY */
+  f = gst_caps_get_features_unchecked (caps, 0);
+  if (f && gst_caps_features_is_any (f)) {
+    f = gst_caps_features_new_empty ();
+    gst_caps_set_features (caps, 0, f);
+  }
+
   return caps;
 }
 
@@ -2078,6 +2148,9 @@ gst_caps_fixate (GstCaps * caps)
  * ]|
  * This prints the caps in human readable form.
  *
+ * The current implementation of serialization will lead to unexpected results
+ * when there are nested #GstCaps / #GstStructure deeper than one level.
+ *
  * Returns: (transfer full): a newly allocated string representing @caps.
  */
 gchar *
@@ -2130,9 +2203,9 @@ gst_caps_to_string (const GstCaps * caps)
     features = gst_caps_get_features_unchecked (caps, i);
 
     g_string_append (s, gst_structure_get_name (structure));
-    if (features
-        && !gst_caps_features_is_equal (features,
-            GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)) {
+    if (features && (gst_caps_features_is_any (features)
+            || !gst_caps_features_is_equal (features,
+                GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY))) {
       g_string_append_c (s, '(');
       priv_gst_caps_features_append_to_gstring (features, s);
       g_string_append_c (s, ')');
@@ -2226,12 +2299,15 @@ gst_caps_from_string_inplace (GstCaps * caps, const gchar * string)
 
     if (!priv_gst_structure_parse_fields (s, &s, structure)) {
       gst_structure_free (structure);
+      if (features)
+        gst_caps_features_free (features);
       g_free (copy);
       return FALSE;
     }
 
   append:
     gst_caps_append_structure_unchecked (caps, structure, features);
+    features = NULL;
     if (*s == '\0')
       break;
   } while (TRUE);
@@ -2247,6 +2323,9 @@ gst_caps_from_string_inplace (GstCaps * caps, const gchar * string)
  *
  * Converts @caps from a string representation.
  *
+ * The current implementation of serialization will lead to unexpected results
+ * when there are nested #GstCaps / #GstStructure deeper than one level.
+ *
  * Returns: (transfer full): a newly allocated #GstCaps
  */
 GstCaps *
@@ -2277,3 +2356,151 @@ gst_caps_transform_to_string (const GValue * src_value, GValue * dest_value)
   g_value_take_string (dest_value,
       gst_caps_to_string (gst_value_get_caps (src_value)));
 }
+
+/**
+ * gst_caps_foreach:
+ * @caps: a #GstCaps
+ * @func: (scope call): a function to call for each field
+ * @user_data: (closure): private data
+ *
+ * Calls the provided function once for each structure and caps feature in the
+ * #GstCaps. The function must not modify the fields.
+ * Also see gst_caps_map_in_place() and gst_caps_filter_and_map_in_place().
+ *
+ * Returns: %TRUE if the supplied function returns %TRUE for each call,
+ * %FALSE otherwise.
+ *
+ * Since: 1.6
+ */
+gboolean
+gst_caps_foreach (const GstCaps * caps, GstCapsForeachFunc func,
+    gpointer user_data)
+{
+  guint i, n;
+  GstCapsFeatures *features;
+  GstStructure *structure;
+  gboolean ret;
+
+  g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
+  g_return_val_if_fail (func != NULL, FALSE);
+
+  n = GST_CAPS_LEN (caps);
+
+  for (i = 0; i < n; i++) {
+    features = gst_caps_get_features_unchecked (caps, i);
+    structure = gst_caps_get_structure_unchecked (caps, i);
+
+    ret = func (features, structure, user_data);
+    if (G_UNLIKELY (!ret))
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+ * gst_caps_map_in_place:
+ * @caps: a #GstCaps
+ * @func: (scope call): a function to call for each field
+ * @user_data: (closure): private data
+ *
+ * Calls the provided function once for each structure and caps feature in the
+ * #GstCaps. In contrast to gst_caps_foreach(), the function may modify but not
+ * delete the structures and features. The caps must be mutable.
+ *
+ * Returns: %TRUE if the supplied function returns %TRUE for each call,
+ * %FALSE otherwise.
+ *
+ * Since: 1.6
+ */
+gboolean
+gst_caps_map_in_place (GstCaps * caps, GstCapsMapFunc func, gpointer user_data)
+{
+  guint i, n;
+  GstCapsFeatures *features;
+  GstStructure *structure;
+  gboolean ret;
+
+  g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
+  g_return_val_if_fail (gst_caps_is_writable (caps), FALSE);
+  g_return_val_if_fail (func != NULL, FALSE);
+
+  n = GST_CAPS_LEN (caps);
+
+  for (i = 0; i < n; i++) {
+    features = gst_caps_get_features_unchecked (caps, i);
+    structure = gst_caps_get_structure_unchecked (caps, i);
+
+    /* Provide sysmem features if there are none yet */
+    if (!features) {
+      features =
+          gst_caps_features_copy (GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY);
+      gst_caps_set_features (caps, i, features);
+    }
+
+    ret = func (features, structure, user_data);
+    if (G_UNLIKELY (!ret))
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+ * gst_caps_filter_and_map_in_place:
+ * @caps: a #GstCaps
+ * @func: (scope call): a function to call for each field
+ * @user_data: (closure): private data
+ *
+ * Calls the provided function once for each structure and caps feature in the
+ * #GstCaps. In contrast to gst_caps_foreach(), the function may modify the
+ * structure and features. In contrast to gst_caps_filter_and_map_in_place(),
+ * the structure and features are removed from the caps if %FALSE is returned
+ * from the function.
+ * The caps must be mutable.
+ *
+ * Since: 1.6
+ */
+void
+gst_caps_filter_and_map_in_place (GstCaps * caps, GstCapsFilterMapFunc func,
+    gpointer user_data)
+{
+  guint i, n;
+  GstCapsFeatures *features;
+  GstStructure *structure;
+  gboolean ret;
+
+  g_return_if_fail (GST_IS_CAPS (caps));
+  g_return_if_fail (gst_caps_is_writable (caps));
+  g_return_if_fail (func != NULL);
+
+  n = GST_CAPS_LEN (caps);
+
+  for (i = 0; i < n;) {
+    features = gst_caps_get_features_unchecked (caps, i);
+    structure = gst_caps_get_structure_unchecked (caps, i);
+
+    /* Provide sysmem features if there are none yet */
+    if (!features) {
+      features =
+          gst_caps_features_copy (GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY);
+      gst_caps_set_features (caps, i, features);
+    }
+
+    ret = func (features, structure, user_data);
+    if (!ret) {
+      GST_CAPS_ARRAY (caps) = g_array_remove_index (GST_CAPS_ARRAY (caps), i);
+
+      gst_structure_set_parent_refcount (structure, NULL);
+      gst_structure_free (structure);
+      if (features) {
+        gst_caps_features_set_parent_refcount (features, NULL);
+        gst_caps_features_free (features);
+      }
+
+      n = GST_CAPS_LEN (caps);
+    } else {
+      i++;
+    }
+  }
+}