mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 06:46:38 +00:00
gst: Add new structure/caps/_to_string using the brackets for nesting
This adds `gst_structure_serialize` and `gst_caps_serialize` which use the newly introduced bracket delimiters for nested structures. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/532>
This commit is contained in:
parent
330450ef93
commit
c35d47127b
9 changed files with 214 additions and 57 deletions
|
@ -183,7 +183,8 @@ G_GNUC_INTERNAL void _priv_gst_element_state_changed (GstElement *element,
|
|||
|
||||
G_GNUC_INTERNAL
|
||||
gboolean priv_gst_structure_append_to_gstring (const GstStructure * structure,
|
||||
GString * s);
|
||||
GString * s,
|
||||
GstSerializeFlags flags);
|
||||
G_GNUC_INTERNAL
|
||||
gboolean priv__gst_structure_append_template_to_gstring (GQuark field_id,
|
||||
const GValue *value,
|
||||
|
|
|
@ -2291,29 +2291,13 @@ gst_caps_fixate (GstCaps * caps)
|
|||
|
||||
/* utility */
|
||||
|
||||
/**
|
||||
* gst_caps_to_string:
|
||||
* @caps: a #GstCaps
|
||||
*
|
||||
* Converts @caps to a string representation. This string representation
|
||||
* can be converted back to a #GstCaps by gst_caps_from_string().
|
||||
*
|
||||
* For debugging purposes its easier to do something like this:
|
||||
* |[<!-- language="C" -->
|
||||
* 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 *
|
||||
gst_caps_to_string (const GstCaps * caps)
|
||||
static gchar *
|
||||
caps_serialize (const GstCaps * caps, GstSerializeFlags flags)
|
||||
{
|
||||
guint i, slen, clen;
|
||||
GString *s;
|
||||
gboolean nested_structs_brackets =
|
||||
!(flags & GST_SERIALIZE_FLAG_BACKWARD_COMPAT);
|
||||
|
||||
/* NOTE: This function is potentially called by the debug system,
|
||||
* so any calls to gst_log() (and GST_DEBUG(), GST_LOG(), etc.)
|
||||
|
@ -2366,7 +2350,8 @@ gst_caps_to_string (const GstCaps * caps)
|
|||
priv_gst_caps_features_append_to_gstring (features, s);
|
||||
g_string_append_c (s, ')');
|
||||
}
|
||||
priv_gst_structure_append_to_gstring (structure, s);
|
||||
priv_gst_structure_append_to_gstring (structure, s,
|
||||
nested_structs_brackets);
|
||||
}
|
||||
if (s->len && s->str[s->len - 1] == ';') {
|
||||
/* remove latest ';' */
|
||||
|
@ -2375,6 +2360,55 @@ gst_caps_to_string (const GstCaps * caps)
|
|||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_caps_to_string:
|
||||
* @caps: a #GstCaps
|
||||
*
|
||||
* Converts @caps to a string representation. This string representation
|
||||
* can be converted back to a #GstCaps by gst_caps_from_string().
|
||||
*
|
||||
* For debugging purposes its easier to do something like this:
|
||||
* |[<!-- language="C" -->
|
||||
* 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 *
|
||||
gst_caps_to_string (const GstCaps * caps)
|
||||
{
|
||||
return caps_serialize (caps, GST_SERIALIZE_FLAG_BACKWARD_COMPAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_caps_serialize:
|
||||
* @caps: a #GstCaps
|
||||
* @flags: a #GstSerializeFlags
|
||||
*
|
||||
* Converts @caps to a string representation. This string representation can be
|
||||
* converted back to a #GstCaps by gst_caps_from_string().
|
||||
*
|
||||
* This prints the caps in human readable form.
|
||||
*
|
||||
* This version of the caps serialization function introduces support for nested
|
||||
* structures and caps but the resulting strings won't be parsable with
|
||||
* GStreamer prior to 1.20 unless #GST_SERIALIZE_FLAG_BACKWARD_COMPAT is passed
|
||||
* as @flag.
|
||||
*
|
||||
* Returns: (transfer full): a newly allocated string representing @caps.
|
||||
*
|
||||
* Since: 1.20
|
||||
*/
|
||||
gchar *
|
||||
gst_caps_serialize (const GstCaps * caps, GstSerializeFlags flags)
|
||||
{
|
||||
return caps_serialize (caps, flags);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_caps_from_string_inplace (GstCaps * caps, const gchar * string)
|
||||
{
|
||||
|
|
|
@ -576,6 +576,8 @@ GstCaps * gst_caps_fixate (GstCaps *caps) G_GNUC_WARN_U
|
|||
|
||||
GST_API
|
||||
gchar * gst_caps_to_string (const GstCaps *caps) G_GNUC_MALLOC;
|
||||
GST_API
|
||||
gchar * gst_caps_serialize (const GstCaps *caps, GstSerializeFlags flags) G_GNUC_MALLOC;
|
||||
|
||||
GST_API
|
||||
GstCaps * gst_caps_from_string (const gchar *string) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
|
|
@ -99,7 +99,7 @@
|
|||
* - [GstValueList](GST_TYPE_LIST) are inside "less and greater than" (`<` and
|
||||
* `>`). For example `a-structure, list=<1, 2, 3>
|
||||
*
|
||||
* Structures are delimited either by a null character `\0` or a semicolumn `;`
|
||||
* Structures are delimited either by a null character `\0` or a semicolon `;`
|
||||
* the latter allowing to store multiple structures in the same string (see
|
||||
* #GstCaps).
|
||||
*
|
||||
|
@ -119,15 +119,16 @@
|
|||
* a-struct, nested=(GstStructure)"nested-struct, nested=true"
|
||||
* ```
|
||||
*
|
||||
* Since 1.20, nested structures and caps can be specified using brackets
|
||||
* (`[` and `]`), for example:
|
||||
* Since 1.20, nested structures and caps can be specified using brackets (`[`
|
||||
* and `]`), for example:
|
||||
*
|
||||
* ```
|
||||
* a-struct, nested=[nested-struct, nested=true]
|
||||
* ```
|
||||
*
|
||||
* > *note*: For backward compatility reason, the serialization functions won't
|
||||
* > use that synthax.
|
||||
* > *note*: gst_structure_to_string() won't use that syntax for backward
|
||||
* > compatibility reason, gst_structure_serialize() has been added for
|
||||
* > that purpose.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -2026,16 +2027,18 @@ gst_structure_value_get_generic_type (const GValue * val)
|
|||
|
||||
gboolean
|
||||
priv_gst_structure_append_to_gstring (const GstStructure * structure,
|
||||
GString * s)
|
||||
GString * s, GstSerializeFlags flags)
|
||||
{
|
||||
GstStructureField *field;
|
||||
guint i, len;
|
||||
gboolean nested_structs_brackets =
|
||||
!(flags & GST_SERIALIZE_FLAG_BACKWARD_COMPAT);
|
||||
|
||||
g_return_val_if_fail (s != NULL, FALSE);
|
||||
|
||||
len = GST_STRUCTURE_LEN (structure);
|
||||
for (i = 0; i < len; i++) {
|
||||
char *t;
|
||||
gchar *t = NULL;
|
||||
GType type;
|
||||
|
||||
field = GST_STRUCTURE_FIELD (structure, i);
|
||||
|
@ -2044,7 +2047,9 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
|
|||
t = _priv_gst_value_serialize_any_list (&field->value, "< ", " >", FALSE);
|
||||
} else if (G_VALUE_TYPE (&field->value) == GST_TYPE_LIST) {
|
||||
t = _priv_gst_value_serialize_any_list (&field->value, "{ ", " }", FALSE);
|
||||
} else {
|
||||
} else if (!nested_structs_brackets
|
||||
|| (G_VALUE_TYPE (&field->value) != GST_TYPE_STRUCTURE
|
||||
&& G_VALUE_TYPE (&field->value) != GST_TYPE_CAPS)) {
|
||||
t = gst_value_serialize (&field->value);
|
||||
}
|
||||
|
||||
|
@ -2056,7 +2061,22 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
|
|||
g_string_append_len (s, "=(", 2);
|
||||
g_string_append (s, _priv_gst_value_gtype_to_abbr (type));
|
||||
g_string_append_c (s, ')');
|
||||
if (t) {
|
||||
if (nested_structs_brackets
|
||||
&& G_VALUE_TYPE (&field->value) == GST_TYPE_STRUCTURE) {
|
||||
const GstStructure *substruct = gst_value_get_structure (&field->value);
|
||||
|
||||
g_string_append_c (s, '[');
|
||||
g_string_append (s, g_quark_to_string (substruct->name));
|
||||
priv_gst_structure_append_to_gstring (substruct, s, flags);
|
||||
g_string_append_c (s, ']');
|
||||
} else if (nested_structs_brackets
|
||||
&& G_VALUE_TYPE (&field->value) == GST_TYPE_CAPS) {
|
||||
const GstCaps *subcaps = gst_value_get_caps (&field->value);
|
||||
gchar *capsstr = gst_caps_serialize (subcaps, flags);
|
||||
|
||||
g_string_append_printf (s, "[%s]", capsstr);
|
||||
g_free (capsstr);
|
||||
} else if (t) {
|
||||
g_string_append (s, t);
|
||||
g_free (t);
|
||||
} else if (G_TYPE_CHECK_VALUE_TYPE (&field->value, G_TYPE_POINTER)) {
|
||||
|
@ -2129,28 +2149,8 @@ priv__gst_structure_append_template_to_gstring (GQuark field_id,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_structure_to_string:
|
||||
* @structure: a #GstStructure
|
||||
*
|
||||
* Converts @structure to a human-readable string representation.
|
||||
*
|
||||
* For debugging purposes its easier to do something like this:
|
||||
* |[<!-- language="C" -->
|
||||
* GST_LOG ("structure is %" GST_PTR_FORMAT, structure);
|
||||
* ]|
|
||||
* This prints the structure in human readable form.
|
||||
*
|
||||
* The current implementation of serialization will lead to unexpected results
|
||||
* when there are nested #GstCaps / #GstStructure deeper than one level.
|
||||
*
|
||||
* Free-function: g_free
|
||||
*
|
||||
* Returns: (transfer full): a pointer to string allocated by g_malloc().
|
||||
* g_free() after usage.
|
||||
*/
|
||||
gchar *
|
||||
gst_structure_to_string (const GstStructure * structure)
|
||||
static gchar *
|
||||
structure_serialize (const GstStructure * structure, GstSerializeFlags flags)
|
||||
{
|
||||
GString *s;
|
||||
|
||||
|
@ -2166,8 +2166,61 @@ gst_structure_to_string (const GstStructure * structure)
|
|||
* avoid unnecessary reallocs within GString */
|
||||
s = g_string_sized_new (STRUCTURE_ESTIMATED_STRING_LEN (structure));
|
||||
g_string_append (s, g_quark_to_string (structure->name));
|
||||
priv_gst_structure_append_to_gstring (structure, s);
|
||||
priv_gst_structure_append_to_gstring (structure, s, flags);
|
||||
return g_string_free (s, FALSE);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_structure_to_string:
|
||||
* @structure: a #GstStructure
|
||||
*
|
||||
* Converts @structure to a human-readable string representation.
|
||||
*
|
||||
* For debugging purposes its easier to do something like this: |[<!--
|
||||
* language="C" --> GST_LOG ("structure is %" GST_PTR_FORMAT, structure);
|
||||
* ]|
|
||||
* This prints the structure in human readable form.
|
||||
*
|
||||
* This function will lead to unexpected results when there are nested #GstCaps
|
||||
* / #GstStructure deeper than one level, you should user
|
||||
* gst_structure_serialize() instead for those cases.
|
||||
*
|
||||
* Free-function: g_free
|
||||
*
|
||||
* Returns: (transfer full): a pointer to string allocated by g_malloc().
|
||||
* g_free() after usage.
|
||||
*/
|
||||
gchar *
|
||||
gst_structure_to_string (const GstStructure * structure)
|
||||
{
|
||||
return structure_serialize (structure, GST_SERIALIZE_FLAG_BACKWARD_COMPAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_structure_serialize:
|
||||
* @structure: a #GstStructure
|
||||
* @flags: The flags to use to serialize structure
|
||||
*
|
||||
* Converts @structure to a human-readable string representation.
|
||||
*
|
||||
* This version of the caps serialization function introduces support for nested
|
||||
* structures and caps but the resulting strings won't be parsable with
|
||||
* GStreamer prior to 1.20 unless #GST_SERIALIZE_FLAG_BACKWARD_COMPAT is passed
|
||||
* as @flag.
|
||||
*
|
||||
* Free-function: g_free
|
||||
*
|
||||
* Returns: (transfer full): a pointer to string allocated by g_malloc().
|
||||
* g_free() after usage.
|
||||
*
|
||||
* Since: 1.20
|
||||
*/
|
||||
gchar *
|
||||
gst_structure_serialize (const GstStructure * structure,
|
||||
GstSerializeFlags flags)
|
||||
{
|
||||
return structure_serialize (structure, flags);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -2306,7 +2359,9 @@ priv_gst_structure_parse_fields (gchar * str, gchar ** end,
|
|||
* where parsing ended will be returned.
|
||||
*
|
||||
* The current implementation of serialization will lead to unexpected results
|
||||
* when there are nested #GstCaps / #GstStructure deeper than one level.
|
||||
* when there are nested #GstCaps / #GstStructure deeper than one level unless
|
||||
* the gst_structure_serialize() function is used (without
|
||||
* #GST_SERIALIZE_FLAG_BACKWARD_COMPAT)
|
||||
*
|
||||
* Free-function: gst_structure_free
|
||||
*
|
||||
|
|
|
@ -32,6 +32,20 @@ GST_API GType _gst_structure_type;
|
|||
|
||||
typedef struct _GstStructure GstStructure;
|
||||
|
||||
/**
|
||||
* GstSerializeFlags:
|
||||
* @GST_SERIALIZE_FLAG_NONE: No special flags specified.
|
||||
* @GST_SERIALIZE_FLAG_BACKWARD_COMPAT: Serialize using the old format for
|
||||
* nested structures.
|
||||
*
|
||||
* Since: 1.20
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GST_SERIALIZE_FLAG_NONE = 0,
|
||||
GST_SERIALIZE_FLAG_BACKWARD_COMPAT = (1 << 0),
|
||||
} GstSerializeFlags;
|
||||
|
||||
#define GST_TYPE_STRUCTURE (_gst_structure_type)
|
||||
#define GST_IS_STRUCTURE(object) ((object) && (GST_STRUCTURE(object)->type == GST_TYPE_STRUCTURE))
|
||||
#define GST_STRUCTURE_CAST(object) ((GstStructure *)(object))
|
||||
|
@ -329,7 +343,10 @@ gboolean gst_structure_get_list (GstStructure *
|
|||
const gchar * fieldname,
|
||||
GValueArray ** array);
|
||||
GST_API
|
||||
gchar * gst_structure_to_string (const GstStructure * structure) G_GNUC_MALLOC;
|
||||
gchar * gst_structure_to_string (const GstStructure * structure) G_GNUC_MALLOC;
|
||||
GST_API
|
||||
gchar * gst_structure_serialize (const GstStructure * structure,
|
||||
GstSerializeFlags flags) G_GNUC_MALLOC;
|
||||
|
||||
GST_API
|
||||
GstStructure * gst_structure_from_string (const gchar * string,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Check that the code follows a consistent code style
|
||||
# Check that the code follows a consistant code style
|
||||
#
|
||||
|
||||
# Check for existence of indent, and error out if not present.
|
||||
|
|
|
@ -32,6 +32,9 @@ static const gchar *caps_list[] = {
|
|||
/* Some random checks */
|
||||
"video/x-raw, format = (string) { I420, Y42B, Y444 }, framerate = (fraction) [1/MAX, MAX], width = (int) [ 1, MAX ], height = (int) [ 1, MAX ]",
|
||||
|
||||
/* Some nesting check */
|
||||
"caps, nested=(GstCaps)[c1;c2;c3,deeply-nested-field=[deep-structure, test=true]]",
|
||||
|
||||
"ANY",
|
||||
"EMPTY"
|
||||
};
|
||||
|
|
|
@ -43,7 +43,16 @@ GST_START_TEST (test_from_string)
|
|||
"Could not convert caps back to string %s\n", caps_list[i]);
|
||||
caps2 = gst_caps_from_string (to_str);
|
||||
fail_if (caps2 == NULL, "Could not create caps from string %s\n", to_str);
|
||||
g_free (to_str);
|
||||
|
||||
fail_unless (gst_caps_is_equal (caps, caps));
|
||||
fail_unless (gst_caps_is_equal (caps, caps2));
|
||||
gst_caps_unref (caps2);
|
||||
|
||||
to_str = gst_caps_serialize (caps, GST_SERIALIZE_FLAG_NONE);
|
||||
fail_if (to_str == NULL,
|
||||
"Could not convert caps back to string %s\n", caps_list[i]);
|
||||
caps2 = gst_caps_from_string (to_str);
|
||||
fail_unless (gst_caps_is_equal (caps, caps));
|
||||
fail_unless (gst_caps_is_equal (caps, caps2));
|
||||
|
||||
|
|
|
@ -723,6 +723,41 @@ GST_START_TEST (test_structure_nested_from_and_to_string)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_serialize_nested_structures)
|
||||
{
|
||||
GstStructure *s;
|
||||
const gchar *str1;
|
||||
gchar *str2, *end = NULL;
|
||||
|
||||
str1 = "main"
|
||||
", main-sub1=(structure)[type-b, machine-type=(int)0;]"
|
||||
", main-sub2=(structure)[type-a, plugin-filename=(string)\"/home/user/lib/lib\\ with\\ spaces.dll\", machine-type=(int)1;]"
|
||||
", main-sub3=(structure)[type-b, plugin-filename=(string)/home/user/lib/lib_no_spaces.so, machine-type=(int)1;]"
|
||||
";";
|
||||
|
||||
s = gst_structure_from_string (str1, &end);
|
||||
fail_unless (s != NULL);
|
||||
|
||||
GST_DEBUG ("not parsed part : %s", end);
|
||||
fail_unless (*end == '\0');
|
||||
|
||||
fail_unless (gst_structure_n_fields (s) == 3);
|
||||
|
||||
fail_unless (gst_structure_has_field_typed (s, "main-sub1",
|
||||
GST_TYPE_STRUCTURE));
|
||||
|
||||
str2 = gst_structure_serialize (s, GST_SERIALIZE_FLAG_NONE);
|
||||
fail_unless (str2 != NULL);
|
||||
|
||||
fail_unless (g_str_equal (str1, str2));
|
||||
|
||||
g_free (str2);
|
||||
|
||||
gst_structure_free (s);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_vararg_getters)
|
||||
{
|
||||
GstStructure *s;
|
||||
|
@ -963,6 +998,7 @@ gst_structure_suite (void)
|
|||
tcase_add_test (tc_chain, test_is_subset_superset_extra_values);
|
||||
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_serialize_nested_structures);
|
||||
tcase_add_test (tc_chain, test_vararg_getters);
|
||||
tcase_add_test (tc_chain, test_foreach);
|
||||
tcase_add_test (tc_chain, test_map_in_place);
|
||||
|
|
Loading…
Reference in a new issue