X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fgstcaps.c;h=c7d990b92ac7ce4658212169b6c46251ede59972;hb=8daad351a46e6e049fd7f0d8acd2f4b986a1bd87;hp=aaa11310d122aaef6757a6a80e81079bcf0e146c;hpb=65c650d7d4f4f814950cbc90c1369abaeaed0a22;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/gstcaps.c b/gst/gstcaps.c index aaa1131..c7d990b 100644 --- a/gst/gstcaps.c +++ b/gst/gstcaps.c @@ -34,20 +34,15 @@ * handle or produce at runtime. * * A #GstCaps can be constructed with the following code fragment: - * - * - * Creating caps - * - * 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); - * - * + * |[ + * 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 @@ -56,7 +51,11 @@ * 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,14 +101,16 @@ 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}; \ @@ -144,6 +145,21 @@ _priv_gst_caps_initialize (void) G_TYPE_STRING, gst_caps_transform_to_string); } +void +_priv_gst_caps_cleanup (void) +{ + gst_caps_unref (_gst_caps_any); + _gst_caps_any = NULL; + gst_caps_unref (_gst_caps_none); + _gst_caps_none = NULL; +} + +GstCapsFeatures * +__gst_caps_get_features_unchecked (const GstCaps * caps, guint idx) +{ + return gst_caps_get_features_unchecked (caps, idx); +} + static GstCaps * _gst_caps_copy (const GstCaps * caps) { @@ -326,7 +342,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 @@ -350,7 +366,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 @@ -483,8 +499,6 @@ gst_caps_remove_and_get_structure (GstCaps * caps, guint idx) return s; } - - /** * gst_caps_steal_structure: * @caps: the #GstCaps to retrieve from @@ -624,6 +638,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, @@ -642,7 +658,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 @@ -689,9 +705,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; } @@ -714,6 +730,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, @@ -740,8 +758,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; } @@ -827,6 +852,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) @@ -837,8 +864,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; } @@ -847,9 +891,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) @@ -860,15 +906,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; + 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) + if (old) { + gst_caps_features_set_parent_refcount (old, NULL); gst_caps_features_free (old); + } } /** @@ -911,6 +960,10 @@ gst_caps_copy_nth (const GstCaps * caps, guint nth) * Discard all but the first structure from @caps. Useful when * fixating. * + * This function takes ownership of @caps and will call gst_caps_make_writable() + * on it if necessary, so you must not use @caps afterwards unless you keep an + * additional reference to it with gst_caps_ref(). + * * Returns: (transfer full): truncated caps */ GstCaps * @@ -965,7 +1018,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 +1055,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 +1078,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 +1094,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,7 +1122,7 @@ 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) @@ -1082,7 +1135,7 @@ gst_caps_is_fixed (const GstCaps * caps) if (GST_CAPS_LEN (caps) != 1) return FALSE; - features = gst_caps_get_features (caps, 0); + features = gst_caps_get_features_unchecked (caps, 0); if (features && gst_caps_features_is_any (features)) return FALSE; @@ -1099,7 +1152,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) @@ -1132,7 +1185,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) @@ -1149,8 +1202,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. - * This function does not work reliably if optional properties for caps - * are included on one caps and omitted on the other. * * Returns: %TRUE if @subset is a subset of @superset */ @@ -1180,8 +1231,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; @@ -1244,6 +1296,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, @@ -1269,8 +1323,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; } @@ -1285,10 +1340,8 @@ gst_caps_is_subset_structure_full (const GstCaps * caps, * @caps2: another #GstCaps * * Checks if the given caps represent the same set of caps. - * This function does not work reliably if optional properties for caps - * are included on one caps and omitted on the other. * - * 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) @@ -1312,7 +1365,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) @@ -1340,8 +1393,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; } @@ -1405,7 +1459,7 @@ gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2) len1 = GST_CAPS_LEN (caps1); len2 = GST_CAPS_LEN (caps2); for (i = 0; i < len1 + len2 - 1; i++) { - /* superset index goes from 0 to sgst_caps_structure_intersectuperset->structs->len-1 */ + /* superset index goes from 0 to superset->structs->len-1 */ j = MIN (i, len1 - 1); /* subset index stays 0 until i reaches superset->structs->len, then it * counts up from 1 to subset->structs->len - 1 */ @@ -1421,8 +1475,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 */ @@ -1499,11 +1553,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)) @@ -1525,7 +1587,7 @@ gst_caps_intersect_zig_zag (GstCaps * caps1, GstCaps * caps2) * Unlike @gst_caps_intersect, the returned caps will be ordered in a similar * fashion as @caps1. * - * Returns: the new #GstCaps + * Returns: (transfer full): the new #GstCaps */ static GstCaps * gst_caps_intersect_first (GstCaps * caps1, GstCaps * caps2) @@ -1567,9 +1629,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)); + } + } } } @@ -1586,7 +1658,7 @@ gst_caps_intersect_first (GstCaps * caps1, GstCaps * caps2) * to both @caps1 and @caps2, the order is defined by the #GstCapsIntersectMode * used. * - * Returns: the new #GstCaps + * Returns: (transfer full): the new #GstCaps */ GstCaps * gst_caps_intersect_full (GstCaps * caps1, GstCaps * caps2, @@ -1614,7 +1686,7 @@ gst_caps_intersect_full (GstCaps * caps1, GstCaps * caps2, * Creates a new #GstCaps that contains all the formats that are common * to both @caps1 and @caps2. Defaults to %GST_CAPS_INTERSECT_ZIG_ZAG mode. * - * Returns: the new #GstCaps + * Returns: (transfer full): the new #GstCaps */ GstCaps * gst_caps_intersect (GstCaps * caps1, GstCaps * caps2) @@ -1694,7 +1766,7 @@ gst_caps_structure_subtract (GSList ** into, const GstStructure * minuend, * This function does not work reliably if optional properties for caps * are included on one caps and omitted on the other. * - * Returns: the resulting caps + * Returns: (transfer full): the resulting caps */ GstCaps * gst_caps_subtract (GstCaps * minuend, GstCaps * subtrahend) @@ -1744,6 +1816,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; @@ -1823,7 +1899,9 @@ gst_caps_normalize_foreach (GQuark field_id, const GValue * value, gpointer ptr) * @caps, but contains no lists. Each list is expanded into separate * @GstStructures. * - * This function takes ownership of @caps. + * This function takes ownership of @caps and will call gst_caps_make_writable() + * on it so you must not use @caps afterwards unless you keep an additional + * reference to it with gst_caps_ref(). * * Returns: (transfer full): the normalized #GstCaps */ @@ -1980,9 +2058,13 @@ gst_caps_switch_structures (GstCaps * caps, GstStructure * old, * identical are merged. Component structures that have values that can be * merged are also merged. * + * This function takes ownership of @caps and will call gst_caps_make_writable() + * on it if necessary, so you must not use @caps afterwards unless you keep an + * additional reference to it with gst_caps_ref(). + * * This method does not preserve the original order of @caps. * - * Returns: The simplified caps. + * Returns: (transfer full): The simplified caps. */ GstCaps * gst_caps_simplify (GstCaps * caps) @@ -2050,12 +2132,17 @@ gst_caps_simplify (GstCaps * caps) * values. First the caps will be truncated and then the first structure will be * fixated with gst_structure_fixate(). * + * This function takes ownership of @caps and will call gst_caps_make_writable() + * on it so you must not use @caps afterwards unless you keep an additional + * reference to it with gst_caps_ref(). + * * Returns: (transfer full): the fixated caps */ GstCaps * gst_caps_fixate (GstCaps * caps) { GstStructure *s; + GstCapsFeatures *f; g_return_val_if_fail (GST_IS_CAPS (caps), NULL); @@ -2065,6 +2152,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,11 +2172,14 @@ gst_caps_fixate (GstCaps * caps) * can be converted back to a #GstCaps by gst_caps_from_string(). * * For debugging purposes its easier to do something like this: - * |[ + * |[ * GST_LOG ("caps are %" GST_PTR_FORMAT, 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 * @@ -2135,9 +2232,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, ')'); @@ -2231,12 +2328,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); @@ -2252,6 +2352,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 * @@ -2282,3 +2385,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++; + } + } +}