gstpad: Fix non-serialized sticky event push
[platform/upstream/gstreamer.git] / subprojects / gstreamer / gst / gstvalue.c
1 /* GStreamer
2  * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /**
21  * SECTION:gstvalue
22  * @title: GstValue
23  * @short_description: GValue implementations specific
24  * to GStreamer
25  *
26  * GValue implementations specific to GStreamer.
27  *
28  * Note that operations on the same #GValue from multiple threads may lead to
29  * undefined behaviour.
30  */
31
32 /* Suppress warnings for GValueAraray */
33 #define GLIB_DISABLE_DEPRECATION_WARNINGS
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 #include <math.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <ctype.h>
43
44 #include "gst_private.h"
45 #include "glib-compat-private.h"
46 #include <gst/gst.h>
47 #include <gobject/gvaluecollector.h>
48 #include "gstutils.h"
49 #include "gstquark.h"
50
51 /* GstValueUnionFunc:
52  * @dest: a #GValue for the result
53  * @value1: a #GValue operand
54  * @value2: a #GValue operand
55  *
56  * Used by gst_value_union() to perform unification for a specific #GValue
57  * type. Register a new implementation with gst_value_register_union_func().
58  *
59  * Returns: %TRUE if a union was successful
60  */
61 typedef gboolean (*GstValueUnionFunc) (GValue * dest,
62     const GValue * value1, const GValue * value2);
63
64 /* GstValueIntersectFunc:
65  * @dest: (out caller-allocates): a #GValue for the result
66  * @value1: a #GValue operand
67  * @value2: a #GValue operand
68  *
69  * Used by gst_value_intersect() to perform intersection for a specific #GValue
70  * type. If the intersection is non-empty, the result is
71  * placed in @dest and %TRUE is returned.  If the intersection is
72  * empty, @dest is unmodified and %FALSE is returned.
73  * Register a new implementation with gst_value_register_intersect_func().
74  *
75  * Returns: %TRUE if the values can intersect
76  */
77 typedef gboolean (*GstValueIntersectFunc) (GValue * dest,
78     const GValue * value1, const GValue * value2);
79
80 /* GstValueSubtractFunc:
81  * @dest: (out caller-allocates): a #GValue for the result
82  * @minuend: a #GValue operand
83  * @subtrahend: a #GValue operand
84  *
85  * Used by gst_value_subtract() to perform subtraction for a specific #GValue
86  * type. Register a new implementation with gst_value_register_subtract_func().
87  *
88  * Returns: %TRUE if the subtraction is not empty
89  */
90 typedef gboolean (*GstValueSubtractFunc) (GValue * dest,
91     const GValue * minuend, const GValue * subtrahend);
92
93 static void gst_value_register_union_func (GType type1,
94     GType type2, GstValueUnionFunc func);
95 static void gst_value_register_intersect_func (GType type1,
96     GType type2, GstValueIntersectFunc func);
97 static void gst_value_register_subtract_func (GType minuend_type,
98     GType subtrahend_type, GstValueSubtractFunc func);
99
100 static gboolean _priv_gst_value_parse_list (gchar * s, gchar ** after,
101     GValue * value, GType type, GParamSpec * pspec);
102 static gboolean _priv_gst_value_parse_array (gchar * s, gchar ** after,
103     GValue * value, GType type, GParamSpec * pspec);
104
105 typedef struct _GstValueUnionInfo GstValueUnionInfo;
106 struct _GstValueUnionInfo
107 {
108   GType type1;
109   GType type2;
110   GstValueUnionFunc func;
111 };
112
113 typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
114 struct _GstValueIntersectInfo
115 {
116   GType type1;
117   GType type2;
118   GstValueIntersectFunc func;
119 };
120
121 typedef struct _GstValueSubtractInfo GstValueSubtractInfo;
122 struct _GstValueSubtractInfo
123 {
124   GType minuend;
125   GType subtrahend;
126   GstValueSubtractFunc func;
127 };
128
129 struct _GstFlagSetClass
130 {
131   GTypeClass parent;
132   GType flags_type;             /* Type of the GFlags this flagset carries (can be 0) */
133 };
134
135 typedef struct _GstFlagSetClass GstFlagSetClass;
136
137 typedef struct _GstValueAbbreviation GstValueAbbreviation;
138
139 struct _GstValueAbbreviation
140 {
141   const gchar *type_name;
142   GType type;
143 };
144
145 /* Actual internal implementation of "GstValueList" and
146  * "GstValueArray" */
147 typedef struct _GstValueList GstValueList;
148
149 struct _GstValueList
150 {
151   /* These 2 fields must remain the same so that they match the public
152    * GArray structure (which was the former implementation) just in
153    * case someone calls `gst_value_peek_pointer` to access the
154    * array/list (such as in gststructure.c) */
155   GValue *fields;
156   guint len;
157
158   guint allocated;
159   GValue arr[1];
160 };
161
162 #define FUNDAMENTAL_TYPE_ID_MAX \
163     (G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT)
164 #define FUNDAMENTAL_TYPE_ID(type) \
165     ((type) >> G_TYPE_FUNDAMENTAL_SHIFT)
166
167 #define VALUE_LIST_ARRAY(v) ((GstValueList *) (v)->data[0].v_pointer)
168 #define VALUE_LIST_SIZE(v) (VALUE_LIST_ARRAY(v)->len)
169 #define VALUE_LIST_GET_VALUE(v, index) ((const GValue *) &(VALUE_LIST_ARRAY(v)->fields[index]))
170 #define VALUE_LIST_IS_USING_DYNAMIC_ARRAY(array) ((array)->fields != &(array)->arr[0])
171
172 static GArray *gst_value_table;
173 static GHashTable *gst_value_hash;
174 static GstValueTable *gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID_MAX + 1];
175 static GArray *gst_value_union_funcs;
176 static GArray *gst_value_intersect_funcs;
177 static GArray *gst_value_subtract_funcs;
178
179 /* Forward declarations */
180 static gchar *gst_value_serialize_fraction (const GValue * value);
181 static gint gst_value_compare_fraction (const GValue * value1,
182     const GValue * value2);
183
184 static GstValueCompareFunc gst_value_get_compare_func (const GValue * value1);
185
186 static gchar *gst_string_wrap (const gchar * s);
187 static gchar *gst_string_unwrap (const gchar * s);
188
189 static void gst_value_move (GValue * dest, GValue * src);
190 static void _gst_value_list_append_and_take_value (GValue * value,
191     GValue * append_value);
192 static void _gst_value_array_append_and_take_value (GValue * value,
193     GValue * append_value);
194
195 static inline GstValueTable *
196 gst_value_hash_lookup_type (GType type)
197 {
198   if (G_LIKELY (G_TYPE_IS_FUNDAMENTAL (type)))
199     return gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)];
200   else
201     return g_hash_table_lookup (gst_value_hash, (gpointer) type);
202 }
203
204 static void
205 gst_value_hash_add_type (GType type, const GstValueTable * table)
206 {
207   if (G_TYPE_IS_FUNDAMENTAL (type))
208     gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)] = (gpointer) table;
209
210   g_hash_table_insert (gst_value_hash, (gpointer) type, (gpointer) table);
211 }
212
213 /********
214  * list *
215  ********/
216
217 static void
218 resize_value_list (GstValueList * vlist)
219 {
220   guint want_alloc;
221
222   if (G_UNLIKELY (vlist->allocated > (G_MAXUINT / 2)))
223     g_error ("Growing GstValueList would result in overflow");
224
225   want_alloc = MAX (GST_ROUND_UP_8 (vlist->len + 1), vlist->allocated * 2);
226
227   if (VALUE_LIST_IS_USING_DYNAMIC_ARRAY (vlist)) {
228     vlist->fields = g_renew (GValue, vlist->fields, want_alloc);
229   } else {
230     vlist->fields = g_new0 (GValue, want_alloc);
231     memcpy (vlist->fields, &vlist->arr[0], vlist->len * sizeof (GValue));
232     GST_CAT_LOG (GST_CAT_PERFORMANCE, "Exceeding pre-allocated array");
233   }
234   vlist->allocated = want_alloc;
235 }
236
237 /* Replacement for g_array_append_val */
238 static void
239 _gst_value_list_append_val (GstValueList * vlist, GValue * val)
240 {
241   /* resize if needed */
242   if (G_UNLIKELY (vlist->len == vlist->allocated))
243     resize_value_list (vlist);
244
245   /* Finally set value */
246   vlist->fields[vlist->len++] = *val;
247 }
248
249 /* Replacement for g_array_prepend_val */
250 static void
251 _gst_value_list_prepend_val (GstValueList * vlist, GValue * val)
252 {
253   /* resize if needed */
254   if (G_UNLIKELY (vlist->len == vlist->allocated))
255     resize_value_list (vlist);
256
257   /* Shift everything */
258   memmove (&vlist->fields[1], &vlist->fields[0],
259       (vlist->len) * sizeof (GValue));
260
261   vlist->fields[0] = *val;
262   vlist->len++;
263 }
264
265 static GstValueList *
266 _gst_value_list_new (guint prealloc)
267 {
268   guint n_alloc;
269   GstValueList *res;
270
271   if (prealloc == 0)
272     prealloc = 1;
273
274   n_alloc = GST_ROUND_UP_8 (prealloc);
275   res = g_malloc0 (sizeof (GstValueList) + (n_alloc - 1) * sizeof (GValue));
276
277   res->len = 0;
278   res->allocated = n_alloc;
279   res->fields = &res->arr[0];
280
281   return res;
282 }
283
284 static void
285 _gst_value_list_init (GValue * value, guint prealloc)
286 {
287   value->g_type = GST_TYPE_LIST;
288   memset (value->data, 0, sizeof (value->data));
289   value->data[0].v_pointer = _gst_value_list_new (prealloc);
290 }
291
292 /**
293  * gst_value_list_init:
294  * @value: A zero-filled (uninitialized) #GValue structure
295  * @prealloc: The number of entries to pre-allocate in the list
296  *
297  * Initializes and pre-allocates a #GValue of type #GST_TYPE_LIST.
298  *
299  * Returns: (transfer none): The #GValue structure that has been passed in
300  *
301  * Since: 1.18
302  */
303
304 GValue *
305 gst_value_list_init (GValue * value, guint prealloc)
306 {
307   g_return_val_if_fail (value != NULL, NULL);
308   g_return_val_if_fail (G_VALUE_TYPE (value) == 0, NULL);
309
310   _gst_value_list_init (value, prealloc);
311
312   return value;
313 }
314
315 static void
316 _gst_value_array_init (GValue * value, guint prealloc)
317 {
318   value->g_type = GST_TYPE_ARRAY;
319   memset (value->data, 0, sizeof (value->data));
320   value->data[0].v_pointer = _gst_value_list_new (prealloc);
321 }
322
323 /**
324  * gst_value_array_init:
325  * @value: A zero-filled (uninitialized) #GValue structure
326  * @prealloc: The number of entries to pre-allocate in the array
327  *
328  * Initializes and pre-allocates a #GValue of type #GST_TYPE_ARRAY.
329  *
330  * Returns: (transfer none): The #GValue structure that has been passed in
331  *
332  * Since: 1.18
333  */
334
335 GValue *
336 gst_value_array_init (GValue * value, guint prealloc)
337 {
338   g_return_val_if_fail (value != NULL, NULL);
339   g_return_val_if_fail (G_VALUE_TYPE (value) == 0, NULL);
340
341   _gst_value_array_init (value, prealloc);
342
343   return value;
344 }
345
346 /* two helper functions to serialize/stringify any type of list
347  * regular lists are done with { }, arrays with < >
348  */
349 gchar *
350 _priv_gst_value_serialize_any_list (const GValue * value, const gchar * begin,
351     const gchar * end, gboolean print_type, GstSerializeFlags flags)
352 {
353   guint i;
354   GstValueList *vlist = value->data[0].v_pointer;
355   GString *s;
356   GValue *v;
357   gchar *s_val;
358   guint alen = vlist->len;
359
360   /* estimate minimum string length to minimise re-allocs in GString */
361   s = g_string_sized_new (2 + (6 * alen) + 2);
362   g_string_append (s, begin);
363   for (i = 0; i < alen; i++) {
364     gboolean nested_structs_brackets;
365     v = &vlist->fields[i];
366     nested_structs_brackets = !(flags & GST_SERIALIZE_FLAG_BACKWARD_COMPAT)
367         && (GST_VALUE_HOLDS_STRUCTURE (v) || GST_VALUE_HOLDS_CAPS (v));
368     if (!nested_structs_brackets) {
369       s_val = gst_value_serialize (v);
370     } else {
371       if (GST_VALUE_HOLDS_STRUCTURE (v))
372         s_val = gst_structure_serialize (gst_value_get_structure (v), flags);
373       else if (GST_VALUE_HOLDS_CAPS (v))
374         s_val = gst_caps_serialize (gst_value_get_caps (v), flags);
375     }
376     if (s_val != NULL) {
377       if (print_type) {
378         g_string_append_c (s, '(');
379         g_string_append (s, _priv_gst_value_gtype_to_abbr (G_VALUE_TYPE (v)));
380         g_string_append_c (s, ')');
381       }
382
383       if (nested_structs_brackets)
384         g_string_append_c (s, '[');
385       g_string_append (s, s_val);
386       if (nested_structs_brackets)
387         g_string_append_c (s, ']');
388       g_free (s_val);
389       if (i < alen - 1) {
390         g_string_append_len (s, ", ", 2);
391       }
392     } else {
393       g_critical ("Could not serialize list/array value of type '%s'",
394           G_VALUE_TYPE_NAME (v));
395     }
396   }
397   g_string_append (s, end);
398   return g_string_free (s, FALSE);
399 }
400
401 static void
402 gst_value_transform_any_list_string (const GValue * src_value,
403     GValue * dest_value, const gchar * begin, const gchar * end)
404 {
405   GValue *list_value;
406   GstValueList *array;
407   GString *s;
408   guint i;
409   gchar *list_s;
410   guint alen;
411
412   array = src_value->data[0].v_pointer;
413   alen = array->len;
414
415   /* estimate minimum string length to minimise re-allocs in GString */
416   s = g_string_sized_new (2 + (10 * alen) + 2);
417   g_string_append (s, begin);
418   for (i = 0; i < alen; i++) {
419     list_value = &array->fields[i];
420
421     if (i != 0) {
422       g_string_append_len (s, ", ", 2);
423     }
424     list_s = g_strdup_value_contents (list_value);
425     g_string_append (s, list_s);
426     g_free (list_s);
427   }
428   g_string_append (s, end);
429
430   dest_value->data[0].v_pointer = g_string_free (s, FALSE);
431 }
432
433 static gchar *
434 _gst_value_serialize_g_value_array (const GValue * value, const gchar * begin,
435     const gchar * end)
436 {
437   guint i;
438   GValueArray *array = value->data[0].v_pointer;
439   GString *s;
440   GValue *v;
441   gchar *s_val;
442   guint alen = 0;
443
444   if (array)
445     alen = array->n_values;
446
447   /* estimate minimum string length to minimise re-allocs in GString */
448   s = g_string_sized_new (2 + (6 * alen) + 2);
449   g_string_append (s, begin);
450   for (i = 0; i < alen; i++) {
451     v = g_value_array_get_nth (array, i);
452     s_val = gst_value_serialize (v);
453     if (s_val != NULL) {
454       g_string_append (s, s_val);
455       g_free (s_val);
456       if (i < alen - 1) {
457         g_string_append_len (s, ", ", 2);
458       }
459     } else {
460       g_critical ("Could not serialize list/array value of type '%s'",
461           G_VALUE_TYPE_NAME (v));
462     }
463   }
464   g_string_append (s, end);
465   return g_string_free (s, FALSE);
466 }
467
468 static void
469 _gst_value_transform_g_value_array_string (const GValue * src_value,
470     GValue * dest_value, const gchar * begin, const gchar * end)
471 {
472   GValue *list_value;
473   GValueArray *array;
474   GString *s;
475   guint i;
476   gchar *list_s;
477   guint alen;
478
479   array = src_value->data[0].v_pointer;
480   alen = array->n_values;
481
482   /* estimate minimum string length to minimise re-allocs in GString */
483   s = g_string_sized_new (2 + (10 * alen) + 2);
484   g_string_append (s, begin);
485   for (i = 0; i < alen; i++) {
486     list_value = g_value_array_get_nth (array, i);
487
488     if (i != 0) {
489       g_string_append_len (s, ", ", 2);
490     }
491     list_s = g_strdup_value_contents (list_value);
492     g_string_append (s, list_s);
493     g_free (list_s);
494   }
495   g_string_append (s, end);
496
497   dest_value->data[0].v_pointer = g_string_free (s, FALSE);
498 }
499
500 /*
501  * helper function to see if a type is fixed. Is used internally here and
502  * there. Do not export, since it doesn't work for types where the content
503  * decides the fixedness (e.g. GST_TYPE_ARRAY).
504  */
505 static gboolean
506 gst_type_is_fixed (GType type)
507 {
508   /* the basic int, string, double types */
509   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
510     return TRUE;
511   }
512   /* our fundamental types that are certainly not fixed */
513   if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE ||
514       type == GST_TYPE_INT64_RANGE ||
515       type == GST_TYPE_LIST || type == GST_TYPE_FRACTION_RANGE ||
516       type == GST_TYPE_STRUCTURE) {
517     return FALSE;
518   }
519   /* other (boxed) types that are fixed */
520   if (type == GST_TYPE_BUFFER) {
521     return TRUE;
522   }
523   /* heavy checks */
524   if (G_TYPE_IS_FUNDAMENTAL (type) || G_TYPE_FUNDAMENTAL (type) <=
525       G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
526     return TRUE;
527   }
528
529   return FALSE;
530 }
531
532 /* GValue functions usable for both regular lists and arrays */
533 static void
534 gst_value_init_list_or_array (GValue * value)
535 {
536   value->data[0].v_pointer = _gst_value_list_new (0);
537 }
538
539 static GstValueList *
540 copy_gst_value_list (const GstValueList * src)
541 {
542   GstValueList *dest;
543   guint i, len;
544
545   len = src->len;
546   dest = _gst_value_list_new (len);
547   dest->len = len;
548   for (i = 0; i < len; i++) {
549     gst_value_init_and_copy (&dest->fields[i], &src->fields[i]);
550   }
551
552   return dest;
553 }
554
555 static void
556 gst_value_copy_list_or_array (const GValue * src_value, GValue * dest_value)
557 {
558   dest_value->data[0].v_pointer =
559       copy_gst_value_list (VALUE_LIST_ARRAY (src_value));
560 }
561
562 static void
563 gst_value_free_list_or_array (GValue * value)
564 {
565   guint i, len;
566   GstValueList *src = VALUE_LIST_ARRAY (value);
567   len = src->len;
568
569   if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
570     for (i = 0; i < len; i++) {
571       g_value_unset (&src->fields[i]);
572     }
573     if (VALUE_LIST_IS_USING_DYNAMIC_ARRAY (src)) {
574       g_free (src->fields);
575     }
576     g_free (src);
577   }
578 }
579
580 static gpointer
581 gst_value_list_or_array_peek_pointer (const GValue * value)
582 {
583   return value->data[0].v_pointer;
584 }
585
586 static gchar *
587 gst_value_collect_list_or_array (GValue * value, guint n_collect_values,
588     GTypeCValue * collect_values, guint collect_flags)
589 {
590   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
591     value->data[0].v_pointer = collect_values[0].v_pointer;
592     value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
593   } else {
594     value->data[0].v_pointer =
595         copy_gst_value_list ((GstValueList *) collect_values[0].v_pointer);
596   }
597   return NULL;
598 }
599
600 static gchar *
601 gst_value_lcopy_list_or_array (const GValue * value, guint n_collect_values,
602     GTypeCValue * collect_values, guint collect_flags)
603 {
604   GstValueList **dest = collect_values[0].v_pointer;
605
606   g_return_val_if_fail (dest != NULL,
607       g_strdup_printf ("value location for `%s' passed as NULL",
608           G_VALUE_TYPE_NAME (value)));
609   g_return_val_if_fail (value->data[0].v_pointer != NULL,
610       g_strdup_printf ("invalid value given for `%s'",
611           G_VALUE_TYPE_NAME (value)));
612
613   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
614     *dest = (GstValueList *) value->data[0].v_pointer;
615   } else {
616     *dest = copy_gst_value_list (VALUE_LIST_ARRAY (value));
617   }
618   return NULL;
619 }
620
621 static gboolean
622 gst_value_list_or_array_get_basic_type (const GValue * value, GType * type)
623 {
624   if (G_UNLIKELY (value == NULL))
625     return FALSE;
626
627   if (GST_VALUE_HOLDS_LIST (value) || GST_VALUE_HOLDS_ARRAY (value)) {
628     if (VALUE_LIST_SIZE (value) == 0)
629       return FALSE;
630     return gst_value_list_or_array_get_basic_type (VALUE_LIST_GET_VALUE (value,
631             0), type);
632   }
633
634   *type = G_VALUE_TYPE (value);
635
636   return TRUE;
637 }
638
639 #define IS_RANGE_COMPAT(type1,type2,t1,t2) \
640   (((t1) == (type1) && (t2) == (type2)) || ((t2) == (type1) && (t1) == (type2)))
641
642 static gboolean
643 gst_value_list_or_array_are_compatible (const GValue * value1,
644     const GValue * value2)
645 {
646   GType basic_type1, basic_type2;
647
648   /* empty or same type is OK */
649   if (!gst_value_list_or_array_get_basic_type (value1, &basic_type1) ||
650       !gst_value_list_or_array_get_basic_type (value2, &basic_type2) ||
651       basic_type1 == basic_type2)
652     return TRUE;
653
654   /* ranges are distinct types for each bound type... */
655   if (IS_RANGE_COMPAT (G_TYPE_INT, GST_TYPE_INT_RANGE, basic_type1,
656           basic_type2))
657     return TRUE;
658   if (IS_RANGE_COMPAT (G_TYPE_INT64, GST_TYPE_INT64_RANGE, basic_type1,
659           basic_type2))
660     return TRUE;
661   if (IS_RANGE_COMPAT (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE, basic_type1,
662           basic_type2))
663     return TRUE;
664   if (IS_RANGE_COMPAT (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, basic_type1,
665           basic_type2))
666     return TRUE;
667
668   return FALSE;
669 }
670
671 static inline void
672 _gst_value_list_append_and_take_value (GValue * value, GValue * append_value)
673 {
674   _gst_value_list_append_val (VALUE_LIST_ARRAY (value), append_value);
675   memset (append_value, 0, sizeof (GValue));
676 }
677
678 /**
679  * gst_value_list_append_and_take_value:
680  * @value: a #GValue of type #GST_TYPE_LIST
681  * @append_value: (transfer full): the value to append
682  *
683  * Appends @append_value to the GstValueList in @value.
684  *
685  * Since: 1.2
686  */
687 void
688 gst_value_list_append_and_take_value (GValue * value, GValue * append_value)
689 {
690   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
691   g_return_if_fail (G_IS_VALUE (append_value));
692   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
693           append_value));
694
695   _gst_value_list_append_and_take_value (value, append_value);
696 }
697
698 /**
699  * gst_value_list_append_value:
700  * @value: a #GValue of type #GST_TYPE_LIST
701  * @append_value: (transfer none): the value to append
702  *
703  * Appends @append_value to the GstValueList in @value.
704  */
705 void
706 gst_value_list_append_value (GValue * value, const GValue * append_value)
707 {
708   GValue val = { 0, };
709
710   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
711   g_return_if_fail (G_IS_VALUE (append_value));
712   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
713           append_value));
714
715   gst_value_init_and_copy (&val, append_value);
716   _gst_value_list_append_val (VALUE_LIST_ARRAY (value), &val);
717 }
718
719 /**
720  * gst_value_list_prepend_value:
721  * @value: a #GValue of type #GST_TYPE_LIST
722  * @prepend_value: the value to prepend
723  *
724  * Prepends @prepend_value to the GstValueList in @value.
725  */
726 void
727 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value)
728 {
729   GValue val = { 0, };
730
731   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
732   g_return_if_fail (G_IS_VALUE (prepend_value));
733   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
734           prepend_value));
735
736   gst_value_init_and_copy (&val, prepend_value);
737   _gst_value_list_prepend_val (VALUE_LIST_ARRAY (value), &val);
738 }
739
740 /**
741  * gst_value_list_concat:
742  * @dest: (out caller-allocates): an uninitialized #GValue to take the result
743  * @value1: a #GValue
744  * @value2: a #GValue
745  *
746  * Concatenates copies of @value1 and @value2 into a list.  Values that are not
747  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
748  * @dest will be initialized to the type #GST_TYPE_LIST.
749  */
750 void
751 gst_value_list_concat (GValue * dest, const GValue * value1,
752     const GValue * value2)
753 {
754   guint i, value1_length, value2_length;
755   GstValueList *vlist;
756
757   g_return_if_fail (dest != NULL);
758   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
759   g_return_if_fail (G_IS_VALUE (value1));
760   g_return_if_fail (G_IS_VALUE (value2));
761   g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2));
762
763   value1_length =
764       (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1);
765   value2_length =
766       (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1);
767
768   _gst_value_list_init (dest, value1_length + value2_length);
769   vlist = VALUE_LIST_ARRAY (dest);
770   vlist->len = value1_length + value2_length;
771
772   if (GST_VALUE_HOLDS_LIST (value1)) {
773     for (i = 0; i < value1_length; i++) {
774       gst_value_init_and_copy (&vlist->fields[i],
775           VALUE_LIST_GET_VALUE (value1, i));
776     }
777   } else {
778     gst_value_init_and_copy (&vlist->fields[0], value1);
779   }
780
781   if (GST_VALUE_HOLDS_LIST (value2)) {
782     for (i = 0; i < value2_length; i++) {
783       gst_value_init_and_copy (&vlist->fields[i + value1_length],
784           VALUE_LIST_GET_VALUE (value2, i));
785     }
786   } else {
787     gst_value_init_and_copy (&vlist->fields[value1_length], value2);
788   }
789 }
790
791 /* same as gst_value_list_concat() but takes ownership of GValues */
792 static void
793 gst_value_list_concat_and_take_values (GValue * dest, GValue * val1,
794     GValue * val2)
795 {
796   guint i, val1_length, val2_length;
797   gboolean val1_is_list;
798   gboolean val2_is_list;
799   GstValueList *vlist;
800
801   g_assert (dest != NULL);
802   g_assert (G_VALUE_TYPE (dest) == 0);
803   g_assert (G_IS_VALUE (val1));
804   g_assert (G_IS_VALUE (val2));
805   g_assert (gst_value_list_or_array_are_compatible (val1, val2));
806
807   val1_is_list = GST_VALUE_HOLDS_LIST (val1);
808   val1_length = (val1_is_list ? VALUE_LIST_SIZE (val1) : 1);
809
810   val2_is_list = GST_VALUE_HOLDS_LIST (val2);
811   val2_length = (val2_is_list ? VALUE_LIST_SIZE (val2) : 1);
812
813   /* Overidding the default initialization to have a list of the target size */
814   _gst_value_list_init (dest, val1_length + val2_length);
815   vlist = VALUE_LIST_ARRAY (dest);
816   vlist->len = val1_length + val2_length;
817
818   if (val1_is_list) {
819     for (i = 0; i < val1_length; i++) {
820       vlist->fields[i] = *VALUE_LIST_GET_VALUE (val1, i);
821     }
822     VALUE_LIST_ARRAY (val1)->len = 0;
823     g_value_unset (val1);
824   } else {
825     vlist->fields[0] = *val1;
826     G_VALUE_TYPE (val1) = G_TYPE_INVALID;
827   }
828
829   if (val2_is_list) {
830     for (i = 0; i < val2_length; i++) {
831       const GValue *v2 = VALUE_LIST_GET_VALUE (val2, i);
832       vlist->fields[i + val1_length] = *v2;
833     }
834
835     VALUE_LIST_ARRAY (val2)->len = 0;
836     g_value_unset (val2);
837   } else {
838     vlist->fields[val1_length] = *val2;
839     G_VALUE_TYPE (val2) = G_TYPE_INVALID;
840   }
841 }
842
843 /**
844  * gst_value_list_merge:
845  * @dest: (out caller-allocates): an uninitialized #GValue to take the result
846  * @value1: a #GValue
847  * @value2: a #GValue
848  *
849  * Merges copies of @value1 and @value2.  Values that are not
850  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
851  *
852  * The result will be put into @dest and will either be a list that will not
853  * contain any duplicates, or a non-list type (if @value1 and @value2
854  * were equal).
855  */
856 void
857 gst_value_list_merge (GValue * dest, const GValue * value1,
858     const GValue * value2)
859 {
860   guint i, j, k, value1_length, value2_length, skipped;
861   const GValue *src;
862   gboolean skip;
863   GstValueList *vlist;
864
865   g_return_if_fail (dest != NULL);
866   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
867   g_return_if_fail (G_IS_VALUE (value1));
868   g_return_if_fail (G_IS_VALUE (value2));
869   g_return_if_fail (gst_value_list_or_array_are_compatible (value1, value2));
870
871   value1_length =
872       (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1);
873   value2_length =
874       (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1);
875
876   _gst_value_list_init (dest, value1_length + value2_length);
877   vlist = VALUE_LIST_ARRAY (dest);
878   vlist->len = value1_length + value2_length;
879
880   if (GST_VALUE_HOLDS_LIST (value1)) {
881     for (i = 0; i < value1_length; i++) {
882       gst_value_init_and_copy (&vlist->fields[i], VALUE_LIST_GET_VALUE (value1,
883               i));
884     }
885   } else {
886     gst_value_init_and_copy (&vlist->fields[0], value1);
887   }
888
889   j = value1_length;
890   skipped = 0;
891   if (GST_VALUE_HOLDS_LIST (value2)) {
892     for (i = 0; i < value2_length; i++) {
893       skip = FALSE;
894       src = VALUE_LIST_GET_VALUE (value2, i);
895       for (k = 0; k < value1_length; k++) {
896         if (gst_value_compare (&vlist->fields[k], src) == GST_VALUE_EQUAL) {
897           skip = TRUE;
898           skipped++;
899           break;
900         }
901       }
902       if (!skip) {
903         gst_value_init_and_copy (&vlist->fields[j], src);
904         j++;
905       }
906     }
907   } else {
908     skip = FALSE;
909     for (k = 0; k < value1_length; k++) {
910       if (gst_value_compare (&vlist->fields[k], value2) == GST_VALUE_EQUAL) {
911         skip = TRUE;
912         skipped++;
913         break;
914       }
915     }
916     if (!skip) {
917       gst_value_init_and_copy (&vlist->fields[j], value2);
918     }
919   }
920   if (skipped) {
921     guint new_size = value1_length + (value2_length - skipped);
922
923     if (new_size > 1) {
924       /* shrink list */
925       vlist->len = new_size;
926     } else {
927       GValue single_dest;
928
929       /* size is 1, take single value in list and make it new dest */
930       single_dest = vlist->fields[0];
931
932       /* clean up old value allocations: must set array size to 0, because
933        * allocated values are not inited meaning g_value_unset() will not
934        * work on them */
935       vlist->len = 0;
936       g_value_unset (dest);
937
938       /* the single value is our new result */
939       *dest = single_dest;
940     }
941   }
942 }
943
944 /**
945  * gst_value_list_get_size:
946  * @value: a #GValue of type #GST_TYPE_LIST
947  *
948  * Gets the number of values contained in @value.
949  *
950  * Returns: the number of values
951  */
952 guint
953 gst_value_list_get_size (const GValue * value)
954 {
955   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
956
957   return VALUE_LIST_SIZE (value);
958 }
959
960 /**
961  * gst_value_list_get_value:
962  * @value: a #GValue of type #GST_TYPE_LIST
963  * @index: index of value to get from the list
964  *
965  * Gets the value that is a member of the list contained in @value and
966  * has the index @index.
967  *
968  * Returns: (transfer none): the value at the given index
969  */
970 const GValue *
971 gst_value_list_get_value (const GValue * value, guint index)
972 {
973   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
974   g_return_val_if_fail (index < VALUE_LIST_SIZE (value), NULL);
975
976   return VALUE_LIST_GET_VALUE (value, index);
977 }
978
979 /**
980  * gst_value_array_append_value:
981  * @value: a #GValue of type #GST_TYPE_ARRAY
982  * @append_value: the value to append
983  *
984  * Appends @append_value to the GstValueArray in @value.
985  */
986 void
987 gst_value_array_append_value (GValue * value, const GValue * append_value)
988 {
989   GValue val = { 0, };
990
991   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
992   g_return_if_fail (G_IS_VALUE (append_value));
993   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
994           append_value));
995
996   gst_value_init_and_copy (&val, append_value);
997   _gst_value_list_append_val (VALUE_LIST_ARRAY (value), &val);
998 }
999
1000 static inline void
1001 _gst_value_array_append_and_take_value (GValue * value, GValue * append_value)
1002 {
1003   _gst_value_list_append_val (VALUE_LIST_ARRAY (value), append_value);
1004   memset (append_value, 0, sizeof (GValue));
1005 }
1006
1007 /**
1008  * gst_value_array_append_and_take_value:
1009  * @value: a #GValue of type #GST_TYPE_ARRAY
1010  * @append_value: (transfer full): the value to append
1011  *
1012  * Appends @append_value to the GstValueArray in @value.
1013  *
1014  * Since: 1.2
1015  */
1016 void
1017 gst_value_array_append_and_take_value (GValue * value, GValue * append_value)
1018 {
1019   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
1020   g_return_if_fail (G_IS_VALUE (append_value));
1021   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
1022           append_value));
1023
1024   _gst_value_array_append_and_take_value (value, append_value);
1025 }
1026
1027 /**
1028  * gst_value_array_prepend_value:
1029  * @value: a #GValue of type #GST_TYPE_ARRAY
1030  * @prepend_value: the value to prepend
1031  *
1032  * Prepends @prepend_value to the GstValueArray in @value.
1033  */
1034 void
1035 gst_value_array_prepend_value (GValue * value, const GValue * prepend_value)
1036 {
1037   GValue val = { 0, };
1038
1039   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
1040   g_return_if_fail (G_IS_VALUE (prepend_value));
1041   g_return_if_fail (gst_value_list_or_array_are_compatible (value,
1042           prepend_value));
1043
1044   gst_value_init_and_copy (&val, prepend_value);
1045   _gst_value_list_prepend_val (VALUE_LIST_ARRAY (value), &val);
1046 }
1047
1048 /**
1049  * gst_value_array_get_size:
1050  * @value: a #GValue of type #GST_TYPE_ARRAY
1051  *
1052  * Gets the number of values contained in @value.
1053  *
1054  * Returns: the number of values
1055  */
1056 guint
1057 gst_value_array_get_size (const GValue * value)
1058 {
1059   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), 0);
1060
1061   return VALUE_LIST_SIZE (value);
1062 }
1063
1064 /**
1065  * gst_value_array_get_value:
1066  * @value: a #GValue of type #GST_TYPE_ARRAY
1067  * @index: index of value to get from the array
1068  *
1069  * Gets the value that is a member of the array contained in @value and
1070  * has the index @index.
1071  *
1072  * Returns: (transfer none): the value at the given index
1073  */
1074 const GValue *
1075 gst_value_array_get_value (const GValue * value, guint index)
1076 {
1077   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), NULL);
1078   g_return_val_if_fail (index < VALUE_LIST_SIZE (value), NULL);
1079
1080   return VALUE_LIST_GET_VALUE (value, index);
1081 }
1082
1083 static void
1084 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value)
1085 {
1086   gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }");
1087 }
1088
1089 static void
1090 gst_value_transform_array_string (const GValue * src_value, GValue * dest_value)
1091 {
1092   gst_value_transform_any_list_string (src_value, dest_value, "< ", " >");
1093 }
1094
1095 static void
1096 gst_value_transform_g_value_array_string (const GValue * src_value,
1097     GValue * dest_value)
1098 {
1099   _gst_value_transform_g_value_array_string (src_value, dest_value, "< ", " >");
1100 }
1101
1102 static void
1103 gst_value_transform_g_value_array_any_list (const GValue * src_value,
1104     GValue * dest_value)
1105 {
1106   const GValueArray *varray;
1107   GstValueList *vlist;
1108   gint i;
1109
1110   varray = g_value_get_boxed (src_value);
1111
1112   /* GLib will unset the value, memset to 0 the data instead of doing a proper
1113    * reset. That's why we need to allocate the array here */
1114   vlist = dest_value->data[0].v_pointer =
1115       _gst_value_list_new (varray->n_values);
1116
1117   for (i = 0; i < varray->n_values; i++) {
1118     GValue val = G_VALUE_INIT;
1119     gst_value_init_and_copy (&val, &varray->values[i]);
1120     _gst_value_list_append_val (vlist, &val);
1121   }
1122 }
1123
1124 static void
1125 gst_value_transform_any_list_g_value_array (const GValue * src_value,
1126     GValue * dest_value)
1127 {
1128   GValueArray *varray;
1129   GstValueList *vlist;
1130   gint i;
1131
1132   vlist = VALUE_LIST_ARRAY (src_value);
1133   varray = g_value_array_new (vlist->len);
1134
1135   for (i = 0; i < vlist->len; i++)
1136     g_value_array_append (varray, &vlist->fields[i]);
1137
1138   g_value_take_boxed (dest_value, varray);
1139 }
1140
1141 /* Do an unordered compare of the contents of a list */
1142 static gint
1143 gst_value_compare_value_list (const GValue * value1, const GValue * value2)
1144 {
1145   guint i, j;
1146   GstValueList *vlist1 = VALUE_LIST_ARRAY (value1);
1147   GstValueList *vlist2 = VALUE_LIST_ARRAY (value2);
1148   GValue *v1;
1149   GValue *v2;
1150   gint len, to_remove;
1151   guint8 *removed;
1152   GstValueCompareFunc compare;
1153
1154   /* get length and do initial length check. */
1155   len = vlist1->len;
1156   if (len != vlist2->len)
1157     return GST_VALUE_UNORDERED;
1158
1159   /* Empty lists are equal */
1160   if (len == 0)
1161     return GST_VALUE_EQUAL;
1162
1163   /* We know lists are not empty. do sanity check on first values */
1164   if (G_VALUE_TYPE (&vlist1->fields[0]) != G_VALUE_TYPE (&vlist2->fields[0]))
1165     return GST_VALUE_UNORDERED;
1166
1167   /* Get the compare function */
1168   if (!(compare = gst_value_get_compare_func (&vlist1->fields[0])))
1169     return GST_VALUE_UNORDERED;
1170
1171   /* place to mark removed value indices of array2 */
1172   removed = g_newa (guint8, len);
1173   memset (removed, 0, len);
1174   to_remove = len;
1175
1176   /* loop over array1, all items should be in array2. When we find an
1177    * item in array2, remove it from array2 by marking it as removed */
1178   for (i = 0; i < len; i++) {
1179     v1 = &vlist1->fields[i];
1180
1181     for (j = 0; j < len; j++) {
1182       /* item is removed, we can skip it */
1183       if (removed[j])
1184         continue;
1185       v2 = &vlist2->fields[j];
1186       /* Note: compare function can be called directly since we know the types
1187        * are identical */
1188       if (compare (v1, v2) == GST_VALUE_EQUAL) {
1189         /* mark item as removed now that we found it in array2 and
1190          * decrement the number of remaining items in array2. */
1191         removed[j] = 1;
1192         to_remove--;
1193         break;
1194       }
1195     }
1196     /* item in array1 and not in array2, UNORDERED */
1197     if (j == len)
1198       return GST_VALUE_UNORDERED;
1199   }
1200   /* if not all items were removed, array2 contained something not in array1 */
1201   if (to_remove != 0)
1202     return GST_VALUE_UNORDERED;
1203
1204   /* arrays are equal */
1205   return GST_VALUE_EQUAL;
1206 }
1207
1208 /* Perform an ordered comparison of the contents of an array */
1209 static gint
1210 gst_value_compare_value_array (const GValue * value1, const GValue * value2)
1211 {
1212   guint i;
1213   GstValueList *vlist1 = VALUE_LIST_ARRAY (value1);
1214   GstValueList *vlist2 = VALUE_LIST_ARRAY (value2);
1215   guint len = vlist1->len;
1216   GValue *v1;
1217   GValue *v2;
1218
1219   if (len != vlist2->len)
1220     return GST_VALUE_UNORDERED;
1221
1222   for (i = 0; i < len; i++) {
1223     v1 = &vlist1->fields[i];
1224     v2 = &vlist2->fields[i];
1225     if (gst_value_compare (v1, v2) != GST_VALUE_EQUAL)
1226       return GST_VALUE_UNORDERED;
1227   }
1228
1229   return GST_VALUE_EQUAL;
1230 }
1231
1232 static gint
1233 gst_value_compare_g_value_array (const GValue * value1, const GValue * value2)
1234 {
1235   guint i;
1236   GValueArray *array1 = value1->data[0].v_pointer;
1237   GValueArray *array2 = value2->data[0].v_pointer;
1238   guint len = array1 ? array1->n_values : 0;
1239   GValue *v1;
1240   GValue *v2;
1241
1242   if (len != (array2 ? array2->n_values : 0))
1243     return GST_VALUE_UNORDERED;
1244
1245   for (i = 0; i < len; i++) {
1246     v1 = g_value_array_get_nth (array1, i);
1247     v2 = g_value_array_get_nth (array2, i);
1248     if (gst_value_compare (v1, v2) != GST_VALUE_EQUAL)
1249       return GST_VALUE_UNORDERED;
1250   }
1251
1252   return GST_VALUE_EQUAL;
1253 }
1254
1255 static gchar *
1256 gst_value_serialize_value_list (const GValue * value)
1257 {
1258   return _priv_gst_value_serialize_any_list (value, "{ ", " }", TRUE,
1259       GST_SERIALIZE_FLAG_BACKWARD_COMPAT);
1260 }
1261
1262 static gboolean
1263 gst_value_deserialize_value_list (GValue * dest, const gchar * s,
1264     GParamSpec * pspec)
1265 {
1266   gchar *s2 = (gchar *) s;
1267   return _priv_gst_value_parse_list (s2, &s2, dest, G_TYPE_INVALID, pspec);
1268 }
1269
1270 static gchar *
1271 gst_value_serialize_value_array (const GValue * value)
1272 {
1273   return _priv_gst_value_serialize_any_list (value, "< ", " >", TRUE,
1274       GST_SERIALIZE_FLAG_BACKWARD_COMPAT);
1275 }
1276
1277 static gboolean
1278 gst_value_deserialize_value_array (GValue * dest, const gchar * s,
1279     GParamSpec * pspec)
1280 {
1281   gchar *s2 = (gchar *) s;
1282   return _priv_gst_value_parse_array (s2, &s2, dest, G_TYPE_INVALID, pspec);
1283 }
1284
1285 static gchar *
1286 gst_value_serialize_g_value_array (const GValue * value)
1287 {
1288   return _gst_value_serialize_g_value_array (value, "< ", " >");
1289 }
1290
1291 static gboolean
1292 gst_value_deserialize_g_value_array (GValue * dest, const gchar * s)
1293 {
1294   g_warning ("gst_value_deserialize_g_value_array: unimplemented");
1295   return FALSE;
1296 }
1297
1298 /*************
1299  * int range *
1300  *
1301  * Values in the range are defined as any value greater or equal
1302  * to min*step, AND lesser or equal to max*step.
1303  * For step == 1, this falls back to the traditional range semantics.
1304  *
1305  * data[0] = (min << 32) | (max)
1306  * data[1] = step
1307  *
1308  *************/
1309
1310 #define INT_RANGE_MIN(v) ((gint) (((v)->data[0].v_uint64) >> 32))
1311 #define INT_RANGE_MAX(v) ((gint) (((v)->data[0].v_uint64) & 0xffffffff))
1312 #define INT_RANGE_STEP(v) ((v)->data[1].v_int)
1313
1314 static void
1315 gst_value_init_int_range (GValue * value)
1316 {
1317   G_STATIC_ASSERT (sizeof (gint) <= 2 * sizeof (guint64));
1318
1319   value->data[0].v_uint64 = 0;
1320   value->data[1].v_int = 1;
1321 }
1322
1323 static void
1324 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value)
1325 {
1326   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
1327   dest_value->data[1].v_int = src_value->data[1].v_int;
1328 }
1329
1330 static gchar *
1331 gst_value_collect_int_range (GValue * value, guint n_collect_values,
1332     GTypeCValue * collect_values, guint collect_flags)
1333 {
1334   g_return_val_if_fail (n_collect_values == 2,
1335       g_strdup_printf ("not enough value locations for `%s' passed",
1336           G_VALUE_TYPE_NAME (value)));
1337   g_return_val_if_fail (collect_values[0].v_int < collect_values[1].v_int,
1338       g_strdup_printf ("range start is not smaller than end for `%s'",
1339           G_VALUE_TYPE_NAME (value)));
1340
1341   gst_value_set_int_range_step (value, collect_values[0].v_int,
1342       collect_values[1].v_int, 1);
1343
1344   return NULL;
1345 }
1346
1347 static gchar *
1348 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values,
1349     GTypeCValue * collect_values, guint collect_flags)
1350 {
1351   guint32 *int_range_start = collect_values[0].v_pointer;
1352   guint32 *int_range_end = collect_values[1].v_pointer;
1353
1354   g_return_val_if_fail (int_range_start != NULL,
1355       g_strdup_printf ("start value location for `%s' passed as NULL",
1356           G_VALUE_TYPE_NAME (value)));
1357   g_return_val_if_fail (int_range_end != NULL,
1358       g_strdup_printf ("end value location for `%s' passed as NULL",
1359           G_VALUE_TYPE_NAME (value)));
1360
1361   *int_range_start = INT_RANGE_MIN (value);
1362   *int_range_end = INT_RANGE_MAX (value);
1363
1364   return NULL;
1365 }
1366
1367 /**
1368  * gst_value_set_int_range_step:
1369  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1370  * @start: the start of the range
1371  * @end: the end of the range
1372  * @step: the step of the range
1373  *
1374  * Sets @value to the range specified by @start, @end and @step.
1375  */
1376 void
1377 gst_value_set_int_range_step (GValue * value, gint start, gint end, gint step)
1378 {
1379   guint64 sstart, sstop;
1380
1381   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
1382   g_return_if_fail (start < end);
1383   g_return_if_fail (step > 0);
1384   g_return_if_fail (start % step == 0);
1385   g_return_if_fail (end % step == 0);
1386
1387   sstart = (guint) (start / step);
1388   sstop = (guint) (end / step);
1389   value->data[0].v_uint64 = (sstart << 32) | sstop;
1390   value->data[1].v_int = step;
1391 }
1392
1393 /**
1394  * gst_value_set_int_range:
1395  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1396  * @start: the start of the range
1397  * @end: the end of the range
1398  *
1399  * Sets @value to the range specified by @start and @end.
1400  */
1401 void
1402 gst_value_set_int_range (GValue * value, gint start, gint end)
1403 {
1404   gst_value_set_int_range_step (value, start, end, 1);
1405 }
1406
1407 /**
1408  * gst_value_get_int_range_min:
1409  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1410  *
1411  * Gets the minimum of the range specified by @value.
1412  *
1413  * Returns: the minimum of the range
1414  */
1415 gint
1416 gst_value_get_int_range_min (const GValue * value)
1417 {
1418   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
1419
1420   return INT_RANGE_MIN (value) * INT_RANGE_STEP (value);
1421 }
1422
1423 /**
1424  * gst_value_get_int_range_max:
1425  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1426  *
1427  * Gets the maximum of the range specified by @value.
1428  *
1429  * Returns: the maximum of the range
1430  */
1431 gint
1432 gst_value_get_int_range_max (const GValue * value)
1433 {
1434   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
1435
1436   return INT_RANGE_MAX (value) * INT_RANGE_STEP (value);
1437 }
1438
1439 /**
1440  * gst_value_get_int_range_step:
1441  * @value: a GValue initialized to GST_TYPE_INT_RANGE
1442  *
1443  * Gets the step of the range specified by @value.
1444  *
1445  * Returns: the step of the range
1446  */
1447 gint
1448 gst_value_get_int_range_step (const GValue * value)
1449 {
1450   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
1451
1452   return INT_RANGE_STEP (value);
1453 }
1454
1455 static void
1456 gst_value_transform_int_range_string (const GValue * src_value,
1457     GValue * dest_value)
1458 {
1459   if (INT_RANGE_STEP (src_value) == 1)
1460     dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]",
1461         INT_RANGE_MIN (src_value), INT_RANGE_MAX (src_value));
1462   else
1463     dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d,%d]",
1464         INT_RANGE_MIN (src_value) * INT_RANGE_STEP (src_value),
1465         INT_RANGE_MAX (src_value) * INT_RANGE_STEP (src_value),
1466         INT_RANGE_STEP (src_value));
1467 }
1468
1469 static gint
1470 gst_value_compare_int_range (const GValue * value1, const GValue * value2)
1471 {
1472 #if 0
1473   /* Compare the ranges. (Kept for clarity for the below comparision) */
1474   if (INT_RANGE_MIN (value1) != INT_RANGE_MIN (value2) ||
1475       INT_RANGE_MAX (value1) != INT_RANGE_MAX (value2))
1476     return GST_VALUE_UNORDERED;
1477 #else
1478   /* The MIN and MAX of the range are actually stored packed into one 64bit
1479    * value. We can therefore compare them directly */
1480   if (value1->data[0].v_uint64 != value2->data[0].v_uint64)
1481     return GST_VALUE_UNORDERED;
1482 #endif
1483
1484   /* The extents are equal */
1485   /* If there is only one value (min == max), we ignore the step for
1486    * comparison */
1487   if (INT_RANGE_MIN (value1) == INT_RANGE_MAX (value1))
1488     return GST_VALUE_EQUAL;
1489
1490   /* Else the ranges are only equal if their step is also equal */
1491   if (INT_RANGE_STEP (value1) == INT_RANGE_STEP (value2))
1492     return GST_VALUE_EQUAL;
1493   return GST_VALUE_UNORDERED;
1494 }
1495
1496 static gchar *
1497 gst_value_serialize_int_range (const GValue * value)
1498 {
1499   if (INT_RANGE_STEP (value) == 1)
1500     return g_strdup_printf ("[ %d, %d ]", INT_RANGE_MIN (value),
1501         INT_RANGE_MAX (value));
1502   else
1503     return g_strdup_printf ("[ %d, %d, %d ]",
1504         INT_RANGE_MIN (value) * INT_RANGE_STEP (value),
1505         INT_RANGE_MAX (value) * INT_RANGE_STEP (value), INT_RANGE_STEP (value));
1506 }
1507
1508 static gboolean
1509 gst_value_deserialize_int_range (GValue * dest, const gchar * s)
1510 {
1511   g_warning ("unimplemented");
1512   return FALSE;
1513 }
1514
1515 /***************
1516  * int64 range *
1517  *
1518  * Values in the range are defined as any value greater or equal
1519  * to min*step, AND lesser or equal to max*step.
1520  * For step == 1, this falls back to the traditional range semantics.
1521  ***************/
1522
1523 #define INT64_RANGE_MIN(v) (((gint64 *)((v)->data[0].v_pointer))[0])
1524 #define INT64_RANGE_MAX(v) (((gint64 *)((v)->data[0].v_pointer))[1])
1525 #define INT64_RANGE_STEP(v) (((gint64 *)((v)->data[0].v_pointer))[2])
1526
1527 static void
1528 gst_value_init_int64_range (GValue * value)
1529 {
1530   gint64 *vals = g_slice_alloc0 (3 * sizeof (gint64));
1531   value->data[0].v_pointer = vals;
1532   INT64_RANGE_MIN (value) = 0;
1533   INT64_RANGE_MAX (value) = 0;
1534   INT64_RANGE_STEP (value) = 1;
1535 }
1536
1537 static void
1538 gst_value_free_int64_range (GValue * value)
1539 {
1540   g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value));
1541   g_slice_free1 (3 * sizeof (gint64), value->data[0].v_pointer);
1542   value->data[0].v_pointer = NULL;
1543 }
1544
1545 static void
1546 gst_value_copy_int64_range (const GValue * src_value, GValue * dest_value)
1547 {
1548   gint64 *vals = (gint64 *) dest_value->data[0].v_pointer;
1549   gint64 *src_vals = (gint64 *) src_value->data[0].v_pointer;
1550
1551   if (vals == NULL) {
1552     gst_value_init_int64_range (dest_value);
1553   }
1554
1555   if (src_vals != NULL) {
1556     INT64_RANGE_MIN (dest_value) = INT64_RANGE_MIN (src_value);
1557     INT64_RANGE_MAX (dest_value) = INT64_RANGE_MAX (src_value);
1558     INT64_RANGE_STEP (dest_value) = INT64_RANGE_STEP (src_value);
1559   }
1560 }
1561
1562 static gchar *
1563 gst_value_collect_int64_range (GValue * value, guint n_collect_values,
1564     GTypeCValue * collect_values, guint collect_flags)
1565 {
1566   gint64 *vals = value->data[0].v_pointer;
1567
1568   g_return_val_if_fail (n_collect_values == 2,
1569       g_strdup_printf ("not enough value locations for `%s' passed",
1570           G_VALUE_TYPE_NAME (value)));
1571
1572   g_return_val_if_fail (collect_values[0].v_int64 < collect_values[1].v_int64,
1573       g_strdup_printf ("range start is not smaller than end for `%s'",
1574           G_VALUE_TYPE_NAME (value)));
1575
1576   if (vals == NULL) {
1577     gst_value_init_int64_range (value);
1578   }
1579
1580   gst_value_set_int64_range_step (value, collect_values[0].v_int64,
1581       collect_values[1].v_int64, 1);
1582
1583   return NULL;
1584 }
1585
1586 static gchar *
1587 gst_value_lcopy_int64_range (const GValue * value, guint n_collect_values,
1588     GTypeCValue * collect_values, guint collect_flags)
1589 {
1590   guint64 *int_range_start = collect_values[0].v_pointer;
1591   guint64 *int_range_end = collect_values[1].v_pointer;
1592   guint64 *int_range_step = collect_values[2].v_pointer;
1593   gint64 *vals = (gint64 *) value->data[0].v_pointer;
1594
1595   g_return_val_if_fail (int_range_start != NULL,
1596       g_strdup_printf ("start value location for `%s' passed as NULL",
1597           G_VALUE_TYPE_NAME (value)));
1598   g_return_val_if_fail (int_range_end != NULL,
1599       g_strdup_printf ("end value location for `%s' passed as NULL",
1600           G_VALUE_TYPE_NAME (value)));
1601   g_return_val_if_fail (int_range_step != NULL,
1602       g_strdup_printf ("step value location for `%s' passed as NULL",
1603           G_VALUE_TYPE_NAME (value)));
1604
1605   g_return_val_if_fail (vals != NULL,
1606       g_strdup_printf ("Uninitialised `%s' passed", G_VALUE_TYPE_NAME (value)));
1607
1608   *int_range_start = INT64_RANGE_MIN (value);
1609   *int_range_end = INT64_RANGE_MAX (value);
1610   *int_range_step = INT64_RANGE_STEP (value);
1611
1612   return NULL;
1613 }
1614
1615 /**
1616  * gst_value_set_int64_range_step:
1617  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1618  * @start: the start of the range
1619  * @end: the end of the range
1620  * @step: the step of the range
1621  *
1622  * Sets @value to the range specified by @start, @end and @step.
1623  */
1624 void
1625 gst_value_set_int64_range_step (GValue * value, gint64 start, gint64 end,
1626     gint64 step)
1627 {
1628   g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value));
1629   g_return_if_fail (start < end);
1630   g_return_if_fail (step > 0);
1631   g_return_if_fail (start % step == 0);
1632   g_return_if_fail (end % step == 0);
1633
1634   INT64_RANGE_MIN (value) = start / step;
1635   INT64_RANGE_MAX (value) = end / step;
1636   INT64_RANGE_STEP (value) = step;
1637 }
1638
1639 /**
1640  * gst_value_set_int64_range:
1641  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1642  * @start: the start of the range
1643  * @end: the end of the range
1644  *
1645  * Sets @value to the range specified by @start and @end.
1646  */
1647 void
1648 gst_value_set_int64_range (GValue * value, gint64 start, gint64 end)
1649 {
1650   gst_value_set_int64_range_step (value, start, end, 1);
1651 }
1652
1653 /**
1654  * gst_value_get_int64_range_min:
1655  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1656  *
1657  * Gets the minimum of the range specified by @value.
1658  *
1659  * Returns: the minimum of the range
1660  */
1661 gint64
1662 gst_value_get_int64_range_min (const GValue * value)
1663 {
1664   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1665
1666   return INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value);
1667 }
1668
1669 /**
1670  * gst_value_get_int64_range_max:
1671  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1672  *
1673  * Gets the maximum of the range specified by @value.
1674  *
1675  * Returns: the maximum of the range
1676  */
1677 gint64
1678 gst_value_get_int64_range_max (const GValue * value)
1679 {
1680   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1681
1682   return INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value);
1683 }
1684
1685 /**
1686  * gst_value_get_int64_range_step:
1687  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
1688  *
1689  * Gets the step of the range specified by @value.
1690  *
1691  * Returns: the step of the range
1692  */
1693 gint64
1694 gst_value_get_int64_range_step (const GValue * value)
1695 {
1696   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
1697
1698   return INT64_RANGE_STEP (value);
1699 }
1700
1701 static void
1702 gst_value_transform_int64_range_string (const GValue * src_value,
1703     GValue * dest_value)
1704 {
1705   if (INT64_RANGE_STEP (src_value) == 1)
1706     dest_value->data[0].v_pointer =
1707         g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT "]",
1708         INT64_RANGE_MIN (src_value), INT64_RANGE_MAX (src_value));
1709   else
1710     dest_value->data[0].v_pointer =
1711         g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT
1712         ",%" G_GINT64_FORMAT "]",
1713         INT64_RANGE_MIN (src_value) * INT64_RANGE_STEP (src_value),
1714         INT64_RANGE_MAX (src_value) * INT64_RANGE_STEP (src_value),
1715         INT64_RANGE_STEP (src_value));
1716 }
1717
1718 static gint
1719 gst_value_compare_int64_range (const GValue * value1, const GValue * value2)
1720 {
1721   /* Compare the ranges. */
1722   if (INT64_RANGE_MIN (value1) != INT64_RANGE_MIN (value2) ||
1723       INT64_RANGE_MAX (value1) != INT64_RANGE_MAX (value2))
1724     return GST_VALUE_UNORDERED;
1725
1726   /* The extents are equal */
1727   /* If there is only one value (min == max), we ignore the step for
1728    * comparison */
1729   if (INT64_RANGE_MIN (value1) == INT64_RANGE_MAX (value1))
1730     return GST_VALUE_EQUAL;
1731
1732   /* Else the ranges are only equal if their step is also equal */
1733   if (INT64_RANGE_STEP (value1) == INT64_RANGE_STEP (value2))
1734     return GST_VALUE_EQUAL;
1735   return GST_VALUE_UNORDERED;
1736 }
1737
1738 static gchar *
1739 gst_value_serialize_int64_range (const GValue * value)
1740 {
1741   if (INT64_RANGE_STEP (value) == 1)
1742     return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT " ]",
1743         INT64_RANGE_MIN (value), INT64_RANGE_MAX (value));
1744   else
1745     return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT ", %"
1746         G_GINT64_FORMAT " ]",
1747         INT64_RANGE_MIN (value) * INT64_RANGE_STEP (value),
1748         INT64_RANGE_MAX (value) * INT64_RANGE_STEP (value),
1749         INT64_RANGE_STEP (value));
1750 }
1751
1752 static gboolean
1753 gst_value_deserialize_int64_range (GValue * dest, const gchar * s)
1754 {
1755   g_warning ("unimplemented");
1756   return FALSE;
1757 }
1758
1759 /****************
1760  * double range *
1761  ****************/
1762
1763 static void
1764 gst_value_init_double_range (GValue * value)
1765 {
1766   value->data[0].v_double = 0;
1767   value->data[1].v_double = 0;
1768 }
1769
1770 static void
1771 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value)
1772 {
1773   dest_value->data[0].v_double = src_value->data[0].v_double;
1774   dest_value->data[1].v_double = src_value->data[1].v_double;
1775 }
1776
1777 static gchar *
1778 gst_value_collect_double_range (GValue * value, guint n_collect_values,
1779     GTypeCValue * collect_values, guint collect_flags)
1780 {
1781   g_return_val_if_fail (n_collect_values == 2,
1782       g_strdup_printf ("not enough value locations for `%s' passed",
1783           G_VALUE_TYPE_NAME (value)));
1784   g_return_val_if_fail (collect_values[0].v_double < collect_values[1].v_double,
1785       g_strdup_printf ("range start is not smaller than end for `%s'",
1786           G_VALUE_TYPE_NAME (value)));
1787
1788   value->data[0].v_double = collect_values[0].v_double;
1789   value->data[1].v_double = collect_values[1].v_double;
1790
1791   return NULL;
1792 }
1793
1794 static gchar *
1795 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values,
1796     GTypeCValue * collect_values, guint collect_flags)
1797 {
1798   gdouble *double_range_start = collect_values[0].v_pointer;
1799   gdouble *double_range_end = collect_values[1].v_pointer;
1800
1801   g_return_val_if_fail (double_range_start != NULL,
1802       g_strdup_printf ("start value location for `%s' passed as NULL",
1803           G_VALUE_TYPE_NAME (value)));
1804   g_return_val_if_fail (double_range_end != NULL,
1805       g_strdup_printf ("end value location for `%s' passed as NULL",
1806           G_VALUE_TYPE_NAME (value)));
1807
1808   *double_range_start = value->data[0].v_double;
1809   *double_range_end = value->data[1].v_double;
1810
1811   return NULL;
1812 }
1813
1814 /**
1815  * gst_value_set_double_range:
1816  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1817  * @start: the start of the range
1818  * @end: the end of the range
1819  *
1820  * Sets @value to the range specified by @start and @end.
1821  */
1822 void
1823 gst_value_set_double_range (GValue * value, gdouble start, gdouble end)
1824 {
1825   g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
1826   g_return_if_fail (start < end);
1827
1828   value->data[0].v_double = start;
1829   value->data[1].v_double = end;
1830 }
1831
1832 /**
1833  * gst_value_get_double_range_min:
1834  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1835  *
1836  * Gets the minimum of the range specified by @value.
1837  *
1838  * Returns: the minimum of the range
1839  */
1840 gdouble
1841 gst_value_get_double_range_min (const GValue * value)
1842 {
1843   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
1844
1845   return value->data[0].v_double;
1846 }
1847
1848 /**
1849  * gst_value_get_double_range_max:
1850  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1851  *
1852  * Gets the maximum of the range specified by @value.
1853  *
1854  * Returns: the maximum of the range
1855  */
1856 gdouble
1857 gst_value_get_double_range_max (const GValue * value)
1858 {
1859   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
1860
1861   return value->data[1].v_double;
1862 }
1863
1864 static void
1865 gst_value_transform_double_range_string (const GValue * src_value,
1866     GValue * dest_value)
1867 {
1868   gchar s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE];
1869
1870   dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]",
1871       g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
1872           src_value->data[0].v_double),
1873       g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
1874           src_value->data[1].v_double));
1875 }
1876
1877 static gint
1878 gst_value_compare_double_range (const GValue * value1, const GValue * value2)
1879 {
1880   if (value2->data[0].v_double == value1->data[0].v_double &&
1881       value2->data[1].v_double == value1->data[1].v_double)
1882     return GST_VALUE_EQUAL;
1883   return GST_VALUE_UNORDERED;
1884 }
1885
1886 static gchar *
1887 gst_value_serialize_double_range (const GValue * value)
1888 {
1889   gchar d1[G_ASCII_DTOSTR_BUF_SIZE];
1890   gchar d2[G_ASCII_DTOSTR_BUF_SIZE];
1891
1892   g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
1893   g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
1894   return g_strdup_printf ("[ %s, %s ]", d1, d2);
1895 }
1896
1897 static gboolean
1898 gst_value_deserialize_double_range (GValue * dest, const gchar * s)
1899 {
1900   g_warning ("unimplemented");
1901   return FALSE;
1902 }
1903
1904 /****************
1905  * fraction range *
1906  ****************/
1907
1908 static void
1909 gst_value_init_fraction_range (GValue * value)
1910 {
1911   GValue *vals;
1912   GType ftype;
1913
1914   ftype = GST_TYPE_FRACTION;
1915
1916   value->data[0].v_pointer = vals = g_slice_alloc0 (2 * sizeof (GValue));
1917   g_value_init (&vals[0], ftype);
1918   g_value_init (&vals[1], ftype);
1919 }
1920
1921 static void
1922 gst_value_free_fraction_range (GValue * value)
1923 {
1924   GValue *vals = (GValue *) value->data[0].v_pointer;
1925
1926   if (vals != NULL) {
1927     /* we know the two values contain fractions without internal allocs */
1928     /* g_value_unset (&vals[0]); */
1929     /* g_value_unset (&vals[1]); */
1930     g_slice_free1 (2 * sizeof (GValue), vals);
1931     value->data[0].v_pointer = NULL;
1932   }
1933 }
1934
1935 static void
1936 gst_value_copy_fraction_range (const GValue * src_value, GValue * dest_value)
1937 {
1938   GValue *vals = (GValue *) dest_value->data[0].v_pointer;
1939   GValue *src_vals = (GValue *) src_value->data[0].v_pointer;
1940
1941   if (vals == NULL) {
1942     gst_value_init_fraction_range (dest_value);
1943     vals = dest_value->data[0].v_pointer;
1944   }
1945   if (src_vals != NULL) {
1946     g_value_copy (&src_vals[0], &vals[0]);
1947     g_value_copy (&src_vals[1], &vals[1]);
1948   }
1949 }
1950
1951 static gchar *
1952 gst_value_collect_fraction_range (GValue * value, guint n_collect_values,
1953     GTypeCValue * collect_values, guint collect_flags)
1954 {
1955   GValue *vals = (GValue *) value->data[0].v_pointer;
1956
1957   g_return_val_if_fail (n_collect_values == 4,
1958       g_strdup_printf ("not enough value locations for `%s' passed",
1959           G_VALUE_TYPE_NAME (value)));
1960   g_return_val_if_fail (collect_values[1].v_int != 0,
1961       g_strdup_printf ("passed '0' as first denominator for `%s'",
1962           G_VALUE_TYPE_NAME (value)));
1963   g_return_val_if_fail (collect_values[3].v_int != 0,
1964       g_strdup_printf ("passed '0' as second denominator for `%s'",
1965           G_VALUE_TYPE_NAME (value)));
1966   g_return_val_if_fail (gst_util_fraction_compare (collect_values[0].v_int,
1967           collect_values[1].v_int, collect_values[2].v_int,
1968           collect_values[3].v_int) < 0,
1969       g_strdup_printf ("range start is not smaller than end for `%s'",
1970           G_VALUE_TYPE_NAME (value)));
1971
1972   if (vals == NULL) {
1973     gst_value_init_fraction_range (value);
1974     vals = value->data[0].v_pointer;
1975   }
1976
1977   gst_value_set_fraction (&vals[0], collect_values[0].v_int,
1978       collect_values[1].v_int);
1979   gst_value_set_fraction (&vals[1], collect_values[2].v_int,
1980       collect_values[3].v_int);
1981
1982   return NULL;
1983 }
1984
1985 static gchar *
1986 gst_value_lcopy_fraction_range (const GValue * value, guint n_collect_values,
1987     GTypeCValue * collect_values, guint collect_flags)
1988 {
1989   gint i;
1990   gint *dest_values[4];
1991   GValue *vals = (GValue *) value->data[0].v_pointer;
1992
1993   g_return_val_if_fail (n_collect_values == 4,
1994       g_strdup_printf ("not enough value locations for `%s' passed",
1995           G_VALUE_TYPE_NAME (value)));
1996   g_return_val_if_fail (vals != NULL,
1997       g_strdup_printf ("Uninitialised `%s' passed", G_VALUE_TYPE_NAME (value)));
1998
1999   for (i = 0; i < 4; i++) {
2000     g_return_val_if_fail (collect_values[i].v_pointer != NULL,
2001         g_strdup_printf ("value location for `%s' passed as NULL",
2002             G_VALUE_TYPE_NAME (value)));
2003
2004     dest_values[i] = collect_values[i].v_pointer;
2005   }
2006
2007   dest_values[0][0] = gst_value_get_fraction_numerator (&vals[0]);
2008   dest_values[1][0] = gst_value_get_fraction_denominator (&vals[0]);
2009   dest_values[2][0] = gst_value_get_fraction_numerator (&vals[1]);
2010   dest_values[3][0] = gst_value_get_fraction_denominator (&vals[1]);
2011   return NULL;
2012 }
2013
2014 /**
2015  * gst_value_set_fraction_range:
2016  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
2017  * @start: the start of the range (a GST_TYPE_FRACTION GValue)
2018  * @end: the end of the range (a GST_TYPE_FRACTION GValue)
2019  *
2020  * Sets @value to the range specified by @start and @end.
2021  */
2022 void
2023 gst_value_set_fraction_range (GValue * value, const GValue * start,
2024     const GValue * end)
2025 {
2026   GValue *vals;
2027
2028   g_return_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value));
2029   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (start));
2030   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (end));
2031   g_return_if_fail (gst_util_fraction_compare (start->data[0].v_int,
2032           start->data[1].v_int, end->data[0].v_int, end->data[1].v_int) < 0);
2033
2034   vals = (GValue *) value->data[0].v_pointer;
2035   if (vals == NULL) {
2036     gst_value_init_fraction_range (value);
2037     vals = value->data[0].v_pointer;
2038   }
2039   g_value_copy (start, &vals[0]);
2040   g_value_copy (end, &vals[1]);
2041 }
2042
2043 /**
2044  * gst_value_set_fraction_range_full:
2045  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
2046  * @numerator_start: the numerator start of the range
2047  * @denominator_start: the denominator start of the range
2048  * @numerator_end: the numerator end of the range
2049  * @denominator_end: the denominator end of the range
2050  *
2051  * Sets @value to the range specified by @numerator_start/@denominator_start
2052  * and @numerator_end/@denominator_end.
2053  */
2054 void
2055 gst_value_set_fraction_range_full (GValue * value,
2056     gint numerator_start, gint denominator_start,
2057     gint numerator_end, gint denominator_end)
2058 {
2059   GValue start = { 0 };
2060   GValue end = { 0 };
2061
2062   g_return_if_fail (value != NULL);
2063   g_return_if_fail (denominator_start != 0);
2064   g_return_if_fail (denominator_end != 0);
2065   g_return_if_fail (gst_util_fraction_compare (numerator_start,
2066           denominator_start, numerator_end, denominator_end) < 0);
2067
2068   g_value_init (&start, GST_TYPE_FRACTION);
2069   g_value_init (&end, GST_TYPE_FRACTION);
2070
2071   gst_value_set_fraction (&start, numerator_start, denominator_start);
2072   gst_value_set_fraction (&end, numerator_end, denominator_end);
2073   gst_value_set_fraction_range (value, &start, &end);
2074
2075   /* we know the two values contain fractions without internal allocs */
2076   /* g_value_unset (&start); */
2077   /* g_value_unset (&end);   */
2078 }
2079
2080 /* FIXME 2.0: Don't leak the internal representation of fraction
2081  * ranges but instead return the numerator and denominator
2082  * separately.
2083  * This would allow to store fraction ranges as
2084  *  data[0] = (min_n << 32) | (min_d)
2085  *  data[1] = (max_n << 32) | (max_d)
2086  * without requiring an additional allocation for each value.
2087  */
2088
2089 /**
2090  * gst_value_get_fraction_range_min:
2091  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
2092  *
2093  * Gets the minimum of the range specified by @value.
2094  *
2095  * Returns: (nullable): the minimum of the range
2096  */
2097 const GValue *
2098 gst_value_get_fraction_range_min (const GValue * value)
2099 {
2100   GValue *vals;
2101
2102   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL);
2103
2104   vals = (GValue *) value->data[0].v_pointer;
2105   if (vals != NULL) {
2106     return &vals[0];
2107   }
2108
2109   return NULL;
2110 }
2111
2112 /**
2113  * gst_value_get_fraction_range_max:
2114  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
2115  *
2116  * Gets the maximum of the range specified by @value.
2117  *
2118  * Returns: (nullable): the maximum of the range
2119  */
2120 const GValue *
2121 gst_value_get_fraction_range_max (const GValue * value)
2122 {
2123   GValue *vals;
2124
2125   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL);
2126
2127   vals = (GValue *) value->data[0].v_pointer;
2128   if (vals != NULL) {
2129     return &vals[1];
2130   }
2131
2132   return NULL;
2133 }
2134
2135 static gchar *
2136 gst_value_serialize_fraction_range (const GValue * value)
2137 {
2138   GValue *vals = (GValue *) value->data[0].v_pointer;
2139   gchar *retval;
2140
2141   if (vals == NULL) {
2142     retval = g_strdup ("[ 0/1, 0/1 ]");
2143   } else {
2144     gchar *start, *end;
2145
2146     start = gst_value_serialize_fraction (&vals[0]);
2147     end = gst_value_serialize_fraction (&vals[1]);
2148
2149     retval = g_strdup_printf ("[ %s, %s ]", start, end);
2150     g_free (start);
2151     g_free (end);
2152   }
2153
2154   return retval;
2155 }
2156
2157 static void
2158 gst_value_transform_fraction_range_string (const GValue * src_value,
2159     GValue * dest_value)
2160 {
2161   dest_value->data[0].v_pointer =
2162       gst_value_serialize_fraction_range (src_value);
2163 }
2164
2165 static gint
2166 gst_value_compare_fraction_range (const GValue * value1, const GValue * value2)
2167 {
2168   GValue *vals1, *vals2;
2169
2170   if (value2->data[0].v_pointer == value1->data[0].v_pointer)
2171     return GST_VALUE_EQUAL;     /* Only possible if both are NULL */
2172
2173   if (value2->data[0].v_pointer == NULL || value1->data[0].v_pointer == NULL)
2174     return GST_VALUE_UNORDERED;
2175
2176   vals1 = (GValue *) value1->data[0].v_pointer;
2177   vals2 = (GValue *) value2->data[0].v_pointer;
2178   if (gst_value_compare_fraction (&vals1[0], &vals2[0]) == GST_VALUE_EQUAL &&
2179       gst_value_compare_fraction (&vals1[1], &vals2[1]) == GST_VALUE_EQUAL)
2180     return GST_VALUE_EQUAL;
2181
2182   return GST_VALUE_UNORDERED;
2183 }
2184
2185 static gboolean
2186 gst_value_deserialize_fraction_range (GValue * dest, const gchar * s)
2187 {
2188   g_warning ("unimplemented");
2189   return FALSE;
2190 }
2191
2192 /***********
2193  * GstCaps *
2194  ***********/
2195
2196 /**
2197  * gst_value_set_caps:
2198  * @value: a GValue initialized to GST_TYPE_CAPS
2199  * @caps: (transfer none): the caps to set the value to
2200  *
2201  * Sets the contents of @value to @caps. A reference to the
2202  * provided @caps will be taken by the @value.
2203  */
2204 void
2205 gst_value_set_caps (GValue * value, const GstCaps * caps)
2206 {
2207   g_return_if_fail (G_IS_VALUE (value));
2208   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS);
2209   g_return_if_fail (caps == NULL || GST_IS_CAPS (caps));
2210
2211   g_value_set_boxed (value, caps);
2212 }
2213
2214 /**
2215  * gst_value_get_caps:
2216  * @value: a GValue initialized to GST_TYPE_CAPS
2217  *
2218  * Gets the contents of @value. The reference count of the returned
2219  * #GstCaps will not be modified, therefore the caller must take one
2220  * before getting rid of the @value.
2221  *
2222  * Returns: (transfer none): the contents of @value
2223  */
2224 const GstCaps *
2225 gst_value_get_caps (const GValue * value)
2226 {
2227   g_return_val_if_fail (G_IS_VALUE (value), NULL);
2228   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL);
2229
2230   return (GstCaps *) g_value_get_boxed (value);
2231 }
2232
2233 static gint
2234 gst_value_compare_caps (const GValue * value1, const GValue * value2)
2235 {
2236   GstCaps *caps1 = GST_CAPS (gst_value_get_caps (value1));
2237   GstCaps *caps2 = GST_CAPS (gst_value_get_caps (value2));
2238
2239   if (caps1 == caps2)
2240     return GST_VALUE_EQUAL;
2241
2242   if (!caps1 || !caps2)
2243     return GST_VALUE_UNORDERED;
2244
2245   if (gst_caps_is_equal (caps1, caps2))
2246     return GST_VALUE_EQUAL;
2247   return GST_VALUE_UNORDERED;
2248 }
2249
2250 static gchar *
2251 gst_value_serialize_caps (const GValue * value)
2252 {
2253   GstCaps *caps = g_value_get_boxed (value);
2254   return priv_gst_string_take_and_wrap (gst_caps_to_string (caps));
2255 }
2256
2257 static gboolean
2258 gst_value_deserialize_caps (GValue * dest, const gchar * s)
2259 {
2260   GstCaps *caps;
2261
2262   if (*s != '"') {
2263     /* this can happen if caps are ANY, EMPTY, or only contains a single
2264      * empty structure */
2265     caps = gst_caps_from_string (s);
2266   } else {
2267     gchar *str = gst_string_unwrap (s);
2268
2269     if (G_UNLIKELY (!str))
2270       return FALSE;
2271
2272     caps = gst_caps_from_string (str);
2273     g_free (str);
2274   }
2275
2276   if (caps) {
2277     g_value_take_boxed (dest, caps);
2278     return TRUE;
2279   }
2280   return FALSE;
2281 }
2282
2283 /********************************************
2284  * Serialization/deserialization of GValues *
2285  ********************************************/
2286
2287 static GstValueAbbreviation *
2288 _priv_gst_value_get_abbrs (gint * n_abbrs)
2289 {
2290   static GstValueAbbreviation *abbrs = NULL;
2291   static gsize num = 0;
2292
2293   if (g_once_init_enter (&num)) {
2294     /* dynamically generate the array */
2295     gsize _num;
2296     GstValueAbbreviation dyn_abbrs[] = {
2297       {"int", G_TYPE_INT}
2298       ,
2299       {"i", G_TYPE_INT}
2300       ,
2301       {"uint", G_TYPE_UINT}
2302       ,
2303       {"u", G_TYPE_UINT}
2304       ,
2305       {"float", G_TYPE_FLOAT}
2306       ,
2307       {"f", G_TYPE_FLOAT}
2308       ,
2309       {"double", G_TYPE_DOUBLE}
2310       ,
2311       {"d", G_TYPE_DOUBLE}
2312       ,
2313       {"buffer", GST_TYPE_BUFFER}
2314       ,
2315       {"fraction", GST_TYPE_FRACTION}
2316       ,
2317       {"boolean", G_TYPE_BOOLEAN}
2318       ,
2319       {"bool", G_TYPE_BOOLEAN}
2320       ,
2321       {"b", G_TYPE_BOOLEAN}
2322       ,
2323       {"string", G_TYPE_STRING}
2324       ,
2325       {"str", G_TYPE_STRING}
2326       ,
2327       {"s", G_TYPE_STRING}
2328       ,
2329       {"structure", GST_TYPE_STRUCTURE}
2330       ,
2331       {"date", G_TYPE_DATE}
2332       ,
2333       {"datetime", GST_TYPE_DATE_TIME}
2334       ,
2335       {"bitmask", GST_TYPE_BITMASK}
2336       ,
2337       {"flagset", GST_TYPE_FLAG_SET}
2338       ,
2339       {"sample", GST_TYPE_SAMPLE}
2340       ,
2341       {"taglist", GST_TYPE_TAG_LIST}
2342       ,
2343       {"type", G_TYPE_GTYPE}
2344       ,
2345       {"array", GST_TYPE_ARRAY}
2346       ,
2347       {"list", GST_TYPE_LIST}
2348     };
2349     _num = G_N_ELEMENTS (dyn_abbrs);
2350     /* permanently allocate and copy the array now */
2351     abbrs = g_new0 (GstValueAbbreviation, _num);
2352     memcpy (abbrs, dyn_abbrs, sizeof (GstValueAbbreviation) * _num);
2353     g_once_init_leave (&num, _num);
2354   }
2355   *n_abbrs = num;
2356
2357   return abbrs;
2358 }
2359
2360 /* given a type_name that could be a type abbreviation or a registered GType,
2361  * return a matching GType */
2362 static GType
2363 _priv_gst_value_gtype_from_abbr (const char *type_name)
2364 {
2365   int i;
2366   GstValueAbbreviation *abbrs;
2367   gint n_abbrs;
2368   GType ret;
2369
2370   g_return_val_if_fail (type_name != NULL, G_TYPE_INVALID);
2371
2372   abbrs = _priv_gst_value_get_abbrs (&n_abbrs);
2373
2374   for (i = 0; i < n_abbrs; i++) {
2375     if (strcmp (type_name, abbrs[i].type_name) == 0) {
2376       return abbrs[i].type;
2377     }
2378   }
2379
2380   /* this is the fallback */
2381   ret = g_type_from_name (type_name);
2382   /* If not found, try it as a dynamic type */
2383   if (G_UNLIKELY (ret == 0))
2384     ret = gst_dynamic_type_factory_load (type_name);
2385   return ret;
2386
2387 }
2388
2389 const char *
2390 _priv_gst_value_gtype_to_abbr (GType type)
2391 {
2392   int i;
2393   GstValueAbbreviation *abbrs;
2394   gint n_abbrs;
2395
2396   g_return_val_if_fail (type != G_TYPE_INVALID, NULL);
2397
2398   abbrs = _priv_gst_value_get_abbrs (&n_abbrs);
2399
2400   for (i = 0; i < n_abbrs; i++) {
2401     if (type == abbrs[i].type) {
2402       return abbrs[i].type_name;
2403     }
2404   }
2405
2406   return g_type_name (type);
2407 }
2408
2409 /*
2410  * _priv_gst_value_parse_string:
2411  * @s: string to parse
2412  * @end: out-pointer to char behind end of string
2413  * @next: out-pointer to start of unread data
2414  * @unescape: @TRUE if the substring is escaped.
2415  *
2416  * Find the end of a sub-string. If end == next, the string will not be
2417  * null-terminated. In all other cases it will be.
2418  *
2419  * Note: This function modifies the string in @s (if unescape == @TRUE).
2420  *
2421  * Returns: @TRUE if a sub-string was found and @FALSE if the string is not
2422  * terminated.
2423  */
2424 gboolean
2425 _priv_gst_value_parse_string (gchar * s, gchar ** end, gchar ** next,
2426     gboolean unescape)
2427 {
2428   gchar *w;
2429
2430   if (*s == 0)
2431     return FALSE;
2432
2433   if (*s != '"') {
2434     int ret = _priv_gst_value_parse_simple_string (s, end);
2435     *next = *end;
2436
2437     return ret;
2438   }
2439
2440   /* Find the closing quotes */
2441   if (unescape) {
2442     w = s;
2443     s++;
2444     while (*s != '"') {
2445       if (G_UNLIKELY (*s == 0))
2446         return FALSE;
2447       if (G_UNLIKELY (*s == '\\')) {
2448         s++;
2449         if (G_UNLIKELY (*s == 0))
2450           return FALSE;
2451       }
2452       *w = *s;
2453       w++;
2454       s++;
2455     }
2456     s++;
2457   } else {
2458     s++;
2459     while (*s != '"') {
2460       if (G_UNLIKELY (*s == 0))
2461         return FALSE;
2462       if (G_UNLIKELY (*s == '\\')) {
2463         s++;
2464         if (G_UNLIKELY (*s == 0))
2465           return FALSE;
2466       }
2467       s++;
2468     }
2469     s++;
2470     w = s;
2471   }
2472
2473   *end = w;
2474   *next = s;
2475
2476   return TRUE;
2477 }
2478
2479 static gboolean
2480 _priv_gst_value_parse_range (gchar * s, gchar ** after, GValue * value,
2481     GType type)
2482 {
2483   GValue value1 = { 0 };
2484   GValue value2 = { 0 };
2485   GValue value3 = { 0 };
2486   GType range_type;
2487   gboolean ret, have_step = FALSE;
2488
2489   if (*s != '[')
2490     return FALSE;
2491   s++;
2492
2493   ret = _priv_gst_value_parse_value (s, &s, &value1, type, NULL);
2494   if (!ret)
2495     goto err;
2496
2497   while (g_ascii_isspace (*s))
2498     s++;
2499
2500   if (*s != ',')
2501     goto err;
2502   s++;
2503
2504   while (g_ascii_isspace (*s))
2505     s++;
2506
2507   ret = _priv_gst_value_parse_value (s, &s, &value2, type, NULL);
2508   if (!ret)
2509     goto err;
2510
2511   while (g_ascii_isspace (*s))
2512     s++;
2513
2514   /* optional step for int and int64 */
2515   if (G_VALUE_TYPE (&value1) == G_TYPE_INT
2516       || G_VALUE_TYPE (&value1) == G_TYPE_INT64) {
2517     if (*s == ',') {
2518       s++;
2519
2520       while (g_ascii_isspace (*s))
2521         s++;
2522
2523       ret = _priv_gst_value_parse_value (s, &s, &value3, type, NULL);
2524       if (!ret)
2525         goto err;
2526
2527       while (g_ascii_isspace (*s))
2528         s++;
2529
2530       have_step = TRUE;
2531     }
2532   }
2533
2534   if (*s != ']')
2535     goto err;
2536   s++;
2537
2538   if (G_VALUE_TYPE (&value1) != G_VALUE_TYPE (&value2))
2539     return FALSE;
2540   if (have_step && G_VALUE_TYPE (&value1) != G_VALUE_TYPE (&value3))
2541     return FALSE;
2542
2543   if (G_VALUE_TYPE (&value1) == G_TYPE_DOUBLE) {
2544     range_type = GST_TYPE_DOUBLE_RANGE;
2545     g_value_init (value, range_type);
2546     gst_value_set_double_range (value,
2547         gst_g_value_get_double_unchecked (&value1),
2548         gst_g_value_get_double_unchecked (&value2));
2549   } else if (G_VALUE_TYPE (&value1) == G_TYPE_INT) {
2550     range_type = GST_TYPE_INT_RANGE;
2551     g_value_init (value, range_type);
2552     if (have_step)
2553       gst_value_set_int_range_step (value,
2554           gst_g_value_get_int_unchecked (&value1),
2555           gst_g_value_get_int_unchecked (&value2),
2556           gst_g_value_get_int_unchecked (&value3));
2557     else
2558       gst_value_set_int_range (value, gst_g_value_get_int_unchecked (&value1),
2559           gst_g_value_get_int_unchecked (&value2));
2560   } else if (G_VALUE_TYPE (&value1) == G_TYPE_INT64) {
2561     range_type = GST_TYPE_INT64_RANGE;
2562     g_value_init (value, range_type);
2563     if (have_step)
2564       gst_value_set_int64_range_step (value,
2565           gst_g_value_get_int64_unchecked (&value1),
2566           gst_g_value_get_int64_unchecked (&value2),
2567           gst_g_value_get_int64_unchecked (&value3));
2568     else
2569       gst_value_set_int64_range (value,
2570           gst_g_value_get_int64_unchecked (&value1),
2571           gst_g_value_get_int64_unchecked (&value2));
2572   } else if (G_VALUE_TYPE (&value1) == GST_TYPE_FRACTION) {
2573     range_type = GST_TYPE_FRACTION_RANGE;
2574     g_value_init (value, range_type);
2575     gst_value_set_fraction_range (value, &value1, &value2);
2576   } else {
2577     goto err;
2578   }
2579
2580   *after = s;
2581   return TRUE;
2582
2583 err:
2584   g_value_unset (value);
2585   g_value_unset (&value1);
2586   g_value_unset (&value2);
2587   g_value_unset (&value3);
2588   return FALSE;
2589 }
2590
2591 static gboolean
2592 _priv_gst_value_parse_any_list (gchar * s, gchar ** after, GValue * value,
2593     GType type, char begin, char end, GParamSpec * pspec)
2594 {
2595   GValue list_value = { 0 };
2596   gboolean ret;
2597   GstValueList *vlist = VALUE_LIST_ARRAY (value);
2598   GParamSpec *element_spec = NULL;
2599
2600   if (pspec)
2601     element_spec = GST_PARAM_SPEC_ARRAY_LIST (pspec)->element_spec;
2602
2603   if (*s != begin)
2604     return FALSE;
2605   s++;
2606
2607   while (g_ascii_isspace (*s))
2608     s++;
2609
2610   while (*s != end) {
2611     if (*s == ',') {
2612       s++;
2613       while (g_ascii_isspace (*s))
2614         s++;
2615
2616       if (*s == ',')
2617         return FALSE;
2618
2619       continue;
2620     }
2621
2622     memset (&list_value, 0, sizeof (list_value));
2623
2624     ret = _priv_gst_value_parse_value (s, &s, &list_value, type, element_spec);
2625     if (!ret)
2626       return FALSE;
2627
2628     _gst_value_list_append_val (vlist, &list_value);
2629
2630     while (g_ascii_isspace (*s))
2631       s++;
2632
2633     if (*s != ',' && *s != end)
2634       return FALSE;
2635   }
2636
2637   s++;
2638
2639   *after = s;
2640   return TRUE;
2641 }
2642
2643 static gboolean
2644 _priv_gst_value_parse_list (gchar * s, gchar ** after, GValue * value,
2645     GType type, GParamSpec * pspec)
2646 {
2647   return _priv_gst_value_parse_any_list (s, after, value, type, '{', '}',
2648       pspec);
2649 }
2650
2651 static gboolean
2652 _priv_gst_value_parse_array (gchar * s, gchar ** after, GValue * value,
2653     GType type, GParamSpec * pspec)
2654 {
2655   return _priv_gst_value_parse_any_list (s, after, value, type, '<', '>',
2656       pspec);
2657 }
2658
2659 gboolean
2660 _priv_gst_value_parse_simple_string (gchar * str, gchar ** end)
2661 {
2662   char *s = str;
2663
2664   while (G_LIKELY (GST_ASCII_IS_STRING (*s))) {
2665     s++;
2666   }
2667
2668   *end = s;
2669
2670   return (s != str);
2671 }
2672
2673 static gboolean
2674 _priv_gst_value_parse_struct_or_caps (gchar * str, gchar ** after, GType type,
2675     GValue * value)
2676 {
2677   gint openers = 1;
2678   gboolean ret = FALSE;
2679   gchar *s = str, t, *start, *end, *next;
2680
2681   if (*s != '[')
2682     return FALSE;
2683
2684   s++;
2685   str = s;
2686   for (; *s; s++) {
2687     if (*s == ']')
2688       openers--;
2689     else if (*s == '[')
2690       openers++;
2691
2692     if (openers == 0) {
2693       *after = s + 1;
2694       break;
2695     }
2696   }
2697
2698   if (*after == NULL)
2699     return FALSE;
2700
2701   t = *s;
2702   *s = '\0';
2703   g_value_init (value, type);
2704   if (priv_gst_structure_parse_name (str, &start, &end, &next, TRUE))
2705     ret = gst_value_deserialize (value, str);
2706   if (G_UNLIKELY (!ret)) {
2707     *s = t;
2708     g_value_unset (value);
2709   }
2710
2711   return ret;
2712 }
2713
2714 static gboolean
2715 _priv_gst_value_parse_range_struct_caps (gchar * s, gchar ** after,
2716     GValue * value, GType type)
2717 {
2718   gint i;
2719   gchar *tmp = s;
2720   gboolean ret = FALSE;
2721   GType try_types[] = {
2722     GST_TYPE_STRUCTURE,
2723     GST_TYPE_CAPS,
2724   };
2725
2726   if (type == GST_TYPE_CAPS || type == GST_TYPE_STRUCTURE)
2727     ret = _priv_gst_value_parse_struct_or_caps (tmp, &tmp, type, value);
2728
2729   if (ret)
2730     goto ok;
2731
2732   tmp = s;
2733   ret = _priv_gst_value_parse_range (tmp, &tmp, value, type);
2734   if (ret)
2735     goto ok;
2736
2737   if (type != G_TYPE_INVALID)
2738     return ret;
2739
2740   for (i = 0; i < G_N_ELEMENTS (try_types); i++) {
2741     tmp = s;
2742     ret = _priv_gst_value_parse_struct_or_caps (tmp, &tmp, try_types[i], value);
2743     if (ret)
2744       goto ok;
2745   }
2746
2747   return ret;
2748
2749 ok:
2750   *after = tmp;
2751   return ret;
2752 }
2753
2754 gboolean
2755 _priv_gst_value_parse_value (gchar * str,
2756     gchar ** after, GValue * value, GType default_type, GParamSpec * pspec)
2757 {
2758   gchar *type_name;
2759   gchar *type_end;
2760   gchar *value_s;
2761   gchar *value_end;
2762   gchar *s;
2763   gchar c;
2764   int ret = 0;
2765   GType type = default_type;
2766
2767   s = str;
2768   while (g_ascii_isspace (*s))
2769     s++;
2770
2771   /* check if there's a (type_name) 'cast' */
2772   type_name = NULL;
2773
2774   if (*s == '(') {
2775     s++;
2776     while (g_ascii_isspace (*s))
2777       s++;
2778     type_name = s;
2779     if (G_UNLIKELY (!_priv_gst_value_parse_simple_string (s, &type_end)))
2780       return FALSE;
2781     s = type_end;
2782     while (g_ascii_isspace (*s))
2783       s++;
2784     if (G_UNLIKELY (*s != ')'))
2785       return FALSE;
2786     s++;
2787     while (g_ascii_isspace (*s))
2788       s++;
2789
2790     c = *type_end;
2791     *type_end = 0;
2792     type = _priv_gst_value_gtype_from_abbr (type_name);
2793     GST_DEBUG ("trying type name '%s'", type_name);
2794     *type_end = c;
2795
2796     if (G_UNLIKELY (type == G_TYPE_INVALID)) {
2797       GST_WARNING ("invalid type");
2798       return FALSE;
2799     }
2800   } else if (pspec) {
2801     type = G_PARAM_SPEC_VALUE_TYPE (pspec);
2802   }
2803
2804   while (g_ascii_isspace (*s))
2805     s++;
2806   if (*s == '[') {
2807     ret = _priv_gst_value_parse_range_struct_caps (s, &s, value, type);
2808   } else if (*s == '{') {
2809     g_value_init (value, GST_TYPE_LIST);
2810     ret = _priv_gst_value_parse_list (s, &s, value, type, pspec);
2811   } else if (*s == '<') {
2812     g_value_init (value, GST_TYPE_ARRAY);
2813     ret = _priv_gst_value_parse_array (s, &s, value, type, pspec);
2814   } else {
2815     value_s = s;
2816
2817     if (G_UNLIKELY (type == G_TYPE_INVALID)) {
2818       GType try_types[] =
2819           { G_TYPE_INT, G_TYPE_DOUBLE, GST_TYPE_FRACTION, GST_TYPE_FLAG_SET,
2820         G_TYPE_BOOLEAN, G_TYPE_STRING
2821       };
2822       int i;
2823       int value_size;
2824       gboolean check_wrapped_non_string;
2825
2826       if (G_UNLIKELY (!_priv_gst_value_parse_string (s, &value_end, &s, FALSE)))
2827         return FALSE;
2828       /* Set NULL terminator for deserialization */
2829       value_size = value_end - value_s;
2830       value_s = g_strndup (value_s, value_end - value_s);
2831       /* Keep old broken behavior where "2" could be interpretted as an int */
2832       check_wrapped_non_string = value_s[0] == '"' &&
2833           strlen (value_s) >= 2 && value_end[-1] == '"';
2834
2835       for (i = 0; i < G_N_ELEMENTS (try_types); i++) {
2836         g_value_init (value, try_types[i]);
2837         if (try_types[i] != G_TYPE_STRING && check_wrapped_non_string) {
2838           value_s[value_size - 1] = '\0';
2839           ret = gst_value_deserialize (value, value_s + 1);
2840           value_s[value_size - 1] = '"';
2841           if (ret) {
2842             const gchar *type_name = g_type_name (try_types[i]);
2843
2844             g_warning ("Received a structure string that contains "
2845                 "'=%s'. Reading as a %s value, rather than a string "
2846                 "value. This is undesired behaviour, and with GStreamer 1.22 "
2847                 " onward, this will be interpreted as a string value instead "
2848                 "because it is wrapped in '\"' quotes. If you want to "
2849                 "guarantee this value is read as a string, before this "
2850                 "change, use '=(string)%s' instead. If you want to read "
2851                 "in a %s value, leave its value unquoted.",
2852                 value_s, type_name, value_s, type_name);
2853             break;
2854           }
2855         } else {
2856           ret = gst_value_deserialize (value, value_s);
2857           if (ret)
2858             break;
2859         }
2860         g_value_unset (value);
2861       }
2862     } else {
2863       g_value_init (value, type);
2864
2865       if (G_UNLIKELY (!_priv_gst_value_parse_string (s, &value_end, &s, FALSE)))
2866         return FALSE;
2867       /* Set NULL terminator for deserialization */
2868       value_s = g_strndup (value_s, value_end - value_s);
2869
2870       ret = gst_value_deserialize_with_pspec (value, value_s, pspec);
2871       if (G_UNLIKELY (!ret))
2872         g_value_unset (value);
2873     }
2874     g_free (value_s);
2875   }
2876
2877   *after = s;
2878
2879   return ret;
2880 }
2881
2882 /**************
2883  * GstSegment *
2884  **************/
2885
2886 static gchar *
2887 gst_value_serialize_segment_internal (const GValue * value, gboolean escape)
2888 {
2889   GstSegment *seg = g_value_get_boxed (value);
2890   gchar *t, *res;
2891   GstStructure *s;
2892
2893   s = gst_structure_new_id (GST_QUARK (SEGMENT),
2894       GST_QUARK (FLAGS), GST_TYPE_SEGMENT_FLAGS, seg->flags,
2895       GST_QUARK (RATE), G_TYPE_DOUBLE, seg->rate,
2896       GST_QUARK (APPLIED_RATE), G_TYPE_DOUBLE, seg->applied_rate,
2897       GST_QUARK (FORMAT), GST_TYPE_FORMAT, seg->format,
2898       GST_QUARK (BASE), G_TYPE_UINT64, seg->base,
2899       GST_QUARK (OFFSET), G_TYPE_UINT64, seg->offset,
2900       GST_QUARK (START), G_TYPE_UINT64, seg->start,
2901       GST_QUARK (STOP), G_TYPE_UINT64, seg->stop,
2902       GST_QUARK (TIME), G_TYPE_UINT64, seg->time,
2903       GST_QUARK (POSITION), G_TYPE_UINT64, seg->position,
2904       GST_QUARK (DURATION), G_TYPE_UINT64, seg->duration, NULL);
2905
2906   t = gst_structure_to_string (s);
2907   if (escape) {
2908     res = g_strdup_printf ("\"%s\"", t);
2909     g_free (t);
2910   } else {
2911     res = t;
2912   }
2913   gst_structure_free (s);
2914
2915   return res;
2916 }
2917
2918 static gchar *
2919 gst_value_serialize_segment (const GValue * value)
2920 {
2921   return gst_value_serialize_segment_internal (value, TRUE);
2922 }
2923
2924 static gboolean
2925 gst_value_deserialize_segment_internal (GValue * dest, const gchar * s,
2926     gboolean unescape)
2927 {
2928   GstStructure *str;
2929   GstSegment seg;
2930   gboolean res;
2931   gsize len;
2932   gchar *t;
2933
2934   if (unescape) {
2935     len = strlen (s);
2936     if (G_UNLIKELY (*s != '"' || len < 2 || s[len - 1] != '"')) {
2937       /* "\"" is not an accepted string, so len must be at least 2 */
2938       GST_ERROR ("Failed deserializing segement: expected string to start and "
2939           "end with '\"'");
2940       return FALSE;
2941     }
2942     t = g_strdup (s + 1);
2943     t[len - 2] = '\0';
2944     /* removed trailing '"' */
2945     str = gst_structure_from_string (t, NULL);
2946     g_free (t);
2947   } else {
2948     str = gst_structure_from_string (s, NULL);
2949   }
2950   if (G_UNLIKELY (str == NULL))
2951     return FALSE;
2952
2953   res = gst_structure_id_get (str,
2954       GST_QUARK (FLAGS), GST_TYPE_SEGMENT_FLAGS, &seg.flags,
2955       GST_QUARK (RATE), G_TYPE_DOUBLE, &seg.rate,
2956       GST_QUARK (APPLIED_RATE), G_TYPE_DOUBLE, &seg.applied_rate,
2957       GST_QUARK (FORMAT), GST_TYPE_FORMAT, &seg.format,
2958       GST_QUARK (BASE), G_TYPE_UINT64, &seg.base,
2959       GST_QUARK (OFFSET), G_TYPE_UINT64, &seg.offset,
2960       GST_QUARK (START), G_TYPE_UINT64, &seg.start,
2961       GST_QUARK (STOP), G_TYPE_UINT64, &seg.stop,
2962       GST_QUARK (TIME), G_TYPE_UINT64, &seg.time,
2963       GST_QUARK (POSITION), G_TYPE_UINT64, &seg.position,
2964       GST_QUARK (DURATION), G_TYPE_UINT64, &seg.duration, NULL);
2965   gst_structure_free (str);
2966
2967   if (res)
2968     g_value_set_boxed (dest, &seg);
2969
2970   return res;
2971 }
2972
2973 static gboolean
2974 gst_value_deserialize_segment (GValue * dest, const gchar * s)
2975 {
2976   return gst_value_deserialize_segment_internal (dest, s, TRUE);
2977 }
2978
2979 /****************
2980  * GstStructure *
2981  ****************/
2982
2983 /**
2984  * gst_value_set_structure:
2985  * @value: a GValue initialized to GST_TYPE_STRUCTURE
2986  * @structure: the structure to set the value to
2987  *
2988  * Sets the contents of @value to @structure.
2989  */
2990 void
2991 gst_value_set_structure (GValue * value, const GstStructure * structure)
2992 {
2993   g_return_if_fail (G_IS_VALUE (value));
2994   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE);
2995   g_return_if_fail (structure == NULL || GST_IS_STRUCTURE (structure));
2996
2997   g_value_set_boxed (value, structure);
2998 }
2999
3000 /**
3001  * gst_value_get_structure:
3002  * @value: a GValue initialized to GST_TYPE_STRUCTURE
3003  *
3004  * Gets the contents of @value.
3005  *
3006  * Returns: (transfer none): the contents of @value
3007  */
3008 const GstStructure *
3009 gst_value_get_structure (const GValue * value)
3010 {
3011   g_return_val_if_fail (G_IS_VALUE (value), NULL);
3012   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, NULL);
3013
3014   return (GstStructure *) g_value_get_boxed (value);
3015 }
3016
3017 static gchar *
3018 gst_value_serialize_structure (const GValue * value)
3019 {
3020   GstStructure *structure = g_value_get_boxed (value);
3021
3022   return priv_gst_string_take_and_wrap (gst_structure_to_string (structure));
3023   /* string should always end up being wrapped, since a structure string
3024    * ends in a ';' character */
3025 }
3026
3027 static gboolean
3028 gst_value_deserialize_structure (GValue * dest, const gchar * s)
3029 {
3030   GstStructure *structure;
3031
3032   if (*s != '"') {
3033     /* the output of gst_value_serialize_structure would never produce
3034      * such a string, but a user may pass to gst_structure_from_string
3035      * the string:
3036      *     name, sub=(GstStructure)sub-name, val=(int)5;
3037      * and expect sub to be read as an *empty* structure with the name
3038      * sub-name. Similar to
3039      *     name, caps=(GstCaps)video/x-raw, val=(int)5;
3040      * which gst_structure_to_string can produce. */
3041     structure = gst_structure_from_string (s, NULL);
3042   } else {
3043     gchar *str = gst_string_unwrap (s);
3044
3045     if (G_UNLIKELY (!str))
3046       return FALSE;
3047
3048     structure = gst_structure_from_string (str, NULL);
3049     g_free (str);
3050   }
3051
3052   if (G_LIKELY (structure)) {
3053     g_value_take_boxed (dest, structure);
3054     return TRUE;
3055   }
3056   return FALSE;
3057 }
3058
3059 static gboolean
3060 gst_value_compare_structure (const GValue * value1, const GValue * value2)
3061 {
3062   GstStructure *structure1 = GST_STRUCTURE (g_value_get_boxed (value1));
3063   GstStructure *structure2 = GST_STRUCTURE (g_value_get_boxed (value2));
3064
3065   if (structure1 == structure2)
3066     return GST_VALUE_EQUAL;
3067
3068   if (!structure1 || !structure2)
3069     return GST_VALUE_UNORDERED;
3070
3071   if (gst_structure_is_equal (structure1, structure2))
3072     return GST_VALUE_EQUAL;
3073
3074   return GST_VALUE_UNORDERED;
3075 }
3076
3077 /*******************
3078  * GstCapsFeatures *
3079  *******************/
3080
3081 /**
3082  * gst_value_set_caps_features:
3083  * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
3084  * @features: the features to set the value to
3085  *
3086  * Sets the contents of @value to @features.
3087  */
3088 void
3089 gst_value_set_caps_features (GValue * value, const GstCapsFeatures * features)
3090 {
3091   g_return_if_fail (G_IS_VALUE (value));
3092   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES);
3093   g_return_if_fail (features == NULL || GST_IS_CAPS_FEATURES (features));
3094
3095   g_value_set_boxed (value, features);
3096 }
3097
3098 /**
3099  * gst_value_get_caps_features:
3100  * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
3101  *
3102  * Gets the contents of @value.
3103  *
3104  * Returns: (transfer none): the contents of @value
3105  */
3106 const GstCapsFeatures *
3107 gst_value_get_caps_features (const GValue * value)
3108 {
3109   g_return_val_if_fail (G_IS_VALUE (value), NULL);
3110   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES, NULL);
3111
3112   return (GstCapsFeatures *) g_value_get_boxed (value);
3113 }
3114
3115 static gchar *
3116 gst_value_serialize_caps_features (const GValue * value)
3117 {
3118   GstCapsFeatures *features = g_value_get_boxed (value);
3119
3120   return priv_gst_string_take_and_wrap (gst_caps_features_to_string (features));
3121 }
3122
3123 static gboolean
3124 gst_value_deserialize_caps_features (GValue * dest, const gchar * s)
3125 {
3126   GstCapsFeatures *features;
3127
3128   if (*s != '"') {
3129     /* This can happen if gst_caps_features_to_string only returns
3130      * ALL, NONE, or a single features name, which means it is not
3131      * actually wrapped by priv_gst_string_take_and_wrap */
3132     features = gst_caps_features_from_string (s);
3133   } else {
3134     gchar *str = gst_string_unwrap (s);
3135
3136     if (G_UNLIKELY (!str))
3137       return FALSE;
3138
3139     features = gst_caps_features_from_string (str);
3140     g_free (str);
3141   }
3142
3143   if (G_LIKELY (features)) {
3144     g_value_take_boxed (dest, features);
3145     return TRUE;
3146   }
3147   return FALSE;
3148 }
3149
3150 /**************
3151  * GstTagList *
3152  **************/
3153 static gint
3154 gst_value_compare_tag_list (const GValue * value1, const GValue * value2)
3155 {
3156   GstTagList *taglist1 = GST_TAG_LIST (g_value_get_boxed (value1));
3157   GstTagList *taglist2 = GST_TAG_LIST (g_value_get_boxed (value2));
3158
3159   if (gst_tag_list_is_equal (taglist1, taglist2))
3160     return GST_VALUE_EQUAL;
3161   return GST_VALUE_UNORDERED;
3162 }
3163
3164 static gboolean
3165 gst_value_deserialize_tag_list (GValue * dest, const gchar * s)
3166 {
3167   GstTagList *taglist;
3168
3169   if (*s != '"') {
3170     /* the output of gst_value_serialize_tag_list would never produce
3171      * such a string, but a user may pass to gst_structure_from_string
3172      * the string:
3173      *     name, list=(GstTagList)taglist, val=(int)5;
3174      * and expect list to be read as an *empty* tag list. Similar to
3175      *     name, caps=(GstCaps)video/x-raw, val=(int)5;
3176      * which gst_structure_to_string can produce. */
3177     taglist = gst_tag_list_new_from_string (s);
3178   } else {
3179     gchar *str = gst_string_unwrap (s);
3180
3181     if (G_UNLIKELY (!str))
3182       return FALSE;
3183
3184     taglist = gst_tag_list_new_from_string (str);
3185     g_free (str);
3186   }
3187
3188   if (G_LIKELY (taglist != NULL)) {
3189     g_value_take_boxed (dest, taglist);
3190     return TRUE;
3191   }
3192   return FALSE;
3193 }
3194
3195 static gchar *
3196 gst_value_serialize_tag_list (const GValue * value)
3197 {
3198   GstTagList *taglist = g_value_get_boxed (value);
3199
3200   return priv_gst_string_take_and_wrap (gst_tag_list_to_string (taglist));
3201   /* string should always end up being wrapped, since a taglist (structure)
3202    * string ends in a ';' character */
3203 }
3204
3205
3206 /*************
3207  * GstBuffer *
3208  *************/
3209
3210 static gint
3211 compare_buffer (GstBuffer * buf1, GstBuffer * buf2)
3212 {
3213   gsize size1, size2;
3214   GstMapInfo info1, info2;
3215   gint result, mret;
3216
3217   if (buf1 == buf2)
3218     return GST_VALUE_EQUAL;
3219
3220   size1 = gst_buffer_get_size (buf1);
3221   size2 = gst_buffer_get_size (buf2);
3222
3223   if (size1 != size2)
3224     return GST_VALUE_UNORDERED;
3225
3226   if (size1 == 0)
3227     return GST_VALUE_EQUAL;
3228
3229   if (!gst_buffer_map (buf1, &info1, GST_MAP_READ))
3230     return GST_VALUE_UNORDERED;
3231
3232   if (!gst_buffer_map (buf2, &info2, GST_MAP_READ)) {
3233     gst_buffer_unmap (buf1, &info1);
3234     return GST_VALUE_UNORDERED;
3235   }
3236
3237   mret = memcmp (info1.data, info2.data, info1.size);
3238   if (mret == 0)
3239     result = GST_VALUE_EQUAL;
3240   else if (mret < 0)
3241     result = GST_VALUE_LESS_THAN;
3242   else
3243     result = GST_VALUE_GREATER_THAN;
3244
3245   gst_buffer_unmap (buf1, &info1);
3246   gst_buffer_unmap (buf2, &info2);
3247
3248   return result;
3249 }
3250
3251 static gint
3252 gst_value_compare_buffer (const GValue * value1, const GValue * value2)
3253 {
3254   GstBuffer *buf1 = gst_value_get_buffer (value1);
3255   GstBuffer *buf2 = gst_value_get_buffer (value2);
3256
3257   return compare_buffer (buf1, buf2);
3258 }
3259
3260 static gchar *
3261 gst_value_serialize_buffer (const GValue * value)
3262 {
3263   GstMapInfo info;
3264   guint8 *data;
3265   gint i;
3266   gchar *string;
3267   GstBuffer *buffer;
3268
3269   buffer = gst_value_get_buffer (value);
3270   if (buffer == NULL)
3271     return NULL;
3272
3273   if (!gst_buffer_map (buffer, &info, GST_MAP_READ))
3274     return NULL;
3275
3276   data = info.data;
3277
3278   string = g_malloc (info.size * 2 + 1);
3279   for (i = 0; i < info.size; i++) {
3280     sprintf (string + i * 2, "%02x", data[i]);
3281   }
3282   string[info.size * 2] = 0;
3283
3284   gst_buffer_unmap (buffer, &info);
3285
3286   return string;
3287 }
3288
3289 static gboolean
3290 gst_value_deserialize_buffer (GValue * dest, const gchar * s)
3291 {
3292   GstBuffer *buffer;
3293   gint len;
3294   gchar ts[3];
3295   GstMapInfo info;
3296   guint8 *data;
3297   gint i;
3298
3299   len = strlen (s);
3300   if (len & 1)
3301     goto wrong_length;
3302
3303   buffer = gst_buffer_new_allocate (NULL, len / 2, NULL);
3304   if (!gst_buffer_map (buffer, &info, GST_MAP_WRITE))
3305     goto map_failed;
3306   data = info.data;
3307
3308   for (i = 0; i < len / 2; i++) {
3309     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1]))
3310       goto wrong_char;
3311
3312     ts[0] = s[i * 2 + 0];
3313     ts[1] = s[i * 2 + 1];
3314     ts[2] = 0;
3315
3316     data[i] = (guint8) strtoul (ts, NULL, 16);
3317   }
3318   gst_buffer_unmap (buffer, &info);
3319
3320   gst_value_take_buffer (dest, buffer);
3321
3322   return TRUE;
3323
3324   /* ERRORS */
3325 wrong_length:
3326   {
3327     return FALSE;
3328   }
3329 map_failed:
3330   {
3331     return FALSE;
3332   }
3333 wrong_char:
3334   {
3335     gst_buffer_unref (buffer);
3336     gst_buffer_unmap (buffer, &info);
3337     return FALSE;
3338   }
3339 }
3340
3341 /*************
3342  * GstSample *
3343  *************/
3344
3345 /* This function is mostly used for comparing image/buffer tags in taglists */
3346 static gint
3347 gst_value_compare_sample (const GValue * value1, const GValue * value2)
3348 {
3349   GstBuffer *buf1 = gst_sample_get_buffer (gst_value_get_sample (value1));
3350   GstBuffer *buf2 = gst_sample_get_buffer (gst_value_get_sample (value2));
3351
3352   /* FIXME: should we take into account anything else such as caps? */
3353   return compare_buffer (buf1, buf2);
3354 }
3355
3356 static gchar *
3357 gst_value_serialize_sample (const GValue * value)
3358 {
3359   const GstStructure *info_structure;
3360   GstSegment *segment;
3361   GstBuffer *buffer;
3362   GstCaps *caps;
3363   GstSample *sample;
3364   GValue val = { 0, };
3365   gchar *info_str, *caps_str, *tmp;
3366   gchar *buf_str, *seg_str, *s;
3367
3368   sample = g_value_get_boxed (value);
3369
3370   buffer = gst_sample_get_buffer (sample);
3371   if (buffer) {
3372     g_value_init (&val, GST_TYPE_BUFFER);
3373     g_value_set_boxed (&val, buffer);
3374     buf_str = gst_value_serialize_buffer (&val);
3375     g_value_unset (&val);
3376   } else {
3377     buf_str = g_strdup ("None");
3378   }
3379
3380   caps = gst_sample_get_caps (sample);
3381   if (caps) {
3382     tmp = gst_caps_to_string (caps);
3383     caps_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
3384     g_strdelimit (caps_str, "=", '_');
3385     g_free (tmp);
3386   } else {
3387     caps_str = g_strdup ("None");
3388   }
3389
3390   segment = gst_sample_get_segment (sample);
3391   if (segment) {
3392     g_value_init (&val, GST_TYPE_SEGMENT);
3393     g_value_set_boxed (&val, segment);
3394     tmp = gst_value_serialize_segment_internal (&val, FALSE);
3395     seg_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
3396     g_strdelimit (seg_str, "=", '_');
3397     g_free (tmp);
3398     g_value_unset (&val);
3399   } else {
3400     seg_str = g_strdup ("None");
3401   }
3402
3403   info_structure = gst_sample_get_info (sample);
3404   if (info_structure) {
3405     tmp = gst_structure_to_string (info_structure);
3406     info_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
3407     g_strdelimit (info_str, "=", '_');
3408     g_free (tmp);
3409   } else {
3410     info_str = g_strdup ("None");
3411   }
3412
3413   s = g_strconcat (buf_str, ":", caps_str, ":", seg_str, ":", info_str, NULL);
3414   g_free (buf_str);
3415   g_free (caps_str);
3416   g_free (seg_str);
3417   g_free (info_str);
3418
3419   return s;
3420 }
3421
3422 static gboolean
3423 gst_value_deserialize_sample (GValue * dest, const gchar * s)
3424 {
3425   GValue bval = G_VALUE_INIT, sval = G_VALUE_INIT;
3426   GstStructure *info;
3427   GstSample *sample;
3428   GstCaps *caps = NULL;
3429   gboolean ret = FALSE;
3430   gchar **fields;
3431   gsize outlen;
3432   gint len;
3433
3434   GST_TRACE ("deserialize '%s'", s);
3435
3436   fields = g_strsplit (s, ":", -1);
3437   len = g_strv_length (fields);
3438   if (len != 4)
3439     goto wrong_length;
3440
3441   g_value_init (&bval, GST_TYPE_BUFFER);
3442   g_value_init (&sval, GST_TYPE_SEGMENT);
3443
3444   if (!gst_value_deserialize_buffer (&bval, fields[0]))
3445     goto fail;
3446
3447   if (strcmp (fields[1], "None") != 0) {
3448     g_strdelimit (fields[1], "_", '=');
3449     g_base64_decode_inplace (fields[1], &outlen);
3450     GST_TRACE ("caps    : %s", fields[1]);
3451     caps = gst_caps_from_string (fields[1]);
3452     if (caps == NULL)
3453       goto fail;
3454   }
3455
3456   if (strcmp (fields[2], "None") != 0) {
3457     g_strdelimit (fields[2], "_", '=');
3458     g_base64_decode_inplace (fields[2], &outlen);
3459     GST_TRACE ("segment : %s", fields[2]);
3460     if (!gst_value_deserialize_segment_internal (&sval, fields[2], FALSE))
3461       goto fail;
3462   }
3463
3464   if (strcmp (fields[3], "None") != 0) {
3465     g_strdelimit (fields[3], "_", '=');
3466     g_base64_decode_inplace (fields[3], &outlen);
3467     GST_TRACE ("info    : %s", fields[3]);
3468     info = gst_structure_from_string (fields[3], NULL);
3469     if (info == NULL)
3470       goto fail;
3471   } else {
3472     info = NULL;
3473   }
3474
3475   sample = gst_sample_new (gst_value_get_buffer (&bval), caps,
3476       g_value_get_boxed (&sval), info);
3477
3478   g_value_take_boxed (dest, sample);
3479
3480   ret = TRUE;
3481
3482 fail:
3483   if (caps)
3484     gst_caps_unref (caps);
3485   g_value_unset (&bval);
3486   g_value_unset (&sval);
3487
3488 wrong_length:
3489
3490   g_strfreev (fields);
3491
3492   return ret;
3493 }
3494
3495 /***********
3496  * boolean *
3497  ***********/
3498
3499 static gint
3500 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
3501 {
3502   if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
3503     return GST_VALUE_EQUAL;
3504   return GST_VALUE_UNORDERED;
3505 }
3506
3507 static gchar *
3508 gst_value_serialize_boolean (const GValue * value)
3509 {
3510   if (value->data[0].v_int) {
3511     return g_strdup ("true");
3512   }
3513   return g_strdup ("false");
3514 }
3515
3516 static gboolean
3517 gst_value_deserialize_boolean (GValue * dest, const gchar * s)
3518 {
3519   gboolean ret = FALSE;
3520
3521   if (g_ascii_strcasecmp (s, "true") == 0 ||
3522       g_ascii_strcasecmp (s, "yes") == 0 ||
3523       g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
3524     g_value_set_boolean (dest, TRUE);
3525     ret = TRUE;
3526   } else if (g_ascii_strcasecmp (s, "false") == 0 ||
3527       g_ascii_strcasecmp (s, "no") == 0 ||
3528       g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
3529     g_value_set_boolean (dest, FALSE);
3530     ret = TRUE;
3531   }
3532
3533   return ret;
3534 }
3535
3536 #define CREATE_SERIALIZATION_START(_type,_macro)                        \
3537 static gint                                                             \
3538 gst_value_compare_ ## _type                                             \
3539 (const GValue * value1, const GValue * value2)                          \
3540 {                                                                       \
3541   g ## _type val1 = g_value_get_ ## _type (value1);                     \
3542   g ## _type val2 = g_value_get_ ## _type (value2);                     \
3543   if (val1 > val2)                                                      \
3544     return GST_VALUE_GREATER_THAN;                                      \
3545   if (val1 < val2)                                                      \
3546     return GST_VALUE_LESS_THAN;                                         \
3547   return GST_VALUE_EQUAL;                                               \
3548 }                                                                       \
3549                                                                         \
3550 static gchar *                                                          \
3551 gst_value_serialize_ ## _type (const GValue * value)                    \
3552 {                                                                       \
3553   GValue val = { 0, };                                                  \
3554   g_value_init (&val, G_TYPE_STRING);                                   \
3555   if (!g_value_transform (value, &val))                                 \
3556     g_assert_not_reached ();                                            \
3557   /* NO_COPY_MADNESS!!! */                                              \
3558   return (char *) g_value_get_string (&val);                            \
3559 }
3560
3561 /* deserialize the given s into to as a gint64.
3562  * check if the result is actually storeable in the given size number of
3563  * bytes.
3564  */
3565 static gboolean
3566 gst_value_deserialize_int_helper (gint64 * to, const gchar * s,
3567     gint64 min, gint64 max, gint size)
3568 {
3569   gboolean ret = FALSE;
3570   gchar *end;
3571   guint64 mask = ~0;
3572
3573   errno = 0;
3574   *to = g_ascii_strtoull (s, &end, 0);
3575   /* a range error is a definitive no-no */
3576   if (errno == ERANGE) {
3577     return FALSE;
3578   }
3579
3580   if (*end == 0) {
3581     ret = TRUE;
3582   } else {
3583     if (g_ascii_strcasecmp (s, "little_endian") == 0) {
3584       *to = G_LITTLE_ENDIAN;
3585       ret = TRUE;
3586     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
3587       *to = G_BIG_ENDIAN;
3588       ret = TRUE;
3589     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
3590       *to = G_BYTE_ORDER;
3591       ret = TRUE;
3592     } else if (g_ascii_strcasecmp (s, "min") == 0) {
3593       *to = min;
3594       ret = TRUE;
3595     } else if (g_ascii_strcasecmp (s, "max") == 0) {
3596       *to = max;
3597       ret = TRUE;
3598     }
3599   }
3600   if (ret) {
3601     /* by definition, a gint64 fits into a gint64; so ignore those */
3602     if (size != sizeof (mask)) {
3603       if (*to >= 0) {
3604         /* for positive numbers, we create a mask of 1's outside of the range
3605          * and 0's inside the range.  An and will thus keep only 1 bits
3606          * outside of the range */
3607         mask <<= (size * 8);
3608         if ((mask & *to) != 0) {
3609           ret = FALSE;
3610         }
3611       } else {
3612         /* for negative numbers, we do a 2's complement version */
3613         mask <<= ((size * 8) - 1);
3614         if ((mask & *to) != mask) {
3615           ret = FALSE;
3616         }
3617       }
3618     }
3619   }
3620   return ret;
3621 }
3622
3623 #define CREATE_SERIALIZATION(_type,_macro)                              \
3624 CREATE_SERIALIZATION_START(_type,_macro)                                \
3625                                                                         \
3626 static gboolean                                                         \
3627 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
3628 {                                                                       \
3629   gint64 x;                                                             \
3630                                                                         \
3631   if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro,         \
3632       G_MAX ## _macro, sizeof (g ## _type))) {                          \
3633     g_value_set_ ## _type (dest, /*(g ## _type)*/ x);                   \
3634     return TRUE;                                                        \
3635   } else {                                                              \
3636     return FALSE;                                                       \
3637   }                                                                     \
3638 }
3639
3640 #define CREATE_USERIALIZATION(_type,_macro)                             \
3641 CREATE_SERIALIZATION_START(_type,_macro)                                \
3642                                                                         \
3643 static gboolean                                                         \
3644 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
3645 {                                                                       \
3646   gint64 x;                                                             \
3647   gchar *end;                                                           \
3648   gboolean ret = FALSE;                                                 \
3649                                                                         \
3650   errno = 0;                                                            \
3651   x = g_ascii_strtoull (s, &end, 0);                                    \
3652   /* a range error is a definitive no-no */                             \
3653   if (errno == ERANGE) {                                                \
3654     return FALSE;                                                       \
3655   }                                                                     \
3656   /* the cast ensures the range check later on makes sense */           \
3657   x = (g ## _type) x;                                                   \
3658   if (*end == 0) {                                                      \
3659     ret = TRUE;                                                         \
3660   } else {                                                              \
3661     if (g_ascii_strcasecmp (s, "little_endian") == 0) {                 \
3662       x = G_LITTLE_ENDIAN;                                              \
3663       ret = TRUE;                                                       \
3664     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {             \
3665       x = G_BIG_ENDIAN;                                                 \
3666       ret = TRUE;                                                       \
3667     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {             \
3668       x = G_BYTE_ORDER;                                                 \
3669       ret = TRUE;                                                       \
3670     } else if (g_ascii_strcasecmp (s, "min") == 0) {                    \
3671       x = 0;                                                            \
3672       ret = TRUE;                                                       \
3673     } else if (g_ascii_strcasecmp (s, "max") == 0) {                    \
3674       x = G_MAX ## _macro;                                              \
3675       ret = TRUE;                                                       \
3676     }                                                                   \
3677   }                                                                     \
3678   if (ret) {                                                            \
3679     if (x > G_MAX ## _macro) {                                          \
3680       ret = FALSE;                                                      \
3681     } else {                                                            \
3682       g_value_set_ ## _type (dest, x);                                  \
3683     }                                                                   \
3684   }                                                                     \
3685   return ret;                                                           \
3686 }
3687
3688 CREATE_SERIALIZATION (int, INT);
3689 CREATE_SERIALIZATION (int64, INT64);
3690 CREATE_SERIALIZATION (long, LONG);
3691
3692 CREATE_USERIALIZATION (uint, UINT);
3693 CREATE_USERIALIZATION (uint64, UINT64);
3694 CREATE_USERIALIZATION (ulong, ULONG);
3695
3696 /* FIXME 2.0: remove this again, plugins shouldn't have uchar properties */
3697 #ifndef G_MAXUCHAR
3698 #define G_MAXUCHAR 255
3699 #endif
3700 CREATE_USERIALIZATION (uchar, UCHAR);
3701
3702 /**********
3703  * double *
3704  **********/
3705 static gint
3706 gst_value_compare_double (const GValue * value1, const GValue * value2)
3707 {
3708   if (value1->data[0].v_double > value2->data[0].v_double)
3709     return GST_VALUE_GREATER_THAN;
3710   if (value1->data[0].v_double < value2->data[0].v_double)
3711     return GST_VALUE_LESS_THAN;
3712   if (value1->data[0].v_double == value2->data[0].v_double)
3713     return GST_VALUE_EQUAL;
3714   return GST_VALUE_UNORDERED;
3715 }
3716
3717 static gchar *
3718 gst_value_serialize_double (const GValue * value)
3719 {
3720   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
3721
3722   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
3723   return g_strdup (d);
3724 }
3725
3726 static gboolean
3727 gst_value_deserialize_double (GValue * dest, const gchar * s)
3728 {
3729   gdouble x;
3730   gboolean ret = FALSE;
3731   gchar *end;
3732
3733   x = g_ascii_strtod (s, &end);
3734   if (*end == 0) {
3735     ret = TRUE;
3736   } else {
3737     if (g_ascii_strcasecmp (s, "min") == 0) {
3738       x = -G_MAXDOUBLE;
3739       ret = TRUE;
3740     } else if (g_ascii_strcasecmp (s, "max") == 0) {
3741       x = G_MAXDOUBLE;
3742       ret = TRUE;
3743     }
3744   }
3745   if (ret) {
3746     g_value_set_double (dest, x);
3747   }
3748   return ret;
3749 }
3750
3751 /*********
3752  * float *
3753  *********/
3754
3755 static gint
3756 gst_value_compare_float (const GValue * value1, const GValue * value2)
3757 {
3758   if (value1->data[0].v_float > value2->data[0].v_float)
3759     return GST_VALUE_GREATER_THAN;
3760   if (value1->data[0].v_float < value2->data[0].v_float)
3761     return GST_VALUE_LESS_THAN;
3762   if (value1->data[0].v_float == value2->data[0].v_float)
3763     return GST_VALUE_EQUAL;
3764   return GST_VALUE_UNORDERED;
3765 }
3766
3767 static gchar *
3768 gst_value_serialize_float (const GValue * value)
3769 {
3770   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
3771
3772   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
3773   return g_strdup (d);
3774 }
3775
3776 static gboolean
3777 gst_value_deserialize_float (GValue * dest, const gchar * s)
3778 {
3779   gdouble x;
3780   gboolean ret = FALSE;
3781   gchar *end;
3782
3783   x = g_ascii_strtod (s, &end);
3784   if (*end == 0) {
3785     ret = TRUE;
3786   } else {
3787     if (g_ascii_strcasecmp (s, "min") == 0) {
3788       x = -G_MAXFLOAT;
3789       ret = TRUE;
3790     } else if (g_ascii_strcasecmp (s, "max") == 0) {
3791       x = G_MAXFLOAT;
3792       ret = TRUE;
3793     }
3794   }
3795   if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
3796     ret = FALSE;
3797   if (ret) {
3798     g_value_set_float (dest, (float) x);
3799   }
3800   return ret;
3801 }
3802
3803 /**********
3804  * string *
3805  **********/
3806
3807 static gint
3808 gst_value_compare_string (const GValue * value1, const GValue * value2)
3809 {
3810   if (G_UNLIKELY (!value1->data[0].v_pointer || !value2->data[0].v_pointer)) {
3811     /* if only one is NULL, no match - otherwise both NULL == EQUAL */
3812     if (value1->data[0].v_pointer != value2->data[0].v_pointer)
3813       return GST_VALUE_UNORDERED;
3814   } else {
3815     gint x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
3816
3817     if (x < 0)
3818       return GST_VALUE_LESS_THAN;
3819     if (x > 0)
3820       return GST_VALUE_GREATER_THAN;
3821   }
3822
3823   return GST_VALUE_EQUAL;
3824 }
3825
3826 static gint
3827 gst_string_measure_wrapping (const gchar * s)
3828 {
3829   gint len;
3830   gboolean wrap = FALSE;
3831
3832   if (G_UNLIKELY (s == NULL))
3833     return -1;
3834
3835   /* Special case: the actual string NULL needs wrapping */
3836   if (G_UNLIKELY (strcmp (s, "NULL") == 0))
3837     return 4;
3838
3839   len = 0;
3840   while (*s) {
3841     if (GST_ASCII_IS_STRING (*s)) {
3842       len++;
3843     } else if (*s < 0x20 || *s >= 0x7f) {
3844       wrap = TRUE;
3845       len += 4;
3846     } else {
3847       wrap = TRUE;
3848       len += 2;
3849     }
3850     s++;
3851   }
3852
3853   /* Wrap the string if we found something that needs
3854    * wrapping, or the empty string (len == 0) */
3855   return (wrap || len == 0) ? len : -1;
3856 }
3857
3858 static gchar *
3859 gst_string_wrap_inner (const gchar * s, gint len)
3860 {
3861   gchar *d, *e;
3862
3863   e = d = g_malloc (len + 3);
3864
3865   *e++ = '\"';
3866   while (*s) {
3867     if (GST_ASCII_IS_STRING (*s)) {
3868       *e++ = *s++;
3869     } else if (*s < 0x20 || *s >= 0x7f) {
3870       *e++ = '\\';
3871       *e++ = '0' + ((*(guchar *) s) >> 6);
3872       *e++ = '0' + (((*s) >> 3) & 0x7);
3873       *e++ = '0' + ((*s++) & 0x7);
3874     } else {
3875       *e++ = '\\';
3876       *e++ = *s++;
3877     }
3878   }
3879   *e++ = '\"';
3880   *e = 0;
3881
3882   g_assert (e - d <= len + 3);
3883   return d;
3884 }
3885
3886 /* Do string wrapping/escaping */
3887 static gchar *
3888 gst_string_wrap (const gchar * s)
3889 {
3890   gint len = gst_string_measure_wrapping (s);
3891
3892   if (G_LIKELY (len < 0))
3893     return g_strdup (s);
3894
3895   return gst_string_wrap_inner (s, len);
3896 }
3897
3898 /* Same as above, but take ownership of the string */
3899 gchar *
3900 priv_gst_string_take_and_wrap (gchar * s)
3901 {
3902   gchar *out;
3903   gint len = gst_string_measure_wrapping (s);
3904
3905   if (G_LIKELY (len < 0))
3906     return s;
3907
3908   out = gst_string_wrap_inner (s, len);
3909   g_free (s);
3910
3911   return out;
3912 }
3913
3914 /*
3915  * This function takes a string delimited with double quotes (")
3916  * and unescapes any \xxx octal numbers.
3917  *
3918  * If sequences of \y are found where y is not in the range of
3919  * 0->3, y is copied unescaped.
3920  *
3921  * If \xyy is found where x is an octal number but y is not, an
3922  * error is encountered and %NULL is returned.
3923  *
3924  * the input string must be \0 terminated.
3925  */
3926 static gchar *
3927 gst_string_unwrap (const gchar * s)
3928 {
3929   gchar *ret;
3930   gchar *read, *write;
3931
3932   /* NULL string returns NULL */
3933   if (s == NULL)
3934     return NULL;
3935
3936   /* strings not starting with " are invalid */
3937   if (*s != '"')
3938     return NULL;
3939
3940   /* make copy of original string to hold the result. This
3941    * string will always be smaller than the original */
3942   ret = g_strdup (s);
3943   read = ret;
3944   write = ret;
3945
3946   /* need to move to the next position as we parsed the " */
3947   read++;
3948
3949   while (*read) {
3950     if (GST_ASCII_IS_STRING (*read)) {
3951       /* normal chars are just copied */
3952       *write++ = *read++;
3953     } else if (*read == '"') {
3954       /* quote marks end of string */
3955       break;
3956     } else if (*read == '\\') {
3957       /* got an escape char, move to next position to read a tripplet
3958        * of octal numbers */
3959       read++;
3960       /* is the next char a possible first octal number? */
3961       if (*read >= '0' && *read <= '3') {
3962         /* parse other 2 numbers, if one of them is not in the range of
3963          * an octal number, we error. We also catch the case where a zero
3964          * byte is found here. */
3965         if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
3966           goto beach;
3967
3968         /* now convert the octal number to a byte again. */
3969         *write++ = ((read[0] - '0') << 6) +
3970             ((read[1] - '0') << 3) + (read[2] - '0');
3971
3972         read += 3;
3973       } else {
3974         /* if we run into a \0 here, we definitely won't get a quote later */
3975         if (*read == 0)
3976           goto beach;
3977         /* else copy \X sequence */
3978         *write++ = *read++;
3979       }
3980     } else if (*read == '\0') {
3981       goto beach;
3982     } else {
3983       *write++ = *read++;
3984     }
3985   }
3986   /* if the string is not ending in " and zero terminated, we error */
3987   if (*read != '"' || read[1] != '\0')
3988     goto beach;
3989
3990   /* null terminate result string and return */
3991   *write = '\0';
3992   return ret;
3993
3994 beach:
3995   g_free (ret);
3996   return NULL;
3997 }
3998
3999 static gchar *
4000 gst_value_serialize_string (const GValue * value)
4001 {
4002   return gst_string_wrap (value->data[0].v_pointer);
4003 }
4004
4005 static gboolean
4006 gst_value_deserialize_string (GValue * dest, const gchar * s)
4007 {
4008   if (G_UNLIKELY (strcmp (s, "NULL") == 0)) {
4009     g_value_set_string (dest, NULL);
4010     return TRUE;
4011   } else if (G_LIKELY (*s != '"' || s[strlen (s) - 1] != '"')) {
4012     if (!g_utf8_validate (s, -1, NULL))
4013       return FALSE;
4014     g_value_set_string (dest, s);
4015     return TRUE;
4016   } else {
4017     /* strings delimited with double quotes should be unwrapped */
4018     gchar *str = gst_string_unwrap (s);
4019     if (G_UNLIKELY (!str))
4020       return FALSE;
4021     if (!g_utf8_validate (str, -1, NULL)) {
4022       g_free (str);
4023       return FALSE;
4024     }
4025     g_value_take_string (dest, str);
4026   }
4027
4028   return TRUE;
4029 }
4030
4031 /********
4032  * enum *
4033  ********/
4034
4035 static gint
4036 gst_value_compare_enum (const GValue * value1, const GValue * value2)
4037 {
4038   GEnumValue *en1, *en2;
4039   GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
4040   GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
4041
4042   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
4043   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
4044   en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
4045   en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
4046   g_type_class_unref (klass1);
4047   g_type_class_unref (klass2);
4048   g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
4049   g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
4050   if (en1->value < en2->value)
4051     return GST_VALUE_LESS_THAN;
4052   if (en1->value > en2->value)
4053     return GST_VALUE_GREATER_THAN;
4054
4055   return GST_VALUE_EQUAL;
4056 }
4057
4058 static gchar *
4059 gst_value_serialize_enum (const GValue * value)
4060 {
4061   GEnumValue *en;
4062   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
4063
4064   g_return_val_if_fail (klass, NULL);
4065   en = g_enum_get_value (klass, g_value_get_enum (value));
4066   g_type_class_unref (klass);
4067
4068   /* might be one of the custom formats registered later */
4069   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) {
4070     const GstFormatDefinition *format_def;
4071
4072     format_def = gst_format_get_details ((GstFormat) g_value_get_enum (value));
4073     g_return_val_if_fail (format_def != NULL, NULL);
4074     return g_strdup (format_def->description);
4075   }
4076
4077   g_return_val_if_fail (en, NULL);
4078   return g_strdup (en->value_nick);
4079 }
4080
4081 static gint
4082 gst_value_deserialize_enum_iter_cmp (const GValue * format_def_value,
4083     const gchar * s)
4084 {
4085   const GstFormatDefinition *format_def =
4086       g_value_get_pointer (format_def_value);
4087
4088   if (g_ascii_strcasecmp (s, format_def->nick) == 0)
4089     return 0;
4090
4091   return g_ascii_strcasecmp (s, format_def->description);
4092 }
4093
4094 static gboolean
4095 gst_value_deserialize_enum (GValue * dest, const gchar * s)
4096 {
4097   GEnumValue *en;
4098   gchar *endptr = NULL;
4099   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
4100
4101   g_return_val_if_fail (klass, FALSE);
4102   if (!(en = g_enum_get_value_by_name (klass, s))) {
4103     if (!(en = g_enum_get_value_by_nick (klass, s))) {
4104       gint i = strtol (s, &endptr, 0);
4105
4106       if (endptr && *endptr == '\0') {
4107         en = g_enum_get_value (klass, i);
4108       }
4109     }
4110   }
4111   g_type_class_unref (klass);
4112
4113   /* might be one of the custom formats registered later */
4114   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (dest) == GST_TYPE_FORMAT)) {
4115     GValue res = { 0, };
4116     const GstFormatDefinition *format_def;
4117     GstIterator *iter;
4118     gboolean found;
4119
4120     iter = gst_format_iterate_definitions ();
4121
4122     found = gst_iterator_find_custom (iter,
4123         (GCompareFunc) gst_value_deserialize_enum_iter_cmp, &res, (gpointer) s);
4124
4125     if (found) {
4126       format_def = g_value_get_pointer (&res);
4127       g_return_val_if_fail (format_def != NULL, FALSE);
4128       g_value_set_enum (dest, (gint) format_def->value);
4129       g_value_unset (&res);
4130     }
4131     gst_iterator_free (iter);
4132     return found;
4133   }
4134
4135   /* enum name/nick not found */
4136   if (en == NULL)
4137     return FALSE;
4138
4139   g_value_set_enum (dest, en->value);
4140   return TRUE;
4141 }
4142
4143 /********
4144  * flags *
4145  ********/
4146
4147 /* we just compare the value here */
4148 static gint
4149 gst_value_compare_gflags (const GValue * value1, const GValue * value2)
4150 {
4151   guint fl1, fl2;
4152   GFlagsClass *klass1 =
4153       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
4154   GFlagsClass *klass2 =
4155       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
4156
4157   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
4158   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
4159   fl1 = g_value_get_flags (value1);
4160   fl2 = g_value_get_flags (value2);
4161   g_type_class_unref (klass1);
4162   g_type_class_unref (klass2);
4163   if (fl1 < fl2)
4164     return GST_VALUE_LESS_THAN;
4165   if (fl1 > fl2)
4166     return GST_VALUE_GREATER_THAN;
4167
4168   return GST_VALUE_EQUAL;
4169 }
4170
4171 /* the different flags are serialized separated with a + */
4172 static gchar *
4173 gst_value_serialize_gflags (const GValue * value)
4174 {
4175   guint flags;
4176   GFlagsValue *fl;
4177   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
4178   gchar *result, *tmp;
4179   gboolean first = TRUE;
4180
4181   g_return_val_if_fail (klass, NULL);
4182
4183   flags = g_value_get_flags (value);
4184
4185   /* if no flags are set, try to serialize to the _NONE string */
4186   if (!flags) {
4187     fl = g_flags_get_first_value (klass, flags);
4188     if (fl)
4189       return g_strdup (fl->value_name);
4190     else
4191       return g_strdup ("0");
4192   }
4193
4194   /* some flags are set, so serialize one by one */
4195   result = g_strdup ("");
4196   while (flags) {
4197     fl = g_flags_get_first_value (klass, flags);
4198     if (fl == NULL) {
4199       if (flags) {
4200         g_critical ("Could not serialize invalid flags 0x%x of type %s",
4201             flags, G_VALUE_TYPE_NAME (value));
4202         g_free (result);
4203         result = g_strdup ("0");
4204       }
4205       break;
4206     }
4207
4208     tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
4209     g_free (result);
4210     result = tmp;
4211     first = FALSE;
4212
4213     /* clear flag */
4214     flags &= ~fl->value;
4215   }
4216   g_type_class_unref (klass);
4217
4218   return result;
4219 }
4220
4221 static gboolean
4222 gst_value_gflags_str_to_flags (GFlagsClass * klass, const gchar * s,
4223     guint * out_flags, guint * out_mask)
4224 {
4225   GFlagsValue *fl;
4226   gchar delimiter;
4227   const gchar *pos = NULL;
4228   const gchar *next;
4229   gchar *cur_str, *endptr;
4230   guint flags = 0;
4231   guint mask = 0;
4232   guint val;
4233
4234   g_return_val_if_fail (klass, FALSE);
4235
4236   /* split into parts delimited with + or / and
4237    * compose the set of flags and mask. */
4238   pos = s;
4239
4240   if (*pos == '\0')
4241     goto done;                  /* Empty string, nothing to do */
4242
4243   /* As a special case if the first char isn't a delimiter, assume
4244    * it's a '+' - for GFlags strings, which don't start with a
4245    * delimiter, while GFlagSet always will */
4246   if (*pos == '/' || *pos == '+') {
4247     delimiter = *pos;
4248     pos++;
4249   } else {
4250     delimiter = '+';
4251   }
4252
4253   do {
4254     /* Find the next delimiter */
4255     next = pos;
4256     while (*next != '\0' && *next != '+' && *next != '/')
4257       next++;
4258     cur_str = g_strndup (pos, next - pos);
4259
4260     if ((fl = g_flags_get_value_by_name (klass, cur_str)))
4261       val = fl->value;
4262     else if ((fl = g_flags_get_value_by_nick (klass, cur_str)))
4263       val = fl->value;
4264     else {
4265       val = strtoul (cur_str, &endptr, 0);
4266       /* direct numeric value */
4267       if (endptr == NULL || *endptr != '\0') {
4268         g_free (cur_str);
4269         return FALSE;           /* Invalid numeric or string we can't convert */
4270       }
4271     }
4272     g_free (cur_str);
4273
4274     if (val) {
4275       mask |= val;
4276       if (delimiter == '+')
4277         flags |= val;
4278     }
4279
4280     /* Advance to the next delimiter */
4281     pos = next;
4282     delimiter = *pos;
4283     pos++;
4284   } while (delimiter != '\0');
4285
4286 done:
4287   if (out_flags)
4288     *out_flags = flags;
4289   if (out_mask)
4290     *out_mask = mask;
4291
4292   return TRUE;
4293 }
4294
4295
4296 static gboolean
4297 gst_value_deserialize_gflags (GValue * dest, const gchar * s)
4298 {
4299   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
4300   gboolean res = FALSE;
4301   guint flags = 0;
4302
4303   if (gst_value_gflags_str_to_flags (klass, s, &flags, NULL)) {
4304     g_value_set_flags (dest, flags);
4305     res = TRUE;
4306   }
4307
4308   g_type_class_unref (klass);
4309
4310   return res;
4311 }
4312
4313 /*********
4314  * gtype *
4315  *********/
4316
4317 static gint
4318 gst_value_compare_gtype (const GValue * value1, const GValue * value2)
4319 {
4320   if (value1->data[0].v_pointer == value2->data[0].v_pointer)
4321     return GST_VALUE_EQUAL;
4322   return GST_VALUE_UNORDERED;
4323 }
4324
4325 static gchar *
4326 gst_value_serialize_gtype (const GValue * value)
4327 {
4328   return g_strdup (g_type_name (g_value_get_gtype (value)));
4329 }
4330
4331 static gboolean
4332 gst_value_deserialize_gtype (GValue * dest, const gchar * s)
4333 {
4334   GType t = g_type_from_name (s);
4335   gboolean ret = TRUE;
4336
4337   if (t == G_TYPE_INVALID)
4338     ret = FALSE;
4339   if (ret) {
4340     g_value_set_gtype (dest, t);
4341   }
4342   return ret;
4343 }
4344
4345 /****************
4346  * subset *
4347  ****************/
4348
4349 static gboolean
4350 gst_value_is_subset_int_range_int_range (const GValue * value1,
4351     const GValue * value2)
4352 {
4353   gint gcd;
4354
4355   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value1), FALSE);
4356   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value2), FALSE);
4357
4358   if (INT_RANGE_MIN (value1) * INT_RANGE_STEP (value1) <
4359       INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2))
4360     return FALSE;
4361   if (INT_RANGE_MAX (value1) * INT_RANGE_STEP (value1) >
4362       INT_RANGE_MAX (value2) * INT_RANGE_STEP (value2))
4363     return FALSE;
4364
4365   if (INT_RANGE_MIN (value2) == INT_RANGE_MAX (value2)) {
4366     if ((INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2)) %
4367         INT_RANGE_STEP (value1))
4368       return FALSE;
4369     return TRUE;
4370   }
4371
4372   gcd =
4373       gst_util_greatest_common_divisor (INT_RANGE_STEP (value1),
4374       INT_RANGE_STEP (value2));
4375   if (gcd != MIN (INT_RANGE_STEP (value1), INT_RANGE_STEP (value2)))
4376     return FALSE;
4377
4378   return TRUE;
4379 }
4380
4381 static gboolean
4382 gst_value_is_subset_int64_range_int64_range (const GValue * value1,
4383     const GValue * value2)
4384 {
4385   gint64 gcd;
4386
4387   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value1), FALSE);
4388   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value2), FALSE);
4389
4390   if (INT64_RANGE_MIN (value1) < INT64_RANGE_MIN (value2))
4391     return FALSE;
4392   if (INT64_RANGE_MAX (value1) > INT64_RANGE_MAX (value2))
4393     return FALSE;
4394
4395   if (INT64_RANGE_MIN (value2) == INT64_RANGE_MAX (value2)) {
4396     if ((INT64_RANGE_MIN (value2) * INT64_RANGE_STEP (value2)) %
4397         INT64_RANGE_STEP (value1))
4398       return FALSE;
4399     return TRUE;
4400   }
4401
4402   gcd =
4403       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (value1),
4404       INT64_RANGE_STEP (value2));
4405   if (gcd != MIN (INT64_RANGE_STEP (value1), INT64_RANGE_STEP (value2)))
4406     return FALSE;
4407
4408   return TRUE;
4409 }
4410
4411 /* A flag set is a subset of another if the superset allows the
4412  * flags of the subset */
4413 static gboolean
4414 gst_value_is_subset_flagset_flagset (const GValue * value1,
4415     const GValue * value2)
4416 {
4417   guint f1, f2;
4418   guint m1, m2;
4419
4420   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value1), FALSE);
4421   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value2), FALSE);
4422
4423   f1 = value1->data[0].v_uint;
4424   f2 = value2->data[0].v_uint;
4425
4426   m1 = value1->data[1].v_uint;
4427   m2 = value2->data[1].v_uint;
4428
4429   /* Not a subset if masked bits of superset disagree */
4430   if ((f1 & m1) != (f2 & (m1 & m2)))
4431     return FALSE;
4432
4433   return TRUE;
4434 }
4435
4436 static gboolean
4437 gst_value_is_subset_structure_structure (const GValue * value1,
4438     const GValue * value2)
4439 {
4440   const GstStructure *s1, *s2;
4441
4442   g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (value1), FALSE);
4443   g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (value2), FALSE);
4444
4445   s1 = gst_value_get_structure (value1);
4446   s2 = gst_value_get_structure (value2);
4447
4448   return gst_structure_is_subset (s1, s2);
4449 }
4450
4451 static gboolean
4452 gst_value_is_subset_list_list (const GValue * value1, const GValue * value2)
4453 {
4454   GstValueList *vlist1 = VALUE_LIST_ARRAY (value1);
4455   GstValueList *vlist2 = VALUE_LIST_ARRAY (value2);
4456   gint it1, len1, it2, len2;
4457
4458   len1 = vlist1->len;
4459   len2 = vlist2->len;
4460
4461   /* A list can't be a subset of a smaller list */
4462   if (len1 > len2)
4463     return FALSE;
4464
4465   /* Check if all elements of the first list are within the 2nd list */
4466   for (it1 = 0; it1 < len1; it1++) {
4467     const GValue *child1 = &vlist1->fields[it1];
4468     gboolean seen = FALSE;
4469
4470     for (it2 = 0; it2 < len2; it2++) {
4471       const GValue *child2 = &vlist2->fields[it2];
4472       if (gst_value_compare (child1, child2) == GST_VALUE_EQUAL) {
4473         seen = TRUE;
4474         break;
4475       }
4476     }
4477     if (!seen)
4478       return FALSE;
4479   }
4480
4481   return TRUE;
4482 }
4483
4484 static gboolean
4485 gst_value_is_subset_list (const GValue * value1, const GValue * value2)
4486 {
4487   GstValueList *vlist2 = VALUE_LIST_ARRAY (value2);
4488   gint it2, len2;
4489
4490   len2 = vlist2->len;
4491
4492   /* Check whether value1 is within the list */
4493   for (it2 = 0; it2 < len2; it2++) {
4494     const GValue *child2 = &vlist2->fields[it2];
4495     if (gst_value_compare (value1, child2) == GST_VALUE_EQUAL) {
4496       return TRUE;
4497     }
4498   }
4499
4500   return FALSE;
4501 }
4502
4503 /**
4504  * gst_value_is_subset:
4505  * @value1: a #GValue
4506  * @value2: a #GValue
4507  *
4508  * Check that @value1 is a subset of @value2.
4509  *
4510  * Return: %TRUE is @value1 is a subset of @value2
4511  */
4512 gboolean
4513 gst_value_is_subset (const GValue * value1, const GValue * value2)
4514 {
4515   GType type1 = G_VALUE_TYPE (value1);
4516   GType type2 = G_VALUE_TYPE (value2);
4517
4518   /* special case for int/int64 ranges, since we cannot compute
4519      the difference for those when they have different steps,
4520      and it's actually a lot simpler to compute whether a range
4521      is a subset of another. */
4522   if (GST_VALUE_HOLDS_INT_RANGE (value1) && GST_VALUE_HOLDS_INT_RANGE (value2)) {
4523     return gst_value_is_subset_int_range_int_range (value1, value2);
4524   } else if (GST_VALUE_HOLDS_INT64_RANGE (value1)
4525       && GST_VALUE_HOLDS_INT64_RANGE (value2)) {
4526     return gst_value_is_subset_int64_range_int64_range (value1, value2);
4527   } else if (GST_VALUE_HOLDS_FLAG_SET (value1) &&
4528       GST_VALUE_HOLDS_FLAG_SET (value2)) {
4529     return gst_value_is_subset_flagset_flagset (value1, value2);
4530   } else if (GST_VALUE_HOLDS_STRUCTURE (value1)
4531       && GST_VALUE_HOLDS_STRUCTURE (value2)) {
4532     return gst_value_is_subset_structure_structure (value1, value2);
4533   } else if (type2 == GST_TYPE_LIST) {
4534     if (type1 == GST_TYPE_LIST)
4535       return gst_value_is_subset_list_list (value1, value2);
4536     return gst_value_is_subset_list (value1, value2);
4537   }
4538
4539   /*
4540    * 1 - [1,2] = empty
4541    * -> !subset
4542    *
4543    * [1,2] - 1 = 2
4544    *  -> 1 - [1,2] = empty
4545    *  -> subset
4546    *
4547    * [1,3] - [1,2] = 3
4548    * -> [1,2] - [1,3] = empty
4549    * -> subset
4550    *
4551    * {1,2} - {1,3} = 2
4552    * -> {1,3} - {1,2} = 3
4553    * -> !subset
4554    *
4555    *  First caps subtraction needs to return a non-empty set, second
4556    *  subtractions needs to give en empty set.
4557    *  Both substractions are switched below, as it's faster that way.
4558    */
4559   if (!gst_value_subtract (NULL, value1, value2)) {
4560     if (gst_value_subtract (NULL, value2, value1)) {
4561       return TRUE;
4562     }
4563   }
4564   return FALSE;
4565 }
4566
4567 /*********
4568  * union *
4569  *********/
4570
4571 static gboolean
4572 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
4573     const GValue * src2)
4574 {
4575   gint v = src1->data[0].v_int;
4576
4577   /* check if it's already in the range */
4578   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= v &&
4579       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= v &&
4580       v % INT_RANGE_STEP (src2) == 0) {
4581     if (dest)
4582       gst_value_init_and_copy (dest, src2);
4583     return TRUE;
4584   }
4585
4586   /* check if it extends the range */
4587   if (v == (INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2)) {
4588     if (dest) {
4589       guint64 new_min = INT_RANGE_MIN (src2) - 1;
4590       guint64 new_max = INT_RANGE_MAX (src2);
4591
4592       gst_value_init_and_copy (dest, src2);
4593       dest->data[0].v_uint64 = (new_min << 32) | (new_max);
4594     }
4595     return TRUE;
4596   }
4597   if (v == (INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2)) {
4598     if (dest) {
4599       guint64 new_min = INT_RANGE_MIN (src2);
4600       guint64 new_max = INT_RANGE_MAX (src2) + 1;
4601
4602       gst_value_init_and_copy (dest, src2);
4603       dest->data[0].v_uint64 = (new_min << 32) | (new_max);
4604     }
4605     return TRUE;
4606   }
4607
4608   return FALSE;
4609 }
4610
4611 static gboolean
4612 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
4613     const GValue * src2)
4614 {
4615   /* We can union in several special cases:
4616      1 - one is a subset of another
4617      2 - same step and not disjoint
4618      3 - different step, at least one with one value which matches a 'next' or 'previous'
4619      - anything else ?
4620    */
4621
4622   /* 1 - subset */
4623   if (gst_value_is_subset_int_range_int_range (src1, src2)) {
4624     if (dest)
4625       gst_value_init_and_copy (dest, src2);
4626     return TRUE;
4627   }
4628   if (gst_value_is_subset_int_range_int_range (src2, src1)) {
4629     if (dest)
4630       gst_value_init_and_copy (dest, src1);
4631     return TRUE;
4632   }
4633
4634   /* 2 - same step and not disjoint */
4635   if (INT_RANGE_STEP (src1) == INT_RANGE_STEP (src2)) {
4636     if ((INT_RANGE_MIN (src1) <= INT_RANGE_MAX (src2) + 1 &&
4637             INT_RANGE_MAX (src1) >= INT_RANGE_MIN (src2) - 1) ||
4638         (INT_RANGE_MIN (src2) <= INT_RANGE_MAX (src1) + 1 &&
4639             INT_RANGE_MAX (src2) >= INT_RANGE_MIN (src1) - 1)) {
4640       if (dest) {
4641         gint step = INT_RANGE_STEP (src1);
4642         gint min = step * MIN (INT_RANGE_MIN (src1), INT_RANGE_MIN (src2));
4643         gint max = step * MAX (INT_RANGE_MAX (src1), INT_RANGE_MAX (src2));
4644         g_value_init (dest, GST_TYPE_INT_RANGE);
4645         gst_value_set_int_range_step (dest, min, max, step);
4646       }
4647       return TRUE;
4648     }
4649   }
4650
4651   /* 3 - single value matches next or previous */
4652   if (INT_RANGE_STEP (src1) != INT_RANGE_STEP (src2)) {
4653     gint n1 = INT_RANGE_MAX (src1) - INT_RANGE_MIN (src1) + 1;
4654     gint n2 = INT_RANGE_MAX (src2) - INT_RANGE_MIN (src2) + 1;
4655     if (n1 == 1 || n2 == 1) {
4656       const GValue *range_value = NULL;
4657       gint scalar = 0;
4658       if (n1 == 1) {
4659         range_value = src2;
4660         scalar = INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1);
4661       } else if (n2 == 1) {
4662         range_value = src1;
4663         scalar = INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2);
4664       }
4665
4666       if (scalar ==
4667           (INT_RANGE_MIN (range_value) - 1) * INT_RANGE_STEP (range_value)) {
4668         if (dest) {
4669           guint64 new_min = (guint)
4670               ((INT_RANGE_MIN (range_value) -
4671                   1) * INT_RANGE_STEP (range_value));
4672           guint64 new_max = (guint)
4673               (INT_RANGE_MAX (range_value) * INT_RANGE_STEP (range_value));
4674
4675           gst_value_init_and_copy (dest, range_value);
4676           dest->data[0].v_uint64 = (new_min << 32) | (new_max);
4677         }
4678         return TRUE;
4679       } else if (scalar ==
4680           (INT_RANGE_MAX (range_value) + 1) * INT_RANGE_STEP (range_value)) {
4681         if (dest) {
4682           guint64 new_min = (guint)
4683               (INT_RANGE_MIN (range_value) * INT_RANGE_STEP (range_value));
4684           guint64 new_max = (guint)
4685               ((INT_RANGE_MAX (range_value) +
4686                   1) * INT_RANGE_STEP (range_value));
4687           gst_value_init_and_copy (dest, range_value);
4688           dest->data[0].v_uint64 = (new_min << 32) | (new_max);
4689         }
4690         return TRUE;
4691       }
4692     }
4693   }
4694
4695   /* If we get there, we did not find a way to make a union that can be
4696      represented with our simplistic model. */
4697   return FALSE;
4698 }
4699
4700 static gboolean
4701 gst_value_union_flagset_flagset (GValue * dest, const GValue * src1,
4702     const GValue * src2)
4703 {
4704   /* We can union 2 flag sets where they do not disagree on
4705    * required (masked) flag bits */
4706   guint64 f1, f2;
4707   guint64 m1, m2;
4708
4709   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src1), FALSE);
4710   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src2), FALSE);
4711
4712   f1 = src1->data[0].v_uint;
4713   f2 = src2->data[0].v_uint;
4714
4715   m1 = src1->data[1].v_uint;
4716   m2 = src2->data[1].v_uint;
4717
4718   /* Can't union if masked bits disagree */
4719   if ((f1 & (m1 & m2)) != (f2 & (m1 & m2)))
4720     return FALSE;
4721
4722   if (dest) {
4723     g_value_init (dest, GST_TYPE_FLAG_SET);
4724     /* Copy masked bits from src2 to src1 */
4725     f1 &= ~m2;
4726     f1 |= (f2 & m2);
4727     m1 |= m2;
4728     gst_value_set_flagset (dest, f1, m1);
4729   }
4730
4731   return TRUE;
4732 }
4733
4734 /* iterating over the result taking the union with the other structure's value */
4735 static gboolean
4736 structure_field_union_into (GQuark field_id, GValue * val, gpointer user_data)
4737 {
4738   GstStructure *other = user_data;
4739   const GValue *other_value;
4740   GValue res_value = G_VALUE_INIT;
4741
4742   other_value = gst_structure_id_get_value (other, field_id);
4743   /* no value in the other struct, just keep this value */
4744   if (!other_value)
4745     return TRUE;
4746
4747   if (!gst_value_union (&res_value, val, other_value))
4748     return FALSE;
4749
4750   g_value_unset (val);
4751   gst_value_move (val, &res_value);
4752   return TRUE;
4753 }
4754
4755 /* iterating over the other source structure adding missing values */
4756 static gboolean
4757 structure_field_union_from (GQuark field_id, const GValue * other_val,
4758     gpointer user_data)
4759 {
4760   GstStructure *result = user_data;
4761   const GValue *result_value;
4762
4763   result_value = gst_structure_id_get_value (result, field_id);
4764   if (!result_value)
4765     gst_structure_id_set_value (result, field_id, other_val);
4766
4767   return TRUE;
4768 }
4769
4770 static gboolean
4771 gst_value_union_structure_structure (GValue * dest, const GValue * src1,
4772     const GValue * src2)
4773 {
4774   const GstStructure *s1, *s2;
4775   GstStructure *result;
4776   gboolean ret;
4777
4778   g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (src1), FALSE);
4779   g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (src2), FALSE);
4780
4781   s1 = gst_value_get_structure (src1);
4782   s2 = gst_value_get_structure (src2);
4783
4784   /* Can't join two structures with different names into a single structure */
4785   if (!gst_structure_has_name (s1, gst_structure_get_name (s2))) {
4786     gst_value_list_concat (dest, src1, src2);
4787     return TRUE;
4788   }
4789
4790   result = gst_structure_copy (s1);
4791   ret =
4792       gst_structure_map_in_place (result, structure_field_union_into,
4793       (gpointer) s2);
4794   if (!ret)
4795     goto out;
4796   ret =
4797       gst_structure_foreach (s2, structure_field_union_from, (gpointer) result);
4798
4799   if (ret) {
4800     g_value_init (dest, GST_TYPE_STRUCTURE);
4801     gst_value_set_structure (dest, result);
4802   }
4803
4804 out:
4805   gst_structure_free (result);
4806   return ret;
4807 }
4808
4809 /****************
4810  * intersection *
4811  ****************/
4812
4813 static gboolean
4814 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
4815     const GValue * src2)
4816 {
4817   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= src1->data[0].v_int &&
4818       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= src1->data[0].v_int &&
4819       src1->data[0].v_int % INT_RANGE_STEP (src2) == 0) {
4820     if (dest)
4821       gst_value_init_and_copy (dest, src1);
4822     return TRUE;
4823   }
4824
4825   return FALSE;
4826 }
4827
4828 static gboolean
4829 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
4830     const GValue * src2)
4831 {
4832   gint min;
4833   gint max;
4834   gint step;
4835
4836   step =
4837       INT_RANGE_STEP (src1) /
4838       gst_util_greatest_common_divisor (INT_RANGE_STEP (src1),
4839       INT_RANGE_STEP (src2));
4840   if (G_MAXINT32 / INT_RANGE_STEP (src2) < step)
4841     return FALSE;
4842   step *= INT_RANGE_STEP (src2);
4843
4844   min =
4845       MAX (INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1),
4846       INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2));
4847   min = (min + step - 1) / step * step;
4848   max =
4849       MIN (INT_RANGE_MAX (src1) * INT_RANGE_STEP (src1),
4850       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2));
4851   max = max / step * step;
4852
4853   if (min < max) {
4854     if (dest) {
4855       g_value_init (dest, GST_TYPE_INT_RANGE);
4856       gst_value_set_int_range_step (dest, min, max, step);
4857     }
4858     return TRUE;
4859   }
4860   if (min == max) {
4861     if (dest) {
4862       g_value_init (dest, G_TYPE_INT);
4863       g_value_set_int (dest, min);
4864     }
4865     return TRUE;
4866   }
4867
4868   return FALSE;
4869 }
4870
4871 #define INT64_RANGE_MIN_VAL(v) (INT64_RANGE_MIN (v) * INT64_RANGE_STEP (v))
4872 #define INT64_RANGE_MAX_VAL(v) (INT64_RANGE_MAX (v) * INT64_RANGE_STEP (v))
4873
4874 static gboolean
4875 gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1,
4876     const GValue * src2)
4877 {
4878   if (INT64_RANGE_MIN_VAL (src2) <= src1->data[0].v_int64 &&
4879       INT64_RANGE_MAX_VAL (src2) >= src1->data[0].v_int64 &&
4880       src1->data[0].v_int64 % INT64_RANGE_STEP (src2) == 0) {
4881     if (dest)
4882       gst_value_init_and_copy (dest, src1);
4883     return TRUE;
4884   }
4885
4886   return FALSE;
4887 }
4888
4889 static gboolean
4890 gst_value_intersect_int64_range_int64_range (GValue * dest, const GValue * src1,
4891     const GValue * src2)
4892 {
4893   gint64 min;
4894   gint64 max;
4895   gint64 step;
4896
4897   step =
4898       INT64_RANGE_STEP (src1) /
4899       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (src1),
4900       INT64_RANGE_STEP (src2));
4901   if (G_MAXINT64 / INT64_RANGE_STEP (src2) < step)
4902     return FALSE;
4903   step *= INT64_RANGE_STEP (src2);
4904
4905   min =
4906       MAX (INT64_RANGE_MIN (src1) * INT64_RANGE_STEP (src1),
4907       INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2));
4908   min = (min + step - 1) / step * step;
4909   max =
4910       MIN (INT64_RANGE_MAX (src1) * INT64_RANGE_STEP (src1),
4911       INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2));
4912   max = max / step * step;
4913
4914   if (min < max) {
4915     if (dest) {
4916       g_value_init (dest, GST_TYPE_INT64_RANGE);
4917       gst_value_set_int64_range_step (dest, min, max, step);
4918     }
4919     return TRUE;
4920   }
4921   if (min == max) {
4922     if (dest) {
4923       g_value_init (dest, G_TYPE_INT64);
4924       g_value_set_int64 (dest, min);
4925     }
4926     return TRUE;
4927   }
4928
4929   return FALSE;
4930 }
4931
4932 static gboolean
4933 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
4934     const GValue * src2)
4935 {
4936   if (src2->data[0].v_double <= src1->data[0].v_double &&
4937       src2->data[1].v_double >= src1->data[0].v_double) {
4938     if (dest)
4939       gst_value_init_and_copy (dest, src1);
4940     return TRUE;
4941   }
4942
4943   return FALSE;
4944 }
4945
4946 static gboolean
4947 gst_value_intersect_double_range_double_range (GValue * dest,
4948     const GValue * src1, const GValue * src2)
4949 {
4950   gdouble min;
4951   gdouble max;
4952
4953   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
4954   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
4955
4956   if (min < max) {
4957     if (dest) {
4958       g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
4959       gst_value_set_double_range (dest, min, max);
4960     }
4961     return TRUE;
4962   }
4963   if (min == max) {
4964     if (dest) {
4965       g_value_init (dest, G_TYPE_DOUBLE);
4966       g_value_set_int (dest, (int) min);
4967     }
4968     return TRUE;
4969   }
4970
4971   return FALSE;
4972 }
4973
4974 static gboolean
4975 gst_value_intersect_list_list (GValue * dest, const GValue * value1,
4976     const GValue * value2)
4977 {
4978   guint8 tmpfield[16];          /* Check up to 128 values */
4979   guint8 *bitfield;
4980   gboolean alloc_bitfield = FALSE;
4981   gboolean res = FALSE;
4982   GValue *tmp;
4983   GType type1, type2;
4984   guint it1, len1, start2, it2, len2, itar;
4985   GstValueList *vlist = NULL;
4986
4987   /* If they don't have the same basic type, all bets are off :) */
4988   if (!gst_value_list_or_array_get_basic_type (value1, &type1) ||
4989       !gst_value_list_or_array_get_basic_type (value2, &type2) ||
4990       type1 != type2)
4991     return FALSE;
4992
4993   len1 = VALUE_LIST_SIZE (value1);
4994   len2 = VALUE_LIST_SIZE (value2);
4995
4996   /* Fast-path with no dest (i.e. only interested in knowing whether
4997    * both lists intersected without wanting the result) */
4998   if (!dest) {
4999     for (it1 = 0; it1 < len1; it1++) {
5000       const GValue *item1 = VALUE_LIST_GET_VALUE (value1, it1);
5001       for (it2 = 0; it2 < len2; it2++) {
5002         const GValue *item2 = VALUE_LIST_GET_VALUE (value2, it2);
5003         if (gst_value_intersect (NULL, item1, item2)) {
5004           res = TRUE;
5005           goto beach;
5006         }
5007       }
5008     }
5009     goto beach;
5010   }
5011 #define is_visited(idx) (bitfield[(idx) >> 3]    & (1 << ((idx) & 0x7)))
5012 #define mark_visited(idx) (bitfield[(idx) >> 3] |= (1 << ((idx) & 0x7)))
5013
5014   /* Bitfield to avoid double-visiting */
5015   if (G_UNLIKELY (len2 > 128)) {
5016     alloc_bitfield = TRUE;
5017     bitfield = g_malloc0 ((len2 / 8) + 1);
5018     GST_CAT_LOG (GST_CAT_PERFORMANCE,
5019         "Allocation for GstValueList with more than 128 members");
5020   } else {
5021     bitfield = &tmpfield[0];
5022     memset (bitfield, 0, 16);
5023   }
5024
5025
5026   /* When doing list<->list intersections, there is a greater
5027    * probability of ending up with a list than with a single value.
5028    * Furthermore, the biggest that list can be will the smallest list
5029    * (i.e. intersects fully).
5030    * Therefore we pre-allocate a GstValueList of that size. */
5031   vlist = _gst_value_list_new (MIN (len1, len2));
5032
5033   itar = 0;
5034   tmp = &vlist->fields[0];
5035   start2 = 0;
5036
5037   for (it1 = 0; it1 < len1; it1++) {
5038     const GValue *item1 = VALUE_LIST_GET_VALUE (value1, it1);
5039     for (it2 = start2; it2 < len2; it2++) {
5040       const GValue *item2;
5041       if (is_visited (it2))
5042         continue;
5043       item2 = VALUE_LIST_GET_VALUE (value2, it2);
5044
5045       if (gst_value_intersect (tmp, item1, item2)) {
5046         res = TRUE;
5047         mark_visited (it2);
5048         /* Increment our inner-loop starting point */
5049         if (it2 == start2)
5050           start2++;
5051
5052         /* Move our collection value */
5053         itar += 1;
5054         tmp = &vlist->fields[itar];
5055         vlist->len += 1;
5056
5057         /* We can stop iterating the second part now that we've matched */
5058         break;
5059       }
5060     }
5061   }
5062
5063 #undef is_visited
5064 #undef mark_visited
5065
5066   if (res) {
5067     /* If we end up with a single value in the list, just use that
5068      * value. Else use the list */
5069     if (vlist->len == 1) {
5070       gst_value_move (dest, &vlist->fields[0]);
5071       g_free (vlist);
5072     } else {
5073       dest->g_type = GST_TYPE_LIST;
5074       dest->data[0].v_pointer = vlist;
5075     }
5076   } else {
5077     g_free (vlist);
5078   }
5079
5080 beach:
5081   if (alloc_bitfield)
5082     g_free (bitfield);
5083   return res;
5084 }
5085
5086 static gboolean
5087 gst_value_intersect_list (GValue * dest, const GValue * value1,
5088     const GValue * value2)
5089 {
5090   guint i, size;
5091   GValue intersection = { 0, };
5092   gboolean ret = FALSE;
5093
5094   /* Use optimized list-list intersection */
5095   if (G_VALUE_TYPE (value2) == GST_TYPE_LIST) {
5096     return gst_value_intersect_list_list (dest, value1, value2);
5097   }
5098
5099   size = VALUE_LIST_SIZE (value1);
5100   for (i = 0; i < size; i++) {
5101     const GValue *cur = VALUE_LIST_GET_VALUE (value1, i);
5102
5103     /* quicker version when we don't need the resulting set */
5104     if (!dest) {
5105       if (gst_value_intersect (NULL, cur, value2)) {
5106         ret = TRUE;
5107         break;
5108       }
5109       continue;
5110     }
5111
5112     if (gst_value_intersect (&intersection, cur, value2)) {
5113       /* append value */
5114       if (!ret) {
5115         gst_value_move (dest, &intersection);
5116         ret = TRUE;
5117       } else if (GST_VALUE_HOLDS_LIST (dest)) {
5118         _gst_value_list_append_and_take_value (dest, &intersection);
5119       } else {
5120         GValue temp;
5121
5122         gst_value_move (&temp, dest);
5123         gst_value_list_merge (dest, &temp, &intersection);
5124         g_value_unset (&temp);
5125         g_value_unset (&intersection);
5126       }
5127     }
5128   }
5129
5130   return ret;
5131 }
5132
5133 static gboolean
5134 gst_value_intersect_array (GValue * dest, const GValue * src1,
5135     const GValue * src2)
5136 {
5137   guint size;
5138   guint n;
5139   GValue val = { 0 };
5140
5141   /* only works on similar-sized arrays */
5142   size = gst_value_array_get_size (src1);
5143   if (size != gst_value_array_get_size (src2))
5144     return FALSE;
5145
5146   /* quicker value when we don't need the resulting set */
5147   if (!dest) {
5148     for (n = 0; n < size; n++) {
5149       if (!gst_value_intersect (NULL, gst_value_array_get_value (src1, n),
5150               gst_value_array_get_value (src2, n))) {
5151         return FALSE;
5152       }
5153     }
5154     return TRUE;
5155   }
5156
5157   g_value_init (dest, GST_TYPE_ARRAY);
5158
5159   for (n = 0; n < size; n++) {
5160     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
5161             gst_value_array_get_value (src2, n))) {
5162       g_value_unset (dest);
5163       return FALSE;
5164     }
5165     _gst_value_array_append_and_take_value (dest, &val);
5166   }
5167
5168   return TRUE;
5169 }
5170
5171 static gboolean
5172 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
5173     const GValue * src2)
5174 {
5175   gint res1, res2;
5176   GValue *vals;
5177
5178   vals = src2->data[0].v_pointer;
5179
5180   if (vals == NULL)
5181     return FALSE;
5182
5183   res1 = gst_value_compare_fraction (&vals[0], src1);
5184   res2 = gst_value_compare_fraction (&vals[1], src1);
5185
5186   if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
5187       (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
5188     if (dest)
5189       gst_value_init_and_copy (dest, src1);
5190     return TRUE;
5191   }
5192   return FALSE;
5193 }
5194
5195 static gboolean
5196 gst_value_intersect_fraction_range_fraction_range (GValue * dest,
5197     const GValue * src1, const GValue * src2)
5198 {
5199   GValue *min;
5200   GValue *max;
5201   gint res;
5202   GValue *vals1, *vals2;
5203
5204   vals1 = src1->data[0].v_pointer;
5205   vals2 = src2->data[0].v_pointer;
5206   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
5207
5208   /* min = MAX (src1.start, src2.start) */
5209   res = gst_value_compare_fraction (&vals1[0], &vals2[0]);
5210   g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
5211   if (res == GST_VALUE_LESS_THAN)
5212     min = &vals2[0];            /* Take the max of the 2 */
5213   else
5214     min = &vals1[0];
5215
5216   /* max = MIN (src1.end, src2.end) */
5217   res = gst_value_compare_fraction (&vals1[1], &vals2[1]);
5218   g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
5219   if (res == GST_VALUE_GREATER_THAN)
5220     max = &vals2[1];            /* Take the min of the 2 */
5221   else
5222     max = &vals1[1];
5223
5224   res = gst_value_compare_fraction (min, max);
5225   g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
5226   if (res == GST_VALUE_LESS_THAN) {
5227     if (dest) {
5228       g_value_init (dest, GST_TYPE_FRACTION_RANGE);
5229       vals1 = dest->data[0].v_pointer;
5230       g_value_copy (min, &vals1[0]);
5231       g_value_copy (max, &vals1[1]);
5232     }
5233     return TRUE;
5234   }
5235   if (res == GST_VALUE_EQUAL) {
5236     if (dest)
5237       gst_value_init_and_copy (dest, min);
5238     return TRUE;
5239   }
5240
5241   return FALSE;
5242 }
5243
5244 /* Two flagsets intersect if the masked bits in both
5245  * flagsets are exactly equal */
5246 static gboolean
5247 gst_value_intersect_flagset_flagset (GValue * dest,
5248     const GValue * src1, const GValue * src2)
5249 {
5250   guint f1, f2;
5251   guint m1, m2;
5252   GType type1, type2, flagset_type;
5253
5254   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src1), FALSE);
5255   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src2), FALSE);
5256
5257   f1 = src1->data[0].v_uint;
5258   f2 = src2->data[0].v_uint;
5259
5260   m1 = src1->data[1].v_uint;
5261   m2 = src2->data[1].v_uint;
5262
5263   /* Don't intersect if masked bits disagree */
5264   if ((f1 & (m1 & m2)) != (f2 & (m1 & m2)))
5265     return FALSE;
5266
5267   /* Allow intersection with the generic FlagSet type, on one
5268    * side, but not 2 different subtypes - that makes no sense */
5269   type1 = G_VALUE_TYPE (src1);
5270   type2 = G_VALUE_TYPE (src2);
5271   flagset_type = GST_TYPE_FLAG_SET;
5272
5273   if (type1 != type2 && type1 != flagset_type && type2 != flagset_type)
5274     return FALSE;
5275
5276   if (dest) {
5277     GType dest_type;
5278
5279     /* Prefer an output type that matches a sub-type,
5280      * rather than the generic type */
5281     if (type1 != flagset_type)
5282       dest_type = type1;
5283     else
5284       dest_type = type2;
5285
5286     g_value_init (dest, dest_type);
5287
5288     /* The compatible set is all the bits from src1 that it
5289      * cares about and all the bits from src2 that it cares
5290      * about. */
5291     dest->data[0].v_uint = (f1 & m1) | (f2 & m2);
5292     dest->data[1].v_uint = m1 | m2;
5293   }
5294
5295   return TRUE;
5296 }
5297
5298 static gboolean
5299 gst_value_intersect_structure_structure (GValue * dest,
5300     const GValue * src1, const GValue * src2)
5301 {
5302   const GstStructure *s1, *s2;
5303   GstStructure *d1;
5304
5305   s1 = gst_value_get_structure (src1);
5306   s2 = gst_value_get_structure (src2);
5307
5308   d1 = gst_structure_intersect (s1, s2);
5309   if (!d1)
5310     return FALSE;
5311
5312   if (dest) {
5313     g_value_init (dest, GST_TYPE_STRUCTURE);
5314     gst_value_set_structure (dest, d1);
5315   }
5316
5317   gst_structure_free (d1);
5318   return TRUE;
5319 }
5320
5321 /***************
5322  * subtraction *
5323  ***************/
5324
5325 static gboolean
5326 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
5327     const GValue * subtrahend)
5328 {
5329   gint min = gst_value_get_int_range_min (subtrahend);
5330   gint max = gst_value_get_int_range_max (subtrahend);
5331   gint step = gst_value_get_int_range_step (subtrahend);
5332   gint val = g_value_get_int (minuend);
5333
5334   if (step == 0)
5335     return FALSE;
5336
5337   /* subtracting a range from an int only works if the int is not in the
5338    * range */
5339   if (val < min || val > max || val % step) {
5340     /* and the result is the int */
5341     if (dest)
5342       gst_value_init_and_copy (dest, minuend);
5343     return TRUE;
5344   }
5345   return FALSE;
5346 }
5347
5348 /* creates a new int range based on input values.
5349  */
5350 static gboolean
5351 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
5352     gint max2, gint step)
5353 {
5354   GValue v1 = { 0, };
5355   GValue v2 = { 0, };
5356   GValue *pv1, *pv2;            /* yeah, hungarian! */
5357
5358   g_return_val_if_fail (step > 0, FALSE);
5359   g_return_val_if_fail (min1 % step == 0, FALSE);
5360   g_return_val_if_fail (max1 % step == 0, FALSE);
5361   g_return_val_if_fail (min2 % step == 0, FALSE);
5362   g_return_val_if_fail (max2 % step == 0, FALSE);
5363
5364   if (min1 <= max1 && min2 <= max2) {
5365     pv1 = &v1;
5366     pv2 = &v2;
5367   } else if (min1 <= max1) {
5368     pv1 = dest;
5369     pv2 = NULL;
5370   } else if (min2 <= max2) {
5371     pv1 = NULL;
5372     pv2 = dest;
5373   } else {
5374     return FALSE;
5375   }
5376
5377   if (!dest)
5378     return TRUE;
5379
5380   if (min1 < max1) {
5381     g_value_init (pv1, GST_TYPE_INT_RANGE);
5382     gst_value_set_int_range_step (pv1, min1, max1, step);
5383   } else if (min1 == max1) {
5384     g_value_init (pv1, G_TYPE_INT);
5385     g_value_set_int (pv1, min1);
5386   }
5387   if (min2 < max2) {
5388     g_value_init (pv2, GST_TYPE_INT_RANGE);
5389     gst_value_set_int_range_step (pv2, min2, max2, step);
5390   } else if (min2 == max2) {
5391     g_value_init (pv2, G_TYPE_INT);
5392     g_value_set_int (pv2, min2);
5393   }
5394
5395   if (min1 <= max1 && min2 <= max2) {
5396     gst_value_list_concat_and_take_values (dest, pv1, pv2);
5397   }
5398   return TRUE;
5399 }
5400
5401 static gboolean
5402 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
5403     const GValue * subtrahend)
5404 {
5405   gint min = gst_value_get_int_range_min (minuend);
5406   gint max = gst_value_get_int_range_max (minuend);
5407   gint step = gst_value_get_int_range_step (minuend);
5408   gint val = g_value_get_int (subtrahend);
5409
5410   g_return_val_if_fail (min < max, FALSE);
5411
5412   if (step == 0)
5413     return FALSE;
5414
5415   /* value is outside of the range, return range unchanged */
5416   if (val < min || val > max || val % step) {
5417     if (dest)
5418       gst_value_init_and_copy (dest, minuend);
5419     return TRUE;
5420   } else {
5421     /* max must be MAXINT too as val <= max */
5422     if (val >= G_MAXINT - step + 1) {
5423       max -= step;
5424       val -= step;
5425     }
5426     /* min must be MININT too as val >= max */
5427     if (val <= G_MININT + step - 1) {
5428       min += step;
5429       val += step;
5430     }
5431     if (dest)
5432       gst_value_create_new_range (dest, min, val - step, val + step, max, step);
5433   }
5434   return TRUE;
5435 }
5436
5437 static gboolean
5438 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
5439     const GValue * subtrahend)
5440 {
5441   gint min1 = gst_value_get_int_range_min (minuend);
5442   gint max1 = gst_value_get_int_range_max (minuend);
5443   gint step1 = gst_value_get_int_range_step (minuend);
5444   gint min2 = gst_value_get_int_range_min (subtrahend);
5445   gint max2 = gst_value_get_int_range_max (subtrahend);
5446   gint step2 = gst_value_get_int_range_step (subtrahend);
5447   gint step;
5448
5449   if (step1 != step2) {
5450     /* ENOIMPL */
5451     g_assert (FALSE);
5452     return FALSE;
5453   }
5454   step = step1;
5455
5456   if (step == 0)
5457     return FALSE;
5458
5459   if (max2 >= max1 && min2 <= min1) {
5460     return FALSE;
5461   } else if (max2 >= max1) {
5462     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
5463         step, 0, step);
5464   } else if (min2 <= min1) {
5465     return gst_value_create_new_range (dest, MAX (max2 + step, min1), max1,
5466         step, 0, step);
5467   } else {
5468     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
5469         MAX (max2 + step, min1), max1, step);
5470   }
5471 }
5472
5473 static gboolean
5474 gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend,
5475     const GValue * subtrahend)
5476 {
5477   gint64 min = gst_value_get_int64_range_min (subtrahend);
5478   gint64 max = gst_value_get_int64_range_max (subtrahend);
5479   gint64 step = gst_value_get_int64_range_step (subtrahend);
5480   gint64 val = g_value_get_int64 (minuend);
5481
5482   if (step == 0)
5483     return FALSE;
5484   /* subtracting a range from an int64 only works if the int64 is not in the
5485    * range */
5486   if (val < min || val > max || val % step) {
5487     /* and the result is the int64 */
5488     if (dest)
5489       gst_value_init_and_copy (dest, minuend);
5490     return TRUE;
5491   }
5492   return FALSE;
5493 }
5494
5495 /* creates a new int64 range based on input values.
5496  */
5497 static gboolean
5498 gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1,
5499     gint64 min2, gint64 max2, gint64 step)
5500 {
5501   GValue v1 = { 0, };
5502   GValue v2 = { 0, };
5503   GValue *pv1, *pv2;            /* yeah, hungarian! */
5504
5505   g_return_val_if_fail (step > 0, FALSE);
5506   g_return_val_if_fail (min1 % step == 0, FALSE);
5507   g_return_val_if_fail (max1 % step == 0, FALSE);
5508   g_return_val_if_fail (min2 % step == 0, FALSE);
5509   g_return_val_if_fail (max2 % step == 0, FALSE);
5510
5511   if (min1 <= max1 && min2 <= max2) {
5512     pv1 = &v1;
5513     pv2 = &v2;
5514   } else if (min1 <= max1) {
5515     pv1 = dest;
5516     pv2 = NULL;
5517   } else if (min2 <= max2) {
5518     pv1 = NULL;
5519     pv2 = dest;
5520   } else {
5521     return FALSE;
5522   }
5523
5524   if (!dest)
5525     return TRUE;
5526
5527   if (min1 < max1) {
5528     g_value_init (pv1, GST_TYPE_INT64_RANGE);
5529     gst_value_set_int64_range_step (pv1, min1, max1, step);
5530   } else if (min1 == max1) {
5531     g_value_init (pv1, G_TYPE_INT64);
5532     g_value_set_int64 (pv1, min1);
5533   }
5534   if (min2 < max2) {
5535     g_value_init (pv2, GST_TYPE_INT64_RANGE);
5536     gst_value_set_int64_range_step (pv2, min2, max2, step);
5537   } else if (min2 == max2) {
5538     g_value_init (pv2, G_TYPE_INT64);
5539     g_value_set_int64 (pv2, min2);
5540   }
5541
5542   if (min1 <= max1 && min2 <= max2) {
5543     gst_value_list_concat_and_take_values (dest, pv1, pv2);
5544   }
5545   return TRUE;
5546 }
5547
5548 static gboolean
5549 gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend,
5550     const GValue * subtrahend)
5551 {
5552   gint64 min = gst_value_get_int64_range_min (minuend);
5553   gint64 max = gst_value_get_int64_range_max (minuend);
5554   gint64 step = gst_value_get_int64_range_step (minuend);
5555   gint64 val = g_value_get_int64 (subtrahend);
5556
5557   g_return_val_if_fail (min < max, FALSE);
5558
5559   if (step == 0)
5560     return FALSE;
5561
5562   /* value is outside of the range, return range unchanged */
5563   if (val < min || val > max || val % step) {
5564     if (dest)
5565       gst_value_init_and_copy (dest, minuend);
5566     return TRUE;
5567   } else {
5568     /* max must be MAXINT64 too as val <= max */
5569     if (val >= G_MAXINT64 - step + 1) {
5570       max -= step;
5571       val -= step;
5572     }
5573     /* min must be MININT64 too as val >= max */
5574     if (val <= G_MININT64 + step - 1) {
5575       min += step;
5576       val += step;
5577     }
5578     if (dest)
5579       gst_value_create_new_int64_range (dest, min, val - step, val + step, max,
5580           step);
5581   }
5582   return TRUE;
5583 }
5584
5585 static gboolean
5586 gst_value_subtract_int64_range_int64_range (GValue * dest,
5587     const GValue * minuend, const GValue * subtrahend)
5588 {
5589   gint64 min1 = gst_value_get_int64_range_min (minuend);
5590   gint64 max1 = gst_value_get_int64_range_max (minuend);
5591   gint64 step1 = gst_value_get_int64_range_step (minuend);
5592   gint64 min2 = gst_value_get_int64_range_min (subtrahend);
5593   gint64 max2 = gst_value_get_int64_range_max (subtrahend);
5594   gint64 step2 = gst_value_get_int64_range_step (subtrahend);
5595   gint64 step;
5596
5597   if (step1 != step2) {
5598     /* ENOIMPL */
5599     g_assert (FALSE);
5600     return FALSE;
5601   }
5602
5603   if (step1 == 0)
5604     return FALSE;
5605
5606   step = step1;
5607
5608   if (max2 >= max1 && min2 <= min1) {
5609     return FALSE;
5610   } else if (max2 >= max1) {
5611     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
5612             max1), step, 0, step);
5613   } else if (min2 <= min1) {
5614     return gst_value_create_new_int64_range (dest, MAX (max2 + step, min1),
5615         max1, step, 0, step);
5616   } else {
5617     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
5618             max1), MAX (max2 + step, min1), max1, step);
5619   }
5620 }
5621
5622 static gboolean
5623 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
5624     const GValue * subtrahend)
5625 {
5626   gdouble min = gst_value_get_double_range_min (subtrahend);
5627   gdouble max = gst_value_get_double_range_max (subtrahend);
5628   gdouble val = g_value_get_double (minuend);
5629
5630   if (val < min || val > max) {
5631     if (dest)
5632       gst_value_init_and_copy (dest, minuend);
5633     return TRUE;
5634   }
5635   return FALSE;
5636 }
5637
5638 static gboolean
5639 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
5640     const GValue * subtrahend)
5641 {
5642   /* since we don't have open ranges, we cannot create a hole in
5643    * a double range. We return the original range */
5644   if (dest)
5645     gst_value_init_and_copy (dest, minuend);
5646   return TRUE;
5647 }
5648
5649 static gboolean
5650 gst_value_subtract_double_range_double_range (GValue * dest,
5651     const GValue * minuend, const GValue * subtrahend)
5652 {
5653   /* since we don't have open ranges, we have to approximate */
5654   /* done like with ints */
5655   gdouble min1 = gst_value_get_double_range_min (minuend);
5656   gdouble max2 = gst_value_get_double_range_max (minuend);
5657   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
5658   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
5659   GValue v1 = { 0, };
5660   GValue v2 = { 0, };
5661   GValue *pv1, *pv2;            /* yeah, hungarian! */
5662
5663   if (min1 < max1 && min2 < max2) {
5664     pv1 = &v1;
5665     pv2 = &v2;
5666   } else if (min1 < max1) {
5667     pv1 = dest;
5668     pv2 = NULL;
5669   } else if (min2 < max2) {
5670     pv1 = NULL;
5671     pv2 = dest;
5672   } else {
5673     return FALSE;
5674   }
5675
5676   if (!dest)
5677     return TRUE;
5678
5679   if (min1 < max1) {
5680     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
5681     gst_value_set_double_range (pv1, min1, max1);
5682   }
5683   if (min2 < max2) {
5684     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
5685     gst_value_set_double_range (pv2, min2, max2);
5686   }
5687
5688   if (min1 < max1 && min2 < max2) {
5689     gst_value_list_concat_and_take_values (dest, pv1, pv2);
5690   }
5691   return TRUE;
5692 }
5693
5694 static gboolean
5695 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
5696     const GValue * subtrahend)
5697 {
5698   guint i, size;
5699   GValue subtraction = { 0, };
5700   gboolean ret = FALSE;
5701
5702   size = VALUE_LIST_SIZE (minuend);
5703   for (i = 0; i < size; i++) {
5704     const GValue *cur = VALUE_LIST_GET_VALUE (minuend, i);
5705
5706     /* quicker version when we can discard the result */
5707     if (!dest) {
5708       if (gst_value_subtract (NULL, cur, subtrahend)) {
5709         ret = TRUE;
5710         break;
5711       }
5712       continue;
5713     }
5714
5715     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
5716       if (!ret) {
5717         gst_value_move (dest, &subtraction);
5718         ret = TRUE;
5719       } else if (G_VALUE_TYPE (dest) == GST_TYPE_LIST
5720           && G_VALUE_TYPE (&subtraction) != GST_TYPE_LIST) {
5721         _gst_value_list_append_and_take_value (dest, &subtraction);
5722       } else {
5723         GValue temp;
5724
5725         gst_value_move (&temp, dest);
5726         gst_value_list_concat_and_take_values (dest, &temp, &subtraction);
5727       }
5728     }
5729   }
5730   return ret;
5731 }
5732
5733 static gboolean
5734 gst_value_subtract_list (GValue * dest, const GValue * minuend,
5735     const GValue * subtrahend)
5736 {
5737   guint i, size;
5738   GValue data[2] = { {0,}, {0,} };
5739   GValue *subtraction = &data[0], *result = &data[1];
5740
5741   gst_value_init_and_copy (result, minuend);
5742   size = VALUE_LIST_SIZE (subtrahend);
5743   for (i = 0; i < size; i++) {
5744     const GValue *cur = VALUE_LIST_GET_VALUE (subtrahend, i);
5745
5746     if (gst_value_subtract (subtraction, result, cur)) {
5747       GValue *temp = result;
5748
5749       result = subtraction;
5750       subtraction = temp;
5751       g_value_unset (subtraction);
5752     } else {
5753       g_value_unset (result);
5754       return FALSE;
5755     }
5756   }
5757   if (dest) {
5758     gst_value_move (dest, result);
5759   } else {
5760     g_value_unset (result);
5761   }
5762   return TRUE;
5763 }
5764
5765 static gboolean
5766 gst_value_subtract_fraction_fraction_range (GValue * dest,
5767     const GValue * minuend, const GValue * subtrahend)
5768 {
5769   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
5770   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
5771
5772   /* subtracting a range from an fraction only works if the fraction
5773    * is not in the range */
5774   if (gst_value_compare_fraction (minuend, min) == GST_VALUE_LESS_THAN ||
5775       gst_value_compare_fraction (minuend, max) == GST_VALUE_GREATER_THAN) {
5776     /* and the result is the value */
5777     if (dest)
5778       gst_value_init_and_copy (dest, minuend);
5779     return TRUE;
5780   }
5781
5782   return FALSE;
5783 }
5784
5785 static gboolean
5786 gst_value_subtract_fraction_range_fraction (GValue * dest,
5787     const GValue * minuend, const GValue * subtrahend)
5788 {
5789   /* since we don't have open ranges, we cannot create a hole in
5790    * a range. We return the original range */
5791   if (dest)
5792     gst_value_init_and_copy (dest, minuend);
5793   return TRUE;
5794 }
5795
5796 static gboolean
5797 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
5798     const GValue * minuend, const GValue * subtrahend)
5799 {
5800   /* since we don't have open ranges, we have to approximate */
5801   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
5802   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
5803   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
5804   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
5805   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
5806   gint cmp1, cmp2;
5807   GValue v1 = { 0, };
5808   GValue v2 = { 0, };
5809   GValue *pv1, *pv2;            /* yeah, hungarian! */
5810
5811   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
5812   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
5813
5814   cmp1 = gst_value_compare_fraction (max2, max1);
5815   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
5816   if (cmp1 == GST_VALUE_LESS_THAN)
5817     max1 = max2;
5818   cmp1 = gst_value_compare_fraction (min1, min2);
5819   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
5820   if (cmp1 == GST_VALUE_GREATER_THAN)
5821     min2 = min1;
5822
5823   cmp1 = gst_value_compare_fraction (min1, max1);
5824   cmp2 = gst_value_compare_fraction (min2, max2);
5825
5826   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
5827     pv1 = &v1;
5828     pv2 = &v2;
5829   } else if (cmp1 == GST_VALUE_LESS_THAN) {
5830     pv1 = dest;
5831     pv2 = NULL;
5832   } else if (cmp2 == GST_VALUE_LESS_THAN) {
5833     pv1 = NULL;
5834     pv2 = dest;
5835   } else {
5836     return FALSE;
5837   }
5838
5839   if (!dest)
5840     return TRUE;
5841
5842   if (cmp1 == GST_VALUE_LESS_THAN) {
5843     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
5844     gst_value_set_fraction_range (pv1, min1, max1);
5845   }
5846   if (cmp2 == GST_VALUE_LESS_THAN) {
5847     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
5848     gst_value_set_fraction_range (pv2, min2, max2);
5849   }
5850
5851   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
5852     gst_value_list_concat_and_take_values (dest, pv1, pv2);
5853   }
5854   return TRUE;
5855 }
5856
5857 /**************
5858  * comparison *
5859  **************/
5860
5861 /*
5862  * gst_value_get_compare_func:
5863  * @value1: a value to get the compare function for
5864  *
5865  * Determines the compare function to be used with values of the same type as
5866  * @value1. The function can be given to gst_value_compare_with_func().
5867  *
5868  * Returns: A #GstValueCompareFunc value
5869  */
5870 static GstValueCompareFunc
5871 gst_value_get_compare_func (const GValue * value1)
5872 {
5873   GstValueTable *table, *best = NULL;
5874   guint i;
5875   GType type1;
5876
5877   type1 = G_VALUE_TYPE (value1);
5878
5879   /* this is a fast check */
5880   best = gst_value_hash_lookup_type (type1);
5881
5882   /* slower checks */
5883   if (G_UNLIKELY (!best || !best->compare)) {
5884     guint len = gst_value_table->len;
5885
5886     best = NULL;
5887     for (i = 0; i < len; i++) {
5888       table = &g_array_index (gst_value_table, GstValueTable, i);
5889       if (table->compare && g_type_is_a (type1, table->type)) {
5890         if (!best || g_type_is_a (table->type, best->type))
5891           best = table;
5892       }
5893     }
5894   }
5895   if (G_LIKELY (best))
5896     return best->compare;
5897
5898   return NULL;
5899 }
5900
5901 static inline gboolean
5902 gst_value_can_compare_unchecked (const GValue * value1, const GValue * value2)
5903 {
5904   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
5905     return FALSE;
5906
5907   return gst_value_get_compare_func (value1) != NULL;
5908 }
5909
5910 /**
5911  * gst_value_can_compare:
5912  * @value1: a value to compare
5913  * @value2: another value to compare
5914  *
5915  * Determines if @value1 and @value2 can be compared.
5916  *
5917  * Returns: %TRUE if the values can be compared
5918  */
5919 gboolean
5920 gst_value_can_compare (const GValue * value1, const GValue * value2)
5921 {
5922   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
5923   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
5924
5925   return gst_value_can_compare_unchecked (value1, value2);
5926 }
5927
5928 static gboolean
5929 gst_value_list_equals_range (const GValue * list, const GValue * value)
5930 {
5931   const GValue *first;
5932   guint list_size, n;
5933
5934   /* TODO: compare against an empty list ? No type though... */
5935   list_size = VALUE_LIST_SIZE (list);
5936   if (list_size == 0)
5937     return FALSE;
5938
5939   /* compare the basic types - they have to match */
5940   first = VALUE_LIST_GET_VALUE (list, 0);
5941 #define CHECK_TYPES(type,prefix) \
5942   ((first) && G_VALUE_TYPE(first) == prefix##_TYPE_##type && GST_VALUE_HOLDS_##type##_RANGE (value))
5943   if (CHECK_TYPES (INT, G)) {
5944     const gint rmin = gst_value_get_int_range_min (value);
5945     const gint rmax = gst_value_get_int_range_max (value);
5946     const gint rstep = gst_value_get_int_range_step (value);
5947     if (rstep == 0)
5948       return FALSE;
5949     /* note: this will overflow for min 0 and max INT_MAX, but this
5950        would only be equal to a list of INT_MAX elements, which seems
5951        very unlikely */
5952     if (list_size != rmax / rstep - rmin / rstep + 1)
5953       return FALSE;
5954     for (n = 0; n < list_size; ++n) {
5955       gint v = g_value_get_int (VALUE_LIST_GET_VALUE (list, n));
5956       if (v < rmin || v > rmax || v % rstep) {
5957         return FALSE;
5958       }
5959     }
5960     return TRUE;
5961   } else if (CHECK_TYPES (INT64, G)) {
5962     const gint64 rmin = gst_value_get_int64_range_min (value);
5963     const gint64 rmax = gst_value_get_int64_range_max (value);
5964     const gint64 rstep = gst_value_get_int64_range_step (value);
5965     GST_DEBUG ("List/range of int64s");
5966     if (rstep == 0)
5967       return FALSE;
5968     if (list_size != rmax / rstep - rmin / rstep + 1)
5969       return FALSE;
5970     for (n = 0; n < list_size; ++n) {
5971       gint64 v = g_value_get_int64 (VALUE_LIST_GET_VALUE (list, n));
5972       if (v < rmin || v > rmax || v % rstep)
5973         return FALSE;
5974     }
5975     return TRUE;
5976   }
5977 #undef CHECK_TYPES
5978
5979   /* other combinations don't make sense for equality */
5980   return FALSE;
5981 }
5982
5983 /* "Pure" variant of gst_value_compare which is guaranteed to
5984  * not have list arguments and therefore does basic comparisons
5985  */
5986 static inline gint
5987 _gst_value_compare_nolist (const GValue * value1, const GValue * value2)
5988 {
5989   GstValueCompareFunc compare;
5990
5991   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
5992     return GST_VALUE_UNORDERED;
5993
5994   compare = gst_value_get_compare_func (value1);
5995   if (compare) {
5996     return compare (value1, value2);
5997   }
5998
5999   g_critical ("unable to compare values of type %s\n",
6000       g_type_name (G_VALUE_TYPE (value1)));
6001   return GST_VALUE_UNORDERED;
6002 }
6003
6004 /**
6005  * gst_value_compare:
6006  * @value1: a value to compare
6007  * @value2: another value to compare
6008  *
6009  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
6010  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
6011  * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned.
6012  * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned.
6013  * If the values are equal, GST_VALUE_EQUAL is returned.
6014  *
6015  * Returns: comparison result
6016  */
6017 gint
6018 gst_value_compare (const GValue * value1, const GValue * value2)
6019 {
6020   gboolean value1_is_list;
6021   gboolean value2_is_list;
6022
6023   g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN);
6024   g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN);
6025
6026   value1_is_list = G_VALUE_TYPE (value1) == GST_TYPE_LIST;
6027   value2_is_list = G_VALUE_TYPE (value2) == GST_TYPE_LIST;
6028
6029   /* Special cases: lists and scalar values ("{ 1 }" and "1" are equal),
6030      as well as lists and ranges ("{ 1, 2 }" and "[ 1, 2 ]" are equal) */
6031   if (value1_is_list && !value2_is_list) {
6032     gint i, n, ret;
6033
6034     if (gst_value_list_equals_range (value1, value2)) {
6035       return GST_VALUE_EQUAL;
6036     }
6037
6038     n = gst_value_list_get_size (value1);
6039     if (n == 0)
6040       return GST_VALUE_UNORDERED;
6041
6042     for (i = 0; i < n; i++) {
6043       const GValue *elt;
6044
6045       elt = gst_value_list_get_value (value1, i);
6046       ret = gst_value_compare (elt, value2);
6047       if (ret != GST_VALUE_EQUAL && n == 1)
6048         return ret;
6049       else if (ret != GST_VALUE_EQUAL)
6050         return GST_VALUE_UNORDERED;
6051     }
6052
6053     return GST_VALUE_EQUAL;
6054   } else if (value2_is_list && !value1_is_list) {
6055     gint i, n, ret;
6056
6057     if (gst_value_list_equals_range (value2, value1)) {
6058       return GST_VALUE_EQUAL;
6059     }
6060
6061     n = gst_value_list_get_size (value2);
6062     if (n == 0)
6063       return GST_VALUE_UNORDERED;
6064
6065     for (i = 0; i < n; i++) {
6066       const GValue *elt;
6067
6068       elt = gst_value_list_get_value (value2, i);
6069       ret = gst_value_compare (elt, value1);
6070       if (ret != GST_VALUE_EQUAL && n == 1)
6071         return ret;
6072       else if (ret != GST_VALUE_EQUAL)
6073         return GST_VALUE_UNORDERED;
6074     }
6075
6076     return GST_VALUE_EQUAL;
6077   }
6078
6079   /* And now handle the generic case */
6080   return _gst_value_compare_nolist (value1, value2);
6081 }
6082
6083 /* union */
6084
6085 /**
6086  * gst_value_can_union:
6087  * @value1: a value to union
6088  * @value2: another value to union
6089  *
6090  * Determines if @value1 and @value2 can be non-trivially unioned.
6091  * Any two values can be trivially unioned by adding both of them
6092  * to a GstValueList.  However, certain types have the possibility
6093  * to be unioned in a simpler way.  For example, an integer range
6094  * and an integer can be unioned if the integer is a subset of the
6095  * integer range.  If there is the possibility that two values can
6096  * be unioned, this function returns %TRUE.
6097  *
6098  * Returns: %TRUE if there is a function allowing the two values to
6099  * be unioned.
6100  */
6101 gboolean
6102 gst_value_can_union (const GValue * value1, const GValue * value2)
6103 {
6104   GstValueUnionInfo *union_info;
6105   guint i, len;
6106
6107   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
6108   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
6109
6110   len = gst_value_union_funcs->len;
6111
6112   for (i = 0; i < len; i++) {
6113     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
6114     if (union_info->type1 == G_VALUE_TYPE (value1) &&
6115         union_info->type2 == G_VALUE_TYPE (value2))
6116       return TRUE;
6117     if (union_info->type1 == G_VALUE_TYPE (value2) &&
6118         union_info->type2 == G_VALUE_TYPE (value1))
6119       return TRUE;
6120   }
6121
6122   return FALSE;
6123 }
6124
6125 /**
6126  * gst_value_union:
6127  * @dest: (out caller-allocates): the destination value
6128  * @value1: a value to union
6129  * @value2: another value to union
6130  *
6131  * Creates a GValue corresponding to the union of @value1 and @value2.
6132  *
6133  * Returns: %TRUE if the union succeeded.
6134  */
6135 gboolean
6136 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
6137 {
6138   const GstValueUnionInfo *union_info;
6139   guint i, len;
6140   GType type1, type2;
6141
6142   g_return_val_if_fail (dest != NULL, FALSE);
6143   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
6144   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
6145   g_return_val_if_fail (gst_value_list_or_array_are_compatible (value1, value2),
6146       FALSE);
6147
6148   len = gst_value_union_funcs->len;
6149   type1 = G_VALUE_TYPE (value1);
6150   type2 = G_VALUE_TYPE (value2);
6151
6152   for (i = 0; i < len; i++) {
6153     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
6154     if (union_info->type1 == type1 && union_info->type2 == type2) {
6155       return union_info->func (dest, value1, value2);
6156     }
6157     if (union_info->type1 == type2 && union_info->type2 == type1) {
6158       return union_info->func (dest, value2, value1);
6159     }
6160   }
6161
6162   gst_value_list_concat (dest, value1, value2);
6163   return TRUE;
6164 }
6165
6166 /* gst_value_register_union_func: (skip)
6167  * @type1: a type to union
6168  * @type2: another type to union
6169  * @func: a function that implements creating a union between the two types
6170  *
6171  * Registers a union function that can create a union between #GValue items
6172  * of the type @type1 and @type2.
6173  *
6174  * Union functions should be registered at startup before any pipelines are
6175  * started, as gst_value_register_union_func() is not thread-safe and cannot
6176  * be used at the same time as gst_value_union() or gst_value_can_union().
6177  */
6178 static void
6179 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
6180 {
6181   GstValueUnionInfo union_info;
6182
6183   union_info.type1 = type1;
6184   union_info.type2 = type2;
6185   union_info.func = func;
6186
6187   g_array_append_val (gst_value_union_funcs, union_info);
6188 }
6189
6190 /* intersection */
6191
6192 /**
6193  * gst_value_can_intersect:
6194  * @value1: a value to intersect
6195  * @value2: another value to intersect
6196  *
6197  * Determines if intersecting two values will produce a valid result.
6198  * Two values will produce a valid intersection if they have the same
6199  * type.
6200  *
6201  * Returns: %TRUE if the values can intersect
6202  */
6203 gboolean
6204 gst_value_can_intersect (const GValue * value1, const GValue * value2)
6205 {
6206   GstValueIntersectInfo *intersect_info;
6207   guint i, len;
6208   GType type1, type2;
6209
6210   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
6211   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
6212
6213   type1 = G_VALUE_TYPE (value1);
6214   type2 = G_VALUE_TYPE (value2);
6215
6216   /* practically all GstValue types have a compare function (_can_compare=TRUE)
6217    * GstStructure and GstCaps have not, but are intersectable */
6218   if (type1 == type2)
6219     return TRUE;
6220
6221   /* special cases */
6222   if (type1 == GST_TYPE_LIST || type2 == GST_TYPE_LIST)
6223     return TRUE;
6224
6225   if (G_UNLIKELY (GST_VALUE_HOLDS_FLAG_SET (value1) &&
6226           GST_VALUE_HOLDS_FLAG_SET (value2))) {
6227     GType flagset_type;
6228
6229     flagset_type = GST_TYPE_FLAG_SET;
6230
6231     /* Allow intersection with the generic FlagSet type, on one
6232      * side, but not 2 different subtypes - that makes no sense */
6233     if (type1 == flagset_type || type2 == flagset_type)
6234       return TRUE;
6235   }
6236
6237   /* check registered intersect functions (only different gtype are checked at
6238    * this point) */
6239   len = gst_value_intersect_funcs->len;
6240   for (i = 0; i < len; i++) {
6241     intersect_info = &g_array_index (gst_value_intersect_funcs,
6242         GstValueIntersectInfo, i);
6243     if ((intersect_info->type1 == type1 && intersect_info->type2 == type2) ||
6244         (intersect_info->type1 == type2 && intersect_info->type2 == type1))
6245       return TRUE;
6246   }
6247
6248   return gst_value_can_compare_unchecked (value1, value2);
6249 }
6250
6251 /**
6252  * gst_value_intersect:
6253  * @dest: (out caller-allocates) (transfer full) (allow-none):
6254  *   a uninitialized #GValue that will hold the calculated
6255  *   intersection value. May be %NULL if the resulting set if not
6256  *   needed.
6257  * @value1: a value to intersect
6258  * @value2: another value to intersect
6259  *
6260  * Calculates the intersection of two values.  If the values have
6261  * a non-empty intersection, the value representing the intersection
6262  * is placed in @dest, unless %NULL.  If the intersection is non-empty,
6263  * @dest is not modified.
6264  *
6265  * Returns: %TRUE if the intersection is non-empty
6266  */
6267 gboolean
6268 gst_value_intersect (GValue * dest, const GValue * value1,
6269     const GValue * value2)
6270 {
6271   GstValueIntersectInfo *intersect_info;
6272   guint i, len;
6273   GType type1, type2;
6274
6275   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
6276   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
6277
6278   type1 = G_VALUE_TYPE (value1);
6279   type2 = G_VALUE_TYPE (value2);
6280
6281   /* special cases first */
6282   if (type1 == GST_TYPE_LIST)
6283     return gst_value_intersect_list (dest, value1, value2);
6284   if (type2 == GST_TYPE_LIST)
6285     return gst_value_intersect_list (dest, value2, value1);
6286
6287   if (_gst_value_compare_nolist (value1, value2) == GST_VALUE_EQUAL) {
6288     if (dest)
6289       gst_value_init_and_copy (dest, value1);
6290     return TRUE;
6291   }
6292
6293   if (type1 == type2) {
6294     /* Equal type comparison */
6295     if (type1 == GST_TYPE_INT_RANGE)
6296       return gst_value_intersect_int_range_int_range (dest, value1, value2);
6297     if (type1 == GST_TYPE_INT64_RANGE)
6298       return gst_value_intersect_int64_range_int64_range (dest, value1, value2);
6299     if (type1 == GST_TYPE_DOUBLE_RANGE)
6300       return gst_value_intersect_double_range_double_range (dest, value1,
6301           value2);
6302     if (type1 == GST_TYPE_ARRAY)
6303       return gst_value_intersect_array (dest, value1, value2);
6304     if (type1 == GST_TYPE_FRACTION_RANGE)
6305       return gst_value_intersect_fraction_range_fraction_range (dest, value1,
6306           value2);
6307     if (type1 == GST_TYPE_FLAG_SET)
6308       return gst_value_intersect_flagset_flagset (dest, value1, value2);
6309     if (type1 == GST_TYPE_STRUCTURE)
6310       return gst_value_intersect_structure_structure (dest, value1, value2);
6311   } else {
6312     /* Different type comparison */
6313     len = gst_value_intersect_funcs->len;
6314     for (i = 0; i < len; i++) {
6315       intersect_info = &g_array_index (gst_value_intersect_funcs,
6316           GstValueIntersectInfo, i);
6317       if (intersect_info->type1 == type1 && intersect_info->type2 == type2) {
6318         return intersect_info->func (dest, value1, value2);
6319       }
6320       if (intersect_info->type1 == type2 && intersect_info->type2 == type1) {
6321         return intersect_info->func (dest, value2, value1);
6322       }
6323     }
6324   }
6325
6326   /* Failed to find a direct intersection, check if these are
6327    * GstFlagSet sub-types. */
6328   if (G_UNLIKELY (GST_VALUE_HOLDS_FLAG_SET (value1) &&
6329           GST_VALUE_HOLDS_FLAG_SET (value2))) {
6330     return gst_value_intersect_flagset_flagset (dest, value1, value2);
6331   }
6332
6333   return FALSE;
6334 }
6335
6336
6337
6338 /* gst_value_register_intersect_func: (skip)
6339  * @type1: the first type to intersect
6340  * @type2: the second type to intersect
6341  * @func: the intersection function
6342  *
6343  * Registers a function that is called to calculate the intersection
6344  * of the values having the types @type1 and @type2.
6345  *
6346  * Intersect functions should be registered at startup before any pipelines are
6347  * started, as gst_value_register_intersect_func() is not thread-safe and
6348  * cannot be used at the same time as gst_value_intersect() or
6349  * gst_value_can_intersect().
6350  */
6351 static void
6352 gst_value_register_intersect_func (GType type1, GType type2,
6353     GstValueIntersectFunc func)
6354 {
6355   GstValueIntersectInfo intersect_info;
6356
6357   intersect_info.type1 = type1;
6358   intersect_info.type2 = type2;
6359   intersect_info.func = func;
6360
6361   g_array_append_val (gst_value_intersect_funcs, intersect_info);
6362 }
6363
6364
6365 /* subtraction */
6366
6367 /**
6368  * gst_value_subtract:
6369  * @dest: (out caller-allocates) (allow-none): the destination value
6370  *     for the result if the subtraction is not empty. May be %NULL,
6371  *     in which case the resulting set will not be computed, which can
6372  *     give a fair speedup.
6373  * @minuend: the value to subtract from
6374  * @subtrahend: the value to subtract
6375  *
6376  * Subtracts @subtrahend from @minuend and stores the result in @dest.
6377  * Note that this means subtraction as in sets, not as in mathematics.
6378  *
6379  * Returns: %TRUE if the subtraction is not empty
6380  */
6381 gboolean
6382 gst_value_subtract (GValue * dest, const GValue * minuend,
6383     const GValue * subtrahend)
6384 {
6385   GstValueSubtractInfo *info;
6386   guint i, len;
6387   GType mtype, stype;
6388
6389   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
6390   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
6391
6392   mtype = G_VALUE_TYPE (minuend);
6393   stype = G_VALUE_TYPE (subtrahend);
6394
6395   /* special cases first */
6396   if (mtype == GST_TYPE_LIST)
6397     return gst_value_subtract_from_list (dest, minuend, subtrahend);
6398   if (stype == GST_TYPE_LIST)
6399     return gst_value_subtract_list (dest, minuend, subtrahend);
6400
6401   len = gst_value_subtract_funcs->len;
6402   for (i = 0; i < len; i++) {
6403     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
6404     if (info->minuend == mtype && info->subtrahend == stype) {
6405       return info->func (dest, minuend, subtrahend);
6406     }
6407   }
6408
6409   if (_gst_value_compare_nolist (minuend, subtrahend) != GST_VALUE_EQUAL) {
6410     if (dest)
6411       gst_value_init_and_copy (dest, minuend);
6412     return TRUE;
6413   }
6414
6415   return FALSE;
6416 }
6417
6418 #if 0
6419 gboolean
6420 gst_value_subtract (GValue * dest, const GValue * minuend,
6421     const GValue * subtrahend)
6422 {
6423   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
6424
6425   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
6426       gst_value_serialize (subtrahend),
6427       ret ? gst_value_serialize (dest) : "---");
6428   return ret;
6429 }
6430 #endif
6431
6432 /**
6433  * gst_value_can_subtract:
6434  * @minuend: the value to subtract from
6435  * @subtrahend: the value to subtract
6436  *
6437  * Checks if it's possible to subtract @subtrahend from @minuend.
6438  *
6439  * Returns: %TRUE if a subtraction is possible
6440  */
6441 gboolean
6442 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
6443 {
6444   GstValueSubtractInfo *info;
6445   guint i, len;
6446   GType mtype, stype;
6447
6448   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
6449   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
6450
6451   mtype = G_VALUE_TYPE (minuend);
6452   stype = G_VALUE_TYPE (subtrahend);
6453
6454   /* special cases */
6455   if (mtype == GST_TYPE_LIST || stype == GST_TYPE_LIST)
6456     return TRUE;
6457   if (mtype == GST_TYPE_STRUCTURE || stype == GST_TYPE_STRUCTURE)
6458     return FALSE;
6459
6460   len = gst_value_subtract_funcs->len;
6461   for (i = 0; i < len; i++) {
6462     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
6463     if (info->minuend == mtype && info->subtrahend == stype)
6464       return TRUE;
6465   }
6466
6467   return gst_value_can_compare_unchecked (minuend, subtrahend);
6468 }
6469
6470 /* gst_value_register_subtract_func: (skip)
6471  * @minuend_type: type of the minuend
6472  * @subtrahend_type: type of the subtrahend
6473  * @func: function to use
6474  *
6475  * Registers @func as a function capable of subtracting the values of
6476  * @subtrahend_type from values of @minuend_type.
6477  *
6478  * Subtract functions should be registered at startup before any pipelines are
6479  * started, as gst_value_register_subtract_func() is not thread-safe and
6480  * cannot be used at the same time as gst_value_subtract().
6481  */
6482 static void
6483 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
6484     GstValueSubtractFunc func)
6485 {
6486   GstValueSubtractInfo info;
6487
6488   g_return_if_fail (!gst_type_is_fixed (minuend_type)
6489       || !gst_type_is_fixed (subtrahend_type));
6490
6491   info.minuend = minuend_type;
6492   info.subtrahend = subtrahend_type;
6493   info.func = func;
6494
6495   g_array_append_val (gst_value_subtract_funcs, info);
6496 }
6497
6498 /**
6499  * gst_value_register:
6500  * @table: structure containing functions to register
6501  *
6502  * Registers functions to perform calculations on #GValue items of a given
6503  * type. Each type can only be added once.
6504  */
6505 void
6506 gst_value_register (const GstValueTable * table)
6507 {
6508   GstValueTable *found;
6509
6510   g_return_if_fail (table != NULL);
6511
6512   g_array_append_val (gst_value_table, *table);
6513
6514   found = gst_value_hash_lookup_type (table->type);
6515   if (found)
6516     g_warning ("adding type %s multiple times", g_type_name (table->type));
6517
6518   /* FIXME: we're not really doing the const justice, we assume the table is
6519    * static */
6520   gst_value_hash_add_type (table->type, table);
6521 }
6522
6523 /**
6524  * gst_value_init_and_copy:
6525  * @dest: (out caller-allocates): the target value
6526  * @src: the source value
6527  *
6528  * Initialises the target value to be of the same type as source and then copies
6529  * the contents from source to target.
6530  */
6531 void
6532 gst_value_init_and_copy (GValue * dest, const GValue * src)
6533 {
6534   GType type;
6535
6536   g_return_if_fail (G_IS_VALUE (src));
6537   g_return_if_fail (dest != NULL);
6538
6539   type = G_VALUE_TYPE (src);
6540   /* We need to shortcut GstValueList/GstValueArray copying because:
6541    * * g_value_init would end up allocating something
6542    * * which g_value_copy would then free and re-alloc.
6543    *
6544    * Instead directly call the copy */
6545   if (type == GST_TYPE_LIST || type == GST_TYPE_ARRAY) {
6546     dest->g_type = type;
6547     gst_value_copy_list_or_array (src, dest);
6548     return;
6549   }
6550
6551   g_value_init (dest, type);
6552   g_value_copy (src, dest);
6553 }
6554
6555 /* move src into dest and clear src */
6556 static void
6557 gst_value_move (GValue * dest, GValue * src)
6558 {
6559   g_assert (G_IS_VALUE (src));
6560   g_assert (dest != NULL);
6561
6562   *dest = *src;
6563   memset (src, 0, sizeof (GValue));
6564 }
6565
6566 /**
6567  * gst_value_serialize:
6568  * @value: a #GValue to serialize
6569  *
6570  * tries to transform the given @value into a string representation that allows
6571  * getting back this string later on using gst_value_deserialize().
6572  *
6573  * Free-function: g_free
6574  *
6575  * Returns: (transfer full) (nullable): the serialization for @value
6576  * or %NULL if none exists
6577  */
6578 gchar *
6579 gst_value_serialize (const GValue * value)
6580 {
6581   guint i, len;
6582   GValue s_val = { 0 };
6583   GstValueTable *table, *best;
6584   gchar *s;
6585   GType type;
6586
6587   g_return_val_if_fail (G_IS_VALUE (value), NULL);
6588
6589   type = G_VALUE_TYPE (value);
6590
6591   best = gst_value_hash_lookup_type (type);
6592
6593   if (G_UNLIKELY (!best || !best->serialize)) {
6594     len = gst_value_table->len;
6595     best = NULL;
6596     for (i = 0; i < len; i++) {
6597       table = &g_array_index (gst_value_table, GstValueTable, i);
6598       if (table->serialize && g_type_is_a (type, table->type)) {
6599         if (!best || g_type_is_a (table->type, best->type))
6600           best = table;
6601       }
6602     }
6603   }
6604   if (G_LIKELY (best))
6605     return best->serialize (value);
6606
6607   g_value_init (&s_val, G_TYPE_STRING);
6608   if (g_value_transform (value, &s_val)) {
6609     s = gst_string_wrap (g_value_get_string (&s_val));
6610   } else {
6611     s = NULL;
6612   }
6613   g_value_unset (&s_val);
6614
6615   return s;
6616 }
6617
6618 /**
6619  * gst_value_deserialize:
6620  * @dest: (out caller-allocates): #GValue to fill with contents of
6621  *     deserialization
6622  * @src: string to deserialize
6623  *
6624  * Tries to deserialize a string into the type specified by the given GValue.
6625  * If the operation succeeds, %TRUE is returned, %FALSE otherwise.
6626  *
6627  * Returns: %TRUE on success
6628  */
6629 gboolean
6630 gst_value_deserialize (GValue * dest, const gchar * src)
6631 {
6632   GstValueTable *table, *best;
6633   guint i, len;
6634   GType type;
6635
6636   g_return_val_if_fail (src != NULL, FALSE);
6637   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
6638
6639   type = G_VALUE_TYPE (dest);
6640
6641   best = gst_value_hash_lookup_type (type);
6642   if (G_UNLIKELY (!best || (!best->deserialize
6643               && !best->deserialize_with_pspec))) {
6644     len = gst_value_table->len;
6645     best = NULL;
6646     for (i = 0; i < len; i++) {
6647       table = &g_array_index (gst_value_table, GstValueTable, i);
6648       if ((table->deserialize || table->deserialize_with_pspec) &&
6649           g_type_is_a (type, table->type)) {
6650         if (!best || g_type_is_a (table->type, best->type))
6651           best = table;
6652       }
6653     }
6654   }
6655   if (G_LIKELY (best)) {
6656     if (best->deserialize_with_pspec)
6657       return best->deserialize_with_pspec (dest, src, NULL);
6658     else
6659       return best->deserialize (dest, src);
6660   }
6661
6662   return FALSE;
6663 }
6664
6665 /**
6666  * gst_value_deserialize_with_pspec:
6667  * @dest: (out caller-allocates): #GValue to fill with contents of
6668  *     deserialization
6669  * @src: string to deserialize
6670  * @pspec: (nullable): the #GParamSpec describing the expected value
6671  *
6672  * Tries to deserialize a string into the type specified by the given GValue.
6673  * @pspec may be used to guide the deserializing of nested members.
6674  * If the operation succeeds, %TRUE is returned, %FALSE otherwise.
6675  *
6676  * Returns: %TRUE on success
6677  * Since: 1.20
6678  */
6679 gboolean
6680 gst_value_deserialize_with_pspec (GValue * dest, const gchar * src,
6681     GParamSpec * pspec)
6682 {
6683   GstValueTable *table, *best;
6684   guint i, len;
6685   GType type;
6686
6687   g_return_val_if_fail (src != NULL, FALSE);
6688   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
6689
6690   if (pspec)
6691     g_return_val_if_fail (G_VALUE_TYPE (dest) ==
6692         G_PARAM_SPEC_VALUE_TYPE (pspec), FALSE);
6693
6694   type = G_VALUE_TYPE (dest);
6695
6696   best = gst_value_hash_lookup_type (type);
6697   if (G_UNLIKELY (!best || (!best->deserialize
6698               && !best->deserialize_with_pspec))) {
6699     len = gst_value_table->len;
6700     best = NULL;
6701     for (i = 0; i < len; i++) {
6702       table = &g_array_index (gst_value_table, GstValueTable, i);
6703       if ((table->deserialize || table->deserialize_with_pspec) &&
6704           g_type_is_a (type, table->type)) {
6705         if (!best || g_type_is_a (table->type, best->type))
6706           best = table;
6707       }
6708     }
6709   }
6710   if (G_LIKELY (best)) {
6711     if (best->deserialize_with_pspec)
6712       return best->deserialize_with_pspec (dest, src, pspec);
6713     else
6714       return best->deserialize (dest, src);
6715   }
6716
6717   return FALSE;
6718 }
6719
6720 static gboolean
6721 structure_field_is_fixed (GQuark field_id, const GValue * val,
6722     gpointer user_data)
6723 {
6724   return gst_value_is_fixed (val);
6725 }
6726
6727 /**
6728  * gst_value_is_fixed:
6729  * @value: the #GValue to check
6730  *
6731  * Tests if the given GValue, if available in a GstStructure (or any other
6732  * container) contains a "fixed" (which means: one value) or an "unfixed"
6733  * (which means: multiple possible values, such as data lists or data
6734  * ranges) value.
6735  *
6736  * Returns: true if the value is "fixed".
6737  */
6738
6739 gboolean
6740 gst_value_is_fixed (const GValue * value)
6741 {
6742   GType type;
6743
6744   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
6745
6746   type = G_VALUE_TYPE (value);
6747
6748   /* the most common types are just basic plain glib types */
6749   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
6750     return TRUE;
6751   }
6752
6753   if (type == GST_TYPE_ARRAY) {
6754     gint size, n;
6755     const GValue *kid;
6756
6757     /* check recursively */
6758     size = gst_value_array_get_size (value);
6759     for (n = 0; n < size; n++) {
6760       kid = gst_value_array_get_value (value, n);
6761       if (!gst_value_is_fixed (kid))
6762         return FALSE;
6763     }
6764     return TRUE;
6765   } else if (GST_VALUE_HOLDS_FLAG_SET (value)) {
6766     /* Flagsets are only fixed if there are no 'don't care' bits */
6767     return (gst_value_get_flagset_mask (value) == GST_FLAG_SET_MASK_EXACT);
6768   } else if (GST_VALUE_HOLDS_STRUCTURE (value)) {
6769     return gst_structure_foreach (gst_value_get_structure (value),
6770         structure_field_is_fixed, NULL);
6771   }
6772   return gst_type_is_fixed (type);
6773 }
6774
6775 /**
6776  * gst_value_fixate:
6777  * @dest: the #GValue destination
6778  * @src: the #GValue to fixate
6779  *
6780  * Fixate @src into a new value @dest.
6781  * For ranges, the first element is taken. For lists and arrays, the
6782  * first item is fixated and returned.
6783  * If @src is already fixed, this function returns %FALSE.
6784  *
6785  * Returns: %TRUE if @dest contains a fixated version of @src.
6786  */
6787 gboolean
6788 gst_value_fixate (GValue * dest, const GValue * src)
6789 {
6790   g_return_val_if_fail (G_IS_VALUE (src), FALSE);
6791   g_return_val_if_fail (dest != NULL, FALSE);
6792
6793   if (G_VALUE_TYPE (src) == GST_TYPE_INT_RANGE) {
6794     g_value_init (dest, G_TYPE_INT);
6795     g_value_set_int (dest, gst_value_get_int_range_min (src));
6796   } else if (G_VALUE_TYPE (src) == GST_TYPE_DOUBLE_RANGE) {
6797     g_value_init (dest, G_TYPE_DOUBLE);
6798     g_value_set_double (dest, gst_value_get_double_range_min (src));
6799   } else if (G_VALUE_TYPE (src) == GST_TYPE_FRACTION_RANGE) {
6800     gst_value_init_and_copy (dest, gst_value_get_fraction_range_min (src));
6801   } else if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
6802     GValue temp = { 0 };
6803
6804     /* list could be empty */
6805     if (gst_value_list_get_size (src) <= 0)
6806       return FALSE;
6807
6808     gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0));
6809
6810     if (!gst_value_fixate (dest, &temp)) {
6811       gst_value_move (dest, &temp);
6812     } else {
6813       g_value_unset (&temp);
6814     }
6815   } else if (G_VALUE_TYPE (src) == GST_TYPE_ARRAY) {
6816     gboolean res = FALSE;
6817     guint n, len;
6818
6819     len = gst_value_array_get_size (src);
6820     g_value_init (dest, GST_TYPE_ARRAY);
6821     for (n = 0; n < len; n++) {
6822       GValue kid = { 0 };
6823       const GValue *orig_kid = gst_value_array_get_value (src, n);
6824
6825       if (!gst_value_fixate (&kid, orig_kid))
6826         gst_value_init_and_copy (&kid, orig_kid);
6827       else
6828         res = TRUE;
6829       _gst_value_array_append_and_take_value (dest, &kid);
6830     }
6831
6832     if (!res)
6833       g_value_unset (dest);
6834
6835     return res;
6836   } else if (GST_VALUE_HOLDS_FLAG_SET (src)) {
6837     guint flags;
6838
6839     if (gst_value_get_flagset_mask (src) == GST_FLAG_SET_MASK_EXACT)
6840       return FALSE;             /* Already fixed */
6841
6842     flags = gst_value_get_flagset_flags (src);
6843     g_value_init (dest, G_VALUE_TYPE (src));
6844     gst_value_set_flagset (dest, flags, GST_FLAG_SET_MASK_EXACT);
6845     return TRUE;
6846   } else if (GST_VALUE_HOLDS_STRUCTURE (src)) {
6847     const GstStructure *str = (GstStructure *) gst_value_get_structure (src);
6848     GstStructure *kid;
6849
6850     if (!str)
6851       return FALSE;
6852
6853     kid = gst_structure_copy (str);
6854     gst_structure_fixate (kid);
6855     g_value_init (dest, GST_TYPE_STRUCTURE);
6856     gst_value_set_structure (dest, kid);
6857     gst_structure_free (kid);
6858     return TRUE;
6859   } else {
6860     return FALSE;
6861   }
6862   return TRUE;
6863 }
6864
6865
6866 /************
6867  * fraction *
6868  ************/
6869
6870 /* helper functions */
6871 static void
6872 gst_value_init_fraction (GValue * value)
6873 {
6874   value->data[0].v_int = 0;
6875   value->data[1].v_int = 1;
6876 }
6877
6878 static void
6879 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
6880 {
6881   dest_value->data[0].v_int = src_value->data[0].v_int;
6882   dest_value->data[1].v_int = src_value->data[1].v_int;
6883 }
6884
6885 static gchar *
6886 gst_value_collect_fraction (GValue * value, guint n_collect_values,
6887     GTypeCValue * collect_values, guint collect_flags)
6888 {
6889   g_return_val_if_fail (n_collect_values == 2,
6890       g_strdup_printf ("not enough value locations for `%s' passed",
6891           G_VALUE_TYPE_NAME (value)));
6892   g_return_val_if_fail (collect_values[1].v_int != 0,
6893       g_strdup_printf ("passed '0' as denominator for `%s'",
6894           G_VALUE_TYPE_NAME (value)));
6895   g_return_val_if_fail (collect_values[0].v_int >= -G_MAXINT,
6896       g_strdup_printf
6897       ("passed value smaller than -G_MAXINT as numerator for `%s'",
6898           G_VALUE_TYPE_NAME (value)));
6899   g_return_val_if_fail (collect_values[1].v_int >= -G_MAXINT,
6900       g_strdup_printf
6901       ("passed value smaller than -G_MAXINT as denominator for `%s'",
6902           G_VALUE_TYPE_NAME (value)));
6903
6904   gst_value_set_fraction (value,
6905       collect_values[0].v_int, collect_values[1].v_int);
6906
6907   return NULL;
6908 }
6909
6910 static gchar *
6911 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
6912     GTypeCValue * collect_values, guint collect_flags)
6913 {
6914   gint *numerator = collect_values[0].v_pointer;
6915   gint *denominator = collect_values[1].v_pointer;
6916
6917   g_return_val_if_fail (numerator != NULL,
6918       g_strdup_printf ("numerator for `%s' passed as NULL",
6919           G_VALUE_TYPE_NAME (value)));
6920   g_return_val_if_fail (denominator != NULL,
6921       g_strdup_printf ("denominator for `%s' passed as NULL",
6922           G_VALUE_TYPE_NAME (value)));
6923
6924   *numerator = value->data[0].v_int;
6925   *denominator = value->data[1].v_int;
6926
6927   return NULL;
6928 }
6929
6930 /**
6931  * gst_value_set_fraction:
6932  * @value: a GValue initialized to #GST_TYPE_FRACTION
6933  * @numerator: the numerator of the fraction
6934  * @denominator: the denominator of the fraction
6935  *
6936  * Sets @value to the fraction specified by @numerator over @denominator.
6937  * The fraction gets reduced to the smallest numerator and denominator,
6938  * and if necessary the sign is moved to the numerator.
6939  */
6940 void
6941 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
6942 {
6943   gint gcd = 0;
6944
6945   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
6946   g_return_if_fail (denominator != 0);
6947   g_return_if_fail (denominator >= -G_MAXINT);
6948   g_return_if_fail (numerator >= -G_MAXINT);
6949
6950   /* normalize sign */
6951   if (denominator < 0) {
6952     numerator = -numerator;
6953     denominator = -denominator;
6954   }
6955
6956   /* check for reduction */
6957   gcd = gst_util_greatest_common_divisor (numerator, denominator);
6958   if (gcd) {
6959     numerator /= gcd;
6960     denominator /= gcd;
6961   }
6962
6963   g_assert (denominator > 0);
6964
6965   value->data[0].v_int = numerator;
6966   value->data[1].v_int = denominator;
6967 }
6968
6969 /**
6970  * gst_value_get_fraction_numerator:
6971  * @value: a GValue initialized to #GST_TYPE_FRACTION
6972  *
6973  * Gets the numerator of the fraction specified by @value.
6974  *
6975  * Returns: the numerator of the fraction.
6976  */
6977 gint
6978 gst_value_get_fraction_numerator (const GValue * value)
6979 {
6980   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
6981
6982   return value->data[0].v_int;
6983 }
6984
6985 /**
6986  * gst_value_get_fraction_denominator:
6987  * @value: a GValue initialized to #GST_TYPE_FRACTION
6988  *
6989  * Gets the denominator of the fraction specified by @value.
6990  *
6991  * Returns: the denominator of the fraction.
6992  */
6993 gint
6994 gst_value_get_fraction_denominator (const GValue * value)
6995 {
6996   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
6997
6998   return value->data[1].v_int;
6999 }
7000
7001 /**
7002  * gst_value_fraction_multiply:
7003  * @product: a GValue initialized to #GST_TYPE_FRACTION
7004  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
7005  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
7006  *
7007  * Multiplies the two #GValue items containing a #GST_TYPE_FRACTION and sets
7008  * @product to the product of the two fractions.
7009  *
7010  * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise.
7011  */
7012 gboolean
7013 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
7014     const GValue * factor2)
7015 {
7016   gint n1, n2, d1, d2;
7017   gint res_n, res_d;
7018
7019   g_return_val_if_fail (product != NULL, FALSE);
7020   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
7021   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
7022
7023   n1 = factor1->data[0].v_int;
7024   n2 = factor2->data[0].v_int;
7025   d1 = factor1->data[1].v_int;
7026   d2 = factor2->data[1].v_int;
7027
7028   if (!gst_util_fraction_multiply (n1, d1, n2, d2, &res_n, &res_d))
7029     return FALSE;
7030
7031   gst_value_set_fraction (product, res_n, res_d);
7032
7033   return TRUE;
7034 }
7035
7036 /**
7037  * gst_value_fraction_subtract:
7038  * @dest: a GValue initialized to #GST_TYPE_FRACTION
7039  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
7040  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
7041  *
7042  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
7043  *
7044  * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise.
7045  */
7046 gboolean
7047 gst_value_fraction_subtract (GValue * dest,
7048     const GValue * minuend, const GValue * subtrahend)
7049 {
7050   gint n1, n2, d1, d2;
7051   gint res_n, res_d;
7052
7053   g_return_val_if_fail (dest != NULL, FALSE);
7054   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
7055   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
7056
7057   n1 = minuend->data[0].v_int;
7058   n2 = subtrahend->data[0].v_int;
7059   d1 = minuend->data[1].v_int;
7060   d2 = subtrahend->data[1].v_int;
7061
7062   if (!gst_util_fraction_add (n1, d1, -n2, d2, &res_n, &res_d))
7063     return FALSE;
7064   gst_value_set_fraction (dest, res_n, res_d);
7065
7066   return TRUE;
7067 }
7068
7069 static gchar *
7070 gst_value_serialize_fraction (const GValue * value)
7071 {
7072   gint32 numerator = value->data[0].v_int;
7073   gint32 denominator = value->data[1].v_int;
7074   gboolean positive = TRUE;
7075
7076   /* get the sign and make components absolute */
7077   if (numerator < 0) {
7078     numerator = -numerator;
7079     positive = !positive;
7080   }
7081   if (denominator < 0) {
7082     denominator = -denominator;
7083     positive = !positive;
7084   }
7085
7086   return g_strdup_printf ("%s%d/%d",
7087       positive ? "" : "-", numerator, denominator);
7088 }
7089
7090 static gboolean
7091 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
7092 {
7093   gint num, den;
7094   gint num_chars;
7095
7096   if (G_UNLIKELY (s == NULL))
7097     return FALSE;
7098
7099   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest)))
7100     return FALSE;
7101
7102   if (sscanf (s, "%d/%d%n", &num, &den, &num_chars) >= 2) {
7103     if (s[num_chars] != 0)
7104       return FALSE;
7105     if (den == 0)
7106       return FALSE;
7107
7108     gst_value_set_fraction (dest, num, den);
7109     return TRUE;
7110   } else if (g_ascii_strcasecmp (s, "1/max") == 0) {
7111     gst_value_set_fraction (dest, 1, G_MAXINT);
7112     return TRUE;
7113   } else if (sscanf (s, "%d%n", &num, &num_chars) >= 1) {
7114     if (s[num_chars] != 0)
7115       return FALSE;
7116     gst_value_set_fraction (dest, num, 1);
7117     return TRUE;
7118   } else if (g_ascii_strcasecmp (s, "min") == 0) {
7119     gst_value_set_fraction (dest, -G_MAXINT, 1);
7120     return TRUE;
7121   } else if (g_ascii_strcasecmp (s, "max") == 0) {
7122     gst_value_set_fraction (dest, G_MAXINT, 1);
7123     return TRUE;
7124   }
7125
7126   return FALSE;
7127 }
7128
7129 static void
7130 gst_value_transform_fraction_string (const GValue * src_value,
7131     GValue * dest_value)
7132 {
7133   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
7134 }
7135
7136 static void
7137 gst_value_transform_string_fraction (const GValue * src_value,
7138     GValue * dest_value)
7139 {
7140   if (!gst_value_deserialize_fraction (dest_value,
7141           src_value->data[0].v_pointer))
7142     /* If the deserialize fails, ensure we leave the fraction in a
7143      * valid, if incorrect, state */
7144     gst_value_set_fraction (dest_value, 0, 1);
7145 }
7146
7147 static void
7148 gst_value_transform_double_fraction (const GValue * src_value,
7149     GValue * dest_value)
7150 {
7151   gdouble src = g_value_get_double (src_value);
7152   gint n, d;
7153
7154   gst_util_double_to_fraction (src, &n, &d);
7155   gst_value_set_fraction (dest_value, n, d);
7156 }
7157
7158 static void
7159 gst_value_transform_float_fraction (const GValue * src_value,
7160     GValue * dest_value)
7161 {
7162   gfloat src = g_value_get_float (src_value);
7163   gint n, d;
7164
7165   gst_util_double_to_fraction (src, &n, &d);
7166   gst_value_set_fraction (dest_value, n, d);
7167 }
7168
7169 static void
7170 gst_value_transform_fraction_double (const GValue * src_value,
7171     GValue * dest_value)
7172 {
7173   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
7174       ((double) src_value->data[1].v_int);
7175 }
7176
7177 static void
7178 gst_value_transform_fraction_float (const GValue * src_value,
7179     GValue * dest_value)
7180 {
7181   dest_value->data[0].v_float = ((float) src_value->data[0].v_int) /
7182       ((float) src_value->data[1].v_int);
7183 }
7184
7185 static gint
7186 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
7187 {
7188   gint n1, n2;
7189   gint d1, d2;
7190   gint ret;
7191
7192   n1 = value1->data[0].v_int;
7193   n2 = value2->data[0].v_int;
7194   d1 = value1->data[1].v_int;
7195   d2 = value2->data[1].v_int;
7196
7197   /* fractions are reduced when set, so we can quickly see if they're equal */
7198   if (n1 == n2 && d1 == d2)
7199     return GST_VALUE_EQUAL;
7200
7201   if (d1 == 0 && d2 == 0)
7202     return GST_VALUE_UNORDERED;
7203   else if (d1 == 0)
7204     return GST_VALUE_GREATER_THAN;
7205   else if (d2 == 0)
7206     return GST_VALUE_LESS_THAN;
7207
7208   ret = gst_util_fraction_compare (n1, d1, n2, d2);
7209   if (ret == -1)
7210     return GST_VALUE_LESS_THAN;
7211   else if (ret == 1)
7212     return GST_VALUE_GREATER_THAN;
7213
7214   /* Equality can't happen here because we check for that
7215    * first already */
7216   g_return_val_if_reached (GST_VALUE_UNORDERED);
7217 }
7218
7219 /*********
7220  * GDate *
7221  *********/
7222
7223 static gint
7224 gst_value_compare_date (const GValue * value1, const GValue * value2)
7225 {
7226   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
7227   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
7228   guint32 j1, j2;
7229
7230   if (date1 == date2)
7231     return GST_VALUE_EQUAL;
7232
7233   if ((date1 == NULL || !g_date_valid (date1))
7234       && (date2 != NULL && g_date_valid (date2))) {
7235     return GST_VALUE_LESS_THAN;
7236   }
7237
7238   if ((date2 == NULL || !g_date_valid (date2))
7239       && (date1 != NULL && g_date_valid (date1))) {
7240     return GST_VALUE_GREATER_THAN;
7241   }
7242
7243   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
7244       || !g_date_valid (date2)) {
7245     return GST_VALUE_UNORDERED;
7246   }
7247
7248   j1 = g_date_get_julian (date1);
7249   j2 = g_date_get_julian (date2);
7250
7251   if (j1 == j2)
7252     return GST_VALUE_EQUAL;
7253   else if (j1 < j2)
7254     return GST_VALUE_LESS_THAN;
7255   else
7256     return GST_VALUE_GREATER_THAN;
7257 }
7258
7259 static gchar *
7260 gst_value_serialize_date (const GValue * val)
7261 {
7262   const GDate *date = (const GDate *) g_value_get_boxed (val);
7263
7264   if (date == NULL || !g_date_valid (date))
7265     return g_strdup ("9999-99-99");
7266
7267   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
7268       g_date_get_month (date), g_date_get_day (date));
7269 }
7270
7271 static gboolean
7272 gst_value_deserialize_date (GValue * dest, const gchar * s)
7273 {
7274   guint year, month, day;
7275
7276   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
7277     return FALSE;
7278
7279   if (!g_date_valid_dmy (day, month, year))
7280     return FALSE;
7281
7282   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
7283   return TRUE;
7284 }
7285
7286 /*************
7287  * GstDateTime *
7288  *************/
7289
7290 static gint
7291 gst_value_compare_date_time (const GValue * value1, const GValue * value2)
7292 {
7293   const GstDateTime *date1 = (const GstDateTime *) g_value_get_boxed (value1);
7294   const GstDateTime *date2 = (const GstDateTime *) g_value_get_boxed (value2);
7295
7296   if (date1 == date2)
7297     return GST_VALUE_EQUAL;
7298
7299   if ((date1 == NULL) && (date2 != NULL)) {
7300     return GST_VALUE_LESS_THAN;
7301   }
7302   if ((date2 == NULL) && (date1 != NULL)) {
7303     return GST_VALUE_LESS_THAN;
7304   }
7305
7306   /* returns GST_VALUE_* */
7307   return __gst_date_time_compare (date1, date2);
7308 }
7309
7310 static gchar *
7311 gst_value_serialize_date_time (const GValue * val)
7312 {
7313   GstDateTime *date = (GstDateTime *) g_value_get_boxed (val);
7314
7315   if (date == NULL)
7316     return g_strdup ("null");
7317
7318   return __gst_date_time_serialize (date, TRUE);
7319 }
7320
7321 static gboolean
7322 gst_value_deserialize_date_time (GValue * dest, const gchar * s)
7323 {
7324   GstDateTime *datetime;
7325
7326   if (!s || strcmp (s, "null") == 0) {
7327     return FALSE;
7328   }
7329
7330   datetime = gst_date_time_new_from_iso8601_string (s);
7331   if (datetime != NULL) {
7332     g_value_take_boxed (dest, datetime);
7333     return TRUE;
7334   }
7335   GST_WARNING ("Failed to deserialize date time string '%s'", s);
7336   return FALSE;
7337 }
7338
7339 static void
7340 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
7341 {
7342   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
7343 }
7344
7345 static void
7346 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
7347 {
7348   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
7349 }
7350
7351
7352 /*********
7353  * bytes *
7354  *********/
7355
7356 static gint
7357 gst_value_compare_bytes (const GValue * value1, const GValue * value2)
7358 {
7359   GBytes *bytes1 = (GBytes *) g_value_get_boxed (value1);
7360   GBytes *bytes2 = (GBytes *) g_value_get_boxed (value2);
7361
7362   if (G_UNLIKELY (!bytes1 || !bytes2)) {
7363     if (bytes1 == bytes2)
7364       return GST_VALUE_EQUAL;
7365     else
7366       return GST_VALUE_UNORDERED;
7367   }
7368
7369   return g_bytes_compare (bytes1, bytes2);
7370 }
7371
7372 static gchar *
7373 gst_value_serialize_bytes (const GValue * value)
7374 {
7375   GBytes *bytes = (GBytes *) g_value_get_boxed (value);
7376   gsize len = 0;
7377   const guint8 *data;
7378
7379   data = bytes ? g_bytes_get_data (bytes, &len) : NULL;
7380
7381   return g_base64_encode (data, len);
7382 }
7383
7384 static gboolean
7385 gst_value_deserialize_bytes (GValue * dest, const gchar * s)
7386 {
7387   gsize len;
7388   guint8 *data;
7389
7390   if (!s) {
7391     g_value_set_boxed (dest, g_bytes_new (NULL, 0));
7392     return TRUE;
7393   }
7394
7395   data = g_base64_decode (s, &len);
7396   g_value_set_boxed (dest, g_bytes_new_take (data, len));
7397   return TRUE;
7398 }
7399
7400
7401 /************
7402  * bitmask *
7403  ************/
7404
7405 /* helper functions */
7406 static void
7407 gst_value_init_bitmask (GValue * value)
7408 {
7409   value->data[0].v_uint64 = 0;
7410 }
7411
7412 static void
7413 gst_value_copy_bitmask (const GValue * src_value, GValue * dest_value)
7414 {
7415   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
7416 }
7417
7418 static gchar *
7419 gst_value_collect_bitmask (GValue * value, guint n_collect_values,
7420     GTypeCValue * collect_values, guint collect_flags)
7421 {
7422   g_return_val_if_fail (n_collect_values == 1,
7423       g_strdup_printf ("not enough value locations for `%s' passed",
7424           G_VALUE_TYPE_NAME (value)));
7425
7426   gst_value_set_bitmask (value, (guint64) collect_values[0].v_int64);
7427
7428   return NULL;
7429 }
7430
7431 static gchar *
7432 gst_value_lcopy_bitmask (const GValue * value, guint n_collect_values,
7433     GTypeCValue * collect_values, guint collect_flags)
7434 {
7435   guint64 *bitmask = collect_values[0].v_pointer;
7436
7437   g_return_val_if_fail (bitmask != NULL,
7438       g_strdup_printf ("value for `%s' passed as NULL",
7439           G_VALUE_TYPE_NAME (value)));
7440
7441   *bitmask = value->data[0].v_uint64;
7442
7443   return NULL;
7444 }
7445
7446 /**
7447  * gst_value_set_bitmask:
7448  * @value: a GValue initialized to #GST_TYPE_BITMASK
7449  * @bitmask: the bitmask
7450  *
7451  * Sets @value to the bitmask specified by @bitmask.
7452  */
7453 void
7454 gst_value_set_bitmask (GValue * value, guint64 bitmask)
7455 {
7456   g_return_if_fail (GST_VALUE_HOLDS_BITMASK (value));
7457
7458   value->data[0].v_uint64 = bitmask;
7459 }
7460
7461 /**
7462  * gst_value_get_bitmask:
7463  * @value: a GValue initialized to #GST_TYPE_BITMASK
7464  *
7465  * Gets the bitmask specified by @value.
7466  *
7467  * Returns: the bitmask.
7468  */
7469 guint64
7470 gst_value_get_bitmask (const GValue * value)
7471 {
7472   g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (value), 0);
7473
7474   return value->data[0].v_uint64;
7475 }
7476
7477 static gchar *
7478 gst_value_serialize_bitmask (const GValue * value)
7479 {
7480   guint64 bitmask = value->data[0].v_uint64;
7481
7482   return g_strdup_printf ("0x%016" G_GINT64_MODIFIER "x", bitmask);
7483 }
7484
7485 static gboolean
7486 gst_value_deserialize_bitmask (GValue * dest, const gchar * s)
7487 {
7488   gchar *endptr = NULL;
7489   guint64 val;
7490
7491   if (G_UNLIKELY (s == NULL))
7492     return FALSE;
7493
7494   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_BITMASK (dest)))
7495     return FALSE;
7496
7497   errno = 0;
7498   val = g_ascii_strtoull (s, &endptr, 16);
7499   if (val == G_MAXUINT64 && (errno == ERANGE || errno == EINVAL))
7500     return FALSE;
7501   if (val == 0 && endptr == s)
7502     return FALSE;
7503
7504   gst_value_set_bitmask (dest, val);
7505
7506   return TRUE;
7507 }
7508
7509 static void
7510 gst_value_transform_bitmask_string (const GValue * src_value,
7511     GValue * dest_value)
7512 {
7513   dest_value->data[0].v_pointer = gst_value_serialize_bitmask (src_value);
7514 }
7515
7516 static void
7517 gst_value_transform_string_bitmask (const GValue * src_value,
7518     GValue * dest_value)
7519 {
7520   if (!gst_value_deserialize_bitmask (dest_value, src_value->data[0].v_pointer))
7521     gst_value_set_bitmask (dest_value, 0);
7522 }
7523
7524 static void
7525 gst_value_transform_uint64_bitmask (const GValue * src_value,
7526     GValue * dest_value)
7527 {
7528   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
7529 }
7530
7531 static void
7532 gst_value_transform_bitmask_uint64 (const GValue * src_value,
7533     GValue * dest_value)
7534 {
7535   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
7536 }
7537
7538 static gint
7539 gst_value_compare_bitmask (const GValue * value1, const GValue * value2)
7540 {
7541   guint64 v1, v2;
7542
7543   v1 = value1->data[0].v_uint64;
7544   v2 = value2->data[0].v_uint64;
7545
7546   if (v1 == v2)
7547     return GST_VALUE_EQUAL;
7548
7549   return GST_VALUE_UNORDERED;
7550 }
7551
7552 /************
7553  * flagset *
7554  ************/
7555
7556 /* helper functions */
7557 static void
7558 gst_value_init_flagset (GValue * value)
7559 {
7560   value->data[0].v_uint = 0;
7561   value->data[1].v_uint = 0;
7562 }
7563
7564 static void
7565 gst_value_copy_flagset (const GValue * src_value, GValue * dest_value)
7566 {
7567   dest_value->data[0].v_uint = src_value->data[0].v_uint;
7568   dest_value->data[1].v_uint = src_value->data[1].v_uint;
7569 }
7570
7571 static gchar *
7572 gst_value_collect_flagset (GValue * value, guint n_collect_values,
7573     GTypeCValue * collect_values, guint collect_flags)
7574 {
7575   g_return_val_if_fail (n_collect_values == 2,
7576       g_strdup_printf ("not enough value locations for `%s' passed",
7577           G_VALUE_TYPE_NAME (value)));
7578
7579   gst_value_set_flagset (value,
7580       (guint) collect_values[0].v_int, (guint) collect_values[1].v_int);
7581
7582   return NULL;
7583 }
7584
7585 static gchar *
7586 gst_value_lcopy_flagset (const GValue * value, guint n_collect_values,
7587     GTypeCValue * collect_values, guint collect_flags)
7588 {
7589   guint *flags = collect_values[0].v_pointer;
7590   guint *mask = collect_values[1].v_pointer;
7591
7592   *flags = value->data[0].v_uint;
7593   *mask = value->data[1].v_uint;
7594
7595   return NULL;
7596 }
7597
7598 /**
7599  * gst_value_set_flagset:
7600  * @value: a GValue initialized to %GST_TYPE_FLAG_SET
7601  * @flags: The value of the flags set or unset
7602  * @mask: The mask indicate which flags bits must match for comparisons
7603  *
7604  * Sets @value to the flags and mask values provided in @flags and @mask.
7605  * The @flags value indicates the values of flags, the @mask represents
7606  * which bits in the flag value have been set, and which are "don't care"
7607  *
7608  * Since: 1.6
7609  */
7610 void
7611 gst_value_set_flagset (GValue * value, guint flags, guint mask)
7612 {
7613   g_return_if_fail (GST_VALUE_HOLDS_FLAG_SET (value));
7614
7615   /* Normalise and only keep flags mentioned in the mask */
7616   value->data[0].v_uint = flags & mask;
7617   value->data[1].v_uint = mask;
7618 }
7619
7620 /**
7621  * gst_value_get_flagset_flags:
7622  * @value: a GValue initialized to #GST_TYPE_FLAG_SET
7623  *
7624  * Retrieve the flags field of a GstFlagSet @value.
7625  *
7626  * Returns: the flags field of the flagset instance.
7627  *
7628  * Since: 1.6
7629  */
7630 guint
7631 gst_value_get_flagset_flags (const GValue * value)
7632 {
7633   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value), 0);
7634
7635   return value->data[0].v_uint;
7636 }
7637
7638 /**
7639  * gst_value_get_flagset_mask:
7640  * @value: a GValue initialized to #GST_TYPE_FLAG_SET
7641  *
7642  * Retrieve the mask field of a GstFlagSet @value.
7643  *
7644  * Returns: the mask field of the flagset instance.
7645  *
7646  * Since: 1.6
7647  */
7648 guint
7649 gst_value_get_flagset_mask (const GValue * value)
7650 {
7651   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value), 1);
7652
7653   return value->data[1].v_uint;
7654 }
7655
7656 static gchar *
7657 gst_value_serialize_flagset (const GValue * value)
7658 {
7659   guint flags = value->data[0].v_uint;
7660   guint mask = value->data[1].v_uint;
7661   GstFlagSetClass *set_klass =
7662       (GstFlagSetClass *) g_type_class_ref (G_VALUE_TYPE (value));
7663   gchar *result;
7664
7665   result = g_strdup_printf ("%x:%x", flags, mask);
7666
7667   /* If this flag set class has an associated GFlags GType, and some
7668    * bits in the mask, serialize the bits in human-readable form to
7669    * aid debugging */
7670   if (mask && set_klass->flags_type) {
7671     GFlagsClass *flags_klass =
7672         (GFlagsClass *) (g_type_class_ref (set_klass->flags_type));
7673     GFlagsValue *fl;
7674     gchar *tmp;
7675     gboolean first = TRUE;
7676
7677     g_return_val_if_fail (flags_klass, NULL);
7678
7679     /* some bits in the mask are set, so serialize one by one, according
7680      * to whether that bit is set or cleared in the flags value */
7681     while (mask) {
7682       fl = g_flags_get_first_value (flags_klass, mask);
7683       if (fl == NULL) {
7684         /* No more bits match in the flags mask - time to stop */
7685         mask = 0;
7686         break;
7687       }
7688
7689       tmp = g_strconcat (result,
7690           first ? ":" : "",
7691           (flags & fl->value) ? "+" : "/", fl->value_nick, NULL);
7692       g_free (result);
7693       result = tmp;
7694       first = FALSE;
7695
7696       /* clear flag */
7697       mask &= ~fl->value;
7698     }
7699     g_type_class_unref (flags_klass);
7700
7701   }
7702   g_type_class_unref (set_klass);
7703
7704   return result;
7705 }
7706
7707 static gboolean
7708 is_valid_flags_string (const gchar * s)
7709 {
7710   /* We're looking to match +this/that+other-thing/not-this-thing type strings */
7711   return g_regex_match_simple ("^([\\+\\/][\\w\\d-]+)+$", s, G_REGEX_CASELESS,
7712       0);
7713 }
7714
7715 static gboolean
7716 gst_value_deserialize_flagset (GValue * dest, const gchar * s)
7717 {
7718   gboolean res = FALSE;
7719   guint flags, mask;
7720   gchar *cur, *next;
7721
7722   if (G_UNLIKELY (s == NULL))
7723     return FALSE;
7724
7725   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FLAG_SET (dest)))
7726     return FALSE;
7727
7728   /* Flagset strings look like %x:%x - hex flags : hex bitmask,
7729    * 32-bit each, or like a concatenated list of flag nicks,
7730    * with either '+' or '/' in front. The first form
7731    * may optionally be followed by ':' and a set of text flag descriptions
7732    * for easier debugging */
7733
7734   /* Try and interpret as hex form first, as it's the most efficient */
7735   /* Read the flags first */
7736   flags = strtoul (s, &next, 16);
7737   if (G_UNLIKELY ((flags == 0 && errno == EINVAL) || s == next))
7738     goto try_as_flags_string;
7739   /* Next char should be a colon */
7740   if (next[0] == ':')
7741     next++;
7742
7743   /* Read the mask */
7744   cur = next;
7745   mask = strtoul (cur, &next, 16);
7746   if (G_UNLIKELY ((mask == 0 && errno == EINVAL) || cur == next))
7747     goto try_as_flags_string;
7748
7749   /* Next char should be NULL terminator, or a ':'. If ':', we need the flag string after */
7750   if (G_UNLIKELY (next[0] == 0)) {
7751     res = TRUE;
7752     goto done;
7753   }
7754
7755   if (next[0] != ':')
7756     return FALSE;
7757
7758   s = next + 1;
7759
7760   if (g_str_equal (g_type_name (G_VALUE_TYPE (dest)), "GstFlagSet")) {
7761     /* If we're parsing a generic flag set, that can mean we're guessing
7762      * at the type in deserialising a GstStructure so at least check that
7763      * we have a valid-looking string, so we don't cause deserialisation of
7764      * other types of strings like 00:01:00:00 - https://bugzilla.gnome.org/show_bug.cgi?id=779755 */
7765     if (is_valid_flags_string (s)) {
7766       res = TRUE;
7767       goto done;
7768     }
7769     return FALSE;
7770   }
7771
7772   /* Otherwise, we already got a hex string for a valid non-generic flagset type */
7773   res = TRUE;
7774   goto done;
7775
7776 try_as_flags_string:
7777
7778   {
7779     const gchar *set_class = g_type_name (G_VALUE_TYPE (dest));
7780     GFlagsClass *flags_klass = NULL;
7781     const gchar *end;
7782
7783     if (g_str_equal (set_class, "GstFlagSet")) {
7784       /* There's no hope to parse the fields of generic flag set if we didn't already
7785        * catch a hex-string above */
7786       return FALSE;
7787     }
7788
7789     /* Flags class is the FlagSet class with 'Set' removed from the end */
7790     end = g_strrstr (set_class, "Set");
7791
7792     if (end != NULL) {
7793       gchar *class_name = g_strndup (set_class, end - set_class);
7794       GType flags_type = g_type_from_name (class_name);
7795       if (flags_type == G_TYPE_INVALID) {
7796         GST_TRACE ("Looking for dynamic type %s", class_name);
7797         gst_dynamic_type_factory_load (class_name);
7798       }
7799
7800       if (flags_type != G_TYPE_INVALID) {
7801         flags_klass = g_type_class_ref (flags_type);
7802         GST_TRACE ("Going to parse %s as %s", s, class_name);
7803       }
7804       g_free (class_name);
7805     }
7806
7807     if (flags_klass) {
7808       res = gst_value_gflags_str_to_flags (flags_klass, s, &flags, &mask);
7809       g_type_class_unref (flags_klass);
7810     }
7811   }
7812
7813 done:
7814   if (res)
7815     gst_value_set_flagset (dest, flags, mask);
7816   return res;
7817
7818 }
7819
7820 static void
7821 gst_value_transform_flagset_string (const GValue * src_value,
7822     GValue * dest_value)
7823 {
7824   dest_value->data[0].v_pointer = gst_value_serialize_flagset (src_value);
7825 }
7826
7827 static void
7828 gst_value_transform_string_flagset (const GValue * src_value,
7829     GValue * dest_value)
7830 {
7831   if (!gst_value_deserialize_flagset (dest_value, src_value->data[0].v_pointer)) {
7832     /* If the deserialize fails, ensure we leave the flags in a
7833      * valid, if incorrect, state */
7834     gst_value_set_flagset (dest_value, 0, 0);
7835   }
7836 }
7837
7838 static gint
7839 gst_value_compare_flagset (const GValue * value1, const GValue * value2)
7840 {
7841   guint v1, v2;
7842   guint m1, m2;
7843
7844   v1 = value1->data[0].v_uint;
7845   v2 = value2->data[0].v_uint;
7846
7847   m1 = value1->data[1].v_uint;
7848   m2 = value2->data[1].v_uint;
7849
7850   if (v1 == v2 && m1 == m2)
7851     return GST_VALUE_EQUAL;
7852
7853   return GST_VALUE_UNORDERED;
7854 }
7855
7856 /***********************
7857  * GstAllocationParams *
7858  ***********************/
7859 static gint
7860 gst_value_compare_allocation_params (const GValue * value1,
7861     const GValue * value2)
7862 {
7863   GstAllocationParams *v1, *v2;
7864
7865   v1 = value1->data[0].v_pointer;
7866   v2 = value2->data[0].v_pointer;
7867
7868   if (v1 == NULL && v1 == v2)
7869     return GST_VALUE_EQUAL;
7870
7871   if (v1 == NULL || v2 == NULL)
7872     return GST_VALUE_UNORDERED;
7873
7874   if (v1->flags == v2->flags && v1->align == v2->align &&
7875       v1->prefix == v2->prefix && v1->padding == v2->padding)
7876     return GST_VALUE_EQUAL;
7877
7878   return GST_VALUE_UNORDERED;
7879 }
7880
7881
7882 /************
7883  * GObject *
7884  ************/
7885
7886 static gint
7887 gst_value_compare_object (const GValue * value1, const GValue * value2)
7888 {
7889   gpointer v1, v2;
7890
7891   v1 = value1->data[0].v_pointer;
7892   v2 = value2->data[0].v_pointer;
7893
7894   if (v1 == v2)
7895     return GST_VALUE_EQUAL;
7896
7897   return GST_VALUE_UNORDERED;
7898 }
7899
7900 static void
7901 gst_value_transform_object_string (const GValue * src_value,
7902     GValue * dest_value)
7903 {
7904   GstObject *obj;
7905   gchar *str;
7906
7907   obj = g_value_get_object (src_value);
7908   if (obj) {
7909     str =
7910         g_strdup_printf ("(%s) %s", G_OBJECT_TYPE_NAME (obj),
7911         GST_OBJECT_NAME (obj));
7912   } else {
7913     str = g_strdup ("NULL");
7914   }
7915
7916   dest_value->data[0].v_pointer = str;
7917 }
7918
7919 static GTypeInfo _info = {
7920   0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL,
7921 };
7922
7923 static GTypeFundamentalInfo _finfo = {
7924   0
7925 };
7926
7927 #define FUNC_VALUE_GET_TYPE_CLASSED(type, name, csize, flags)   \
7928 GType _gst_ ## type ## _type = 0;                               \
7929                                                                 \
7930 GType gst_ ## type ## _get_type (void)                          \
7931 {                                                               \
7932   static GType gst_ ## type ## _type = 0;              \
7933                                                                 \
7934   if (g_once_init_enter (&gst_ ## type ## _type)) {             \
7935     GType _type;                                                \
7936     _info.class_size = csize;                                   \
7937     _finfo.type_flags = flags;                                  \
7938     _info.value_table = & _gst_ ## type ## _value_table;        \
7939     _type = g_type_register_fundamental (                       \
7940         g_type_fundamental_next (),                             \
7941         name, &_info, &_finfo, 0);                              \
7942     _gst_ ## type ## _type = _type;                             \
7943     g_once_init_leave(&gst_ ## type ## _type, _type);           \
7944   }                                                             \
7945                                                                 \
7946   return gst_ ## type ## _type;                                 \
7947 }
7948
7949 #define FUNC_VALUE_GET_TYPE(type, name) \
7950   FUNC_VALUE_GET_TYPE_CLASSED(type, name, 0, 0)
7951
7952 static const GTypeValueTable _gst_int_range_value_table = {
7953   gst_value_init_int_range,
7954   NULL,
7955   gst_value_copy_int_range,
7956   NULL,
7957   (char *) "ii",
7958   gst_value_collect_int_range, (char *) "pp", gst_value_lcopy_int_range
7959 };
7960
7961 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
7962
7963 static const GTypeValueTable _gst_int64_range_value_table = {
7964   gst_value_init_int64_range,
7965   gst_value_free_int64_range,
7966   gst_value_copy_int64_range,
7967   NULL,
7968   (char *) "qq",
7969   gst_value_collect_int64_range,
7970   (char *) "pp", gst_value_lcopy_int64_range
7971 };
7972
7973 FUNC_VALUE_GET_TYPE (int64_range, "GstInt64Range");
7974
7975 static const GTypeValueTable _gst_double_range_value_table = {
7976   gst_value_init_double_range,
7977   NULL,
7978   gst_value_copy_double_range,
7979   NULL,
7980   (char *) "dd",
7981   gst_value_collect_double_range,
7982   (char *) "pp", gst_value_lcopy_double_range
7983 };
7984
7985 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
7986
7987 static const GTypeValueTable _gst_fraction_range_value_table = {
7988   gst_value_init_fraction_range,
7989   gst_value_free_fraction_range,
7990   gst_value_copy_fraction_range,
7991   NULL,
7992   (char *) "iiii",
7993   gst_value_collect_fraction_range,
7994   (char *) "pppp", gst_value_lcopy_fraction_range
7995 };
7996
7997 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
7998
7999 static const GTypeValueTable _gst_value_list_value_table = {
8000   gst_value_init_list_or_array,
8001   gst_value_free_list_or_array,
8002   gst_value_copy_list_or_array,
8003   gst_value_list_or_array_peek_pointer,
8004   (char *) "p",
8005   gst_value_collect_list_or_array,
8006   (char *) "p", gst_value_lcopy_list_or_array
8007 };
8008
8009 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
8010
8011 static const GTypeValueTable _gst_value_array_value_table = {
8012   gst_value_init_list_or_array,
8013   gst_value_free_list_or_array,
8014   gst_value_copy_list_or_array,
8015   gst_value_list_or_array_peek_pointer,
8016   (char *) "p",
8017   gst_value_collect_list_or_array,
8018   (char *) "p", gst_value_lcopy_list_or_array
8019 };
8020
8021 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
8022
8023 static const GTypeValueTable _gst_fraction_value_table = {
8024   gst_value_init_fraction,
8025   NULL,
8026   gst_value_copy_fraction,
8027   NULL,
8028   (char *) "ii",
8029   gst_value_collect_fraction, (char *) "pp", gst_value_lcopy_fraction
8030 };
8031
8032 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
8033
8034 static const GTypeValueTable _gst_bitmask_value_table = {
8035   gst_value_init_bitmask,
8036   NULL,
8037   gst_value_copy_bitmask,
8038   NULL,
8039   (char *) "q",
8040   gst_value_collect_bitmask, (char *) "p", gst_value_lcopy_bitmask
8041 };
8042
8043 FUNC_VALUE_GET_TYPE (bitmask, "GstBitmask");
8044
8045 static const GTypeValueTable _gst_flagset_value_table = {
8046   gst_value_init_flagset,
8047   NULL,
8048   gst_value_copy_flagset,
8049   NULL,
8050   (char *) "ii",
8051   gst_value_collect_flagset, (char *) "pp", gst_value_lcopy_flagset
8052 };
8053
8054 FUNC_VALUE_GET_TYPE_CLASSED (flagset, "GstFlagSet",
8055     sizeof (GstFlagSetClass), G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_DERIVABLE);
8056
8057 GType
8058 gst_g_thread_get_type (void)
8059 {
8060   return G_TYPE_THREAD;
8061 }
8062
8063 #define SERIAL_VTABLE(t,c,s,d) { t, c, s, d, NULL }
8064 #define SERIAL_VTABLE_PSPEC(t,c,s,d) { t, c, s, NULL, d }
8065
8066 #define REGISTER_SERIALIZATION_CONST(_gtype, _type)                     \
8067 G_STMT_START {                                                          \
8068   static const GstValueTable gst_value =                                \
8069     SERIAL_VTABLE (_gtype, gst_value_compare_ ## _type,                 \
8070     gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type);    \
8071   gst_value_register (&gst_value);                                      \
8072 } G_STMT_END
8073
8074 #define REGISTER_SERIALIZATION(_gtype, _type)                           \
8075 G_STMT_START {                                                          \
8076   static GstValueTable gst_value =                                      \
8077     SERIAL_VTABLE (0, gst_value_compare_ ## _type,                      \
8078     gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type);    \
8079   gst_value.type = _gtype;                                              \
8080   gst_value_register (&gst_value);                                      \
8081 } G_STMT_END
8082
8083 #define REGISTER_SERIALIZATION_WITH_PSPEC(_gtype, _type)                \
8084 G_STMT_START {                                                          \
8085   static GstValueTable gst_value =                                      \
8086     SERIAL_VTABLE_PSPEC (0, gst_value_compare_ ## _type,                \
8087     gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type);    \
8088   gst_value.type = _gtype;                                              \
8089   gst_value_register (&gst_value);                                      \
8090 } G_STMT_END
8091
8092 #define REGISTER_SERIALIZATION_NO_COMPARE(_gtype, _type)                \
8093 G_STMT_START {                                                          \
8094   static GstValueTable gst_value =                                      \
8095     SERIAL_VTABLE (0, NULL,                                             \
8096     gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type);    \
8097   gst_value.type = _gtype;                                              \
8098   gst_value_register (&gst_value);                                      \
8099 } G_STMT_END
8100
8101 #define REGISTER_SERIALIZATION_COMPARE_ONLY(_gtype, _type)              \
8102 G_STMT_START {                                                          \
8103   static GstValueTable gst_value =                                      \
8104     SERIAL_VTABLE (0, gst_value_compare_ ## _type,                      \
8105         NULL, NULL);                                                    \
8106   gst_value.type = _gtype;                                              \
8107   gst_value_register (&gst_value);                                      \
8108 } G_STMT_END
8109
8110 /* These initial sizes are used for the tables
8111  * below, and save a couple of reallocs at startup */
8112
8113 static const gint GST_VALUE_TABLE_DEFAULT_SIZE = 40;
8114 static const gint GST_VALUE_UNION_TABLE_DEFAULT_SIZE = 8;
8115 static const gint GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE = 4;
8116 static const gint GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE = 16;
8117
8118 void
8119 _priv_gst_value_initialize (void)
8120 {
8121   gst_value_table =
8122       g_array_sized_new (FALSE, FALSE, sizeof (GstValueTable),
8123       GST_VALUE_TABLE_DEFAULT_SIZE);
8124   gst_value_hash = g_hash_table_new (NULL, NULL);
8125   gst_value_union_funcs = g_array_sized_new (FALSE, FALSE,
8126       sizeof (GstValueUnionInfo), GST_VALUE_UNION_TABLE_DEFAULT_SIZE);
8127   gst_value_intersect_funcs = g_array_sized_new (FALSE, FALSE,
8128       sizeof (GstValueIntersectInfo), GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE);
8129   gst_value_subtract_funcs = g_array_sized_new (FALSE, FALSE,
8130       sizeof (GstValueSubtractInfo), GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE);
8131
8132   REGISTER_SERIALIZATION (gst_int_range_get_type (), int_range);
8133   REGISTER_SERIALIZATION (gst_int64_range_get_type (), int64_range);
8134   REGISTER_SERIALIZATION (gst_double_range_get_type (), double_range);
8135   REGISTER_SERIALIZATION (gst_fraction_range_get_type (), fraction_range);
8136   REGISTER_SERIALIZATION (g_value_array_get_type (), g_value_array);
8137   REGISTER_SERIALIZATION (gst_buffer_get_type (), buffer);
8138   REGISTER_SERIALIZATION (gst_sample_get_type (), sample);
8139   REGISTER_SERIALIZATION (gst_fraction_get_type (), fraction);
8140   REGISTER_SERIALIZATION (gst_caps_get_type (), caps);
8141   REGISTER_SERIALIZATION (gst_tag_list_get_type (), tag_list);
8142   REGISTER_SERIALIZATION (G_TYPE_DATE, date);
8143   REGISTER_SERIALIZATION (G_TYPE_BYTES, bytes);
8144   REGISTER_SERIALIZATION (gst_date_time_get_type (), date_time);
8145   REGISTER_SERIALIZATION (gst_bitmask_get_type (), bitmask);
8146   REGISTER_SERIALIZATION (gst_structure_get_type (), structure);
8147   REGISTER_SERIALIZATION (gst_flagset_get_type (), flagset);
8148
8149   REGISTER_SERIALIZATION_NO_COMPARE (gst_segment_get_type (), segment);
8150   REGISTER_SERIALIZATION_NO_COMPARE (gst_caps_features_get_type (),
8151       caps_features);
8152
8153   REGISTER_SERIALIZATION_COMPARE_ONLY (gst_allocation_params_get_type (),
8154       allocation_params);
8155   REGISTER_SERIALIZATION_COMPARE_ONLY (G_TYPE_OBJECT, object);
8156
8157   REGISTER_SERIALIZATION_CONST (G_TYPE_DOUBLE, double);
8158   REGISTER_SERIALIZATION_CONST (G_TYPE_FLOAT, float);
8159
8160   REGISTER_SERIALIZATION_CONST (G_TYPE_STRING, string);
8161   REGISTER_SERIALIZATION_CONST (G_TYPE_BOOLEAN, boolean);
8162   REGISTER_SERIALIZATION_CONST (G_TYPE_ENUM, enum);
8163
8164   REGISTER_SERIALIZATION_CONST (G_TYPE_FLAGS, gflags);
8165
8166   REGISTER_SERIALIZATION_CONST (G_TYPE_INT, int);
8167
8168   REGISTER_SERIALIZATION_CONST (G_TYPE_INT64, int64);
8169   REGISTER_SERIALIZATION_CONST (G_TYPE_LONG, long);
8170
8171   REGISTER_SERIALIZATION_CONST (G_TYPE_UINT, uint);
8172   REGISTER_SERIALIZATION_CONST (G_TYPE_UINT64, uint64);
8173   REGISTER_SERIALIZATION_CONST (G_TYPE_ULONG, ulong);
8174
8175   REGISTER_SERIALIZATION_CONST (G_TYPE_UCHAR, uchar);
8176
8177   REGISTER_SERIALIZATION (G_TYPE_GTYPE, gtype);
8178
8179   REGISTER_SERIALIZATION_WITH_PSPEC (gst_value_list_get_type (), value_list);
8180   REGISTER_SERIALIZATION_WITH_PSPEC (gst_value_array_get_type (), value_array);
8181
8182   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
8183       gst_value_transform_int_range_string);
8184   g_value_register_transform_func (GST_TYPE_INT64_RANGE, G_TYPE_STRING,
8185       gst_value_transform_int64_range_string);
8186   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
8187       gst_value_transform_double_range_string);
8188   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
8189       gst_value_transform_fraction_range_string);
8190   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
8191       gst_value_transform_list_string);
8192   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_VALUE_ARRAY,
8193       gst_value_transform_any_list_g_value_array);
8194   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
8195       gst_value_transform_array_string);
8196   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_VALUE_ARRAY,
8197       gst_value_transform_any_list_g_value_array);
8198   g_value_register_transform_func (G_TYPE_VALUE_ARRAY, G_TYPE_STRING,
8199       gst_value_transform_g_value_array_string);
8200   g_value_register_transform_func (G_TYPE_VALUE_ARRAY, GST_TYPE_ARRAY,
8201       gst_value_transform_g_value_array_any_list);
8202   g_value_register_transform_func (G_TYPE_VALUE_ARRAY, GST_TYPE_LIST,
8203       gst_value_transform_g_value_array_any_list);
8204   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
8205       gst_value_transform_fraction_string);
8206   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
8207       gst_value_transform_string_fraction);
8208   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
8209       gst_value_transform_fraction_double);
8210   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_FLOAT,
8211       gst_value_transform_fraction_float);
8212   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
8213       gst_value_transform_double_fraction);
8214   g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION,
8215       gst_value_transform_float_fraction);
8216   g_value_register_transform_func (G_TYPE_DATE, G_TYPE_STRING,
8217       gst_value_transform_date_string);
8218   g_value_register_transform_func (G_TYPE_STRING, G_TYPE_DATE,
8219       gst_value_transform_string_date);
8220   g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING,
8221       gst_value_transform_object_string);
8222   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_UINT64,
8223       gst_value_transform_bitmask_uint64);
8224   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_STRING,
8225       gst_value_transform_bitmask_string);
8226   g_value_register_transform_func (G_TYPE_UINT64, GST_TYPE_BITMASK,
8227       gst_value_transform_uint64_bitmask);
8228   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_BITMASK,
8229       gst_value_transform_string_bitmask);
8230
8231   g_value_register_transform_func (GST_TYPE_FLAG_SET, G_TYPE_STRING,
8232       gst_value_transform_flagset_string);
8233   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FLAG_SET,
8234       gst_value_transform_string_flagset);
8235
8236   /* Only register intersection functions for *different* types.
8237    * Identical type intersection should be specified directly in
8238    * gst_value_intersect() */
8239   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
8240       gst_value_intersect_int_int_range);
8241   gst_value_register_intersect_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
8242       gst_value_intersect_int64_int64_range);
8243   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
8244       gst_value_intersect_double_double_range);
8245   gst_value_register_intersect_func (GST_TYPE_FRACTION,
8246       GST_TYPE_FRACTION_RANGE, gst_value_intersect_fraction_fraction_range);
8247
8248   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
8249       gst_value_subtract_int_int_range);
8250   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
8251       gst_value_subtract_int_range_int);
8252   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
8253       gst_value_subtract_int_range_int_range);
8254   gst_value_register_subtract_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
8255       gst_value_subtract_int64_int64_range);
8256   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, G_TYPE_INT64,
8257       gst_value_subtract_int64_range_int64);
8258   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE,
8259       GST_TYPE_INT64_RANGE, gst_value_subtract_int64_range_int64_range);
8260   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
8261       gst_value_subtract_double_double_range);
8262   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
8263       gst_value_subtract_double_range_double);
8264   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
8265       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
8266   gst_value_register_subtract_func (GST_TYPE_FRACTION,
8267       GST_TYPE_FRACTION_RANGE, gst_value_subtract_fraction_fraction_range);
8268   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
8269       GST_TYPE_FRACTION, gst_value_subtract_fraction_range_fraction);
8270   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
8271       GST_TYPE_FRACTION_RANGE,
8272       gst_value_subtract_fraction_range_fraction_range);
8273
8274   {
8275     GType date_type = G_TYPE_DATE;
8276
8277     g_type_name (date_type);
8278   }
8279
8280   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
8281       gst_value_union_int_int_range);
8282   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
8283       gst_value_union_int_range_int_range);
8284   gst_value_register_union_func (GST_TYPE_FLAG_SET, GST_TYPE_FLAG_SET,
8285       gst_value_union_flagset_flagset);
8286   gst_value_register_union_func (GST_TYPE_STRUCTURE, GST_TYPE_STRUCTURE,
8287       gst_value_union_structure_structure);
8288
8289 #if GST_VERSION_NANO == 1
8290   /* If building from git master, check starting array sizes matched actual size
8291    * so we can keep the defines in sync and save a few reallocs on startup */
8292   if (gst_value_table->len > GST_VALUE_TABLE_DEFAULT_SIZE) {
8293     GST_ERROR ("Wrong initial gst_value_table size. "
8294         "Please set GST_VALUE_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
8295         gst_value_table->len);
8296   }
8297   if (gst_value_union_funcs->len > GST_VALUE_UNION_TABLE_DEFAULT_SIZE) {
8298     GST_ERROR ("Wrong initial gst_value_union_funcs table size. "
8299         "Please set GST_VALUE_UNION_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
8300         gst_value_union_funcs->len);
8301   }
8302   if (gst_value_intersect_funcs->len > GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE) {
8303     GST_ERROR ("Wrong initial gst_value_intersect_funcs table size. "
8304         "Please set GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
8305         gst_value_intersect_funcs->len);
8306   }
8307   if (gst_value_subtract_funcs->len > GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE) {
8308     GST_ERROR ("Wrong initial gst_value_subtract_funcs table size. "
8309         "Please set GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
8310         gst_value_subtract_funcs->len);
8311   }
8312 #endif
8313
8314 #if 0
8315   /* Implement these if needed */
8316   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
8317       gst_value_union_fraction_fraction_range);
8318   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
8319       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
8320 #endif
8321 }
8322
8323 static void
8324 gst_flagset_class_init (gpointer g_class, gpointer class_data)
8325 {
8326   GstFlagSetClass *f_class = (GstFlagSetClass *) (g_class);
8327   f_class->flags_type = (GType) GPOINTER_TO_SIZE (class_data);
8328 }
8329
8330 /**
8331  * gst_flagset_register:
8332  * @flags_type: a #GType of a #G_TYPE_FLAGS type.
8333  *
8334  * Create a new sub-class of #GST_TYPE_FLAG_SET
8335  * which will pretty-print the human-readable flags
8336  * when serializing, for easier debugging.
8337  *
8338  * Since: 1.6
8339  */
8340 GType
8341 gst_flagset_register (GType flags_type)
8342 {
8343   GTypeInfo info = {
8344     sizeof (GstFlagSetClass),
8345     NULL, NULL,
8346     (GClassInitFunc) gst_flagset_class_init,
8347     NULL, GSIZE_TO_POINTER (flags_type), 0, 0, NULL, NULL
8348   };
8349   GType t;
8350   gchar *class_name;
8351
8352   g_return_val_if_fail (G_TYPE_IS_FLAGS (flags_type), 0);
8353
8354   class_name = g_strdup_printf ("%sSet", g_type_name (flags_type));
8355
8356   t = g_type_register_static (GST_TYPE_FLAG_SET,
8357       g_intern_string (class_name), &info, 0);
8358   g_free (class_name);
8359
8360   return t;
8361 }