/* GStreamer * Copyright (C) 2003 David A. Schleef * * gststructure.c: lists of { GQuark, GValue } tuples * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include //#define G_TYPE_FOURCC G_TYPE_FLOAT static GType _gst_structure_type; static void _gst_structure_transform_to_string(const GValue *src_value, GValue *dest_value); static void _gst_structure_value_init (GValue *value); static void _gst_structure_value_free (GValue *value); static void _gst_structure_value_copy (const GValue *src, GValue *dest); static gpointer _gst_structure_value_peek_pointer (const GValue *value); GType gst_structure_get_type(void) { return _gst_structure_type; } void _gst_structure_initialize(void) { static const GTypeValueTable type_value_table = { _gst_structure_value_init, _gst_structure_value_free, _gst_structure_value_copy, _gst_structure_value_peek_pointer, NULL, NULL, NULL, NULL, }; static const GTypeInfo structure_info = { 0, NULL, NULL, NULL, NULL, NULL, 0, /* sizeof(GstStructure), */ 0, NULL, /* _gst_structure_init, */ &type_value_table, }; _gst_structure_type = g_type_register_static(G_TYPE_BOXED, "GstStructure", &structure_info, 0); #if 0 _gst_structure_type = g_boxed_type_register_static("GstStructure", (GBoxedCopyFunc) gst_structure_copy, (GBoxedFreeFunc) gst_structure_free); #endif g_value_register_transform_func(_gst_structure_type, G_TYPE_STRING, _gst_structure_transform_to_string); } /** * gst_structure_id_empty_new: * @name: name of new structure * * Creates a new, empty #GstStructure with the given name. * * Returns: a new, empty #GstStructure */ GstStructure *gst_structure_id_empty_new(GQuark quark) { GstStructure *structure; g_return_val_if_fail(quark != 0, NULL); structure = g_new0(GstStructure, 1); structure->name = quark; structure->fields = g_array_new(FALSE,TRUE,sizeof(GstStructureField)); return structure; } /** * gst_structure_empty_new: * @name: name of new structure * * Creates a new, empty #GstStructure with the given name. * * Returns: a new, empty #GstStructure */ GstStructure *gst_structure_empty_new(const gchar *name) { GstStructure *structure; g_return_val_if_fail(name != NULL, NULL); structure = g_new0(GstStructure, 1); structure->name = g_quark_from_string(name); structure->fields = g_array_new(FALSE,TRUE,sizeof(GstStructureField)); return structure; } /** * gst_structure_new: * @name: name of new structure * @firstfield: name of first field to set * @...: additional arguments * * Creates a new #GstStructure with the given name. Parses the * list of variable arguments and sets fields to the values listed. * Variable arguments should be passed as field name, field type, * and value. Last variable argument should be NULL. * * Returns: a new #GstStructure */ GstStructure *gst_structure_new(const gchar *name, const gchar *firstfield, ...) { GstStructure *structure; va_list varargs; g_return_val_if_fail(name != NULL, NULL); va_start(varargs, firstfield); structure = gst_structure_new_valist(name,firstfield,varargs); va_end(varargs); return structure; } /** * gst_structure_new_valist: * @name: name of new structure * @firstfield: name of first field to set * @varags: variable argument list * * Creates a new #GstStructure with the given name. Structure fields * are set according to the varargs in a manner similar to * @gst_structure_new. * * Returns: a new #GstStructure */ GstStructure *gst_structure_new_valist(const gchar *name, const gchar *firstfield, va_list varargs) { GstStructure *structure; g_return_val_if_fail(name != NULL, NULL); structure = gst_structure_empty_new(name); gst_structure_set_valist(structure, firstfield, varargs); return structure; } /** * gst_structure_copy: * @structure: a #GstStructure to duplicate * * Duplicates a #GstStructure and all its fields and values. * * Returns: a new #GstStructure. */ GstStructure *gst_structure_copy(GstStructure *structure) { GstStructure *new_structure; GstStructureField *field; int i; g_return_val_if_fail(structure != NULL, NULL); new_structure = gst_structure_empty_new(g_quark_to_string(structure->name)); new_structure->fields = g_array_set_size(new_structure->fields, structure->fields->len); new_structure->name = structure->name; for(i=0;ifields->len;i++){ GstStructureField new_field = { 0 }; field = GST_STRUCTURE_FIELD(structure, i); new_field.name = field->name; g_value_init(&new_field.value, G_VALUE_TYPE(&field->value)); g_value_copy(&field->value, &new_field.value); g_array_append_val(new_structure->fields, new_field); } return structure; } /** * gst_structure_free: * @structure: the #GstStructure to free * * Frees a #GstStructure and all its fields and values. */ void gst_structure_free(GstStructure *structure) { GstStructureField *field; int i; return; g_return_if_fail(structure != NULL); for(i=0;ifields->len;i++){ field = GST_STRUCTURE_FIELD(structure, i); if(G_IS_VALUE(&field->value)){ g_value_unset(&field->value); } } g_free(structure); } /** * gst_structure_get_name: * @structure: a #GstStructure * * Accessor fuction. * * Returns: the name of the structure. */ const gchar *gst_structure_get_name(GstStructure *structure) { g_return_val_if_fail(structure != NULL, NULL); return g_quark_to_string(structure->name); } /** * gst_structure_set_name: * @structure: a #GstStructure * @name: the new name of the structure * * Sets the name of the structure to the given name. The string * provided is copied before being used. */ void gst_structure_set_name(GstStructure *structure, const gchar *name) { g_return_if_fail(structure != NULL); g_return_if_fail(name != NULL); structure->name = g_quark_from_string(name); } /** * gst_structure_id_set_value: * @structure: a #GstStructure * @field_id: a #GQuark representing a field * @value: the new value of the field * * Sets the field with the given ID to the provided value. If the field * does not exist, it is created. If the field exists, the previous * value is freed. */ void gst_structure_id_set_value(GstStructure *structure, GQuark fieldname, const GValue *value) { GstStructureField field = { 0, { 0, } }; g_return_if_fail(structure != NULL); g_return_if_fail(G_IS_VALUE(value)); field.name = fieldname; g_value_init(&field.value, G_VALUE_TYPE (value)); g_value_copy(value, &field.value); gst_structure_set_field(structure, &field); } /** * gst_structure_set_value: * @structure: a #GstStructure * @field: the name of the field to set * @value: the new value of the field * * Sets the field with the given name to the provided value. If the field * does not exist, it is created. If the field exists, the previous * value is freed. */ void gst_structure_set_value(GstStructure *structure, const gchar *field, const GValue *value) { g_return_if_fail(structure != NULL); g_return_if_fail(field != NULL); g_return_if_fail(G_IS_VALUE(value)); gst_structure_id_set_value(structure, g_quark_from_string(field), value); } /** * gst_structure_set: * @structure: a #GstStructure * @field: the name of the field to set * @...: variable arguments * * Parses the variable arguments and sets fields accordingly. * Variable arguments should be in the form field name, field type * (as a GType), value. The last variable argument should be NULL. */ void gst_structure_set(GstStructure *structure, const gchar *field, ...) { va_list varargs; g_return_if_fail(structure != NULL); va_start(varargs, field); gst_structure_set_valist(structure,field,varargs); va_end(varargs); } /** * gst_structure_set: * @structure: a #GstStructure * @field: the name of the field to set * @varargs: variable arguments * * va_list form of #gst_structure_set. */ void gst_structure_set_valist(GstStructure *structure, const gchar *fieldname, va_list varargs) { GType type; int i; double d; char *s; g_return_if_fail(structure != NULL); while(fieldname){ GstStructureField field = { 0 }; field.name = g_quark_from_string(fieldname); type = va_arg (varargs, GType); switch(type){ case G_TYPE_INT: i = va_arg(varargs, int); g_value_init(&field.value, G_TYPE_INT); g_value_set_int(&field.value, i); break; case G_TYPE_DOUBLE: d = va_arg(varargs, double); g_value_init(&field.value, G_TYPE_DOUBLE); g_value_set_double(&field.value, d); break; case G_TYPE_BOOLEAN: i = va_arg(varargs, int); g_value_init(&field.value, G_TYPE_BOOLEAN); g_value_set_boolean(&field.value, i); break; case G_TYPE_STRING: s = va_arg(varargs, char *); g_value_init(&field.value, G_TYPE_STRING); g_value_set_string(&field.value, s); break; default: if(type == GST_TYPE_FOURCC){ i = va_arg(varargs, int); g_value_init(&field.value, GST_TYPE_FOURCC); gst_value_set_fourcc(&field.value, i); break; }else{ g_critical("unimplemented vararg field type %d\n", (int)type); } break; } gst_structure_set_field(structure, &field); fieldname = va_arg (varargs, gchar *); } } /** * gst_structure_set_field_copy: * @structure: a #GstStructure * @field: the #GstStructureField to set * * Sets a field in the structure. If the structure currently contains * a field with the same name, it is replaced with the provided field. * Otherwise, the field is added to the structure. The field's value * is deeply copied. * * This function is intended mainly for internal use. The function * #gst_structure_set() is recommended instead of this one. */ void gst_structure_set_field_copy (GstStructure *structure, const GstStructureField *field) { GstStructureField f = { 0 }; GType type = G_VALUE_TYPE (&field->value); f.name = field->name; g_value_init (&f.value, type); g_value_copy (&field->value, &f.value); gst_structure_set_field (structure, &f); } /** * gst_structure_set_field: * @structure: a #GstStructure * @field: the #GstStructureField to set * * Sets a field in the structure. If the structure currently contains * a field with the same name, it is replaced with the provided field. * Otherwise, the field is added to the structure. The field's value * is not deeply copied. * * This function is intended mainly for internal use. The function * #gst_structure_set() is recommended instead of this one. */ void gst_structure_set_field(GstStructure *structure, GstStructureField *field) { GstStructureField *f; int i; for(i=0;ifields->len;i++){ f = GST_STRUCTURE_FIELD(structure, i); if(f->name == field->name){ g_value_unset(&f->value); memcpy(f,field,sizeof(GstStructureField)); return; } } g_array_append_val(structure->fields, *field); } /** * gst_structure_id_get_field: * @structure: a #GstStructure * @field_id: the GQuark of the field to get * * Gets the specified field from the structure. If there is no * field with the given ID, NULL is returned. * * Returns: the #GstStructureField with the given ID */ GstStructureField *gst_structure_id_get_field(const GstStructure *structure, GQuark field_id) { GstStructureField *field; int i; g_return_val_if_fail(structure != NULL, NULL); for(i=0;ifields->len;i++){ field = GST_STRUCTURE_FIELD(structure, i); if(field->name == field_id) return field; } return NULL; } /** * gst_structure_get_field: * @structure: a #GstStructure * @fieldname: the name of the field to get * * Gets the specified field from the structure. If there is no * field with the given ID, NULL is returned. * * Returns: the #GstStructureField with the given name */ GstStructureField * gst_structure_get_field(const GstStructure *structure, const gchar *fieldname) { g_return_val_if_fail(structure != NULL, NULL); g_return_val_if_fail(fieldname != NULL, NULL); return gst_structure_id_get_field(structure, g_quark_from_string(fieldname)); } /** * gst_structure_get_value: * @structure: a #GstStructure * @fieldname: the name of the field to get * * Accessor function. * * Returns: the #GValue corresponding to the field with the given name. */ const GValue * gst_structure_get_value(const GstStructure *structure, const gchar *fieldname) { GstStructureField *field; g_return_val_if_fail(structure != NULL, NULL); g_return_val_if_fail(fieldname != NULL, NULL); field = gst_structure_get_field(structure, fieldname); if(field == NULL) return NULL; return &field->value; } #if 0 void gst_structure_get(GstStructure *structure, const gchar *fieldname, ...) { } #endif /** * gst_structure_remove_field: * @structure: a #GstStructure * @fieldname: the name of the field to remove * * Removes the field with the given name. If the field with the given * name does not exist, the structure is unchanged. */ void gst_structure_remove_field(GstStructure *structure, const gchar *fieldname) { GstStructureField *field; GQuark id; int i; g_return_if_fail(structure != NULL); g_return_if_fail(fieldname != NULL); id = g_quark_from_string(fieldname); for(i=0;ifields->len;i++){ field = GST_STRUCTURE_FIELD(structure, i); if(field->name == id){ if(G_IS_VALUE(&field->value)){ g_value_unset(&field->value); } structure->fields = g_array_remove_index(structure->fields, i); return; } } } /** * gst_structure_remove_all_fields: * @structure: a #GstStructure * * Removes all fields in a GstStructure. */ void gst_structure_remove_all_fields(GstStructure *structure) { GstStructureField *field; int i; g_return_if_fail(structure != NULL); for (i = structure->fields->len - 1; i >= 0; i-- ) { field = GST_STRUCTURE_FIELD(structure, i); if (G_IS_VALUE (&field->value)) { g_value_unset(&field->value); } structure->fields = g_array_remove_index (structure->fields, i); } } /** * gst_structure_get_field_type: * @structure: a #GstStructure * @fieldname: the name of the field * * Finds the field with the given name, and returns the type of the * value it contains. If the field is not found, G_TYPE_INVALID is * returned. * * Returns: the #GValue of the field */ GType gst_structure_get_field_type(const GstStructure *structure, const gchar *fieldname) { GstStructureField *field; g_return_val_if_fail(structure != NULL, G_TYPE_INVALID); g_return_val_if_fail(fieldname != NULL, G_TYPE_INVALID); field = gst_structure_get_field(structure, fieldname); if(field == NULL) return G_TYPE_INVALID; return G_VALUE_TYPE(&field->value); } /** * gst_structure_n_fields: * @structure: a #GstStructure * * Accessor function. * * Returns: the number of fields in the structure */ gint gst_structure_n_fields(const GstStructure *structure) { g_return_val_if_fail(structure != NULL, 0); return structure->fields->len; } /** * gst_structure_field_foreach: * @structure: a #GstStructure * @func: a function to call for each field * @user_data: private data * * Calls the provided function once for each field in the #GstStructure. */ void gst_structure_field_foreach (GstStructure *structure, GstStructureForeachFunc func, gpointer user_data) { int i; GstStructureField *field; for(i=0;ifields->len;i++){ field = GST_STRUCTURE_FIELD(structure, i); func (structure, field->name, &field->value, user_data); } } /** * gst_structure_has_field: * @structure: a #GstStructure * @fieldname: the name of a field * * Accessor function. * * Returns: TRUE if the structure contains a field with the given name */ gboolean gst_structure_has_field(const GstStructure *structure, const gchar *fieldname) { GstStructureField *field; g_return_val_if_fail(structure != NULL, 0); g_return_val_if_fail(fieldname != NULL, 0); field = gst_structure_get_field(structure, fieldname); return (field != NULL); } /** * gst_structure_has_field: * @structure: a #GstStructure * @fieldname: the name of a field * @type: the type of a value * * Accessor function. * * Returns: TRUE if the structure contains a field with the given name and type */ gboolean gst_structure_has_field_typed(const GstStructure *structure, const gchar *fieldname, GType type) { GstStructureField *field; g_return_val_if_fail(structure != NULL, 0); g_return_val_if_fail(fieldname != NULL, 0); field = gst_structure_get_field(structure, fieldname); if(field == NULL) return FALSE; return (G_VALUE_TYPE(&field->value) == type); } /* utility functions */ /** * gst_structure_get_boolean: * @structure: a #GstStructure * @fieldname: the name of a field * @ptr: a pointer to a #gboolean to set * * Sets the boolean pointed to by @ptr corresponding to the value of the * given field. Caller is responsible for making sure the field exists * and has the correct type. * * Returns: TRUE if the value could be set correctly */ gboolean gst_structure_get_boolean(const GstStructure *structure, const gchar *fieldname, gboolean *value) { GstStructureField *field; g_return_val_if_fail(structure != NULL, FALSE); g_return_val_if_fail(fieldname != NULL, FALSE); field = gst_structure_get_field(structure, fieldname); if(field == NULL) return FALSE; if(!G_VALUE_HOLDS_BOOLEAN(&field->value))return FALSE; *value = g_value_get_boolean(&field->value); return TRUE; } /** * gst_structure_get_int: * @structure: a #GstStructure * @fieldname: the name of a field * @ptr: a pointer to an int to set * * Sets the int pointed to by @ptr corresponding to the value of the * given field. Caller is responsible for making sure the field exists * and has the correct type. * * Returns: TRUE if the value could be set correctly */ gboolean gst_structure_get_int(const GstStructure *structure, const gchar *fieldname, gint *value) { GstStructureField *field; g_return_val_if_fail(structure != NULL, FALSE); g_return_val_if_fail(fieldname != NULL, FALSE); g_return_val_if_fail(value != NULL, FALSE); field = gst_structure_get_field(structure, fieldname); if(field == NULL) return FALSE; if(!G_VALUE_HOLDS_INT(&field->value))return FALSE; *value = g_value_get_int(&field->value); return TRUE; } /** * gst_structure_get_fourcc: * @structure: a #GstStructure * @fieldname: the name of a field * @ptr: a pointer to a #GstFourcc to set * * Sets the #GstFourcc pointed to by @ptr corresponding to the value of the * given field. Caller is responsible for making sure the field exists * and has the correct type. * * Returns: TRUE if the value could be set correctly */ gboolean gst_structure_get_fourcc(const GstStructure *structure, const gchar *fieldname, guint32 *value) { GstStructureField *field; g_return_val_if_fail(structure != NULL, FALSE); g_return_val_if_fail(fieldname != NULL, FALSE); g_return_val_if_fail(value != NULL, FALSE); field = gst_structure_get_field(structure, fieldname); if(field == NULL) return FALSE; if(!G_VALUE_HOLDS_UINT(&field->value))return FALSE; *value = g_value_get_uint(&field->value); return TRUE; } /** * gst_structure_get_double: * @structure: a #GstStructure * @fieldname: the name of a field * @ptr: a pointer to a #GstFourcc to set * * Sets the double pointed to by @ptr corresponding to the value of the * given field. Caller is responsible for making sure the field exists * and has the correct type. * * Returns: TRUE if the value could be set correctly */ gboolean gst_structure_get_double(const GstStructure *structure, const gchar *fieldname, gdouble *value) { GstStructureField *field; g_return_val_if_fail(structure != NULL, FALSE); g_return_val_if_fail(fieldname != NULL, FALSE); g_return_val_if_fail(value != NULL, FALSE); field = gst_structure_get_field(structure, fieldname); if(field == NULL) return FALSE; if(!G_VALUE_HOLDS_DOUBLE(&field->value))return FALSE; *value = g_value_get_double(&field->value); return TRUE; } /** * gst_structure_get_string: * @structure: a #GstStructure * @fieldname: the name of a field * @ptr: a pointer to a #GstFourcc to set * * Finds the field corresponding to @fieldname, and returns the string * contained in the field's value. Caller is responsible for making * sure the field exists and has the correct type. * * The string should not be modified, and remains valid until the next * call to a gst_structure_*() function with the given structure. * * Returns: a pointer to the string */ const gchar * gst_structure_get_string(const GstStructure *structure, const gchar *fieldname) { GstStructureField *field; g_return_val_if_fail(structure != NULL, NULL); g_return_val_if_fail(fieldname != NULL, NULL); field = gst_structure_get_field(structure, fieldname); if(field == NULL) return FALSE; if(!G_VALUE_HOLDS_STRING(&field->value))return FALSE; return g_value_get_string(&field->value); } typedef struct _GstStructureAbbreviation { char *type_name; GType type; } GstStructureAbbreviation; static GstStructureAbbreviation _gst_structure_abbrs[] = { { "int", G_TYPE_INT }, { "i", G_TYPE_INT }, { "float", G_TYPE_FLOAT }, { "f", G_TYPE_FLOAT }, { "double", G_TYPE_DOUBLE }, { "d", G_TYPE_DOUBLE }, //{ "fourcc", GST_TYPE_FOURCC }, { "boolean", G_TYPE_BOOLEAN }, { "bool", G_TYPE_BOOLEAN }, { "b", G_TYPE_BOOLEAN }, { "string", G_TYPE_STRING }, { "str", G_TYPE_STRING }, { "s", G_TYPE_STRING } }; static GType _gst_structure_from_abbr(const char *type_name) { int i; g_return_val_if_fail(type_name != NULL, G_TYPE_INVALID); for(i=0;iname)); for(i=0;ifields->len;i++){ GValue s_val = { 0 }; GType type; field = GST_STRUCTURE_FIELD(structure, i); g_value_init(&s_val, G_TYPE_STRING); g_value_transform (&field->value, &s_val); type = G_VALUE_TYPE (&field->value); if (type == GST_TYPE_LIST) { GPtrArray *ptr_array = g_value_peek_pointer (&field->value); if (ptr_array->len > 0){ GValue *value = g_ptr_array_index (ptr_array, 0); type = G_VALUE_TYPE (value); } else { type = G_TYPE_INT; } } else if (G_VALUE_TYPE(&field->value) == GST_TYPE_INT_RANGE) { type = G_TYPE_INT; } else if (G_VALUE_TYPE(&field->value) == GST_TYPE_DOUBLE_RANGE) { type = G_TYPE_DOUBLE; } g_string_append_printf(s, ", %s:%s=%s", g_quark_to_string(field->name), _gst_structure_to_abbr(type), g_value_get_string(&s_val)); g_value_unset (&s_val); } return g_string_free(s, FALSE); } /* * r will still point to the string. if end == next, the string will not be * null-terminated. In all other cases it will be. * end = pointer to char behind end of string, next = pointer to start of * unread data. * THIS FUNCTION MODIFIES THE STRING AND DETECTS INSIDE A NONTERMINATED STRING */ static gboolean _gst_structure_parse_string (gchar *r, gchar **end, gchar **next) { gchar *w; gchar c = '\0'; w = r; if (*r == '\'' || *r == '\"') { c = *r; r++; } for (;;r++) { if (*r == '\0') { if (c) { goto error; } else { goto found; } } if (*r == '\\') { r++; if (*r == '\0') goto error; *w++ = *r; continue; } if (*r == c) { r++; if (*r == '\0') goto found; break; } if (!c) { if (g_ascii_isspace (*r)) break; /* this needs to be escaped */ if (*r == ',' || *r == ')' || *r == ']' || *r == ':' || *r == ';' || *r == '(' || *r == '[') break; } *w++ = *r; } found: while (g_ascii_isspace (*r)) r++; if (w != r) *w++ = '\0'; *end = w; *next = r; return TRUE; error: return FALSE; } static gboolean _gst_structure_parse_value (gchar *s, gchar **after, GType type, GValue *value) { gboolean ret = FALSE; gchar *val; gchar *end; if (type == G_TYPE_INVALID) return FALSE; while (g_ascii_isspace (*s)) s++; g_value_init(value, type); val = s; switch (type) { case G_TYPE_INT: { int x; x = strtol (val, &s, 0); if (val != s) { g_value_set_int (value, x); ret = TRUE; } } break; case G_TYPE_FLOAT: { double x; x = g_ascii_strtod (val, &s); if (val != s) { g_value_set_float (value, x); ret = TRUE; } } break; case G_TYPE_DOUBLE: { double x; x = g_ascii_strtod (val, &s); if (val != s) { g_value_set_double (value, x); ret = TRUE; } } break; case G_TYPE_BOOLEAN: { int len; ret = _gst_structure_parse_string (val, &end, &s); len = end - val; if (ret && len > 0) { if (g_ascii_strncasecmp (val, "true", len) == 0 || g_ascii_strncasecmp (val, "yes", len) == 0 || g_ascii_strncasecmp (val, "t", len) == 0 || strncmp (val, "1", len)) { g_value_set_boolean (value, TRUE); } else if (g_ascii_strncasecmp (val, "false", len) == 0 || g_ascii_strncasecmp (val, "no", len) == 0 || g_ascii_strncasecmp (val, "f", len) == 0 || strncmp (val, "0", len)) { g_value_set_boolean (value, FALSE); } else { ret = FALSE; } } } break; case G_TYPE_STRING: { ret = _gst_structure_parse_string (val, &end, &s); if (ret) { g_value_set_string_take_ownership (value, g_strndup(val, end - val)); ret = TRUE; } } break; default: /* FIXME: make more general */ if (type == GST_TYPE_FOURCC) { guint32 fourcc = 0; if (g_ascii_isdigit (*s)) { fourcc = strtoul (val, &s, 0); if (val != s) { ret = TRUE; } } else { ret = _gst_structure_parse_string (val, &end, &s); g_print("end - val = %d\n", end - val); if (end - val >= 4) { fourcc = GST_MAKE_FOURCC(val[0], val[1], val[2], val[3]); ret = TRUE; } } gst_value_set_fourcc (value, fourcc); } else { g_critical("type %s not handled", g_type_name(type)); } break; } *after = s; return ret; } static gboolean _gst_structure_parse_range (gchar *s, gchar **after, GType type, GValue *value) { GValue value1 = { 0 }; GValue value2 = { 0 }; GType range_type; gboolean ret; if (type == G_TYPE_DOUBLE) { range_type = GST_TYPE_DOUBLE_RANGE; } else if (type == G_TYPE_INT) { range_type = GST_TYPE_INT_RANGE; } else { return FALSE; } g_print("%d \"%s\"\n", __LINE__, s); if (*s != '[') return FALSE; s++; g_print("%d \"%s\"\n", __LINE__, s); ret = _gst_structure_parse_value(s, &s, type, &value1); if (ret == FALSE) return FALSE; while (g_ascii_isspace (*s)) s++; g_print("%d \"%s\"\n", __LINE__, s); if (*s != ',') return FALSE; s++; while (g_ascii_isspace (*s)) s++; g_print("%d \"%s\"\n", __LINE__, s); ret = _gst_structure_parse_value(s, &s, type, &value2); if (ret == FALSE) return FALSE; while (g_ascii_isspace (*s)) s++; g_print("%d \"%s\"\n", __LINE__, s); if (*s != ']') return FALSE; s++; g_value_init(value, range_type); if (range_type == GST_TYPE_DOUBLE_RANGE) { gst_value_set_double_range(value, g_value_get_double(&value1), g_value_get_double(&value2)); } else { gst_value_set_int_range(value, g_value_get_int(&value1), g_value_get_int(&value2)); } *after = s; return TRUE; } static gboolean _gst_structure_parse_list (gchar *s, gchar **after, GType type, GValue *value) { GValue list_value = { 0 }; gboolean ret; g_value_init(value, GST_TYPE_LIST); if (*s != '(') return FALSE; s++; while (g_ascii_isspace (*s)) s++; if (*s == ')') { s++; *after = s; return TRUE; } ret = _gst_structure_parse_value(s, &s, type, &list_value); if (ret == FALSE) return FALSE; while (g_ascii_isspace (*s)) s++; while (*s != ')') { if (*s != ',') return FALSE; s++; while (g_ascii_isspace (*s)) s++; memset (&list_value, 0, sizeof (list_value)); ret = _gst_structure_parse_value(s, &s, type, &list_value); if (ret == FALSE) return FALSE; while (g_ascii_isspace (*s)) s++; } s++; *after = s; return TRUE; } static gboolean _gst_structure_parse_field (gchar *str, gchar **after, GstStructureField *field) { /* NAME[:TYPE]=VALUE */ gchar *name; gchar *type_name; gchar *s, *del; gboolean have_type = FALSE; GType type = G_TYPE_INVALID; int ret; g_print("parsing: \"%s\"\n", str); name = s = str; while (g_ascii_isalnum (*s) || *s == '_' || *s == '-') s++; del = s; while (g_ascii_isspace (*s)) s++; if (!(*s == '=' || *s == ':')) return FALSE; if (*s == ':') have_type = TRUE; s++; while (g_ascii_isspace (*s)) s++; *del = '\0'; field->name = g_quark_from_string (name); if (have_type) { while (g_ascii_isspace (*s)) s++; type_name = s; while (g_ascii_isalnum (*s) || *s == '_' || *s == '-') s++; del = s; while (g_ascii_isspace (*s)) s++; if (*s != '=') return FALSE; s++; while (g_ascii_isspace (*s)) s++; *del = '\0'; g_print("type name is \"%s\"\n",type_name); type = _gst_structure_from_abbr(type_name); g_print("type n is \"%s\"\n",g_type_name(type)); if (type == G_TYPE_INVALID) return FALSE; } else { if (g_ascii_isdigit (*s) || ((*s == '-' || *s == '+') && g_ascii_isdigit (s[1]))) { char *t = s; while (g_ascii_isdigit (*t)) t++; if (*t == '.'){ type = G_TYPE_DOUBLE; } else { type = G_TYPE_INT; } } else if (g_ascii_isalpha (*s) || *s == '"' || *s == '\'') { type = G_TYPE_STRING; } } if (*s == '[') { ret = _gst_structure_parse_range (s, &s, type, &field->value); } else if (*s == '(') { ret = _gst_structure_parse_list (s, &s, type, &field->value); } else { ret = _gst_structure_parse_value(s, &s, type, &field->value); } *after = s; return ret; } /** * gst_structure_from_string: * @structure: a #GstStructure * * Creates a #GstStructure from a string representation. * * Returns: a new #GstStructure */ GstStructure * gst_structure_from_string (const gchar *string, gchar **end) { char *name; char *copy; char *w; char *r; char save; GstStructure *structure; GstStructureField field = { 0 }; gboolean res; g_return_val_if_fail(string != NULL, NULL); copy = g_strdup(string); r = copy; name = r; res = _gst_structure_parse_string (r, &w, &r); if (!res) return NULL; while (g_ascii_isspace(*r)) r++; if(*r != 0 && *r != ';' && *r != ',') return NULL; save = *w; *w = 0; structure = gst_structure_empty_new(name); *w = save; while (*r && (*r != ';')){ if(*r != ',') { return NULL; } r++; while (*r && g_ascii_isspace(*r)) r++; memset(&field,0,sizeof(field)); res = _gst_structure_parse_field (r, &r, &field); g_print("returned %d \"%s\"\n", res, r); if (!res) { gst_structure_free (structure); return NULL; } gst_structure_set_field(structure, &field); while (*r && g_ascii_isspace(*r)) r++; } if (end) *end = (char *)string + (r - copy); return structure; } static void _gst_structure_transform_to_string(const GValue *src_value, GValue *dest_value) { g_return_if_fail(src_value != NULL); g_return_if_fail(dest_value != NULL); dest_value->data[0].v_pointer = gst_structure_to_string (src_value->data[0].v_pointer); } static void _gst_structure_value_init (GValue *value) { value->data[0].v_pointer = gst_structure_empty_new(""); } static void _gst_structure_value_free (GValue *value) { gst_structure_free(value->data[0].v_pointer); } static void _gst_structure_value_copy (const GValue *src, GValue *dest) { dest->data[0].v_pointer = gst_structure_copy(src->data[0].v_pointer); } static gpointer _gst_structure_value_peek_pointer (const GValue *value) { return value->data[0].v_pointer; }