mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-17 22:06:41 +00:00
58b18a3624
Original commit message from CVS: Merge gstvalue and gststructure from CAPS branch
1411 lines
33 KiB
C
1411 lines
33 KiB
C
/* GStreamer
|
|
* Copyright (C) 2003 David A. Schleef <ds@schleef.org>
|
|
*
|
|
* 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 <string.h>
|
|
|
|
#include <gst/gst.h>
|
|
#include <gobject/gvaluecollector.h>
|
|
|
|
//#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;i<structure->fields->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;i<structure->fields->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;i<structure->fields->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;i<structure->fields->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;i<structure->fields->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;i<structure->fields->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;i<G_N_ELEMENTS(_gst_structure_abbrs);i++){
|
|
if(strcmp(type_name,_gst_structure_abbrs[i].type_name)==0){
|
|
return _gst_structure_abbrs[i].type;
|
|
}
|
|
}
|
|
|
|
/* FIXME shouldn't be a special case */
|
|
if (strcmp (type_name,"fourcc") == 0 || strcmp (type_name, "4") == 0) {
|
|
return GST_TYPE_FOURCC;
|
|
}
|
|
|
|
return g_type_from_name (type_name);
|
|
}
|
|
|
|
static const char *_gst_structure_to_abbr(GType type)
|
|
{
|
|
int i;
|
|
|
|
g_return_val_if_fail(type != G_TYPE_INVALID, NULL);
|
|
|
|
for(i=0;i<G_N_ELEMENTS(_gst_structure_abbrs);i++){
|
|
if(type == _gst_structure_abbrs[i].type){
|
|
return _gst_structure_abbrs[i].type_name;
|
|
}
|
|
}
|
|
|
|
/* FIXME shouldn't be a special case */
|
|
if (type == GST_TYPE_FOURCC) {
|
|
return "fourcc";
|
|
}
|
|
|
|
return g_type_name(type);
|
|
}
|
|
|
|
/**
|
|
* gst_structure_to_string:
|
|
* @structure: a #GstStructure
|
|
*
|
|
* Converts @structure to a human-readable representation.
|
|
*
|
|
* Returns: a pointer to string allocated by g_malloc()
|
|
*/
|
|
gchar *
|
|
gst_structure_to_string(const GstStructure *structure)
|
|
{
|
|
GstStructureField *field;
|
|
GString *s;
|
|
int i;
|
|
|
|
g_return_val_if_fail(structure != NULL, NULL);
|
|
|
|
s = g_string_new("");
|
|
g_string_append_printf(s, "\"%s\"", g_quark_to_string(structure->name));
|
|
for(i=0;i<structure->fields->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;
|
|
}
|
|
|