First THREADED backport attempt, focusing on adding locks and making sure the API...
[platform/upstream/gstreamer.git] / gst / gststructure.c
1 /* GStreamer
2  * Copyright (C) 2003 David A. Schleef <ds@schleef.org>
3  *
4  * gststructure.c: lists of { GQuark, GValue } tuples
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <string.h>
27
28 #include "gst_private.h"
29 #include <gst/gst.h>
30 #include <gobject/gvaluecollector.h>
31
32 typedef struct _GstStructureField GstStructureField;
33
34 struct _GstStructureField
35 {
36   GQuark name;
37   GValue value;
38 };
39
40 #define GST_STRUCTURE_FIELD(structure, index) \
41     &g_array_index((structure)->fields, GstStructureField, (index))
42
43 #define IS_MUTABLE(structure) \
44     (!(structure)->parent_refcount || \
45      gst_atomic_int_read ((structure)->parent_refcount) == 1)
46
47 static void gst_structure_set_field (GstStructure * structure,
48     GstStructureField * field);
49 static GstStructureField *gst_structure_get_field (const GstStructure *
50     structure, const gchar * fieldname);
51 static GstStructureField *gst_structure_id_get_field (const GstStructure *
52     structure, GQuark field);
53 static void gst_structure_transform_to_string (const GValue * src_value,
54     GValue * dest_value);
55 static GstStructure *gst_structure_copy_conditional (const GstStructure *
56     structure);
57 static gboolean gst_structure_parse_value (gchar * str, gchar ** after,
58     GValue * value, GType default_type);
59 static gboolean gst_structure_parse_simple_string (gchar * s, gchar ** end);
60
61 GType
62 gst_structure_get_type (void)
63 {
64   static GType gst_structure_type;
65
66   if (!gst_structure_type) {
67     gst_structure_type = g_boxed_type_register_static ("GstStructure",
68         (GBoxedCopyFunc) gst_structure_copy_conditional,
69         (GBoxedFreeFunc) gst_structure_free);
70
71     g_value_register_transform_func (gst_structure_type, G_TYPE_STRING,
72         gst_structure_transform_to_string);
73   }
74
75   return gst_structure_type;
76 }
77
78 static GstStructure *
79 gst_structure_id_empty_new_with_size (GQuark quark, guint prealloc)
80 {
81   GstStructure *structure;
82
83   structure = g_new0 (GstStructure, 1);
84   structure->type = gst_structure_get_type ();
85   structure->name = quark;
86   structure->fields =
87       g_array_sized_new (FALSE, TRUE, sizeof (GstStructureField), prealloc);
88
89   return structure;
90 }
91
92 /**
93  * gst_structure_id_empty_new:
94  * @quark: name of new structure
95  *
96  * Creates a new, empty #GstStructure with the given name.
97  *
98  * Returns: a new, empty #GstStructure
99  */
100 GstStructure *
101 gst_structure_id_empty_new (GQuark quark)
102 {
103   g_return_val_if_fail (quark != 0, NULL);
104
105   return gst_structure_id_empty_new_with_size (quark, 0);
106 }
107
108 /**
109  * gst_structure_empty_new:
110  * @name: name of new structure
111  *
112  * Creates a new, empty #GstStructure with the given name.
113  *
114  * Returns: a new, empty #GstStructure
115  */
116 GstStructure *
117 gst_structure_empty_new (const gchar * name)
118 {
119   g_return_val_if_fail (name != NULL, NULL);
120
121   return gst_structure_id_empty_new_with_size (g_quark_from_string (name), 0);
122 }
123
124 /**
125  * gst_structure_new:
126  * @name: name of new structure
127  * @firstfield: name of first field to set
128  * @...: additional arguments
129  *
130  * Creates a new #GstStructure with the given name.  Parses the
131  * list of variable arguments and sets fields to the values listed.
132  * Variable arguments should be passed as field name, field type,
133  * and value.  Last variable argument should be NULL.
134  *
135  * Returns: a new #GstStructure
136  */
137 GstStructure *
138 gst_structure_new (const gchar * name, const gchar * firstfield, ...)
139 {
140   GstStructure *structure;
141   va_list varargs;
142
143   g_return_val_if_fail (name != NULL, NULL);
144
145   va_start (varargs, firstfield);
146
147   structure = gst_structure_new_valist (name, firstfield, varargs);
148
149   va_end (varargs);
150
151   return structure;
152 }
153
154 /**
155  * gst_structure_new_valist:
156  * @name: name of new structure
157  * @firstfield: name of first field to set
158  * @varargs: variable argument list
159  *
160  * Creates a new #GstStructure with the given name.  Structure fields
161  * are set according to the varargs in a manner similar to
162  * @gst_structure_new.
163  *
164  * Returns: a new #GstStructure
165  */
166 GstStructure *
167 gst_structure_new_valist (const gchar * name,
168     const gchar * firstfield, va_list varargs)
169 {
170   GstStructure *structure;
171
172   g_return_val_if_fail (name != NULL, NULL);
173
174   structure = gst_structure_empty_new (name);
175   gst_structure_set_valist (structure, firstfield, varargs);
176
177   return structure;
178 }
179
180 /**
181  * gst_structure_set_parent_refcount:
182  * @structure: a #GstStructure
183  * @refcount: a pointer to the parent's #GstAtomicInt refcount
184  *
185  * Sets the parent_refcount field of #GstStructure. This field is used to
186  * determine whether a structure is mutable or not. This function should only be
187  * called by code implementing parent objects of GstStructure, as described in
188  * the MT Refcounting section of the design documents.
189  *
190  * Returns: a new #GstStructure.
191  */
192 void
193 gst_structure_set_parent_refcount (GstStructure * structure,
194     GstAtomicInt * refcount)
195 {
196   if (structure->parent_refcount)
197     g_return_if_fail (refcount == NULL);
198   else
199     g_return_if_fail (refcount != NULL);
200
201   structure->parent_refcount = refcount;
202 }
203
204 /**
205  * gst_structure_copy:
206  * @structure: a #GstStructure to duplicate
207  *
208  * Duplicates a #GstStructure and all its fields and values.
209  *
210  * Returns: a new #GstStructure.
211  */
212 GstStructure *
213 gst_structure_copy (const GstStructure * structure)
214 {
215   GstStructure *new_structure;
216   GstStructureField *field;
217   int i;
218
219   g_return_val_if_fail (structure != NULL, NULL);
220
221   new_structure =
222       gst_structure_id_empty_new_with_size (structure->name,
223       structure->fields->len);
224
225   for (i = 0; i < structure->fields->len; i++) {
226     GstStructureField new_field = { 0 };
227
228     field = GST_STRUCTURE_FIELD (structure, i);
229
230     new_field.name = field->name;
231     gst_value_init_and_copy (&new_field.value, &field->value);
232     g_array_append_val (new_structure->fields, new_field);
233   }
234
235   return new_structure;
236 }
237
238 /**
239  * gst_structure_free: 
240  * @structure: the #GstStructure to free
241  *
242  * Frees a #GstStructure and all its fields and values. The structure must not
243  * parent when this function is called.
244  */
245 void
246 gst_structure_free (GstStructure * structure)
247 {
248   GstStructureField *field;
249   int i;
250
251   g_return_if_fail (structure != NULL);
252   g_return_if_fail (structure->parent_refcount == NULL);
253
254   for (i = 0; i < structure->fields->len; i++) {
255     field = GST_STRUCTURE_FIELD (structure, i);
256
257     if (G_IS_VALUE (&field->value)) {
258       g_value_unset (&field->value);
259     }
260   }
261   g_array_free (structure->fields, TRUE);
262 #ifdef USE_POISONING
263   memset (structure, 0xff, sizeof (GstStructure));
264 #endif
265   g_free (structure);
266 }
267
268 /**
269  * gst_structure_get_name:
270  * @structure: a #GstStructure
271  *
272  * Accessor fuction.
273  *
274  * Returns: the name of the structure.
275  */
276 const gchar *
277 gst_structure_get_name (const GstStructure * structure)
278 {
279   g_return_val_if_fail (structure != NULL, NULL);
280
281   return g_quark_to_string (structure->name);
282 }
283
284 /**
285  * gst_structure_get_name:
286  * @structure: a #GstStructure
287  *
288  * Accessor fuction.
289  *
290  * Returns: the quark representing the name of the structure.
291  */
292 GQuark
293 gst_structure_get_name_id (const GstStructure * structure)
294 {
295   g_return_val_if_fail (structure != NULL, 0);
296
297   return structure->name;
298 }
299
300 /**
301  * gst_structure_set_name:
302  * @structure: a #GstStructure
303  * @name: the new name of the structure
304  *
305  * Sets the name of the structure to the given name.  The string
306  * provided is copied before being used.
307  */
308 void
309 gst_structure_set_name (GstStructure * structure, const gchar * name)
310 {
311   g_return_if_fail (structure != NULL);
312   g_return_if_fail (name != NULL);
313   g_return_if_fail (IS_MUTABLE (structure));
314
315   structure->name = g_quark_from_string (name);
316 }
317
318 /**
319  * gst_structure_id_set_value:
320  * @structure: a #GstStructure
321  * @field: a #GQuark representing a field
322  * @value: the new value of the field
323  *
324  * Sets the field with the given ID to the provided value.  If the field
325  * does not exist, it is created.  If the field exists, the previous
326  * value is freed.
327  */
328 void
329 gst_structure_id_set_value (GstStructure * structure,
330     GQuark field, const GValue * value)
331 {
332   GstStructureField gsfield = { 0, {0,} };
333
334   g_return_if_fail (structure != NULL);
335   g_return_if_fail (G_IS_VALUE (value));
336   g_return_if_fail (IS_MUTABLE (structure));
337
338   gsfield.name = field;
339   gst_value_init_and_copy (&gsfield.value, value);
340
341   gst_structure_set_field (structure, &gsfield);
342 }
343
344 /**
345  * gst_structure_set_value:
346  * @structure: a #GstStructure
347  * @fieldname: the name of the field to set
348  * @value: the new value of the field
349  *
350  * Sets the field with the given name to the provided value.  If the field
351  * does not exist, it is created.  If the field exists, the previous
352  * value is freed.
353  */
354 void
355 gst_structure_set_value (GstStructure * structure,
356     const gchar * fieldname, const GValue * value)
357 {
358   g_return_if_fail (structure != NULL);
359   g_return_if_fail (fieldname != NULL);
360   g_return_if_fail (G_IS_VALUE (value));
361   g_return_if_fail (IS_MUTABLE (structure));
362
363   gst_structure_id_set_value (structure, g_quark_from_string (fieldname),
364       value);
365 }
366
367 /**
368  * gst_structure_set:
369  * @structure: a #GstStructure
370  * @fieldname: the name of the field to set
371  * @...: variable arguments
372  *
373  * Parses the variable arguments and sets fields accordingly.
374  * Variable arguments should be in the form field name, field type
375  * (as a GType), value.  The last variable argument should be NULL.
376  */
377 void
378 gst_structure_set (GstStructure * structure, const gchar * field, ...)
379 {
380   va_list varargs;
381
382   g_return_if_fail (structure != NULL);
383
384   va_start (varargs, field);
385
386   gst_structure_set_valist (structure, field, varargs);
387
388   va_end (varargs);
389 }
390
391 /**
392  * gst_structure_set_valist:
393  * @structure: a #GstStructure
394  * @fieldname: the name of the field to set
395  * @varargs: variable arguments
396  *
397  * va_list form of #gst_structure_set.
398  */
399 void
400 gst_structure_set_valist (GstStructure * structure,
401     const gchar * fieldname, va_list varargs)
402 {
403   GType type;
404   int i;
405   double d;
406   char *s;
407
408   g_return_if_fail (structure != NULL);
409   g_return_if_fail (IS_MUTABLE (structure));
410
411   while (fieldname) {
412     GstStructureField field = { 0 };
413
414     field.name = g_quark_from_string (fieldname);
415
416     type = va_arg (varargs, GType);
417
418     switch (type) {
419       case G_TYPE_INT:
420         i = va_arg (varargs, int);
421
422         g_value_init (&field.value, G_TYPE_INT);
423         g_value_set_int (&field.value, i);
424         break;
425       case G_TYPE_DOUBLE:
426         d = va_arg (varargs, double);
427
428         g_value_init (&field.value, G_TYPE_DOUBLE);
429         g_value_set_double (&field.value, d);
430         break;
431       case G_TYPE_BOOLEAN:
432         i = va_arg (varargs, int);
433
434         g_value_init (&field.value, G_TYPE_BOOLEAN);
435         g_value_set_boolean (&field.value, i);
436         break;
437       case G_TYPE_STRING:
438         s = va_arg (varargs, char *);
439
440         g_value_init (&field.value, G_TYPE_STRING);
441         g_value_set_string (&field.value, s);
442         break;
443       default:
444         if (type == GST_TYPE_FOURCC) {
445           i = va_arg (varargs, int);
446
447           g_value_init (&field.value, GST_TYPE_FOURCC);
448           gst_value_set_fourcc (&field.value, i);
449         } else if (type == GST_TYPE_INT_RANGE) {
450           int min, max;
451           min = va_arg (varargs, int);
452           max = va_arg (varargs, int);
453
454           g_value_init (&field.value, GST_TYPE_INT_RANGE);
455           gst_value_set_int_range (&field.value, min, max);
456         } else if (type == GST_TYPE_DOUBLE_RANGE) {
457           double min, max;
458           min = va_arg (varargs, double);
459           max = va_arg (varargs, double);
460
461           g_value_init (&field.value, GST_TYPE_DOUBLE_RANGE);
462           gst_value_set_double_range (&field.value, min, max);
463         } else if (type == GST_TYPE_BUFFER) {
464           GstBuffer *buffer = va_arg (varargs, GstBuffer *);
465
466           g_value_init (&field.value, GST_TYPE_BUFFER);
467           g_value_set_boxed (&field.value, buffer);
468         } else if (type == GST_TYPE_FRACTION) {
469           gint n, d;
470           n = va_arg (varargs, int);
471           d = va_arg (varargs, int);
472
473           g_value_init (&field.value, GST_TYPE_FRACTION);
474           gst_value_set_fraction (&field.value, n, d);
475         } else {
476           g_critical ("unimplemented vararg field type %d\n", (int) type);
477           return;
478         }
479         break;
480     }
481
482     gst_structure_set_field (structure, &field);
483
484     fieldname = va_arg (varargs, gchar *);
485   }
486 }
487
488 /* If the structure currently contains a field with the same name, it is
489  * replaced with the provided field. Otherwise, the field is added to the
490  * structure. The field's value is not deeply copied.
491  */
492 static void
493 gst_structure_set_field (GstStructure * structure, GstStructureField * field)
494 {
495   GstStructureField *f;
496   int i;
497
498   for (i = 0; i < structure->fields->len; i++) {
499     f = GST_STRUCTURE_FIELD (structure, i);
500
501     if (f->name == field->name) {
502       g_value_unset (&f->value);
503       memcpy (f, field, sizeof (GstStructureField));
504       return;
505     }
506   }
507
508   g_array_append_val (structure->fields, *field);
509 }
510
511 /* If there is no field with the given ID, NULL is returned.
512  */
513 static GstStructureField *
514 gst_structure_id_get_field (const GstStructure * structure, GQuark field_id)
515 {
516   GstStructureField *field;
517   int i;
518
519   g_return_val_if_fail (structure != NULL, NULL);
520
521   for (i = 0; i < structure->fields->len; i++) {
522     field = GST_STRUCTURE_FIELD (structure, i);
523
524     if (field->name == field_id)
525       return field;
526   }
527
528   return NULL;
529 }
530
531 /* If there is no field with the given ID, NULL is returned.
532  */
533 static GstStructureField *
534 gst_structure_get_field (const GstStructure * structure,
535     const gchar * fieldname)
536 {
537   g_return_val_if_fail (structure != NULL, NULL);
538   g_return_val_if_fail (fieldname != NULL, NULL);
539
540   return gst_structure_id_get_field (structure,
541       g_quark_from_string (fieldname));
542 }
543
544 /**
545  * gst_structure_get_value:
546  * @structure: a #GstStructure
547  * @fieldname: the name of the field to get
548  *
549  * Accessor function.
550  *
551  * Returns: the #GValue corresponding to the field with the given name.
552  */
553 const GValue *
554 gst_structure_get_value (const GstStructure * structure,
555     const gchar * fieldname)
556 {
557   GstStructureField *field;
558
559   g_return_val_if_fail (structure != NULL, NULL);
560   g_return_val_if_fail (fieldname != NULL, NULL);
561
562   field = gst_structure_get_field (structure, fieldname);
563   if (field == NULL)
564     return NULL;
565
566   return &field->value;
567 }
568
569 /**
570  * gst_structure_id_get_value:
571  * @structure: a #GstStructure
572  * @field: the #GQuark of the field to get
573  *
574  * Accessor function.
575  *
576  * Returns: the #GValue corresponding to the field with the given name 
577  *          identifier.
578  */
579 const GValue *
580 gst_structure_id_get_value (const GstStructure * structure, GQuark field)
581 {
582   GstStructureField *gsfield;
583
584   g_return_val_if_fail (structure != NULL, NULL);
585
586   gsfield = gst_structure_id_get_field (structure, field);
587   if (gsfield == NULL)
588     return NULL;
589
590   return &gsfield->value;
591 }
592
593 /**
594  * gst_structure_remove_field:
595  * @structure: a #GstStructure
596  * @fieldname: the name of the field to remove
597  *
598  * Removes the field with the given name.  If the field with the given
599  * name does not exist, the structure is unchanged.
600  */
601 void
602 gst_structure_remove_field (GstStructure * structure, const gchar * fieldname)
603 {
604   GstStructureField *field;
605   GQuark id;
606   int i;
607
608   g_return_if_fail (structure != NULL);
609   g_return_if_fail (fieldname != NULL);
610   g_return_if_fail (IS_MUTABLE (structure));
611
612   id = g_quark_from_string (fieldname);
613
614   for (i = 0; i < structure->fields->len; i++) {
615     field = GST_STRUCTURE_FIELD (structure, i);
616
617     if (field->name == id) {
618       if (G_IS_VALUE (&field->value)) {
619         g_value_unset (&field->value);
620       }
621       structure->fields = g_array_remove_index (structure->fields, i);
622       return;
623     }
624   }
625 }
626
627 /**
628  * gst_structure_remove_fields:
629  * @structure: a #GstStructure
630  * @fieldname: the name of the field to remove
631  * @...: NULL-terminated list of more fieldnames to remove
632  *
633  * Removes the field with the given names. If a field does not exist, the
634  * argument is ignored.
635  */
636 void
637 gst_structure_remove_fields (GstStructure * structure,
638     const gchar * fieldname, ...)
639 {
640   va_list varargs;
641
642   g_return_if_fail (structure != NULL);
643   g_return_if_fail (fieldname != NULL);
644   /* mutability checked in remove_field */
645
646   va_start (varargs, fieldname);
647
648   gst_structure_remove_fields_valist (structure, fieldname, varargs);
649
650   va_end (varargs);
651 }
652
653 /**
654  * gst_structure_remove_fields_valist:
655  * @structure: a #GstStructure
656  * @fieldname: the name of the field to remove
657  * @varargs: NULL-terminated list of more fieldnames to remove
658  *
659  * Removes the field with the given names. If a field does not exist, the
660  * argument is ignored.
661  */
662 void
663 gst_structure_remove_fields_valist (GstStructure * structure,
664     const gchar * fieldname, va_list varargs)
665 {
666   gchar *field = (gchar *) fieldname;
667
668   g_return_if_fail (structure != NULL);
669   g_return_if_fail (fieldname != NULL);
670   /* mutability checked in remove_field */
671
672   while (field) {
673     gst_structure_remove_field (structure, field);
674     field = va_arg (varargs, char *);
675   }
676 }
677
678 /**
679  * gst_structure_remove_all_fields:
680  * @structure: a #GstStructure
681  *
682  * Removes all fields in a GstStructure. 
683  */
684 void
685 gst_structure_remove_all_fields (GstStructure * structure)
686 {
687   GstStructureField *field;
688   int i;
689
690   g_return_if_fail (structure != NULL);
691   g_return_if_fail (IS_MUTABLE (structure));
692
693   for (i = structure->fields->len - 1; i >= 0; i--) {
694     field = GST_STRUCTURE_FIELD (structure, i);
695
696     if (G_IS_VALUE (&field->value)) {
697       g_value_unset (&field->value);
698     }
699     structure->fields = g_array_remove_index (structure->fields, i);
700   }
701 }
702
703 /**
704  * gst_structure_get_field_type:
705  * @structure: a #GstStructure
706  * @fieldname: the name of the field
707  *
708  * Finds the field with the given name, and returns the type of the
709  * value it contains.  If the field is not found, G_TYPE_INVALID is
710  * returned.
711  *
712  * Returns: the #GValue of the field
713  */
714 GType
715 gst_structure_get_field_type (const GstStructure * structure,
716     const gchar * fieldname)
717 {
718   GstStructureField *field;
719
720   g_return_val_if_fail (structure != NULL, G_TYPE_INVALID);
721   g_return_val_if_fail (fieldname != NULL, G_TYPE_INVALID);
722
723   field = gst_structure_get_field (structure, fieldname);
724   if (field == NULL)
725     return G_TYPE_INVALID;
726
727   return G_VALUE_TYPE (&field->value);
728 }
729
730 /**
731  * gst_structure_n_fields:
732  * @structure: a #GstStructure
733  *
734  * Accessor function.
735  *
736  * Returns: the number of fields in the structure
737  */
738 gint
739 gst_structure_n_fields (const GstStructure * structure)
740 {
741   g_return_val_if_fail (structure != NULL, 0);
742
743   return structure->fields->len;
744 }
745
746 /**
747  * gst_structure_foreach:
748  * @structure: a #GstStructure
749  * @func: a function to call for each field
750  * @user_data: private data
751  *
752  * Calls the provided function once for each field in the #GstStructure. The
753  * function must not modify the fields. Also see gst_structure_map_in_place().
754  *
755  * Returns: TRUE if the supplied function returns TRUE For each of the fields,
756  * FALSE otherwise.
757  */
758 gboolean
759 gst_structure_foreach (const GstStructure * structure,
760     GstStructureForeachFunc func, gpointer user_data)
761 {
762   int i;
763   GstStructureField *field;
764   gboolean ret;
765
766   g_return_val_if_fail (structure != NULL, FALSE);
767
768   for (i = 0; i < structure->fields->len; i++) {
769     field = GST_STRUCTURE_FIELD (structure, i);
770
771     ret = func (field->name, &field->value, user_data);
772     if (!ret)
773       return FALSE;
774   }
775
776   return TRUE;
777 }
778
779 /**
780  * gst_structure_map_in_place:
781  * @structure: a #GstStructure
782  * @func: a function to call for each field
783  * @user_data: private data
784  *
785  * Calls the provided function once for each field in the #GstStructure. In
786  * contrast to gst_structure_foreach(), the function may modify the fields. The
787  * structure must be mutable.
788  *
789  * Returns: TRUE if the supplied function returns TRUE For each of the fields,
790  * FALSE otherwise.
791  */
792 gboolean
793 gst_structure_map_in_place (GstStructure * structure,
794     GstStructureMapFunc func, gpointer user_data)
795 {
796   int i;
797   GstStructureField *field;
798   gboolean ret;
799
800   g_return_val_if_fail (structure != NULL, FALSE);
801   g_return_val_if_fail (IS_MUTABLE (structure), FALSE);
802
803   for (i = 0; i < structure->fields->len; i++) {
804     field = GST_STRUCTURE_FIELD (structure, i);
805
806     ret = func (field->name, &field->value, user_data);
807     if (!ret)
808       return FALSE;
809   }
810
811   return TRUE;
812 }
813
814 /**
815  * gst_structure_has_field:
816  * @structure: a #GstStructure
817  * @fieldname: the name of a field
818  *
819  * Accessor function.
820  *
821  * Returns: TRUE if the structure contains a field with the given name
822  */
823 gboolean
824 gst_structure_has_field (const GstStructure * structure,
825     const gchar * fieldname)
826 {
827   GstStructureField *field;
828
829   g_return_val_if_fail (structure != NULL, 0);
830   g_return_val_if_fail (fieldname != NULL, 0);
831
832   field = gst_structure_get_field (structure, fieldname);
833
834   return (field != NULL);
835 }
836
837 /**
838  * gst_structure_has_field_typed:
839  * @structure: a #GstStructure
840  * @fieldname: the name of a field
841  * @type: the type of a value
842  *
843  * Accessor function.
844  *
845  * Returns: TRUE if the structure contains a field with the given name and type
846  */
847 gboolean
848 gst_structure_has_field_typed (const GstStructure * structure,
849     const gchar * fieldname, GType type)
850 {
851   GstStructureField *field;
852
853   g_return_val_if_fail (structure != NULL, 0);
854   g_return_val_if_fail (fieldname != NULL, 0);
855
856   field = gst_structure_get_field (structure, fieldname);
857   if (field == NULL)
858     return FALSE;
859
860   return (G_VALUE_TYPE (&field->value) == type);
861 }
862
863
864 /* utility functions */
865
866 /**
867  * gst_structure_get_boolean:
868  * @structure: a #GstStructure
869  * @fieldname: the name of a field
870  * @value: a pointer to a #gboolean to set
871  *
872  * Sets the boolean pointed to by @value corresponding to the value of the
873  * given field.  Caller is responsible for making sure the field exists
874  * and has the correct type.
875  *
876  * Returns: TRUE if the value could be set correctly
877  */
878 gboolean
879 gst_structure_get_boolean (const GstStructure * structure,
880     const gchar * fieldname, gboolean * value)
881 {
882   GstStructureField *field;
883
884   g_return_val_if_fail (structure != NULL, FALSE);
885   g_return_val_if_fail (fieldname != NULL, FALSE);
886
887   field = gst_structure_get_field (structure, fieldname);
888
889   if (field == NULL)
890     return FALSE;
891   if (!G_VALUE_HOLDS_BOOLEAN (&field->value))
892     return FALSE;
893
894   *value = g_value_get_boolean (&field->value);
895
896   return TRUE;
897 }
898
899 /**
900  * gst_structure_get_int:
901  * @structure: a #GstStructure
902  * @fieldname: the name of a field
903  * @value: a pointer to an int to set
904  *
905  * Sets the int pointed to by @value corresponding to the value of the
906  * given field.  Caller is responsible for making sure the field exists
907  * and has the correct type.
908  *
909  * Returns: TRUE if the value could be set correctly
910  */
911 gboolean
912 gst_structure_get_int (const GstStructure * structure,
913     const gchar * fieldname, gint * value)
914 {
915   GstStructureField *field;
916
917   g_return_val_if_fail (structure != NULL, FALSE);
918   g_return_val_if_fail (fieldname != NULL, FALSE);
919   g_return_val_if_fail (value != NULL, FALSE);
920
921   field = gst_structure_get_field (structure, fieldname);
922
923   if (field == NULL)
924     return FALSE;
925   if (!G_VALUE_HOLDS_INT (&field->value))
926     return FALSE;
927
928   *value = g_value_get_int (&field->value);
929
930   return TRUE;
931 }
932
933 /**
934  * gst_structure_get_fourcc:
935  * @structure: a #GstStructure
936  * @fieldname: the name of a field
937  * @value: a pointer to a #GstFourcc to set
938  *
939  * Sets the #GstFourcc pointed to by @value corresponding to the value of the
940  * given field.  Caller is responsible for making sure the field exists
941  * and has the correct type.
942  *
943  * Returns: TRUE if the value could be set correctly
944  */
945 gboolean
946 gst_structure_get_fourcc (const GstStructure * structure,
947     const gchar * fieldname, guint32 * value)
948 {
949   GstStructureField *field;
950
951   g_return_val_if_fail (structure != NULL, FALSE);
952   g_return_val_if_fail (fieldname != NULL, FALSE);
953   g_return_val_if_fail (value != NULL, FALSE);
954
955   field = gst_structure_get_field (structure, fieldname);
956
957   if (field == NULL)
958     return FALSE;
959   if (!GST_VALUE_HOLDS_FOURCC (&field->value))
960     return FALSE;
961
962   *value = gst_value_get_fourcc (&field->value);
963
964   return TRUE;
965 }
966
967 /**
968  * gst_structure_get_double:
969  * @structure: a #GstStructure
970  * @fieldname: the name of a field
971  * @value: a pointer to a #GstFourcc to set
972  *
973  * Sets the double pointed to by @value corresponding to the value of the
974  * given field.  Caller is responsible for making sure the field exists
975  * and has the correct type.
976  *
977  * Returns: TRUE if the value could be set correctly
978  */
979 gboolean
980 gst_structure_get_double (const GstStructure * structure,
981     const gchar * fieldname, gdouble * value)
982 {
983   GstStructureField *field;
984
985   g_return_val_if_fail (structure != NULL, FALSE);
986   g_return_val_if_fail (fieldname != NULL, FALSE);
987   g_return_val_if_fail (value != NULL, FALSE);
988
989   field = gst_structure_get_field (structure, fieldname);
990
991   if (field == NULL)
992     return FALSE;
993   if (!G_VALUE_HOLDS_DOUBLE (&field->value))
994     return FALSE;
995
996   *value = g_value_get_double (&field->value);
997
998   return TRUE;
999 }
1000
1001 /**
1002  * gst_structure_get_string:
1003  * @structure: a #GstStructure
1004  * @fieldname: the name of a field
1005  *
1006  * Finds the field corresponding to @fieldname, and returns the string
1007  * contained in the field's value.  Caller is responsible for making
1008  * sure the field exists and has the correct type.
1009  *
1010  * The string should not be modified, and remains valid until the next
1011  * call to a gst_structure_*() function with the given structure.
1012  *
1013  * Returns: a pointer to the string
1014  */
1015 const gchar *
1016 gst_structure_get_string (const GstStructure * structure,
1017     const gchar * fieldname)
1018 {
1019   GstStructureField *field;
1020
1021   g_return_val_if_fail (structure != NULL, NULL);
1022   g_return_val_if_fail (fieldname != NULL, NULL);
1023
1024   field = gst_structure_get_field (structure, fieldname);
1025
1026   if (field == NULL)
1027     return NULL;
1028   if (!G_VALUE_HOLDS_STRING (&field->value))
1029     return NULL;
1030
1031   return g_value_get_string (&field->value);
1032 }
1033
1034 typedef struct _GstStructureAbbreviation
1035 {
1036   char *type_name;
1037   GType type;
1038 }
1039 GstStructureAbbreviation;
1040
1041 static GstStructureAbbreviation *
1042 gst_structure_get_abbrs (gint * n_abbrs)
1043 {
1044   static GstStructureAbbreviation *abbrs = NULL;
1045   static gint num = 0;
1046
1047   if (abbrs == NULL) {
1048     /* dynamically generate the array */
1049     GstStructureAbbreviation dyn_abbrs[] = {
1050       {"int", G_TYPE_INT}
1051       ,
1052       {"i", G_TYPE_INT}
1053       ,
1054       {"float", G_TYPE_FLOAT}
1055       ,
1056       {"f", G_TYPE_FLOAT}
1057       ,
1058       {"double", G_TYPE_DOUBLE}
1059       ,
1060       {"d", G_TYPE_DOUBLE}
1061       ,
1062       {"buffer", GST_TYPE_BUFFER}
1063       ,
1064       {"fourcc", GST_TYPE_FOURCC}
1065       ,
1066       {"4", GST_TYPE_FOURCC}
1067       ,
1068       {"fraction", GST_TYPE_FRACTION}
1069       ,
1070       {"boolean", G_TYPE_BOOLEAN}
1071       ,
1072       {"bool", G_TYPE_BOOLEAN}
1073       ,
1074       {"b", G_TYPE_BOOLEAN}
1075       ,
1076       {"string", G_TYPE_STRING}
1077       ,
1078       {"str", G_TYPE_STRING}
1079       ,
1080       {"s", G_TYPE_STRING}
1081     };
1082     num = G_N_ELEMENTS (dyn_abbrs);
1083     /* permanently allocate and copy the array now */
1084     abbrs = g_new0 (GstStructureAbbreviation, num);
1085     memcpy (abbrs, dyn_abbrs, sizeof (GstStructureAbbreviation) * num);
1086   }
1087   *n_abbrs = num;
1088
1089   return abbrs;
1090 }
1091
1092 static GType
1093 gst_structure_from_abbr (const char *type_name)
1094 {
1095   int i;
1096   GstStructureAbbreviation *abbrs;
1097   gint n_abbrs;
1098
1099   g_return_val_if_fail (type_name != NULL, G_TYPE_INVALID);
1100
1101   abbrs = gst_structure_get_abbrs (&n_abbrs);
1102
1103   for (i = 0; i < n_abbrs; i++) {
1104     if (strcmp (type_name, abbrs[i].type_name) == 0) {
1105       return abbrs[i].type;
1106     }
1107   }
1108
1109   /* this is the fallback */
1110   return g_type_from_name (type_name);
1111 }
1112
1113 static const char *
1114 gst_structure_to_abbr (GType type)
1115 {
1116   int i;
1117   GstStructureAbbreviation *abbrs;
1118   gint n_abbrs;
1119
1120   g_return_val_if_fail (type != G_TYPE_INVALID, NULL);
1121
1122   abbrs = gst_structure_get_abbrs (&n_abbrs);
1123
1124   for (i = 0; i < n_abbrs; i++) {
1125     if (type == abbrs[i].type) {
1126       return abbrs[i].type_name;
1127     }
1128   }
1129
1130   return g_type_name (type);
1131 }
1132
1133 static GType
1134 gst_structure_value_get_generic_type (GValue * val)
1135 {
1136   if (G_VALUE_TYPE (val) == GST_TYPE_LIST
1137       || G_VALUE_TYPE (val) == GST_TYPE_FIXED_LIST) {
1138     GArray *array = g_value_peek_pointer (val);
1139
1140     if (array->len > 0) {
1141       GValue *value = &g_array_index (array, GValue, 0);
1142
1143       return gst_structure_value_get_generic_type (value);
1144     } else {
1145       return G_TYPE_INT;
1146     }
1147   } else if (G_VALUE_TYPE (val) == GST_TYPE_INT_RANGE) {
1148     return G_TYPE_INT;
1149   } else if (G_VALUE_TYPE (val) == GST_TYPE_DOUBLE_RANGE) {
1150     return G_TYPE_DOUBLE;
1151   }
1152   return G_VALUE_TYPE (val);
1153 }
1154
1155 #define GST_ASCII_IS_STRING(c) (g_ascii_isalnum((c)) || ((c) == '_') || \
1156       ((c) == '-') || ((c) == '+') || ((c) == '/') || ((c) == ':') || \
1157       ((c) == '.'))
1158
1159 /**
1160  * gst_structure_to_string:
1161  * @structure: a #GstStructure
1162  *
1163  * Converts @structure to a human-readable representation.
1164  * 
1165  * Returns: a pointer to string allocated by g_malloc()
1166  */
1167 gchar *
1168 gst_structure_to_string (const GstStructure * structure)
1169 {
1170   GstStructureField *field;
1171   GString *s;
1172   int i;
1173
1174   /* NOTE:  This function is potentially called by the debug system,
1175    * so any calls to gst_log() (and GST_DEBUG(), GST_LOG(), etc.)
1176    * should be careful to avoid recursion.  This includes any functions
1177    * called by gst_structure_to_string.  In particular, calls should
1178    * not use the GST_PTR_FORMAT extension.  */
1179
1180   g_return_val_if_fail (structure != NULL, NULL);
1181
1182   s = g_string_new ("");
1183   /* FIXME this string may need to be escaped */
1184   g_string_append_printf (s, "%s", g_quark_to_string (structure->name));
1185   for (i = 0; i < structure->fields->len; i++) {
1186     char *t;
1187     GType type;
1188
1189     field = GST_STRUCTURE_FIELD (structure, i);
1190
1191     t = gst_value_serialize (&field->value);
1192     type = gst_structure_value_get_generic_type (&field->value);
1193
1194     g_string_append_printf (s, ", %s=(%s)%s", g_quark_to_string (field->name),
1195         gst_structure_to_abbr (type), t);
1196     g_free (t);
1197   }
1198   return g_string_free (s, FALSE);
1199 }
1200
1201 /*
1202  * r will still point to the string. if end == next, the string will not be 
1203  * null-terminated. In all other cases it will be.
1204  * end = pointer to char behind end of string, next = pointer to start of
1205  * unread data.
1206  * THIS FUNCTION MODIFIES THE STRING AND DETECTS INSIDE A NONTERMINATED STRING 
1207  */
1208 static gboolean
1209 gst_structure_parse_string (gchar * s, gchar ** end, gchar ** next)
1210 {
1211   gchar *w;
1212
1213   if (*s == 0)
1214     return FALSE;
1215
1216   if (*s != '"') {
1217     int ret;
1218
1219     ret = gst_structure_parse_simple_string (s, end);
1220     *next = *end;
1221
1222     return ret;
1223   }
1224
1225   w = s;
1226   s++;
1227   while (*s != '"') {
1228     if (*s == 0)
1229       return FALSE;
1230
1231     if (*s == '\\') {
1232       s++;
1233     }
1234
1235     *w = *s;
1236     w++;
1237     s++;
1238   }
1239   s++;
1240
1241   *end = w;
1242   *next = s;
1243
1244   return TRUE;
1245 }
1246
1247 static gboolean
1248 gst_structure_parse_range (gchar * s, gchar ** after, GValue * value,
1249     GType type)
1250 {
1251   GValue value1 = { 0 };
1252   GValue value2 = { 0 };
1253   GType range_type;
1254   gboolean ret;
1255
1256
1257   if (*s != '[')
1258     return FALSE;
1259   s++;
1260
1261   ret = gst_structure_parse_value (s, &s, &value1, type);
1262   if (ret == FALSE)
1263     return FALSE;
1264
1265   while (g_ascii_isspace (*s))
1266     s++;
1267
1268   if (*s != ',')
1269     return FALSE;
1270   s++;
1271
1272   while (g_ascii_isspace (*s))
1273     s++;
1274
1275   ret = gst_structure_parse_value (s, &s, &value2, type);
1276   if (ret == FALSE)
1277     return FALSE;
1278
1279   while (g_ascii_isspace (*s))
1280     s++;
1281
1282   if (*s != ']')
1283     return FALSE;
1284   s++;
1285
1286   if (G_VALUE_TYPE (&value1) != G_VALUE_TYPE (&value2))
1287     return FALSE;
1288
1289   if (G_VALUE_TYPE (&value1) == G_TYPE_DOUBLE) {
1290     range_type = GST_TYPE_DOUBLE_RANGE;
1291   } else if (G_VALUE_TYPE (&value1) == G_TYPE_INT) {
1292     range_type = GST_TYPE_INT_RANGE;
1293   } else {
1294     return FALSE;
1295   }
1296
1297   g_value_init (value, range_type);
1298   if (range_type == GST_TYPE_DOUBLE_RANGE) {
1299     gst_value_set_double_range (value, g_value_get_double (&value1),
1300         g_value_get_double (&value2));
1301   } else {
1302     gst_value_set_int_range (value, g_value_get_int (&value1),
1303         g_value_get_int (&value2));
1304   }
1305
1306   *after = s;
1307   return TRUE;
1308 }
1309
1310 static gboolean
1311 gst_structure_parse_any_list (gchar * s, gchar ** after, GValue * value,
1312     GType type, GType list_type, char begin, char end)
1313 {
1314   GValue list_value = { 0 };
1315   gboolean ret;
1316   GArray *array;
1317
1318   g_value_init (value, list_type);
1319   array = g_value_peek_pointer (value);
1320
1321   if (*s != begin)
1322     return FALSE;
1323   s++;
1324
1325   while (g_ascii_isspace (*s))
1326     s++;
1327   if (*s == end) {
1328     s++;
1329     *after = s;
1330     return TRUE;
1331   }
1332
1333   ret = gst_structure_parse_value (s, &s, &list_value, type);
1334   if (ret == FALSE)
1335     return FALSE;
1336
1337   g_array_append_val (array, list_value);
1338
1339   while (g_ascii_isspace (*s))
1340     s++;
1341
1342   while (*s != end) {
1343     if (*s != ',')
1344       return FALSE;
1345     s++;
1346
1347     while (g_ascii_isspace (*s))
1348       s++;
1349
1350     memset (&list_value, 0, sizeof (list_value));
1351     ret = gst_structure_parse_value (s, &s, &list_value, type);
1352     if (ret == FALSE)
1353       return FALSE;
1354
1355     g_array_append_val (array, list_value);
1356     while (g_ascii_isspace (*s))
1357       s++;
1358   }
1359
1360   s++;
1361
1362   *after = s;
1363   return TRUE;
1364 }
1365
1366 static gboolean
1367 gst_structure_parse_list (gchar * s, gchar ** after, GValue * value, GType type)
1368 {
1369   return gst_structure_parse_any_list (s, after, value, type, GST_TYPE_LIST,
1370       '{', '}');
1371 }
1372
1373 static gboolean
1374 gst_structure_parse_fixed_list (gchar * s, gchar ** after, GValue * value,
1375     GType type)
1376 {
1377   return gst_structure_parse_any_list (s, after, value, type,
1378       GST_TYPE_FIXED_LIST, '<', '>');
1379 }
1380
1381 static gboolean
1382 gst_structure_parse_simple_string (gchar * str, gchar ** end)
1383 {
1384   char *s = str;
1385
1386   while (GST_ASCII_IS_STRING (*s)) {
1387     s++;
1388   }
1389
1390   *end = s;
1391
1392   return (s != str);
1393 }
1394
1395 static gboolean
1396 gst_structure_parse_field (gchar * str,
1397     gchar ** after, GstStructureField * field)
1398 {
1399   gchar *name;
1400   gchar *name_end;
1401   gchar *s;
1402   gchar c;
1403
1404   s = str;
1405
1406   while (g_ascii_isspace (*s))
1407     s++;
1408   name = s;
1409   if (!gst_structure_parse_simple_string (s, &name_end))
1410     return FALSE;
1411
1412   s = name_end;
1413   while (g_ascii_isspace (*s))
1414     s++;
1415
1416   if (*s != '=')
1417     return FALSE;
1418   s++;
1419
1420   c = *name_end;
1421   *name_end = 0;
1422   field->name = g_quark_from_string (name);
1423   *name_end = c;
1424
1425   if (!gst_structure_parse_value (s, &s, &field->value, G_TYPE_INVALID))
1426     return FALSE;
1427
1428   *after = s;
1429   return TRUE;
1430 }
1431
1432 static gboolean
1433 gst_structure_parse_value (gchar * str,
1434     gchar ** after, GValue * value, GType default_type)
1435 {
1436   gchar *type_name;
1437   gchar *type_end;
1438   gchar *value_s;
1439   gchar *value_end;
1440   gchar *s;
1441   gchar c;
1442   int ret = 0;
1443   GType type = default_type;
1444
1445
1446   s = str;
1447   while (g_ascii_isspace (*s))
1448     s++;
1449
1450   type_name = NULL;
1451   if (*s == '(') {
1452     type = G_TYPE_INVALID;
1453
1454     s++;
1455     while (g_ascii_isspace (*s))
1456       s++;
1457     type_name = s;
1458     if (!gst_structure_parse_simple_string (s, &type_end))
1459       return FALSE;
1460     s = type_end;
1461     while (g_ascii_isspace (*s))
1462       s++;
1463     if (*s != ')')
1464       return FALSE;
1465     s++;
1466     while (g_ascii_isspace (*s))
1467       s++;
1468
1469     c = *type_end;
1470     *type_end = 0;
1471     type = gst_structure_from_abbr (type_name);
1472     *type_end = c;
1473
1474     if (type == G_TYPE_INVALID)
1475       return FALSE;
1476   }
1477
1478   while (g_ascii_isspace (*s))
1479     s++;
1480   if (*s == '[') {
1481     ret = gst_structure_parse_range (s, &s, value, type);
1482   } else if (*s == '{') {
1483     ret = gst_structure_parse_list (s, &s, value, type);
1484   } else if (*s == '<') {
1485     ret = gst_structure_parse_fixed_list (s, &s, value, type);
1486   } else {
1487     value_s = s;
1488     if (!gst_structure_parse_string (s, &value_end, &s))
1489       return FALSE;
1490
1491     c = *value_end;
1492     *value_end = 0;
1493     if (type == G_TYPE_INVALID) {
1494       GType try_types[] = { G_TYPE_INT, G_TYPE_DOUBLE, G_TYPE_STRING };
1495       int i;
1496
1497       for (i = 0; i < 3; i++) {
1498         g_value_init (value, try_types[i]);
1499         ret = gst_value_deserialize (value, value_s);
1500         if (ret)
1501           break;
1502         g_value_unset (value);
1503       }
1504     } else {
1505       g_value_init (value, type);
1506
1507       ret = gst_value_deserialize (value, value_s);
1508     }
1509     *value_end = c;
1510   }
1511
1512   *after = s;
1513
1514   return ret;
1515 }
1516
1517 /**
1518  * gst_structure_from_string:
1519  * @string: a string representation of a #GstStructure.
1520  * @end: FIXME, deduce from code
1521  *
1522  * Creates a #GstStructure from a string representation.
1523  * 
1524  * Returns: a new #GstStructure
1525  */
1526 GstStructure *
1527 gst_structure_from_string (const gchar * string, gchar ** end)
1528 {
1529   char *name;
1530   char *copy;
1531   char *w;
1532   char *r;
1533   char save;
1534   GstStructure *structure = NULL;
1535   GstStructureField field = { 0 };
1536
1537   g_return_val_if_fail (string != NULL, NULL);
1538
1539   copy = g_strdup (string);
1540   r = copy;
1541
1542   name = r;
1543   if (!gst_structure_parse_string (r, &w, &r))
1544     goto error;
1545
1546   while (g_ascii_isspace (*r))
1547     r++;
1548   if (*r != 0 && *r != ';' && *r != ',')
1549     goto error;
1550
1551   save = *w;
1552   *w = 0;
1553   structure = gst_structure_empty_new (name);
1554   *w = save;
1555
1556   while (*r && (*r != ';')) {
1557     if (*r != ',')
1558       goto error;
1559     r++;
1560     while (*r && g_ascii_isspace (*r))
1561       r++;
1562
1563     memset (&field, 0, sizeof (field));
1564     if (!gst_structure_parse_field (r, &r, &field))
1565       goto error;
1566     gst_structure_set_field (structure, &field);
1567     while (*r && g_ascii_isspace (*r))
1568       r++;
1569   }
1570
1571   if (end)
1572     *end = (char *) string + (r - copy);
1573
1574   g_free (copy);
1575   return structure;
1576
1577 error:
1578   if (structure)
1579     gst_structure_free (structure);
1580   g_free (copy);
1581   return NULL;
1582 }
1583
1584 static void
1585 gst_structure_transform_to_string (const GValue * src_value,
1586     GValue * dest_value)
1587 {
1588   g_return_if_fail (src_value != NULL);
1589   g_return_if_fail (dest_value != NULL);
1590
1591   dest_value->data[0].v_pointer =
1592       gst_structure_to_string (src_value->data[0].v_pointer);
1593 }
1594
1595 static GstStructure *
1596 gst_structure_copy_conditional (const GstStructure * structure)
1597 {
1598   if (structure)
1599     return gst_structure_copy (structure);
1600   return NULL;
1601 }
1602
1603 /* fixate utility functions */
1604
1605 /**
1606  * gst_caps_structure_fixate_field_nearest_int:
1607  * @structure: a #GstStructure
1608  * @field_name: a field in @structure
1609  * @target: the target value of the fixation
1610  *
1611  * Fixates a #GstStructure by changing the given field to the nearest
1612  * integer to @target that is a subset of the existing field.
1613  *
1614  * Returns: TRUE if the structure could be fixated
1615  */
1616 gboolean
1617 gst_caps_structure_fixate_field_nearest_int (GstStructure * structure,
1618     const char *field_name, int target)
1619 {
1620   const GValue *value;
1621
1622   g_return_val_if_fail (gst_structure_has_field (structure, field_name), FALSE);
1623   g_return_val_if_fail (IS_MUTABLE (structure), FALSE);
1624
1625   value = gst_structure_get_value (structure, field_name);
1626
1627   if (G_VALUE_TYPE (value) == G_TYPE_INT) {
1628     /* already fixed */
1629     return FALSE;
1630   } else if (G_VALUE_TYPE (value) == GST_TYPE_INT_RANGE) {
1631     int x;
1632
1633     x = gst_value_get_int_range_min (value);
1634     if (target < x)
1635       target = x;
1636     x = gst_value_get_int_range_max (value);
1637     if (target > x)
1638       target = x;
1639     gst_structure_set (structure, field_name, G_TYPE_INT, target, NULL);
1640     return TRUE;
1641   } else if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
1642     const GValue *list_value;
1643     int i, n;
1644     int best = 0;
1645     int best_index = -1;
1646
1647     n = gst_value_list_get_size (value);
1648     for (i = 0; i < n; i++) {
1649       list_value = gst_value_list_get_value (value, i);
1650       if (G_VALUE_TYPE (list_value) == G_TYPE_INT) {
1651         int x = g_value_get_int (list_value);
1652
1653         if (best_index == -1 || (ABS (target - x) < ABS (target - best))) {
1654           best_index = i;
1655           best = x;
1656         }
1657       }
1658     }
1659     if (best_index != -1) {
1660       gst_structure_set (structure, field_name, G_TYPE_INT, best, NULL);
1661       return TRUE;
1662     }
1663     return FALSE;
1664   }
1665
1666   return FALSE;
1667 }
1668
1669 /**
1670  * gst_caps_structure_fixate_field_nearest_double:
1671  * @structure: a #GstStructure
1672  * @field_name: a field in @structure
1673  * @target: the target value of the fixation
1674  *
1675  * Fixates a #GstStructure by changing the given field to the nearest
1676  * double to @target that is a subset of the existing field.
1677  *
1678  * Returns: TRUE if the structure could be fixated
1679  */
1680 gboolean
1681 gst_caps_structure_fixate_field_nearest_double (GstStructure * structure,
1682     const char *field_name, double target)
1683 {
1684   const GValue *value;
1685
1686   g_return_val_if_fail (gst_structure_has_field (structure, field_name), FALSE);
1687   g_return_val_if_fail (IS_MUTABLE (structure), FALSE);
1688
1689   value = gst_structure_get_value (structure, field_name);
1690
1691   if (G_VALUE_TYPE (value) == G_TYPE_DOUBLE) {
1692     /* already fixed */
1693     return FALSE;
1694   } else if (G_VALUE_TYPE (value) == GST_TYPE_DOUBLE_RANGE) {
1695     double x;
1696
1697     x = gst_value_get_double_range_min (value);
1698     if (target < x)
1699       target = x;
1700     x = gst_value_get_double_range_max (value);
1701     if (target > x)
1702       target = x;
1703     gst_structure_set (structure, field_name, G_TYPE_DOUBLE, target, NULL);
1704     return TRUE;
1705   } else if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
1706     const GValue *list_value;
1707     int i, n;
1708     double best = 0;
1709     int best_index = -1;
1710
1711     n = gst_value_list_get_size (value);
1712     for (i = 0; i < n; i++) {
1713       list_value = gst_value_list_get_value (value, i);
1714       if (G_VALUE_TYPE (list_value) == G_TYPE_DOUBLE) {
1715         double x = g_value_get_double (list_value);
1716
1717         if (best_index == -1 || (ABS (target - x) < ABS (target - best))) {
1718           best_index = i;
1719           best = x;
1720         }
1721       }
1722     }
1723     if (best_index != -1) {
1724       gst_structure_set (structure, field_name, G_TYPE_DOUBLE, best, NULL);
1725       return TRUE;
1726     }
1727     return FALSE;
1728   }
1729
1730   return FALSE;
1731
1732 }