X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fgstcaps.c;h=4b3b8c8ed862305144ff2bc46c42264be52e8810;hb=ccd2966f7a0af2bab970415225cbd4317392d89a;hp=57f8ae69684b4871af3fa8a2610151e4d6eb4f03;hpb=4348851cd98d50013f341e067c06f4176ff41fce;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/gstcaps.c b/gst/gstcaps.c index 57f8ae6..4b3b8c8 100644 --- a/gst/gstcaps.c +++ b/gst/gstcaps.c @@ -13,8 +13,8 @@ * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ /** @@ -29,7 +29,7 @@ * given pad can handle. They are also stored in the #GstRegistry along with * a description of the #GstElement. * - * Caps are exposed on the element pads using the gst_pad_get_caps() pad + * Caps are exposed on the element pads using the gst_pad_query_caps() pad * function. This function describes the possible types that the pad can * handle or produce at runtime. * @@ -71,11 +71,17 @@ #define DEBUG_REFCOUNT +typedef struct _GstCapsArrayElement +{ + GstStructure *structure; + GstCapsFeatures *features; +} GstCapsArrayElement; + typedef struct _GstCapsImpl { GstCaps caps; - GPtrArray *array; + GArray *array; } GstCapsImpl; #define GST_CAPS_ARRAY(c) (((GstCapsImpl *)(c))->array) @@ -96,15 +102,20 @@ 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) + /* 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) \ - ((GstStructure *)g_ptr_array_index (GST_CAPS_ARRAY (caps), (index))) + (g_array_index (GST_CAPS_ARRAY (caps), GstCapsArrayElement, (index)).structure) +#define gst_caps_get_features_unchecked(caps, index) \ + (g_array_index (GST_CAPS_ARRAY (caps), GstCapsArrayElement, (index)).features) /* quick way to append a structure without checking the args */ -#define gst_caps_append_structure_unchecked(caps, structure) G_STMT_START{\ - GstStructure *__s=structure; \ - if (gst_structure_set_parent_refcount (__s, &GST_MINI_OBJECT_REFCOUNT(caps))) \ - g_ptr_array_add (GST_CAPS_ARRAY (caps), __s); \ +#define gst_caps_append_structure_unchecked(caps, s, f) G_STMT_START{\ + GstCapsArrayElement __e={s, f}; \ + 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); \ }G_STMT_END /* lock to protect multiple invocations of static caps to caps conversion */ @@ -138,6 +149,7 @@ _gst_caps_copy (const GstCaps * caps) { GstCaps *newcaps; GstStructure *structure; + GstCapsFeatures *features; guint i, n; g_return_val_if_fail (GST_IS_CAPS (caps), NULL); @@ -151,7 +163,9 @@ _gst_caps_copy (const GstCaps * caps) for (i = 0; i < n; i++) { structure = gst_caps_get_structure_unchecked (caps, i); - gst_caps_append_structure (newcaps, gst_structure_copy (structure)); + features = gst_caps_get_features_unchecked (caps, i); + gst_caps_append_structure_full (newcaps, gst_structure_copy (structure), + gst_caps_features_copy_conditional (features)); } return newcaps; @@ -162,6 +176,7 @@ static void _gst_caps_free (GstCaps * caps) { GstStructure *structure; + GstCapsFeatures *features; guint i, len; /* The refcount must be 0, but since we're only called by gst_caps_unref, @@ -170,33 +185,37 @@ _gst_caps_free (GstCaps * caps) /* This can be used to get statistics about caps sizes */ /*GST_CAT_INFO (GST_CAT_CAPS, "caps size: %d", len); */ for (i = 0; i < len; i++) { - structure = (GstStructure *) gst_caps_get_structure_unchecked (caps, i); + structure = gst_caps_get_structure_unchecked (caps, i); gst_structure_set_parent_refcount (structure, NULL); gst_structure_free (structure); + features = gst_caps_get_features_unchecked (caps, i); + if (features) { + gst_caps_features_set_parent_refcount (features, NULL); + gst_caps_features_free (features); + } } - g_ptr_array_free (GST_CAPS_ARRAY (caps), TRUE); + g_array_free (GST_CAPS_ARRAY (caps), TRUE); #ifdef DEBUG_REFCOUNT - GST_CAT_LOG (GST_CAT_CAPS, "freeing caps %p", caps); + GST_CAT_TRACE (GST_CAT_CAPS, "freeing caps %p", caps); #endif - g_slice_free1 (GST_MINI_OBJECT_SIZE (caps), caps); + g_slice_free1 (sizeof (GstCapsImpl), caps); } static void -gst_caps_init (GstCaps * caps, gsize size) +gst_caps_init (GstCaps * caps) { - gst_mini_object_init (GST_MINI_OBJECT_CAST (caps), _gst_caps_type, size); - - caps->mini_object.copy = (GstMiniObjectCopyFunction) _gst_caps_copy; - caps->mini_object.dispose = NULL; - caps->mini_object.free = (GstMiniObjectFreeFunction) _gst_caps_free; + gst_mini_object_init (GST_MINI_OBJECT_CAST (caps), 0, _gst_caps_type, + (GstMiniObjectCopyFunction) _gst_caps_copy, NULL, + (GstMiniObjectFreeFunction) _gst_caps_free); /* the 32 has been determined by logging caps sizes in _gst_caps_free * but g_ptr_array uses 16 anyway if it expands once, so this does not help * in practice * GST_CAPS_ARRAY (caps) = g_ptr_array_sized_new (32); */ - GST_CAPS_ARRAY (caps) = g_ptr_array_new (); + GST_CAPS_ARRAY (caps) = + g_array_new (FALSE, TRUE, sizeof (GstCapsArrayElement)); } /** @@ -216,7 +235,7 @@ gst_caps_new_empty (void) caps = (GstCaps *) g_slice_new (GstCapsImpl); - gst_caps_init (caps, sizeof (GstCapsImpl)); + gst_caps_init (caps); #ifdef DEBUG_REFCOUNT GST_CAT_TRACE (GST_CAT_CAPS, "created caps %p", caps); @@ -262,7 +281,7 @@ gst_caps_new_empty_simple (const char *media_type) caps = gst_caps_new_empty (); structure = gst_structure_new_empty (media_type); if (structure) - gst_caps_append_structure_unchecked (caps, structure); + gst_caps_append_structure_unchecked (caps, structure, NULL); return caps; } @@ -294,7 +313,7 @@ gst_caps_new_simple (const char *media_type, const char *fieldname, ...) va_end (var_args); if (structure) - gst_caps_append_structure_unchecked (caps, structure); + gst_caps_append_structure_unchecked (caps, structure, NULL); else gst_caps_replace (&caps, NULL); @@ -344,7 +363,7 @@ gst_caps_new_full_valist (GstStructure * structure, va_list var_args) caps = gst_caps_new_empty (); while (structure) { - gst_caps_append_structure_unchecked (caps, structure); + gst_caps_append_structure_unchecked (caps, structure, NULL); structure = va_arg (var_args, GstStructure *); } @@ -428,16 +447,44 @@ gst_static_caps_cleanup (GstStaticCaps * static_caps) /* manipulation */ +static void +gst_caps_remove_and_get_structure_and_features (GstCaps * caps, guint idx, + GstStructure ** s, GstCapsFeatures ** f) +{ + GstStructure *s_; + GstCapsFeatures *f_; + + s_ = gst_caps_get_structure_unchecked (caps, idx); + f_ = gst_caps_get_features_unchecked (caps, idx); + + /* don't use index_fast, gst_caps_simplify relies on the order */ + g_array_remove_index (GST_CAPS_ARRAY (caps), idx); + + gst_structure_set_parent_refcount (s_, NULL); + if (f_) { + gst_caps_features_set_parent_refcount (f_, NULL); + } + + *s = s_; + *f = f_; +} + static GstStructure * gst_caps_remove_and_get_structure (GstCaps * caps, guint idx) { - /* don't use index_fast, gst_caps_simplify relies on the order */ - GstStructure *s = g_ptr_array_remove_index (GST_CAPS_ARRAY (caps), idx); + GstStructure *s; + GstCapsFeatures *f; + + gst_caps_remove_and_get_structure_and_features (caps, idx, &s, &f); + + if (f) + gst_caps_features_free (f); - gst_structure_set_parent_refcount (s, NULL); return s; } + + /** * gst_caps_steal_structure: * @caps: the #GstCaps to retrieve from @@ -448,8 +495,6 @@ gst_caps_remove_and_get_structure (GstCaps * caps, guint idx) * * Returns: (transfer full): a pointer to the #GstStructure corresponding * to @index. - * - * Since: 0.10.30 */ GstStructure * gst_caps_steal_structure (GstCaps * caps, guint index) @@ -476,6 +521,7 @@ void gst_caps_append (GstCaps * caps1, GstCaps * caps2) { GstStructure *structure; + GstCapsFeatures *features; int i; g_return_if_fail (GST_IS_CAPS (caps1)); @@ -489,8 +535,9 @@ gst_caps_append (GstCaps * caps1, GstCaps * caps2) caps2 = gst_caps_make_writable (caps2); for (i = GST_CAPS_LEN (caps2); i; i--) { - structure = gst_caps_remove_and_get_structure (caps2, 0); - gst_caps_append_structure_unchecked (caps1, structure); + gst_caps_remove_and_get_structure_and_features (caps2, 0, &structure, + &features); + gst_caps_append_structure_unchecked (caps1, structure, features); } gst_caps_unref (caps2); /* guaranteed to free it */ } @@ -507,13 +554,12 @@ gst_caps_append (GstCaps * caps1, GstCaps * caps2) * If either caps is ANY, the resulting caps will be ANY. * * Returns: (transfer full): the merged caps. - * - * Since: 0.10.10 */ GstCaps * gst_caps_merge (GstCaps * caps1, GstCaps * caps2) { GstStructure *structure; + GstCapsFeatures *features; int i; GstCaps *result; @@ -530,8 +576,9 @@ gst_caps_merge (GstCaps * caps1, GstCaps * caps2) caps2 = gst_caps_make_writable (caps2); for (i = GST_CAPS_LEN (caps2); i; i--) { - structure = gst_caps_remove_and_get_structure (caps2, 0); - caps1 = gst_caps_merge_structure (caps1, structure); + gst_caps_remove_and_get_structure_and_features (caps2, 0, &structure, + &features); + caps1 = gst_caps_merge_structure_full (caps1, structure, features); } gst_caps_unref (caps2); result = caps1; @@ -565,7 +612,28 @@ gst_caps_append_structure (GstCaps * caps, GstStructure * structure) g_return_if_fail (IS_WRITABLE (caps)); if (G_LIKELY (structure)) { - gst_caps_append_structure_unchecked (caps, structure); + gst_caps_append_structure_unchecked (caps, structure, NULL); + } +} + +/** + * gst_caps_append_structure_full: + * @caps: the #GstCaps that will be appended to + * @structure: (transfer full): the #GstStructure to append + * @features: (transfer full) (allow-none): the #GstCapsFeatures to append + * + * Appends @structure with @features to @caps. The structure is not copied; @caps + * becomes the owner of @structure. + */ +void +gst_caps_append_structure_full (GstCaps * caps, GstStructure * structure, + GstCapsFeatures * features) +{ + g_return_if_fail (GST_IS_CAPS (caps)); + g_return_if_fail (IS_WRITABLE (caps)); + + if (G_LIKELY (structure)) { + gst_caps_append_structure_unchecked (caps, structure, features); } } @@ -603,6 +671,56 @@ GstCaps * gst_caps_merge_structure (GstCaps * caps, GstStructure * structure) { GstStructure *structure1; + GstCapsFeatures *features1; + int i; + gboolean unique = TRUE; + + g_return_val_if_fail (GST_IS_CAPS (caps), NULL); + + if (G_UNLIKELY (structure == NULL)) + return caps; + + /* check each structure */ + for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) { + structure1 = gst_caps_get_structure_unchecked (caps, i); + features1 = gst_caps_get_features_unchecked (caps, i); + if (!features1) + features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; + + /* 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)) { + unique = FALSE; + break; + } + } + if (unique) { + caps = gst_caps_make_writable (caps); + gst_caps_append_structure_unchecked (caps, structure, NULL); + } else { + gst_structure_free (structure); + } + return caps; +} + +/** + * gst_caps_merge_structure_full: + * @caps: (transfer full): the #GstCaps to merge into + * @structure: (transfer full): the #GstStructure to merge + * @features: (transfer full) (allow-none): the #GstCapsFeatures to merge + * + * Appends @structure with @features to @caps if its not already expressed by @caps. + * + * Returns: (transfer full): the merged caps. + */ +GstCaps * +gst_caps_merge_structure_full (GstCaps * caps, GstStructure * structure, + GstCapsFeatures * features) +{ + GstStructure *structure1; + GstCapsFeatures *features1, *features_tmp; int i; gboolean unique = TRUE; @@ -611,20 +729,30 @@ gst_caps_merge_structure (GstCaps * caps, GstStructure * structure) if (G_UNLIKELY (structure == NULL)) return caps; + /* To make comparisons easier below */ + features_tmp = features ? features : GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; + /* check each structure */ for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) { structure1 = gst_caps_get_structure_unchecked (caps, i); - /* if structure is a subset of structure1, then skip it */ - if (gst_structure_is_subset (structure, structure1)) { + features1 = gst_caps_get_features_unchecked (caps, i); + if (!features1) + 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)) { unique = FALSE; break; } } if (unique) { caps = gst_caps_make_writable (caps); - gst_caps_append_structure_unchecked (caps, structure); + gst_caps_append_structure_unchecked (caps, structure, features); } else { gst_structure_free (structure); + if (features) + gst_caps_features_free (features); } return caps; } @@ -678,6 +806,68 @@ gst_caps_get_structure (const GstCaps * caps, guint index) } /** + * gst_caps_get_features: + * @caps: a #GstCaps + * @index: the index of the structure + * + * Finds the features in @caps that has the index @index, and + * returns it. + * + * WARNING: This function takes a const GstCaps *, but returns a + * non-const GstCapsFeatures *. This is for programming convenience -- + * the caller should be aware that structures inside a constant + * #GstCaps should not be modified. However, if you know the caps + * are writable, either because you have just copied them or made + * them writable with gst_caps_make_writable(), you may modify the + * features returned in the usual way, e.g. with functions like + * gst_caps_features_add(). + * + * You do not need to free or unref the structure returned, it + * belongs to the #GstCaps. + * + * Returns: (transfer none): a pointer to the #GstCapsFeatures corresponding + * to @index + */ +GstCapsFeatures * +gst_caps_get_features (const GstCaps * caps, guint index) +{ + GstCapsFeatures *features; + + g_return_val_if_fail (GST_IS_CAPS (caps), NULL); + g_return_val_if_fail (index < GST_CAPS_LEN (caps), NULL); + + features = gst_caps_get_features_unchecked (caps, index); + if (!features) + features = gst_caps_features_copy (GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY); + + return features; +} + +/** + * gst_caps_set_features: + * @caps: a #GstCaps + * @index: the index of the structure + * @features: (allow-none) (transfer full): the #GstFeatures to set + * + * Sets the #GstCapsFeatures @features for the structure at @index. + */ +void +gst_caps_set_features (GstCaps * caps, guint index, GstCapsFeatures * features) +{ + GstCapsFeatures **storage, *old; + + g_return_if_fail (caps != NULL); + 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) + gst_caps_features_free (old); +} + +/** * gst_caps_copy_nth: * @caps: the #GstCaps to copy * @nth: the nth structure to copy @@ -692,6 +882,7 @@ gst_caps_copy_nth (const GstCaps * caps, guint nth) { GstCaps *newcaps; GstStructure *structure; + GstCapsFeatures *features; g_return_val_if_fail (GST_IS_CAPS (caps), NULL); @@ -700,8 +891,10 @@ gst_caps_copy_nth (const GstCaps * caps, guint nth) if (G_LIKELY (GST_CAPS_LEN (caps) > nth)) { structure = gst_caps_get_structure_unchecked (caps, nth); + features = gst_caps_get_features_unchecked (caps, nth); gst_caps_append_structure_unchecked (newcaps, - gst_structure_copy (structure)); + gst_structure_copy (structure), + gst_caps_features_copy_conditional (features)); } return newcaps; @@ -743,8 +936,6 @@ gst_caps_truncate (GstCaps * caps) * Sets the given @field on all structures of @caps to the given @value. * This is a convenience function for calling gst_structure_set_value() on * all structures of @caps. - * - * Since: 0.10.26 **/ void gst_caps_set_value (GstCaps * caps, const char *field, const GValue * value) @@ -771,10 +962,6 @@ gst_caps_set_value (GstCaps * caps, const char *field, const GValue * value) * * Sets fields in a #GstCaps. The arguments must be passed in the same * manner as gst_structure_set(), and be NULL-terminated. - * Prior to GStreamer version 0.10.26, this function failed when - * @caps was not simple. If your code needs to work with those versions - * of GStreamer, you may only call this function when GST_CAPS_IS_SIMPLE() - * is %TRUE for @caps. */ void gst_caps_set_simple_valist (GstCaps * caps, const char *field, va_list varargs) @@ -812,10 +999,6 @@ gst_caps_set_simple_valist (GstCaps * caps, const char *field, va_list varargs) * * Sets fields in a #GstCaps. The arguments must be passed in the same * manner as gst_structure_set(), and be NULL-terminated. - * Prior to GStreamer version 0.10.26, this function failed when - * @caps was not simple. If your code needs to work with those versions - * of GStreamer, you may only call this function when GST_CAPS_IS_SIMPLE() - * is %TRUE for @caps. */ void gst_caps_set_simple (GstCaps * caps, const char *field, ...) @@ -913,14 +1096,22 @@ gboolean gst_caps_is_equal_fixed (const GstCaps * caps1, const GstCaps * caps2) { GstStructure *struct1, *struct2; + GstCapsFeatures *features1, *features2; g_return_val_if_fail (gst_caps_is_fixed (caps1), FALSE); g_return_val_if_fail (gst_caps_is_fixed (caps2), FALSE); struct1 = gst_caps_get_structure_unchecked (caps1, 0); + features1 = gst_caps_get_features_unchecked (caps1, 0); + if (!features1) + features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; struct2 = gst_caps_get_structure_unchecked (caps2, 0); + features2 = gst_caps_get_features_unchecked (caps2, 0); + if (!features2) + features2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; - return gst_structure_is_equal (struct1, struct2); + return gst_structure_is_equal (struct1, struct2) && + gst_caps_features_is_equal (features1, features2); } /** @@ -958,6 +1149,7 @@ gboolean gst_caps_is_subset (const GstCaps * subset, const GstCaps * superset) { GstStructure *s1, *s2; + GstCapsFeatures *f1, *f2; gboolean ret = TRUE; gint i, j; @@ -972,8 +1164,15 @@ gst_caps_is_subset (const GstCaps * subset, const GstCaps * superset) for (i = GST_CAPS_LEN (subset) - 1; i >= 0; i--) { for (j = GST_CAPS_LEN (superset) - 1; j >= 0; j--) { s1 = gst_caps_get_structure_unchecked (subset, i); + f1 = gst_caps_get_features_unchecked (subset, i); + if (!f1) + f1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; s2 = gst_caps_get_structure_unchecked (superset, j); - if (gst_structure_is_subset (s1, s2)) { + 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 we found a superset, continue with the next * subset structure */ break; @@ -999,8 +1198,6 @@ gst_caps_is_subset (const GstCaps * subset, const GstCaps * superset) * for more information. * * Returns: %TRUE if @structure is a subset of @caps - * - * Since: 0.10.36 */ gboolean gst_caps_is_subset_structure (const GstCaps * caps, @@ -1029,6 +1226,51 @@ gst_caps_is_subset_structure (const GstCaps * caps, } /** + * gst_caps_is_subset_structure_full: + * @caps: a #GstCaps + * @structure: a potential #GstStructure subset of @caps + * @features: (allow-none): a #GstCapsFeatures for @structure + * + * Checks if @structure is a subset of @caps. See gst_caps_is_subset() + * for more information. + * + * Returns: %TRUE if @structure is a subset of @caps + */ +gboolean +gst_caps_is_subset_structure_full (const GstCaps * caps, + const GstStructure * structure, const GstCapsFeatures * features) +{ + GstStructure *s; + GstCapsFeatures *f; + gint i; + + g_return_val_if_fail (caps != NULL, FALSE); + g_return_val_if_fail (structure != NULL, FALSE); + + if (CAPS_IS_ANY (caps)) + return TRUE; + if (CAPS_IS_EMPTY (caps)) + return FALSE; + + if (!features) + features = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; + + for (i = GST_CAPS_LEN (caps) - 1; i >= 0; i--) { + s = gst_caps_get_structure_unchecked (caps, i); + 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 we found a superset return TRUE */ + return TRUE; + } + } + + return FALSE; +} + +/** * gst_caps_is_equal: * @caps1: a #GstCaps * @caps2: another #GstCaps @@ -1037,8 +1279,6 @@ gst_caps_is_subset_structure (const GstCaps * caps, * This function does not work reliably if optional properties for caps * are included on one caps and omitted on the other. * - * This function deals correctly with passing NULL for any of the caps. - * * Returns: TRUE if both caps are equal. */ gboolean @@ -1063,16 +1303,14 @@ gst_caps_is_equal (const GstCaps * caps1, const GstCaps * caps2) * * Checks if the given caps are exactly the same set of caps. * - * This function deals correctly with passing NULL for any of the caps. - * * Returns: TRUE if both caps are strictly equal. - * - * Since: 0.10.36 */ gboolean gst_caps_is_strictly_equal (const GstCaps * caps1, const GstCaps * caps2) { int i; + GstStructure *s1, *s2; + GstCapsFeatures *f1, *f2; g_return_val_if_fail (GST_IS_CAPS (caps1), FALSE); g_return_val_if_fail (GST_IS_CAPS (caps2), FALSE); @@ -1084,8 +1322,17 @@ gst_caps_is_strictly_equal (const GstCaps * caps1, const GstCaps * caps2) return FALSE; for (i = 0; i < GST_CAPS_LEN (caps1); i++) { - if (!gst_structure_is_equal (gst_caps_get_structure_unchecked (caps1, i), - gst_caps_get_structure_unchecked (caps2, i))) + s1 = gst_caps_get_structure_unchecked (caps1, i); + f1 = gst_caps_get_features_unchecked (caps1, i); + if (!f1) + f1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; + s2 = gst_caps_get_structure_unchecked (caps2, i); + f2 = gst_caps_get_features_unchecked (caps2, i); + if (!f2) + f2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; + + if (!gst_structure_is_equal (s1, s2) + || !gst_caps_features_is_equal (f1, f2)) return FALSE; } @@ -1103,8 +1350,6 @@ gst_caps_is_strictly_equal (const GstCaps * caps1, const GstCaps * caps2) * be empty * * Returns: %TRUE if intersection would be not empty - * - * Since: 0.10.25 */ gboolean gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2) @@ -1113,6 +1358,8 @@ gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2) guint j, k, len1, len2; GstStructure *struct1; GstStructure *struct2; + GstCapsFeatures *features1; + GstCapsFeatures *features2; g_return_val_if_fail (GST_IS_CAPS (caps1), FALSE); g_return_val_if_fail (GST_IS_CAPS (caps2), FALSE); @@ -1154,14 +1401,19 @@ gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2) /* subset index stays 0 until i reaches superset->structs->len, then it * counts up from 1 to subset->structs->len - 1 */ k = (i > j) ? (i - j) : 0; /* MAX (0, i - j) */ - /* now run the diagonal line, end condition is the left or bottom * border */ while (k < len2) { struct1 = gst_caps_get_structure_unchecked (caps1, j); + features1 = gst_caps_get_features_unchecked (caps1, j); + if (!features1) + features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; struct2 = gst_caps_get_structure_unchecked (caps2, k); - - if (gst_structure_can_intersect (struct1, struct2)) { + 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)) { return TRUE; } /* move down left */ @@ -1171,6 +1423,7 @@ gst_caps_can_intersect (const GstCaps * caps1, const GstCaps * caps2) j--; } } + return FALSE; } @@ -1179,9 +1432,10 @@ gst_caps_intersect_zig_zag (GstCaps * caps1, GstCaps * caps2) { guint64 i; /* index can be up to 2 * G_MAX_UINT */ guint j, k, len1, len2; - GstStructure *struct1; GstStructure *struct2; + GstCapsFeatures *features1; + GstCapsFeatures *features2; GstCaps *dest; GstStructure *istruct; @@ -1196,11 +1450,11 @@ gst_caps_intersect_zig_zag (GstCaps * caps1, GstCaps * caps2) /* one of the caps is any, just copy the other caps */ if (G_UNLIKELY (CAPS_IS_ANY (caps1))) return gst_caps_ref (caps2); + if (G_UNLIKELY (CAPS_IS_ANY (caps2))) return gst_caps_ref (caps1); dest = gst_caps_new_empty (); - /* run zigzag on top line then right line, this preserves the caps order * much better than a simple loop. * @@ -1225,16 +1479,22 @@ gst_caps_intersect_zig_zag (GstCaps * caps1, GstCaps * caps2) /* caps2 index stays 0 until i reaches GST_CAPS_LEN (caps1), then it counts * up from 1 to GST_CAPS_LEN (caps2) - 1 */ k = (i > j) ? (i - j) : 0; /* MAX (0, i - j) */ - /* now run the diagonal line, end condition is the left or bottom * border */ while (k < len2) { struct1 = gst_caps_get_structure_unchecked (caps1, j); + features1 = gst_caps_get_features_unchecked (caps1, j); + if (!features1) + features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; struct2 = gst_caps_get_structure_unchecked (caps2, k); - + features2 = gst_caps_get_features_unchecked (caps2, k); + if (!features2) + features2 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; istruct = gst_structure_intersect (struct1, struct2); - - dest = gst_caps_merge_structure (dest, istruct); + if (istruct && gst_caps_features_is_equal (features1, features2)) + dest = + gst_caps_merge_structure_full (dest, istruct, + gst_caps_features_copy_conditional (features1)); /* move down left */ k++; if (G_UNLIKELY (j == 0)) @@ -1263,9 +1523,10 @@ gst_caps_intersect_first (GstCaps * caps1, GstCaps * caps2) { guint i; guint j, len1, len2; - GstStructure *struct1; GstStructure *struct2; + GstCapsFeatures *features1; + GstCapsFeatures *features2; GstCaps *dest; GstStructure *istruct; @@ -1280,19 +1541,25 @@ gst_caps_intersect_first (GstCaps * caps1, GstCaps * caps2) /* one of the caps is any, just copy the other caps */ if (G_UNLIKELY (CAPS_IS_ANY (caps1))) return gst_caps_ref (caps2); + if (G_UNLIKELY (CAPS_IS_ANY (caps2))) return gst_caps_ref (caps1); dest = gst_caps_new_empty (); - len1 = GST_CAPS_LEN (caps1); len2 = GST_CAPS_LEN (caps2); for (i = 0; i < len1; i++) { struct1 = gst_caps_get_structure_unchecked (caps1, i); + features1 = gst_caps_get_features_unchecked (caps1, i); + if (!features1) + features1 = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; for (j = 0; j < len2; j++) { struct2 = gst_caps_get_structure_unchecked (caps2, j); + 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) + if (istruct && gst_caps_features_is_equal (features1, features2)) dest = gst_caps_merge_structure (dest, istruct); } } @@ -1311,7 +1578,6 @@ gst_caps_intersect_first (GstCaps * caps1, GstCaps * caps2) * used. * * Returns: the new #GstCaps - * Since: 0.10.33 */ GstCaps * gst_caps_intersect_full (GstCaps * caps1, GstCaps * caps2, @@ -1347,15 +1613,13 @@ gst_caps_intersect (GstCaps * caps1, GstCaps * caps2) return gst_caps_intersect_full (caps1, caps2, GST_CAPS_INTERSECT_ZIG_ZAG); } - /* subtract operation */ typedef struct { const GstStructure *subtract_from; GSList *put_into; -} -SubtractionEntry; +} SubtractionEntry; static gboolean gst_caps_structure_subtract_field (GQuark field_id, const GValue * value, @@ -1367,18 +1631,20 @@ gst_caps_structure_subtract_field (GQuark field_id, const GValue * value, GstStructure *structure; other = gst_structure_id_get_value (e->subtract_from, field_id); + if (!other) { return FALSE; } + if (!gst_value_subtract (&subtraction, other, value)) return TRUE; + if (gst_value_compare (&subtraction, other) == GST_VALUE_EQUAL) { g_value_unset (&subtraction); return FALSE; } else { structure = gst_structure_copy (e->subtract_from); - gst_structure_id_set_value (structure, field_id, &subtraction); - g_value_unset (&subtraction); + gst_structure_id_take_value (structure, field_id, &subtraction); e->put_into = g_slist_prepend (e->put_into, structure); return TRUE; } @@ -1393,9 +1659,9 @@ gst_caps_structure_subtract (GSList ** into, const GstStructure * minuend, e.subtract_from = minuend; e.put_into = NULL; - ret = gst_structure_foreach ((GstStructure *) subtrahend, gst_caps_structure_subtract_field, &e); + if (ret) { *into = e.put_into; } else { @@ -1406,6 +1672,7 @@ gst_caps_structure_subtract (GSList ** into, const GstStructure * minuend, } g_slist_free (e.put_into); } + return ret; } @@ -1426,6 +1693,7 @@ gst_caps_subtract (GstCaps * minuend, GstCaps * subtrahend) guint i, j, sublen; GstStructure *min; GstStructure *sub; + GstCapsFeatures *min_f, *sub_f; GstCaps *dest = NULL, *src; g_return_val_if_fail (minuend != NULL, NULL); @@ -1434,6 +1702,7 @@ gst_caps_subtract (GstCaps * minuend, GstCaps * subtrahend) if (CAPS_IS_EMPTY (minuend) || CAPS_IS_ANY (subtrahend)) { return gst_caps_new_empty (); } + if (CAPS_IS_EMPTY_SIMPLE (subtrahend)) return gst_caps_ref (minuend); @@ -1442,6 +1711,7 @@ gst_caps_subtract (GstCaps * minuend, GstCaps * subtrahend) ANY means for specific types, so it's not possible to reduce ANY partially You can only remove everything or nothing and that is done above. Note: there's a test that checks this behaviour. */ + g_return_val_if_fail (!CAPS_IS_ANY (minuend), NULL); sublen = GST_CAPS_LEN (subtrahend); g_assert (sublen > 0); @@ -1451,6 +1721,9 @@ gst_caps_subtract (GstCaps * minuend, GstCaps * subtrahend) guint srclen; sub = gst_caps_get_structure_unchecked (subtrahend, i); + sub_f = gst_caps_get_features_unchecked (subtrahend, i); + if (!sub_f) + sub_f = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; if (dest) { gst_caps_unref (src); src = dest; @@ -1459,7 +1732,11 @@ gst_caps_subtract (GstCaps * minuend, GstCaps * subtrahend) srclen = GST_CAPS_LEN (src); for (j = 0; j < srclen; j++) { min = gst_caps_get_structure_unchecked (src, j); - if (gst_structure_get_name_id (min) == gst_structure_get_name_id (sub)) { + min_f = gst_caps_get_features_unchecked (src, j); + if (!min_f) + min_f = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; + if (gst_structure_get_name_id (min) == gst_structure_get_name_id (sub) && + gst_caps_features_is_equal (min_f, sub_f)) { GSList *list; if (gst_caps_structure_subtract (&list, min, sub)) { @@ -1467,16 +1744,20 @@ gst_caps_subtract (GstCaps * minuend, GstCaps * subtrahend) for (walk = list; walk; walk = g_slist_next (walk)) { gst_caps_append_structure_unchecked (dest, - (GstStructure *) walk->data); + (GstStructure *) walk->data, + gst_caps_features_copy_conditional (min_f)); } g_slist_free (list); } else { - gst_caps_append_structure_unchecked (dest, gst_structure_copy (min)); + gst_caps_append_structure_unchecked (dest, gst_structure_copy (min), + gst_caps_features_copy_conditional (min_f)); } } else { - gst_caps_append_structure_unchecked (dest, gst_structure_copy (min)); + gst_caps_append_structure_unchecked (dest, gst_structure_copy (min), + gst_caps_features_copy_conditional (min_f)); } } + if (CAPS_IS_EMPTY_SIMPLE (dest)) { gst_caps_unref (src); return dest; @@ -1485,6 +1766,7 @@ gst_caps_subtract (GstCaps * minuend, GstCaps * subtrahend) gst_caps_unref (src); dest = gst_caps_simplify (dest); + return dest; } @@ -1494,8 +1776,8 @@ typedef struct _NormalizeForeach { GstCaps *caps; GstStructure *structure; -} -NormalizeForeach; + GstCapsFeatures *features; +} NormalizeForeach; static gboolean gst_caps_normalize_foreach (GQuark field_id, const GValue * value, gpointer ptr) @@ -1506,20 +1788,21 @@ gst_caps_normalize_foreach (GQuark field_id, const GValue * value, gpointer ptr) if (G_VALUE_TYPE (value) == GST_TYPE_LIST) { guint len = gst_value_list_get_size (value); + for (i = 1; i < len; i++) { const GValue *v = gst_value_list_get_value (value, i); GstStructure *structure = gst_structure_copy (nf->structure); gst_structure_id_set_value (structure, field_id, v); - gst_caps_append_structure_unchecked (nf->caps, structure); + gst_caps_append_structure_unchecked (nf->caps, structure, + gst_caps_features_copy_conditional (nf->features)); } gst_value_init_and_copy (&val, gst_value_list_get_value (value, 0)); - gst_structure_id_set_value (nf->structure, field_id, &val); - g_value_unset (&val); - + gst_structure_id_take_value (nf->structure, field_id, &val); return FALSE; } + return TRUE; } @@ -1544,12 +1827,11 @@ gst_caps_normalize (GstCaps * caps) g_return_val_if_fail (GST_IS_CAPS (caps), NULL); caps = gst_caps_make_writable (caps); - nf.caps = caps; for (i = 0; i < gst_caps_get_size (nf.caps); i++) { nf.structure = gst_caps_get_structure_unchecked (nf.caps, i); - + nf.features = gst_caps_get_features_unchecked (nf.caps, i); while (!gst_structure_foreach (nf.structure, gst_caps_normalize_foreach, &nf)); } @@ -1561,13 +1843,14 @@ static gint gst_caps_compare_structures (gconstpointer one, gconstpointer two) { gint ret; - const GstStructure *struct1 = *((const GstStructure **) one); - const GstStructure *struct2 = *((const GstStructure **) two); + const GstStructure *struct1 = ((const GstCapsArrayElement *) one)->structure; + const GstStructure *struct2 = ((const GstCapsArrayElement *) two)->structure; /* FIXME: this orders alphabetically, but ordering the quarks might be faster So what's the best way? */ ret = strcmp (gst_structure_get_name (struct1), gst_structure_get_name (struct2)); + if (ret) return ret; @@ -1579,8 +1862,7 @@ typedef struct GQuark name; GValue value; GstStructure *compare; -} -UnionField; +} UnionField; static gboolean gst_caps_structure_figure_out_union (GQuark field_id, const GValue * value, @@ -1594,14 +1876,18 @@ gst_caps_structure_figure_out_union (GQuark field_id, const GValue * value, g_value_unset (&u->value); return FALSE; } + if (gst_value_compare (val, value) == GST_VALUE_EQUAL) return TRUE; + if (u->name) { g_value_unset (&u->value); return FALSE; } + u->name = field_id; gst_value_union (&u->value, val, value); + return TRUE; } @@ -1638,12 +1924,14 @@ gst_caps_structure_simplify (GstStructure ** result, * but at most one field: field.name */ if (G_IS_VALUE (&field.value)) { if (gst_structure_n_fields (simplify) == gst_structure_n_fields (compare)) { - gst_structure_id_set_value (compare, field.name, &field.value); + gst_structure_id_take_value (compare, field.name, &field.value); *result = NULL; ret = TRUE; + } else { + g_value_unset (&field.value); } - g_value_unset (&field.value); - } else if (gst_structure_n_fields (simplify) <= + } else + if (gst_structure_n_fields (simplify) <= gst_structure_n_fields (compare)) { /* compare is just more specific, will be optimized away later */ /* FIXME: do this here? */ @@ -1671,7 +1959,7 @@ gst_caps_switch_structures (GstCaps * caps, GstStructure * old, gst_structure_set_parent_refcount (old, NULL); gst_structure_free (old); gst_structure_set_parent_refcount (new, &GST_CAPS_REFCOUNT (caps)); - g_ptr_array_index (GST_CAPS_ARRAY (caps), i) = new; + g_array_index (GST_CAPS_ARRAY (caps), GstCapsArrayElement, i).structure = new; } /** @@ -1691,6 +1979,7 @@ GstCaps * gst_caps_simplify (GstCaps * caps) { GstStructure *simplify, *compare, *result = NULL; + GstCapsFeatures *simplify_f, *compare_f; gint i, j, start; g_return_val_if_fail (GST_IS_CAPS (caps), NULL); @@ -1702,20 +1991,31 @@ gst_caps_simplify (GstCaps * caps) caps = gst_caps_make_writable (caps); - g_ptr_array_sort (GST_CAPS_ARRAY (caps), gst_caps_compare_structures); + g_array_sort (GST_CAPS_ARRAY (caps), gst_caps_compare_structures); for (i = start; i >= 0; i--) { simplify = gst_caps_get_structure_unchecked (caps, i); + simplify_f = gst_caps_get_features_unchecked (caps, i); + if (!simplify_f) + simplify_f = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; compare = gst_caps_get_structure_unchecked (caps, start); + compare_f = gst_caps_get_features_unchecked (caps, start); + if (!compare_f) + compare_f = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; if (gst_structure_get_name_id (simplify) != - gst_structure_get_name_id (compare)) + gst_structure_get_name_id (compare) || + !gst_caps_features_is_equal (simplify_f, compare_f)) start = i; for (j = start; j >= 0; j--) { if (j == i) continue; compare = gst_caps_get_structure_unchecked (caps, j); + compare_f = gst_caps_get_features_unchecked (caps, j); + if (!compare_f) + compare_f = GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY; if (gst_structure_get_name_id (simplify) != - gst_structure_get_name_id (compare)) { + gst_structure_get_name_id (compare) || + !gst_caps_features_is_equal (simplify_f, compare_f)) { break; } if (gst_caps_structure_simplify (&result, simplify, compare)) { @@ -1802,14 +2102,20 @@ gst_caps_to_string (const GstCaps * caps) slen = 0; clen = GST_CAPS_LEN (caps); for (i = 0; i < clen; i++) { + GstCapsFeatures *f; + slen += - STRUCTURE_ESTIMATED_STRING_LEN (gst_caps_get_structure_unchecked (caps, - i)); + STRUCTURE_ESTIMATED_STRING_LEN (gst_caps_get_structure_unchecked + (caps, i)); + f = gst_caps_get_features_unchecked (caps, i); + if (f) + slen += FEATURES_ESTIMATED_STRING_LEN (f); } s = g_string_sized_new (slen); for (i = 0; i < clen; i++) { GstStructure *structure; + GstCapsFeatures *features; if (i > 0) { /* ';' is now added by gst_structure_to_string */ @@ -1817,6 +2123,16 @@ gst_caps_to_string (const GstCaps * caps) } structure = gst_caps_get_structure_unchecked (caps, i); + 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)) { + g_string_append_c (s, '('); + priv_gst_caps_features_append_to_gstring (features, s); + g_string_append_c (s, ')'); + } priv_gst_structure_append_to_gstring (structure, s); } if (s->len && s->str[s->len - 1] == ';') { @@ -1830,37 +2146,94 @@ static gboolean gst_caps_from_string_inplace (GstCaps * caps, const gchar * string) { GstStructure *structure; - gchar *s; + gchar *s, *copy, *end, *next, save; if (strcmp ("ANY", string) == 0) { GST_CAPS_FLAGS (caps) = GST_CAPS_FLAG_ANY; return TRUE; } - if (strcmp ("EMPTY", string) == 0) { - return TRUE; - } - structure = gst_structure_from_string (string, &s); - if (structure == NULL) { - return FALSE; + if (strcmp ("EMPTY", string) == 0 || strcmp ("NONE", string) == 0) { + return TRUE; } - gst_caps_append_structure_unchecked (caps, structure); + copy = s = g_strdup (string); do { + GstCapsFeatures *features = NULL; while (g_ascii_isspace (*s)) s++; if (*s == '\0') { break; } - structure = gst_structure_from_string (s, &s); + + if (!priv_gst_structure_parse_name (s, &s, &end, &next)) { + g_free (copy); + return FALSE; + } + + save = *end; + *end = '\0'; + structure = gst_structure_new_empty (s); + *end = save; + if (structure == NULL) { + g_free (copy); + return FALSE; + } + + s = next; + + if (*s == '\0') { + goto append; + } + + if (*s == '(') { + s++; + end = s; + + while (TRUE) { + if (*end == '\0') { + break; + } else if (*end == ')') { + break; + } else { + end++; + } + } + + save = *end; + *end = '\0'; + features = gst_caps_features_from_string (s); + if (!features) { + gst_structure_free (structure); + g_free (copy); + return FALSE; + } + *end = save; + s = end; + if (save == ')') + s++; + } + + if (*s == '\0') { + goto append; + } + + if (!priv_gst_structure_parse_fields (s, &s, structure)) { + gst_structure_free (structure); + g_free (copy); return FALSE; } - gst_caps_append_structure_unchecked (caps, structure); + append: + gst_caps_append_structure_unchecked (caps, structure, features); + if (*s == '\0') + break; } while (TRUE); + g_free (copy); + return TRUE; }