From 1f6d5d3ff5cb03527acb99b4059788f53d49567e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 16 Dec 2014 16:31:21 +0100 Subject: [PATCH] structure/caps: Add gst_{structure,caps}_filter_and_map_in_place() https://bugzilla.gnome.org/show_bug.cgi?id=739765 --- docs/gst/gstreamer-sections.txt | 6 +++- gst/gstcaps.c | 63 +++++++++++++++++++++++++++++++-- gst/gstcaps.h | 21 +++++++++++ gst/gststructure.c | 48 ++++++++++++++++++++++++- gst/gststructure.h | 21 +++++++++++ tests/check/gst/gstcaps.c | 47 ++++++++++++++++++++++++ tests/check/gst/gststructure.c | 28 +++++++++++++++ win32/common/libgstreamer.def | 4 +++ 8 files changed, 233 insertions(+), 5 deletions(-) diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index f5863bb8f5..4d36c26dbe 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -400,6 +400,7 @@ GST_CAPS_FLAG_UNSET GstCapsForeachFunc GstCapsMapFunc +GstCapsFilterMapFunc gst_caps_new_empty gst_caps_new_empty_simple @@ -429,6 +430,7 @@ gst_caps_set_simple gst_caps_set_simple_valist gst_caps_foreach gst_caps_map_in_place +gst_caps_filter_and_map_in_place gst_caps_is_any gst_caps_is_empty gst_caps_is_fixed @@ -2525,6 +2527,7 @@ gst_segment_flags_get_type GstStructure GstStructureForeachFunc GstStructureMapFunc +GstStructureFilterMapFunc gst_structure_new_empty gst_structure_new_id_empty gst_structure_new @@ -2556,7 +2559,6 @@ gst_structure_remove_fields gst_structure_remove_fields_valist gst_structure_remove_all_fields gst_structure_get_field_type -gst_structure_foreach gst_structure_n_fields gst_structure_has_field gst_structure_has_field_typed @@ -2578,7 +2580,9 @@ gst_structure_get_date_time gst_structure_get_clock_time gst_structure_get_enum gst_structure_get_fraction +gst_structure_foreach gst_structure_map_in_place +gst_structure_filter_and_map_in_place gst_structure_nth_field_name gst_structure_set_parent_refcount gst_structure_to_string diff --git a/gst/gstcaps.c b/gst/gstcaps.c index c9b72df71f..147b32c9c1 100644 --- a/gst/gstcaps.c +++ b/gst/gstcaps.c @@ -484,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 @@ -2367,7 +2365,7 @@ gst_caps_transform_to_string (const GValue * src_value, GValue * dest_value) * * 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(). + * 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. @@ -2447,3 +2445,62 @@ gst_caps_map_in_place (GstCaps * caps, GstCapsMapFunc func, gpointer user_data) 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++; + } + } +} diff --git a/gst/gstcaps.h b/gst/gstcaps.h index 4102f277a6..5cd1b781ef 100644 --- a/gst/gstcaps.h +++ b/gst/gstcaps.h @@ -397,6 +397,23 @@ typedef gboolean (*GstCapsMapFunc) (GstCapsFeatures *features, GstStructure *structure, gpointer user_data); +/** + * GstCapsFilterMapFunc: + * @features: the #GstCapsFeatures + * @structure: the #GstStructure + * @user_data: user data + * + * A function that will be called in gst_caps_filter_and_map_in_place(). + * The function may modify @features and @structure, and both will be + * removed from the caps if %FALSE is returned. + * + * Returns: %TRUE if the features and structure should be preserved, + * %FALSE if it should be removed. + */ +typedef gboolean (*GstCapsFilterMapFunc) (GstCapsFeatures *features, + GstStructure *structure, + gpointer user_data); + GType gst_caps_get_type (void); @@ -460,6 +477,10 @@ gboolean gst_caps_map_in_place (GstCaps *caps, GstCapsMapFunc func, gpointer user_data); +void gst_caps_filter_and_map_in_place (GstCaps *caps, + GstCapsFilterMapFunc func, + gpointer user_data); + /* tests */ gboolean gst_caps_is_any (const GstCaps *caps); gboolean gst_caps_is_empty (const GstCaps *caps); diff --git a/gst/gststructure.c b/gst/gststructure.c index 378161534b..8b0b54b929 100644 --- a/gst/gststructure.c +++ b/gst/gststructure.c @@ -1100,7 +1100,8 @@ gst_structure_nth_field_name (const GstStructure * structure, guint index) * @user_data: (closure): private data * * Calls the provided function once for each field in the #GstStructure. The - * function must not modify the fields. Also see gst_structure_map_in_place(). + * function must not modify the fields. Also see gst_structure_map_in_place() + * and gst_structure_filter_and_map_in_place(). * * Returns: %TRUE if the supplied function returns %TRUE For each of the fields, * %FALSE otherwise. @@ -1166,6 +1167,51 @@ gst_structure_map_in_place (GstStructure * structure, return TRUE; } +/** + * gst_structure_filter_and_map_in_place: + * @structure: a #GstStructure + * @func: (scope call): a function to call for each field + * @user_data: (closure): private data + * + * Calls the provided function once for each field in the #GstStructure. In + * contrast to gst_structure_foreach(), the function may modify the fields. + * In contrast to gst_structure_map_in_place(), the field is removed from + * the structure if %FALSE is returned from the function. + * The structure must be mutable. + * + * Since: 1.6 + */ +void +gst_structure_filter_and_map_in_place (GstStructure * structure, + GstStructureFilterMapFunc func, gpointer user_data) +{ + guint i, len; + GstStructureField *field; + gboolean ret; + + g_return_if_fail (structure != NULL); + g_return_if_fail (IS_MUTABLE (structure)); + g_return_if_fail (func != NULL); + len = GST_STRUCTURE_FIELDS (structure)->len; + + for (i = 0; i < len;) { + field = GST_STRUCTURE_FIELD (structure, i); + + ret = func (field->name, &field->value, user_data); + + if (!ret) { + if (G_IS_VALUE (&field->value)) { + g_value_unset (&field->value); + } + GST_STRUCTURE_FIELDS (structure) = + g_array_remove_index (GST_STRUCTURE_FIELDS (structure), i); + len = GST_STRUCTURE_FIELDS (structure)->len; + } else { + i++; + } + } +} + /** * gst_structure_id_has_field: * @structure: a #GstStructure diff --git a/gst/gststructure.h b/gst/gststructure.h index 6687970d81..014ef37e53 100644 --- a/gst/gststructure.h +++ b/gst/gststructure.h @@ -70,6 +70,23 @@ typedef gboolean (*GstStructureMapFunc) (GQuark field_id, GValue * value, gpointer user_data); +/** + * GstStructureFilterMapFunc: + * @field_id: the #GQuark of the field name + * @value: the #GValue of the field + * @user_data: user data + * + * A function that will be called in gst_structure_filter_and_map_in_place(). + * The function may modify @value, and the value will be removed from + * the structure if %FALSE is returned. + * + * Returns: %TRUE if the field should be preserved, %FALSE if it + * should be removed. + */ +typedef gboolean (*GstStructureFilterMapFunc) (GQuark field_id, + GValue * value, + gpointer user_data); + /** * GstStructure: * @type: the GType of a structure @@ -198,6 +215,10 @@ gboolean gst_structure_map_in_place (GstStructure * GstStructureMapFunc func, gpointer user_data); +void gst_structure_filter_and_map_in_place (GstStructure * structure, + GstStructureFilterMapFunc func, + gpointer user_data); + gint gst_structure_n_fields (const GstStructure * structure); const gchar * gst_structure_nth_field_name (const GstStructure * structure, diff --git a/tests/check/gst/gstcaps.c b/tests/check/gst/gstcaps.c index cb6128b532..66453610e3 100644 --- a/tests/check/gst/gstcaps.c +++ b/tests/check/gst/gstcaps.c @@ -1240,6 +1240,52 @@ GST_START_TEST (test_map_in_place) GST_END_TEST; +static gboolean +filter_map_function (GstCapsFeatures * features, GstStructure * structure, + gpointer user_data) +{ + if (!gst_structure_has_name (structure, "video/x-raw")) + return FALSE; + + if (!gst_caps_features_contains (features, "foo:bar")) + return FALSE; + + /* Set some dummy integer in the structure */ + gst_structure_set (structure, "foo", G_TYPE_INT, 123, NULL); + + return TRUE; +} + +GST_START_TEST (test_filter_and_map_in_place) +{ + GstCaps *caps, *caps2; + + caps = + gst_caps_from_string + ("video/x-raw, format=I420; video/x-raw(foo:bar); video/x-h264"); + caps2 = gst_caps_from_string ("video/x-raw(foo:bar), foo=(int)123"); + gst_caps_filter_and_map_in_place (caps, filter_map_function, NULL); + fail_unless (gst_caps_is_strictly_equal (caps, caps2)); + gst_caps_unref (caps); + gst_caps_unref (caps2); + + caps = gst_caps_from_string ("video/x-raw, format=I420; video/x-h264"); + caps2 = gst_caps_new_empty (); + gst_caps_filter_and_map_in_place (caps, filter_map_function, NULL); + fail_unless (gst_caps_is_strictly_equal (caps, caps2)); + gst_caps_unref (caps); + gst_caps_unref (caps2); + + caps = gst_caps_new_empty (); + caps2 = gst_caps_new_empty (); + gst_caps_filter_and_map_in_place (caps, filter_map_function, NULL); + fail_unless (gst_caps_is_strictly_equal (caps, caps2)); + gst_caps_unref (caps); + gst_caps_unref (caps2); +} + +GST_END_TEST; + static Suite * gst_caps_suite (void) { @@ -1271,6 +1317,7 @@ gst_caps_suite (void) tcase_add_test (tc_chain, test_special_caps); tcase_add_test (tc_chain, test_foreach); tcase_add_test (tc_chain, test_map_in_place); + tcase_add_test (tc_chain, test_filter_and_map_in_place); return s; } diff --git a/tests/check/gst/gststructure.c b/tests/check/gst/gststructure.c index a73db33fb3..18c58f6fa6 100644 --- a/tests/check/gst/gststructure.c +++ b/tests/check/gst/gststructure.c @@ -722,6 +722,33 @@ GST_START_TEST (test_map_in_place) GST_END_TEST; +static gboolean +filter_map_func (GQuark field_id, GValue * value, gpointer user_data) +{ + if (strcmp (g_quark_to_string (field_id), "bla") == 0) + return FALSE; + + if (G_VALUE_HOLDS_INT (value)) + g_value_set_int (value, 2); + + return TRUE; +} + +GST_START_TEST (test_filter_and_map_in_place) +{ + GstStructure *s, *s2; + + s = gst_structure_new ("foo/bar", "baz", G_TYPE_INT, 1, "bla", G_TYPE_INT, 3, + NULL); + s2 = gst_structure_new ("foo/bar", "baz", G_TYPE_INT, 2, NULL); + gst_structure_filter_and_map_in_place (s, filter_map_func, NULL); + fail_unless (gst_structure_is_equal (s, s2)); + gst_structure_free (s); + gst_structure_free (s2); +} + +GST_END_TEST; + static Suite * gst_structure_suite (void) { @@ -746,6 +773,7 @@ gst_structure_suite (void) tcase_add_test (tc_chain, test_vararg_getters); tcase_add_test (tc_chain, test_foreach); tcase_add_test (tc_chain, test_map_in_place); + tcase_add_test (tc_chain, test_filter_and_map_in_place); return s; } diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index 5908d42902..98cb12dd6e 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -241,8 +241,10 @@ EXPORTS gst_caps_features_remove_id gst_caps_features_set_parent_refcount gst_caps_features_to_string + gst_caps_filter_and_map_in_place gst_caps_fixate gst_caps_flags_get_type + gst_caps_foreach gst_caps_from_string gst_caps_get_features gst_caps_get_size @@ -261,6 +263,7 @@ EXPORTS gst_caps_is_subset gst_caps_is_subset_structure gst_caps_is_subset_structure_full + gst_caps_map_in_place gst_caps_merge gst_caps_merge_structure gst_caps_merge_structure_full @@ -1139,6 +1142,7 @@ EXPORTS gst_structure_can_intersect gst_structure_change_type_get_type gst_structure_copy + gst_structure_filter_and_map_in_place gst_structure_fixate gst_structure_fixate_field gst_structure_fixate_field_boolean