tools: Count argc after parsing GOption on Windows
[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       {"gdatetime", G_TYPE_DATE_TIME}
2336       ,
2337       {"bitmask", GST_TYPE_BITMASK}
2338       ,
2339       {"flagset", GST_TYPE_FLAG_SET}
2340       ,
2341       {"sample", GST_TYPE_SAMPLE}
2342       ,
2343       {"taglist", GST_TYPE_TAG_LIST}
2344       ,
2345       {"type", G_TYPE_GTYPE}
2346       ,
2347       {"array", GST_TYPE_ARRAY}
2348       ,
2349       {"list", GST_TYPE_LIST}
2350     };
2351     _num = G_N_ELEMENTS (dyn_abbrs);
2352     /* permanently allocate and copy the array now */
2353     abbrs = g_new0 (GstValueAbbreviation, _num);
2354     memcpy (abbrs, dyn_abbrs, sizeof (GstValueAbbreviation) * _num);
2355     g_once_init_leave (&num, _num);
2356   }
2357   *n_abbrs = num;
2358
2359   return abbrs;
2360 }
2361
2362 /* given a type_name that could be a type abbreviation or a registered GType,
2363  * return a matching GType */
2364 static GType
2365 _priv_gst_value_gtype_from_abbr (const char *type_name)
2366 {
2367   int i;
2368   GstValueAbbreviation *abbrs;
2369   gint n_abbrs;
2370   GType ret;
2371
2372   g_return_val_if_fail (type_name != NULL, G_TYPE_INVALID);
2373
2374   abbrs = _priv_gst_value_get_abbrs (&n_abbrs);
2375
2376   for (i = 0; i < n_abbrs; i++) {
2377     if (strcmp (type_name, abbrs[i].type_name) == 0) {
2378       return abbrs[i].type;
2379     }
2380   }
2381
2382   /* this is the fallback */
2383   ret = g_type_from_name (type_name);
2384   /* If not found, try it as a dynamic type */
2385   if (G_UNLIKELY (ret == 0))
2386     ret = gst_dynamic_type_factory_load (type_name);
2387   return ret;
2388
2389 }
2390
2391 const char *
2392 _priv_gst_value_gtype_to_abbr (GType type)
2393 {
2394   int i;
2395   GstValueAbbreviation *abbrs;
2396   gint n_abbrs;
2397
2398   g_return_val_if_fail (type != G_TYPE_INVALID, NULL);
2399
2400   abbrs = _priv_gst_value_get_abbrs (&n_abbrs);
2401
2402   for (i = 0; i < n_abbrs; i++) {
2403     if (type == abbrs[i].type) {
2404       return abbrs[i].type_name;
2405     }
2406   }
2407
2408   return g_type_name (type);
2409 }
2410
2411 /*
2412  * _priv_gst_value_parse_string:
2413  * @s: string to parse
2414  * @end: out-pointer to char behind end of string
2415  * @next: out-pointer to start of unread data
2416  * @unescape: @TRUE if the substring is escaped.
2417  *
2418  * Find the end of a sub-string. If end == next, the string will not be
2419  * null-terminated. In all other cases it will be.
2420  *
2421  * Note: This function modifies the string in @s (if unescape == @TRUE).
2422  *
2423  * Returns: @TRUE if a sub-string was found and @FALSE if the string is not
2424  * terminated.
2425  */
2426 gboolean
2427 _priv_gst_value_parse_string (gchar * s, gchar ** end, gchar ** next,
2428     gboolean unescape)
2429 {
2430   gchar *w;
2431
2432   if (*s == 0)
2433     return FALSE;
2434
2435   if (*s != '"') {
2436     int ret = _priv_gst_value_parse_simple_string (s, end);
2437     *next = *end;
2438
2439     return ret;
2440   }
2441
2442   /* Find the closing quotes */
2443   if (unescape) {
2444     w = s;
2445     s++;
2446     while (*s != '"') {
2447       if (G_UNLIKELY (*s == 0))
2448         return FALSE;
2449       if (G_UNLIKELY (*s == '\\')) {
2450         s++;
2451         if (G_UNLIKELY (*s == 0))
2452           return FALSE;
2453       }
2454       *w = *s;
2455       w++;
2456       s++;
2457     }
2458     s++;
2459   } else {
2460     s++;
2461     while (*s != '"') {
2462       if (G_UNLIKELY (*s == 0))
2463         return FALSE;
2464       if (G_UNLIKELY (*s == '\\')) {
2465         s++;
2466         if (G_UNLIKELY (*s == 0))
2467           return FALSE;
2468       }
2469       s++;
2470     }
2471     s++;
2472     w = s;
2473   }
2474
2475   *end = w;
2476   *next = s;
2477
2478   return TRUE;
2479 }
2480
2481 static gboolean
2482 _priv_gst_value_parse_range (gchar * s, gchar ** after, GValue * value,
2483     GType type)
2484 {
2485   GValue value1 = { 0 };
2486   GValue value2 = { 0 };
2487   GValue value3 = { 0 };
2488   GType range_type;
2489   gboolean ret, have_step = FALSE;
2490
2491   if (*s != '[')
2492     return FALSE;
2493   s++;
2494
2495   ret = _priv_gst_value_parse_value (s, &s, &value1, type, NULL);
2496   if (!ret)
2497     goto err;
2498
2499   while (g_ascii_isspace (*s))
2500     s++;
2501
2502   if (*s != ',')
2503     goto err;
2504   s++;
2505
2506   while (g_ascii_isspace (*s))
2507     s++;
2508
2509   ret = _priv_gst_value_parse_value (s, &s, &value2, type, NULL);
2510   if (!ret)
2511     goto err;
2512
2513   while (g_ascii_isspace (*s))
2514     s++;
2515
2516   /* optional step for int and int64 */
2517   if (G_VALUE_TYPE (&value1) == G_TYPE_INT
2518       || G_VALUE_TYPE (&value1) == G_TYPE_INT64) {
2519     if (*s == ',') {
2520       s++;
2521
2522       while (g_ascii_isspace (*s))
2523         s++;
2524
2525       ret = _priv_gst_value_parse_value (s, &s, &value3, type, NULL);
2526       if (!ret)
2527         goto err;
2528
2529       while (g_ascii_isspace (*s))
2530         s++;
2531
2532       have_step = TRUE;
2533     }
2534   }
2535
2536   if (*s != ']')
2537     goto err;
2538   s++;
2539
2540   if (G_VALUE_TYPE (&value1) != G_VALUE_TYPE (&value2))
2541     return FALSE;
2542   if (have_step && G_VALUE_TYPE (&value1) != G_VALUE_TYPE (&value3))
2543     return FALSE;
2544
2545   if (G_VALUE_TYPE (&value1) == G_TYPE_DOUBLE) {
2546     range_type = GST_TYPE_DOUBLE_RANGE;
2547     g_value_init (value, range_type);
2548     gst_value_set_double_range (value,
2549         gst_g_value_get_double_unchecked (&value1),
2550         gst_g_value_get_double_unchecked (&value2));
2551   } else if (G_VALUE_TYPE (&value1) == G_TYPE_INT) {
2552     range_type = GST_TYPE_INT_RANGE;
2553     g_value_init (value, range_type);
2554     if (have_step)
2555       gst_value_set_int_range_step (value,
2556           gst_g_value_get_int_unchecked (&value1),
2557           gst_g_value_get_int_unchecked (&value2),
2558           gst_g_value_get_int_unchecked (&value3));
2559     else
2560       gst_value_set_int_range (value, gst_g_value_get_int_unchecked (&value1),
2561           gst_g_value_get_int_unchecked (&value2));
2562   } else if (G_VALUE_TYPE (&value1) == G_TYPE_INT64) {
2563     range_type = GST_TYPE_INT64_RANGE;
2564     g_value_init (value, range_type);
2565     if (have_step)
2566       gst_value_set_int64_range_step (value,
2567           gst_g_value_get_int64_unchecked (&value1),
2568           gst_g_value_get_int64_unchecked (&value2),
2569           gst_g_value_get_int64_unchecked (&value3));
2570     else
2571       gst_value_set_int64_range (value,
2572           gst_g_value_get_int64_unchecked (&value1),
2573           gst_g_value_get_int64_unchecked (&value2));
2574   } else if (G_VALUE_TYPE (&value1) == GST_TYPE_FRACTION) {
2575     range_type = GST_TYPE_FRACTION_RANGE;
2576     g_value_init (value, range_type);
2577     gst_value_set_fraction_range (value, &value1, &value2);
2578   } else {
2579     goto err;
2580   }
2581
2582   *after = s;
2583   return TRUE;
2584
2585 err:
2586   g_value_unset (value);
2587   g_value_unset (&value1);
2588   g_value_unset (&value2);
2589   g_value_unset (&value3);
2590   return FALSE;
2591 }
2592
2593 static gboolean
2594 _priv_gst_value_parse_any_list (gchar * s, gchar ** after, GValue * value,
2595     GType type, char begin, char end, GParamSpec * pspec)
2596 {
2597   GValue list_value = { 0 };
2598   gboolean ret;
2599   GstValueList *vlist = VALUE_LIST_ARRAY (value);
2600   GParamSpec *element_spec = NULL;
2601
2602   if (pspec)
2603     element_spec = GST_PARAM_SPEC_ARRAY_LIST (pspec)->element_spec;
2604
2605   if (*s != begin)
2606     return FALSE;
2607   s++;
2608
2609   while (g_ascii_isspace (*s))
2610     s++;
2611
2612   while (*s != end) {
2613     if (*s == ',') {
2614       s++;
2615       while (g_ascii_isspace (*s))
2616         s++;
2617
2618       if (*s == ',')
2619         return FALSE;
2620
2621       continue;
2622     }
2623
2624     memset (&list_value, 0, sizeof (list_value));
2625
2626     ret = _priv_gst_value_parse_value (s, &s, &list_value, type, element_spec);
2627     if (!ret)
2628       return FALSE;
2629
2630     _gst_value_list_append_val (vlist, &list_value);
2631
2632     while (g_ascii_isspace (*s))
2633       s++;
2634
2635     if (*s != ',' && *s != end)
2636       return FALSE;
2637   }
2638
2639   s++;
2640
2641   *after = s;
2642   return TRUE;
2643 }
2644
2645 static gboolean
2646 _priv_gst_value_parse_list (gchar * s, gchar ** after, GValue * value,
2647     GType type, GParamSpec * pspec)
2648 {
2649   return _priv_gst_value_parse_any_list (s, after, value, type, '{', '}',
2650       pspec);
2651 }
2652
2653 static gboolean
2654 _priv_gst_value_parse_array (gchar * s, gchar ** after, GValue * value,
2655     GType type, GParamSpec * pspec)
2656 {
2657   return _priv_gst_value_parse_any_list (s, after, value, type, '<', '>',
2658       pspec);
2659 }
2660
2661 gboolean
2662 _priv_gst_value_parse_simple_string (gchar * str, gchar ** end)
2663 {
2664   char *s = str;
2665
2666   while (G_LIKELY (GST_ASCII_IS_STRING (*s))) {
2667     s++;
2668   }
2669
2670   *end = s;
2671
2672   return (s != str);
2673 }
2674
2675 static gboolean
2676 _priv_gst_value_parse_struct_or_caps (gchar * str, gchar ** after, GType type,
2677     GValue * value)
2678 {
2679   gint openers = 1;
2680   gboolean ret = FALSE;
2681   gchar *s = str, t, *start, *end, *next;
2682
2683   if (*s != '[')
2684     return FALSE;
2685
2686   s++;
2687   str = s;
2688   for (; *s; s++) {
2689     if (*s == ']')
2690       openers--;
2691     else if (*s == '[')
2692       openers++;
2693
2694     if (openers == 0) {
2695       *after = s + 1;
2696       break;
2697     }
2698   }
2699
2700   if (*after == NULL)
2701     return FALSE;
2702
2703   t = *s;
2704   *s = '\0';
2705   g_value_init (value, type);
2706   if (priv_gst_structure_parse_name (str, &start, &end, &next, TRUE))
2707     ret = gst_value_deserialize (value, str);
2708   if (G_UNLIKELY (!ret)) {
2709     *s = t;
2710     g_value_unset (value);
2711   }
2712
2713   return ret;
2714 }
2715
2716 static gboolean
2717 _priv_gst_value_parse_range_struct_caps (gchar * s, gchar ** after,
2718     GValue * value, GType type)
2719 {
2720   gint i;
2721   gchar *tmp = s;
2722   gboolean ret = FALSE;
2723   GType try_types[] = {
2724     GST_TYPE_STRUCTURE,
2725     GST_TYPE_CAPS,
2726   };
2727
2728   if (type == GST_TYPE_CAPS || type == GST_TYPE_STRUCTURE)
2729     ret = _priv_gst_value_parse_struct_or_caps (tmp, &tmp, type, value);
2730
2731   if (ret)
2732     goto ok;
2733
2734   tmp = s;
2735   ret = _priv_gst_value_parse_range (tmp, &tmp, value, type);
2736   if (ret)
2737     goto ok;
2738
2739   if (type != G_TYPE_INVALID)
2740     return ret;
2741
2742   for (i = 0; i < G_N_ELEMENTS (try_types); i++) {
2743     tmp = s;
2744     ret = _priv_gst_value_parse_struct_or_caps (tmp, &tmp, try_types[i], value);
2745     if (ret)
2746       goto ok;
2747   }
2748
2749   return ret;
2750
2751 ok:
2752   *after = tmp;
2753   return ret;
2754 }
2755
2756 gboolean
2757 _priv_gst_value_parse_value (gchar * str,
2758     gchar ** after, GValue * value, GType default_type, GParamSpec * pspec)
2759 {
2760   gchar *type_name;
2761   gchar *type_end;
2762   gchar *value_s;
2763   gchar *value_end;
2764   gchar *s;
2765   gchar c;
2766   int ret = 0;
2767   GType type = default_type;
2768
2769   s = str;
2770   while (g_ascii_isspace (*s))
2771     s++;
2772
2773   /* check if there's a (type_name) 'cast' */
2774   type_name = NULL;
2775
2776   if (*s == '(') {
2777     s++;
2778     while (g_ascii_isspace (*s))
2779       s++;
2780     type_name = s;
2781     if (G_UNLIKELY (!_priv_gst_value_parse_simple_string (s, &type_end)))
2782       return FALSE;
2783     s = type_end;
2784     while (g_ascii_isspace (*s))
2785       s++;
2786     if (G_UNLIKELY (*s != ')'))
2787       return FALSE;
2788     s++;
2789     while (g_ascii_isspace (*s))
2790       s++;
2791
2792     c = *type_end;
2793     *type_end = 0;
2794     type = _priv_gst_value_gtype_from_abbr (type_name);
2795     GST_DEBUG ("trying type name '%s'", type_name);
2796     *type_end = c;
2797
2798     if (G_UNLIKELY (type == G_TYPE_INVALID)) {
2799       GST_WARNING ("invalid type");
2800       return FALSE;
2801     }
2802   } else if (pspec) {
2803     type = G_PARAM_SPEC_VALUE_TYPE (pspec);
2804   }
2805
2806   while (g_ascii_isspace (*s))
2807     s++;
2808   if (*s == '[') {
2809     ret = _priv_gst_value_parse_range_struct_caps (s, &s, value, type);
2810   } else if (*s == '{') {
2811     g_value_init (value, GST_TYPE_LIST);
2812     ret = _priv_gst_value_parse_list (s, &s, value, type, pspec);
2813   } else if (*s == '<') {
2814     g_value_init (value, GST_TYPE_ARRAY);
2815     ret = _priv_gst_value_parse_array (s, &s, value, type, pspec);
2816   } else {
2817     value_s = s;
2818
2819     if (G_UNLIKELY (type == G_TYPE_INVALID)) {
2820       GType try_types[] =
2821           { G_TYPE_INT, G_TYPE_DOUBLE, GST_TYPE_FRACTION, GST_TYPE_FLAG_SET,
2822         G_TYPE_BOOLEAN, G_TYPE_STRING
2823       };
2824       int i;
2825       int value_size;
2826       gboolean check_wrapped_non_string;
2827
2828       if (G_UNLIKELY (!_priv_gst_value_parse_string (s, &value_end, &s, FALSE)))
2829         return FALSE;
2830       /* Set NULL terminator for deserialization */
2831       value_size = value_end - value_s;
2832       value_s = g_strndup (value_s, value_end - value_s);
2833       /* Keep old broken behavior where "2" could be interpretted as an int */
2834       check_wrapped_non_string = value_s[0] == '"' &&
2835           strlen (value_s) >= 2 && value_end[-1] == '"';
2836
2837       for (i = 0; i < G_N_ELEMENTS (try_types); i++) {
2838         g_value_init (value, try_types[i]);
2839         if (try_types[i] != G_TYPE_STRING && check_wrapped_non_string) {
2840           value_s[value_size - 1] = '\0';
2841           ret = gst_value_deserialize (value, value_s + 1);
2842           value_s[value_size - 1] = '"';
2843           if (ret) {
2844             const gchar *type_name = g_type_name (try_types[i]);
2845
2846             g_warning ("Received a structure string that contains "
2847                 "'=%s'. Reading as a %s value, rather than a string "
2848                 "value. This is undesired behaviour, and with GStreamer 1.22 "
2849                 " onward, this will be interpreted as a string value instead "
2850                 "because it is wrapped in '\"' quotes. If you want to "
2851                 "guarantee this value is read as a string, before this "
2852                 "change, use '=(string)%s' instead. If you want to read "
2853                 "in a %s value, leave its value unquoted.",
2854                 value_s, type_name, value_s, type_name);
2855             break;
2856           }
2857         } else {
2858           ret = gst_value_deserialize (value, value_s);
2859           if (ret)
2860             break;
2861         }
2862         g_value_unset (value);
2863       }
2864     } else {
2865       g_value_init (value, type);
2866
2867       if (G_UNLIKELY (!_priv_gst_value_parse_string (s, &value_end, &s, FALSE)))
2868         return FALSE;
2869       /* Set NULL terminator for deserialization */
2870       value_s = g_strndup (value_s, value_end - value_s);
2871
2872       ret = gst_value_deserialize_with_pspec (value, value_s, pspec);
2873       if (G_UNLIKELY (!ret))
2874         g_value_unset (value);
2875     }
2876     g_free (value_s);
2877   }
2878
2879   *after = s;
2880
2881   return ret;
2882 }
2883
2884 /**************
2885  * GstSegment *
2886  **************/
2887
2888 static gchar *
2889 gst_value_serialize_segment_internal (const GValue * value, gboolean escape)
2890 {
2891   GstSegment *seg = g_value_get_boxed (value);
2892   gchar *t, *res;
2893   GstStructure *s;
2894
2895   s = gst_structure_new_id (GST_QUARK (SEGMENT),
2896       GST_QUARK (FLAGS), GST_TYPE_SEGMENT_FLAGS, seg->flags,
2897       GST_QUARK (RATE), G_TYPE_DOUBLE, seg->rate,
2898       GST_QUARK (APPLIED_RATE), G_TYPE_DOUBLE, seg->applied_rate,
2899       GST_QUARK (FORMAT), GST_TYPE_FORMAT, seg->format,
2900       GST_QUARK (BASE), G_TYPE_UINT64, seg->base,
2901       GST_QUARK (OFFSET), G_TYPE_UINT64, seg->offset,
2902       GST_QUARK (START), G_TYPE_UINT64, seg->start,
2903       GST_QUARK (STOP), G_TYPE_UINT64, seg->stop,
2904       GST_QUARK (TIME), G_TYPE_UINT64, seg->time,
2905       GST_QUARK (POSITION), G_TYPE_UINT64, seg->position,
2906       GST_QUARK (DURATION), G_TYPE_UINT64, seg->duration, NULL);
2907
2908   t = gst_structure_to_string (s);
2909   if (escape) {
2910     res = g_strdup_printf ("\"%s\"", t);
2911     g_free (t);
2912   } else {
2913     res = t;
2914   }
2915   gst_structure_free (s);
2916
2917   return res;
2918 }
2919
2920 static gchar *
2921 gst_value_serialize_segment (const GValue * value)
2922 {
2923   return gst_value_serialize_segment_internal (value, TRUE);
2924 }
2925
2926 static gboolean
2927 gst_value_deserialize_segment_internal (GValue * dest, const gchar * s,
2928     gboolean unescape)
2929 {
2930   GstStructure *str;
2931   GstSegment seg;
2932   gboolean res;
2933   gsize len;
2934   gchar *t;
2935
2936   if (unescape) {
2937     len = strlen (s);
2938     if (G_UNLIKELY (*s != '"' || len < 2 || s[len - 1] != '"')) {
2939       /* "\"" is not an accepted string, so len must be at least 2 */
2940       GST_ERROR ("Failed deserializing segement: expected string to start and "
2941           "end with '\"'");
2942       return FALSE;
2943     }
2944     t = g_strdup (s + 1);
2945     t[len - 2] = '\0';
2946     /* removed trailing '"' */
2947     str = gst_structure_from_string (t, NULL);
2948     g_free (t);
2949   } else {
2950     str = gst_structure_from_string (s, NULL);
2951   }
2952   if (G_UNLIKELY (str == NULL))
2953     return FALSE;
2954
2955   res = gst_structure_id_get (str,
2956       GST_QUARK (FLAGS), GST_TYPE_SEGMENT_FLAGS, &seg.flags,
2957       GST_QUARK (RATE), G_TYPE_DOUBLE, &seg.rate,
2958       GST_QUARK (APPLIED_RATE), G_TYPE_DOUBLE, &seg.applied_rate,
2959       GST_QUARK (FORMAT), GST_TYPE_FORMAT, &seg.format,
2960       GST_QUARK (BASE), G_TYPE_UINT64, &seg.base,
2961       GST_QUARK (OFFSET), G_TYPE_UINT64, &seg.offset,
2962       GST_QUARK (START), G_TYPE_UINT64, &seg.start,
2963       GST_QUARK (STOP), G_TYPE_UINT64, &seg.stop,
2964       GST_QUARK (TIME), G_TYPE_UINT64, &seg.time,
2965       GST_QUARK (POSITION), G_TYPE_UINT64, &seg.position,
2966       GST_QUARK (DURATION), G_TYPE_UINT64, &seg.duration, NULL);
2967   gst_structure_free (str);
2968
2969   if (res)
2970     g_value_set_boxed (dest, &seg);
2971
2972   return res;
2973 }
2974
2975 static gboolean
2976 gst_value_deserialize_segment (GValue * dest, const gchar * s)
2977 {
2978   return gst_value_deserialize_segment_internal (dest, s, TRUE);
2979 }
2980
2981 /****************
2982  * GstStructure *
2983  ****************/
2984
2985 /**
2986  * gst_value_set_structure:
2987  * @value: a GValue initialized to GST_TYPE_STRUCTURE
2988  * @structure: the structure to set the value to
2989  *
2990  * Sets the contents of @value to @structure.
2991  */
2992 void
2993 gst_value_set_structure (GValue * value, const GstStructure * structure)
2994 {
2995   g_return_if_fail (G_IS_VALUE (value));
2996   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE);
2997   g_return_if_fail (structure == NULL || GST_IS_STRUCTURE (structure));
2998
2999   g_value_set_boxed (value, structure);
3000 }
3001
3002 /**
3003  * gst_value_get_structure:
3004  * @value: a GValue initialized to GST_TYPE_STRUCTURE
3005  *
3006  * Gets the contents of @value.
3007  *
3008  * Returns: (transfer none): the contents of @value
3009  */
3010 const GstStructure *
3011 gst_value_get_structure (const GValue * value)
3012 {
3013   g_return_val_if_fail (G_IS_VALUE (value), NULL);
3014   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, NULL);
3015
3016   return (GstStructure *) g_value_get_boxed (value);
3017 }
3018
3019 static gchar *
3020 gst_value_serialize_structure (const GValue * value)
3021 {
3022   GstStructure *structure = g_value_get_boxed (value);
3023
3024   return priv_gst_string_take_and_wrap (gst_structure_to_string (structure));
3025   /* string should always end up being wrapped, since a structure string
3026    * ends in a ';' character */
3027 }
3028
3029 static gboolean
3030 gst_value_deserialize_structure (GValue * dest, const gchar * s)
3031 {
3032   GstStructure *structure;
3033
3034   if (*s != '"') {
3035     /* the output of gst_value_serialize_structure would never produce
3036      * such a string, but a user may pass to gst_structure_from_string
3037      * the string:
3038      *     name, sub=(GstStructure)sub-name, val=(int)5;
3039      * and expect sub to be read as an *empty* structure with the name
3040      * sub-name. Similar to
3041      *     name, caps=(GstCaps)video/x-raw, val=(int)5;
3042      * which gst_structure_to_string can produce. */
3043     structure = gst_structure_from_string (s, NULL);
3044   } else {
3045     gchar *str = gst_string_unwrap (s);
3046
3047     if (G_UNLIKELY (!str))
3048       return FALSE;
3049
3050     structure = gst_structure_from_string (str, NULL);
3051     g_free (str);
3052   }
3053
3054   if (G_LIKELY (structure)) {
3055     g_value_take_boxed (dest, structure);
3056     return TRUE;
3057   }
3058   return FALSE;
3059 }
3060
3061 static gboolean
3062 gst_value_compare_structure (const GValue * value1, const GValue * value2)
3063 {
3064   GstStructure *structure1 = GST_STRUCTURE (g_value_get_boxed (value1));
3065   GstStructure *structure2 = GST_STRUCTURE (g_value_get_boxed (value2));
3066
3067   if (structure1 == structure2)
3068     return GST_VALUE_EQUAL;
3069
3070   if (!structure1 || !structure2)
3071     return GST_VALUE_UNORDERED;
3072
3073   if (gst_structure_is_equal (structure1, structure2))
3074     return GST_VALUE_EQUAL;
3075
3076   return GST_VALUE_UNORDERED;
3077 }
3078
3079 /*******************
3080  * GstCapsFeatures *
3081  *******************/
3082
3083 /**
3084  * gst_value_set_caps_features:
3085  * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
3086  * @features: the features to set the value to
3087  *
3088  * Sets the contents of @value to @features.
3089  */
3090 void
3091 gst_value_set_caps_features (GValue * value, const GstCapsFeatures * features)
3092 {
3093   g_return_if_fail (G_IS_VALUE (value));
3094   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES);
3095   g_return_if_fail (features == NULL || GST_IS_CAPS_FEATURES (features));
3096
3097   g_value_set_boxed (value, features);
3098 }
3099
3100 /**
3101  * gst_value_get_caps_features:
3102  * @value: a GValue initialized to GST_TYPE_CAPS_FEATURES
3103  *
3104  * Gets the contents of @value.
3105  *
3106  * Returns: (transfer none): the contents of @value
3107  */
3108 const GstCapsFeatures *
3109 gst_value_get_caps_features (const GValue * value)
3110 {
3111   g_return_val_if_fail (G_IS_VALUE (value), NULL);
3112   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS_FEATURES, NULL);
3113
3114   return (GstCapsFeatures *) g_value_get_boxed (value);
3115 }
3116
3117 static gchar *
3118 gst_value_serialize_caps_features (const GValue * value)
3119 {
3120   GstCapsFeatures *features = g_value_get_boxed (value);
3121
3122   return priv_gst_string_take_and_wrap (gst_caps_features_to_string (features));
3123 }
3124
3125 static gboolean
3126 gst_value_deserialize_caps_features (GValue * dest, const gchar * s)
3127 {
3128   GstCapsFeatures *features;
3129
3130   if (*s != '"') {
3131     /* This can happen if gst_caps_features_to_string only returns
3132      * ALL, NONE, or a single features name, which means it is not
3133      * actually wrapped by priv_gst_string_take_and_wrap */
3134     features = gst_caps_features_from_string (s);
3135   } else {
3136     gchar *str = gst_string_unwrap (s);
3137
3138     if (G_UNLIKELY (!str))
3139       return FALSE;
3140
3141     features = gst_caps_features_from_string (str);
3142     g_free (str);
3143   }
3144
3145   if (G_LIKELY (features)) {
3146     g_value_take_boxed (dest, features);
3147     return TRUE;
3148   }
3149   return FALSE;
3150 }
3151
3152 /**************
3153  * GstTagList *
3154  **************/
3155 static gint
3156 gst_value_compare_tag_list (const GValue * value1, const GValue * value2)
3157 {
3158   GstTagList *taglist1 = GST_TAG_LIST (g_value_get_boxed (value1));
3159   GstTagList *taglist2 = GST_TAG_LIST (g_value_get_boxed (value2));
3160
3161   if (gst_tag_list_is_equal (taglist1, taglist2))
3162     return GST_VALUE_EQUAL;
3163   return GST_VALUE_UNORDERED;
3164 }
3165
3166 static gboolean
3167 gst_value_deserialize_tag_list (GValue * dest, const gchar * s)
3168 {
3169   GstTagList *taglist;
3170
3171   if (*s != '"') {
3172     /* the output of gst_value_serialize_tag_list would never produce
3173      * such a string, but a user may pass to gst_structure_from_string
3174      * the string:
3175      *     name, list=(GstTagList)taglist, val=(int)5;
3176      * and expect list to be read as an *empty* tag list. Similar to
3177      *     name, caps=(GstCaps)video/x-raw, val=(int)5;
3178      * which gst_structure_to_string can produce. */
3179     taglist = gst_tag_list_new_from_string (s);
3180   } else {
3181     gchar *str = gst_string_unwrap (s);
3182
3183     if (G_UNLIKELY (!str))
3184       return FALSE;
3185
3186     taglist = gst_tag_list_new_from_string (str);
3187     g_free (str);
3188   }
3189
3190   if (G_LIKELY (taglist != NULL)) {
3191     g_value_take_boxed (dest, taglist);
3192     return TRUE;
3193   }
3194   return FALSE;
3195 }
3196
3197 static gchar *
3198 gst_value_serialize_tag_list (const GValue * value)
3199 {
3200   GstTagList *taglist = g_value_get_boxed (value);
3201
3202   return priv_gst_string_take_and_wrap (gst_tag_list_to_string (taglist));
3203   /* string should always end up being wrapped, since a taglist (structure)
3204    * string ends in a ';' character */
3205 }
3206
3207
3208 /*************
3209  * GstBuffer *
3210  *************/
3211
3212 static gint
3213 compare_buffer (GstBuffer * buf1, GstBuffer * buf2)
3214 {
3215   gsize size1, size2;
3216   GstMapInfo info1, info2;
3217   gint result, mret;
3218
3219   if (buf1 == buf2)
3220     return GST_VALUE_EQUAL;
3221
3222   size1 = gst_buffer_get_size (buf1);
3223   size2 = gst_buffer_get_size (buf2);
3224
3225   if (size1 != size2)
3226     return GST_VALUE_UNORDERED;
3227
3228   if (size1 == 0)
3229     return GST_VALUE_EQUAL;
3230
3231   if (!gst_buffer_map (buf1, &info1, GST_MAP_READ))
3232     return GST_VALUE_UNORDERED;
3233
3234   if (!gst_buffer_map (buf2, &info2, GST_MAP_READ)) {
3235     gst_buffer_unmap (buf1, &info1);
3236     return GST_VALUE_UNORDERED;
3237   }
3238
3239   mret = memcmp (info1.data, info2.data, info1.size);
3240   if (mret == 0)
3241     result = GST_VALUE_EQUAL;
3242   else if (mret < 0)
3243     result = GST_VALUE_LESS_THAN;
3244   else
3245     result = GST_VALUE_GREATER_THAN;
3246
3247   gst_buffer_unmap (buf1, &info1);
3248   gst_buffer_unmap (buf2, &info2);
3249
3250   return result;
3251 }
3252
3253 static gint
3254 gst_value_compare_buffer (const GValue * value1, const GValue * value2)
3255 {
3256   GstBuffer *buf1 = gst_value_get_buffer (value1);
3257   GstBuffer *buf2 = gst_value_get_buffer (value2);
3258
3259   return compare_buffer (buf1, buf2);
3260 }
3261
3262 static gchar *
3263 gst_value_serialize_buffer (const GValue * value)
3264 {
3265   GstMapInfo info;
3266   guint8 *data;
3267   gint i;
3268   gchar *string;
3269   GstBuffer *buffer;
3270
3271   buffer = gst_value_get_buffer (value);
3272   if (buffer == NULL)
3273     return NULL;
3274
3275   if (!gst_buffer_map (buffer, &info, GST_MAP_READ))
3276     return NULL;
3277
3278   data = info.data;
3279
3280   string = g_malloc (info.size * 2 + 1);
3281   for (i = 0; i < info.size; i++) {
3282     sprintf (string + i * 2, "%02x", data[i]);
3283   }
3284   string[info.size * 2] = 0;
3285
3286   gst_buffer_unmap (buffer, &info);
3287
3288   return string;
3289 }
3290
3291 static gboolean
3292 gst_value_deserialize_buffer (GValue * dest, const gchar * s)
3293 {
3294   GstBuffer *buffer;
3295   gint len;
3296   gchar ts[3];
3297   GstMapInfo info;
3298   guint8 *data;
3299   gint i;
3300
3301   len = strlen (s);
3302   if (len & 1)
3303     goto wrong_length;
3304
3305   buffer = gst_buffer_new_allocate (NULL, len / 2, NULL);
3306   if (!gst_buffer_map (buffer, &info, GST_MAP_WRITE))
3307     goto map_failed;
3308   data = info.data;
3309
3310   for (i = 0; i < len / 2; i++) {
3311     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1]))
3312       goto wrong_char;
3313
3314     ts[0] = s[i * 2 + 0];
3315     ts[1] = s[i * 2 + 1];
3316     ts[2] = 0;
3317
3318     data[i] = (guint8) strtoul (ts, NULL, 16);
3319   }
3320   gst_buffer_unmap (buffer, &info);
3321
3322   gst_value_take_buffer (dest, buffer);
3323
3324   return TRUE;
3325
3326   /* ERRORS */
3327 wrong_length:
3328   {
3329     return FALSE;
3330   }
3331 map_failed:
3332   {
3333     return FALSE;
3334   }
3335 wrong_char:
3336   {
3337     gst_buffer_unref (buffer);
3338     gst_buffer_unmap (buffer, &info);
3339     return FALSE;
3340   }
3341 }
3342
3343 /*************
3344  * GstSample *
3345  *************/
3346
3347 /* This function is mostly used for comparing image/buffer tags in taglists */
3348 static gint
3349 gst_value_compare_sample (const GValue * value1, const GValue * value2)
3350 {
3351   GstBuffer *buf1 = gst_sample_get_buffer (gst_value_get_sample (value1));
3352   GstBuffer *buf2 = gst_sample_get_buffer (gst_value_get_sample (value2));
3353
3354   /* FIXME: should we take into account anything else such as caps? */
3355   return compare_buffer (buf1, buf2);
3356 }
3357
3358 static gchar *
3359 gst_value_serialize_sample (const GValue * value)
3360 {
3361   const GstStructure *info_structure;
3362   GstSegment *segment;
3363   GstBuffer *buffer;
3364   GstCaps *caps;
3365   GstSample *sample;
3366   GValue val = { 0, };
3367   gchar *info_str, *caps_str, *tmp;
3368   gchar *buf_str, *seg_str, *s;
3369
3370   sample = g_value_get_boxed (value);
3371
3372   buffer = gst_sample_get_buffer (sample);
3373   if (buffer) {
3374     g_value_init (&val, GST_TYPE_BUFFER);
3375     g_value_set_boxed (&val, buffer);
3376     buf_str = gst_value_serialize_buffer (&val);
3377     g_value_unset (&val);
3378   } else {
3379     buf_str = g_strdup ("None");
3380   }
3381
3382   caps = gst_sample_get_caps (sample);
3383   if (caps) {
3384     tmp = gst_caps_to_string (caps);
3385     caps_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
3386     g_strdelimit (caps_str, "=", '_');
3387     g_free (tmp);
3388   } else {
3389     caps_str = g_strdup ("None");
3390   }
3391
3392   segment = gst_sample_get_segment (sample);
3393   if (segment) {
3394     g_value_init (&val, GST_TYPE_SEGMENT);
3395     g_value_set_boxed (&val, segment);
3396     tmp = gst_value_serialize_segment_internal (&val, FALSE);
3397     seg_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
3398     g_strdelimit (seg_str, "=", '_');
3399     g_free (tmp);
3400     g_value_unset (&val);
3401   } else {
3402     seg_str = g_strdup ("None");
3403   }
3404
3405   info_structure = gst_sample_get_info (sample);
3406   if (info_structure) {
3407     tmp = gst_structure_to_string (info_structure);
3408     info_str = g_base64_encode ((guchar *) tmp, strlen (tmp) + 1);
3409     g_strdelimit (info_str, "=", '_');
3410     g_free (tmp);
3411   } else {
3412     info_str = g_strdup ("None");
3413   }
3414
3415   s = g_strconcat (buf_str, ":", caps_str, ":", seg_str, ":", info_str, NULL);
3416   g_free (buf_str);
3417   g_free (caps_str);
3418   g_free (seg_str);
3419   g_free (info_str);
3420
3421   return s;
3422 }
3423
3424 static gboolean
3425 gst_value_deserialize_sample (GValue * dest, const gchar * s)
3426 {
3427   GValue bval = G_VALUE_INIT, sval = G_VALUE_INIT;
3428   GstStructure *info;
3429   GstSample *sample;
3430   GstCaps *caps = NULL;
3431   gboolean ret = FALSE;
3432   gchar **fields;
3433   gsize outlen;
3434   gint len;
3435
3436   GST_TRACE ("deserialize '%s'", s);
3437
3438   fields = g_strsplit (s, ":", -1);
3439   len = g_strv_length (fields);
3440   if (len != 4)
3441     goto wrong_length;
3442
3443   g_value_init (&bval, GST_TYPE_BUFFER);
3444   g_value_init (&sval, GST_TYPE_SEGMENT);
3445
3446   if (!gst_value_deserialize_buffer (&bval, fields[0]))
3447     goto fail;
3448
3449   if (strcmp (fields[1], "None") != 0) {
3450     g_strdelimit (fields[1], "_", '=');
3451     g_base64_decode_inplace (fields[1], &outlen);
3452     GST_TRACE ("caps    : %s", fields[1]);
3453     caps = gst_caps_from_string (fields[1]);
3454     if (caps == NULL)
3455       goto fail;
3456   }
3457
3458   if (strcmp (fields[2], "None") != 0) {
3459     g_strdelimit (fields[2], "_", '=');
3460     g_base64_decode_inplace (fields[2], &outlen);
3461     GST_TRACE ("segment : %s", fields[2]);
3462     if (!gst_value_deserialize_segment_internal (&sval, fields[2], FALSE))
3463       goto fail;
3464   }
3465
3466   if (strcmp (fields[3], "None") != 0) {
3467     g_strdelimit (fields[3], "_", '=');
3468     g_base64_decode_inplace (fields[3], &outlen);
3469     GST_TRACE ("info    : %s", fields[3]);
3470     info = gst_structure_from_string (fields[3], NULL);
3471     if (info == NULL)
3472       goto fail;
3473   } else {
3474     info = NULL;
3475   }
3476
3477   sample = gst_sample_new (gst_value_get_buffer (&bval), caps,
3478       g_value_get_boxed (&sval), info);
3479
3480   g_value_take_boxed (dest, sample);
3481
3482   ret = TRUE;
3483
3484 fail:
3485   if (caps)
3486     gst_caps_unref (caps);
3487   g_value_unset (&bval);
3488   g_value_unset (&sval);
3489
3490 wrong_length:
3491
3492   g_strfreev (fields);
3493
3494   return ret;
3495 }
3496
3497 /***********
3498  * boolean *
3499  ***********/
3500
3501 static gint
3502 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
3503 {
3504   if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
3505     return GST_VALUE_EQUAL;
3506   return GST_VALUE_UNORDERED;
3507 }
3508
3509 static gchar *
3510 gst_value_serialize_boolean (const GValue * value)
3511 {
3512   if (value->data[0].v_int) {
3513     return g_strdup ("true");
3514   }
3515   return g_strdup ("false");
3516 }
3517
3518 static gboolean
3519 gst_value_deserialize_boolean (GValue * dest, const gchar * s)
3520 {
3521   gboolean ret = FALSE;
3522
3523   if (g_ascii_strcasecmp (s, "true") == 0 ||
3524       g_ascii_strcasecmp (s, "yes") == 0 ||
3525       g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
3526     g_value_set_boolean (dest, TRUE);
3527     ret = TRUE;
3528   } else if (g_ascii_strcasecmp (s, "false") == 0 ||
3529       g_ascii_strcasecmp (s, "no") == 0 ||
3530       g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
3531     g_value_set_boolean (dest, FALSE);
3532     ret = TRUE;
3533   }
3534
3535   return ret;
3536 }
3537
3538 #define CREATE_SERIALIZATION_START(_type,_macro)                        \
3539 static gint                                                             \
3540 gst_value_compare_ ## _type                                             \
3541 (const GValue * value1, const GValue * value2)                          \
3542 {                                                                       \
3543   g ## _type val1 = g_value_get_ ## _type (value1);                     \
3544   g ## _type val2 = g_value_get_ ## _type (value2);                     \
3545   if (val1 > val2)                                                      \
3546     return GST_VALUE_GREATER_THAN;                                      \
3547   if (val1 < val2)                                                      \
3548     return GST_VALUE_LESS_THAN;                                         \
3549   return GST_VALUE_EQUAL;                                               \
3550 }                                                                       \
3551                                                                         \
3552 static gchar *                                                          \
3553 gst_value_serialize_ ## _type (const GValue * value)                    \
3554 {                                                                       \
3555   GValue val = { 0, };                                                  \
3556   g_value_init (&val, G_TYPE_STRING);                                   \
3557   if (!g_value_transform (value, &val))                                 \
3558     g_assert_not_reached ();                                            \
3559   /* NO_COPY_MADNESS!!! */                                              \
3560   return (char *) g_value_get_string (&val);                            \
3561 }
3562
3563 /* deserialize the given s into to as a gint64.
3564  * check if the result is actually storeable in the given size number of
3565  * bytes.
3566  */
3567 static gboolean
3568 gst_value_deserialize_int_helper (gint64 * to, const gchar * s,
3569     gint64 min, gint64 max, gint size)
3570 {
3571   gboolean ret = FALSE;
3572   gchar *end;
3573   guint64 mask = ~0;
3574
3575   errno = 0;
3576   *to = g_ascii_strtoull (s, &end, 0);
3577   /* a range error is a definitive no-no */
3578   if (errno == ERANGE) {
3579     return FALSE;
3580   }
3581
3582   if (*end == 0) {
3583     ret = TRUE;
3584   } else {
3585     if (g_ascii_strcasecmp (s, "little_endian") == 0) {
3586       *to = G_LITTLE_ENDIAN;
3587       ret = TRUE;
3588     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
3589       *to = G_BIG_ENDIAN;
3590       ret = TRUE;
3591     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
3592       *to = G_BYTE_ORDER;
3593       ret = TRUE;
3594     } else if (g_ascii_strcasecmp (s, "min") == 0) {
3595       *to = min;
3596       ret = TRUE;
3597     } else if (g_ascii_strcasecmp (s, "max") == 0) {
3598       *to = max;
3599       ret = TRUE;
3600     }
3601   }
3602   if (ret) {
3603     /* by definition, a gint64 fits into a gint64; so ignore those */
3604     if (size != sizeof (mask)) {
3605       if (*to >= 0) {
3606         /* for positive numbers, we create a mask of 1's outside of the range
3607          * and 0's inside the range.  An and will thus keep only 1 bits
3608          * outside of the range */
3609         mask <<= (size * 8);
3610         if ((mask & *to) != 0) {
3611           ret = FALSE;
3612         }
3613       } else {
3614         /* for negative numbers, we do a 2's complement version */
3615         mask <<= ((size * 8) - 1);
3616         if ((mask & *to) != mask) {
3617           ret = FALSE;
3618         }
3619       }
3620     }
3621   }
3622   return ret;
3623 }
3624
3625 #define CREATE_SERIALIZATION(_type,_macro)                              \
3626 CREATE_SERIALIZATION_START(_type,_macro)                                \
3627                                                                         \
3628 static gboolean                                                         \
3629 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
3630 {                                                                       \
3631   gint64 x;                                                             \
3632                                                                         \
3633   if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro,         \
3634       G_MAX ## _macro, sizeof (g ## _type))) {                          \
3635     g_value_set_ ## _type (dest, /*(g ## _type)*/ x);                   \
3636     return TRUE;                                                        \
3637   } else {                                                              \
3638     return FALSE;                                                       \
3639   }                                                                     \
3640 }
3641
3642 #define CREATE_USERIALIZATION(_type,_macro)                             \
3643 CREATE_SERIALIZATION_START(_type,_macro)                                \
3644                                                                         \
3645 static gboolean                                                         \
3646 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
3647 {                                                                       \
3648   gint64 x;                                                             \
3649   gchar *end;                                                           \
3650   gboolean ret = FALSE;                                                 \
3651                                                                         \
3652   errno = 0;                                                            \
3653   x = g_ascii_strtoull (s, &end, 0);                                    \
3654   /* a range error is a definitive no-no */                             \
3655   if (errno == ERANGE) {                                                \
3656     return FALSE;                                                       \
3657   }                                                                     \
3658   /* the cast ensures the range check later on makes sense */           \
3659   x = (g ## _type) x;                                                   \
3660   if (*end == 0) {                                                      \
3661     ret = TRUE;                                                         \
3662   } else {                                                              \
3663     if (g_ascii_strcasecmp (s, "little_endian") == 0) {                 \
3664       x = G_LITTLE_ENDIAN;                                              \
3665       ret = TRUE;                                                       \
3666     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {             \
3667       x = G_BIG_ENDIAN;                                                 \
3668       ret = TRUE;                                                       \
3669     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {             \
3670       x = G_BYTE_ORDER;                                                 \
3671       ret = TRUE;                                                       \
3672     } else if (g_ascii_strcasecmp (s, "min") == 0) {                    \
3673       x = 0;                                                            \
3674       ret = TRUE;                                                       \
3675     } else if (g_ascii_strcasecmp (s, "max") == 0) {                    \
3676       x = G_MAX ## _macro;                                              \
3677       ret = TRUE;                                                       \
3678     }                                                                   \
3679   }                                                                     \
3680   if (ret) {                                                            \
3681     if (x > G_MAX ## _macro) {                                          \
3682       ret = FALSE;                                                      \
3683     } else {                                                            \
3684       g_value_set_ ## _type (dest, x);                                  \
3685     }                                                                   \
3686   }                                                                     \
3687   return ret;                                                           \
3688 }
3689
3690 CREATE_SERIALIZATION (int, INT);
3691 CREATE_SERIALIZATION (int64, INT64);
3692 CREATE_SERIALIZATION (long, LONG);
3693
3694 CREATE_USERIALIZATION (uint, UINT);
3695 CREATE_USERIALIZATION (uint64, UINT64);
3696 CREATE_USERIALIZATION (ulong, ULONG);
3697
3698 /* FIXME 2.0: remove this again, plugins shouldn't have uchar properties */
3699 #ifndef G_MAXUCHAR
3700 #define G_MAXUCHAR 255
3701 #endif
3702 CREATE_USERIALIZATION (uchar, UCHAR);
3703
3704 /**********
3705  * double *
3706  **********/
3707 static gint
3708 gst_value_compare_double (const GValue * value1, const GValue * value2)
3709 {
3710   if (value1->data[0].v_double > value2->data[0].v_double)
3711     return GST_VALUE_GREATER_THAN;
3712   if (value1->data[0].v_double < value2->data[0].v_double)
3713     return GST_VALUE_LESS_THAN;
3714   if (value1->data[0].v_double == value2->data[0].v_double)
3715     return GST_VALUE_EQUAL;
3716   return GST_VALUE_UNORDERED;
3717 }
3718
3719 static gchar *
3720 gst_value_serialize_double (const GValue * value)
3721 {
3722   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
3723
3724   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
3725   return g_strdup (d);
3726 }
3727
3728 static gboolean
3729 gst_value_deserialize_double (GValue * dest, const gchar * s)
3730 {
3731   gdouble x;
3732   gboolean ret = FALSE;
3733   gchar *end;
3734
3735   x = g_ascii_strtod (s, &end);
3736   if (*end == 0) {
3737     ret = TRUE;
3738   } else {
3739     if (g_ascii_strcasecmp (s, "min") == 0) {
3740       x = -G_MAXDOUBLE;
3741       ret = TRUE;
3742     } else if (g_ascii_strcasecmp (s, "max") == 0) {
3743       x = G_MAXDOUBLE;
3744       ret = TRUE;
3745     }
3746   }
3747   if (ret) {
3748     g_value_set_double (dest, x);
3749   }
3750   return ret;
3751 }
3752
3753 /*********
3754  * float *
3755  *********/
3756
3757 static gint
3758 gst_value_compare_float (const GValue * value1, const GValue * value2)
3759 {
3760   if (value1->data[0].v_float > value2->data[0].v_float)
3761     return GST_VALUE_GREATER_THAN;
3762   if (value1->data[0].v_float < value2->data[0].v_float)
3763     return GST_VALUE_LESS_THAN;
3764   if (value1->data[0].v_float == value2->data[0].v_float)
3765     return GST_VALUE_EQUAL;
3766   return GST_VALUE_UNORDERED;
3767 }
3768
3769 static gchar *
3770 gst_value_serialize_float (const GValue * value)
3771 {
3772   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
3773
3774   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
3775   return g_strdup (d);
3776 }
3777
3778 static gboolean
3779 gst_value_deserialize_float (GValue * dest, const gchar * s)
3780 {
3781   gdouble x;
3782   gboolean ret = FALSE;
3783   gchar *end;
3784
3785   x = g_ascii_strtod (s, &end);
3786   if (*end == 0) {
3787     ret = TRUE;
3788   } else {
3789     if (g_ascii_strcasecmp (s, "min") == 0) {
3790       x = -G_MAXFLOAT;
3791       ret = TRUE;
3792     } else if (g_ascii_strcasecmp (s, "max") == 0) {
3793       x = G_MAXFLOAT;
3794       ret = TRUE;
3795     }
3796   }
3797   if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
3798     ret = FALSE;
3799   if (ret) {
3800     g_value_set_float (dest, (float) x);
3801   }
3802   return ret;
3803 }
3804
3805 /**********
3806  * string *
3807  **********/
3808
3809 static gint
3810 gst_value_compare_string (const GValue * value1, const GValue * value2)
3811 {
3812   if (G_UNLIKELY (!value1->data[0].v_pointer || !value2->data[0].v_pointer)) {
3813     /* if only one is NULL, no match - otherwise both NULL == EQUAL */
3814     if (value1->data[0].v_pointer != value2->data[0].v_pointer)
3815       return GST_VALUE_UNORDERED;
3816   } else {
3817     gint x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
3818
3819     if (x < 0)
3820       return GST_VALUE_LESS_THAN;
3821     if (x > 0)
3822       return GST_VALUE_GREATER_THAN;
3823   }
3824
3825   return GST_VALUE_EQUAL;
3826 }
3827
3828 static gint
3829 gst_string_measure_wrapping (const gchar * s)
3830 {
3831   gint len;
3832   gboolean wrap = FALSE;
3833
3834   if (G_UNLIKELY (s == NULL))
3835     return -1;
3836
3837   /* Special case: the actual string NULL needs wrapping */
3838   if (G_UNLIKELY (strcmp (s, "NULL") == 0))
3839     return 4;
3840
3841   len = 0;
3842   while (*s) {
3843     if (GST_ASCII_IS_STRING (*s)) {
3844       len++;
3845     } else if (*s < 0x20 || *s >= 0x7f) {
3846       wrap = TRUE;
3847       len += 4;
3848     } else {
3849       wrap = TRUE;
3850       len += 2;
3851     }
3852     s++;
3853   }
3854
3855   /* Wrap the string if we found something that needs
3856    * wrapping, or the empty string (len == 0) */
3857   return (wrap || len == 0) ? len : -1;
3858 }
3859
3860 static gchar *
3861 gst_string_wrap_inner (const gchar * s, gint len)
3862 {
3863   gchar *d, *e;
3864
3865   e = d = g_malloc (len + 3);
3866
3867   *e++ = '\"';
3868   while (*s) {
3869     if (GST_ASCII_IS_STRING (*s)) {
3870       *e++ = *s++;
3871     } else if (*s < 0x20 || *s >= 0x7f) {
3872       *e++ = '\\';
3873       *e++ = '0' + ((*(guchar *) s) >> 6);
3874       *e++ = '0' + (((*s) >> 3) & 0x7);
3875       *e++ = '0' + ((*s++) & 0x7);
3876     } else {
3877       *e++ = '\\';
3878       *e++ = *s++;
3879     }
3880   }
3881   *e++ = '\"';
3882   *e = 0;
3883
3884   g_assert (e - d <= len + 3);
3885   return d;
3886 }
3887
3888 /* Do string wrapping/escaping */
3889 static gchar *
3890 gst_string_wrap (const gchar * s)
3891 {
3892   gint len = gst_string_measure_wrapping (s);
3893
3894   if (G_LIKELY (len < 0))
3895     return g_strdup (s);
3896
3897   return gst_string_wrap_inner (s, len);
3898 }
3899
3900 /* Same as above, but take ownership of the string */
3901 gchar *
3902 priv_gst_string_take_and_wrap (gchar * s)
3903 {
3904   gchar *out;
3905   gint len = gst_string_measure_wrapping (s);
3906
3907   if (G_LIKELY (len < 0))
3908     return s;
3909
3910   out = gst_string_wrap_inner (s, len);
3911   g_free (s);
3912
3913   return out;
3914 }
3915
3916 /*
3917  * This function takes a string delimited with double quotes (")
3918  * and unescapes any \xxx octal numbers.
3919  *
3920  * If sequences of \y are found where y is not in the range of
3921  * 0->3, y is copied unescaped.
3922  *
3923  * If \xyy is found where x is an octal number but y is not, an
3924  * error is encountered and %NULL is returned.
3925  *
3926  * the input string must be \0 terminated.
3927  */
3928 static gchar *
3929 gst_string_unwrap (const gchar * s)
3930 {
3931   gchar *ret;
3932   gchar *read, *write;
3933
3934   /* NULL string returns NULL */
3935   if (s == NULL)
3936     return NULL;
3937
3938   /* strings not starting with " are invalid */
3939   if (*s != '"')
3940     return NULL;
3941
3942   /* make copy of original string to hold the result. This
3943    * string will always be smaller than the original */
3944   ret = g_strdup (s);
3945   read = ret;
3946   write = ret;
3947
3948   /* need to move to the next position as we parsed the " */
3949   read++;
3950
3951   while (*read) {
3952     if (GST_ASCII_IS_STRING (*read)) {
3953       /* normal chars are just copied */
3954       *write++ = *read++;
3955     } else if (*read == '"') {
3956       /* quote marks end of string */
3957       break;
3958     } else if (*read == '\\') {
3959       /* got an escape char, move to next position to read a tripplet
3960        * of octal numbers */
3961       read++;
3962       /* is the next char a possible first octal number? */
3963       if (*read >= '0' && *read <= '3') {
3964         /* parse other 2 numbers, if one of them is not in the range of
3965          * an octal number, we error. We also catch the case where a zero
3966          * byte is found here. */
3967         if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
3968           goto beach;
3969
3970         /* now convert the octal number to a byte again. */
3971         *write++ = ((read[0] - '0') << 6) +
3972             ((read[1] - '0') << 3) + (read[2] - '0');
3973
3974         read += 3;
3975       } else {
3976         /* if we run into a \0 here, we definitely won't get a quote later */
3977         if (*read == 0)
3978           goto beach;
3979         /* else copy \X sequence */
3980         *write++ = *read++;
3981       }
3982     } else if (*read == '\0') {
3983       goto beach;
3984     } else {
3985       *write++ = *read++;
3986     }
3987   }
3988   /* if the string is not ending in " and zero terminated, we error */
3989   if (*read != '"' || read[1] != '\0')
3990     goto beach;
3991
3992   /* null terminate result string and return */
3993   *write = '\0';
3994   return ret;
3995
3996 beach:
3997   g_free (ret);
3998   return NULL;
3999 }
4000
4001 static gchar *
4002 gst_value_serialize_string (const GValue * value)
4003 {
4004   return gst_string_wrap (value->data[0].v_pointer);
4005 }
4006
4007 static gboolean
4008 gst_value_deserialize_string (GValue * dest, const gchar * s)
4009 {
4010   if (G_UNLIKELY (strcmp (s, "NULL") == 0)) {
4011     g_value_set_string (dest, NULL);
4012     return TRUE;
4013   } else if (G_LIKELY (*s != '"' || s[strlen (s) - 1] != '"')) {
4014     if (!g_utf8_validate (s, -1, NULL))
4015       return FALSE;
4016     g_value_set_string (dest, s);
4017     return TRUE;
4018   } else {
4019     /* strings delimited with double quotes should be unwrapped */
4020     gchar *str = gst_string_unwrap (s);
4021     if (G_UNLIKELY (!str))
4022       return FALSE;
4023     if (!g_utf8_validate (str, -1, NULL)) {
4024       g_free (str);
4025       return FALSE;
4026     }
4027     g_value_take_string (dest, str);
4028   }
4029
4030   return TRUE;
4031 }
4032
4033 /********
4034  * enum *
4035  ********/
4036
4037 static gint
4038 gst_value_compare_enum (const GValue * value1, const GValue * value2)
4039 {
4040   GEnumValue *en1, *en2;
4041   GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
4042   GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
4043
4044   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
4045   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
4046   en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
4047   en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
4048   g_type_class_unref (klass1);
4049   g_type_class_unref (klass2);
4050   g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
4051   g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
4052   if (en1->value < en2->value)
4053     return GST_VALUE_LESS_THAN;
4054   if (en1->value > en2->value)
4055     return GST_VALUE_GREATER_THAN;
4056
4057   return GST_VALUE_EQUAL;
4058 }
4059
4060 static gchar *
4061 gst_value_serialize_enum (const GValue * value)
4062 {
4063   GEnumValue *en;
4064   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
4065
4066   g_return_val_if_fail (klass, NULL);
4067   en = g_enum_get_value (klass, g_value_get_enum (value));
4068   g_type_class_unref (klass);
4069
4070   /* might be one of the custom formats registered later */
4071   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) {
4072     const GstFormatDefinition *format_def;
4073
4074     format_def = gst_format_get_details ((GstFormat) g_value_get_enum (value));
4075     g_return_val_if_fail (format_def != NULL, NULL);
4076     return g_strdup (format_def->description);
4077   }
4078
4079   g_return_val_if_fail (en, NULL);
4080   return g_strdup (en->value_nick);
4081 }
4082
4083 static gint
4084 gst_value_deserialize_enum_iter_cmp (const GValue * format_def_value,
4085     const gchar * s)
4086 {
4087   const GstFormatDefinition *format_def =
4088       g_value_get_pointer (format_def_value);
4089
4090   if (g_ascii_strcasecmp (s, format_def->nick) == 0)
4091     return 0;
4092
4093   return g_ascii_strcasecmp (s, format_def->description);
4094 }
4095
4096 static gboolean
4097 gst_value_deserialize_enum (GValue * dest, const gchar * s)
4098 {
4099   GEnumValue *en;
4100   gchar *endptr = NULL;
4101   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
4102
4103   g_return_val_if_fail (klass, FALSE);
4104   if (!(en = g_enum_get_value_by_name (klass, s))) {
4105     if (!(en = g_enum_get_value_by_nick (klass, s))) {
4106       gint i = strtol (s, &endptr, 0);
4107
4108       if (endptr && *endptr == '\0') {
4109         en = g_enum_get_value (klass, i);
4110       }
4111     }
4112   }
4113   g_type_class_unref (klass);
4114
4115   /* might be one of the custom formats registered later */
4116   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (dest) == GST_TYPE_FORMAT)) {
4117     GValue res = { 0, };
4118     const GstFormatDefinition *format_def;
4119     GstIterator *iter;
4120     gboolean found;
4121
4122     iter = gst_format_iterate_definitions ();
4123
4124     found = gst_iterator_find_custom (iter,
4125         (GCompareFunc) gst_value_deserialize_enum_iter_cmp, &res, (gpointer) s);
4126
4127     if (found) {
4128       format_def = g_value_get_pointer (&res);
4129       g_return_val_if_fail (format_def != NULL, FALSE);
4130       g_value_set_enum (dest, (gint) format_def->value);
4131       g_value_unset (&res);
4132     }
4133     gst_iterator_free (iter);
4134     return found;
4135   }
4136
4137   /* enum name/nick not found */
4138   if (en == NULL)
4139     return FALSE;
4140
4141   g_value_set_enum (dest, en->value);
4142   return TRUE;
4143 }
4144
4145 /********
4146  * flags *
4147  ********/
4148
4149 /* we just compare the value here */
4150 static gint
4151 gst_value_compare_gflags (const GValue * value1, const GValue * value2)
4152 {
4153   guint fl1, fl2;
4154   GFlagsClass *klass1 =
4155       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
4156   GFlagsClass *klass2 =
4157       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
4158
4159   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
4160   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
4161   fl1 = g_value_get_flags (value1);
4162   fl2 = g_value_get_flags (value2);
4163   g_type_class_unref (klass1);
4164   g_type_class_unref (klass2);
4165   if (fl1 < fl2)
4166     return GST_VALUE_LESS_THAN;
4167   if (fl1 > fl2)
4168     return GST_VALUE_GREATER_THAN;
4169
4170   return GST_VALUE_EQUAL;
4171 }
4172
4173 /* the different flags are serialized separated with a + */
4174 static gchar *
4175 gst_value_serialize_gflags (const GValue * value)
4176 {
4177   guint flags;
4178   GFlagsValue *fl;
4179   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
4180   gchar *result, *tmp;
4181   gboolean first = TRUE;
4182
4183   g_return_val_if_fail (klass, NULL);
4184
4185   flags = g_value_get_flags (value);
4186
4187   /* if no flags are set, try to serialize to the _NONE string */
4188   if (!flags) {
4189     fl = g_flags_get_first_value (klass, flags);
4190     if (fl)
4191       return g_strdup (fl->value_name);
4192     else
4193       return g_strdup ("0");
4194   }
4195
4196   /* some flags are set, so serialize one by one */
4197   result = g_strdup ("");
4198   while (flags) {
4199     fl = g_flags_get_first_value (klass, flags);
4200     if (fl == NULL) {
4201       if (flags) {
4202         g_critical ("Could not serialize invalid flags 0x%x of type %s",
4203             flags, G_VALUE_TYPE_NAME (value));
4204         g_free (result);
4205         result = g_strdup ("0");
4206       }
4207       break;
4208     }
4209
4210     tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
4211     g_free (result);
4212     result = tmp;
4213     first = FALSE;
4214
4215     /* clear flag */
4216     flags &= ~fl->value;
4217   }
4218   g_type_class_unref (klass);
4219
4220   return result;
4221 }
4222
4223 static gboolean
4224 gst_value_gflags_str_to_flags (GFlagsClass * klass, const gchar * s,
4225     guint * out_flags, guint * out_mask)
4226 {
4227   GFlagsValue *fl;
4228   gchar delimiter;
4229   const gchar *pos = NULL;
4230   const gchar *next;
4231   gchar *cur_str, *endptr;
4232   guint flags = 0;
4233   guint mask = 0;
4234   guint val;
4235
4236   g_return_val_if_fail (klass, FALSE);
4237
4238   /* split into parts delimited with + or / and
4239    * compose the set of flags and mask. */
4240   pos = s;
4241
4242   if (*pos == '\0')
4243     goto done;                  /* Empty string, nothing to do */
4244
4245   /* As a special case if the first char isn't a delimiter, assume
4246    * it's a '+' - for GFlags strings, which don't start with a
4247    * delimiter, while GFlagSet always will */
4248   if (*pos == '/' || *pos == '+') {
4249     delimiter = *pos;
4250     pos++;
4251   } else {
4252     delimiter = '+';
4253   }
4254
4255   do {
4256     /* Find the next delimiter */
4257     next = pos;
4258     while (*next != '\0' && *next != '+' && *next != '/')
4259       next++;
4260     cur_str = g_strndup (pos, next - pos);
4261
4262     if ((fl = g_flags_get_value_by_name (klass, cur_str)))
4263       val = fl->value;
4264     else if ((fl = g_flags_get_value_by_nick (klass, cur_str)))
4265       val = fl->value;
4266     else {
4267       val = strtoul (cur_str, &endptr, 0);
4268       /* direct numeric value */
4269       if (endptr == NULL || *endptr != '\0') {
4270         g_free (cur_str);
4271         return FALSE;           /* Invalid numeric or string we can't convert */
4272       }
4273     }
4274     g_free (cur_str);
4275
4276     if (val) {
4277       mask |= val;
4278       if (delimiter == '+')
4279         flags |= val;
4280     }
4281
4282     /* Advance to the next delimiter */
4283     pos = next;
4284     delimiter = *pos;
4285     pos++;
4286   } while (delimiter != '\0');
4287
4288 done:
4289   if (out_flags)
4290     *out_flags = flags;
4291   if (out_mask)
4292     *out_mask = mask;
4293
4294   return TRUE;
4295 }
4296
4297
4298 static gboolean
4299 gst_value_deserialize_gflags (GValue * dest, const gchar * s)
4300 {
4301   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
4302   gboolean res = FALSE;
4303   guint flags = 0;
4304
4305   if (gst_value_gflags_str_to_flags (klass, s, &flags, NULL)) {
4306     g_value_set_flags (dest, flags);
4307     res = TRUE;
4308   }
4309
4310   g_type_class_unref (klass);
4311
4312   return res;
4313 }
4314
4315 /*********
4316  * gtype *
4317  *********/
4318
4319 static gint
4320 gst_value_compare_gtype (const GValue * value1, const GValue * value2)
4321 {
4322   if (value1->data[0].v_pointer == value2->data[0].v_pointer)
4323     return GST_VALUE_EQUAL;
4324   return GST_VALUE_UNORDERED;
4325 }
4326
4327 static gchar *
4328 gst_value_serialize_gtype (const GValue * value)
4329 {
4330   return g_strdup (g_type_name (g_value_get_gtype (value)));
4331 }
4332
4333 static gboolean
4334 gst_value_deserialize_gtype (GValue * dest, const gchar * s)
4335 {
4336   GType t = g_type_from_name (s);
4337   gboolean ret = TRUE;
4338
4339   if (t == G_TYPE_INVALID)
4340     ret = FALSE;
4341   if (ret) {
4342     g_value_set_gtype (dest, t);
4343   }
4344   return ret;
4345 }
4346
4347 /****************
4348  * subset *
4349  ****************/
4350
4351 static gboolean
4352 gst_value_is_subset_int_range_int_range (const GValue * value1,
4353     const GValue * value2)
4354 {
4355   gint gcd;
4356
4357   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value1), FALSE);
4358   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value2), FALSE);
4359
4360   if (INT_RANGE_MIN (value1) * INT_RANGE_STEP (value1) <
4361       INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2))
4362     return FALSE;
4363   if (INT_RANGE_MAX (value1) * INT_RANGE_STEP (value1) >
4364       INT_RANGE_MAX (value2) * INT_RANGE_STEP (value2))
4365     return FALSE;
4366
4367   if (INT_RANGE_MIN (value2) == INT_RANGE_MAX (value2)) {
4368     if ((INT_RANGE_MIN (value2) * INT_RANGE_STEP (value2)) %
4369         INT_RANGE_STEP (value1))
4370       return FALSE;
4371     return TRUE;
4372   }
4373
4374   gcd =
4375       gst_util_greatest_common_divisor (INT_RANGE_STEP (value1),
4376       INT_RANGE_STEP (value2));
4377   if (gcd != MIN (INT_RANGE_STEP (value1), INT_RANGE_STEP (value2)))
4378     return FALSE;
4379
4380   return TRUE;
4381 }
4382
4383 static gboolean
4384 gst_value_is_subset_int64_range_int64_range (const GValue * value1,
4385     const GValue * value2)
4386 {
4387   gint64 gcd;
4388
4389   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value1), FALSE);
4390   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value2), FALSE);
4391
4392   if (INT64_RANGE_MIN (value1) < INT64_RANGE_MIN (value2))
4393     return FALSE;
4394   if (INT64_RANGE_MAX (value1) > INT64_RANGE_MAX (value2))
4395     return FALSE;
4396
4397   if (INT64_RANGE_MIN (value2) == INT64_RANGE_MAX (value2)) {
4398     if ((INT64_RANGE_MIN (value2) * INT64_RANGE_STEP (value2)) %
4399         INT64_RANGE_STEP (value1))
4400       return FALSE;
4401     return TRUE;
4402   }
4403
4404   gcd =
4405       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (value1),
4406       INT64_RANGE_STEP (value2));
4407   if (gcd != MIN (INT64_RANGE_STEP (value1), INT64_RANGE_STEP (value2)))
4408     return FALSE;
4409
4410   return TRUE;
4411 }
4412
4413 /* A flag set is a subset of another if the superset allows the
4414  * flags of the subset */
4415 static gboolean
4416 gst_value_is_subset_flagset_flagset (const GValue * value1,
4417     const GValue * value2)
4418 {
4419   guint f1, f2;
4420   guint m1, m2;
4421
4422   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value1), FALSE);
4423   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value2), FALSE);
4424
4425   f1 = value1->data[0].v_uint;
4426   f2 = value2->data[0].v_uint;
4427
4428   m1 = value1->data[1].v_uint;
4429   m2 = value2->data[1].v_uint;
4430
4431   /* Not a subset if masked bits of superset disagree */
4432   if ((f1 & m1) != (f2 & (m1 & m2)))
4433     return FALSE;
4434
4435   return TRUE;
4436 }
4437
4438 static gboolean
4439 gst_value_is_subset_structure_structure (const GValue * value1,
4440     const GValue * value2)
4441 {
4442   const GstStructure *s1, *s2;
4443
4444   g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (value1), FALSE);
4445   g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (value2), FALSE);
4446
4447   s1 = gst_value_get_structure (value1);
4448   s2 = gst_value_get_structure (value2);
4449
4450   return gst_structure_is_subset (s1, s2);
4451 }
4452
4453 static gboolean
4454 gst_value_is_subset_list_list (const GValue * value1, const GValue * value2)
4455 {
4456   GstValueList *vlist1 = VALUE_LIST_ARRAY (value1);
4457   GstValueList *vlist2 = VALUE_LIST_ARRAY (value2);
4458   gint it1, len1, it2, len2;
4459
4460   len1 = vlist1->len;
4461   len2 = vlist2->len;
4462
4463   /* A list can't be a subset of a smaller list */
4464   if (len1 > len2)
4465     return FALSE;
4466
4467   /* Check if all elements of the first list are within the 2nd list */
4468   for (it1 = 0; it1 < len1; it1++) {
4469     const GValue *child1 = &vlist1->fields[it1];
4470     gboolean seen = FALSE;
4471
4472     for (it2 = 0; it2 < len2; it2++) {
4473       const GValue *child2 = &vlist2->fields[it2];
4474       if (gst_value_compare (child1, child2) == GST_VALUE_EQUAL) {
4475         seen = TRUE;
4476         break;
4477       }
4478     }
4479     if (!seen)
4480       return FALSE;
4481   }
4482
4483   return TRUE;
4484 }
4485
4486 static gboolean
4487 gst_value_is_subset_list (const GValue * value1, const GValue * value2)
4488 {
4489   GstValueList *vlist2 = VALUE_LIST_ARRAY (value2);
4490   gint it2, len2;
4491
4492   len2 = vlist2->len;
4493
4494   /* Check whether value1 is within the list */
4495   for (it2 = 0; it2 < len2; it2++) {
4496     const GValue *child2 = &vlist2->fields[it2];
4497     if (gst_value_compare (value1, child2) == GST_VALUE_EQUAL) {
4498       return TRUE;
4499     }
4500   }
4501
4502   return FALSE;
4503 }
4504
4505 /**
4506  * gst_value_is_subset:
4507  * @value1: a #GValue
4508  * @value2: a #GValue
4509  *
4510  * Check that @value1 is a subset of @value2.
4511  *
4512  * Return: %TRUE is @value1 is a subset of @value2
4513  */
4514 gboolean
4515 gst_value_is_subset (const GValue * value1, const GValue * value2)
4516 {
4517   GType type1 = G_VALUE_TYPE (value1);
4518   GType type2 = G_VALUE_TYPE (value2);
4519
4520   /* special case for int/int64 ranges, since we cannot compute
4521      the difference for those when they have different steps,
4522      and it's actually a lot simpler to compute whether a range
4523      is a subset of another. */
4524   if (GST_VALUE_HOLDS_INT_RANGE (value1) && GST_VALUE_HOLDS_INT_RANGE (value2)) {
4525     return gst_value_is_subset_int_range_int_range (value1, value2);
4526   } else if (GST_VALUE_HOLDS_INT64_RANGE (value1)
4527       && GST_VALUE_HOLDS_INT64_RANGE (value2)) {
4528     return gst_value_is_subset_int64_range_int64_range (value1, value2);
4529   } else if (GST_VALUE_HOLDS_FLAG_SET (value1) &&
4530       GST_VALUE_HOLDS_FLAG_SET (value2)) {
4531     return gst_value_is_subset_flagset_flagset (value1, value2);
4532   } else if (GST_VALUE_HOLDS_STRUCTURE (value1)
4533       && GST_VALUE_HOLDS_STRUCTURE (value2)) {
4534     return gst_value_is_subset_structure_structure (value1, value2);
4535   } else if (type2 == GST_TYPE_LIST) {
4536     if (type1 == GST_TYPE_LIST)
4537       return gst_value_is_subset_list_list (value1, value2);
4538     return gst_value_is_subset_list (value1, value2);
4539   }
4540
4541   /*
4542    * 1 - [1,2] = empty
4543    * -> !subset
4544    *
4545    * [1,2] - 1 = 2
4546    *  -> 1 - [1,2] = empty
4547    *  -> subset
4548    *
4549    * [1,3] - [1,2] = 3
4550    * -> [1,2] - [1,3] = empty
4551    * -> subset
4552    *
4553    * {1,2} - {1,3} = 2
4554    * -> {1,3} - {1,2} = 3
4555    * -> !subset
4556    *
4557    *  First caps subtraction needs to return a non-empty set, second
4558    *  subtractions needs to give en empty set.
4559    *  Both substractions are switched below, as it's faster that way.
4560    */
4561   if (!gst_value_subtract (NULL, value1, value2)) {
4562     if (gst_value_subtract (NULL, value2, value1)) {
4563       return TRUE;
4564     }
4565   }
4566   return FALSE;
4567 }
4568
4569 /*********
4570  * union *
4571  *********/
4572
4573 static gboolean
4574 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
4575     const GValue * src2)
4576 {
4577   gint v = src1->data[0].v_int;
4578
4579   /* check if it's already in the range */
4580   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= v &&
4581       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= v &&
4582       v % INT_RANGE_STEP (src2) == 0) {
4583     if (dest)
4584       gst_value_init_and_copy (dest, src2);
4585     return TRUE;
4586   }
4587
4588   /* check if it extends the range */
4589   if (v == (INT_RANGE_MIN (src2) - 1) * INT_RANGE_STEP (src2)) {
4590     if (dest) {
4591       guint64 new_min = INT_RANGE_MIN (src2) - 1;
4592       guint64 new_max = INT_RANGE_MAX (src2);
4593
4594       gst_value_init_and_copy (dest, src2);
4595       dest->data[0].v_uint64 = (new_min << 32) | (new_max);
4596     }
4597     return TRUE;
4598   }
4599   if (v == (INT_RANGE_MAX (src2) + 1) * INT_RANGE_STEP (src2)) {
4600     if (dest) {
4601       guint64 new_min = INT_RANGE_MIN (src2);
4602       guint64 new_max = INT_RANGE_MAX (src2) + 1;
4603
4604       gst_value_init_and_copy (dest, src2);
4605       dest->data[0].v_uint64 = (new_min << 32) | (new_max);
4606     }
4607     return TRUE;
4608   }
4609
4610   return FALSE;
4611 }
4612
4613 static gboolean
4614 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
4615     const GValue * src2)
4616 {
4617   /* We can union in several special cases:
4618      1 - one is a subset of another
4619      2 - same step and not disjoint
4620      3 - different step, at least one with one value which matches a 'next' or 'previous'
4621      - anything else ?
4622    */
4623
4624   /* 1 - subset */
4625   if (gst_value_is_subset_int_range_int_range (src1, src2)) {
4626     if (dest)
4627       gst_value_init_and_copy (dest, src2);
4628     return TRUE;
4629   }
4630   if (gst_value_is_subset_int_range_int_range (src2, src1)) {
4631     if (dest)
4632       gst_value_init_and_copy (dest, src1);
4633     return TRUE;
4634   }
4635
4636   /* 2 - same step and not disjoint */
4637   if (INT_RANGE_STEP (src1) == INT_RANGE_STEP (src2)) {
4638     if ((INT_RANGE_MIN (src1) <= INT_RANGE_MAX (src2) + 1 &&
4639             INT_RANGE_MAX (src1) >= INT_RANGE_MIN (src2) - 1) ||
4640         (INT_RANGE_MIN (src2) <= INT_RANGE_MAX (src1) + 1 &&
4641             INT_RANGE_MAX (src2) >= INT_RANGE_MIN (src1) - 1)) {
4642       if (dest) {
4643         gint step = INT_RANGE_STEP (src1);
4644         gint min = step * MIN (INT_RANGE_MIN (src1), INT_RANGE_MIN (src2));
4645         gint max = step * MAX (INT_RANGE_MAX (src1), INT_RANGE_MAX (src2));
4646         g_value_init (dest, GST_TYPE_INT_RANGE);
4647         gst_value_set_int_range_step (dest, min, max, step);
4648       }
4649       return TRUE;
4650     }
4651   }
4652
4653   /* 3 - single value matches next or previous */
4654   if (INT_RANGE_STEP (src1) != INT_RANGE_STEP (src2)) {
4655     gint n1 = INT_RANGE_MAX (src1) - INT_RANGE_MIN (src1) + 1;
4656     gint n2 = INT_RANGE_MAX (src2) - INT_RANGE_MIN (src2) + 1;
4657     if (n1 == 1 || n2 == 1) {
4658       const GValue *range_value = NULL;
4659       gint scalar = 0;
4660       if (n1 == 1) {
4661         range_value = src2;
4662         scalar = INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1);
4663       } else if (n2 == 1) {
4664         range_value = src1;
4665         scalar = INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2);
4666       }
4667
4668       if (scalar ==
4669           (INT_RANGE_MIN (range_value) - 1) * INT_RANGE_STEP (range_value)) {
4670         if (dest) {
4671           guint64 new_min = (guint)
4672               ((INT_RANGE_MIN (range_value) -
4673                   1) * INT_RANGE_STEP (range_value));
4674           guint64 new_max = (guint)
4675               (INT_RANGE_MAX (range_value) * INT_RANGE_STEP (range_value));
4676
4677           gst_value_init_and_copy (dest, range_value);
4678           dest->data[0].v_uint64 = (new_min << 32) | (new_max);
4679         }
4680         return TRUE;
4681       } else if (scalar ==
4682           (INT_RANGE_MAX (range_value) + 1) * INT_RANGE_STEP (range_value)) {
4683         if (dest) {
4684           guint64 new_min = (guint)
4685               (INT_RANGE_MIN (range_value) * INT_RANGE_STEP (range_value));
4686           guint64 new_max = (guint)
4687               ((INT_RANGE_MAX (range_value) +
4688                   1) * INT_RANGE_STEP (range_value));
4689           gst_value_init_and_copy (dest, range_value);
4690           dest->data[0].v_uint64 = (new_min << 32) | (new_max);
4691         }
4692         return TRUE;
4693       }
4694     }
4695   }
4696
4697   /* If we get there, we did not find a way to make a union that can be
4698      represented with our simplistic model. */
4699   return FALSE;
4700 }
4701
4702 static gboolean
4703 gst_value_union_flagset_flagset (GValue * dest, const GValue * src1,
4704     const GValue * src2)
4705 {
4706   /* We can union 2 flag sets where they do not disagree on
4707    * required (masked) flag bits */
4708   guint64 f1, f2;
4709   guint64 m1, m2;
4710
4711   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src1), FALSE);
4712   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src2), FALSE);
4713
4714   f1 = src1->data[0].v_uint;
4715   f2 = src2->data[0].v_uint;
4716
4717   m1 = src1->data[1].v_uint;
4718   m2 = src2->data[1].v_uint;
4719
4720   /* Can't union if masked bits disagree */
4721   if ((f1 & (m1 & m2)) != (f2 & (m1 & m2)))
4722     return FALSE;
4723
4724   if (dest) {
4725     g_value_init (dest, GST_TYPE_FLAG_SET);
4726     /* Copy masked bits from src2 to src1 */
4727     f1 &= ~m2;
4728     f1 |= (f2 & m2);
4729     m1 |= m2;
4730     gst_value_set_flagset (dest, f1, m1);
4731   }
4732
4733   return TRUE;
4734 }
4735
4736 /* iterating over the result taking the union with the other structure's value */
4737 static gboolean
4738 structure_field_union_into (GQuark field_id, GValue * val, gpointer user_data)
4739 {
4740   GstStructure *other = user_data;
4741   const GValue *other_value;
4742   GValue res_value = G_VALUE_INIT;
4743
4744   other_value = gst_structure_id_get_value (other, field_id);
4745   /* no value in the other struct, just keep this value */
4746   if (!other_value)
4747     return TRUE;
4748
4749   if (!gst_value_union (&res_value, val, other_value))
4750     return FALSE;
4751
4752   g_value_unset (val);
4753   gst_value_move (val, &res_value);
4754   return TRUE;
4755 }
4756
4757 /* iterating over the other source structure adding missing values */
4758 static gboolean
4759 structure_field_union_from (GQuark field_id, const GValue * other_val,
4760     gpointer user_data)
4761 {
4762   GstStructure *result = user_data;
4763   const GValue *result_value;
4764
4765   result_value = gst_structure_id_get_value (result, field_id);
4766   if (!result_value)
4767     gst_structure_id_set_value (result, field_id, other_val);
4768
4769   return TRUE;
4770 }
4771
4772 static gboolean
4773 gst_value_union_structure_structure (GValue * dest, const GValue * src1,
4774     const GValue * src2)
4775 {
4776   const GstStructure *s1, *s2;
4777   GstStructure *result;
4778   gboolean ret;
4779
4780   g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (src1), FALSE);
4781   g_return_val_if_fail (GST_VALUE_HOLDS_STRUCTURE (src2), FALSE);
4782
4783   s1 = gst_value_get_structure (src1);
4784   s2 = gst_value_get_structure (src2);
4785
4786   /* Can't join two structures with different names into a single structure */
4787   if (!gst_structure_has_name (s1, gst_structure_get_name (s2))) {
4788     gst_value_list_concat (dest, src1, src2);
4789     return TRUE;
4790   }
4791
4792   result = gst_structure_copy (s1);
4793   ret =
4794       gst_structure_map_in_place (result, structure_field_union_into,
4795       (gpointer) s2);
4796   if (!ret)
4797     goto out;
4798   ret =
4799       gst_structure_foreach (s2, structure_field_union_from, (gpointer) result);
4800
4801   if (ret) {
4802     g_value_init (dest, GST_TYPE_STRUCTURE);
4803     gst_value_set_structure (dest, result);
4804   }
4805
4806 out:
4807   gst_structure_free (result);
4808   return ret;
4809 }
4810
4811 /****************
4812  * intersection *
4813  ****************/
4814
4815 static gboolean
4816 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
4817     const GValue * src2)
4818 {
4819   if (INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2) <= src1->data[0].v_int &&
4820       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2) >= src1->data[0].v_int &&
4821       src1->data[0].v_int % INT_RANGE_STEP (src2) == 0) {
4822     if (dest)
4823       gst_value_init_and_copy (dest, src1);
4824     return TRUE;
4825   }
4826
4827   return FALSE;
4828 }
4829
4830 static gboolean
4831 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
4832     const GValue * src2)
4833 {
4834   gint min;
4835   gint max;
4836   gint step;
4837
4838   step =
4839       INT_RANGE_STEP (src1) /
4840       gst_util_greatest_common_divisor (INT_RANGE_STEP (src1),
4841       INT_RANGE_STEP (src2));
4842   if (G_MAXINT32 / INT_RANGE_STEP (src2) < step)
4843     return FALSE;
4844   step *= INT_RANGE_STEP (src2);
4845
4846   min =
4847       MAX (INT_RANGE_MIN (src1) * INT_RANGE_STEP (src1),
4848       INT_RANGE_MIN (src2) * INT_RANGE_STEP (src2));
4849   min = (min + step - 1) / step * step;
4850   max =
4851       MIN (INT_RANGE_MAX (src1) * INT_RANGE_STEP (src1),
4852       INT_RANGE_MAX (src2) * INT_RANGE_STEP (src2));
4853   max = max / step * step;
4854
4855   if (min < max) {
4856     if (dest) {
4857       g_value_init (dest, GST_TYPE_INT_RANGE);
4858       gst_value_set_int_range_step (dest, min, max, step);
4859     }
4860     return TRUE;
4861   }
4862   if (min == max) {
4863     if (dest) {
4864       g_value_init (dest, G_TYPE_INT);
4865       g_value_set_int (dest, min);
4866     }
4867     return TRUE;
4868   }
4869
4870   return FALSE;
4871 }
4872
4873 #define INT64_RANGE_MIN_VAL(v) (INT64_RANGE_MIN (v) * INT64_RANGE_STEP (v))
4874 #define INT64_RANGE_MAX_VAL(v) (INT64_RANGE_MAX (v) * INT64_RANGE_STEP (v))
4875
4876 static gboolean
4877 gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1,
4878     const GValue * src2)
4879 {
4880   if (INT64_RANGE_MIN_VAL (src2) <= src1->data[0].v_int64 &&
4881       INT64_RANGE_MAX_VAL (src2) >= src1->data[0].v_int64 &&
4882       src1->data[0].v_int64 % INT64_RANGE_STEP (src2) == 0) {
4883     if (dest)
4884       gst_value_init_and_copy (dest, src1);
4885     return TRUE;
4886   }
4887
4888   return FALSE;
4889 }
4890
4891 static gboolean
4892 gst_value_intersect_int64_range_int64_range (GValue * dest, const GValue * src1,
4893     const GValue * src2)
4894 {
4895   gint64 min;
4896   gint64 max;
4897   gint64 step;
4898
4899   step =
4900       INT64_RANGE_STEP (src1) /
4901       gst_util_greatest_common_divisor_int64 (INT64_RANGE_STEP (src1),
4902       INT64_RANGE_STEP (src2));
4903   if (G_MAXINT64 / INT64_RANGE_STEP (src2) < step)
4904     return FALSE;
4905   step *= INT64_RANGE_STEP (src2);
4906
4907   min =
4908       MAX (INT64_RANGE_MIN (src1) * INT64_RANGE_STEP (src1),
4909       INT64_RANGE_MIN (src2) * INT64_RANGE_STEP (src2));
4910   min = (min + step - 1) / step * step;
4911   max =
4912       MIN (INT64_RANGE_MAX (src1) * INT64_RANGE_STEP (src1),
4913       INT64_RANGE_MAX (src2) * INT64_RANGE_STEP (src2));
4914   max = max / step * step;
4915
4916   if (min < max) {
4917     if (dest) {
4918       g_value_init (dest, GST_TYPE_INT64_RANGE);
4919       gst_value_set_int64_range_step (dest, min, max, step);
4920     }
4921     return TRUE;
4922   }
4923   if (min == max) {
4924     if (dest) {
4925       g_value_init (dest, G_TYPE_INT64);
4926       g_value_set_int64 (dest, min);
4927     }
4928     return TRUE;
4929   }
4930
4931   return FALSE;
4932 }
4933
4934 static gboolean
4935 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
4936     const GValue * src2)
4937 {
4938   if (src2->data[0].v_double <= src1->data[0].v_double &&
4939       src2->data[1].v_double >= src1->data[0].v_double) {
4940     if (dest)
4941       gst_value_init_and_copy (dest, src1);
4942     return TRUE;
4943   }
4944
4945   return FALSE;
4946 }
4947
4948 static gboolean
4949 gst_value_intersect_double_range_double_range (GValue * dest,
4950     const GValue * src1, const GValue * src2)
4951 {
4952   gdouble min;
4953   gdouble max;
4954
4955   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
4956   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
4957
4958   if (min < max) {
4959     if (dest) {
4960       g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
4961       gst_value_set_double_range (dest, min, max);
4962     }
4963     return TRUE;
4964   }
4965   if (min == max) {
4966     if (dest) {
4967       g_value_init (dest, G_TYPE_DOUBLE);
4968       g_value_set_int (dest, (int) min);
4969     }
4970     return TRUE;
4971   }
4972
4973   return FALSE;
4974 }
4975
4976 static gboolean
4977 gst_value_intersect_list_list (GValue * dest, const GValue * value1,
4978     const GValue * value2)
4979 {
4980   guint8 tmpfield[16];          /* Check up to 128 values */
4981   guint8 *bitfield;
4982   gboolean alloc_bitfield = FALSE;
4983   gboolean res = FALSE;
4984   GValue *tmp;
4985   GType type1, type2;
4986   guint it1, len1, start2, it2, len2, itar;
4987   GstValueList *vlist = NULL;
4988
4989   /* If they don't have the same basic type, all bets are off :) */
4990   if (!gst_value_list_or_array_get_basic_type (value1, &type1) ||
4991       !gst_value_list_or_array_get_basic_type (value2, &type2) ||
4992       type1 != type2)
4993     return FALSE;
4994
4995   len1 = VALUE_LIST_SIZE (value1);
4996   len2 = VALUE_LIST_SIZE (value2);
4997
4998   /* Fast-path with no dest (i.e. only interested in knowing whether
4999    * both lists intersected without wanting the result) */
5000   if (!dest) {
5001     for (it1 = 0; it1 < len1; it1++) {
5002       const GValue *item1 = VALUE_LIST_GET_VALUE (value1, it1);
5003       for (it2 = 0; it2 < len2; it2++) {
5004         const GValue *item2 = VALUE_LIST_GET_VALUE (value2, it2);
5005         if (gst_value_intersect (NULL, item1, item2)) {
5006           res = TRUE;
5007           goto beach;
5008         }
5009       }
5010     }
5011     goto beach;
5012   }
5013 #define is_visited(idx) (bitfield[(idx) >> 3]    & (1 << ((idx) & 0x7)))
5014 #define mark_visited(idx) (bitfield[(idx) >> 3] |= (1 << ((idx) & 0x7)))
5015
5016   /* Bitfield to avoid double-visiting */
5017   if (G_UNLIKELY (len2 > 128)) {
5018     alloc_bitfield = TRUE;
5019     bitfield = g_malloc0 ((len2 / 8) + 1);
5020     GST_CAT_LOG (GST_CAT_PERFORMANCE,
5021         "Allocation for GstValueList with more than 128 members");
5022   } else {
5023     bitfield = &tmpfield[0];
5024     memset (bitfield, 0, 16);
5025   }
5026
5027
5028   /* When doing list<->list intersections, there is a greater
5029    * probability of ending up with a list than with a single value.
5030    * Furthermore, the biggest that list can be will the smallest list
5031    * (i.e. intersects fully).
5032    * Therefore we pre-allocate a GstValueList of that size. */
5033   vlist = _gst_value_list_new (MIN (len1, len2));
5034
5035   itar = 0;
5036   tmp = &vlist->fields[0];
5037   start2 = 0;
5038
5039   for (it1 = 0; it1 < len1; it1++) {
5040     const GValue *item1 = VALUE_LIST_GET_VALUE (value1, it1);
5041     for (it2 = start2; it2 < len2; it2++) {
5042       const GValue *item2;
5043       if (is_visited (it2))
5044         continue;
5045       item2 = VALUE_LIST_GET_VALUE (value2, it2);
5046
5047       if (gst_value_intersect (tmp, item1, item2)) {
5048         res = TRUE;
5049         mark_visited (it2);
5050         /* Increment our inner-loop starting point */
5051         if (it2 == start2)
5052           start2++;
5053
5054         /* Move our collection value */
5055         itar += 1;
5056         tmp = &vlist->fields[itar];
5057         vlist->len += 1;
5058
5059         /* We can stop iterating the second part now that we've matched */
5060         break;
5061       }
5062     }
5063   }
5064
5065 #undef is_visited
5066 #undef mark_visited
5067
5068   if (res) {
5069     /* If we end up with a single value in the list, just use that
5070      * value. Else use the list */
5071     if (vlist->len == 1) {
5072       gst_value_move (dest, &vlist->fields[0]);
5073       g_free (vlist);
5074     } else {
5075       dest->g_type = GST_TYPE_LIST;
5076       dest->data[0].v_pointer = vlist;
5077     }
5078   } else {
5079     g_free (vlist);
5080   }
5081
5082 beach:
5083   if (alloc_bitfield)
5084     g_free (bitfield);
5085   return res;
5086 }
5087
5088 static gboolean
5089 gst_value_intersect_list (GValue * dest, const GValue * value1,
5090     const GValue * value2)
5091 {
5092   guint i, size;
5093   GValue intersection = { 0, };
5094   gboolean ret = FALSE;
5095
5096   /* Use optimized list-list intersection */
5097   if (G_VALUE_TYPE (value2) == GST_TYPE_LIST) {
5098     return gst_value_intersect_list_list (dest, value1, value2);
5099   }
5100
5101   size = VALUE_LIST_SIZE (value1);
5102   for (i = 0; i < size; i++) {
5103     const GValue *cur = VALUE_LIST_GET_VALUE (value1, i);
5104
5105     /* quicker version when we don't need the resulting set */
5106     if (!dest) {
5107       if (gst_value_intersect (NULL, cur, value2)) {
5108         ret = TRUE;
5109         break;
5110       }
5111       continue;
5112     }
5113
5114     if (gst_value_intersect (&intersection, cur, value2)) {
5115       /* append value */
5116       if (!ret) {
5117         gst_value_move (dest, &intersection);
5118         ret = TRUE;
5119       } else if (GST_VALUE_HOLDS_LIST (dest)) {
5120         _gst_value_list_append_and_take_value (dest, &intersection);
5121       } else {
5122         GValue temp;
5123
5124         gst_value_move (&temp, dest);
5125         gst_value_list_merge (dest, &temp, &intersection);
5126         g_value_unset (&temp);
5127         g_value_unset (&intersection);
5128       }
5129     }
5130   }
5131
5132   return ret;
5133 }
5134
5135 static gboolean
5136 gst_value_intersect_array (GValue * dest, const GValue * src1,
5137     const GValue * src2)
5138 {
5139   guint size;
5140   guint n;
5141   GValue val = { 0 };
5142
5143   /* only works on similar-sized arrays */
5144   size = gst_value_array_get_size (src1);
5145   if (size != gst_value_array_get_size (src2))
5146     return FALSE;
5147
5148   /* quicker value when we don't need the resulting set */
5149   if (!dest) {
5150     for (n = 0; n < size; n++) {
5151       if (!gst_value_intersect (NULL, gst_value_array_get_value (src1, n),
5152               gst_value_array_get_value (src2, n))) {
5153         return FALSE;
5154       }
5155     }
5156     return TRUE;
5157   }
5158
5159   g_value_init (dest, GST_TYPE_ARRAY);
5160
5161   for (n = 0; n < size; n++) {
5162     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
5163             gst_value_array_get_value (src2, n))) {
5164       g_value_unset (dest);
5165       return FALSE;
5166     }
5167     _gst_value_array_append_and_take_value (dest, &val);
5168   }
5169
5170   return TRUE;
5171 }
5172
5173 static gboolean
5174 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
5175     const GValue * src2)
5176 {
5177   gint res1, res2;
5178   GValue *vals;
5179
5180   vals = src2->data[0].v_pointer;
5181
5182   if (vals == NULL)
5183     return FALSE;
5184
5185   res1 = gst_value_compare_fraction (&vals[0], src1);
5186   res2 = gst_value_compare_fraction (&vals[1], src1);
5187
5188   if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
5189       (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
5190     if (dest)
5191       gst_value_init_and_copy (dest, src1);
5192     return TRUE;
5193   }
5194   return FALSE;
5195 }
5196
5197 static gboolean
5198 gst_value_intersect_fraction_range_fraction_range (GValue * dest,
5199     const GValue * src1, const GValue * src2)
5200 {
5201   GValue *min;
5202   GValue *max;
5203   gint res;
5204   GValue *vals1, *vals2;
5205
5206   vals1 = src1->data[0].v_pointer;
5207   vals2 = src2->data[0].v_pointer;
5208   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
5209
5210   /* min = MAX (src1.start, src2.start) */
5211   res = gst_value_compare_fraction (&vals1[0], &vals2[0]);
5212   g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
5213   if (res == GST_VALUE_LESS_THAN)
5214     min = &vals2[0];            /* Take the max of the 2 */
5215   else
5216     min = &vals1[0];
5217
5218   /* max = MIN (src1.end, src2.end) */
5219   res = gst_value_compare_fraction (&vals1[1], &vals2[1]);
5220   g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
5221   if (res == GST_VALUE_GREATER_THAN)
5222     max = &vals2[1];            /* Take the min of the 2 */
5223   else
5224     max = &vals1[1];
5225
5226   res = gst_value_compare_fraction (min, max);
5227   g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
5228   if (res == GST_VALUE_LESS_THAN) {
5229     if (dest) {
5230       g_value_init (dest, GST_TYPE_FRACTION_RANGE);
5231       vals1 = dest->data[0].v_pointer;
5232       g_value_copy (min, &vals1[0]);
5233       g_value_copy (max, &vals1[1]);
5234     }
5235     return TRUE;
5236   }
5237   if (res == GST_VALUE_EQUAL) {
5238     if (dest)
5239       gst_value_init_and_copy (dest, min);
5240     return TRUE;
5241   }
5242
5243   return FALSE;
5244 }
5245
5246 /* Two flagsets intersect if the masked bits in both
5247  * flagsets are exactly equal */
5248 static gboolean
5249 gst_value_intersect_flagset_flagset (GValue * dest,
5250     const GValue * src1, const GValue * src2)
5251 {
5252   guint f1, f2;
5253   guint m1, m2;
5254   GType type1, type2, flagset_type;
5255
5256   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src1), FALSE);
5257   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (src2), FALSE);
5258
5259   f1 = src1->data[0].v_uint;
5260   f2 = src2->data[0].v_uint;
5261
5262   m1 = src1->data[1].v_uint;
5263   m2 = src2->data[1].v_uint;
5264
5265   /* Don't intersect if masked bits disagree */
5266   if ((f1 & (m1 & m2)) != (f2 & (m1 & m2)))
5267     return FALSE;
5268
5269   /* Allow intersection with the generic FlagSet type, on one
5270    * side, but not 2 different subtypes - that makes no sense */
5271   type1 = G_VALUE_TYPE (src1);
5272   type2 = G_VALUE_TYPE (src2);
5273   flagset_type = GST_TYPE_FLAG_SET;
5274
5275   if (type1 != type2 && type1 != flagset_type && type2 != flagset_type)
5276     return FALSE;
5277
5278   if (dest) {
5279     GType dest_type;
5280
5281     /* Prefer an output type that matches a sub-type,
5282      * rather than the generic type */
5283     if (type1 != flagset_type)
5284       dest_type = type1;
5285     else
5286       dest_type = type2;
5287
5288     g_value_init (dest, dest_type);
5289
5290     /* The compatible set is all the bits from src1 that it
5291      * cares about and all the bits from src2 that it cares
5292      * about. */
5293     dest->data[0].v_uint = (f1 & m1) | (f2 & m2);
5294     dest->data[1].v_uint = m1 | m2;
5295   }
5296
5297   return TRUE;
5298 }
5299
5300 static gboolean
5301 gst_value_intersect_structure_structure (GValue * dest,
5302     const GValue * src1, const GValue * src2)
5303 {
5304   const GstStructure *s1, *s2;
5305   GstStructure *d1;
5306
5307   s1 = gst_value_get_structure (src1);
5308   s2 = gst_value_get_structure (src2);
5309
5310   d1 = gst_structure_intersect (s1, s2);
5311   if (!d1)
5312     return FALSE;
5313
5314   if (dest) {
5315     g_value_init (dest, GST_TYPE_STRUCTURE);
5316     gst_value_set_structure (dest, d1);
5317   }
5318
5319   gst_structure_free (d1);
5320   return TRUE;
5321 }
5322
5323 /***************
5324  * subtraction *
5325  ***************/
5326
5327 static gboolean
5328 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
5329     const GValue * subtrahend)
5330 {
5331   gint min = gst_value_get_int_range_min (subtrahend);
5332   gint max = gst_value_get_int_range_max (subtrahend);
5333   gint step = gst_value_get_int_range_step (subtrahend);
5334   gint val = g_value_get_int (minuend);
5335
5336   if (step == 0)
5337     return FALSE;
5338
5339   /* subtracting a range from an int only works if the int is not in the
5340    * range */
5341   if (val < min || val > max || val % step) {
5342     /* and the result is the int */
5343     if (dest)
5344       gst_value_init_and_copy (dest, minuend);
5345     return TRUE;
5346   }
5347   return FALSE;
5348 }
5349
5350 /* creates a new int range based on input values.
5351  */
5352 static gboolean
5353 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
5354     gint max2, gint step)
5355 {
5356   GValue v1 = { 0, };
5357   GValue v2 = { 0, };
5358   GValue *pv1, *pv2;            /* yeah, hungarian! */
5359
5360   g_return_val_if_fail (step > 0, FALSE);
5361   g_return_val_if_fail (min1 % step == 0, FALSE);
5362   g_return_val_if_fail (max1 % step == 0, FALSE);
5363   g_return_val_if_fail (min2 % step == 0, FALSE);
5364   g_return_val_if_fail (max2 % step == 0, FALSE);
5365
5366   if (min1 <= max1 && min2 <= max2) {
5367     pv1 = &v1;
5368     pv2 = &v2;
5369   } else if (min1 <= max1) {
5370     pv1 = dest;
5371     pv2 = NULL;
5372   } else if (min2 <= max2) {
5373     pv1 = NULL;
5374     pv2 = dest;
5375   } else {
5376     return FALSE;
5377   }
5378
5379   if (!dest)
5380     return TRUE;
5381
5382   if (min1 < max1) {
5383     g_value_init (pv1, GST_TYPE_INT_RANGE);
5384     gst_value_set_int_range_step (pv1, min1, max1, step);
5385   } else if (min1 == max1) {
5386     g_value_init (pv1, G_TYPE_INT);
5387     g_value_set_int (pv1, min1);
5388   }
5389   if (min2 < max2) {
5390     g_value_init (pv2, GST_TYPE_INT_RANGE);
5391     gst_value_set_int_range_step (pv2, min2, max2, step);
5392   } else if (min2 == max2) {
5393     g_value_init (pv2, G_TYPE_INT);
5394     g_value_set_int (pv2, min2);
5395   }
5396
5397   if (min1 <= max1 && min2 <= max2) {
5398     gst_value_list_concat_and_take_values (dest, pv1, pv2);
5399   }
5400   return TRUE;
5401 }
5402
5403 static gboolean
5404 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
5405     const GValue * subtrahend)
5406 {
5407   gint min = gst_value_get_int_range_min (minuend);
5408   gint max = gst_value_get_int_range_max (minuend);
5409   gint step = gst_value_get_int_range_step (minuend);
5410   gint val = g_value_get_int (subtrahend);
5411
5412   g_return_val_if_fail (min < max, FALSE);
5413
5414   if (step == 0)
5415     return FALSE;
5416
5417   /* value is outside of the range, return range unchanged */
5418   if (val < min || val > max || val % step) {
5419     if (dest)
5420       gst_value_init_and_copy (dest, minuend);
5421     return TRUE;
5422   } else {
5423     /* max must be MAXINT too as val <= max */
5424     if (val >= G_MAXINT - step + 1) {
5425       max -= step;
5426       val -= step;
5427     }
5428     /* min must be MININT too as val >= max */
5429     if (val <= G_MININT + step - 1) {
5430       min += step;
5431       val += step;
5432     }
5433     if (dest)
5434       gst_value_create_new_range (dest, min, val - step, val + step, max, step);
5435   }
5436   return TRUE;
5437 }
5438
5439 static gboolean
5440 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
5441     const GValue * subtrahend)
5442 {
5443   gint min1 = gst_value_get_int_range_min (minuend);
5444   gint max1 = gst_value_get_int_range_max (minuend);
5445   gint step1 = gst_value_get_int_range_step (minuend);
5446   gint min2 = gst_value_get_int_range_min (subtrahend);
5447   gint max2 = gst_value_get_int_range_max (subtrahend);
5448   gint step2 = gst_value_get_int_range_step (subtrahend);
5449   gint step;
5450
5451   if (step1 != step2) {
5452     /* ENOIMPL */
5453     g_assert (FALSE);
5454     return FALSE;
5455   }
5456   step = step1;
5457
5458   if (step == 0)
5459     return FALSE;
5460
5461   if (max2 >= max1 && min2 <= min1) {
5462     return FALSE;
5463   } else if (max2 >= max1) {
5464     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
5465         step, 0, step);
5466   } else if (min2 <= min1) {
5467     return gst_value_create_new_range (dest, MAX (max2 + step, min1), max1,
5468         step, 0, step);
5469   } else {
5470     return gst_value_create_new_range (dest, min1, MIN (min2 - step, max1),
5471         MAX (max2 + step, min1), max1, step);
5472   }
5473 }
5474
5475 static gboolean
5476 gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend,
5477     const GValue * subtrahend)
5478 {
5479   gint64 min = gst_value_get_int64_range_min (subtrahend);
5480   gint64 max = gst_value_get_int64_range_max (subtrahend);
5481   gint64 step = gst_value_get_int64_range_step (subtrahend);
5482   gint64 val = g_value_get_int64 (minuend);
5483
5484   if (step == 0)
5485     return FALSE;
5486   /* subtracting a range from an int64 only works if the int64 is not in the
5487    * range */
5488   if (val < min || val > max || val % step) {
5489     /* and the result is the int64 */
5490     if (dest)
5491       gst_value_init_and_copy (dest, minuend);
5492     return TRUE;
5493   }
5494   return FALSE;
5495 }
5496
5497 /* creates a new int64 range based on input values.
5498  */
5499 static gboolean
5500 gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1,
5501     gint64 min2, gint64 max2, gint64 step)
5502 {
5503   GValue v1 = { 0, };
5504   GValue v2 = { 0, };
5505   GValue *pv1, *pv2;            /* yeah, hungarian! */
5506
5507   g_return_val_if_fail (step > 0, FALSE);
5508   g_return_val_if_fail (min1 % step == 0, FALSE);
5509   g_return_val_if_fail (max1 % step == 0, FALSE);
5510   g_return_val_if_fail (min2 % step == 0, FALSE);
5511   g_return_val_if_fail (max2 % step == 0, FALSE);
5512
5513   if (min1 <= max1 && min2 <= max2) {
5514     pv1 = &v1;
5515     pv2 = &v2;
5516   } else if (min1 <= max1) {
5517     pv1 = dest;
5518     pv2 = NULL;
5519   } else if (min2 <= max2) {
5520     pv1 = NULL;
5521     pv2 = dest;
5522   } else {
5523     return FALSE;
5524   }
5525
5526   if (!dest)
5527     return TRUE;
5528
5529   if (min1 < max1) {
5530     g_value_init (pv1, GST_TYPE_INT64_RANGE);
5531     gst_value_set_int64_range_step (pv1, min1, max1, step);
5532   } else if (min1 == max1) {
5533     g_value_init (pv1, G_TYPE_INT64);
5534     g_value_set_int64 (pv1, min1);
5535   }
5536   if (min2 < max2) {
5537     g_value_init (pv2, GST_TYPE_INT64_RANGE);
5538     gst_value_set_int64_range_step (pv2, min2, max2, step);
5539   } else if (min2 == max2) {
5540     g_value_init (pv2, G_TYPE_INT64);
5541     g_value_set_int64 (pv2, min2);
5542   }
5543
5544   if (min1 <= max1 && min2 <= max2) {
5545     gst_value_list_concat_and_take_values (dest, pv1, pv2);
5546   }
5547   return TRUE;
5548 }
5549
5550 static gboolean
5551 gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend,
5552     const GValue * subtrahend)
5553 {
5554   gint64 min = gst_value_get_int64_range_min (minuend);
5555   gint64 max = gst_value_get_int64_range_max (minuend);
5556   gint64 step = gst_value_get_int64_range_step (minuend);
5557   gint64 val = g_value_get_int64 (subtrahend);
5558
5559   g_return_val_if_fail (min < max, FALSE);
5560
5561   if (step == 0)
5562     return FALSE;
5563
5564   /* value is outside of the range, return range unchanged */
5565   if (val < min || val > max || val % step) {
5566     if (dest)
5567       gst_value_init_and_copy (dest, minuend);
5568     return TRUE;
5569   } else {
5570     /* max must be MAXINT64 too as val <= max */
5571     if (val >= G_MAXINT64 - step + 1) {
5572       max -= step;
5573       val -= step;
5574     }
5575     /* min must be MININT64 too as val >= max */
5576     if (val <= G_MININT64 + step - 1) {
5577       min += step;
5578       val += step;
5579     }
5580     if (dest)
5581       gst_value_create_new_int64_range (dest, min, val - step, val + step, max,
5582           step);
5583   }
5584   return TRUE;
5585 }
5586
5587 static gboolean
5588 gst_value_subtract_int64_range_int64_range (GValue * dest,
5589     const GValue * minuend, const GValue * subtrahend)
5590 {
5591   gint64 min1 = gst_value_get_int64_range_min (minuend);
5592   gint64 max1 = gst_value_get_int64_range_max (minuend);
5593   gint64 step1 = gst_value_get_int64_range_step (minuend);
5594   gint64 min2 = gst_value_get_int64_range_min (subtrahend);
5595   gint64 max2 = gst_value_get_int64_range_max (subtrahend);
5596   gint64 step2 = gst_value_get_int64_range_step (subtrahend);
5597   gint64 step;
5598
5599   if (step1 != step2) {
5600     /* ENOIMPL */
5601     g_assert (FALSE);
5602     return FALSE;
5603   }
5604
5605   if (step1 == 0)
5606     return FALSE;
5607
5608   step = step1;
5609
5610   if (max2 >= max1 && min2 <= min1) {
5611     return FALSE;
5612   } else if (max2 >= max1) {
5613     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
5614             max1), step, 0, step);
5615   } else if (min2 <= min1) {
5616     return gst_value_create_new_int64_range (dest, MAX (max2 + step, min1),
5617         max1, step, 0, step);
5618   } else {
5619     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - step,
5620             max1), MAX (max2 + step, min1), max1, step);
5621   }
5622 }
5623
5624 static gboolean
5625 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
5626     const GValue * subtrahend)
5627 {
5628   gdouble min = gst_value_get_double_range_min (subtrahend);
5629   gdouble max = gst_value_get_double_range_max (subtrahend);
5630   gdouble val = g_value_get_double (minuend);
5631
5632   if (val < min || val > max) {
5633     if (dest)
5634       gst_value_init_and_copy (dest, minuend);
5635     return TRUE;
5636   }
5637   return FALSE;
5638 }
5639
5640 static gboolean
5641 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
5642     const GValue * subtrahend)
5643 {
5644   /* since we don't have open ranges, we cannot create a hole in
5645    * a double range. We return the original range */
5646   if (dest)
5647     gst_value_init_and_copy (dest, minuend);
5648   return TRUE;
5649 }
5650
5651 static gboolean
5652 gst_value_subtract_double_range_double_range (GValue * dest,
5653     const GValue * minuend, const GValue * subtrahend)
5654 {
5655   /* since we don't have open ranges, we have to approximate */
5656   /* done like with ints */
5657   gdouble min1 = gst_value_get_double_range_min (minuend);
5658   gdouble max2 = gst_value_get_double_range_max (minuend);
5659   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
5660   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
5661   GValue v1 = { 0, };
5662   GValue v2 = { 0, };
5663   GValue *pv1, *pv2;            /* yeah, hungarian! */
5664
5665   if (min1 < max1 && min2 < max2) {
5666     pv1 = &v1;
5667     pv2 = &v2;
5668   } else if (min1 < max1) {
5669     pv1 = dest;
5670     pv2 = NULL;
5671   } else if (min2 < max2) {
5672     pv1 = NULL;
5673     pv2 = dest;
5674   } else {
5675     return FALSE;
5676   }
5677
5678   if (!dest)
5679     return TRUE;
5680
5681   if (min1 < max1) {
5682     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
5683     gst_value_set_double_range (pv1, min1, max1);
5684   }
5685   if (min2 < max2) {
5686     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
5687     gst_value_set_double_range (pv2, min2, max2);
5688   }
5689
5690   if (min1 < max1 && min2 < max2) {
5691     gst_value_list_concat_and_take_values (dest, pv1, pv2);
5692   }
5693   return TRUE;
5694 }
5695
5696 static gboolean
5697 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
5698     const GValue * subtrahend)
5699 {
5700   guint i, size;
5701   GValue subtraction = { 0, };
5702   gboolean ret = FALSE;
5703
5704   size = VALUE_LIST_SIZE (minuend);
5705   for (i = 0; i < size; i++) {
5706     const GValue *cur = VALUE_LIST_GET_VALUE (minuend, i);
5707
5708     /* quicker version when we can discard the result */
5709     if (!dest) {
5710       if (gst_value_subtract (NULL, cur, subtrahend)) {
5711         ret = TRUE;
5712         break;
5713       }
5714       continue;
5715     }
5716
5717     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
5718       if (!ret) {
5719         gst_value_move (dest, &subtraction);
5720         ret = TRUE;
5721       } else if (G_VALUE_TYPE (dest) == GST_TYPE_LIST
5722           && G_VALUE_TYPE (&subtraction) != GST_TYPE_LIST) {
5723         _gst_value_list_append_and_take_value (dest, &subtraction);
5724       } else {
5725         GValue temp;
5726
5727         gst_value_move (&temp, dest);
5728         gst_value_list_concat_and_take_values (dest, &temp, &subtraction);
5729       }
5730     }
5731   }
5732   return ret;
5733 }
5734
5735 static gboolean
5736 gst_value_subtract_list (GValue * dest, const GValue * minuend,
5737     const GValue * subtrahend)
5738 {
5739   guint i, size;
5740   GValue data[2] = { {0,}, {0,} };
5741   GValue *subtraction = &data[0], *result = &data[1];
5742
5743   gst_value_init_and_copy (result, minuend);
5744   size = VALUE_LIST_SIZE (subtrahend);
5745   for (i = 0; i < size; i++) {
5746     const GValue *cur = VALUE_LIST_GET_VALUE (subtrahend, i);
5747
5748     if (gst_value_subtract (subtraction, result, cur)) {
5749       GValue *temp = result;
5750
5751       result = subtraction;
5752       subtraction = temp;
5753       g_value_unset (subtraction);
5754     } else {
5755       g_value_unset (result);
5756       return FALSE;
5757     }
5758   }
5759   if (dest) {
5760     gst_value_move (dest, result);
5761   } else {
5762     g_value_unset (result);
5763   }
5764   return TRUE;
5765 }
5766
5767 static gboolean
5768 gst_value_subtract_fraction_fraction_range (GValue * dest,
5769     const GValue * minuend, const GValue * subtrahend)
5770 {
5771   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
5772   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
5773
5774   /* subtracting a range from an fraction only works if the fraction
5775    * is not in the range */
5776   if (gst_value_compare_fraction (minuend, min) == GST_VALUE_LESS_THAN ||
5777       gst_value_compare_fraction (minuend, max) == GST_VALUE_GREATER_THAN) {
5778     /* and the result is the value */
5779     if (dest)
5780       gst_value_init_and_copy (dest, minuend);
5781     return TRUE;
5782   }
5783
5784   return FALSE;
5785 }
5786
5787 static gboolean
5788 gst_value_subtract_fraction_range_fraction (GValue * dest,
5789     const GValue * minuend, const GValue * subtrahend)
5790 {
5791   /* since we don't have open ranges, we cannot create a hole in
5792    * a range. We return the original range */
5793   if (dest)
5794     gst_value_init_and_copy (dest, minuend);
5795   return TRUE;
5796 }
5797
5798 static gboolean
5799 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
5800     const GValue * minuend, const GValue * subtrahend)
5801 {
5802   /* since we don't have open ranges, we have to approximate */
5803   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
5804   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
5805   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
5806   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
5807   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
5808   gint cmp1, cmp2;
5809   GValue v1 = { 0, };
5810   GValue v2 = { 0, };
5811   GValue *pv1, *pv2;            /* yeah, hungarian! */
5812
5813   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
5814   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
5815
5816   cmp1 = gst_value_compare_fraction (max2, max1);
5817   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
5818   if (cmp1 == GST_VALUE_LESS_THAN)
5819     max1 = max2;
5820   cmp1 = gst_value_compare_fraction (min1, min2);
5821   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
5822   if (cmp1 == GST_VALUE_GREATER_THAN)
5823     min2 = min1;
5824
5825   cmp1 = gst_value_compare_fraction (min1, max1);
5826   cmp2 = gst_value_compare_fraction (min2, max2);
5827
5828   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
5829     pv1 = &v1;
5830     pv2 = &v2;
5831   } else if (cmp1 == GST_VALUE_LESS_THAN) {
5832     pv1 = dest;
5833     pv2 = NULL;
5834   } else if (cmp2 == GST_VALUE_LESS_THAN) {
5835     pv1 = NULL;
5836     pv2 = dest;
5837   } else {
5838     return FALSE;
5839   }
5840
5841   if (!dest)
5842     return TRUE;
5843
5844   if (cmp1 == GST_VALUE_LESS_THAN) {
5845     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
5846     gst_value_set_fraction_range (pv1, min1, max1);
5847   }
5848   if (cmp2 == GST_VALUE_LESS_THAN) {
5849     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
5850     gst_value_set_fraction_range (pv2, min2, max2);
5851   }
5852
5853   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
5854     gst_value_list_concat_and_take_values (dest, pv1, pv2);
5855   }
5856   return TRUE;
5857 }
5858
5859 /**************
5860  * comparison *
5861  **************/
5862
5863 /*
5864  * gst_value_get_compare_func:
5865  * @value1: a value to get the compare function for
5866  *
5867  * Determines the compare function to be used with values of the same type as
5868  * @value1. The function can be given to gst_value_compare_with_func().
5869  *
5870  * Returns: A #GstValueCompareFunc value
5871  */
5872 static GstValueCompareFunc
5873 gst_value_get_compare_func (const GValue * value1)
5874 {
5875   GstValueTable *table, *best = NULL;
5876   guint i;
5877   GType type1;
5878
5879   type1 = G_VALUE_TYPE (value1);
5880
5881   /* this is a fast check */
5882   best = gst_value_hash_lookup_type (type1);
5883
5884   /* slower checks */
5885   if (G_UNLIKELY (!best || !best->compare)) {
5886     guint len = gst_value_table->len;
5887
5888     best = NULL;
5889     for (i = 0; i < len; i++) {
5890       table = &g_array_index (gst_value_table, GstValueTable, i);
5891       if (table->compare && g_type_is_a (type1, table->type)) {
5892         if (!best || g_type_is_a (table->type, best->type))
5893           best = table;
5894       }
5895     }
5896   }
5897   if (G_LIKELY (best))
5898     return best->compare;
5899
5900   return NULL;
5901 }
5902
5903 static inline gboolean
5904 gst_value_can_compare_unchecked (const GValue * value1, const GValue * value2)
5905 {
5906   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
5907     return FALSE;
5908
5909   return gst_value_get_compare_func (value1) != NULL;
5910 }
5911
5912 /**
5913  * gst_value_can_compare:
5914  * @value1: a value to compare
5915  * @value2: another value to compare
5916  *
5917  * Determines if @value1 and @value2 can be compared.
5918  *
5919  * Returns: %TRUE if the values can be compared
5920  */
5921 gboolean
5922 gst_value_can_compare (const GValue * value1, const GValue * value2)
5923 {
5924   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
5925   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
5926
5927   return gst_value_can_compare_unchecked (value1, value2);
5928 }
5929
5930 static gboolean
5931 gst_value_list_equals_range (const GValue * list, const GValue * value)
5932 {
5933   const GValue *first;
5934   guint list_size, n;
5935
5936   /* TODO: compare against an empty list ? No type though... */
5937   list_size = VALUE_LIST_SIZE (list);
5938   if (list_size == 0)
5939     return FALSE;
5940
5941   /* compare the basic types - they have to match */
5942   first = VALUE_LIST_GET_VALUE (list, 0);
5943 #define CHECK_TYPES(type,prefix) \
5944   ((first) && G_VALUE_TYPE(first) == prefix##_TYPE_##type && GST_VALUE_HOLDS_##type##_RANGE (value))
5945   if (CHECK_TYPES (INT, G)) {
5946     const gint rmin = gst_value_get_int_range_min (value);
5947     const gint rmax = gst_value_get_int_range_max (value);
5948     const gint rstep = gst_value_get_int_range_step (value);
5949     if (rstep == 0)
5950       return FALSE;
5951     /* note: this will overflow for min 0 and max INT_MAX, but this
5952        would only be equal to a list of INT_MAX elements, which seems
5953        very unlikely */
5954     if (list_size != rmax / rstep - rmin / rstep + 1)
5955       return FALSE;
5956     for (n = 0; n < list_size; ++n) {
5957       gint v = g_value_get_int (VALUE_LIST_GET_VALUE (list, n));
5958       if (v < rmin || v > rmax || v % rstep) {
5959         return FALSE;
5960       }
5961     }
5962     return TRUE;
5963   } else if (CHECK_TYPES (INT64, G)) {
5964     const gint64 rmin = gst_value_get_int64_range_min (value);
5965     const gint64 rmax = gst_value_get_int64_range_max (value);
5966     const gint64 rstep = gst_value_get_int64_range_step (value);
5967     GST_DEBUG ("List/range of int64s");
5968     if (rstep == 0)
5969       return FALSE;
5970     if (list_size != rmax / rstep - rmin / rstep + 1)
5971       return FALSE;
5972     for (n = 0; n < list_size; ++n) {
5973       gint64 v = g_value_get_int64 (VALUE_LIST_GET_VALUE (list, n));
5974       if (v < rmin || v > rmax || v % rstep)
5975         return FALSE;
5976     }
5977     return TRUE;
5978   }
5979 #undef CHECK_TYPES
5980
5981   /* other combinations don't make sense for equality */
5982   return FALSE;
5983 }
5984
5985 /* "Pure" variant of gst_value_compare which is guaranteed to
5986  * not have list arguments and therefore does basic comparisons
5987  */
5988 static inline gint
5989 _gst_value_compare_nolist (const GValue * value1, const GValue * value2)
5990 {
5991   GstValueCompareFunc compare;
5992
5993   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
5994     return GST_VALUE_UNORDERED;
5995
5996   compare = gst_value_get_compare_func (value1);
5997   if (compare) {
5998     return compare (value1, value2);
5999   }
6000
6001   g_critical ("unable to compare values of type %s\n",
6002       g_type_name (G_VALUE_TYPE (value1)));
6003   return GST_VALUE_UNORDERED;
6004 }
6005
6006 /**
6007  * gst_value_compare:
6008  * @value1: a value to compare
6009  * @value2: another value to compare
6010  *
6011  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
6012  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
6013  * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned.
6014  * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned.
6015  * If the values are equal, GST_VALUE_EQUAL is returned.
6016  *
6017  * Returns: comparison result
6018  */
6019 gint
6020 gst_value_compare (const GValue * value1, const GValue * value2)
6021 {
6022   gboolean value1_is_list;
6023   gboolean value2_is_list;
6024
6025   g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN);
6026   g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN);
6027
6028   value1_is_list = G_VALUE_TYPE (value1) == GST_TYPE_LIST;
6029   value2_is_list = G_VALUE_TYPE (value2) == GST_TYPE_LIST;
6030
6031   /* Special cases: lists and scalar values ("{ 1 }" and "1" are equal),
6032      as well as lists and ranges ("{ 1, 2 }" and "[ 1, 2 ]" are equal) */
6033   if (value1_is_list && !value2_is_list) {
6034     gint i, n, ret;
6035
6036     if (gst_value_list_equals_range (value1, value2)) {
6037       return GST_VALUE_EQUAL;
6038     }
6039
6040     n = gst_value_list_get_size (value1);
6041     if (n == 0)
6042       return GST_VALUE_UNORDERED;
6043
6044     for (i = 0; i < n; i++) {
6045       const GValue *elt;
6046
6047       elt = gst_value_list_get_value (value1, i);
6048       ret = gst_value_compare (elt, value2);
6049       if (ret != GST_VALUE_EQUAL && n == 1)
6050         return ret;
6051       else if (ret != GST_VALUE_EQUAL)
6052         return GST_VALUE_UNORDERED;
6053     }
6054
6055     return GST_VALUE_EQUAL;
6056   } else if (value2_is_list && !value1_is_list) {
6057     gint i, n, ret;
6058
6059     if (gst_value_list_equals_range (value2, value1)) {
6060       return GST_VALUE_EQUAL;
6061     }
6062
6063     n = gst_value_list_get_size (value2);
6064     if (n == 0)
6065       return GST_VALUE_UNORDERED;
6066
6067     for (i = 0; i < n; i++) {
6068       const GValue *elt;
6069
6070       elt = gst_value_list_get_value (value2, i);
6071       ret = gst_value_compare (elt, value1);
6072       if (ret != GST_VALUE_EQUAL && n == 1)
6073         return ret;
6074       else if (ret != GST_VALUE_EQUAL)
6075         return GST_VALUE_UNORDERED;
6076     }
6077
6078     return GST_VALUE_EQUAL;
6079   }
6080
6081   /* And now handle the generic case */
6082   return _gst_value_compare_nolist (value1, value2);
6083 }
6084
6085 /* union */
6086
6087 /**
6088  * gst_value_can_union:
6089  * @value1: a value to union
6090  * @value2: another value to union
6091  *
6092  * Determines if @value1 and @value2 can be non-trivially unioned.
6093  * Any two values can be trivially unioned by adding both of them
6094  * to a GstValueList.  However, certain types have the possibility
6095  * to be unioned in a simpler way.  For example, an integer range
6096  * and an integer can be unioned if the integer is a subset of the
6097  * integer range.  If there is the possibility that two values can
6098  * be unioned, this function returns %TRUE.
6099  *
6100  * Returns: %TRUE if there is a function allowing the two values to
6101  * be unioned.
6102  */
6103 gboolean
6104 gst_value_can_union (const GValue * value1, const GValue * value2)
6105 {
6106   GstValueUnionInfo *union_info;
6107   guint i, len;
6108
6109   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
6110   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
6111
6112   len = gst_value_union_funcs->len;
6113
6114   for (i = 0; i < len; i++) {
6115     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
6116     if (union_info->type1 == G_VALUE_TYPE (value1) &&
6117         union_info->type2 == G_VALUE_TYPE (value2))
6118       return TRUE;
6119     if (union_info->type1 == G_VALUE_TYPE (value2) &&
6120         union_info->type2 == G_VALUE_TYPE (value1))
6121       return TRUE;
6122   }
6123
6124   return FALSE;
6125 }
6126
6127 /**
6128  * gst_value_union:
6129  * @dest: (out caller-allocates): the destination value
6130  * @value1: a value to union
6131  * @value2: another value to union
6132  *
6133  * Creates a GValue corresponding to the union of @value1 and @value2.
6134  *
6135  * Returns: %TRUE if the union succeeded.
6136  */
6137 gboolean
6138 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
6139 {
6140   const GstValueUnionInfo *union_info;
6141   guint i, len;
6142   GType type1, type2;
6143
6144   g_return_val_if_fail (dest != NULL, FALSE);
6145   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
6146   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
6147   g_return_val_if_fail (gst_value_list_or_array_are_compatible (value1, value2),
6148       FALSE);
6149
6150   len = gst_value_union_funcs->len;
6151   type1 = G_VALUE_TYPE (value1);
6152   type2 = G_VALUE_TYPE (value2);
6153
6154   for (i = 0; i < len; i++) {
6155     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
6156     if (union_info->type1 == type1 && union_info->type2 == type2) {
6157       return union_info->func (dest, value1, value2);
6158     }
6159     if (union_info->type1 == type2 && union_info->type2 == type1) {
6160       return union_info->func (dest, value2, value1);
6161     }
6162   }
6163
6164   gst_value_list_concat (dest, value1, value2);
6165   return TRUE;
6166 }
6167
6168 /* gst_value_register_union_func: (skip)
6169  * @type1: a type to union
6170  * @type2: another type to union
6171  * @func: a function that implements creating a union between the two types
6172  *
6173  * Registers a union function that can create a union between #GValue items
6174  * of the type @type1 and @type2.
6175  *
6176  * Union functions should be registered at startup before any pipelines are
6177  * started, as gst_value_register_union_func() is not thread-safe and cannot
6178  * be used at the same time as gst_value_union() or gst_value_can_union().
6179  */
6180 static void
6181 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
6182 {
6183   GstValueUnionInfo union_info;
6184
6185   union_info.type1 = type1;
6186   union_info.type2 = type2;
6187   union_info.func = func;
6188
6189   g_array_append_val (gst_value_union_funcs, union_info);
6190 }
6191
6192 /* intersection */
6193
6194 /**
6195  * gst_value_can_intersect:
6196  * @value1: a value to intersect
6197  * @value2: another value to intersect
6198  *
6199  * Determines if intersecting two values will produce a valid result.
6200  * Two values will produce a valid intersection if they have the same
6201  * type.
6202  *
6203  * Returns: %TRUE if the values can intersect
6204  */
6205 gboolean
6206 gst_value_can_intersect (const GValue * value1, const GValue * value2)
6207 {
6208   GstValueIntersectInfo *intersect_info;
6209   guint i, len;
6210   GType type1, type2;
6211
6212   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
6213   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
6214
6215   type1 = G_VALUE_TYPE (value1);
6216   type2 = G_VALUE_TYPE (value2);
6217
6218   /* practically all GstValue types have a compare function (_can_compare=TRUE)
6219    * GstStructure and GstCaps have not, but are intersectable */
6220   if (type1 == type2)
6221     return TRUE;
6222
6223   /* special cases */
6224   if (type1 == GST_TYPE_LIST || type2 == GST_TYPE_LIST)
6225     return TRUE;
6226
6227   if (G_UNLIKELY (GST_VALUE_HOLDS_FLAG_SET (value1) &&
6228           GST_VALUE_HOLDS_FLAG_SET (value2))) {
6229     GType flagset_type;
6230
6231     flagset_type = GST_TYPE_FLAG_SET;
6232
6233     /* Allow intersection with the generic FlagSet type, on one
6234      * side, but not 2 different subtypes - that makes no sense */
6235     if (type1 == flagset_type || type2 == flagset_type)
6236       return TRUE;
6237   }
6238
6239   /* check registered intersect functions (only different gtype are checked at
6240    * this point) */
6241   len = gst_value_intersect_funcs->len;
6242   for (i = 0; i < len; i++) {
6243     intersect_info = &g_array_index (gst_value_intersect_funcs,
6244         GstValueIntersectInfo, i);
6245     if ((intersect_info->type1 == type1 && intersect_info->type2 == type2) ||
6246         (intersect_info->type1 == type2 && intersect_info->type2 == type1))
6247       return TRUE;
6248   }
6249
6250   return gst_value_can_compare_unchecked (value1, value2);
6251 }
6252
6253 /**
6254  * gst_value_intersect:
6255  * @dest: (out caller-allocates) (transfer full) (allow-none):
6256  *   a uninitialized #GValue that will hold the calculated
6257  *   intersection value. May be %NULL if the resulting set if not
6258  *   needed.
6259  * @value1: a value to intersect
6260  * @value2: another value to intersect
6261  *
6262  * Calculates the intersection of two values.  If the values have
6263  * a non-empty intersection, the value representing the intersection
6264  * is placed in @dest, unless %NULL.  If the intersection is non-empty,
6265  * @dest is not modified.
6266  *
6267  * Returns: %TRUE if the intersection is non-empty
6268  */
6269 gboolean
6270 gst_value_intersect (GValue * dest, const GValue * value1,
6271     const GValue * value2)
6272 {
6273   GstValueIntersectInfo *intersect_info;
6274   guint i, len;
6275   GType type1, type2;
6276
6277   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
6278   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
6279
6280   type1 = G_VALUE_TYPE (value1);
6281   type2 = G_VALUE_TYPE (value2);
6282
6283   /* special cases first */
6284   if (type1 == GST_TYPE_LIST)
6285     return gst_value_intersect_list (dest, value1, value2);
6286   if (type2 == GST_TYPE_LIST)
6287     return gst_value_intersect_list (dest, value2, value1);
6288
6289   if (_gst_value_compare_nolist (value1, value2) == GST_VALUE_EQUAL) {
6290     if (dest)
6291       gst_value_init_and_copy (dest, value1);
6292     return TRUE;
6293   }
6294
6295   if (type1 == type2) {
6296     /* Equal type comparison */
6297     if (type1 == GST_TYPE_INT_RANGE)
6298       return gst_value_intersect_int_range_int_range (dest, value1, value2);
6299     if (type1 == GST_TYPE_INT64_RANGE)
6300       return gst_value_intersect_int64_range_int64_range (dest, value1, value2);
6301     if (type1 == GST_TYPE_DOUBLE_RANGE)
6302       return gst_value_intersect_double_range_double_range (dest, value1,
6303           value2);
6304     if (type1 == GST_TYPE_ARRAY)
6305       return gst_value_intersect_array (dest, value1, value2);
6306     if (type1 == GST_TYPE_FRACTION_RANGE)
6307       return gst_value_intersect_fraction_range_fraction_range (dest, value1,
6308           value2);
6309     if (type1 == GST_TYPE_FLAG_SET)
6310       return gst_value_intersect_flagset_flagset (dest, value1, value2);
6311     if (type1 == GST_TYPE_STRUCTURE)
6312       return gst_value_intersect_structure_structure (dest, value1, value2);
6313   } else {
6314     /* Different type comparison */
6315     len = gst_value_intersect_funcs->len;
6316     for (i = 0; i < len; i++) {
6317       intersect_info = &g_array_index (gst_value_intersect_funcs,
6318           GstValueIntersectInfo, i);
6319       if (intersect_info->type1 == type1 && intersect_info->type2 == type2) {
6320         return intersect_info->func (dest, value1, value2);
6321       }
6322       if (intersect_info->type1 == type2 && intersect_info->type2 == type1) {
6323         return intersect_info->func (dest, value2, value1);
6324       }
6325     }
6326   }
6327
6328   /* Failed to find a direct intersection, check if these are
6329    * GstFlagSet sub-types. */
6330   if (G_UNLIKELY (GST_VALUE_HOLDS_FLAG_SET (value1) &&
6331           GST_VALUE_HOLDS_FLAG_SET (value2))) {
6332     return gst_value_intersect_flagset_flagset (dest, value1, value2);
6333   }
6334
6335   return FALSE;
6336 }
6337
6338
6339
6340 /* gst_value_register_intersect_func: (skip)
6341  * @type1: the first type to intersect
6342  * @type2: the second type to intersect
6343  * @func: the intersection function
6344  *
6345  * Registers a function that is called to calculate the intersection
6346  * of the values having the types @type1 and @type2.
6347  *
6348  * Intersect functions should be registered at startup before any pipelines are
6349  * started, as gst_value_register_intersect_func() is not thread-safe and
6350  * cannot be used at the same time as gst_value_intersect() or
6351  * gst_value_can_intersect().
6352  */
6353 static void
6354 gst_value_register_intersect_func (GType type1, GType type2,
6355     GstValueIntersectFunc func)
6356 {
6357   GstValueIntersectInfo intersect_info;
6358
6359   intersect_info.type1 = type1;
6360   intersect_info.type2 = type2;
6361   intersect_info.func = func;
6362
6363   g_array_append_val (gst_value_intersect_funcs, intersect_info);
6364 }
6365
6366
6367 /* subtraction */
6368
6369 /**
6370  * gst_value_subtract:
6371  * @dest: (out caller-allocates) (allow-none): the destination value
6372  *     for the result if the subtraction is not empty. May be %NULL,
6373  *     in which case the resulting set will not be computed, which can
6374  *     give a fair speedup.
6375  * @minuend: the value to subtract from
6376  * @subtrahend: the value to subtract
6377  *
6378  * Subtracts @subtrahend from @minuend and stores the result in @dest.
6379  * Note that this means subtraction as in sets, not as in mathematics.
6380  *
6381  * Returns: %TRUE if the subtraction is not empty
6382  */
6383 gboolean
6384 gst_value_subtract (GValue * dest, const GValue * minuend,
6385     const GValue * subtrahend)
6386 {
6387   GstValueSubtractInfo *info;
6388   guint i, len;
6389   GType mtype, stype;
6390
6391   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
6392   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
6393
6394   mtype = G_VALUE_TYPE (minuend);
6395   stype = G_VALUE_TYPE (subtrahend);
6396
6397   /* special cases first */
6398   if (mtype == GST_TYPE_LIST)
6399     return gst_value_subtract_from_list (dest, minuend, subtrahend);
6400   if (stype == GST_TYPE_LIST)
6401     return gst_value_subtract_list (dest, minuend, subtrahend);
6402
6403   len = gst_value_subtract_funcs->len;
6404   for (i = 0; i < len; i++) {
6405     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
6406     if (info->minuend == mtype && info->subtrahend == stype) {
6407       return info->func (dest, minuend, subtrahend);
6408     }
6409   }
6410
6411   if (_gst_value_compare_nolist (minuend, subtrahend) != GST_VALUE_EQUAL) {
6412     if (dest)
6413       gst_value_init_and_copy (dest, minuend);
6414     return TRUE;
6415   }
6416
6417   return FALSE;
6418 }
6419
6420 #if 0
6421 gboolean
6422 gst_value_subtract (GValue * dest, const GValue * minuend,
6423     const GValue * subtrahend)
6424 {
6425   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
6426
6427   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
6428       gst_value_serialize (subtrahend),
6429       ret ? gst_value_serialize (dest) : "---");
6430   return ret;
6431 }
6432 #endif
6433
6434 /**
6435  * gst_value_can_subtract:
6436  * @minuend: the value to subtract from
6437  * @subtrahend: the value to subtract
6438  *
6439  * Checks if it's possible to subtract @subtrahend from @minuend.
6440  *
6441  * Returns: %TRUE if a subtraction is possible
6442  */
6443 gboolean
6444 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
6445 {
6446   GstValueSubtractInfo *info;
6447   guint i, len;
6448   GType mtype, stype;
6449
6450   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
6451   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
6452
6453   mtype = G_VALUE_TYPE (minuend);
6454   stype = G_VALUE_TYPE (subtrahend);
6455
6456   /* special cases */
6457   if (mtype == GST_TYPE_LIST || stype == GST_TYPE_LIST)
6458     return TRUE;
6459   if (mtype == GST_TYPE_STRUCTURE || stype == GST_TYPE_STRUCTURE)
6460     return FALSE;
6461
6462   len = gst_value_subtract_funcs->len;
6463   for (i = 0; i < len; i++) {
6464     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
6465     if (info->minuend == mtype && info->subtrahend == stype)
6466       return TRUE;
6467   }
6468
6469   return gst_value_can_compare_unchecked (minuend, subtrahend);
6470 }
6471
6472 /* gst_value_register_subtract_func: (skip)
6473  * @minuend_type: type of the minuend
6474  * @subtrahend_type: type of the subtrahend
6475  * @func: function to use
6476  *
6477  * Registers @func as a function capable of subtracting the values of
6478  * @subtrahend_type from values of @minuend_type.
6479  *
6480  * Subtract functions should be registered at startup before any pipelines are
6481  * started, as gst_value_register_subtract_func() is not thread-safe and
6482  * cannot be used at the same time as gst_value_subtract().
6483  */
6484 static void
6485 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
6486     GstValueSubtractFunc func)
6487 {
6488   GstValueSubtractInfo info;
6489
6490   g_return_if_fail (!gst_type_is_fixed (minuend_type)
6491       || !gst_type_is_fixed (subtrahend_type));
6492
6493   info.minuend = minuend_type;
6494   info.subtrahend = subtrahend_type;
6495   info.func = func;
6496
6497   g_array_append_val (gst_value_subtract_funcs, info);
6498 }
6499
6500 /**
6501  * gst_value_register:
6502  * @table: structure containing functions to register
6503  *
6504  * Registers functions to perform calculations on #GValue items of a given
6505  * type. Each type can only be added once.
6506  */
6507 void
6508 gst_value_register (const GstValueTable * table)
6509 {
6510   GstValueTable *found;
6511
6512   g_return_if_fail (table != NULL);
6513
6514   g_array_append_val (gst_value_table, *table);
6515
6516   found = gst_value_hash_lookup_type (table->type);
6517   if (found)
6518     g_warning ("adding type %s multiple times", g_type_name (table->type));
6519
6520   /* FIXME: we're not really doing the const justice, we assume the table is
6521    * static */
6522   gst_value_hash_add_type (table->type, table);
6523 }
6524
6525 /**
6526  * gst_value_init_and_copy:
6527  * @dest: (out caller-allocates): the target value
6528  * @src: the source value
6529  *
6530  * Initialises the target value to be of the same type as source and then copies
6531  * the contents from source to target.
6532  */
6533 void
6534 gst_value_init_and_copy (GValue * dest, const GValue * src)
6535 {
6536   GType type;
6537
6538   g_return_if_fail (G_IS_VALUE (src));
6539   g_return_if_fail (dest != NULL);
6540
6541   type = G_VALUE_TYPE (src);
6542   /* We need to shortcut GstValueList/GstValueArray copying because:
6543    * * g_value_init would end up allocating something
6544    * * which g_value_copy would then free and re-alloc.
6545    *
6546    * Instead directly call the copy */
6547   if (type == GST_TYPE_LIST || type == GST_TYPE_ARRAY) {
6548     dest->g_type = type;
6549     gst_value_copy_list_or_array (src, dest);
6550     return;
6551   }
6552
6553   g_value_init (dest, type);
6554   g_value_copy (src, dest);
6555 }
6556
6557 /* move src into dest and clear src */
6558 static void
6559 gst_value_move (GValue * dest, GValue * src)
6560 {
6561   g_assert (G_IS_VALUE (src));
6562   g_assert (dest != NULL);
6563
6564   *dest = *src;
6565   memset (src, 0, sizeof (GValue));
6566 }
6567
6568 /**
6569  * gst_value_serialize:
6570  * @value: a #GValue to serialize
6571  *
6572  * tries to transform the given @value into a string representation that allows
6573  * getting back this string later on using gst_value_deserialize().
6574  *
6575  * Free-function: g_free
6576  *
6577  * Returns: (transfer full) (nullable): the serialization for @value
6578  * or %NULL if none exists
6579  */
6580 gchar *
6581 gst_value_serialize (const GValue * value)
6582 {
6583   guint i, len;
6584   GValue s_val = { 0 };
6585   GstValueTable *table, *best;
6586   gchar *s;
6587   GType type;
6588
6589   g_return_val_if_fail (G_IS_VALUE (value), NULL);
6590
6591   type = G_VALUE_TYPE (value);
6592
6593   best = gst_value_hash_lookup_type (type);
6594
6595   if (G_UNLIKELY (!best || !best->serialize)) {
6596     len = gst_value_table->len;
6597     best = NULL;
6598     for (i = 0; i < len; i++) {
6599       table = &g_array_index (gst_value_table, GstValueTable, i);
6600       if (table->serialize && g_type_is_a (type, table->type)) {
6601         if (!best || g_type_is_a (table->type, best->type))
6602           best = table;
6603       }
6604     }
6605   }
6606   if (G_LIKELY (best))
6607     return best->serialize (value);
6608
6609   g_value_init (&s_val, G_TYPE_STRING);
6610   if (g_value_transform (value, &s_val)) {
6611     s = gst_string_wrap (g_value_get_string (&s_val));
6612   } else {
6613     s = NULL;
6614   }
6615   g_value_unset (&s_val);
6616
6617   return s;
6618 }
6619
6620 /**
6621  * gst_value_deserialize:
6622  * @dest: (out caller-allocates): #GValue to fill with contents of
6623  *     deserialization
6624  * @src: string to deserialize
6625  *
6626  * Tries to deserialize a string into the type specified by the given GValue.
6627  * If the operation succeeds, %TRUE is returned, %FALSE otherwise.
6628  *
6629  * Returns: %TRUE on success
6630  */
6631 gboolean
6632 gst_value_deserialize (GValue * dest, const gchar * src)
6633 {
6634   GstValueTable *table, *best;
6635   guint i, len;
6636   GType type;
6637
6638   g_return_val_if_fail (src != NULL, FALSE);
6639   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
6640
6641   type = G_VALUE_TYPE (dest);
6642
6643   best = gst_value_hash_lookup_type (type);
6644   if (G_UNLIKELY (!best || (!best->deserialize
6645               && !best->deserialize_with_pspec))) {
6646     len = gst_value_table->len;
6647     best = NULL;
6648     for (i = 0; i < len; i++) {
6649       table = &g_array_index (gst_value_table, GstValueTable, i);
6650       if ((table->deserialize || table->deserialize_with_pspec) &&
6651           g_type_is_a (type, table->type)) {
6652         if (!best || g_type_is_a (table->type, best->type))
6653           best = table;
6654       }
6655     }
6656   }
6657   if (G_LIKELY (best)) {
6658     if (best->deserialize_with_pspec)
6659       return best->deserialize_with_pspec (dest, src, NULL);
6660     else
6661       return best->deserialize (dest, src);
6662   }
6663
6664   return FALSE;
6665 }
6666
6667 /**
6668  * gst_value_deserialize_with_pspec:
6669  * @dest: (out caller-allocates): #GValue to fill with contents of
6670  *     deserialization
6671  * @src: string to deserialize
6672  * @pspec: (nullable): the #GParamSpec describing the expected value
6673  *
6674  * Tries to deserialize a string into the type specified by the given GValue.
6675  * @pspec may be used to guide the deserializing of nested members.
6676  * If the operation succeeds, %TRUE is returned, %FALSE otherwise.
6677  *
6678  * Returns: %TRUE on success
6679  * Since: 1.20
6680  */
6681 gboolean
6682 gst_value_deserialize_with_pspec (GValue * dest, const gchar * src,
6683     GParamSpec * pspec)
6684 {
6685   GstValueTable *table, *best;
6686   guint i, len;
6687   GType type;
6688
6689   g_return_val_if_fail (src != NULL, FALSE);
6690   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
6691
6692   if (pspec)
6693     g_return_val_if_fail (G_VALUE_TYPE (dest) ==
6694         G_PARAM_SPEC_VALUE_TYPE (pspec), FALSE);
6695
6696   type = G_VALUE_TYPE (dest);
6697
6698   best = gst_value_hash_lookup_type (type);
6699   if (G_UNLIKELY (!best || (!best->deserialize
6700               && !best->deserialize_with_pspec))) {
6701     len = gst_value_table->len;
6702     best = NULL;
6703     for (i = 0; i < len; i++) {
6704       table = &g_array_index (gst_value_table, GstValueTable, i);
6705       if ((table->deserialize || table->deserialize_with_pspec) &&
6706           g_type_is_a (type, table->type)) {
6707         if (!best || g_type_is_a (table->type, best->type))
6708           best = table;
6709       }
6710     }
6711   }
6712   if (G_LIKELY (best)) {
6713     if (best->deserialize_with_pspec)
6714       return best->deserialize_with_pspec (dest, src, pspec);
6715     else
6716       return best->deserialize (dest, src);
6717   }
6718
6719   return FALSE;
6720 }
6721
6722 static gboolean
6723 structure_field_is_fixed (GQuark field_id, const GValue * val,
6724     gpointer user_data)
6725 {
6726   return gst_value_is_fixed (val);
6727 }
6728
6729 /**
6730  * gst_value_is_fixed:
6731  * @value: the #GValue to check
6732  *
6733  * Tests if the given GValue, if available in a GstStructure (or any other
6734  * container) contains a "fixed" (which means: one value) or an "unfixed"
6735  * (which means: multiple possible values, such as data lists or data
6736  * ranges) value.
6737  *
6738  * Returns: true if the value is "fixed".
6739  */
6740
6741 gboolean
6742 gst_value_is_fixed (const GValue * value)
6743 {
6744   GType type;
6745
6746   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
6747
6748   type = G_VALUE_TYPE (value);
6749
6750   /* the most common types are just basic plain glib types */
6751   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
6752     return TRUE;
6753   }
6754
6755   if (type == GST_TYPE_ARRAY) {
6756     gint size, n;
6757     const GValue *kid;
6758
6759     /* check recursively */
6760     size = gst_value_array_get_size (value);
6761     for (n = 0; n < size; n++) {
6762       kid = gst_value_array_get_value (value, n);
6763       if (!gst_value_is_fixed (kid))
6764         return FALSE;
6765     }
6766     return TRUE;
6767   } else if (GST_VALUE_HOLDS_FLAG_SET (value)) {
6768     /* Flagsets are only fixed if there are no 'don't care' bits */
6769     return (gst_value_get_flagset_mask (value) == GST_FLAG_SET_MASK_EXACT);
6770   } else if (GST_VALUE_HOLDS_STRUCTURE (value)) {
6771     return gst_structure_foreach (gst_value_get_structure (value),
6772         structure_field_is_fixed, NULL);
6773   }
6774   return gst_type_is_fixed (type);
6775 }
6776
6777 /**
6778  * gst_value_fixate:
6779  * @dest: the #GValue destination
6780  * @src: the #GValue to fixate
6781  *
6782  * Fixate @src into a new value @dest.
6783  * For ranges, the first element is taken. For lists and arrays, the
6784  * first item is fixated and returned.
6785  * If @src is already fixed, this function returns %FALSE.
6786  *
6787  * Returns: %TRUE if @dest contains a fixated version of @src.
6788  */
6789 gboolean
6790 gst_value_fixate (GValue * dest, const GValue * src)
6791 {
6792   g_return_val_if_fail (G_IS_VALUE (src), FALSE);
6793   g_return_val_if_fail (dest != NULL, FALSE);
6794
6795   if (G_VALUE_TYPE (src) == GST_TYPE_INT_RANGE) {
6796     g_value_init (dest, G_TYPE_INT);
6797     g_value_set_int (dest, gst_value_get_int_range_min (src));
6798   } else if (G_VALUE_TYPE (src) == GST_TYPE_DOUBLE_RANGE) {
6799     g_value_init (dest, G_TYPE_DOUBLE);
6800     g_value_set_double (dest, gst_value_get_double_range_min (src));
6801   } else if (G_VALUE_TYPE (src) == GST_TYPE_FRACTION_RANGE) {
6802     gst_value_init_and_copy (dest, gst_value_get_fraction_range_min (src));
6803   } else if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
6804     GValue temp = { 0 };
6805
6806     /* list could be empty */
6807     if (gst_value_list_get_size (src) <= 0)
6808       return FALSE;
6809
6810     gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0));
6811
6812     if (!gst_value_fixate (dest, &temp)) {
6813       gst_value_move (dest, &temp);
6814     } else {
6815       g_value_unset (&temp);
6816     }
6817   } else if (G_VALUE_TYPE (src) == GST_TYPE_ARRAY) {
6818     gboolean res = FALSE;
6819     guint n, len;
6820
6821     len = gst_value_array_get_size (src);
6822     g_value_init (dest, GST_TYPE_ARRAY);
6823     for (n = 0; n < len; n++) {
6824       GValue kid = { 0 };
6825       const GValue *orig_kid = gst_value_array_get_value (src, n);
6826
6827       if (!gst_value_fixate (&kid, orig_kid))
6828         gst_value_init_and_copy (&kid, orig_kid);
6829       else
6830         res = TRUE;
6831       _gst_value_array_append_and_take_value (dest, &kid);
6832     }
6833
6834     if (!res)
6835       g_value_unset (dest);
6836
6837     return res;
6838   } else if (GST_VALUE_HOLDS_FLAG_SET (src)) {
6839     guint flags;
6840
6841     if (gst_value_get_flagset_mask (src) == GST_FLAG_SET_MASK_EXACT)
6842       return FALSE;             /* Already fixed */
6843
6844     flags = gst_value_get_flagset_flags (src);
6845     g_value_init (dest, G_VALUE_TYPE (src));
6846     gst_value_set_flagset (dest, flags, GST_FLAG_SET_MASK_EXACT);
6847     return TRUE;
6848   } else if (GST_VALUE_HOLDS_STRUCTURE (src)) {
6849     const GstStructure *str = (GstStructure *) gst_value_get_structure (src);
6850     GstStructure *kid;
6851
6852     if (!str)
6853       return FALSE;
6854
6855     kid = gst_structure_copy (str);
6856     gst_structure_fixate (kid);
6857     g_value_init (dest, GST_TYPE_STRUCTURE);
6858     gst_value_set_structure (dest, kid);
6859     gst_structure_free (kid);
6860     return TRUE;
6861   } else {
6862     return FALSE;
6863   }
6864   return TRUE;
6865 }
6866
6867
6868 /************
6869  * fraction *
6870  ************/
6871
6872 /* helper functions */
6873 static void
6874 gst_value_init_fraction (GValue * value)
6875 {
6876   value->data[0].v_int = 0;
6877   value->data[1].v_int = 1;
6878 }
6879
6880 static void
6881 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
6882 {
6883   dest_value->data[0].v_int = src_value->data[0].v_int;
6884   dest_value->data[1].v_int = src_value->data[1].v_int;
6885 }
6886
6887 static gchar *
6888 gst_value_collect_fraction (GValue * value, guint n_collect_values,
6889     GTypeCValue * collect_values, guint collect_flags)
6890 {
6891   g_return_val_if_fail (n_collect_values == 2,
6892       g_strdup_printf ("not enough value locations for `%s' passed",
6893           G_VALUE_TYPE_NAME (value)));
6894   g_return_val_if_fail (collect_values[1].v_int != 0,
6895       g_strdup_printf ("passed '0' as denominator for `%s'",
6896           G_VALUE_TYPE_NAME (value)));
6897   g_return_val_if_fail (collect_values[0].v_int >= -G_MAXINT,
6898       g_strdup_printf
6899       ("passed value smaller than -G_MAXINT as numerator for `%s'",
6900           G_VALUE_TYPE_NAME (value)));
6901   g_return_val_if_fail (collect_values[1].v_int >= -G_MAXINT,
6902       g_strdup_printf
6903       ("passed value smaller than -G_MAXINT as denominator for `%s'",
6904           G_VALUE_TYPE_NAME (value)));
6905
6906   gst_value_set_fraction (value,
6907       collect_values[0].v_int, collect_values[1].v_int);
6908
6909   return NULL;
6910 }
6911
6912 static gchar *
6913 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
6914     GTypeCValue * collect_values, guint collect_flags)
6915 {
6916   gint *numerator = collect_values[0].v_pointer;
6917   gint *denominator = collect_values[1].v_pointer;
6918
6919   g_return_val_if_fail (numerator != NULL,
6920       g_strdup_printf ("numerator for `%s' passed as NULL",
6921           G_VALUE_TYPE_NAME (value)));
6922   g_return_val_if_fail (denominator != NULL,
6923       g_strdup_printf ("denominator for `%s' passed as NULL",
6924           G_VALUE_TYPE_NAME (value)));
6925
6926   *numerator = value->data[0].v_int;
6927   *denominator = value->data[1].v_int;
6928
6929   return NULL;
6930 }
6931
6932 /**
6933  * gst_value_set_fraction:
6934  * @value: a GValue initialized to #GST_TYPE_FRACTION
6935  * @numerator: the numerator of the fraction
6936  * @denominator: the denominator of the fraction
6937  *
6938  * Sets @value to the fraction specified by @numerator over @denominator.
6939  * The fraction gets reduced to the smallest numerator and denominator,
6940  * and if necessary the sign is moved to the numerator.
6941  */
6942 void
6943 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
6944 {
6945   gint gcd = 0;
6946
6947   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
6948   g_return_if_fail (denominator != 0);
6949   g_return_if_fail (denominator >= -G_MAXINT);
6950   g_return_if_fail (numerator >= -G_MAXINT);
6951
6952   /* normalize sign */
6953   if (denominator < 0) {
6954     numerator = -numerator;
6955     denominator = -denominator;
6956   }
6957
6958   /* check for reduction */
6959   gcd = gst_util_greatest_common_divisor (numerator, denominator);
6960   if (gcd) {
6961     numerator /= gcd;
6962     denominator /= gcd;
6963   }
6964
6965   g_assert (denominator > 0);
6966
6967   value->data[0].v_int = numerator;
6968   value->data[1].v_int = denominator;
6969 }
6970
6971 /**
6972  * gst_value_get_fraction_numerator:
6973  * @value: a GValue initialized to #GST_TYPE_FRACTION
6974  *
6975  * Gets the numerator of the fraction specified by @value.
6976  *
6977  * Returns: the numerator of the fraction.
6978  */
6979 gint
6980 gst_value_get_fraction_numerator (const GValue * value)
6981 {
6982   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
6983
6984   return value->data[0].v_int;
6985 }
6986
6987 /**
6988  * gst_value_get_fraction_denominator:
6989  * @value: a GValue initialized to #GST_TYPE_FRACTION
6990  *
6991  * Gets the denominator of the fraction specified by @value.
6992  *
6993  * Returns: the denominator of the fraction.
6994  */
6995 gint
6996 gst_value_get_fraction_denominator (const GValue * value)
6997 {
6998   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
6999
7000   return value->data[1].v_int;
7001 }
7002
7003 /**
7004  * gst_value_fraction_multiply:
7005  * @product: a GValue initialized to #GST_TYPE_FRACTION
7006  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
7007  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
7008  *
7009  * Multiplies the two #GValue items containing a #GST_TYPE_FRACTION and sets
7010  * @product to the product of the two fractions.
7011  *
7012  * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise.
7013  */
7014 gboolean
7015 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
7016     const GValue * factor2)
7017 {
7018   gint n1, n2, d1, d2;
7019   gint res_n, res_d;
7020
7021   g_return_val_if_fail (product != NULL, FALSE);
7022   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
7023   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
7024
7025   n1 = factor1->data[0].v_int;
7026   n2 = factor2->data[0].v_int;
7027   d1 = factor1->data[1].v_int;
7028   d2 = factor2->data[1].v_int;
7029
7030   if (!gst_util_fraction_multiply (n1, d1, n2, d2, &res_n, &res_d))
7031     return FALSE;
7032
7033   gst_value_set_fraction (product, res_n, res_d);
7034
7035   return TRUE;
7036 }
7037
7038 /**
7039  * gst_value_fraction_subtract:
7040  * @dest: a GValue initialized to #GST_TYPE_FRACTION
7041  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
7042  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
7043  *
7044  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
7045  *
7046  * Returns: %FALSE in case of an error (like integer overflow), %TRUE otherwise.
7047  */
7048 gboolean
7049 gst_value_fraction_subtract (GValue * dest,
7050     const GValue * minuend, const GValue * subtrahend)
7051 {
7052   gint n1, n2, d1, d2;
7053   gint res_n, res_d;
7054
7055   g_return_val_if_fail (dest != NULL, FALSE);
7056   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
7057   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
7058
7059   n1 = minuend->data[0].v_int;
7060   n2 = subtrahend->data[0].v_int;
7061   d1 = minuend->data[1].v_int;
7062   d2 = subtrahend->data[1].v_int;
7063
7064   if (!gst_util_fraction_add (n1, d1, -n2, d2, &res_n, &res_d))
7065     return FALSE;
7066   gst_value_set_fraction (dest, res_n, res_d);
7067
7068   return TRUE;
7069 }
7070
7071 static gchar *
7072 gst_value_serialize_fraction (const GValue * value)
7073 {
7074   gint32 numerator = value->data[0].v_int;
7075   gint32 denominator = value->data[1].v_int;
7076   gboolean positive = TRUE;
7077
7078   /* get the sign and make components absolute */
7079   if (numerator < 0) {
7080     numerator = -numerator;
7081     positive = !positive;
7082   }
7083   if (denominator < 0) {
7084     denominator = -denominator;
7085     positive = !positive;
7086   }
7087
7088   return g_strdup_printf ("%s%d/%d",
7089       positive ? "" : "-", numerator, denominator);
7090 }
7091
7092 static gboolean
7093 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
7094 {
7095   gint num, den;
7096   gint num_chars;
7097
7098   if (G_UNLIKELY (s == NULL))
7099     return FALSE;
7100
7101   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest)))
7102     return FALSE;
7103
7104   if (sscanf (s, "%d/%d%n", &num, &den, &num_chars) >= 2) {
7105     if (s[num_chars] != 0)
7106       return FALSE;
7107     if (den == 0)
7108       return FALSE;
7109
7110     gst_value_set_fraction (dest, num, den);
7111     return TRUE;
7112   } else if (g_ascii_strcasecmp (s, "1/max") == 0) {
7113     gst_value_set_fraction (dest, 1, G_MAXINT);
7114     return TRUE;
7115   } else if (sscanf (s, "%d%n", &num, &num_chars) >= 1) {
7116     if (s[num_chars] != 0)
7117       return FALSE;
7118     gst_value_set_fraction (dest, num, 1);
7119     return TRUE;
7120   } else if (g_ascii_strcasecmp (s, "min") == 0) {
7121     gst_value_set_fraction (dest, -G_MAXINT, 1);
7122     return TRUE;
7123   } else if (g_ascii_strcasecmp (s, "max") == 0) {
7124     gst_value_set_fraction (dest, G_MAXINT, 1);
7125     return TRUE;
7126   }
7127
7128   return FALSE;
7129 }
7130
7131 static void
7132 gst_value_transform_fraction_string (const GValue * src_value,
7133     GValue * dest_value)
7134 {
7135   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
7136 }
7137
7138 static void
7139 gst_value_transform_string_fraction (const GValue * src_value,
7140     GValue * dest_value)
7141 {
7142   if (!gst_value_deserialize_fraction (dest_value,
7143           src_value->data[0].v_pointer))
7144     /* If the deserialize fails, ensure we leave the fraction in a
7145      * valid, if incorrect, state */
7146     gst_value_set_fraction (dest_value, 0, 1);
7147 }
7148
7149 static void
7150 gst_value_transform_double_fraction (const GValue * src_value,
7151     GValue * dest_value)
7152 {
7153   gdouble src = g_value_get_double (src_value);
7154   gint n, d;
7155
7156   gst_util_double_to_fraction (src, &n, &d);
7157   gst_value_set_fraction (dest_value, n, d);
7158 }
7159
7160 static void
7161 gst_value_transform_float_fraction (const GValue * src_value,
7162     GValue * dest_value)
7163 {
7164   gfloat src = g_value_get_float (src_value);
7165   gint n, d;
7166
7167   gst_util_double_to_fraction (src, &n, &d);
7168   gst_value_set_fraction (dest_value, n, d);
7169 }
7170
7171 static void
7172 gst_value_transform_fraction_double (const GValue * src_value,
7173     GValue * dest_value)
7174 {
7175   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
7176       ((double) src_value->data[1].v_int);
7177 }
7178
7179 static void
7180 gst_value_transform_fraction_float (const GValue * src_value,
7181     GValue * dest_value)
7182 {
7183   dest_value->data[0].v_float = ((float) src_value->data[0].v_int) /
7184       ((float) src_value->data[1].v_int);
7185 }
7186
7187 static gint
7188 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
7189 {
7190   gint n1, n2;
7191   gint d1, d2;
7192   gint ret;
7193
7194   n1 = value1->data[0].v_int;
7195   n2 = value2->data[0].v_int;
7196   d1 = value1->data[1].v_int;
7197   d2 = value2->data[1].v_int;
7198
7199   /* fractions are reduced when set, so we can quickly see if they're equal */
7200   if (n1 == n2 && d1 == d2)
7201     return GST_VALUE_EQUAL;
7202
7203   if (d1 == 0 && d2 == 0)
7204     return GST_VALUE_UNORDERED;
7205   else if (d1 == 0)
7206     return GST_VALUE_GREATER_THAN;
7207   else if (d2 == 0)
7208     return GST_VALUE_LESS_THAN;
7209
7210   ret = gst_util_fraction_compare (n1, d1, n2, d2);
7211   if (ret == -1)
7212     return GST_VALUE_LESS_THAN;
7213   else if (ret == 1)
7214     return GST_VALUE_GREATER_THAN;
7215
7216   /* Equality can't happen here because we check for that
7217    * first already */
7218   g_return_val_if_reached (GST_VALUE_UNORDERED);
7219 }
7220
7221 /*********
7222  * GDate *
7223  *********/
7224
7225 static gint
7226 gst_value_compare_date (const GValue * value1, const GValue * value2)
7227 {
7228   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
7229   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
7230   guint32 j1, j2;
7231
7232   if (date1 == date2)
7233     return GST_VALUE_EQUAL;
7234
7235   if ((date1 == NULL || !g_date_valid (date1))
7236       && (date2 != NULL && g_date_valid (date2))) {
7237     return GST_VALUE_LESS_THAN;
7238   }
7239
7240   if ((date2 == NULL || !g_date_valid (date2))
7241       && (date1 != NULL && g_date_valid (date1))) {
7242     return GST_VALUE_GREATER_THAN;
7243   }
7244
7245   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
7246       || !g_date_valid (date2)) {
7247     return GST_VALUE_UNORDERED;
7248   }
7249
7250   j1 = g_date_get_julian (date1);
7251   j2 = g_date_get_julian (date2);
7252
7253   if (j1 == j2)
7254     return GST_VALUE_EQUAL;
7255   else if (j1 < j2)
7256     return GST_VALUE_LESS_THAN;
7257   else
7258     return GST_VALUE_GREATER_THAN;
7259 }
7260
7261 static gchar *
7262 gst_value_serialize_date (const GValue * val)
7263 {
7264   const GDate *date = (const GDate *) g_value_get_boxed (val);
7265
7266   if (date == NULL || !g_date_valid (date))
7267     return g_strdup ("9999-99-99");
7268
7269   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
7270       g_date_get_month (date), g_date_get_day (date));
7271 }
7272
7273 static gboolean
7274 gst_value_deserialize_date (GValue * dest, const gchar * s)
7275 {
7276   guint year, month, day;
7277
7278   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
7279     return FALSE;
7280
7281   if (!g_date_valid_dmy (day, month, year))
7282     return FALSE;
7283
7284   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
7285   return TRUE;
7286 }
7287
7288 /***************
7289  * GstDateTime *
7290  ***************/
7291
7292 static gint
7293 gst_value_compare_date_time (const GValue * value1, const GValue * value2)
7294 {
7295   const GstDateTime *date1 = (const GstDateTime *) g_value_get_boxed (value1);
7296   const GstDateTime *date2 = (const GstDateTime *) g_value_get_boxed (value2);
7297
7298   if (date1 == date2)
7299     return GST_VALUE_EQUAL;
7300
7301   if ((date1 == NULL) && (date2 != NULL)) {
7302     return GST_VALUE_LESS_THAN;
7303   }
7304   if ((date2 == NULL) && (date1 != NULL)) {
7305     return GST_VALUE_LESS_THAN;
7306   }
7307
7308   /* returns GST_VALUE_* */
7309   return __gst_date_time_compare (date1, date2);
7310 }
7311
7312 static gchar *
7313 gst_value_serialize_date_time (const GValue * val)
7314 {
7315   GstDateTime *date = (GstDateTime *) g_value_get_boxed (val);
7316
7317   if (date == NULL)
7318     return g_strdup ("null");
7319
7320   return __gst_date_time_serialize (date, TRUE);
7321 }
7322
7323 static gboolean
7324 gst_value_deserialize_date_time (GValue * dest, const gchar * s)
7325 {
7326   GstDateTime *datetime;
7327
7328   if (!s || strcmp (s, "null") == 0) {
7329     return FALSE;
7330   }
7331
7332   datetime = gst_date_time_new_from_iso8601_string (s);
7333   if (datetime != NULL) {
7334     g_value_take_boxed (dest, datetime);
7335     return TRUE;
7336   }
7337   GST_WARNING ("Failed to deserialize date time string '%s'", s);
7338   return FALSE;
7339 }
7340
7341 static void
7342 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
7343 {
7344   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
7345 }
7346
7347 static void
7348 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
7349 {
7350   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
7351 }
7352
7353 /*************
7354  * GDateTime *
7355  *************/
7356
7357 static gint
7358 gst_value_compare_g_date_time (const GValue * value1, const GValue * value2)
7359 {
7360   const GDateTime *date1 = (const GDateTime *) g_value_get_boxed (value1);
7361   const GDateTime *date2 = (const GDateTime *) g_value_get_boxed (value2);
7362
7363   if (date1 == date2)
7364     return GST_VALUE_EQUAL;
7365
7366   if ((date1 == NULL) && (date2 != NULL)) {
7367     return GST_VALUE_LESS_THAN;
7368   }
7369   if ((date2 == NULL) && (date1 != NULL)) {
7370     return GST_VALUE_LESS_THAN;
7371   }
7372
7373   return g_date_time_compare (date1, date2);
7374 }
7375
7376 static gchar *
7377 gst_value_serialize_g_date_time (const GValue * val)
7378 {
7379   GDateTime *date = (GDateTime *) g_value_get_boxed (val);
7380
7381   if (date == NULL)
7382     return g_strdup ("null");
7383
7384   return g_date_time_format_iso8601 (date);
7385 }
7386
7387 static gboolean
7388 gst_value_deserialize_g_date_time (GValue * dest, const gchar * s)
7389 {
7390   GDateTime *datetime;
7391
7392   if (!s || strcmp (s, "null") == 0) {
7393     return FALSE;
7394   }
7395
7396   /* The Gstreamer iso8601 parser is a bit more forgiving */
7397   datetime =
7398       gst_date_time_to_g_date_time (gst_date_time_new_from_iso8601_string (s));
7399   if (datetime != NULL) {
7400     g_value_take_boxed (dest, datetime);
7401     return TRUE;
7402   }
7403   GST_WARNING ("Failed to deserialize date time string '%s' to GLibDateTime",
7404       s);
7405   return FALSE;
7406 }
7407
7408 /*********
7409  * bytes *
7410  *********/
7411
7412 static gint
7413 gst_value_compare_bytes (const GValue * value1, const GValue * value2)
7414 {
7415   GBytes *bytes1 = (GBytes *) g_value_get_boxed (value1);
7416   GBytes *bytes2 = (GBytes *) g_value_get_boxed (value2);
7417
7418   if (G_UNLIKELY (!bytes1 || !bytes2)) {
7419     if (bytes1 == bytes2)
7420       return GST_VALUE_EQUAL;
7421     else
7422       return GST_VALUE_UNORDERED;
7423   }
7424
7425   return g_bytes_compare (bytes1, bytes2);
7426 }
7427
7428 static gchar *
7429 gst_value_serialize_bytes (const GValue * value)
7430 {
7431   GBytes *bytes = (GBytes *) g_value_get_boxed (value);
7432   gsize len = 0;
7433   const guint8 *data;
7434
7435   data = bytes ? g_bytes_get_data (bytes, &len) : NULL;
7436
7437   return g_base64_encode (data, len);
7438 }
7439
7440 static gboolean
7441 gst_value_deserialize_bytes (GValue * dest, const gchar * s)
7442 {
7443   gsize len;
7444   guint8 *data;
7445
7446   if (!s) {
7447     g_value_set_boxed (dest, g_bytes_new (NULL, 0));
7448     return TRUE;
7449   }
7450
7451   data = g_base64_decode (s, &len);
7452   g_value_set_boxed (dest, g_bytes_new_take (data, len));
7453   return TRUE;
7454 }
7455
7456
7457 /************
7458  * bitmask *
7459  ************/
7460
7461 /* helper functions */
7462 static void
7463 gst_value_init_bitmask (GValue * value)
7464 {
7465   value->data[0].v_uint64 = 0;
7466 }
7467
7468 static void
7469 gst_value_copy_bitmask (const GValue * src_value, GValue * dest_value)
7470 {
7471   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
7472 }
7473
7474 static gchar *
7475 gst_value_collect_bitmask (GValue * value, guint n_collect_values,
7476     GTypeCValue * collect_values, guint collect_flags)
7477 {
7478   g_return_val_if_fail (n_collect_values == 1,
7479       g_strdup_printf ("not enough value locations for `%s' passed",
7480           G_VALUE_TYPE_NAME (value)));
7481
7482   gst_value_set_bitmask (value, (guint64) collect_values[0].v_int64);
7483
7484   return NULL;
7485 }
7486
7487 static gchar *
7488 gst_value_lcopy_bitmask (const GValue * value, guint n_collect_values,
7489     GTypeCValue * collect_values, guint collect_flags)
7490 {
7491   guint64 *bitmask = collect_values[0].v_pointer;
7492
7493   g_return_val_if_fail (bitmask != NULL,
7494       g_strdup_printf ("value for `%s' passed as NULL",
7495           G_VALUE_TYPE_NAME (value)));
7496
7497   *bitmask = value->data[0].v_uint64;
7498
7499   return NULL;
7500 }
7501
7502 /**
7503  * gst_value_set_bitmask:
7504  * @value: a GValue initialized to #GST_TYPE_BITMASK
7505  * @bitmask: the bitmask
7506  *
7507  * Sets @value to the bitmask specified by @bitmask.
7508  */
7509 void
7510 gst_value_set_bitmask (GValue * value, guint64 bitmask)
7511 {
7512   g_return_if_fail (GST_VALUE_HOLDS_BITMASK (value));
7513
7514   value->data[0].v_uint64 = bitmask;
7515 }
7516
7517 /**
7518  * gst_value_get_bitmask:
7519  * @value: a GValue initialized to #GST_TYPE_BITMASK
7520  *
7521  * Gets the bitmask specified by @value.
7522  *
7523  * Returns: the bitmask.
7524  */
7525 guint64
7526 gst_value_get_bitmask (const GValue * value)
7527 {
7528   g_return_val_if_fail (GST_VALUE_HOLDS_BITMASK (value), 0);
7529
7530   return value->data[0].v_uint64;
7531 }
7532
7533 static gchar *
7534 gst_value_serialize_bitmask (const GValue * value)
7535 {
7536   guint64 bitmask = value->data[0].v_uint64;
7537
7538   return g_strdup_printf ("0x%016" G_GINT64_MODIFIER "x", bitmask);
7539 }
7540
7541 static gboolean
7542 gst_value_deserialize_bitmask (GValue * dest, const gchar * s)
7543 {
7544   gchar *endptr = NULL;
7545   guint64 val;
7546
7547   if (G_UNLIKELY (s == NULL))
7548     return FALSE;
7549
7550   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_BITMASK (dest)))
7551     return FALSE;
7552
7553   errno = 0;
7554   val = g_ascii_strtoull (s, &endptr, 16);
7555   if (val == G_MAXUINT64 && (errno == ERANGE || errno == EINVAL))
7556     return FALSE;
7557   if (val == 0 && endptr == s)
7558     return FALSE;
7559
7560   gst_value_set_bitmask (dest, val);
7561
7562   return TRUE;
7563 }
7564
7565 static void
7566 gst_value_transform_bitmask_string (const GValue * src_value,
7567     GValue * dest_value)
7568 {
7569   dest_value->data[0].v_pointer = gst_value_serialize_bitmask (src_value);
7570 }
7571
7572 static void
7573 gst_value_transform_string_bitmask (const GValue * src_value,
7574     GValue * dest_value)
7575 {
7576   if (!gst_value_deserialize_bitmask (dest_value, src_value->data[0].v_pointer))
7577     gst_value_set_bitmask (dest_value, 0);
7578 }
7579
7580 static void
7581 gst_value_transform_uint64_bitmask (const GValue * src_value,
7582     GValue * dest_value)
7583 {
7584   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
7585 }
7586
7587 static void
7588 gst_value_transform_bitmask_uint64 (const GValue * src_value,
7589     GValue * dest_value)
7590 {
7591   dest_value->data[0].v_uint64 = src_value->data[0].v_uint64;
7592 }
7593
7594 static gint
7595 gst_value_compare_bitmask (const GValue * value1, const GValue * value2)
7596 {
7597   guint64 v1, v2;
7598
7599   v1 = value1->data[0].v_uint64;
7600   v2 = value2->data[0].v_uint64;
7601
7602   if (v1 == v2)
7603     return GST_VALUE_EQUAL;
7604
7605   return GST_VALUE_UNORDERED;
7606 }
7607
7608 /************
7609  * flagset *
7610  ************/
7611
7612 /* helper functions */
7613 static void
7614 gst_value_init_flagset (GValue * value)
7615 {
7616   value->data[0].v_uint = 0;
7617   value->data[1].v_uint = 0;
7618 }
7619
7620 static void
7621 gst_value_copy_flagset (const GValue * src_value, GValue * dest_value)
7622 {
7623   dest_value->data[0].v_uint = src_value->data[0].v_uint;
7624   dest_value->data[1].v_uint = src_value->data[1].v_uint;
7625 }
7626
7627 static gchar *
7628 gst_value_collect_flagset (GValue * value, guint n_collect_values,
7629     GTypeCValue * collect_values, guint collect_flags)
7630 {
7631   g_return_val_if_fail (n_collect_values == 2,
7632       g_strdup_printf ("not enough value locations for `%s' passed",
7633           G_VALUE_TYPE_NAME (value)));
7634
7635   gst_value_set_flagset (value,
7636       (guint) collect_values[0].v_int, (guint) collect_values[1].v_int);
7637
7638   return NULL;
7639 }
7640
7641 static gchar *
7642 gst_value_lcopy_flagset (const GValue * value, guint n_collect_values,
7643     GTypeCValue * collect_values, guint collect_flags)
7644 {
7645   guint *flags = collect_values[0].v_pointer;
7646   guint *mask = collect_values[1].v_pointer;
7647
7648   *flags = value->data[0].v_uint;
7649   *mask = value->data[1].v_uint;
7650
7651   return NULL;
7652 }
7653
7654 /**
7655  * gst_value_set_flagset:
7656  * @value: a GValue initialized to %GST_TYPE_FLAG_SET
7657  * @flags: The value of the flags set or unset
7658  * @mask: The mask indicate which flags bits must match for comparisons
7659  *
7660  * Sets @value to the flags and mask values provided in @flags and @mask.
7661  * The @flags value indicates the values of flags, the @mask represents
7662  * which bits in the flag value have been set, and which are "don't care"
7663  *
7664  * Since: 1.6
7665  */
7666 void
7667 gst_value_set_flagset (GValue * value, guint flags, guint mask)
7668 {
7669   g_return_if_fail (GST_VALUE_HOLDS_FLAG_SET (value));
7670
7671   /* Normalise and only keep flags mentioned in the mask */
7672   value->data[0].v_uint = flags & mask;
7673   value->data[1].v_uint = mask;
7674 }
7675
7676 /**
7677  * gst_value_get_flagset_flags:
7678  * @value: a GValue initialized to #GST_TYPE_FLAG_SET
7679  *
7680  * Retrieve the flags field of a GstFlagSet @value.
7681  *
7682  * Returns: the flags field of the flagset instance.
7683  *
7684  * Since: 1.6
7685  */
7686 guint
7687 gst_value_get_flagset_flags (const GValue * value)
7688 {
7689   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value), 0);
7690
7691   return value->data[0].v_uint;
7692 }
7693
7694 /**
7695  * gst_value_get_flagset_mask:
7696  * @value: a GValue initialized to #GST_TYPE_FLAG_SET
7697  *
7698  * Retrieve the mask field of a GstFlagSet @value.
7699  *
7700  * Returns: the mask field of the flagset instance.
7701  *
7702  * Since: 1.6
7703  */
7704 guint
7705 gst_value_get_flagset_mask (const GValue * value)
7706 {
7707   g_return_val_if_fail (GST_VALUE_HOLDS_FLAG_SET (value), 1);
7708
7709   return value->data[1].v_uint;
7710 }
7711
7712 static gchar *
7713 gst_value_serialize_flagset (const GValue * value)
7714 {
7715   guint flags = value->data[0].v_uint;
7716   guint mask = value->data[1].v_uint;
7717   GstFlagSetClass *set_klass =
7718       (GstFlagSetClass *) g_type_class_ref (G_VALUE_TYPE (value));
7719   gchar *result;
7720
7721   result = g_strdup_printf ("%x:%x", flags, mask);
7722
7723   /* If this flag set class has an associated GFlags GType, and some
7724    * bits in the mask, serialize the bits in human-readable form to
7725    * aid debugging */
7726   if (mask && set_klass->flags_type) {
7727     GFlagsClass *flags_klass =
7728         (GFlagsClass *) (g_type_class_ref (set_klass->flags_type));
7729     GFlagsValue *fl;
7730     gchar *tmp;
7731     gboolean first = TRUE;
7732
7733     g_return_val_if_fail (flags_klass, NULL);
7734
7735     /* some bits in the mask are set, so serialize one by one, according
7736      * to whether that bit is set or cleared in the flags value */
7737     while (mask) {
7738       fl = g_flags_get_first_value (flags_klass, mask);
7739       if (fl == NULL) {
7740         /* No more bits match in the flags mask - time to stop */
7741         mask = 0;
7742         break;
7743       }
7744
7745       tmp = g_strconcat (result,
7746           first ? ":" : "",
7747           (flags & fl->value) ? "+" : "/", fl->value_nick, NULL);
7748       g_free (result);
7749       result = tmp;
7750       first = FALSE;
7751
7752       /* clear flag */
7753       mask &= ~fl->value;
7754     }
7755     g_type_class_unref (flags_klass);
7756
7757   }
7758   g_type_class_unref (set_klass);
7759
7760   return result;
7761 }
7762
7763 static gboolean
7764 is_valid_flags_string (const gchar * s)
7765 {
7766   /* We're looking to match +this/that+other-thing/not-this-thing type strings */
7767   return g_regex_match_simple ("^([\\+\\/][\\w\\d-]+)+$", s, G_REGEX_CASELESS,
7768       0);
7769 }
7770
7771 static gboolean
7772 gst_value_deserialize_flagset (GValue * dest, const gchar * s)
7773 {
7774   gboolean res = FALSE;
7775   guint flags, mask;
7776   gchar *cur, *next;
7777
7778   if (G_UNLIKELY (s == NULL))
7779     return FALSE;
7780
7781   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FLAG_SET (dest)))
7782     return FALSE;
7783
7784   /* Flagset strings look like %x:%x - hex flags : hex bitmask,
7785    * 32-bit each, or like a concatenated list of flag nicks,
7786    * with either '+' or '/' in front. The first form
7787    * may optionally be followed by ':' and a set of text flag descriptions
7788    * for easier debugging */
7789
7790   /* Try and interpret as hex form first, as it's the most efficient */
7791   /* Read the flags first */
7792   flags = strtoul (s, &next, 16);
7793   if (G_UNLIKELY ((flags == 0 && errno == EINVAL) || s == next))
7794     goto try_as_flags_string;
7795   /* Next char should be a colon */
7796   if (next[0] == ':')
7797     next++;
7798
7799   /* Read the mask */
7800   cur = next;
7801   mask = strtoul (cur, &next, 16);
7802   if (G_UNLIKELY ((mask == 0 && errno == EINVAL) || cur == next))
7803     goto try_as_flags_string;
7804
7805   /* Next char should be NULL terminator, or a ':'. If ':', we need the flag string after */
7806   if (G_UNLIKELY (next[0] == 0)) {
7807     res = TRUE;
7808     goto done;
7809   }
7810
7811   if (next[0] != ':')
7812     return FALSE;
7813
7814   s = next + 1;
7815
7816   if (g_str_equal (g_type_name (G_VALUE_TYPE (dest)), "GstFlagSet")) {
7817     /* If we're parsing a generic flag set, that can mean we're guessing
7818      * at the type in deserialising a GstStructure so at least check that
7819      * we have a valid-looking string, so we don't cause deserialisation of
7820      * other types of strings like 00:01:00:00 - https://bugzilla.gnome.org/show_bug.cgi?id=779755 */
7821     if (is_valid_flags_string (s)) {
7822       res = TRUE;
7823       goto done;
7824     }
7825     return FALSE;
7826   }
7827
7828   /* Otherwise, we already got a hex string for a valid non-generic flagset type */
7829   res = TRUE;
7830   goto done;
7831
7832 try_as_flags_string:
7833
7834   {
7835     const gchar *set_class = g_type_name (G_VALUE_TYPE (dest));
7836     GFlagsClass *flags_klass = NULL;
7837     const gchar *end;
7838
7839     if (g_str_equal (set_class, "GstFlagSet")) {
7840       /* There's no hope to parse the fields of generic flag set if we didn't already
7841        * catch a hex-string above */
7842       return FALSE;
7843     }
7844
7845     /* Flags class is the FlagSet class with 'Set' removed from the end */
7846     end = g_strrstr (set_class, "Set");
7847
7848     if (end != NULL) {
7849       gchar *class_name = g_strndup (set_class, end - set_class);
7850       GType flags_type = g_type_from_name (class_name);
7851       if (flags_type == G_TYPE_INVALID) {
7852         GST_TRACE ("Looking for dynamic type %s", class_name);
7853         gst_dynamic_type_factory_load (class_name);
7854       }
7855
7856       if (flags_type != G_TYPE_INVALID) {
7857         flags_klass = g_type_class_ref (flags_type);
7858         GST_TRACE ("Going to parse %s as %s", s, class_name);
7859       }
7860       g_free (class_name);
7861     }
7862
7863     if (flags_klass) {
7864       res = gst_value_gflags_str_to_flags (flags_klass, s, &flags, &mask);
7865       g_type_class_unref (flags_klass);
7866     }
7867   }
7868
7869 done:
7870   if (res)
7871     gst_value_set_flagset (dest, flags, mask);
7872   return res;
7873
7874 }
7875
7876 static void
7877 gst_value_transform_flagset_string (const GValue * src_value,
7878     GValue * dest_value)
7879 {
7880   dest_value->data[0].v_pointer = gst_value_serialize_flagset (src_value);
7881 }
7882
7883 static void
7884 gst_value_transform_string_flagset (const GValue * src_value,
7885     GValue * dest_value)
7886 {
7887   if (!gst_value_deserialize_flagset (dest_value, src_value->data[0].v_pointer)) {
7888     /* If the deserialize fails, ensure we leave the flags in a
7889      * valid, if incorrect, state */
7890     gst_value_set_flagset (dest_value, 0, 0);
7891   }
7892 }
7893
7894 static gint
7895 gst_value_compare_flagset (const GValue * value1, const GValue * value2)
7896 {
7897   guint v1, v2;
7898   guint m1, m2;
7899
7900   v1 = value1->data[0].v_uint;
7901   v2 = value2->data[0].v_uint;
7902
7903   m1 = value1->data[1].v_uint;
7904   m2 = value2->data[1].v_uint;
7905
7906   if (v1 == v2 && m1 == m2)
7907     return GST_VALUE_EQUAL;
7908
7909   return GST_VALUE_UNORDERED;
7910 }
7911
7912 /***********************
7913  * GstAllocationParams *
7914  ***********************/
7915 static gint
7916 gst_value_compare_allocation_params (const GValue * value1,
7917     const GValue * value2)
7918 {
7919   GstAllocationParams *v1, *v2;
7920
7921   v1 = value1->data[0].v_pointer;
7922   v2 = value2->data[0].v_pointer;
7923
7924   if (v1 == NULL && v1 == v2)
7925     return GST_VALUE_EQUAL;
7926
7927   if (v1 == NULL || v2 == NULL)
7928     return GST_VALUE_UNORDERED;
7929
7930   if (v1->flags == v2->flags && v1->align == v2->align &&
7931       v1->prefix == v2->prefix && v1->padding == v2->padding)
7932     return GST_VALUE_EQUAL;
7933
7934   return GST_VALUE_UNORDERED;
7935 }
7936
7937
7938 /************
7939  * GObject *
7940  ************/
7941
7942 static gint
7943 gst_value_compare_object (const GValue * value1, const GValue * value2)
7944 {
7945   gpointer v1, v2;
7946
7947   v1 = value1->data[0].v_pointer;
7948   v2 = value2->data[0].v_pointer;
7949
7950   if (v1 == v2)
7951     return GST_VALUE_EQUAL;
7952
7953   return GST_VALUE_UNORDERED;
7954 }
7955
7956 static void
7957 gst_value_transform_object_string (const GValue * src_value,
7958     GValue * dest_value)
7959 {
7960   GstObject *obj;
7961   gchar *str;
7962
7963   obj = g_value_get_object (src_value);
7964   if (obj) {
7965     str =
7966         g_strdup_printf ("(%s) %s", G_OBJECT_TYPE_NAME (obj),
7967         GST_OBJECT_NAME (obj));
7968   } else {
7969     str = g_strdup ("NULL");
7970   }
7971
7972   dest_value->data[0].v_pointer = str;
7973 }
7974
7975 static GTypeInfo _info = {
7976   0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL,
7977 };
7978
7979 static GTypeFundamentalInfo _finfo = {
7980   0
7981 };
7982
7983 #define FUNC_VALUE_GET_TYPE_CLASSED(type, name, csize, flags)   \
7984 GType _gst_ ## type ## _type = 0;                               \
7985                                                                 \
7986 GType gst_ ## type ## _get_type (void)                          \
7987 {                                                               \
7988   static GType gst_ ## type ## _type = 0;              \
7989                                                                 \
7990   if (g_once_init_enter (&gst_ ## type ## _type)) {             \
7991     GType _type;                                                \
7992     _info.class_size = csize;                                   \
7993     _finfo.type_flags = flags;                                  \
7994     _info.value_table = & _gst_ ## type ## _value_table;        \
7995     _type = g_type_register_fundamental (                       \
7996         g_type_fundamental_next (),                             \
7997         name, &_info, &_finfo, 0);                              \
7998     _gst_ ## type ## _type = _type;                             \
7999     g_once_init_leave(&gst_ ## type ## _type, _type);           \
8000   }                                                             \
8001                                                                 \
8002   return gst_ ## type ## _type;                                 \
8003 }
8004
8005 #define FUNC_VALUE_GET_TYPE(type, name) \
8006   FUNC_VALUE_GET_TYPE_CLASSED(type, name, 0, 0)
8007
8008 static const GTypeValueTable _gst_int_range_value_table = {
8009   gst_value_init_int_range,
8010   NULL,
8011   gst_value_copy_int_range,
8012   NULL,
8013   (char *) "ii",
8014   gst_value_collect_int_range, (char *) "pp", gst_value_lcopy_int_range
8015 };
8016
8017 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
8018
8019 static const GTypeValueTable _gst_int64_range_value_table = {
8020   gst_value_init_int64_range,
8021   gst_value_free_int64_range,
8022   gst_value_copy_int64_range,
8023   NULL,
8024   (char *) "qq",
8025   gst_value_collect_int64_range,
8026   (char *) "pp", gst_value_lcopy_int64_range
8027 };
8028
8029 FUNC_VALUE_GET_TYPE (int64_range, "GstInt64Range");
8030
8031 static const GTypeValueTable _gst_double_range_value_table = {
8032   gst_value_init_double_range,
8033   NULL,
8034   gst_value_copy_double_range,
8035   NULL,
8036   (char *) "dd",
8037   gst_value_collect_double_range,
8038   (char *) "pp", gst_value_lcopy_double_range
8039 };
8040
8041 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
8042
8043 static const GTypeValueTable _gst_fraction_range_value_table = {
8044   gst_value_init_fraction_range,
8045   gst_value_free_fraction_range,
8046   gst_value_copy_fraction_range,
8047   NULL,
8048   (char *) "iiii",
8049   gst_value_collect_fraction_range,
8050   (char *) "pppp", gst_value_lcopy_fraction_range
8051 };
8052
8053 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
8054
8055 static const GTypeValueTable _gst_value_list_value_table = {
8056   gst_value_init_list_or_array,
8057   gst_value_free_list_or_array,
8058   gst_value_copy_list_or_array,
8059   gst_value_list_or_array_peek_pointer,
8060   (char *) "p",
8061   gst_value_collect_list_or_array,
8062   (char *) "p", gst_value_lcopy_list_or_array
8063 };
8064
8065 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
8066
8067 static const GTypeValueTable _gst_value_array_value_table = {
8068   gst_value_init_list_or_array,
8069   gst_value_free_list_or_array,
8070   gst_value_copy_list_or_array,
8071   gst_value_list_or_array_peek_pointer,
8072   (char *) "p",
8073   gst_value_collect_list_or_array,
8074   (char *) "p", gst_value_lcopy_list_or_array
8075 };
8076
8077 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
8078
8079 static const GTypeValueTable _gst_fraction_value_table = {
8080   gst_value_init_fraction,
8081   NULL,
8082   gst_value_copy_fraction,
8083   NULL,
8084   (char *) "ii",
8085   gst_value_collect_fraction, (char *) "pp", gst_value_lcopy_fraction
8086 };
8087
8088 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
8089
8090 static const GTypeValueTable _gst_bitmask_value_table = {
8091   gst_value_init_bitmask,
8092   NULL,
8093   gst_value_copy_bitmask,
8094   NULL,
8095   (char *) "q",
8096   gst_value_collect_bitmask, (char *) "p", gst_value_lcopy_bitmask
8097 };
8098
8099 FUNC_VALUE_GET_TYPE (bitmask, "GstBitmask");
8100
8101 static const GTypeValueTable _gst_flagset_value_table = {
8102   gst_value_init_flagset,
8103   NULL,
8104   gst_value_copy_flagset,
8105   NULL,
8106   (char *) "ii",
8107   gst_value_collect_flagset, (char *) "pp", gst_value_lcopy_flagset
8108 };
8109
8110 FUNC_VALUE_GET_TYPE_CLASSED (flagset, "GstFlagSet",
8111     sizeof (GstFlagSetClass), G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_DERIVABLE);
8112
8113 GType
8114 gst_g_thread_get_type (void)
8115 {
8116   return G_TYPE_THREAD;
8117 }
8118
8119 #define SERIAL_VTABLE(t,c,s,d) { t, c, s, d, NULL }
8120 #define SERIAL_VTABLE_PSPEC(t,c,s,d) { t, c, s, NULL, d }
8121
8122 #define REGISTER_SERIALIZATION_CONST(_gtype, _type)                     \
8123 G_STMT_START {                                                          \
8124   static const GstValueTable gst_value =                                \
8125     SERIAL_VTABLE (_gtype, gst_value_compare_ ## _type,                 \
8126     gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type);    \
8127   gst_value_register (&gst_value);                                      \
8128 } G_STMT_END
8129
8130 #define REGISTER_SERIALIZATION(_gtype, _type)                           \
8131 G_STMT_START {                                                          \
8132   static GstValueTable gst_value =                                      \
8133     SERIAL_VTABLE (0, gst_value_compare_ ## _type,                      \
8134     gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type);    \
8135   gst_value.type = _gtype;                                              \
8136   gst_value_register (&gst_value);                                      \
8137 } G_STMT_END
8138
8139 #define REGISTER_SERIALIZATION_WITH_PSPEC(_gtype, _type)                \
8140 G_STMT_START {                                                          \
8141   static GstValueTable gst_value =                                      \
8142     SERIAL_VTABLE_PSPEC (0, gst_value_compare_ ## _type,                \
8143     gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type);    \
8144   gst_value.type = _gtype;                                              \
8145   gst_value_register (&gst_value);                                      \
8146 } G_STMT_END
8147
8148 #define REGISTER_SERIALIZATION_NO_COMPARE(_gtype, _type)                \
8149 G_STMT_START {                                                          \
8150   static GstValueTable gst_value =                                      \
8151     SERIAL_VTABLE (0, NULL,                                             \
8152     gst_value_serialize_ ## _type, gst_value_deserialize_ ## _type);    \
8153   gst_value.type = _gtype;                                              \
8154   gst_value_register (&gst_value);                                      \
8155 } G_STMT_END
8156
8157 #define REGISTER_SERIALIZATION_COMPARE_ONLY(_gtype, _type)              \
8158 G_STMT_START {                                                          \
8159   static GstValueTable gst_value =                                      \
8160     SERIAL_VTABLE (0, gst_value_compare_ ## _type,                      \
8161         NULL, NULL);                                                    \
8162   gst_value.type = _gtype;                                              \
8163   gst_value_register (&gst_value);                                      \
8164 } G_STMT_END
8165
8166 /* These initial sizes are used for the tables
8167  * below, and save a couple of reallocs at startup */
8168
8169 static const gint GST_VALUE_TABLE_DEFAULT_SIZE = 40;
8170 static const gint GST_VALUE_UNION_TABLE_DEFAULT_SIZE = 8;
8171 static const gint GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE = 4;
8172 static const gint GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE = 16;
8173
8174 void
8175 _priv_gst_value_initialize (void)
8176 {
8177   gst_value_table =
8178       g_array_sized_new (FALSE, FALSE, sizeof (GstValueTable),
8179       GST_VALUE_TABLE_DEFAULT_SIZE);
8180   gst_value_hash = g_hash_table_new (NULL, NULL);
8181   gst_value_union_funcs = g_array_sized_new (FALSE, FALSE,
8182       sizeof (GstValueUnionInfo), GST_VALUE_UNION_TABLE_DEFAULT_SIZE);
8183   gst_value_intersect_funcs = g_array_sized_new (FALSE, FALSE,
8184       sizeof (GstValueIntersectInfo), GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE);
8185   gst_value_subtract_funcs = g_array_sized_new (FALSE, FALSE,
8186       sizeof (GstValueSubtractInfo), GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE);
8187
8188   REGISTER_SERIALIZATION (gst_int_range_get_type (), int_range);
8189   REGISTER_SERIALIZATION (gst_int64_range_get_type (), int64_range);
8190   REGISTER_SERIALIZATION (gst_double_range_get_type (), double_range);
8191   REGISTER_SERIALIZATION (gst_fraction_range_get_type (), fraction_range);
8192   REGISTER_SERIALIZATION (g_value_array_get_type (), g_value_array);
8193   REGISTER_SERIALIZATION (gst_buffer_get_type (), buffer);
8194   REGISTER_SERIALIZATION (gst_sample_get_type (), sample);
8195   REGISTER_SERIALIZATION (gst_fraction_get_type (), fraction);
8196   REGISTER_SERIALIZATION (gst_caps_get_type (), caps);
8197   REGISTER_SERIALIZATION (gst_tag_list_get_type (), tag_list);
8198   REGISTER_SERIALIZATION (G_TYPE_DATE, date);
8199   REGISTER_SERIALIZATION (G_TYPE_BYTES, bytes);
8200   REGISTER_SERIALIZATION (gst_date_time_get_type (), date_time);
8201   REGISTER_SERIALIZATION (G_TYPE_DATE_TIME, g_date_time);
8202   REGISTER_SERIALIZATION (gst_bitmask_get_type (), bitmask);
8203   REGISTER_SERIALIZATION (gst_structure_get_type (), structure);
8204   REGISTER_SERIALIZATION (gst_flagset_get_type (), flagset);
8205
8206   REGISTER_SERIALIZATION_NO_COMPARE (gst_segment_get_type (), segment);
8207   REGISTER_SERIALIZATION_NO_COMPARE (gst_caps_features_get_type (),
8208       caps_features);
8209
8210   REGISTER_SERIALIZATION_COMPARE_ONLY (gst_allocation_params_get_type (),
8211       allocation_params);
8212   REGISTER_SERIALIZATION_COMPARE_ONLY (G_TYPE_OBJECT, object);
8213
8214   REGISTER_SERIALIZATION_CONST (G_TYPE_DOUBLE, double);
8215   REGISTER_SERIALIZATION_CONST (G_TYPE_FLOAT, float);
8216
8217   REGISTER_SERIALIZATION_CONST (G_TYPE_STRING, string);
8218   REGISTER_SERIALIZATION_CONST (G_TYPE_BOOLEAN, boolean);
8219   REGISTER_SERIALIZATION_CONST (G_TYPE_ENUM, enum);
8220
8221   REGISTER_SERIALIZATION_CONST (G_TYPE_FLAGS, gflags);
8222
8223   REGISTER_SERIALIZATION_CONST (G_TYPE_INT, int);
8224
8225   REGISTER_SERIALIZATION_CONST (G_TYPE_INT64, int64);
8226   REGISTER_SERIALIZATION_CONST (G_TYPE_LONG, long);
8227
8228   REGISTER_SERIALIZATION_CONST (G_TYPE_UINT, uint);
8229   REGISTER_SERIALIZATION_CONST (G_TYPE_UINT64, uint64);
8230   REGISTER_SERIALIZATION_CONST (G_TYPE_ULONG, ulong);
8231
8232   REGISTER_SERIALIZATION_CONST (G_TYPE_UCHAR, uchar);
8233
8234   REGISTER_SERIALIZATION (G_TYPE_GTYPE, gtype);
8235
8236   REGISTER_SERIALIZATION_WITH_PSPEC (gst_value_list_get_type (), value_list);
8237   REGISTER_SERIALIZATION_WITH_PSPEC (gst_value_array_get_type (), value_array);
8238
8239   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
8240       gst_value_transform_int_range_string);
8241   g_value_register_transform_func (GST_TYPE_INT64_RANGE, G_TYPE_STRING,
8242       gst_value_transform_int64_range_string);
8243   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
8244       gst_value_transform_double_range_string);
8245   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
8246       gst_value_transform_fraction_range_string);
8247   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
8248       gst_value_transform_list_string);
8249   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_VALUE_ARRAY,
8250       gst_value_transform_any_list_g_value_array);
8251   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
8252       gst_value_transform_array_string);
8253   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_VALUE_ARRAY,
8254       gst_value_transform_any_list_g_value_array);
8255   g_value_register_transform_func (G_TYPE_VALUE_ARRAY, G_TYPE_STRING,
8256       gst_value_transform_g_value_array_string);
8257   g_value_register_transform_func (G_TYPE_VALUE_ARRAY, GST_TYPE_ARRAY,
8258       gst_value_transform_g_value_array_any_list);
8259   g_value_register_transform_func (G_TYPE_VALUE_ARRAY, GST_TYPE_LIST,
8260       gst_value_transform_g_value_array_any_list);
8261   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
8262       gst_value_transform_fraction_string);
8263   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
8264       gst_value_transform_string_fraction);
8265   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
8266       gst_value_transform_fraction_double);
8267   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_FLOAT,
8268       gst_value_transform_fraction_float);
8269   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
8270       gst_value_transform_double_fraction);
8271   g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION,
8272       gst_value_transform_float_fraction);
8273   g_value_register_transform_func (G_TYPE_DATE, G_TYPE_STRING,
8274       gst_value_transform_date_string);
8275   g_value_register_transform_func (G_TYPE_STRING, G_TYPE_DATE,
8276       gst_value_transform_string_date);
8277   g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING,
8278       gst_value_transform_object_string);
8279   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_UINT64,
8280       gst_value_transform_bitmask_uint64);
8281   g_value_register_transform_func (GST_TYPE_BITMASK, G_TYPE_STRING,
8282       gst_value_transform_bitmask_string);
8283   g_value_register_transform_func (G_TYPE_UINT64, GST_TYPE_BITMASK,
8284       gst_value_transform_uint64_bitmask);
8285   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_BITMASK,
8286       gst_value_transform_string_bitmask);
8287
8288   g_value_register_transform_func (GST_TYPE_FLAG_SET, G_TYPE_STRING,
8289       gst_value_transform_flagset_string);
8290   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FLAG_SET,
8291       gst_value_transform_string_flagset);
8292
8293   /* Only register intersection functions for *different* types.
8294    * Identical type intersection should be specified directly in
8295    * gst_value_intersect() */
8296   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
8297       gst_value_intersect_int_int_range);
8298   gst_value_register_intersect_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
8299       gst_value_intersect_int64_int64_range);
8300   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
8301       gst_value_intersect_double_double_range);
8302   gst_value_register_intersect_func (GST_TYPE_FRACTION,
8303       GST_TYPE_FRACTION_RANGE, gst_value_intersect_fraction_fraction_range);
8304
8305   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
8306       gst_value_subtract_int_int_range);
8307   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
8308       gst_value_subtract_int_range_int);
8309   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
8310       gst_value_subtract_int_range_int_range);
8311   gst_value_register_subtract_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
8312       gst_value_subtract_int64_int64_range);
8313   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, G_TYPE_INT64,
8314       gst_value_subtract_int64_range_int64);
8315   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE,
8316       GST_TYPE_INT64_RANGE, gst_value_subtract_int64_range_int64_range);
8317   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
8318       gst_value_subtract_double_double_range);
8319   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
8320       gst_value_subtract_double_range_double);
8321   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
8322       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
8323   gst_value_register_subtract_func (GST_TYPE_FRACTION,
8324       GST_TYPE_FRACTION_RANGE, gst_value_subtract_fraction_fraction_range);
8325   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
8326       GST_TYPE_FRACTION, gst_value_subtract_fraction_range_fraction);
8327   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
8328       GST_TYPE_FRACTION_RANGE,
8329       gst_value_subtract_fraction_range_fraction_range);
8330
8331   {
8332     GType date_type = G_TYPE_DATE;
8333
8334     g_type_name (date_type);
8335   }
8336
8337   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
8338       gst_value_union_int_int_range);
8339   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
8340       gst_value_union_int_range_int_range);
8341   gst_value_register_union_func (GST_TYPE_FLAG_SET, GST_TYPE_FLAG_SET,
8342       gst_value_union_flagset_flagset);
8343   gst_value_register_union_func (GST_TYPE_STRUCTURE, GST_TYPE_STRUCTURE,
8344       gst_value_union_structure_structure);
8345
8346 #if GST_VERSION_NANO == 1
8347   /* If building from git master, check starting array sizes matched actual size
8348    * so we can keep the defines in sync and save a few reallocs on startup */
8349   if (gst_value_table->len > GST_VALUE_TABLE_DEFAULT_SIZE) {
8350     GST_ERROR ("Wrong initial gst_value_table size. "
8351         "Please set GST_VALUE_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
8352         gst_value_table->len);
8353   }
8354   if (gst_value_union_funcs->len > GST_VALUE_UNION_TABLE_DEFAULT_SIZE) {
8355     GST_ERROR ("Wrong initial gst_value_union_funcs table size. "
8356         "Please set GST_VALUE_UNION_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
8357         gst_value_union_funcs->len);
8358   }
8359   if (gst_value_intersect_funcs->len > GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE) {
8360     GST_ERROR ("Wrong initial gst_value_intersect_funcs table size. "
8361         "Please set GST_VALUE_INTERSECT_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
8362         gst_value_intersect_funcs->len);
8363   }
8364   if (gst_value_subtract_funcs->len > GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE) {
8365     GST_ERROR ("Wrong initial gst_value_subtract_funcs table size. "
8366         "Please set GST_VALUE_SUBTRACT_TABLE_DEFAULT_SIZE to %u in gstvalue.c",
8367         gst_value_subtract_funcs->len);
8368   }
8369 #endif
8370
8371 #if 0
8372   /* Implement these if needed */
8373   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
8374       gst_value_union_fraction_fraction_range);
8375   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
8376       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
8377 #endif
8378 }
8379
8380 static void
8381 gst_flagset_class_init (gpointer g_class, gpointer class_data)
8382 {
8383   GstFlagSetClass *f_class = (GstFlagSetClass *) (g_class);
8384   f_class->flags_type = (GType) GPOINTER_TO_SIZE (class_data);
8385 }
8386
8387 /**
8388  * gst_flagset_register:
8389  * @flags_type: a #GType of a #G_TYPE_FLAGS type.
8390  *
8391  * Create a new sub-class of #GST_TYPE_FLAG_SET
8392  * which will pretty-print the human-readable flags
8393  * when serializing, for easier debugging.
8394  *
8395  * Since: 1.6
8396  */
8397 GType
8398 gst_flagset_register (GType flags_type)
8399 {
8400   GTypeInfo info = {
8401     sizeof (GstFlagSetClass),
8402     NULL, NULL,
8403     (GClassInitFunc) gst_flagset_class_init,
8404     NULL, GSIZE_TO_POINTER (flags_type), 0, 0, NULL, NULL
8405   };
8406   GType t;
8407   gchar *class_name;
8408
8409   g_return_val_if_fail (G_TYPE_IS_FLAGS (flags_type), 0);
8410
8411   class_name = g_strdup_printf ("%sSet", g_type_name (flags_type));
8412
8413   t = g_type_register_static (GST_TYPE_FLAG_SET,
8414       g_intern_string (class_name), &info, 0);
8415   g_free (class_name);
8416
8417   return t;
8418 }