From cdd47a37e9b11604ab626907d43aa510a0b5d614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 8 Jun 2009 23:43:16 +0100 Subject: [PATCH] structure: add gst_structure_*_get*() vararg functions Add a bunch of vararg getter convenience functions to complement the vararg setter functions, and a basic unit test. Fixes #534208. API: gst_structure_get() API: gst_structure_id_get() API: gst_structure_get_valist() API: gst_structure_id_get_valist() --- docs/gst/gstreamer-sections.txt | 4 + gst/gststructure.c | 247 ++++++++++++++++++++++++++++++++ gst/gststructure.h | 15 ++ tests/check/gst/gststructure.c | 103 +++++++++++++ win32/common/libgstreamer.def | 4 + 5 files changed, 373 insertions(+) diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 048d24fed8..df5fb4cc10 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -2012,8 +2012,12 @@ gst_structure_get_name gst_structure_has_name gst_structure_set_name gst_structure_get_name_id +gst_structure_id_get +gst_structure_id_get_valist gst_structure_id_get_value gst_structure_id_set_value +gst_structure_get +gst_structure_get_valist gst_structure_get_value gst_structure_set_value gst_structure_set diff --git a/gst/gststructure.c b/gst/gststructure.c index 8962321827..e446b7fbf7 100644 --- a/gst/gststructure.c +++ b/gst/gststructure.c @@ -2342,3 +2342,250 @@ gst_structure_fixate_field_nearest_fraction (GstStructure * structure, return FALSE; } + +/* our very own version of G_VALUE_LCOPY that allows NULL return locations + * (useful for message parsing functions where the return location is user + * supplied and the user may pass NULL if the value isn't of interest) */ +#define GST_VALUE_LCOPY(value, var_args, flags, __error, fieldname) \ +G_STMT_START { \ + const GValue *_value = (value); \ + guint _flags = (flags); \ + GType _value_type = G_VALUE_TYPE (_value); \ + GTypeValueTable *_vtable = g_type_value_table_peek (_value_type); \ + gchar *_lcopy_format = _vtable->lcopy_format; \ + GTypeCValue _cvalues[G_VALUE_COLLECT_FORMAT_MAX_LENGTH] = { { 0, }, }; \ + guint _n_values = 0; \ + \ + while (*_lcopy_format != '\0') { \ + g_assert (*_lcopy_format == G_VALUE_COLLECT_POINTER); \ + _cvalues[_n_values++].v_pointer = va_arg ((var_args), gpointer); \ + _lcopy_format++; \ + } \ + if (_n_values == 2 && !!_cvalues[0].v_pointer != !!_cvalues[1].v_pointer) { \ + *(__error) = g_strdup_printf ("either all or none of the return " \ + "locations for field '%s' need to be NULL", fieldname); \ + } else if (_cvalues[0].v_pointer != NULL) { \ + *(__error) = _vtable->lcopy_value (_value, _n_values, _cvalues, _flags); \ + } \ +} G_STMT_END + +/** + * gst_structure_get_valist: + * @structure: a #GstStructure + * @first_fieldname: the name of the first field to read + * @valist: variable arguments + * + * Parses the variable arguments and reads fields from @structure accordingly. + * valist-variant of gst_structure_get(). Look at the documentation of + * gst_structure_get() for more details. + * + * Returns: TRUE, or FALSE if there was a problem reading any of the fields + * + * Since: 0.10.24 + */ +gboolean +gst_structure_get_valist (GstStructure * structure, + const char *first_fieldname, va_list args) +{ + const char *field_name; + GType expected_type = G_TYPE_INVALID; + + g_return_val_if_fail (GST_IS_STRUCTURE (structure), FALSE); + g_return_val_if_fail (first_fieldname != NULL, FALSE); + + field_name = first_fieldname; + while (field_name) { + const GValue *val = NULL; + gchar *err = NULL; + + expected_type = va_arg (args, GType); + + val = gst_structure_get_value (structure, field_name); + + if (val == NULL) + goto no_such_field; + + if (G_VALUE_TYPE (val) != expected_type) + goto wrong_type; + + GST_VALUE_LCOPY (val, args, 0, &err, field_name); + if (err) { + g_warning ("%s: %s", G_STRFUNC, err); + g_free (err); + return FALSE; + } + + field_name = va_arg (args, const gchar *); + } + + return TRUE; + +/* ERRORS */ +no_such_field: + { + GST_WARNING ("Expected field '%s' in structure: %" GST_PTR_FORMAT, + field_name, structure); + return FALSE; + } +wrong_type: + { + GST_WARNING ("Expected field '%s' in structure to be of type '%s', but " + "field was of type '%s': %" GST_PTR_FORMAT, field_name, + GST_STR_NULL (g_type_name (expected_type)), + G_VALUE_TYPE_NAME (gst_structure_get_value (structure, field_name)), + structure); + return FALSE; + } +} + +/** + * gst_structure_id_get_valist: + * @structure: a #GstStructure + * @first_field_id: the quark of the first field to read + * @valist: variable arguments + * + * Parses the variable arguments and reads fields from @structure accordingly. + * valist-variant of gst_structure_id_get(). Look at the documentation of + * gst_structure_id_get() for more details. + * + * Returns: TRUE, or FALSE if there was a problem reading any of the fields + * + * Since: 0.10.24 + */ +gboolean +gst_structure_id_get_valist (GstStructure * structure, GQuark first_field_id, + va_list args) +{ + GQuark field_id; + GType expected_type = G_TYPE_INVALID; + + g_return_val_if_fail (GST_IS_STRUCTURE (structure), FALSE); + g_return_val_if_fail (first_field_id != 0, FALSE); + + field_id = first_field_id; + while (field_id) { + const GValue *val = NULL; + gchar *err = NULL; + + expected_type = va_arg (args, GType); + + val = gst_structure_id_get_value (structure, field_id); + + if (val == NULL) + goto no_such_field; + + if (G_VALUE_TYPE (val) != expected_type) + goto wrong_type; + + GST_VALUE_LCOPY (val, args, 0, &err, g_quark_to_string (field_id)); + if (err) { + g_warning ("%s: %s", G_STRFUNC, err); + g_free (err); + return FALSE; + } + + field_id = va_arg (args, GQuark); + } + + return TRUE; + +/* ERRORS */ +no_such_field: + { + GST_WARNING ("Expected field '%s' in structure: %" GST_PTR_FORMAT, + GST_STR_NULL (g_quark_to_string (field_id)), structure); + return FALSE; + } +wrong_type: + { + GST_WARNING ("Expected field '%s' in structure to be of type '%s', but " + "field was of type '%s': %" GST_PTR_FORMAT, + g_quark_to_string (field_id), + GST_STR_NULL (g_type_name (expected_type)), + G_VALUE_TYPE_NAME (gst_structure_id_get_value (structure, field_id)), + structure); + return FALSE; + } +} + +/** + * gst_structure_get: + * @structure: a #GstStructure + * @first_fieldname: the name of the first field to read + * @...: variable arguments + * + * Parses the variable arguments and reads fields from @structure accordingly. + * Variable arguments should be in the form field name, field type + * (as a GType), pointer(s) to a variable(s) to hold the return value(s). + * The last variable argument should be NULL. + * + * For refcounted (mini)objects you will acquire your own reference which + * you must release with a suitable _unref() when no longer needed. For + * strings and boxed types you will acquire a copy which you will need to + * release with either g_free() or the suiteable function for the boxed type. + * + * Returns: FALSE if there was a problem reading any of the fields (e.g. + * because the field requested did not exist, or was of a type other + * than the type specified), otherwise TRUE. + * + * Since: 0.10.24 + */ +gboolean +gst_structure_get (GstStructure * structure, const char *first_fieldname, ...) +{ + gboolean ret; + va_list args; + + g_return_val_if_fail (GST_IS_STRUCTURE (structure), FALSE); + g_return_val_if_fail (first_fieldname != NULL, FALSE); + + va_start (args, first_fieldname); + ret = gst_structure_get_valist (structure, first_fieldname, args); + va_end (args); + + return ret; +} + +/** + * gst_structure_id_get: + * @structure: a #GstStructure + * @first_field_id: the quark of the first field to read + * @...: variable arguments + * + * Parses the variable arguments and reads fields from @structure accordingly. + * Variable arguments should be in the form field id quark, field type + * (as a GType), pointer(s) to a variable(s) to hold the return value(s). + * The last variable argument should be NULL (technically it should be a + * 0 quark, but we require NULL so compilers that support it can check for + * the NULL terminator and warn if it's not there). + * + * This function is just like gst_structure_get() only that it is slightly + * more efficient since it saves the string-to-quark lookup in the global + * quark hashtable. + * + * For refcounted (mini)objects you will acquire your own reference which + * you must release with a suitable _unref() when no longer needed. For + * strings and boxed types you will acquire a copy which you will need to + * release with either g_free() or the suiteable function for the boxed type. + * + * Returns: FALSE if there was a problem reading any of the fields (e.g. + * because the field requested did not exist, or was of a type other + * than the type specified), otherwise TRUE. + * + * Since: 0.10.24 + */ +gboolean +gst_structure_id_get (GstStructure * structure, GQuark first_field_id, ...) +{ + gboolean ret; + va_list args; + + g_return_val_if_fail (GST_IS_STRUCTURE (structure), FALSE); + g_return_val_if_fail (first_field_id != 0, FALSE); + + va_start (args, first_field_id); + ret = gst_structure_id_get_valist (structure, first_field_id, args); + va_end (args); + + return ret; +} diff --git a/gst/gststructure.h b/gst/gststructure.h index ecefea284c..aa3aa5d6b5 100644 --- a/gst/gststructure.h +++ b/gst/gststructure.h @@ -132,6 +132,21 @@ void gst_structure_id_set_valist (GstStructure GQuark fieldname, va_list varargs); +gboolean gst_structure_get_valist (GstStructure *structure, + const char *first_fieldname, + va_list args); + +gboolean gst_structure_get (GstStructure *structure, + const char *first_fieldname, + ...) G_GNUC_NULL_TERMINATED; + +gboolean gst_structure_id_get_valist (GstStructure *structure, + GQuark first_field_id, + va_list args); + +gboolean gst_structure_id_get (GstStructure *structure, + GQuark first_field_id, + ...) G_GNUC_NULL_TERMINATED; G_CONST_RETURN GValue * gst_structure_id_get_value (const GstStructure *structure, GQuark field); diff --git a/tests/check/gst/gststructure.c b/tests/check/gst/gststructure.c index 3d84057e00..bd126cf22b 100644 --- a/tests/check/gst/gststructure.c +++ b/tests/check/gst/gststructure.c @@ -433,6 +433,108 @@ GST_START_TEST (test_empty_string_fields) GST_END_TEST; +GST_START_TEST (test_vararg_getters) +{ + GstStructure *s; + GstBuffer *buf, *buf2; + gboolean ret; + GstCaps *caps, *caps2; + gdouble d; + gint64 i64; + gchar *c; + gint i, num, denom; + + buf = gst_buffer_new_and_alloc (3); + GST_BUFFER_DATA (buf)[0] = 0xf0; + GST_BUFFER_DATA (buf)[1] = 0x66; + GST_BUFFER_DATA (buf)[2] = 0x0d; + + caps = gst_caps_new_simple ("video/x-foo", NULL); + + s = gst_structure_new ("test", "int", G_TYPE_INT, 12345678, "string", + G_TYPE_STRING, "Hello World!", "buf", GST_TYPE_BUFFER, buf, "caps", + GST_TYPE_CAPS, caps, "int64", G_TYPE_INT64, G_GINT64_CONSTANT (-99), + "double", G_TYPE_DOUBLE, G_MAXDOUBLE, "frag", GST_TYPE_FRACTION, 39, 14, + NULL); + + /* first the plain one */ + ret = gst_structure_get (s, "double", G_TYPE_DOUBLE, &d, "string", + G_TYPE_STRING, &c, "caps", GST_TYPE_CAPS, &caps2, "buf", + GST_TYPE_BUFFER, &buf2, "frag", GST_TYPE_FRACTION, &num, &denom, "int", + G_TYPE_INT, &i, "int64", G_TYPE_INT64, &i64, NULL); + + fail_unless (ret); + fail_unless_equals_string (c, "Hello World!"); + fail_unless_equals_int (i, 12345678); + fail_unless_equals_float (d, G_MAXDOUBLE); + fail_unless_equals_int (num, 39); + fail_unless_equals_int (denom, 14); + fail_unless (i64 == -99); + fail_unless (caps == caps2); + fail_unless (buf == buf2); + + /* expected failures */ + ASSERT_CRITICAL (gst_structure_get (s, NULL, G_TYPE_INT, &i, NULL)); + fail_if (gst_structure_get (s, "int", G_TYPE_INT, &i, "double", + G_TYPE_FLOAT, &d, NULL)); + fail_if (gst_structure_get (s, "int", G_TYPE_INT, &i, "dooble", + G_TYPE_DOUBLE, &d, NULL)); + + g_free (c); + c = NULL; + gst_caps_unref (caps2); + caps2 = NULL; + gst_buffer_unref (buf2); + buf2 = NULL; + + /* and now the _id variant */ + ret = gst_structure_id_get (s, g_quark_from_static_string ("double"), + G_TYPE_DOUBLE, &d, g_quark_from_static_string ("string"), G_TYPE_STRING, + &c, g_quark_from_static_string ("caps"), GST_TYPE_CAPS, &caps2, + g_quark_from_static_string ("buf"), GST_TYPE_BUFFER, &buf2, + g_quark_from_static_string ("int"), G_TYPE_INT, &i, + g_quark_from_static_string ("int64"), G_TYPE_INT64, &i64, NULL); + + fail_unless (ret); + fail_unless_equals_string (c, "Hello World!"); + fail_unless_equals_int (i, 12345678); + fail_unless_equals_float (d, G_MAXDOUBLE); + fail_unless (i64 == -99); + fail_unless (caps == caps2); + fail_unless (buf == buf2); + + /* expected failures */ + ASSERT_CRITICAL (gst_structure_get (s, 0, G_TYPE_INT, &i, NULL)); + fail_if (gst_structure_id_get (s, g_quark_from_static_string ("int"), + G_TYPE_INT, &i, g_quark_from_static_string ("double"), G_TYPE_FLOAT, + &d, NULL)); + fail_if (gst_structure_id_get (s, g_quark_from_static_string ("int"), + G_TYPE_INT, &i, g_quark_from_static_string ("dooble"), G_TYPE_DOUBLE, + &d, NULL)); + + g_free (c); + gst_caps_unref (caps2); + gst_buffer_unref (buf2); + + /* finally make sure NULL as return location is handled gracefully */ + ret = gst_structure_get (s, "double", G_TYPE_DOUBLE, NULL, "string", + G_TYPE_STRING, NULL, "caps", GST_TYPE_CAPS, NULL, "buf", + GST_TYPE_BUFFER, NULL, "int", G_TYPE_INT, &i, "frag", GST_TYPE_FRACTION, + NULL, NULL, "int64", G_TYPE_INT64, &i64, NULL); + + ASSERT_WARNING (gst_structure_get (s, "frag", GST_TYPE_FRACTION, NULL, + &denom, NULL)); + ASSERT_WARNING (gst_structure_get (s, "frag", GST_TYPE_FRACTION, &num, + NULL, NULL)); + + /* clean up */ + gst_caps_unref (caps); + gst_buffer_unref (buf); + gst_structure_free (s); +} + +GST_END_TEST; + static Suite * gst_structure_suite (void) { @@ -451,6 +553,7 @@ gst_structure_suite (void) tcase_add_test (tc_chain, test_structure_nested); tcase_add_test (tc_chain, test_structure_nested_from_and_to_string); tcase_add_test (tc_chain, test_empty_string_fields); + tcase_add_test (tc_chain, test_vararg_getters); return s; } diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index 006ad95943..7abab529b5 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -866,6 +866,7 @@ EXPORTS gst_structure_foreach gst_structure_free gst_structure_from_string + gst_structure_get gst_structure_get_boolean gst_structure_get_clock_time gst_structure_get_date @@ -880,11 +881,14 @@ EXPORTS gst_structure_get_string gst_structure_get_type gst_structure_get_uint + gst_structure_get_valist gst_structure_get_value gst_structure_has_field gst_structure_has_field_typed gst_structure_has_name gst_structure_id_empty_new + gst_structure_id_get + gst_structure_id_get_valist gst_structure_id_get_value gst_structure_id_new gst_structure_id_set