mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-29 20:35:40 +00:00
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()
This commit is contained in:
parent
26b201273a
commit
cdd47a37e9
5 changed files with 373 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue