7073484d53d95f4a7c0b48a03b8612eeb7d423af
[platform/upstream/gstreamer.git] / 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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:gstvalue
22  * @short_description: GValue implementations specific
23  * to GStreamer
24  *
25  * GValue implementations specific to GStreamer.
26  *
27  * Note that operations on the same #GValue from multiple threads may lead to
28  * undefined behaviour.
29  *
30  * Last reviewed on 2008-03-11 (0.10.18)
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 #include <math.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ctype.h>
41
42 #include "gst_private.h"
43 #include "glib-compat-private.h"
44 #include <gst/gst.h>
45 #include <gobject/gvaluecollector.h>
46 #include "gstutils.h"
47
48 typedef struct _GstValueUnionInfo GstValueUnionInfo;
49 struct _GstValueUnionInfo
50 {
51   GType type1;
52   GType type2;
53   GstValueUnionFunc func;
54 };
55
56 typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
57 struct _GstValueIntersectInfo
58 {
59   GType type1;
60   GType type2;
61   GstValueIntersectFunc func;
62 };
63
64 typedef struct _GstValueSubtractInfo GstValueSubtractInfo;
65 struct _GstValueSubtractInfo
66 {
67   GType minuend;
68   GType subtrahend;
69   GstValueSubtractFunc func;
70 };
71
72 #define FUNDAMENTAL_TYPE_ID_MAX \
73     (G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT)
74 #define FUNDAMENTAL_TYPE_ID(type) \
75     ((type) >> G_TYPE_FUNDAMENTAL_SHIFT)
76
77 #define VALUE_LIST_SIZE(v) (((GArray *) (v)->data[0].v_pointer)->len)
78 #define VALUE_LIST_GET_VALUE(v, index) ((const GValue *) &g_array_index ((GArray *) (v)->data[0].v_pointer, GValue, (index)))
79
80 static GArray *gst_value_table;
81 static GHashTable *gst_value_hash;
82 static GstValueTable *gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID_MAX + 1];
83 static GArray *gst_value_union_funcs;
84 static GArray *gst_value_intersect_funcs;
85 static GArray *gst_value_subtract_funcs;
86
87 /* Forward declarations */
88 static gchar *gst_value_serialize_fraction (const GValue * value);
89
90 static GstValueCompareFunc gst_value_get_compare_func (const GValue * value1);
91 static gint gst_value_compare_with_func (const GValue * value1,
92     const GValue * value2, GstValueCompareFunc compare);
93
94 static gchar *gst_string_wrap (const gchar * s);
95 static gchar *gst_string_take_and_wrap (gchar * s);
96 static gchar *gst_string_unwrap (const gchar * s);
97
98 static inline GstValueTable *
99 gst_value_hash_lookup_type (GType type)
100 {
101   if (G_LIKELY (G_TYPE_IS_FUNDAMENTAL (type)))
102     return gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)];
103   else
104     return g_hash_table_lookup (gst_value_hash, (gpointer) type);
105 }
106
107 static void
108 gst_value_hash_add_type (GType type, const GstValueTable * table)
109 {
110   if (G_TYPE_IS_FUNDAMENTAL (type))
111     gst_value_tables_fundamental[FUNDAMENTAL_TYPE_ID (type)] = (gpointer) table;
112
113   g_hash_table_insert (gst_value_hash, (gpointer) type, (gpointer) table);
114 }
115
116 /********
117  * list *
118  ********/
119
120 /* two helper functions to serialize/stringify any type of list
121  * regular lists are done with { }, arrays with < >
122  */
123 static gchar *
124 gst_value_serialize_any_list (const GValue * value, const gchar * begin,
125     const gchar * end)
126 {
127   guint i;
128   GArray *array = value->data[0].v_pointer;
129   GString *s;
130   GValue *v;
131   gchar *s_val;
132   guint alen = array->len;
133
134   /* estimate minimum string length to minimise re-allocs in GString */
135   s = g_string_sized_new (2 + (6 * alen) + 2);
136   g_string_append (s, begin);
137   for (i = 0; i < alen; i++) {
138     v = &g_array_index (array, GValue, i);
139     s_val = gst_value_serialize (v);
140     g_string_append (s, s_val);
141     g_free (s_val);
142     if (i < alen - 1) {
143       g_string_append_len (s, ", ", 2);
144     }
145   }
146   g_string_append (s, end);
147   return g_string_free (s, FALSE);
148 }
149
150 static void
151 gst_value_transform_any_list_string (const GValue * src_value,
152     GValue * dest_value, const gchar * begin, const gchar * end)
153 {
154   GValue *list_value;
155   GArray *array;
156   GString *s;
157   guint i;
158   gchar *list_s;
159   guint alen;
160
161   array = src_value->data[0].v_pointer;
162   alen = array->len;
163
164   /* estimate minimum string length to minimise re-allocs in GString */
165   s = g_string_sized_new (2 + (10 * alen) + 2);
166   g_string_append (s, begin);
167   for (i = 0; i < alen; i++) {
168     list_value = &g_array_index (array, GValue, i);
169
170     if (i != 0) {
171       g_string_append_len (s, ", ", 2);
172     }
173     list_s = g_strdup_value_contents (list_value);
174     g_string_append (s, list_s);
175     g_free (list_s);
176   }
177   g_string_append (s, end);
178
179   dest_value->data[0].v_pointer = g_string_free (s, FALSE);
180 }
181
182 /*
183  * helper function to see if a type is fixed. Is used internally here and
184  * there. Do not export, since it doesn't work for types where the content
185  * decides the fixedness (e.g. GST_TYPE_ARRAY).
186  */
187 static gboolean
188 gst_type_is_fixed (GType type)
189 {
190   /* the basic int, string, double types */
191   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
192     return TRUE;
193   }
194   /* our fundamental types that are certainly not fixed */
195   if (type == GST_TYPE_INT_RANGE || type == GST_TYPE_DOUBLE_RANGE ||
196       type == GST_TYPE_INT64_RANGE ||
197       type == GST_TYPE_LIST || type == GST_TYPE_FRACTION_RANGE) {
198     return FALSE;
199   }
200   /* other (boxed) types that are fixed */
201   if (type == GST_TYPE_BUFFER) {
202     return TRUE;
203   }
204   /* heavy checks */
205   if (G_TYPE_IS_FUNDAMENTAL (type) || G_TYPE_FUNDAMENTAL (type) <=
206       G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
207     return TRUE;
208   }
209
210   return FALSE;
211 }
212
213 /* GValue functions usable for both regular lists and arrays */
214 static void
215 gst_value_init_list_or_array (GValue * value)
216 {
217   value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof (GValue));
218 }
219
220 static GArray *
221 copy_garray_of_gstvalue (const GArray * src)
222 {
223   GArray *dest;
224   guint i, len;
225
226   len = src->len;
227   dest = g_array_sized_new (FALSE, TRUE, sizeof (GValue), len);
228   g_array_set_size (dest, len);
229   for (i = 0; i < len; i++) {
230     gst_value_init_and_copy (&g_array_index (dest, GValue, i),
231         &g_array_index (src, GValue, i));
232   }
233
234   return dest;
235 }
236
237 static void
238 gst_value_copy_list_or_array (const GValue * src_value, GValue * dest_value)
239 {
240   dest_value->data[0].v_pointer =
241       copy_garray_of_gstvalue ((GArray *) src_value->data[0].v_pointer);
242 }
243
244 static void
245 gst_value_free_list_or_array (GValue * value)
246 {
247   guint i, len;
248   GArray *src = (GArray *) value->data[0].v_pointer;
249   len = src->len;
250
251   if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
252     for (i = 0; i < len; i++) {
253       g_value_unset (&g_array_index (src, GValue, i));
254     }
255     g_array_free (src, TRUE);
256   }
257 }
258
259 static gpointer
260 gst_value_list_or_array_peek_pointer (const GValue * value)
261 {
262   return value->data[0].v_pointer;
263 }
264
265 static gchar *
266 gst_value_collect_list_or_array (GValue * value, guint n_collect_values,
267     GTypeCValue * collect_values, guint collect_flags)
268 {
269   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
270     value->data[0].v_pointer = collect_values[0].v_pointer;
271     value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
272   } else {
273     value->data[0].v_pointer =
274         copy_garray_of_gstvalue ((GArray *) collect_values[0].v_pointer);
275   }
276   return NULL;
277 }
278
279 static gchar *
280 gst_value_lcopy_list_or_array (const GValue * value, guint n_collect_values,
281     GTypeCValue * collect_values, guint collect_flags)
282 {
283   GArray **dest = collect_values[0].v_pointer;
284
285   if (!dest)
286     return g_strdup_printf ("value location for `%s' passed as NULL",
287         G_VALUE_TYPE_NAME (value));
288   if (!value->data[0].v_pointer)
289     return g_strdup_printf ("invalid value given for `%s'",
290         G_VALUE_TYPE_NAME (value));
291   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
292     *dest = (GArray *) value->data[0].v_pointer;
293   } else {
294     *dest = copy_garray_of_gstvalue ((GArray *) value->data[0].v_pointer);
295   }
296   return NULL;
297 }
298
299 /**
300  * gst_value_list_append_value:
301  * @value: a #GValue of type #GST_TYPE_LIST
302  * @append_value: the value to append
303  *
304  * Appends @append_value to the GstValueList in @value.
305  */
306 void
307 gst_value_list_append_value (GValue * value, const GValue * append_value)
308 {
309   GValue val = { 0, };
310
311   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
312   g_return_if_fail (G_IS_VALUE (append_value));
313
314   gst_value_init_and_copy (&val, append_value);
315   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
316 }
317
318 /**
319  * gst_value_list_prepend_value:
320  * @value: a #GValue of type #GST_TYPE_LIST
321  * @prepend_value: the value to prepend
322  *
323  * Prepends @prepend_value to the GstValueList in @value.
324  */
325 void
326 gst_value_list_prepend_value (GValue * value, const GValue * prepend_value)
327 {
328   GValue val = { 0, };
329
330   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
331   g_return_if_fail (G_IS_VALUE (prepend_value));
332
333   gst_value_init_and_copy (&val, prepend_value);
334   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
335 }
336
337 /**
338  * gst_value_list_concat:
339  * @dest: (out caller-allocates): an uninitialized #GValue to take the result
340  * @value1: a #GValue
341  * @value2: a #GValue
342  *
343  * Concatenates copies of @value1 and @value2 into a list.  Values that are not
344  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
345  * @dest will be initialized to the type #GST_TYPE_LIST.
346  */
347 void
348 gst_value_list_concat (GValue * dest, const GValue * value1,
349     const GValue * value2)
350 {
351   guint i, value1_length, value2_length;
352   GArray *array;
353
354   g_return_if_fail (dest != NULL);
355   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
356   g_return_if_fail (G_IS_VALUE (value1));
357   g_return_if_fail (G_IS_VALUE (value2));
358
359   value1_length =
360       (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1);
361   value2_length =
362       (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1);
363   g_value_init (dest, GST_TYPE_LIST);
364   array = (GArray *) dest->data[0].v_pointer;
365   g_array_set_size (array, value1_length + value2_length);
366
367   if (GST_VALUE_HOLDS_LIST (value1)) {
368     for (i = 0; i < value1_length; i++) {
369       gst_value_init_and_copy (&g_array_index (array, GValue, i),
370           VALUE_LIST_GET_VALUE (value1, i));
371     }
372   } else {
373     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
374   }
375
376   if (GST_VALUE_HOLDS_LIST (value2)) {
377     for (i = 0; i < value2_length; i++) {
378       gst_value_init_and_copy (&g_array_index (array, GValue,
379               i + value1_length), VALUE_LIST_GET_VALUE (value2, i));
380     }
381   } else {
382     gst_value_init_and_copy (&g_array_index (array, GValue, value1_length),
383         value2);
384   }
385 }
386
387 /**
388  * gst_value_list_merge:
389  * @dest: (out caller-allocates): an uninitialized #GValue to take the result
390  * @value1: a #GValue
391  * @value2: a #GValue
392  *
393  * Merges copies of @value1 and @value2.  Values that are not
394  * of type #GST_TYPE_LIST are treated as if they were lists of length 1.
395  *
396  * The result will be put into @dest and will either be a list that will not
397  * contain any duplicates, or a non-list type (if @value1 and @value2
398  * were equal).
399  *
400  * Since: 0.10.32
401  */
402 void
403 gst_value_list_merge (GValue * dest, const GValue * value1,
404     const GValue * value2)
405 {
406   guint i, j, k, value1_length, value2_length, skipped;
407   const GValue *src;
408   gboolean skip;
409   GArray *array;
410
411   g_return_if_fail (dest != NULL);
412   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
413   g_return_if_fail (G_IS_VALUE (value1));
414   g_return_if_fail (G_IS_VALUE (value2));
415
416   value1_length =
417       (GST_VALUE_HOLDS_LIST (value1) ? VALUE_LIST_SIZE (value1) : 1);
418   value2_length =
419       (GST_VALUE_HOLDS_LIST (value2) ? VALUE_LIST_SIZE (value2) : 1);
420   g_value_init (dest, GST_TYPE_LIST);
421   array = (GArray *) dest->data[0].v_pointer;
422   g_array_set_size (array, value1_length + value2_length);
423
424   if (GST_VALUE_HOLDS_LIST (value1)) {
425     for (i = 0; i < value1_length; i++) {
426       gst_value_init_and_copy (&g_array_index (array, GValue, i),
427           VALUE_LIST_GET_VALUE (value1, i));
428     }
429   } else {
430     gst_value_init_and_copy (&g_array_index (array, GValue, 0), value1);
431   }
432
433   j = value1_length;
434   skipped = 0;
435   if (GST_VALUE_HOLDS_LIST (value2)) {
436     for (i = 0; i < value2_length; i++) {
437       skip = FALSE;
438       src = VALUE_LIST_GET_VALUE (value2, i);
439       for (k = 0; k < value1_length; k++) {
440         if (gst_value_compare (&g_array_index (array, GValue, k),
441                 src) == GST_VALUE_EQUAL) {
442           skip = TRUE;
443           skipped++;
444           break;
445         }
446       }
447       if (!skip) {
448         gst_value_init_and_copy (&g_array_index (array, GValue, j), src);
449         j++;
450       }
451     }
452   } else {
453     skip = FALSE;
454     for (k = 0; k < value1_length; k++) {
455       if (gst_value_compare (&g_array_index (array, GValue, k),
456               value2) == GST_VALUE_EQUAL) {
457         skip = TRUE;
458         skipped++;
459         break;
460       }
461     }
462     if (!skip) {
463       gst_value_init_and_copy (&g_array_index (array, GValue, j), value2);
464     }
465   }
466   if (skipped) {
467     guint new_size = value1_length + (value2_length - skipped);
468
469     if (new_size > 1) {
470       /* shrink list */
471       g_array_set_size (array, new_size);
472     } else {
473       GValue single_dest;
474
475       /* size is 1, take single value in list and make it new dest */
476       single_dest = g_array_index (array, GValue, 0);
477
478       /* clean up old value allocations: must set array size to 0, because
479        * allocated values are not inited meaning g_value_unset() will not
480        * work on them */
481       g_array_set_size (array, 0);
482       g_value_unset (dest);
483
484       /* the single value is our new result */
485       *dest = single_dest;
486     }
487   }
488 }
489
490 /**
491  * gst_value_list_get_size:
492  * @value: a #GValue of type #GST_TYPE_LIST
493  *
494  * Gets the number of values contained in @value.
495  *
496  * Returns: the number of values
497  */
498 guint
499 gst_value_list_get_size (const GValue * value)
500 {
501   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
502
503   return ((GArray *) value->data[0].v_pointer)->len;
504 }
505
506 /**
507  * gst_value_list_get_value:
508  * @value: a #GValue of type #GST_TYPE_LIST
509  * @index: index of value to get from the list
510  *
511  * Gets the value that is a member of the list contained in @value and
512  * has the index @index.
513  *
514  * Returns: (transfer none): the value at the given index
515  */
516 const GValue *
517 gst_value_list_get_value (const GValue * value, guint index)
518 {
519   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
520   g_return_val_if_fail (index < VALUE_LIST_SIZE (value), NULL);
521
522   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
523       GValue, index);
524 }
525
526 /**
527  * gst_value_array_append_value:
528  * @value: a #GValue of type #GST_TYPE_ARRAY
529  * @append_value: the value to append
530  *
531  * Appends @append_value to the GstValueArray in @value.
532  */
533 void
534 gst_value_array_append_value (GValue * value, const GValue * append_value)
535 {
536   GValue val = { 0, };
537
538   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
539   g_return_if_fail (G_IS_VALUE (append_value));
540
541   gst_value_init_and_copy (&val, append_value);
542   g_array_append_vals ((GArray *) value->data[0].v_pointer, &val, 1);
543 }
544
545 /**
546  * gst_value_array_prepend_value:
547  * @value: a #GValue of type #GST_TYPE_ARRAY
548  * @prepend_value: the value to prepend
549  *
550  * Prepends @prepend_value to the GstValueArray in @value.
551  */
552 void
553 gst_value_array_prepend_value (GValue * value, const GValue * prepend_value)
554 {
555   GValue val = { 0, };
556
557   g_return_if_fail (GST_VALUE_HOLDS_ARRAY (value));
558   g_return_if_fail (G_IS_VALUE (prepend_value));
559
560   gst_value_init_and_copy (&val, prepend_value);
561   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, &val, 1);
562 }
563
564 /**
565  * gst_value_array_get_size:
566  * @value: a #GValue of type #GST_TYPE_ARRAY
567  *
568  * Gets the number of values contained in @value.
569  *
570  * Returns: the number of values
571  */
572 guint
573 gst_value_array_get_size (const GValue * value)
574 {
575   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), 0);
576
577   return ((GArray *) value->data[0].v_pointer)->len;
578 }
579
580 /**
581  * gst_value_array_get_value:
582  * @value: a #GValue of type #GST_TYPE_ARRAY
583  * @index: index of value to get from the array
584  *
585  * Gets the value that is a member of the array contained in @value and
586  * has the index @index.
587  *
588  * Returns: (transfer none): the value at the given index
589  */
590 const GValue *
591 gst_value_array_get_value (const GValue * value, guint index)
592 {
593   g_return_val_if_fail (GST_VALUE_HOLDS_ARRAY (value), NULL);
594   g_return_val_if_fail (index < gst_value_array_get_size (value), NULL);
595
596   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer,
597       GValue, index);
598 }
599
600 static void
601 gst_value_transform_list_string (const GValue * src_value, GValue * dest_value)
602 {
603   gst_value_transform_any_list_string (src_value, dest_value, "{ ", " }");
604 }
605
606 static void
607 gst_value_transform_array_string (const GValue * src_value, GValue * dest_value)
608 {
609   gst_value_transform_any_list_string (src_value, dest_value, "< ", " >");
610 }
611
612 /* Do an unordered compare of the contents of a list */
613 static gint
614 gst_value_compare_list (const GValue * value1, const GValue * value2)
615 {
616   guint i, j;
617   GArray *array1 = value1->data[0].v_pointer;
618   GArray *array2 = value2->data[0].v_pointer;
619   GValue *v1;
620   GValue *v2;
621   gint len, to_remove;
622   guint8 *removed;
623   GstValueCompareFunc compare;
624
625   /* get length and do initial length check. */
626   len = array1->len;
627   if (len != array2->len)
628     return GST_VALUE_UNORDERED;
629
630   /* place to mark removed value indices of array2 */
631   removed = g_newa (guint8, len);
632   memset (removed, 0, len);
633   to_remove = len;
634
635   /* loop over array1, all items should be in array2. When we find an
636    * item in array2, remove it from array2 by marking it as removed */
637   for (i = 0; i < len; i++) {
638     v1 = &g_array_index (array1, GValue, i);
639     if ((compare = gst_value_get_compare_func (v1))) {
640       for (j = 0; j < len; j++) {
641         /* item is removed, we can skip it */
642         if (removed[j])
643           continue;
644         v2 = &g_array_index (array2, GValue, j);
645         if (gst_value_compare_with_func (v1, v2, compare) == GST_VALUE_EQUAL) {
646           /* mark item as removed now that we found it in array2 and 
647            * decrement the number of remaining items in array2. */
648           removed[j] = 1;
649           to_remove--;
650           break;
651         }
652       }
653       /* item in array1 and not in array2, UNORDERED */
654       if (j == len)
655         return GST_VALUE_UNORDERED;
656     } else
657       return GST_VALUE_UNORDERED;
658   }
659   /* if not all items were removed, array2 contained something not in array1 */
660   if (to_remove != 0)
661     return GST_VALUE_UNORDERED;
662
663   /* arrays are equal */
664   return GST_VALUE_EQUAL;
665 }
666
667 /* Perform an ordered comparison of the contents of an array */
668 static gint
669 gst_value_compare_array (const GValue * value1, const GValue * value2)
670 {
671   guint i;
672   GArray *array1 = value1->data[0].v_pointer;
673   GArray *array2 = value2->data[0].v_pointer;
674   guint len = array1->len;
675   GValue *v1;
676   GValue *v2;
677
678   if (len != array2->len)
679     return GST_VALUE_UNORDERED;
680
681   for (i = 0; i < len; i++) {
682     v1 = &g_array_index (array1, GValue, i);
683     v2 = &g_array_index (array2, GValue, i);
684     if (gst_value_compare (v1, v2) != GST_VALUE_EQUAL)
685       return GST_VALUE_UNORDERED;
686   }
687
688   return GST_VALUE_EQUAL;
689 }
690
691 static gchar *
692 gst_value_serialize_list (const GValue * value)
693 {
694   return gst_value_serialize_any_list (value, "{ ", " }");
695 }
696
697 static gboolean
698 gst_value_deserialize_list (GValue * dest, const gchar * s)
699 {
700   g_warning ("gst_value_deserialize_list: unimplemented");
701   return FALSE;
702 }
703
704 static gchar *
705 gst_value_serialize_array (const GValue * value)
706 {
707   return gst_value_serialize_any_list (value, "< ", " >");
708 }
709
710 static gboolean
711 gst_value_deserialize_array (GValue * dest, const gchar * s)
712 {
713   g_warning ("gst_value_deserialize_array: unimplemented");
714   return FALSE;
715 }
716
717 /*************
718  * int range *
719  *************/
720
721 static void
722 gst_value_init_int_range (GValue * value)
723 {
724   value->data[0].v_int = 0;
725   value->data[1].v_int = 0;
726 }
727
728 static void
729 gst_value_copy_int_range (const GValue * src_value, GValue * dest_value)
730 {
731   dest_value->data[0].v_int = src_value->data[0].v_int;
732   dest_value->data[1].v_int = src_value->data[1].v_int;
733 }
734
735 static gchar *
736 gst_value_collect_int_range (GValue * value, guint n_collect_values,
737     GTypeCValue * collect_values, guint collect_flags)
738 {
739   if (n_collect_values != 2)
740     return g_strdup_printf ("not enough value locations for `%s' passed",
741         G_VALUE_TYPE_NAME (value));
742   if (collect_values[0].v_int >= collect_values[1].v_int)
743     return g_strdup_printf ("range start is not smaller than end for `%s'",
744         G_VALUE_TYPE_NAME (value));
745
746   value->data[0].v_int = collect_values[0].v_int;
747   value->data[1].v_int = collect_values[1].v_int;
748
749   return NULL;
750 }
751
752 static gchar *
753 gst_value_lcopy_int_range (const GValue * value, guint n_collect_values,
754     GTypeCValue * collect_values, guint collect_flags)
755 {
756   guint32 *int_range_start = collect_values[0].v_pointer;
757   guint32 *int_range_end = collect_values[1].v_pointer;
758
759   if (!int_range_start)
760     return g_strdup_printf ("start value location for `%s' passed as NULL",
761         G_VALUE_TYPE_NAME (value));
762   if (!int_range_end)
763     return g_strdup_printf ("end value location for `%s' passed as NULL",
764         G_VALUE_TYPE_NAME (value));
765
766   *int_range_start = value->data[0].v_int;
767   *int_range_end = value->data[1].v_int;
768
769   return NULL;
770 }
771
772 /**
773  * gst_value_set_int_range:
774  * @value: a GValue initialized to GST_TYPE_INT_RANGE
775  * @start: the start of the range
776  * @end: the end of the range
777  *
778  * Sets @value to the range specified by @start and @end.
779  */
780 void
781 gst_value_set_int_range (GValue * value, gint start, gint end)
782 {
783   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
784   g_return_if_fail (start < end);
785
786   value->data[0].v_int = start;
787   value->data[1].v_int = end;
788 }
789
790 /**
791  * gst_value_get_int_range_min:
792  * @value: a GValue initialized to GST_TYPE_INT_RANGE
793  *
794  * Gets the minimum of the range specified by @value.
795  *
796  * Returns: the minimum of the range
797  */
798 gint
799 gst_value_get_int_range_min (const GValue * value)
800 {
801   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
802
803   return value->data[0].v_int;
804 }
805
806 /**
807  * gst_value_get_int_range_max:
808  * @value: a GValue initialized to GST_TYPE_INT_RANGE
809  *
810  * Gets the maximum of the range specified by @value.
811  *
812  * Returns: the maxumum of the range
813  */
814 gint
815 gst_value_get_int_range_max (const GValue * value)
816 {
817   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
818
819   return value->data[1].v_int;
820 }
821
822 static void
823 gst_value_transform_int_range_string (const GValue * src_value,
824     GValue * dest_value)
825 {
826   dest_value->data[0].v_pointer = g_strdup_printf ("[%d,%d]",
827       (int) src_value->data[0].v_int, (int) src_value->data[1].v_int);
828 }
829
830 static gint
831 gst_value_compare_int_range (const GValue * value1, const GValue * value2)
832 {
833   if (value2->data[0].v_int == value1->data[0].v_int &&
834       value2->data[1].v_int == value1->data[1].v_int)
835     return GST_VALUE_EQUAL;
836   return GST_VALUE_UNORDERED;
837 }
838
839 static gchar *
840 gst_value_serialize_int_range (const GValue * value)
841 {
842   return g_strdup_printf ("[ %d, %d ]", value->data[0].v_int,
843       value->data[1].v_int);
844 }
845
846 static gboolean
847 gst_value_deserialize_int_range (GValue * dest, const gchar * s)
848 {
849   g_warning ("unimplemented");
850   return FALSE;
851 }
852
853 /***************
854  * int64 range *
855  ***************/
856
857 static void
858 gst_value_init_int64_range (GValue * value)
859 {
860   value->data[0].v_int64 = 0;
861   value->data[1].v_int64 = 0;
862 }
863
864 static void
865 gst_value_copy_int64_range (const GValue * src_value, GValue * dest_value)
866 {
867   dest_value->data[0].v_int64 = src_value->data[0].v_int64;
868   dest_value->data[1].v_int64 = src_value->data[1].v_int64;
869 }
870
871 static gchar *
872 gst_value_collect_int64_range (GValue * value, guint n_collect_values,
873     GTypeCValue * collect_values, guint collect_flags)
874 {
875   if (n_collect_values != 2)
876     return g_strdup_printf ("not enough value locations for `%s' passed",
877         G_VALUE_TYPE_NAME (value));
878   if (collect_values[0].v_int64 >= collect_values[1].v_int64)
879     return g_strdup_printf ("range start is not smaller than end for `%s'",
880         G_VALUE_TYPE_NAME (value));
881
882   value->data[0].v_int64 = collect_values[0].v_int64;
883   value->data[1].v_int64 = collect_values[1].v_int64;
884
885   return NULL;
886 }
887
888 static gchar *
889 gst_value_lcopy_int64_range (const GValue * value, guint n_collect_values,
890     GTypeCValue * collect_values, guint collect_flags)
891 {
892   guint64 *int_range_start = collect_values[0].v_pointer;
893   guint64 *int_range_end = collect_values[1].v_pointer;
894
895   if (!int_range_start)
896     return g_strdup_printf ("start value location for `%s' passed as NULL",
897         G_VALUE_TYPE_NAME (value));
898   if (!int_range_end)
899     return g_strdup_printf ("end value location for `%s' passed as NULL",
900         G_VALUE_TYPE_NAME (value));
901
902   *int_range_start = value->data[0].v_int64;
903   *int_range_end = value->data[1].v_int64;
904
905   return NULL;
906 }
907
908 /**
909  * gst_value_set_int64_range:
910  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
911  * @start: the start of the range
912  * @end: the end of the range
913  *
914  * Sets @value to the range specified by @start and @end.
915  *
916  * Since: 0.10.31
917  */
918 void
919 gst_value_set_int64_range (GValue * value, gint64 start, gint64 end)
920 {
921   g_return_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value));
922   g_return_if_fail (start < end);
923
924   value->data[0].v_int64 = start;
925   value->data[1].v_int64 = end;
926 }
927
928 /**
929  * gst_value_get_int64_range_min:
930  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
931  *
932  * Gets the minimum of the range specified by @value.
933  *
934  * Returns: the minimum of the range
935  *
936  * Since: 0.10.31
937  */
938 gint64
939 gst_value_get_int64_range_min (const GValue * value)
940 {
941   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
942
943   return value->data[0].v_int64;
944 }
945
946 /**
947  * gst_value_get_int64_range_max:
948  * @value: a GValue initialized to GST_TYPE_INT64_RANGE
949  *
950  * Gets the maximum of the range specified by @value.
951  *
952  * Returns: the maxumum of the range
953  *
954  * Since: 0.10.31
955  */
956 gint64
957 gst_value_get_int64_range_max (const GValue * value)
958 {
959   g_return_val_if_fail (GST_VALUE_HOLDS_INT64_RANGE (value), 0);
960
961   return value->data[1].v_int64;
962 }
963
964 static void
965 gst_value_transform_int64_range_string (const GValue * src_value,
966     GValue * dest_value)
967 {
968   dest_value->data[0].v_pointer =
969       g_strdup_printf ("(gint64)[%" G_GINT64_FORMAT ",%" G_GINT64_FORMAT "]",
970       src_value->data[0].v_int64, src_value->data[1].v_int64);
971 }
972
973 static gint
974 gst_value_compare_int64_range (const GValue * value1, const GValue * value2)
975 {
976   if (value2->data[0].v_int64 == value1->data[0].v_int64 &&
977       value2->data[1].v_int64 == value1->data[1].v_int64)
978     return GST_VALUE_EQUAL;
979   return GST_VALUE_UNORDERED;
980 }
981
982 static gchar *
983 gst_value_serialize_int64_range (const GValue * value)
984 {
985   return g_strdup_printf ("[ %" G_GINT64_FORMAT ", %" G_GINT64_FORMAT " ]",
986       value->data[0].v_int64, value->data[1].v_int64);
987 }
988
989 static gboolean
990 gst_value_deserialize_int64_range (GValue * dest, const gchar * s)
991 {
992   g_warning ("unimplemented");
993   return FALSE;
994 }
995
996 /****************
997  * double range *
998  ****************/
999
1000 static void
1001 gst_value_init_double_range (GValue * value)
1002 {
1003   value->data[0].v_double = 0;
1004   value->data[1].v_double = 0;
1005 }
1006
1007 static void
1008 gst_value_copy_double_range (const GValue * src_value, GValue * dest_value)
1009 {
1010   dest_value->data[0].v_double = src_value->data[0].v_double;
1011   dest_value->data[1].v_double = src_value->data[1].v_double;
1012 }
1013
1014 static gchar *
1015 gst_value_collect_double_range (GValue * value, guint n_collect_values,
1016     GTypeCValue * collect_values, guint collect_flags)
1017 {
1018   if (n_collect_values != 2)
1019     return g_strdup_printf ("not enough value locations for `%s' passed",
1020         G_VALUE_TYPE_NAME (value));
1021   if (collect_values[0].v_double >= collect_values[1].v_double)
1022     return g_strdup_printf ("range start is not smaller than end for `%s'",
1023         G_VALUE_TYPE_NAME (value));
1024
1025   value->data[0].v_double = collect_values[0].v_double;
1026   value->data[1].v_double = collect_values[1].v_double;
1027
1028   return NULL;
1029 }
1030
1031 static gchar *
1032 gst_value_lcopy_double_range (const GValue * value, guint n_collect_values,
1033     GTypeCValue * collect_values, guint collect_flags)
1034 {
1035   gdouble *double_range_start = collect_values[0].v_pointer;
1036   gdouble *double_range_end = collect_values[1].v_pointer;
1037
1038   if (!double_range_start)
1039     return g_strdup_printf ("start value location for `%s' passed as NULL",
1040         G_VALUE_TYPE_NAME (value));
1041   if (!double_range_end)
1042     return g_strdup_printf ("end value location for `%s' passed as NULL",
1043         G_VALUE_TYPE_NAME (value));
1044
1045   *double_range_start = value->data[0].v_double;
1046   *double_range_end = value->data[1].v_double;
1047
1048   return NULL;
1049 }
1050
1051 /**
1052  * gst_value_set_double_range:
1053  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1054  * @start: the start of the range
1055  * @end: the end of the range
1056  *
1057  * Sets @value to the range specified by @start and @end.
1058  */
1059 void
1060 gst_value_set_double_range (GValue * value, gdouble start, gdouble end)
1061 {
1062   g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
1063   g_return_if_fail (start < end);
1064
1065   value->data[0].v_double = start;
1066   value->data[1].v_double = end;
1067 }
1068
1069 /**
1070  * gst_value_get_double_range_min:
1071  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1072  *
1073  * Gets the minimum of the range specified by @value.
1074  *
1075  * Returns: the minimum of the range
1076  */
1077 gdouble
1078 gst_value_get_double_range_min (const GValue * value)
1079 {
1080   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
1081
1082   return value->data[0].v_double;
1083 }
1084
1085 /**
1086  * gst_value_get_double_range_max:
1087  * @value: a GValue initialized to GST_TYPE_DOUBLE_RANGE
1088  *
1089  * Gets the maximum of the range specified by @value.
1090  *
1091  * Returns: the maxumum of the range
1092  */
1093 gdouble
1094 gst_value_get_double_range_max (const GValue * value)
1095 {
1096   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
1097
1098   return value->data[1].v_double;
1099 }
1100
1101 static void
1102 gst_value_transform_double_range_string (const GValue * src_value,
1103     GValue * dest_value)
1104 {
1105   gchar s1[G_ASCII_DTOSTR_BUF_SIZE], s2[G_ASCII_DTOSTR_BUF_SIZE];
1106
1107   dest_value->data[0].v_pointer = g_strdup_printf ("[%s,%s]",
1108       g_ascii_dtostr (s1, G_ASCII_DTOSTR_BUF_SIZE,
1109           src_value->data[0].v_double),
1110       g_ascii_dtostr (s2, G_ASCII_DTOSTR_BUF_SIZE,
1111           src_value->data[1].v_double));
1112 }
1113
1114 static gint
1115 gst_value_compare_double_range (const GValue * value1, const GValue * value2)
1116 {
1117   if (value2->data[0].v_double == value1->data[0].v_double &&
1118       value2->data[0].v_double == value1->data[0].v_double)
1119     return GST_VALUE_EQUAL;
1120   return GST_VALUE_UNORDERED;
1121 }
1122
1123 static gchar *
1124 gst_value_serialize_double_range (const GValue * value)
1125 {
1126   gchar d1[G_ASCII_DTOSTR_BUF_SIZE];
1127   gchar d2[G_ASCII_DTOSTR_BUF_SIZE];
1128
1129   g_ascii_dtostr (d1, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
1130   g_ascii_dtostr (d2, G_ASCII_DTOSTR_BUF_SIZE, value->data[1].v_double);
1131   return g_strdup_printf ("[ %s, %s ]", d1, d2);
1132 }
1133
1134 static gboolean
1135 gst_value_deserialize_double_range (GValue * dest, const gchar * s)
1136 {
1137   g_warning ("unimplemented");
1138   return FALSE;
1139 }
1140
1141 /****************
1142  * fraction range *
1143  ****************/
1144
1145 static void
1146 gst_value_init_fraction_range (GValue * value)
1147 {
1148   GValue *vals;
1149   GType ftype;
1150
1151   ftype = GST_TYPE_FRACTION;
1152
1153   value->data[0].v_pointer = vals = g_slice_alloc0 (2 * sizeof (GValue));
1154   g_value_init (&vals[0], ftype);
1155   g_value_init (&vals[1], ftype);
1156 }
1157
1158 static void
1159 gst_value_free_fraction_range (GValue * value)
1160 {
1161   GValue *vals = (GValue *) value->data[0].v_pointer;
1162
1163   if (vals != NULL) {
1164     g_value_unset (&vals[0]);
1165     g_value_unset (&vals[1]);
1166     g_slice_free1 (2 * sizeof (GValue), vals);
1167     value->data[0].v_pointer = NULL;
1168   }
1169 }
1170
1171 static void
1172 gst_value_copy_fraction_range (const GValue * src_value, GValue * dest_value)
1173 {
1174   GValue *vals = (GValue *) dest_value->data[0].v_pointer;
1175   GValue *src_vals = (GValue *) src_value->data[0].v_pointer;
1176
1177   if (vals == NULL) {
1178     gst_value_init_fraction_range (dest_value);
1179     vals = dest_value->data[0].v_pointer;
1180   }
1181   if (src_vals != NULL) {
1182     g_value_copy (&src_vals[0], &vals[0]);
1183     g_value_copy (&src_vals[1], &vals[1]);
1184   }
1185 }
1186
1187 static gchar *
1188 gst_value_collect_fraction_range (GValue * value, guint n_collect_values,
1189     GTypeCValue * collect_values, guint collect_flags)
1190 {
1191   GValue *vals = (GValue *) value->data[0].v_pointer;
1192
1193   if (n_collect_values != 4)
1194     return g_strdup_printf ("not enough value locations for `%s' passed",
1195         G_VALUE_TYPE_NAME (value));
1196   if (collect_values[1].v_int == 0)
1197     return g_strdup_printf ("passed '0' as first denominator for `%s'",
1198         G_VALUE_TYPE_NAME (value));
1199   if (collect_values[3].v_int == 0)
1200     return g_strdup_printf ("passed '0' as second denominator for `%s'",
1201         G_VALUE_TYPE_NAME (value));
1202   if (gst_util_fraction_compare (collect_values[0].v_int,
1203           collect_values[1].v_int, collect_values[2].v_int,
1204           collect_values[3].v_int) >= 0)
1205     return g_strdup_printf ("range start is not smaller than end for `%s'",
1206         G_VALUE_TYPE_NAME (value));
1207
1208   if (vals == NULL) {
1209     gst_value_init_fraction_range (value);
1210     vals = value->data[0].v_pointer;
1211   }
1212
1213   gst_value_set_fraction (&vals[0], collect_values[0].v_int,
1214       collect_values[1].v_int);
1215   gst_value_set_fraction (&vals[1], collect_values[2].v_int,
1216       collect_values[3].v_int);
1217
1218   return NULL;
1219 }
1220
1221 static gchar *
1222 gst_value_lcopy_fraction_range (const GValue * value, guint n_collect_values,
1223     GTypeCValue * collect_values, guint collect_flags)
1224 {
1225   gint i;
1226   gint *dest_values[4];
1227   GValue *vals = (GValue *) value->data[0].v_pointer;
1228
1229   if (G_UNLIKELY (n_collect_values != 4))
1230     return g_strdup_printf ("not enough value locations for `%s' passed",
1231         G_VALUE_TYPE_NAME (value));
1232
1233   for (i = 0; i < 4; i++) {
1234     if (G_UNLIKELY (collect_values[i].v_pointer == NULL)) {
1235       return g_strdup_printf ("value location for `%s' passed as NULL",
1236           G_VALUE_TYPE_NAME (value));
1237     }
1238     dest_values[i] = collect_values[i].v_pointer;
1239   }
1240
1241   if (G_UNLIKELY (vals == NULL)) {
1242     return g_strdup_printf ("Uninitialised `%s' passed",
1243         G_VALUE_TYPE_NAME (value));
1244   }
1245
1246   dest_values[0][0] = gst_value_get_fraction_numerator (&vals[0]);
1247   dest_values[1][0] = gst_value_get_fraction_denominator (&vals[0]);
1248   dest_values[2][0] = gst_value_get_fraction_numerator (&vals[1]);
1249   dest_values[3][0] = gst_value_get_fraction_denominator (&vals[1]);
1250   return NULL;
1251 }
1252
1253 /**
1254  * gst_value_set_fraction_range:
1255  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1256  * @start: the start of the range (a GST_TYPE_FRACTION GValue)
1257  * @end: the end of the range (a GST_TYPE_FRACTION GValue)
1258  *
1259  * Sets @value to the range specified by @start and @end.
1260  */
1261 void
1262 gst_value_set_fraction_range (GValue * value, const GValue * start,
1263     const GValue * end)
1264 {
1265   GValue *vals;
1266
1267   g_return_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value));
1268   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (start));
1269   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (end));
1270   g_return_if_fail (gst_util_fraction_compare (start->data[0].v_int,
1271           start->data[1].v_int, end->data[0].v_int, end->data[1].v_int) < 0);
1272
1273   vals = (GValue *) value->data[0].v_pointer;
1274   if (vals == NULL) {
1275     gst_value_init_fraction_range (value);
1276     vals = value->data[0].v_pointer;
1277   }
1278   g_value_copy (start, &vals[0]);
1279   g_value_copy (end, &vals[1]);
1280 }
1281
1282 /**
1283  * gst_value_set_fraction_range_full:
1284  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1285  * @numerator_start: the numerator start of the range
1286  * @denominator_start: the denominator start of the range
1287  * @numerator_end: the numerator end of the range
1288  * @denominator_end: the denominator end of the range
1289  *
1290  * Sets @value to the range specified by @numerator_start/@denominator_start
1291  * and @numerator_end/@denominator_end.
1292  */
1293 void
1294 gst_value_set_fraction_range_full (GValue * value,
1295     gint numerator_start, gint denominator_start,
1296     gint numerator_end, gint denominator_end)
1297 {
1298   GValue start = { 0 };
1299   GValue end = { 0 };
1300
1301   g_return_if_fail (value != NULL);
1302   g_return_if_fail (denominator_start != 0);
1303   g_return_if_fail (denominator_end != 0);
1304   g_return_if_fail (gst_util_fraction_compare (numerator_start,
1305           denominator_start, numerator_end, denominator_end) < 0);
1306
1307   g_value_init (&start, GST_TYPE_FRACTION);
1308   g_value_init (&end, GST_TYPE_FRACTION);
1309
1310   gst_value_set_fraction (&start, numerator_start, denominator_start);
1311   gst_value_set_fraction (&end, numerator_end, denominator_end);
1312   gst_value_set_fraction_range (value, &start, &end);
1313
1314   g_value_unset (&start);
1315   g_value_unset (&end);
1316 }
1317
1318 /**
1319  * gst_value_get_fraction_range_min:
1320  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1321  *
1322  * Gets the minimum of the range specified by @value.
1323  *
1324  * Returns: the minimum of the range
1325  */
1326 const GValue *
1327 gst_value_get_fraction_range_min (const GValue * value)
1328 {
1329   GValue *vals;
1330
1331   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL);
1332
1333   vals = (GValue *) value->data[0].v_pointer;
1334   if (vals != NULL) {
1335     return &vals[0];
1336   }
1337
1338   return NULL;
1339 }
1340
1341 /**
1342  * gst_value_get_fraction_range_max:
1343  * @value: a GValue initialized to GST_TYPE_FRACTION_RANGE
1344  *
1345  * Gets the maximum of the range specified by @value.
1346  *
1347  * Returns: the maximum of the range
1348  */
1349 const GValue *
1350 gst_value_get_fraction_range_max (const GValue * value)
1351 {
1352   GValue *vals;
1353
1354   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION_RANGE (value), NULL);
1355
1356   vals = (GValue *) value->data[0].v_pointer;
1357   if (vals != NULL) {
1358     return &vals[1];
1359   }
1360
1361   return NULL;
1362 }
1363
1364 static gchar *
1365 gst_value_serialize_fraction_range (const GValue * value)
1366 {
1367   GValue *vals = (GValue *) value->data[0].v_pointer;
1368   gchar *retval;
1369
1370   if (vals == NULL) {
1371     retval = g_strdup ("[ 0/1, 0/1 ]");
1372   } else {
1373     gchar *start, *end;
1374
1375     start = gst_value_serialize_fraction (&vals[0]);
1376     end = gst_value_serialize_fraction (&vals[1]);
1377
1378     retval = g_strdup_printf ("[ %s, %s ]", start, end);
1379     g_free (start);
1380     g_free (end);
1381   }
1382
1383   return retval;
1384 }
1385
1386 static void
1387 gst_value_transform_fraction_range_string (const GValue * src_value,
1388     GValue * dest_value)
1389 {
1390   dest_value->data[0].v_pointer =
1391       gst_value_serialize_fraction_range (src_value);
1392 }
1393
1394 static gint
1395 gst_value_compare_fraction_range (const GValue * value1, const GValue * value2)
1396 {
1397   GValue *vals1, *vals2;
1398   GstValueCompareFunc compare;
1399
1400   if (value2->data[0].v_pointer == value1->data[0].v_pointer)
1401     return GST_VALUE_EQUAL;     /* Only possible if both are NULL */
1402
1403   if (value2->data[0].v_pointer == NULL || value1->data[0].v_pointer == NULL)
1404     return GST_VALUE_UNORDERED;
1405
1406   vals1 = (GValue *) value1->data[0].v_pointer;
1407   vals2 = (GValue *) value2->data[0].v_pointer;
1408   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
1409     if (gst_value_compare_with_func (&vals1[0], &vals2[0], compare) ==
1410         GST_VALUE_EQUAL &&
1411         gst_value_compare_with_func (&vals1[1], &vals2[1], compare) ==
1412         GST_VALUE_EQUAL)
1413       return GST_VALUE_EQUAL;
1414   }
1415   return GST_VALUE_UNORDERED;
1416 }
1417
1418 static gboolean
1419 gst_value_deserialize_fraction_range (GValue * dest, const gchar * s)
1420 {
1421   g_warning ("unimplemented");
1422   return FALSE;
1423 }
1424
1425 /***********
1426  * GstCaps *
1427  ***********/
1428
1429 /**
1430  * gst_value_set_caps:
1431  * @value: a GValue initialized to GST_TYPE_CAPS
1432  * @caps: (transfer none): the caps to set the value to
1433  *
1434  * Sets the contents of @value to @caps. A reference to the
1435  * provided @caps will be taken by the @value.
1436  */
1437 void
1438 gst_value_set_caps (GValue * value, const GstCaps * caps)
1439 {
1440   g_return_if_fail (G_IS_VALUE (value));
1441   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS);
1442   g_return_if_fail (caps == NULL || GST_IS_CAPS (caps));
1443
1444   g_value_set_boxed (value, caps);
1445 }
1446
1447 /**
1448  * gst_value_get_caps:
1449  * @value: a GValue initialized to GST_TYPE_CAPS
1450  *
1451  * Gets the contents of @value. The reference count of the returned
1452  * #GstCaps will not be modified, therefore the caller must take one
1453  * before getting rid of the @value.
1454  *
1455  * Returns: (transfer none): the contents of @value
1456  */
1457 const GstCaps *
1458 gst_value_get_caps (const GValue * value)
1459 {
1460   g_return_val_if_fail (G_IS_VALUE (value), NULL);
1461   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_CAPS, NULL);
1462
1463   return (GstCaps *) g_value_get_boxed (value);
1464 }
1465
1466 static gchar *
1467 gst_value_serialize_caps (const GValue * value)
1468 {
1469   GstCaps *caps = g_value_get_boxed (value);
1470
1471   return gst_caps_to_string (caps);
1472 }
1473
1474 static gboolean
1475 gst_value_deserialize_caps (GValue * dest, const gchar * s)
1476 {
1477   GstCaps *caps;
1478
1479   caps = gst_caps_from_string (s);
1480
1481   if (caps) {
1482     g_value_take_boxed (dest, caps);
1483     return TRUE;
1484   }
1485   return FALSE;
1486 }
1487
1488 /****************
1489  * GstStructure *
1490  ****************/
1491
1492 /**
1493  * gst_value_set_structure:
1494  * @value: a GValue initialized to GST_TYPE_STRUCTURE
1495  * @structure: the structure to set the value to
1496  *
1497  * Sets the contents of @value to @structure.  The actual
1498  *
1499  * Since: 0.10.15
1500  */
1501 void
1502 gst_value_set_structure (GValue * value, const GstStructure * structure)
1503 {
1504   g_return_if_fail (G_IS_VALUE (value));
1505   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE);
1506   g_return_if_fail (structure == NULL || GST_IS_STRUCTURE (structure));
1507
1508   g_value_set_boxed (value, structure);
1509 }
1510
1511 /**
1512  * gst_value_get_structure:
1513  * @value: a GValue initialized to GST_TYPE_STRUCTURE
1514  *
1515  * Gets the contents of @value.
1516  *
1517  * Returns: (transfer none): the contents of @value
1518  *
1519  * Since: 0.10.15
1520  */
1521 const GstStructure *
1522 gst_value_get_structure (const GValue * value)
1523 {
1524   g_return_val_if_fail (G_IS_VALUE (value), NULL);
1525   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, NULL);
1526
1527   return (GstStructure *) g_value_get_boxed (value);
1528 }
1529
1530 static gchar *
1531 gst_value_serialize_structure (const GValue * value)
1532 {
1533   GstStructure *structure = g_value_get_boxed (value);
1534
1535   return gst_string_take_and_wrap (gst_structure_to_string (structure));
1536 }
1537
1538 static gboolean
1539 gst_value_deserialize_structure (GValue * dest, const gchar * s)
1540 {
1541   GstStructure *structure;
1542
1543   if (*s != '"') {
1544     structure = gst_structure_from_string (s, NULL);
1545   } else {
1546     gchar *str = gst_string_unwrap (s);
1547
1548     if (G_UNLIKELY (!str))
1549       return FALSE;
1550
1551     structure = gst_structure_from_string (str, NULL);
1552     g_free (str);
1553   }
1554
1555   if (G_LIKELY (structure)) {
1556     g_value_take_boxed (dest, structure);
1557     return TRUE;
1558   }
1559   return FALSE;
1560 }
1561
1562 /*************
1563  * GstBuffer *
1564  *************/
1565
1566 static gint
1567 gst_value_compare_buffer (const GValue * value1, const GValue * value2)
1568 {
1569   GstBuffer *buf1 = gst_value_get_buffer (value1);
1570   GstBuffer *buf2 = gst_value_get_buffer (value2);
1571   gsize size1, size2;
1572   gpointer data1, data2;
1573   gint result = GST_VALUE_UNORDERED;
1574
1575   size1 = gst_buffer_get_size (buf1);
1576   size2 = gst_buffer_get_size (buf2);
1577
1578   if (size1 != size2)
1579     return GST_VALUE_UNORDERED;
1580
1581   if (size1 == 0)
1582     return GST_VALUE_EQUAL;
1583
1584   data1 = gst_buffer_map (buf1, &size1, NULL, GST_MAP_READ);
1585   data2 = gst_buffer_map (buf2, &size2, NULL, GST_MAP_READ);
1586   g_assert (data1);
1587   g_assert (data2);
1588
1589   if (memcmp (data1, data2, size1) == 0)
1590     result = GST_VALUE_EQUAL;
1591
1592   gst_buffer_unmap (buf2, data2, size2);
1593   gst_buffer_unmap (buf1, data1, size1);
1594
1595   return result;
1596 }
1597
1598 static gchar *
1599 gst_value_serialize_buffer (const GValue * value)
1600 {
1601   guint8 *data;
1602   gint i;
1603   gsize size;
1604   gchar *string;
1605   GstBuffer *buffer;
1606
1607   buffer = gst_value_get_buffer (value);
1608   if (buffer == NULL)
1609     return NULL;
1610
1611   data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
1612
1613   string = g_malloc (size * 2 + 1);
1614   for (i = 0; i < size; i++) {
1615     sprintf (string + i * 2, "%02x", data[i]);
1616   }
1617   string[size * 2] = 0;
1618
1619   gst_buffer_unmap (buffer, data, size);
1620
1621   return string;
1622 }
1623
1624 static gboolean
1625 gst_value_deserialize_buffer (GValue * dest, const gchar * s)
1626 {
1627   GstBuffer *buffer;
1628   gint len;
1629   gchar ts[3];
1630   guint8 *data;
1631   gint i;
1632   gsize size;
1633
1634   len = strlen (s);
1635   if (len & 1)
1636     goto wrong_length;
1637
1638   buffer = gst_buffer_new_allocate (NULL, len / 2, 0);
1639   data = gst_buffer_map (buffer, &size, NULL, GST_MAP_WRITE);
1640
1641   for (i = 0; i < len / 2; i++) {
1642     if (!isxdigit ((int) s[i * 2]) || !isxdigit ((int) s[i * 2 + 1]))
1643       goto wrong_char;
1644
1645     ts[0] = s[i * 2 + 0];
1646     ts[1] = s[i * 2 + 1];
1647     ts[2] = 0;
1648
1649     data[i] = (guint8) strtoul (ts, NULL, 16);
1650   }
1651   gst_buffer_unmap (buffer, data, size);
1652
1653   gst_value_take_buffer (dest, buffer);
1654
1655   return TRUE;
1656
1657   /* ERRORS */
1658 wrong_length:
1659   {
1660     return FALSE;
1661   }
1662 wrong_char:
1663   {
1664     gst_buffer_unref (buffer);
1665     gst_buffer_unmap (buffer, data, size);
1666     return FALSE;
1667   }
1668 }
1669
1670
1671 /***********
1672  * boolean *
1673  ***********/
1674
1675 static gint
1676 gst_value_compare_boolean (const GValue * value1, const GValue * value2)
1677 {
1678   if ((value1->data[0].v_int != 0) == (value2->data[0].v_int != 0))
1679     return GST_VALUE_EQUAL;
1680   return GST_VALUE_UNORDERED;
1681 }
1682
1683 static gchar *
1684 gst_value_serialize_boolean (const GValue * value)
1685 {
1686   if (value->data[0].v_int) {
1687     return g_strdup ("true");
1688   }
1689   return g_strdup ("false");
1690 }
1691
1692 static gboolean
1693 gst_value_deserialize_boolean (GValue * dest, const gchar * s)
1694 {
1695   gboolean ret = FALSE;
1696
1697   if (g_ascii_strcasecmp (s, "true") == 0 ||
1698       g_ascii_strcasecmp (s, "yes") == 0 ||
1699       g_ascii_strcasecmp (s, "t") == 0 || strcmp (s, "1") == 0) {
1700     g_value_set_boolean (dest, TRUE);
1701     ret = TRUE;
1702   } else if (g_ascii_strcasecmp (s, "false") == 0 ||
1703       g_ascii_strcasecmp (s, "no") == 0 ||
1704       g_ascii_strcasecmp (s, "f") == 0 || strcmp (s, "0") == 0) {
1705     g_value_set_boolean (dest, FALSE);
1706     ret = TRUE;
1707   }
1708
1709   return ret;
1710 }
1711
1712 #define CREATE_SERIALIZATION_START(_type,_macro)                        \
1713 static gint                                                             \
1714 gst_value_compare_ ## _type                                             \
1715 (const GValue * value1, const GValue * value2)                          \
1716 {                                                                       \
1717   g ## _type val1 = g_value_get_ ## _type (value1);                     \
1718   g ## _type val2 = g_value_get_ ## _type (value2);                     \
1719   if (val1 > val2)                                                      \
1720     return GST_VALUE_GREATER_THAN;                                      \
1721   if (val1 < val2)                                                      \
1722     return GST_VALUE_LESS_THAN;                                         \
1723   return GST_VALUE_EQUAL;                                               \
1724 }                                                                       \
1725                                                                         \
1726 static gchar *                                                          \
1727 gst_value_serialize_ ## _type (const GValue * value)                    \
1728 {                                                                       \
1729   GValue val = { 0, };                                                  \
1730   g_value_init (&val, G_TYPE_STRING);                                   \
1731   if (!g_value_transform (value, &val))                                 \
1732     g_assert_not_reached ();                                            \
1733   /* NO_COPY_MADNESS!!! */                                              \
1734   return (char *) g_value_get_string (&val);                            \
1735 }
1736
1737 /* deserialize the given s into to as a gint64.
1738  * check if the result is actually storeable in the given size number of
1739  * bytes.
1740  */
1741 static gboolean
1742 gst_value_deserialize_int_helper (gint64 * to, const gchar * s,
1743     gint64 min, gint64 max, gint size)
1744 {
1745   gboolean ret = FALSE;
1746   gchar *end;
1747   gint64 mask = -1;
1748
1749   errno = 0;
1750   *to = g_ascii_strtoull (s, &end, 0);
1751   /* a range error is a definitive no-no */
1752   if (errno == ERANGE) {
1753     return FALSE;
1754   }
1755
1756   if (*end == 0) {
1757     ret = TRUE;
1758   } else {
1759     if (g_ascii_strcasecmp (s, "little_endian") == 0) {
1760       *to = G_LITTLE_ENDIAN;
1761       ret = TRUE;
1762     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {
1763       *to = G_BIG_ENDIAN;
1764       ret = TRUE;
1765     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {
1766       *to = G_BYTE_ORDER;
1767       ret = TRUE;
1768     } else if (g_ascii_strcasecmp (s, "min") == 0) {
1769       *to = min;
1770       ret = TRUE;
1771     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1772       *to = max;
1773       ret = TRUE;
1774     }
1775   }
1776   if (ret) {
1777     /* by definition, a gint64 fits into a gint64; so ignore those */
1778     if (size != sizeof (mask)) {
1779       if (*to >= 0) {
1780         /* for positive numbers, we create a mask of 1's outside of the range
1781          * and 0's inside the range.  An and will thus keep only 1 bits
1782          * outside of the range */
1783         mask <<= (size * 8);
1784         if ((mask & *to) != 0) {
1785           ret = FALSE;
1786         }
1787       } else {
1788         /* for negative numbers, we do a 2's complement version */
1789         mask <<= ((size * 8) - 1);
1790         if ((mask & *to) != mask) {
1791           ret = FALSE;
1792         }
1793       }
1794     }
1795   }
1796   return ret;
1797 }
1798
1799 #define CREATE_SERIALIZATION(_type,_macro)                              \
1800 CREATE_SERIALIZATION_START(_type,_macro)                                \
1801                                                                         \
1802 static gboolean                                                         \
1803 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
1804 {                                                                       \
1805   gint64 x;                                                             \
1806                                                                         \
1807   if (gst_value_deserialize_int_helper (&x, s, G_MIN ## _macro,         \
1808       G_MAX ## _macro, sizeof (g ## _type))) {                          \
1809     g_value_set_ ## _type (dest, /*(g ## _type)*/ x);                   \
1810     return TRUE;                                                        \
1811   } else {                                                              \
1812     return FALSE;                                                       \
1813   }                                                                     \
1814 }
1815
1816 #define CREATE_USERIALIZATION(_type,_macro)                             \
1817 CREATE_SERIALIZATION_START(_type,_macro)                                \
1818                                                                         \
1819 static gboolean                                                         \
1820 gst_value_deserialize_ ## _type (GValue * dest, const gchar *s)         \
1821 {                                                                       \
1822   gint64 x;                                                             \
1823   gchar *end;                                                           \
1824   gboolean ret = FALSE;                                                 \
1825                                                                         \
1826   errno = 0;                                                            \
1827   x = g_ascii_strtoull (s, &end, 0);                                    \
1828   /* a range error is a definitive no-no */                             \
1829   if (errno == ERANGE) {                                                \
1830     return FALSE;                                                       \
1831   }                                                                     \
1832   /* the cast ensures the range check later on makes sense */           \
1833   x = (g ## _type) x;                                                   \
1834   if (*end == 0) {                                                      \
1835     ret = TRUE;                                                         \
1836   } else {                                                              \
1837     if (g_ascii_strcasecmp (s, "little_endian") == 0) {                 \
1838       x = G_LITTLE_ENDIAN;                                              \
1839       ret = TRUE;                                                       \
1840     } else if (g_ascii_strcasecmp (s, "big_endian") == 0) {             \
1841       x = G_BIG_ENDIAN;                                                 \
1842       ret = TRUE;                                                       \
1843     } else if (g_ascii_strcasecmp (s, "byte_order") == 0) {             \
1844       x = G_BYTE_ORDER;                                                 \
1845       ret = TRUE;                                                       \
1846     } else if (g_ascii_strcasecmp (s, "min") == 0) {                    \
1847       x = 0;                                                            \
1848       ret = TRUE;                                                       \
1849     } else if (g_ascii_strcasecmp (s, "max") == 0) {                    \
1850       x = G_MAX ## _macro;                                              \
1851       ret = TRUE;                                                       \
1852     }                                                                   \
1853   }                                                                     \
1854   if (ret) {                                                            \
1855     if (x > G_MAX ## _macro) {                                          \
1856       ret = FALSE;                                                      \
1857     } else {                                                            \
1858       g_value_set_ ## _type (dest, x);                                  \
1859     }                                                                   \
1860   }                                                                     \
1861   return ret;                                                           \
1862 }
1863
1864 #define REGISTER_SERIALIZATION(_gtype, _type)                           \
1865 G_STMT_START {                                                          \
1866   static const GstValueTable gst_value = {                              \
1867     _gtype,                                                             \
1868     gst_value_compare_ ## _type,                                        \
1869     gst_value_serialize_ ## _type,                                      \
1870     gst_value_deserialize_ ## _type,                                    \
1871   };                                                                    \
1872                                                                         \
1873   gst_value_register (&gst_value);                                      \
1874 } G_STMT_END
1875
1876 CREATE_SERIALIZATION (int, INT);
1877 CREATE_SERIALIZATION (int64, INT64);
1878 CREATE_SERIALIZATION (long, LONG);
1879
1880 CREATE_USERIALIZATION (uint, UINT);
1881 CREATE_USERIALIZATION (uint64, UINT64);
1882 CREATE_USERIALIZATION (ulong, ULONG);
1883
1884 /* FIXME 0.11: remove this again, plugins shouldn't have uchar properties */
1885 #ifndef G_MAXUCHAR
1886 #define G_MAXUCHAR 255
1887 #endif
1888 CREATE_USERIALIZATION (uchar, UCHAR);
1889
1890 /**********
1891  * double *
1892  **********/
1893 static gint
1894 gst_value_compare_double (const GValue * value1, const GValue * value2)
1895 {
1896   if (value1->data[0].v_double > value2->data[0].v_double)
1897     return GST_VALUE_GREATER_THAN;
1898   if (value1->data[0].v_double < value2->data[0].v_double)
1899     return GST_VALUE_LESS_THAN;
1900   if (value1->data[0].v_double == value2->data[0].v_double)
1901     return GST_VALUE_EQUAL;
1902   return GST_VALUE_UNORDERED;
1903 }
1904
1905 static gchar *
1906 gst_value_serialize_double (const GValue * value)
1907 {
1908   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
1909
1910   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_double);
1911   return g_strdup (d);
1912 }
1913
1914 static gboolean
1915 gst_value_deserialize_double (GValue * dest, const gchar * s)
1916 {
1917   gdouble x;
1918   gboolean ret = FALSE;
1919   gchar *end;
1920
1921   x = g_ascii_strtod (s, &end);
1922   if (*end == 0) {
1923     ret = TRUE;
1924   } else {
1925     if (g_ascii_strcasecmp (s, "min") == 0) {
1926       x = -G_MAXDOUBLE;
1927       ret = TRUE;
1928     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1929       x = G_MAXDOUBLE;
1930       ret = TRUE;
1931     }
1932   }
1933   if (ret) {
1934     g_value_set_double (dest, x);
1935   }
1936   return ret;
1937 }
1938
1939 /*********
1940  * float *
1941  *********/
1942
1943 static gint
1944 gst_value_compare_float (const GValue * value1, const GValue * value2)
1945 {
1946   if (value1->data[0].v_float > value2->data[0].v_float)
1947     return GST_VALUE_GREATER_THAN;
1948   if (value1->data[0].v_float < value2->data[0].v_float)
1949     return GST_VALUE_LESS_THAN;
1950   if (value1->data[0].v_float == value2->data[0].v_float)
1951     return GST_VALUE_EQUAL;
1952   return GST_VALUE_UNORDERED;
1953 }
1954
1955 static gchar *
1956 gst_value_serialize_float (const GValue * value)
1957 {
1958   gchar d[G_ASCII_DTOSTR_BUF_SIZE];
1959
1960   g_ascii_dtostr (d, G_ASCII_DTOSTR_BUF_SIZE, value->data[0].v_float);
1961   return g_strdup (d);
1962 }
1963
1964 static gboolean
1965 gst_value_deserialize_float (GValue * dest, const gchar * s)
1966 {
1967   gdouble x;
1968   gboolean ret = FALSE;
1969   gchar *end;
1970
1971   x = g_ascii_strtod (s, &end);
1972   if (*end == 0) {
1973     ret = TRUE;
1974   } else {
1975     if (g_ascii_strcasecmp (s, "min") == 0) {
1976       x = -G_MAXFLOAT;
1977       ret = TRUE;
1978     } else if (g_ascii_strcasecmp (s, "max") == 0) {
1979       x = G_MAXFLOAT;
1980       ret = TRUE;
1981     }
1982   }
1983   if (x > G_MAXFLOAT || x < -G_MAXFLOAT)
1984     ret = FALSE;
1985   if (ret) {
1986     g_value_set_float (dest, (float) x);
1987   }
1988   return ret;
1989 }
1990
1991 /**********
1992  * string *
1993  **********/
1994
1995 static gint
1996 gst_value_compare_string (const GValue * value1, const GValue * value2)
1997 {
1998   if (G_UNLIKELY (!value1->data[0].v_pointer || !value2->data[0].v_pointer)) {
1999     /* if only one is NULL, no match - otherwise both NULL == EQUAL */
2000     if (value1->data[0].v_pointer != value2->data[0].v_pointer)
2001       return GST_VALUE_UNORDERED;
2002   } else {
2003     gint x = strcmp (value1->data[0].v_pointer, value2->data[0].v_pointer);
2004
2005     if (x < 0)
2006       return GST_VALUE_LESS_THAN;
2007     if (x > 0)
2008       return GST_VALUE_GREATER_THAN;
2009   }
2010
2011   return GST_VALUE_EQUAL;
2012 }
2013
2014 static gint
2015 gst_string_measure_wrapping (const gchar * s)
2016 {
2017   gint len;
2018   gboolean wrap = FALSE;
2019
2020   if (G_UNLIKELY (s == NULL))
2021     return -1;
2022
2023   /* Special case: the actual string NULL needs wrapping */
2024   if (G_UNLIKELY (strcmp (s, "NULL") == 0))
2025     return 4;
2026
2027   len = 0;
2028   while (*s) {
2029     if (GST_ASCII_IS_STRING (*s)) {
2030       len++;
2031     } else if (*s < 0x20 || *s >= 0x7f) {
2032       wrap = TRUE;
2033       len += 4;
2034     } else {
2035       wrap = TRUE;
2036       len += 2;
2037     }
2038     s++;
2039   }
2040
2041   /* Wrap the string if we found something that needs
2042    * wrapping, or the empty string (len == 0) */
2043   return (wrap || len == 0) ? len : -1;
2044 }
2045
2046 static gchar *
2047 gst_string_wrap_inner (const gchar * s, gint len)
2048 {
2049   gchar *d, *e;
2050
2051   e = d = g_malloc (len + 3);
2052
2053   *e++ = '\"';
2054   while (*s) {
2055     if (GST_ASCII_IS_STRING (*s)) {
2056       *e++ = *s++;
2057     } else if (*s < 0x20 || *s >= 0x7f) {
2058       *e++ = '\\';
2059       *e++ = '0' + ((*(guchar *) s) >> 6);
2060       *e++ = '0' + (((*s) >> 3) & 0x7);
2061       *e++ = '0' + ((*s++) & 0x7);
2062     } else {
2063       *e++ = '\\';
2064       *e++ = *s++;
2065     }
2066   }
2067   *e++ = '\"';
2068   *e = 0;
2069
2070   g_assert (e - d <= len + 3);
2071   return d;
2072 }
2073
2074 /* Do string wrapping/escaping */
2075 static gchar *
2076 gst_string_wrap (const gchar * s)
2077 {
2078   gint len = gst_string_measure_wrapping (s);
2079
2080   if (G_LIKELY (len < 0))
2081     return g_strdup (s);
2082
2083   return gst_string_wrap_inner (s, len);
2084 }
2085
2086 /* Same as above, but take ownership of the string */
2087 static gchar *
2088 gst_string_take_and_wrap (gchar * s)
2089 {
2090   gchar *out;
2091   gint len = gst_string_measure_wrapping (s);
2092
2093   if (G_LIKELY (len < 0))
2094     return s;
2095
2096   out = gst_string_wrap_inner (s, len);
2097   g_free (s);
2098
2099   return out;
2100 }
2101
2102 /*
2103  * This function takes a string delimited with double quotes (")
2104  * and unescapes any \xxx octal numbers.
2105  *
2106  * If sequences of \y are found where y is not in the range of
2107  * 0->3, y is copied unescaped.
2108  *
2109  * If \xyy is found where x is an octal number but y is not, an
2110  * error is encountered and NULL is returned.
2111  *
2112  * the input string must be \0 terminated.
2113  */
2114 static gchar *
2115 gst_string_unwrap (const gchar * s)
2116 {
2117   gchar *ret;
2118   gchar *read, *write;
2119
2120   /* NULL string returns NULL */
2121   if (s == NULL)
2122     return NULL;
2123
2124   /* strings not starting with " are invalid */
2125   if (*s != '"')
2126     return NULL;
2127
2128   /* make copy of original string to hold the result. This
2129    * string will always be smaller than the original */
2130   ret = g_strdup (s);
2131   read = ret;
2132   write = ret;
2133
2134   /* need to move to the next position as we parsed the " */
2135   read++;
2136
2137   while (*read) {
2138     if (GST_ASCII_IS_STRING (*read)) {
2139       /* normal chars are just copied */
2140       *write++ = *read++;
2141     } else if (*read == '"') {
2142       /* quote marks end of string */
2143       break;
2144     } else if (*read == '\\') {
2145       /* got an escape char, move to next position to read a tripplet
2146        * of octal numbers */
2147       read++;
2148       /* is the next char a possible first octal number? */
2149       if (*read >= '0' && *read <= '3') {
2150         /* parse other 2 numbers, if one of them is not in the range of
2151          * an octal number, we error. We also catch the case where a zero
2152          * byte is found here. */
2153         if (read[1] < '0' || read[1] > '7' || read[2] < '0' || read[2] > '7')
2154           goto beach;
2155
2156         /* now convert the octal number to a byte again. */
2157         *write++ = ((read[0] - '0') << 6) +
2158             ((read[1] - '0') << 3) + (read[2] - '0');
2159
2160         read += 3;
2161       } else {
2162         /* if we run into a \0 here, we definately won't get a quote later */
2163         if (*read == 0)
2164           goto beach;
2165
2166         /* else copy \X sequence */
2167         *write++ = *read++;
2168       }
2169     } else {
2170       /* weird character, error */
2171       goto beach;
2172     }
2173   }
2174   /* if the string is not ending in " and zero terminated, we error */
2175   if (*read != '"' || read[1] != '\0')
2176     goto beach;
2177
2178   /* null terminate result string and return */
2179   *write = '\0';
2180   return ret;
2181
2182 beach:
2183   g_free (ret);
2184   return NULL;
2185 }
2186
2187 static gchar *
2188 gst_value_serialize_string (const GValue * value)
2189 {
2190   return gst_string_wrap (value->data[0].v_pointer);
2191 }
2192
2193 static gboolean
2194 gst_value_deserialize_string (GValue * dest, const gchar * s)
2195 {
2196   if (G_UNLIKELY (strcmp (s, "NULL") == 0)) {
2197     g_value_set_string (dest, NULL);
2198     return TRUE;
2199   } else if (G_LIKELY (*s != '"')) {
2200     if (!g_utf8_validate (s, -1, NULL))
2201       return FALSE;
2202     g_value_set_string (dest, s);
2203     return TRUE;
2204   } else {
2205     gchar *str = gst_string_unwrap (s);
2206     if (G_UNLIKELY (!str))
2207       return FALSE;
2208     g_value_take_string (dest, str);
2209   }
2210
2211   return TRUE;
2212 }
2213
2214 /********
2215  * enum *
2216  ********/
2217
2218 static gint
2219 gst_value_compare_enum (const GValue * value1, const GValue * value2)
2220 {
2221   GEnumValue *en1, *en2;
2222   GEnumClass *klass1 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value1));
2223   GEnumClass *klass2 = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value2));
2224
2225   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
2226   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
2227   en1 = g_enum_get_value (klass1, g_value_get_enum (value1));
2228   en2 = g_enum_get_value (klass2, g_value_get_enum (value2));
2229   g_type_class_unref (klass1);
2230   g_type_class_unref (klass2);
2231   g_return_val_if_fail (en1, GST_VALUE_UNORDERED);
2232   g_return_val_if_fail (en2, GST_VALUE_UNORDERED);
2233   if (en1->value < en2->value)
2234     return GST_VALUE_LESS_THAN;
2235   if (en1->value > en2->value)
2236     return GST_VALUE_GREATER_THAN;
2237
2238   return GST_VALUE_EQUAL;
2239 }
2240
2241 static gchar *
2242 gst_value_serialize_enum (const GValue * value)
2243 {
2244   GEnumValue *en;
2245   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (value));
2246
2247   g_return_val_if_fail (klass, NULL);
2248   en = g_enum_get_value (klass, g_value_get_enum (value));
2249   g_type_class_unref (klass);
2250
2251   /* might be one of the custom formats registered later */
2252   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (value) == GST_TYPE_FORMAT)) {
2253     const GstFormatDefinition *format_def;
2254
2255     format_def = gst_format_get_details (g_value_get_enum (value));
2256     g_return_val_if_fail (format_def != NULL, NULL);
2257     return g_strdup (format_def->description);
2258   }
2259
2260   g_return_val_if_fail (en, NULL);
2261   return g_strdup (en->value_name);
2262 }
2263
2264 static gint
2265 gst_value_deserialize_enum_iter_cmp (const GValue * format_def_value,
2266     const gchar * s)
2267 {
2268   const GstFormatDefinition *format_def =
2269       g_value_get_pointer (format_def_value);
2270
2271   if (g_ascii_strcasecmp (s, format_def->nick) == 0)
2272     return 0;
2273
2274   return g_ascii_strcasecmp (s, format_def->description);
2275 }
2276
2277 static gboolean
2278 gst_value_deserialize_enum (GValue * dest, const gchar * s)
2279 {
2280   GEnumValue *en;
2281   gchar *endptr = NULL;
2282   GEnumClass *klass = (GEnumClass *) g_type_class_ref (G_VALUE_TYPE (dest));
2283
2284   g_return_val_if_fail (klass, FALSE);
2285   if (!(en = g_enum_get_value_by_name (klass, s))) {
2286     if (!(en = g_enum_get_value_by_nick (klass, s))) {
2287       gint i = strtol (s, &endptr, 0);
2288
2289       if (endptr && *endptr == '\0') {
2290         en = g_enum_get_value (klass, i);
2291       }
2292     }
2293   }
2294   g_type_class_unref (klass);
2295
2296   /* might be one of the custom formats registered later */
2297   if (G_UNLIKELY (en == NULL && G_VALUE_TYPE (dest) == GST_TYPE_FORMAT)) {
2298     GValue res = { 0, };
2299     const GstFormatDefinition *format_def;
2300     GstIterator *iter;
2301     gboolean found;
2302
2303     iter = gst_format_iterate_definitions ();
2304
2305     found = gst_iterator_find_custom (iter,
2306         (GCompareFunc) gst_value_deserialize_enum_iter_cmp, &res, (gpointer) s);
2307
2308     g_return_val_if_fail (found, FALSE);
2309     format_def = g_value_get_pointer (&res);
2310     g_return_val_if_fail (format_def != NULL, FALSE);
2311     g_value_set_enum (dest, (gint) format_def->value);
2312     g_value_unset (&res);
2313     gst_iterator_free (iter);
2314     return TRUE;
2315   }
2316
2317   g_return_val_if_fail (en, FALSE);
2318   g_value_set_enum (dest, en->value);
2319   return TRUE;
2320 }
2321
2322 /********
2323  * flags *
2324  ********/
2325
2326 /* we just compare the value here */
2327 static gint
2328 gst_value_compare_flags (const GValue * value1, const GValue * value2)
2329 {
2330   guint fl1, fl2;
2331   GFlagsClass *klass1 =
2332       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value1));
2333   GFlagsClass *klass2 =
2334       (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value2));
2335
2336   g_return_val_if_fail (klass1, GST_VALUE_UNORDERED);
2337   g_return_val_if_fail (klass2, GST_VALUE_UNORDERED);
2338   fl1 = g_value_get_flags (value1);
2339   fl2 = g_value_get_flags (value2);
2340   g_type_class_unref (klass1);
2341   g_type_class_unref (klass2);
2342   if (fl1 < fl2)
2343     return GST_VALUE_LESS_THAN;
2344   if (fl1 > fl2)
2345     return GST_VALUE_GREATER_THAN;
2346
2347   return GST_VALUE_EQUAL;
2348 }
2349
2350 /* the different flags are serialized separated with a + */
2351 static gchar *
2352 gst_value_serialize_flags (const GValue * value)
2353 {
2354   guint flags;
2355   GFlagsValue *fl;
2356   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (value));
2357   gchar *result, *tmp;
2358   gboolean first = TRUE;
2359
2360   g_return_val_if_fail (klass, NULL);
2361
2362   flags = g_value_get_flags (value);
2363
2364   /* if no flags are set, try to serialize to the _NONE string */
2365   if (!flags) {
2366     fl = g_flags_get_first_value (klass, flags);
2367     return g_strdup (fl->value_name);
2368   }
2369
2370   /* some flags are set, so serialize one by one */
2371   result = g_strdup ("");
2372   while (flags) {
2373     fl = g_flags_get_first_value (klass, flags);
2374     if (fl != NULL) {
2375       tmp = g_strconcat (result, (first ? "" : "+"), fl->value_name, NULL);
2376       g_free (result);
2377       result = tmp;
2378       first = FALSE;
2379
2380       /* clear flag */
2381       flags &= ~fl->value;
2382     }
2383   }
2384   g_type_class_unref (klass);
2385
2386   return result;
2387 }
2388
2389 static gboolean
2390 gst_value_deserialize_flags (GValue * dest, const gchar * s)
2391 {
2392   GFlagsValue *fl;
2393   gchar *endptr = NULL;
2394   GFlagsClass *klass = (GFlagsClass *) g_type_class_ref (G_VALUE_TYPE (dest));
2395   gchar **split;
2396   guint flags;
2397   gint i;
2398
2399   g_return_val_if_fail (klass, FALSE);
2400
2401   /* split into parts delimited with + */
2402   split = g_strsplit (s, "+", 0);
2403
2404   flags = 0;
2405   i = 0;
2406   /* loop over each part */
2407   while (split[i]) {
2408     if (!(fl = g_flags_get_value_by_name (klass, split[i]))) {
2409       if (!(fl = g_flags_get_value_by_nick (klass, split[i]))) {
2410         gint val = strtol (split[i], &endptr, 0);
2411
2412         /* just or numeric value */
2413         if (endptr && *endptr == '\0') {
2414           flags |= val;
2415         }
2416       }
2417     }
2418     if (fl) {
2419       flags |= fl->value;
2420     }
2421     i++;
2422   }
2423   g_strfreev (split);
2424   g_type_class_unref (klass);
2425   g_value_set_flags (dest, flags);
2426
2427   return TRUE;
2428 }
2429
2430 /*********
2431  * union *
2432  *********/
2433
2434 static gboolean
2435 gst_value_union_int_int_range (GValue * dest, const GValue * src1,
2436     const GValue * src2)
2437 {
2438   if (src2->data[0].v_int <= src1->data[0].v_int &&
2439       src2->data[1].v_int >= src1->data[0].v_int) {
2440     gst_value_init_and_copy (dest, src2);
2441     return TRUE;
2442   }
2443   return FALSE;
2444 }
2445
2446 static gboolean
2447 gst_value_union_int_range_int_range (GValue * dest, const GValue * src1,
2448     const GValue * src2)
2449 {
2450   gint min;
2451   gint max;
2452
2453   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
2454   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
2455
2456   if (min <= max) {
2457     g_value_init (dest, GST_TYPE_INT_RANGE);
2458     gst_value_set_int_range (dest,
2459         MIN (src1->data[0].v_int, src2->data[0].v_int),
2460         MAX (src1->data[1].v_int, src2->data[1].v_int));
2461     return TRUE;
2462   }
2463
2464   return FALSE;
2465 }
2466
2467 /****************
2468  * intersection *
2469  ****************/
2470
2471 static gboolean
2472 gst_value_intersect_int_int_range (GValue * dest, const GValue * src1,
2473     const GValue * src2)
2474 {
2475   if (src2->data[0].v_int <= src1->data[0].v_int &&
2476       src2->data[1].v_int >= src1->data[0].v_int) {
2477     gst_value_init_and_copy (dest, src1);
2478     return TRUE;
2479   }
2480
2481   return FALSE;
2482 }
2483
2484 static gboolean
2485 gst_value_intersect_int_range_int_range (GValue * dest, const GValue * src1,
2486     const GValue * src2)
2487 {
2488   gint min;
2489   gint max;
2490
2491   min = MAX (src1->data[0].v_int, src2->data[0].v_int);
2492   max = MIN (src1->data[1].v_int, src2->data[1].v_int);
2493
2494   if (min < max) {
2495     g_value_init (dest, GST_TYPE_INT_RANGE);
2496     gst_value_set_int_range (dest, min, max);
2497     return TRUE;
2498   }
2499   if (min == max) {
2500     g_value_init (dest, G_TYPE_INT);
2501     g_value_set_int (dest, min);
2502     return TRUE;
2503   }
2504
2505   return FALSE;
2506 }
2507
2508 static gboolean
2509 gst_value_intersect_int64_int64_range (GValue * dest, const GValue * src1,
2510     const GValue * src2)
2511 {
2512   if (src2->data[0].v_int64 <= src1->data[0].v_int64 &&
2513       src2->data[1].v_int64 >= src1->data[0].v_int64) {
2514     gst_value_init_and_copy (dest, src1);
2515     return TRUE;
2516   }
2517
2518   return FALSE;
2519 }
2520
2521 static gboolean
2522 gst_value_intersect_int64_range_int64_range (GValue * dest, const GValue * src1,
2523     const GValue * src2)
2524 {
2525   gint64 min;
2526   gint64 max;
2527
2528   min = MAX (src1->data[0].v_int64, src2->data[0].v_int64);
2529   max = MIN (src1->data[1].v_int64, src2->data[1].v_int64);
2530
2531   if (min < max) {
2532     g_value_init (dest, GST_TYPE_INT64_RANGE);
2533     gst_value_set_int64_range (dest, min, max);
2534     return TRUE;
2535   }
2536   if (min == max) {
2537     g_value_init (dest, G_TYPE_INT64);
2538     g_value_set_int64 (dest, min);
2539     return TRUE;
2540   }
2541
2542   return FALSE;
2543 }
2544
2545 static gboolean
2546 gst_value_intersect_double_double_range (GValue * dest, const GValue * src1,
2547     const GValue * src2)
2548 {
2549   if (src2->data[0].v_double <= src1->data[0].v_double &&
2550       src2->data[1].v_double >= src1->data[0].v_double) {
2551     gst_value_init_and_copy (dest, src1);
2552     return TRUE;
2553   }
2554
2555   return FALSE;
2556 }
2557
2558 static gboolean
2559 gst_value_intersect_double_range_double_range (GValue * dest,
2560     const GValue * src1, const GValue * src2)
2561 {
2562   gdouble min;
2563   gdouble max;
2564
2565   min = MAX (src1->data[0].v_double, src2->data[0].v_double);
2566   max = MIN (src1->data[1].v_double, src2->data[1].v_double);
2567
2568   if (min < max) {
2569     g_value_init (dest, GST_TYPE_DOUBLE_RANGE);
2570     gst_value_set_double_range (dest, min, max);
2571     return TRUE;
2572   }
2573   if (min == max) {
2574     g_value_init (dest, G_TYPE_DOUBLE);
2575     g_value_set_int (dest, (int) min);
2576     return TRUE;
2577   }
2578
2579   return FALSE;
2580 }
2581
2582 static gboolean
2583 gst_value_intersect_list (GValue * dest, const GValue * value1,
2584     const GValue * value2)
2585 {
2586   guint i, size;
2587   GValue intersection = { 0, };
2588   gboolean ret = FALSE;
2589
2590   size = VALUE_LIST_SIZE (value1);
2591   for (i = 0; i < size; i++) {
2592     const GValue *cur = VALUE_LIST_GET_VALUE (value1, i);
2593
2594     if (gst_value_intersect (&intersection, cur, value2)) {
2595       /* append value */
2596       if (!ret) {
2597         gst_value_init_and_copy (dest, &intersection);
2598         ret = TRUE;
2599       } else if (GST_VALUE_HOLDS_LIST (dest)) {
2600         gst_value_list_append_value (dest, &intersection);
2601       } else {
2602         GValue temp = { 0, };
2603
2604         gst_value_init_and_copy (&temp, dest);
2605         g_value_unset (dest);
2606         gst_value_list_concat (dest, &temp, &intersection);
2607         g_value_unset (&temp);
2608       }
2609       g_value_unset (&intersection);
2610     }
2611   }
2612
2613   return ret;
2614 }
2615
2616 static gboolean
2617 gst_value_intersect_array (GValue * dest, const GValue * src1,
2618     const GValue * src2)
2619 {
2620   guint size;
2621   guint n;
2622   GValue val = { 0 };
2623
2624   /* only works on similar-sized arrays */
2625   size = gst_value_array_get_size (src1);
2626   if (size != gst_value_array_get_size (src2))
2627     return FALSE;
2628   g_value_init (dest, GST_TYPE_ARRAY);
2629
2630   for (n = 0; n < size; n++) {
2631     if (!gst_value_intersect (&val, gst_value_array_get_value (src1, n),
2632             gst_value_array_get_value (src2, n))) {
2633       g_value_unset (dest);
2634       return FALSE;
2635     }
2636     gst_value_array_append_value (dest, &val);
2637     g_value_unset (&val);
2638   }
2639
2640   return TRUE;
2641 }
2642
2643 static gboolean
2644 gst_value_intersect_fraction_fraction_range (GValue * dest, const GValue * src1,
2645     const GValue * src2)
2646 {
2647   gint res1, res2;
2648   GValue *vals;
2649   GstValueCompareFunc compare;
2650
2651   vals = src2->data[0].v_pointer;
2652
2653   if (vals == NULL)
2654     return FALSE;
2655
2656   if ((compare = gst_value_get_compare_func (src1))) {
2657     res1 = gst_value_compare_with_func (&vals[0], src1, compare);
2658     res2 = gst_value_compare_with_func (&vals[1], src1, compare);
2659
2660     if ((res1 == GST_VALUE_EQUAL || res1 == GST_VALUE_LESS_THAN) &&
2661         (res2 == GST_VALUE_EQUAL || res2 == GST_VALUE_GREATER_THAN)) {
2662       gst_value_init_and_copy (dest, src1);
2663       return TRUE;
2664     }
2665   }
2666
2667   return FALSE;
2668 }
2669
2670 static gboolean
2671 gst_value_intersect_fraction_range_fraction_range (GValue * dest,
2672     const GValue * src1, const GValue * src2)
2673 {
2674   GValue *min;
2675   GValue *max;
2676   gint res;
2677   GValue *vals1, *vals2;
2678   GstValueCompareFunc compare;
2679
2680   vals1 = src1->data[0].v_pointer;
2681   vals2 = src2->data[0].v_pointer;
2682   g_return_val_if_fail (vals1 != NULL && vals2 != NULL, FALSE);
2683
2684   if ((compare = gst_value_get_compare_func (&vals1[0]))) {
2685     /* min = MAX (src1.start, src2.start) */
2686     res = gst_value_compare_with_func (&vals1[0], &vals2[0], compare);
2687     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2688     if (res == GST_VALUE_LESS_THAN)
2689       min = &vals2[0];          /* Take the max of the 2 */
2690     else
2691       min = &vals1[0];
2692
2693     /* max = MIN (src1.end, src2.end) */
2694     res = gst_value_compare_with_func (&vals1[1], &vals2[1], compare);
2695     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2696     if (res == GST_VALUE_GREATER_THAN)
2697       max = &vals2[1];          /* Take the min of the 2 */
2698     else
2699       max = &vals1[1];
2700
2701     res = gst_value_compare_with_func (min, max, compare);
2702     g_return_val_if_fail (res != GST_VALUE_UNORDERED, FALSE);
2703     if (res == GST_VALUE_LESS_THAN) {
2704       g_value_init (dest, GST_TYPE_FRACTION_RANGE);
2705       vals1 = dest->data[0].v_pointer;
2706       g_value_copy (min, &vals1[0]);
2707       g_value_copy (max, &vals1[1]);
2708       return TRUE;
2709     }
2710     if (res == GST_VALUE_EQUAL) {
2711       gst_value_init_and_copy (dest, min);
2712       return TRUE;
2713     }
2714   }
2715
2716   return FALSE;
2717 }
2718
2719 /***************
2720  * subtraction *
2721  ***************/
2722
2723 static gboolean
2724 gst_value_subtract_int_int_range (GValue * dest, const GValue * minuend,
2725     const GValue * subtrahend)
2726 {
2727   gint min = gst_value_get_int_range_min (subtrahend);
2728   gint max = gst_value_get_int_range_max (subtrahend);
2729   gint val = g_value_get_int (minuend);
2730
2731   /* subtracting a range from an int only works if the int is not in the
2732    * range */
2733   if (val < min || val > max) {
2734     /* and the result is the int */
2735     gst_value_init_and_copy (dest, minuend);
2736     return TRUE;
2737   }
2738   return FALSE;
2739 }
2740
2741 /* creates a new int range based on input values.
2742  */
2743 static gboolean
2744 gst_value_create_new_range (GValue * dest, gint min1, gint max1, gint min2,
2745     gint max2)
2746 {
2747   GValue v1 = { 0, };
2748   GValue v2 = { 0, };
2749   GValue *pv1, *pv2;            /* yeah, hungarian! */
2750
2751   if (min1 <= max1 && min2 <= max2) {
2752     pv1 = &v1;
2753     pv2 = &v2;
2754   } else if (min1 <= max1) {
2755     pv1 = dest;
2756     pv2 = NULL;
2757   } else if (min2 <= max2) {
2758     pv1 = NULL;
2759     pv2 = dest;
2760   } else {
2761     return FALSE;
2762   }
2763
2764   if (min1 < max1) {
2765     g_value_init (pv1, GST_TYPE_INT_RANGE);
2766     gst_value_set_int_range (pv1, min1, max1);
2767   } else if (min1 == max1) {
2768     g_value_init (pv1, G_TYPE_INT);
2769     g_value_set_int (pv1, min1);
2770   }
2771   if (min2 < max2) {
2772     g_value_init (pv2, GST_TYPE_INT_RANGE);
2773     gst_value_set_int_range (pv2, min2, max2);
2774   } else if (min2 == max2) {
2775     g_value_init (pv2, G_TYPE_INT);
2776     g_value_set_int (pv2, min2);
2777   }
2778
2779   if (min1 <= max1 && min2 <= max2) {
2780     gst_value_list_concat (dest, pv1, pv2);
2781     g_value_unset (pv1);
2782     g_value_unset (pv2);
2783   }
2784   return TRUE;
2785 }
2786
2787 static gboolean
2788 gst_value_subtract_int_range_int (GValue * dest, const GValue * minuend,
2789     const GValue * subtrahend)
2790 {
2791   gint min = gst_value_get_int_range_min (minuend);
2792   gint max = gst_value_get_int_range_max (minuend);
2793   gint val = g_value_get_int (subtrahend);
2794
2795   g_return_val_if_fail (min < max, FALSE);
2796
2797   /* value is outside of the range, return range unchanged */
2798   if (val < min || val > max) {
2799     gst_value_init_and_copy (dest, minuend);
2800     return TRUE;
2801   } else {
2802     /* max must be MAXINT too as val <= max */
2803     if (val == G_MAXINT) {
2804       max--;
2805       val--;
2806     }
2807     /* min must be MININT too as val >= max */
2808     if (val == G_MININT) {
2809       min++;
2810       val++;
2811     }
2812     gst_value_create_new_range (dest, min, val - 1, val + 1, max);
2813   }
2814   return TRUE;
2815 }
2816
2817 static gboolean
2818 gst_value_subtract_int_range_int_range (GValue * dest, const GValue * minuend,
2819     const GValue * subtrahend)
2820 {
2821   gint min1 = gst_value_get_int_range_min (minuend);
2822   gint max1 = gst_value_get_int_range_max (minuend);
2823   gint min2 = gst_value_get_int_range_min (subtrahend);
2824   gint max2 = gst_value_get_int_range_max (subtrahend);
2825
2826   if (max2 == G_MAXINT && min2 == G_MININT) {
2827     return FALSE;
2828   } else if (max2 == G_MAXINT) {
2829     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1), 1, 0);
2830   } else if (min2 == G_MININT) {
2831     return gst_value_create_new_range (dest, MAX (max2 + 1, min1), max1, 1, 0);
2832   } else {
2833     return gst_value_create_new_range (dest, min1, MIN (min2 - 1, max1),
2834         MAX (max2 + 1, min1), max1);
2835   }
2836 }
2837
2838 static gboolean
2839 gst_value_subtract_int64_int64_range (GValue * dest, const GValue * minuend,
2840     const GValue * subtrahend)
2841 {
2842   gint64 min = gst_value_get_int64_range_min (subtrahend);
2843   gint64 max = gst_value_get_int64_range_max (subtrahend);
2844   gint64 val = g_value_get_int64 (minuend);
2845
2846   /* subtracting a range from an int64 only works if the int64 is not in the
2847    * range */
2848   if (val < min || val > max) {
2849     /* and the result is the int64 */
2850     gst_value_init_and_copy (dest, minuend);
2851     return TRUE;
2852   }
2853   return FALSE;
2854 }
2855
2856 /* creates a new int64 range based on input values.
2857  */
2858 static gboolean
2859 gst_value_create_new_int64_range (GValue * dest, gint64 min1, gint64 max1,
2860     gint64 min2, gint64 max2)
2861 {
2862   GValue v1 = { 0, };
2863   GValue v2 = { 0, };
2864   GValue *pv1, *pv2;            /* yeah, hungarian! */
2865
2866   if (min1 <= max1 && min2 <= max2) {
2867     pv1 = &v1;
2868     pv2 = &v2;
2869   } else if (min1 <= max1) {
2870     pv1 = dest;
2871     pv2 = NULL;
2872   } else if (min2 <= max2) {
2873     pv1 = NULL;
2874     pv2 = dest;
2875   } else {
2876     return FALSE;
2877   }
2878
2879   if (min1 < max1) {
2880     g_value_init (pv1, GST_TYPE_INT64_RANGE);
2881     gst_value_set_int64_range (pv1, min1, max1);
2882   } else if (min1 == max1) {
2883     g_value_init (pv1, G_TYPE_INT64);
2884     g_value_set_int64 (pv1, min1);
2885   }
2886   if (min2 < max2) {
2887     g_value_init (pv2, GST_TYPE_INT64_RANGE);
2888     gst_value_set_int64_range (pv2, min2, max2);
2889   } else if (min2 == max2) {
2890     g_value_init (pv2, G_TYPE_INT64);
2891     g_value_set_int64 (pv2, min2);
2892   }
2893
2894   if (min1 <= max1 && min2 <= max2) {
2895     gst_value_list_concat (dest, pv1, pv2);
2896     g_value_unset (pv1);
2897     g_value_unset (pv2);
2898   }
2899   return TRUE;
2900 }
2901
2902 static gboolean
2903 gst_value_subtract_int64_range_int64 (GValue * dest, const GValue * minuend,
2904     const GValue * subtrahend)
2905 {
2906   gint64 min = gst_value_get_int64_range_min (minuend);
2907   gint64 max = gst_value_get_int64_range_max (minuend);
2908   gint64 val = g_value_get_int64 (subtrahend);
2909
2910   g_return_val_if_fail (min < max, FALSE);
2911
2912   /* value is outside of the range, return range unchanged */
2913   if (val < min || val > max) {
2914     gst_value_init_and_copy (dest, minuend);
2915     return TRUE;
2916   } else {
2917     /* max must be MAXINT64 too as val <= max */
2918     if (val == G_MAXINT64) {
2919       max--;
2920       val--;
2921     }
2922     /* min must be MININT64 too as val >= max */
2923     if (val == G_MININT64) {
2924       min++;
2925       val++;
2926     }
2927     gst_value_create_new_int64_range (dest, min, val - 1, val + 1, max);
2928   }
2929   return TRUE;
2930 }
2931
2932 static gboolean
2933 gst_value_subtract_int64_range_int64_range (GValue * dest,
2934     const GValue * minuend, const GValue * subtrahend)
2935 {
2936   gint64 min1 = gst_value_get_int64_range_min (minuend);
2937   gint64 max1 = gst_value_get_int64_range_max (minuend);
2938   gint64 min2 = gst_value_get_int64_range_min (subtrahend);
2939   gint64 max2 = gst_value_get_int64_range_max (subtrahend);
2940
2941   if (max2 == G_MAXINT64 && min2 == G_MININT64) {
2942     return FALSE;
2943   } else if (max2 == G_MAXINT64) {
2944     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - 1, max1),
2945         1, 0);
2946   } else if (min2 == G_MININT64) {
2947     return gst_value_create_new_int64_range (dest, MAX (max2 + 1, min1), max1,
2948         1, 0);
2949   } else {
2950     return gst_value_create_new_int64_range (dest, min1, MIN (min2 - 1, max1),
2951         MAX (max2 + 1, min1), max1);
2952   }
2953 }
2954
2955 static gboolean
2956 gst_value_subtract_double_double_range (GValue * dest, const GValue * minuend,
2957     const GValue * subtrahend)
2958 {
2959   gdouble min = gst_value_get_double_range_min (subtrahend);
2960   gdouble max = gst_value_get_double_range_max (subtrahend);
2961   gdouble val = g_value_get_double (minuend);
2962
2963   if (val < min || val > max) {
2964     gst_value_init_and_copy (dest, minuend);
2965     return TRUE;
2966   }
2967   return FALSE;
2968 }
2969
2970 static gboolean
2971 gst_value_subtract_double_range_double (GValue * dest, const GValue * minuend,
2972     const GValue * subtrahend)
2973 {
2974   /* since we don't have open ranges, we cannot create a hole in
2975    * a double range. We return the original range */
2976   gst_value_init_and_copy (dest, minuend);
2977   return TRUE;
2978 }
2979
2980 static gboolean
2981 gst_value_subtract_double_range_double_range (GValue * dest,
2982     const GValue * minuend, const GValue * subtrahend)
2983 {
2984   /* since we don't have open ranges, we have to approximate */
2985   /* done like with ints */
2986   gdouble min1 = gst_value_get_double_range_min (minuend);
2987   gdouble max2 = gst_value_get_double_range_max (minuend);
2988   gdouble max1 = MIN (gst_value_get_double_range_min (subtrahend), max2);
2989   gdouble min2 = MAX (gst_value_get_double_range_max (subtrahend), min1);
2990   GValue v1 = { 0, };
2991   GValue v2 = { 0, };
2992   GValue *pv1, *pv2;            /* yeah, hungarian! */
2993
2994   if (min1 < max1 && min2 < max2) {
2995     pv1 = &v1;
2996     pv2 = &v2;
2997   } else if (min1 < max1) {
2998     pv1 = dest;
2999     pv2 = NULL;
3000   } else if (min2 < max2) {
3001     pv1 = NULL;
3002     pv2 = dest;
3003   } else {
3004     return FALSE;
3005   }
3006
3007   if (min1 < max1) {
3008     g_value_init (pv1, GST_TYPE_DOUBLE_RANGE);
3009     gst_value_set_double_range (pv1, min1, max1);
3010   }
3011   if (min2 < max2) {
3012     g_value_init (pv2, GST_TYPE_DOUBLE_RANGE);
3013     gst_value_set_double_range (pv2, min2, max2);
3014   }
3015
3016   if (min1 < max1 && min2 < max2) {
3017     gst_value_list_concat (dest, pv1, pv2);
3018     g_value_unset (pv1);
3019     g_value_unset (pv2);
3020   }
3021   return TRUE;
3022 }
3023
3024 static gboolean
3025 gst_value_subtract_from_list (GValue * dest, const GValue * minuend,
3026     const GValue * subtrahend)
3027 {
3028   guint i, size;
3029   GValue subtraction = { 0, };
3030   gboolean ret = FALSE;
3031   GType ltype;
3032
3033   ltype = gst_value_list_get_type ();
3034
3035   size = VALUE_LIST_SIZE (minuend);
3036   for (i = 0; i < size; i++) {
3037     const GValue *cur = VALUE_LIST_GET_VALUE (minuend, i);
3038
3039     if (gst_value_subtract (&subtraction, cur, subtrahend)) {
3040       if (!ret) {
3041         gst_value_init_and_copy (dest, &subtraction);
3042         ret = TRUE;
3043       } else if (G_VALUE_HOLDS (dest, ltype)
3044           && !G_VALUE_HOLDS (&subtraction, ltype)) {
3045         gst_value_list_append_value (dest, &subtraction);
3046       } else {
3047         GValue temp = { 0, };
3048
3049         gst_value_init_and_copy (&temp, dest);
3050         g_value_unset (dest);
3051         gst_value_list_concat (dest, &temp, &subtraction);
3052         g_value_unset (&temp);
3053       }
3054       g_value_unset (&subtraction);
3055     }
3056   }
3057   return ret;
3058 }
3059
3060 static gboolean
3061 gst_value_subtract_list (GValue * dest, const GValue * minuend,
3062     const GValue * subtrahend)
3063 {
3064   guint i, size;
3065   GValue data[2] = { {0,}, {0,} };
3066   GValue *subtraction = &data[0], *result = &data[1];
3067
3068   gst_value_init_and_copy (result, minuend);
3069   size = VALUE_LIST_SIZE (subtrahend);
3070   for (i = 0; i < size; i++) {
3071     const GValue *cur = VALUE_LIST_GET_VALUE (subtrahend, i);
3072
3073     if (gst_value_subtract (subtraction, result, cur)) {
3074       GValue *temp = result;
3075
3076       result = subtraction;
3077       subtraction = temp;
3078       g_value_unset (subtraction);
3079     } else {
3080       g_value_unset (result);
3081       return FALSE;
3082     }
3083   }
3084   gst_value_init_and_copy (dest, result);
3085   g_value_unset (result);
3086   return TRUE;
3087 }
3088
3089 static gboolean
3090 gst_value_subtract_fraction_fraction_range (GValue * dest,
3091     const GValue * minuend, const GValue * subtrahend)
3092 {
3093   const GValue *min = gst_value_get_fraction_range_min (subtrahend);
3094   const GValue *max = gst_value_get_fraction_range_max (subtrahend);
3095   GstValueCompareFunc compare;
3096
3097   if ((compare = gst_value_get_compare_func (minuend))) {
3098     /* subtracting a range from an fraction only works if the fraction
3099      * is not in the range */
3100     if (gst_value_compare_with_func (minuend, min, compare) ==
3101         GST_VALUE_LESS_THAN ||
3102         gst_value_compare_with_func (minuend, max, compare) ==
3103         GST_VALUE_GREATER_THAN) {
3104       /* and the result is the value */
3105       gst_value_init_and_copy (dest, minuend);
3106       return TRUE;
3107     }
3108   }
3109   return FALSE;
3110 }
3111
3112 static gboolean
3113 gst_value_subtract_fraction_range_fraction (GValue * dest,
3114     const GValue * minuend, const GValue * subtrahend)
3115 {
3116   /* since we don't have open ranges, we cannot create a hole in
3117    * a range. We return the original range */
3118   gst_value_init_and_copy (dest, minuend);
3119   return TRUE;
3120 }
3121
3122 static gboolean
3123 gst_value_subtract_fraction_range_fraction_range (GValue * dest,
3124     const GValue * minuend, const GValue * subtrahend)
3125 {
3126   /* since we don't have open ranges, we have to approximate */
3127   /* done like with ints and doubles. Creates a list of 2 fraction ranges */
3128   const GValue *min1 = gst_value_get_fraction_range_min (minuend);
3129   const GValue *max2 = gst_value_get_fraction_range_max (minuend);
3130   const GValue *max1 = gst_value_get_fraction_range_min (subtrahend);
3131   const GValue *min2 = gst_value_get_fraction_range_max (subtrahend);
3132   gint cmp1, cmp2;
3133   GValue v1 = { 0, };
3134   GValue v2 = { 0, };
3135   GValue *pv1, *pv2;            /* yeah, hungarian! */
3136   GstValueCompareFunc compare;
3137
3138   g_return_val_if_fail (min1 != NULL && max1 != NULL, FALSE);
3139   g_return_val_if_fail (min2 != NULL && max2 != NULL, FALSE);
3140
3141   compare = gst_value_get_compare_func (min1);
3142   g_return_val_if_fail (compare, FALSE);
3143
3144   cmp1 = gst_value_compare_with_func (max2, max1, compare);
3145   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
3146   if (cmp1 == GST_VALUE_LESS_THAN)
3147     max1 = max2;
3148   cmp1 = gst_value_compare_with_func (min1, min2, compare);
3149   g_return_val_if_fail (cmp1 != GST_VALUE_UNORDERED, FALSE);
3150   if (cmp1 == GST_VALUE_GREATER_THAN)
3151     min2 = min1;
3152
3153   cmp1 = gst_value_compare_with_func (min1, max1, compare);
3154   cmp2 = gst_value_compare_with_func (min2, max2, compare);
3155
3156   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
3157     pv1 = &v1;
3158     pv2 = &v2;
3159   } else if (cmp1 == GST_VALUE_LESS_THAN) {
3160     pv1 = dest;
3161     pv2 = NULL;
3162   } else if (cmp2 == GST_VALUE_LESS_THAN) {
3163     pv1 = NULL;
3164     pv2 = dest;
3165   } else {
3166     return FALSE;
3167   }
3168
3169   if (cmp1 == GST_VALUE_LESS_THAN) {
3170     g_value_init (pv1, GST_TYPE_FRACTION_RANGE);
3171     gst_value_set_fraction_range (pv1, min1, max1);
3172   }
3173   if (cmp2 == GST_VALUE_LESS_THAN) {
3174     g_value_init (pv2, GST_TYPE_FRACTION_RANGE);
3175     gst_value_set_fraction_range (pv2, min2, max2);
3176   }
3177
3178   if (cmp1 == GST_VALUE_LESS_THAN && cmp2 == GST_VALUE_LESS_THAN) {
3179     gst_value_list_concat (dest, pv1, pv2);
3180     g_value_unset (pv1);
3181     g_value_unset (pv2);
3182   }
3183   return TRUE;
3184 }
3185
3186
3187 /**************
3188  * comparison *
3189  **************/
3190
3191 /*
3192  * gst_value_get_compare_func:
3193  * @value1: a value to get the compare function for
3194  *
3195  * Determines the compare function to be used with values of the same type as
3196  * @value1. The function can be given to gst_value_compare_with_func().
3197  *
3198  * Returns: A #GstValueCompareFunc value
3199  */
3200 static GstValueCompareFunc
3201 gst_value_get_compare_func (const GValue * value1)
3202 {
3203   GstValueTable *table, *best = NULL;
3204   guint i;
3205   GType type1;
3206
3207   type1 = G_VALUE_TYPE (value1);
3208
3209   /* this is a fast check */
3210   best = gst_value_hash_lookup_type (type1);
3211
3212   /* slower checks */
3213   if (G_UNLIKELY (!best || !best->compare)) {
3214     guint len = gst_value_table->len;
3215
3216     best = NULL;
3217     for (i = 0; i < len; i++) {
3218       table = &g_array_index (gst_value_table, GstValueTable, i);
3219       if (table->compare && g_type_is_a (type1, table->type)) {
3220         if (!best || g_type_is_a (table->type, best->type))
3221           best = table;
3222       }
3223     }
3224   }
3225   if (G_LIKELY (best))
3226     return best->compare;
3227
3228   return NULL;
3229 }
3230
3231 /**
3232  * gst_value_can_compare:
3233  * @value1: a value to compare
3234  * @value2: another value to compare
3235  *
3236  * Determines if @value1 and @value2 can be compared.
3237  *
3238  * Returns: TRUE if the values can be compared
3239  */
3240 gboolean
3241 gst_value_can_compare (const GValue * value1, const GValue * value2)
3242 {
3243   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
3244   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
3245
3246   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
3247     return FALSE;
3248
3249   return gst_value_get_compare_func (value1) != NULL;
3250 }
3251
3252 /**
3253  * gst_value_compare:
3254  * @value1: a value to compare
3255  * @value2: another value to compare
3256  *
3257  * Compares @value1 and @value2.  If @value1 and @value2 cannot be
3258  * compared, the function returns GST_VALUE_UNORDERED.  Otherwise,
3259  * if @value1 is greater than @value2, GST_VALUE_GREATER_THAN is returned.
3260  * If @value1 is less than @value2, GST_VALUE_LESS_THAN is returned.
3261  * If the values are equal, GST_VALUE_EQUAL is returned.
3262  *
3263  * Returns: comparison result
3264  */
3265 gint
3266 gst_value_compare (const GValue * value1, const GValue * value2)
3267 {
3268   GstValueCompareFunc compare;
3269   GType ltype;
3270
3271   g_return_val_if_fail (G_IS_VALUE (value1), GST_VALUE_LESS_THAN);
3272   g_return_val_if_fail (G_IS_VALUE (value2), GST_VALUE_GREATER_THAN);
3273
3274   /* Special case: lists and scalar values 
3275    * "{ 1 }" and "1" are equal */
3276   ltype = gst_value_list_get_type ();
3277   if (G_VALUE_HOLDS (value1, ltype) && !G_VALUE_HOLDS (value2, ltype)
3278       && gst_value_list_get_size (value1) == 1) {
3279     const GValue *elt;
3280
3281     elt = gst_value_list_get_value (value1, 0);
3282     return gst_value_compare (elt, value2);
3283   } else if (G_VALUE_HOLDS (value2, ltype) && !G_VALUE_HOLDS (value1, ltype)
3284       && gst_value_list_get_size (value2) == 1) {
3285     const GValue *elt;
3286
3287     elt = gst_value_list_get_value (value2, 0);
3288     return gst_value_compare (elt, value1);
3289   }
3290
3291   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
3292     return GST_VALUE_UNORDERED;
3293
3294   compare = gst_value_get_compare_func (value1);
3295   if (compare) {
3296     return compare (value1, value2);
3297   }
3298
3299   g_critical ("unable to compare values of type %s\n",
3300       g_type_name (G_VALUE_TYPE (value1)));
3301   return GST_VALUE_UNORDERED;
3302 }
3303
3304 /*
3305  * gst_value_compare_with_func:
3306  * @value1: a value to compare
3307  * @value2: another value to compare
3308  * @compare: compare function
3309  *
3310  * Compares @value1 and @value2 using the @compare function. Works like
3311  * gst_value_compare() but allows to save time determining the compare function
3312  * a multiple times. 
3313  *
3314  * Returns: comparison result
3315  */
3316 static gint
3317 gst_value_compare_with_func (const GValue * value1, const GValue * value2,
3318     GstValueCompareFunc compare)
3319 {
3320   g_assert (compare);
3321
3322   if (G_VALUE_TYPE (value1) != G_VALUE_TYPE (value2))
3323     return GST_VALUE_UNORDERED;
3324
3325   return compare (value1, value2);
3326 }
3327
3328 /* union */
3329
3330 /**
3331  * gst_value_can_union:
3332  * @value1: a value to union
3333  * @value2: another value to union
3334  *
3335  * Determines if @value1 and @value2 can be non-trivially unioned.
3336  * Any two values can be trivially unioned by adding both of them
3337  * to a GstValueList.  However, certain types have the possibility
3338  * to be unioned in a simpler way.  For example, an integer range
3339  * and an integer can be unioned if the integer is a subset of the
3340  * integer range.  If there is the possibility that two values can
3341  * be unioned, this function returns TRUE.
3342  *
3343  * Returns: TRUE if there is a function allowing the two values to
3344  * be unioned.
3345  */
3346 gboolean
3347 gst_value_can_union (const GValue * value1, const GValue * value2)
3348 {
3349   GstValueUnionInfo *union_info;
3350   guint i, len;
3351
3352   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
3353   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
3354
3355   len = gst_value_union_funcs->len;
3356
3357   for (i = 0; i < len; i++) {
3358     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
3359     if (union_info->type1 == G_VALUE_TYPE (value1) &&
3360         union_info->type2 == G_VALUE_TYPE (value2))
3361       return TRUE;
3362     if (union_info->type1 == G_VALUE_TYPE (value2) &&
3363         union_info->type2 == G_VALUE_TYPE (value1))
3364       return TRUE;
3365   }
3366
3367   return FALSE;
3368 }
3369
3370 /**
3371  * gst_value_union:
3372  * @dest: (out caller-allocates): the destination value
3373  * @value1: a value to union
3374  * @value2: another value to union
3375  *
3376  * Creates a GValue corresponding to the union of @value1 and @value2.
3377  *
3378  * Returns: always returns %TRUE
3379  */
3380 /* FIXME: change return type to 'void'? */
3381 gboolean
3382 gst_value_union (GValue * dest, const GValue * value1, const GValue * value2)
3383 {
3384   GstValueUnionInfo *union_info;
3385   guint i, len;
3386
3387   g_return_val_if_fail (dest != NULL, FALSE);
3388   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
3389   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
3390
3391   len = gst_value_union_funcs->len;
3392
3393   for (i = 0; i < len; i++) {
3394     union_info = &g_array_index (gst_value_union_funcs, GstValueUnionInfo, i);
3395     if (union_info->type1 == G_VALUE_TYPE (value1) &&
3396         union_info->type2 == G_VALUE_TYPE (value2)) {
3397       if (union_info->func (dest, value1, value2)) {
3398         return TRUE;
3399       }
3400     }
3401     if (union_info->type1 == G_VALUE_TYPE (value2) &&
3402         union_info->type2 == G_VALUE_TYPE (value1)) {
3403       if (union_info->func (dest, value2, value1)) {
3404         return TRUE;
3405       }
3406     }
3407   }
3408
3409   gst_value_list_concat (dest, value1, value2);
3410   return TRUE;
3411 }
3412
3413 /**
3414  * gst_value_register_union_func:
3415  * @type1: a type to union
3416  * @type2: another type to union
3417  * @func: a function that implments creating a union between the two types
3418  *
3419  * Registers a union function that can create a union between #GValue items
3420  * of the type @type1 and @type2.
3421  *
3422  * Union functions should be registered at startup before any pipelines are
3423  * started, as gst_value_register_union_func() is not thread-safe and cannot
3424  * be used at the same time as gst_value_union() or gst_value_can_union().
3425  */
3426 void
3427 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
3428 {
3429   GstValueUnionInfo union_info;
3430
3431   union_info.type1 = type1;
3432   union_info.type2 = type2;
3433   union_info.func = func;
3434
3435   g_array_append_val (gst_value_union_funcs, union_info);
3436 }
3437
3438 /* intersection */
3439
3440 /**
3441  * gst_value_can_intersect:
3442  * @value1: a value to intersect
3443  * @value2: another value to intersect
3444  *
3445  * Determines if intersecting two values will produce a valid result.
3446  * Two values will produce a valid intersection if they have the same
3447  * type, or if there is a method (registered by
3448  * gst_value_register_intersect_func()) to calculate the intersection.
3449  *
3450  * Returns: TRUE if the values can intersect
3451  */
3452 gboolean
3453 gst_value_can_intersect (const GValue * value1, const GValue * value2)
3454 {
3455   GstValueIntersectInfo *intersect_info;
3456   guint i, len;
3457   GType ltype, type1, type2;
3458
3459   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
3460   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
3461
3462   ltype = gst_value_list_get_type ();
3463
3464   /* special cases */
3465   if (G_VALUE_HOLDS (value1, ltype) || G_VALUE_HOLDS (value2, ltype))
3466     return TRUE;
3467
3468   type1 = G_VALUE_TYPE (value1);
3469   type2 = G_VALUE_TYPE (value2);
3470
3471   /* practically all GstValue types have a compare function (_can_compare=TRUE)
3472    * GstStructure and GstCaps have npot, but are intersectable */
3473   if (type1 == type2)
3474     return TRUE;
3475
3476   /* check registered intersect functions */
3477   len = gst_value_intersect_funcs->len;
3478   for (i = 0; i < len; i++) {
3479     intersect_info = &g_array_index (gst_value_intersect_funcs,
3480         GstValueIntersectInfo, i);
3481     if ((intersect_info->type1 == type1 && intersect_info->type2 == type2) ||
3482         (intersect_info->type1 == type2 && intersect_info->type2 == type1))
3483       return TRUE;
3484   }
3485
3486   return gst_value_can_compare (value1, value2);
3487 }
3488
3489 /**
3490  * gst_value_intersect:
3491  * @dest: (out caller-allocates): a uninitialized #GValue that will hold the calculated
3492  * intersection value
3493  * @value1: a value to intersect
3494  * @value2: another value to intersect
3495  *
3496  * Calculates the intersection of two values.  If the values have
3497  * a non-empty intersection, the value representing the intersection
3498  * is placed in @dest.  If the intersection is non-empty, @dest is
3499  * not modified.
3500  *
3501  * Returns: TRUE if the intersection is non-empty
3502  */
3503 gboolean
3504 gst_value_intersect (GValue * dest, const GValue * value1,
3505     const GValue * value2)
3506 {
3507   GstValueIntersectInfo *intersect_info;
3508   guint i, len;
3509   GType ltype, type1, type2;
3510
3511   g_return_val_if_fail (dest != NULL, FALSE);
3512   g_return_val_if_fail (G_IS_VALUE (value1), FALSE);
3513   g_return_val_if_fail (G_IS_VALUE (value2), FALSE);
3514
3515   ltype = gst_value_list_get_type ();
3516
3517   /* special cases first */
3518   if (G_VALUE_HOLDS (value1, ltype))
3519     return gst_value_intersect_list (dest, value1, value2);
3520   if (G_VALUE_HOLDS (value2, ltype))
3521     return gst_value_intersect_list (dest, value2, value1);
3522
3523   if (gst_value_compare (value1, value2) == GST_VALUE_EQUAL) {
3524     gst_value_init_and_copy (dest, value1);
3525     return TRUE;
3526   }
3527
3528   type1 = G_VALUE_TYPE (value1);
3529   type2 = G_VALUE_TYPE (value2);
3530
3531   len = gst_value_intersect_funcs->len;
3532   for (i = 0; i < len; i++) {
3533     intersect_info = &g_array_index (gst_value_intersect_funcs,
3534         GstValueIntersectInfo, i);
3535     if (intersect_info->type1 == type1 && intersect_info->type2 == type2) {
3536       return intersect_info->func (dest, value1, value2);
3537     }
3538     if (intersect_info->type1 == type2 && intersect_info->type2 == type1) {
3539       return intersect_info->func (dest, value2, value1);
3540     }
3541   }
3542   return FALSE;
3543 }
3544
3545 /**
3546  * gst_value_register_intersect_func:
3547  * @type1: the first type to intersect
3548  * @type2: the second type to intersect
3549  * @func: the intersection function
3550  *
3551  * Registers a function that is called to calculate the intersection
3552  * of the values having the types @type1 and @type2.
3553  *
3554  * Intersect functions should be registered at startup before any pipelines are
3555  * started, as gst_value_register_intersect_func() is not thread-safe and
3556  * cannot be used at the same time as gst_value_intersect() or
3557  * gst_value_can_intersect().
3558  */
3559 void
3560 gst_value_register_intersect_func (GType type1, GType type2,
3561     GstValueIntersectFunc func)
3562 {
3563   GstValueIntersectInfo intersect_info;
3564
3565   intersect_info.type1 = type1;
3566   intersect_info.type2 = type2;
3567   intersect_info.func = func;
3568
3569   g_array_append_val (gst_value_intersect_funcs, intersect_info);
3570 }
3571
3572
3573 /* subtraction */
3574
3575 /**
3576  * gst_value_subtract:
3577  * @dest: (out caller-allocates): the destination value for the result if the
3578  *     subtraction is not empty
3579  * @minuend: the value to subtract from
3580  * @subtrahend: the value to subtract
3581  *
3582  * Subtracts @subtrahend from @minuend and stores the result in @dest.
3583  * Note that this means subtraction as in sets, not as in mathematics.
3584  *
3585  * Returns: %TRUE if the subtraction is not empty
3586  */
3587 gboolean
3588 gst_value_subtract (GValue * dest, const GValue * minuend,
3589     const GValue * subtrahend)
3590 {
3591   GstValueSubtractInfo *info;
3592   guint i, len;
3593   GType ltype, mtype, stype;
3594
3595   g_return_val_if_fail (dest != NULL, FALSE);
3596   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
3597   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
3598
3599   ltype = gst_value_list_get_type ();
3600
3601   /* special cases first */
3602   if (G_VALUE_HOLDS (minuend, ltype))
3603     return gst_value_subtract_from_list (dest, minuend, subtrahend);
3604   if (G_VALUE_HOLDS (subtrahend, ltype))
3605     return gst_value_subtract_list (dest, minuend, subtrahend);
3606
3607   mtype = G_VALUE_TYPE (minuend);
3608   stype = G_VALUE_TYPE (subtrahend);
3609
3610   len = gst_value_subtract_funcs->len;
3611   for (i = 0; i < len; i++) {
3612     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
3613     if (info->minuend == mtype && info->subtrahend == stype) {
3614       return info->func (dest, minuend, subtrahend);
3615     }
3616   }
3617
3618   if (gst_value_compare (minuend, subtrahend) != GST_VALUE_EQUAL) {
3619     gst_value_init_and_copy (dest, minuend);
3620     return TRUE;
3621   }
3622
3623   return FALSE;
3624 }
3625
3626 #if 0
3627 gboolean
3628 gst_value_subtract (GValue * dest, const GValue * minuend,
3629     const GValue * subtrahend)
3630 {
3631   gboolean ret = gst_value_subtract2 (dest, minuend, subtrahend);
3632
3633   g_printerr ("\"%s\"  -  \"%s\"  =  \"%s\"\n", gst_value_serialize (minuend),
3634       gst_value_serialize (subtrahend),
3635       ret ? gst_value_serialize (dest) : "---");
3636   return ret;
3637 }
3638 #endif
3639
3640 /**
3641  * gst_value_can_subtract:
3642  * @minuend: the value to subtract from
3643  * @subtrahend: the value to subtract
3644  *
3645  * Checks if it's possible to subtract @subtrahend from @minuend.
3646  *
3647  * Returns: TRUE if a subtraction is possible
3648  */
3649 gboolean
3650 gst_value_can_subtract (const GValue * minuend, const GValue * subtrahend)
3651 {
3652   GstValueSubtractInfo *info;
3653   guint i, len;
3654   GType ltype, mtype, stype;
3655
3656   g_return_val_if_fail (G_IS_VALUE (minuend), FALSE);
3657   g_return_val_if_fail (G_IS_VALUE (subtrahend), FALSE);
3658
3659   ltype = gst_value_list_get_type ();
3660
3661   /* special cases */
3662   if (G_VALUE_HOLDS (minuend, ltype) || G_VALUE_HOLDS (subtrahend, ltype))
3663     return TRUE;
3664
3665   mtype = G_VALUE_TYPE (minuend);
3666   stype = G_VALUE_TYPE (subtrahend);
3667
3668   len = gst_value_subtract_funcs->len;
3669   for (i = 0; i < len; i++) {
3670     info = &g_array_index (gst_value_subtract_funcs, GstValueSubtractInfo, i);
3671     if (info->minuend == mtype && info->subtrahend == stype)
3672       return TRUE;
3673   }
3674
3675   return gst_value_can_compare (minuend, subtrahend);
3676 }
3677
3678 /**
3679  * gst_value_register_subtract_func:
3680  * @minuend_type: type of the minuend
3681  * @subtrahend_type: type of the subtrahend
3682  * @func: function to use
3683  *
3684  * Registers @func as a function capable of subtracting the values of
3685  * @subtrahend_type from values of @minuend_type.
3686  *
3687  * Subtract functions should be registered at startup before any pipelines are
3688  * started, as gst_value_register_subtract_func() is not thread-safe and
3689  * cannot be used at the same time as gst_value_subtract().
3690  */
3691 void
3692 gst_value_register_subtract_func (GType minuend_type, GType subtrahend_type,
3693     GstValueSubtractFunc func)
3694 {
3695   GstValueSubtractInfo info;
3696
3697   /* one type must be unfixed, other subtractions can be done as comparisons */
3698   g_return_if_fail (!gst_type_is_fixed (minuend_type)
3699       || !gst_type_is_fixed (subtrahend_type));
3700
3701   info.minuend = minuend_type;
3702   info.subtrahend = subtrahend_type;
3703   info.func = func;
3704
3705   g_array_append_val (gst_value_subtract_funcs, info);
3706 }
3707
3708 /**
3709  * gst_value_register:
3710  * @table: structure containing functions to register
3711  *
3712  * Registers functions to perform calculations on #GValue items of a given
3713  * type. Each type can only be added once.
3714  */
3715 void
3716 gst_value_register (const GstValueTable * table)
3717 {
3718   GstValueTable *found;
3719
3720   g_return_if_fail (table != NULL);
3721
3722   g_array_append_val (gst_value_table, *table);
3723
3724   found = gst_value_hash_lookup_type (table->type);
3725   if (found)
3726     g_warning ("adding type %s multiple times", g_type_name (table->type));
3727
3728   /* FIXME: we're not really doing the const justice, we assume the table is
3729    * static */
3730   gst_value_hash_add_type (table->type, table);
3731 }
3732
3733 /**
3734  * gst_value_init_and_copy:
3735  * @dest: (out caller-allocates): the target value
3736  * @src: the source value
3737  *
3738  * Initialises the target value to be of the same type as source and then copies
3739  * the contents from source to target.
3740  */
3741 void
3742 gst_value_init_and_copy (GValue * dest, const GValue * src)
3743 {
3744   g_return_if_fail (G_IS_VALUE (src));
3745   g_return_if_fail (dest != NULL);
3746
3747   g_value_init (dest, G_VALUE_TYPE (src));
3748   g_value_copy (src, dest);
3749 }
3750
3751 /**
3752  * gst_value_serialize:
3753  * @value: a #GValue to serialize
3754  *
3755  * tries to transform the given @value into a string representation that allows
3756  * getting back this string later on using gst_value_deserialize().
3757  *
3758  * Free-function: g_free
3759  *
3760  * Returns: (transfer full): the serialization for @value or NULL if none exists
3761  */
3762 gchar *
3763 gst_value_serialize (const GValue * value)
3764 {
3765   guint i, len;
3766   GValue s_val = { 0 };
3767   GstValueTable *table, *best;
3768   gchar *s;
3769   GType type;
3770
3771   g_return_val_if_fail (G_IS_VALUE (value), NULL);
3772
3773   type = G_VALUE_TYPE (value);
3774
3775   best = gst_value_hash_lookup_type (type);
3776
3777   if (G_UNLIKELY (!best || !best->serialize)) {
3778     len = gst_value_table->len;
3779     best = NULL;
3780     for (i = 0; i < len; i++) {
3781       table = &g_array_index (gst_value_table, GstValueTable, i);
3782       if (table->serialize && g_type_is_a (type, table->type)) {
3783         if (!best || g_type_is_a (table->type, best->type))
3784           best = table;
3785       }
3786     }
3787   }
3788   if (G_LIKELY (best))
3789     return best->serialize (value);
3790
3791   g_value_init (&s_val, G_TYPE_STRING);
3792   if (g_value_transform (value, &s_val)) {
3793     s = gst_string_wrap (g_value_get_string (&s_val));
3794   } else {
3795     s = NULL;
3796   }
3797   g_value_unset (&s_val);
3798
3799   return s;
3800 }
3801
3802 /**
3803  * gst_value_deserialize:
3804  * @dest: (out caller-allocates): #GValue to fill with contents of
3805  *     deserialization
3806  * @src: string to deserialize
3807  *
3808  * Tries to deserialize a string into the type specified by the given GValue.
3809  * If the operation succeeds, TRUE is returned, FALSE otherwise.
3810  *
3811  * Returns: TRUE on success
3812  */
3813 gboolean
3814 gst_value_deserialize (GValue * dest, const gchar * src)
3815 {
3816   GstValueTable *table, *best;
3817   guint i, len;
3818   GType type;
3819
3820   g_return_val_if_fail (src != NULL, FALSE);
3821   g_return_val_if_fail (G_IS_VALUE (dest), FALSE);
3822
3823   type = G_VALUE_TYPE (dest);
3824
3825   best = gst_value_hash_lookup_type (type);
3826   if (G_UNLIKELY (!best || !best->deserialize)) {
3827     len = gst_value_table->len;
3828     best = NULL;
3829     for (i = 0; i < len; i++) {
3830       table = &g_array_index (gst_value_table, GstValueTable, i);
3831       if (table->deserialize && g_type_is_a (type, table->type)) {
3832         if (!best || g_type_is_a (table->type, best->type))
3833           best = table;
3834       }
3835     }
3836   }
3837   if (G_LIKELY (best))
3838     return best->deserialize (dest, src);
3839
3840   return FALSE;
3841 }
3842
3843 /**
3844  * gst_value_is_fixed:
3845  * @value: the #GValue to check
3846  *
3847  * Tests if the given GValue, if available in a GstStructure (or any other
3848  * container) contains a "fixed" (which means: one value) or an "unfixed"
3849  * (which means: multiple possible values, such as data lists or data
3850  * ranges) value.
3851  *
3852  * Returns: true if the value is "fixed".
3853  */
3854
3855 gboolean
3856 gst_value_is_fixed (const GValue * value)
3857 {
3858   GType type;
3859
3860   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
3861
3862   type = G_VALUE_TYPE (value);
3863
3864   /* the most common types are just basic plain glib types */
3865   if (type <= G_TYPE_MAKE_FUNDAMENTAL (G_TYPE_RESERVED_GLIB_LAST)) {
3866     return TRUE;
3867   }
3868
3869   if (type == GST_TYPE_ARRAY) {
3870     gint size, n;
3871     const GValue *kid;
3872
3873     /* check recursively */
3874     size = gst_value_array_get_size (value);
3875     for (n = 0; n < size; n++) {
3876       kid = gst_value_array_get_value (value, n);
3877       if (!gst_value_is_fixed (kid))
3878         return FALSE;
3879     }
3880     return TRUE;
3881   }
3882   return gst_type_is_fixed (type);
3883 }
3884
3885 /**
3886  * gst_value_fixate:
3887  * @dest: the #GValue destination
3888  * @src: the #GValue to fixate
3889  *
3890  * Fixate @src into a new value @dest.
3891  * For ranges, the first element is taken. For lists and arrays, the
3892  * first item is fixated and returned.
3893  * If @src is already fixed, this function returns FALSE.
3894  *
3895  * Returns: true if @dest contains a fixated version of @src.
3896  */
3897 gboolean
3898 gst_value_fixate (GValue * dest, const GValue * src)
3899 {
3900   g_return_val_if_fail (G_IS_VALUE (src), FALSE);
3901   g_return_val_if_fail (dest != NULL, FALSE);
3902
3903   if (G_VALUE_TYPE (src) == GST_TYPE_INT_RANGE) {
3904     g_value_init (dest, G_TYPE_INT);
3905     g_value_set_int (dest, gst_value_get_int_range_min (src));
3906   } else if (G_VALUE_TYPE (src) == GST_TYPE_DOUBLE_RANGE) {
3907     g_value_init (dest, G_TYPE_DOUBLE);
3908     g_value_set_double (dest, gst_value_get_double_range_min (src));
3909   } else if (G_VALUE_TYPE (src) == GST_TYPE_FRACTION_RANGE) {
3910     gst_value_init_and_copy (dest, gst_value_get_fraction_range_min (src));
3911   } else if (G_VALUE_TYPE (src) == GST_TYPE_LIST) {
3912     GValue temp = { 0 };
3913
3914     /* list could be empty */
3915     if (gst_value_list_get_size (src) <= 0)
3916       return FALSE;
3917
3918     gst_value_init_and_copy (&temp, gst_value_list_get_value (src, 0));
3919
3920     if (!gst_value_fixate (dest, &temp))
3921       gst_value_init_and_copy (dest, &temp);
3922     g_value_unset (&temp);
3923   } else if (G_VALUE_TYPE (src) == GST_TYPE_ARRAY) {
3924     gboolean res = FALSE;
3925     guint n, len;
3926
3927     len = gst_value_array_get_size (src);
3928     g_value_init (dest, GST_TYPE_ARRAY);
3929     for (n = 0; n < len; n++) {
3930       GValue kid = { 0 };
3931       const GValue *orig_kid = gst_value_array_get_value (src, n);
3932
3933       if (!gst_value_fixate (&kid, orig_kid))
3934         gst_value_init_and_copy (&kid, orig_kid);
3935       else
3936         res = TRUE;
3937       gst_value_array_append_value (dest, &kid);
3938       g_value_unset (&kid);
3939     }
3940
3941     if (!res)
3942       g_value_unset (dest);
3943
3944     return res;
3945   } else {
3946     return FALSE;
3947   }
3948   return TRUE;
3949 }
3950
3951
3952 /************
3953  * fraction *
3954  ************/
3955
3956 /* helper functions */
3957 static void
3958 gst_value_init_fraction (GValue * value)
3959 {
3960   value->data[0].v_int = 0;
3961   value->data[1].v_int = 1;
3962 }
3963
3964 static void
3965 gst_value_copy_fraction (const GValue * src_value, GValue * dest_value)
3966 {
3967   dest_value->data[0].v_int = src_value->data[0].v_int;
3968   dest_value->data[1].v_int = src_value->data[1].v_int;
3969 }
3970
3971 static gchar *
3972 gst_value_collect_fraction (GValue * value, guint n_collect_values,
3973     GTypeCValue * collect_values, guint collect_flags)
3974 {
3975   if (n_collect_values != 2)
3976     return g_strdup_printf ("not enough value locations for `%s' passed",
3977         G_VALUE_TYPE_NAME (value));
3978   if (collect_values[1].v_int == 0)
3979     return g_strdup_printf ("passed '0' as denominator for `%s'",
3980         G_VALUE_TYPE_NAME (value));
3981   if (collect_values[0].v_int < -G_MAXINT)
3982     return
3983         g_strdup_printf
3984         ("passed value smaller than -G_MAXINT as numerator for `%s'",
3985         G_VALUE_TYPE_NAME (value));
3986   if (collect_values[1].v_int < -G_MAXINT)
3987     return
3988         g_strdup_printf
3989         ("passed value smaller than -G_MAXINT as denominator for `%s'",
3990         G_VALUE_TYPE_NAME (value));
3991
3992   gst_value_set_fraction (value,
3993       collect_values[0].v_int, collect_values[1].v_int);
3994
3995   return NULL;
3996 }
3997
3998 static gchar *
3999 gst_value_lcopy_fraction (const GValue * value, guint n_collect_values,
4000     GTypeCValue * collect_values, guint collect_flags)
4001 {
4002   gint *numerator = collect_values[0].v_pointer;
4003   gint *denominator = collect_values[1].v_pointer;
4004
4005   if (!numerator)
4006     return g_strdup_printf ("numerator for `%s' passed as NULL",
4007         G_VALUE_TYPE_NAME (value));
4008   if (!denominator)
4009     return g_strdup_printf ("denominator for `%s' passed as NULL",
4010         G_VALUE_TYPE_NAME (value));
4011
4012   *numerator = value->data[0].v_int;
4013   *denominator = value->data[1].v_int;
4014
4015   return NULL;
4016 }
4017
4018 /**
4019  * gst_value_set_fraction:
4020  * @value: a GValue initialized to #GST_TYPE_FRACTION
4021  * @numerator: the numerator of the fraction
4022  * @denominator: the denominator of the fraction
4023  *
4024  * Sets @value to the fraction specified by @numerator over @denominator.
4025  * The fraction gets reduced to the smallest numerator and denominator,
4026  * and if necessary the sign is moved to the numerator.
4027  */
4028 void
4029 gst_value_set_fraction (GValue * value, gint numerator, gint denominator)
4030 {
4031   gint gcd = 0;
4032
4033   g_return_if_fail (GST_VALUE_HOLDS_FRACTION (value));
4034   g_return_if_fail (denominator != 0);
4035   g_return_if_fail (denominator >= -G_MAXINT);
4036   g_return_if_fail (numerator >= -G_MAXINT);
4037
4038   /* normalize sign */
4039   if (denominator < 0) {
4040     numerator = -numerator;
4041     denominator = -denominator;
4042   }
4043
4044   /* check for reduction */
4045   gcd = gst_util_greatest_common_divisor (numerator, denominator);
4046   if (gcd) {
4047     numerator /= gcd;
4048     denominator /= gcd;
4049   }
4050
4051   g_assert (denominator > 0);
4052
4053   value->data[0].v_int = numerator;
4054   value->data[1].v_int = denominator;
4055 }
4056
4057 /**
4058  * gst_value_get_fraction_numerator:
4059  * @value: a GValue initialized to #GST_TYPE_FRACTION
4060  *
4061  * Gets the numerator of the fraction specified by @value.
4062  *
4063  * Returns: the numerator of the fraction.
4064  */
4065 gint
4066 gst_value_get_fraction_numerator (const GValue * value)
4067 {
4068   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 0);
4069
4070   return value->data[0].v_int;
4071 }
4072
4073 /**
4074  * gst_value_get_fraction_denominator:
4075  * @value: a GValue initialized to #GST_TYPE_FRACTION
4076  *
4077  * Gets the denominator of the fraction specified by @value.
4078  *
4079  * Returns: the denominator of the fraction.
4080  */
4081 gint
4082 gst_value_get_fraction_denominator (const GValue * value)
4083 {
4084   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (value), 1);
4085
4086   return value->data[1].v_int;
4087 }
4088
4089 /**
4090  * gst_value_fraction_multiply:
4091  * @product: a GValue initialized to #GST_TYPE_FRACTION
4092  * @factor1: a GValue initialized to #GST_TYPE_FRACTION
4093  * @factor2: a GValue initialized to #GST_TYPE_FRACTION
4094  *
4095  * Multiplies the two #GValue items containing a #GST_TYPE_FRACTION and sets
4096  * @product to the product of the two fractions.
4097  *
4098  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
4099  */
4100 gboolean
4101 gst_value_fraction_multiply (GValue * product, const GValue * factor1,
4102     const GValue * factor2)
4103 {
4104   gint n1, n2, d1, d2;
4105   gint res_n, res_d;
4106
4107   g_return_val_if_fail (product != NULL, FALSE);
4108   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor1), FALSE);
4109   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (factor2), FALSE);
4110
4111   n1 = factor1->data[0].v_int;
4112   n2 = factor2->data[0].v_int;
4113   d1 = factor1->data[1].v_int;
4114   d2 = factor2->data[1].v_int;
4115
4116   if (!gst_util_fraction_multiply (n1, d1, n2, d2, &res_n, &res_d))
4117     return FALSE;
4118
4119   gst_value_set_fraction (product, res_n, res_d);
4120
4121   return TRUE;
4122 }
4123
4124 /**
4125  * gst_value_fraction_subtract:
4126  * @dest: a GValue initialized to #GST_TYPE_FRACTION
4127  * @minuend: a GValue initialized to #GST_TYPE_FRACTION
4128  * @subtrahend: a GValue initialized to #GST_TYPE_FRACTION
4129  *
4130  * Subtracts the @subtrahend from the @minuend and sets @dest to the result.
4131  *
4132  * Returns: FALSE in case of an error (like integer overflow), TRUE otherwise.
4133  */
4134 gboolean
4135 gst_value_fraction_subtract (GValue * dest,
4136     const GValue * minuend, const GValue * subtrahend)
4137 {
4138   gint n1, n2, d1, d2;
4139   gint res_n, res_d;
4140
4141   g_return_val_if_fail (dest != NULL, FALSE);
4142   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (minuend), FALSE);
4143   g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (subtrahend), FALSE);
4144
4145   n1 = minuend->data[0].v_int;
4146   n2 = subtrahend->data[0].v_int;
4147   d1 = minuend->data[1].v_int;
4148   d2 = subtrahend->data[1].v_int;
4149
4150   if (!gst_util_fraction_add (n1, d1, -n2, d2, &res_n, &res_d))
4151     return FALSE;
4152   gst_value_set_fraction (dest, res_n, res_d);
4153
4154   return TRUE;
4155 }
4156
4157 static gchar *
4158 gst_value_serialize_fraction (const GValue * value)
4159 {
4160   gint32 numerator = value->data[0].v_int;
4161   gint32 denominator = value->data[1].v_int;
4162   gboolean positive = TRUE;
4163
4164   /* get the sign and make components absolute */
4165   if (numerator < 0) {
4166     numerator = -numerator;
4167     positive = !positive;
4168   }
4169   if (denominator < 0) {
4170     denominator = -denominator;
4171     positive = !positive;
4172   }
4173
4174   return g_strdup_printf ("%s%d/%d",
4175       positive ? "" : "-", numerator, denominator);
4176 }
4177
4178 static gboolean
4179 gst_value_deserialize_fraction (GValue * dest, const gchar * s)
4180 {
4181   gint num, den;
4182   gint num_chars;
4183
4184   if (G_UNLIKELY (s == NULL))
4185     return FALSE;
4186
4187   if (G_UNLIKELY (dest == NULL || !GST_VALUE_HOLDS_FRACTION (dest)))
4188     return FALSE;
4189
4190   if (sscanf (s, "%d/%d%n", &num, &den, &num_chars) >= 2) {
4191     if (s[num_chars] != 0)
4192       return FALSE;
4193     if (den == 0)
4194       return FALSE;
4195
4196     gst_value_set_fraction (dest, num, den);
4197     return TRUE;
4198   } else if (g_ascii_strcasecmp (s, "1/max") == 0) {
4199     gst_value_set_fraction (dest, 1, G_MAXINT);
4200     return TRUE;
4201   } else if (sscanf (s, "%d%n", &num, &num_chars) >= 1) {
4202     if (s[num_chars] != 0)
4203       return FALSE;
4204     gst_value_set_fraction (dest, num, 1);
4205     return TRUE;
4206   } else if (g_ascii_strcasecmp (s, "min") == 0) {
4207     gst_value_set_fraction (dest, -G_MAXINT, 1);
4208     return TRUE;
4209   } else if (g_ascii_strcasecmp (s, "max") == 0) {
4210     gst_value_set_fraction (dest, G_MAXINT, 1);
4211     return TRUE;
4212   }
4213
4214   return FALSE;
4215 }
4216
4217 static void
4218 gst_value_transform_fraction_string (const GValue * src_value,
4219     GValue * dest_value)
4220 {
4221   dest_value->data[0].v_pointer = gst_value_serialize_fraction (src_value);
4222 }
4223
4224 static void
4225 gst_value_transform_string_fraction (const GValue * src_value,
4226     GValue * dest_value)
4227 {
4228   if (!gst_value_deserialize_fraction (dest_value,
4229           src_value->data[0].v_pointer))
4230     /* If the deserialize fails, ensure we leave the fraction in a
4231      * valid, if incorrect, state */
4232     gst_value_set_fraction (dest_value, 0, 1);
4233 }
4234
4235 static void
4236 gst_value_transform_double_fraction (const GValue * src_value,
4237     GValue * dest_value)
4238 {
4239   gdouble src = g_value_get_double (src_value);
4240   gint n, d;
4241
4242   gst_util_double_to_fraction (src, &n, &d);
4243   gst_value_set_fraction (dest_value, n, d);
4244 }
4245
4246 static void
4247 gst_value_transform_float_fraction (const GValue * src_value,
4248     GValue * dest_value)
4249 {
4250   gfloat src = g_value_get_float (src_value);
4251   gint n, d;
4252
4253   gst_util_double_to_fraction (src, &n, &d);
4254   gst_value_set_fraction (dest_value, n, d);
4255 }
4256
4257 static void
4258 gst_value_transform_fraction_double (const GValue * src_value,
4259     GValue * dest_value)
4260 {
4261   dest_value->data[0].v_double = ((double) src_value->data[0].v_int) /
4262       ((double) src_value->data[1].v_int);
4263 }
4264
4265 static void
4266 gst_value_transform_fraction_float (const GValue * src_value,
4267     GValue * dest_value)
4268 {
4269   dest_value->data[0].v_float = ((float) src_value->data[0].v_int) /
4270       ((float) src_value->data[1].v_int);
4271 }
4272
4273 static gint
4274 gst_value_compare_fraction (const GValue * value1, const GValue * value2)
4275 {
4276   gint n1, n2;
4277   gint d1, d2;
4278   gint ret;
4279
4280   n1 = value1->data[0].v_int;
4281   n2 = value2->data[0].v_int;
4282   d1 = value1->data[1].v_int;
4283   d2 = value2->data[1].v_int;
4284
4285   /* fractions are reduced when set, so we can quickly see if they're equal */
4286   if (n1 == n2 && d1 == d2)
4287     return GST_VALUE_EQUAL;
4288
4289   if (d1 == 0 && d2 == 0)
4290     return GST_VALUE_UNORDERED;
4291   else if (d1 == 0)
4292     return GST_VALUE_GREATER_THAN;
4293   else if (d2 == 0)
4294     return GST_VALUE_LESS_THAN;
4295
4296   ret = gst_util_fraction_compare (n1, d1, n2, d2);
4297   if (ret == -1)
4298     return GST_VALUE_LESS_THAN;
4299   else if (ret == 1)
4300     return GST_VALUE_GREATER_THAN;
4301
4302   /* Equality can't happen here because we check for that
4303    * first already */
4304   g_return_val_if_reached (GST_VALUE_UNORDERED);
4305 }
4306
4307 /*********
4308  * GDate *
4309  *********/
4310
4311 /**
4312  * gst_value_set_date:
4313  * @value: a GValue initialized to GST_TYPE_DATE
4314  * @date: the date to set the value to
4315  *
4316  * Sets the contents of @value to coorespond to @date.  The actual
4317  * #GDate structure is copied before it is used.
4318  */
4319 void
4320 gst_value_set_date (GValue * value, const GDate * date)
4321 {
4322   g_return_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE);
4323   g_return_if_fail (g_date_valid (date));
4324
4325   g_value_set_boxed (value, date);
4326 }
4327
4328 /**
4329  * gst_value_get_date:
4330  * @value: a GValue initialized to GST_TYPE_DATE
4331  *
4332  * Gets the contents of @value.
4333  *
4334  * Returns: (transfer none): the contents of @value
4335  */
4336 const GDate *
4337 gst_value_get_date (const GValue * value)
4338 {
4339   g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_DATE, NULL);
4340
4341   return (const GDate *) g_value_get_boxed (value);
4342 }
4343
4344 static gpointer
4345 gst_date_copy (gpointer boxed)
4346 {
4347   const GDate *date = (const GDate *) boxed;
4348
4349   if (!g_date_valid (date)) {
4350     GST_WARNING ("invalid GDate");
4351     return NULL;
4352   }
4353
4354   return g_date_new_julian (g_date_get_julian (date));
4355 }
4356
4357 static gint
4358 gst_value_compare_date (const GValue * value1, const GValue * value2)
4359 {
4360   const GDate *date1 = (const GDate *) g_value_get_boxed (value1);
4361   const GDate *date2 = (const GDate *) g_value_get_boxed (value2);
4362   guint32 j1, j2;
4363
4364   if (date1 == date2)
4365     return GST_VALUE_EQUAL;
4366
4367   if ((date1 == NULL || !g_date_valid (date1))
4368       && (date2 != NULL && g_date_valid (date2))) {
4369     return GST_VALUE_LESS_THAN;
4370   }
4371
4372   if ((date2 == NULL || !g_date_valid (date2))
4373       && (date1 != NULL && g_date_valid (date1))) {
4374     return GST_VALUE_GREATER_THAN;
4375   }
4376
4377   if (date1 == NULL || date2 == NULL || !g_date_valid (date1)
4378       || !g_date_valid (date2)) {
4379     return GST_VALUE_UNORDERED;
4380   }
4381
4382   j1 = g_date_get_julian (date1);
4383   j2 = g_date_get_julian (date2);
4384
4385   if (j1 == j2)
4386     return GST_VALUE_EQUAL;
4387   else if (j1 < j2)
4388     return GST_VALUE_LESS_THAN;
4389   else
4390     return GST_VALUE_GREATER_THAN;
4391 }
4392
4393 static gchar *
4394 gst_value_serialize_date (const GValue * val)
4395 {
4396   const GDate *date = (const GDate *) g_value_get_boxed (val);
4397
4398   if (date == NULL || !g_date_valid (date))
4399     return g_strdup ("9999-99-99");
4400
4401   return g_strdup_printf ("%04u-%02u-%02u", g_date_get_year (date),
4402       g_date_get_month (date), g_date_get_day (date));
4403 }
4404
4405 static gboolean
4406 gst_value_deserialize_date (GValue * dest, const gchar * s)
4407 {
4408   guint year, month, day;
4409
4410   if (!s || sscanf (s, "%04u-%02u-%02u", &year, &month, &day) != 3)
4411     return FALSE;
4412
4413   if (!g_date_valid_dmy (day, month, year))
4414     return FALSE;
4415
4416   g_value_take_boxed (dest, g_date_new_dmy (day, month, year));
4417   return TRUE;
4418 }
4419
4420 /*************
4421  * GstDateTime *
4422  *************/
4423
4424 static gint
4425 gst_value_compare_date_time (const GValue * value1, const GValue * value2)
4426 {
4427   const GstDateTime *date1 = (const GstDateTime *) g_value_get_boxed (value1);
4428   const GstDateTime *date2 = (const GstDateTime *) g_value_get_boxed (value2);
4429   gint ret;
4430
4431   if (date1 == date2)
4432     return GST_VALUE_EQUAL;
4433
4434   if ((date1 == NULL) && (date2 != NULL)) {
4435     return GST_VALUE_LESS_THAN;
4436   }
4437   if ((date2 == NULL) && (date1 != NULL)) {
4438     return GST_VALUE_LESS_THAN;
4439   }
4440
4441   ret = priv_gst_date_time_compare (date1, date2);
4442
4443   if (ret == 0)
4444     return GST_VALUE_EQUAL;
4445   else if (ret < 0)
4446     return GST_VALUE_LESS_THAN;
4447   else
4448     return GST_VALUE_GREATER_THAN;
4449 }
4450
4451 static gchar *
4452 gst_value_serialize_date_time (const GValue * val)
4453 {
4454   GstDateTime *date = (GstDateTime *) g_value_get_boxed (val);
4455   gfloat offset;
4456   gint tzhour, tzminute;
4457
4458   if (date == NULL)
4459     return g_strdup ("null");
4460
4461   offset = gst_date_time_get_time_zone_offset (date);
4462
4463   tzhour = (gint) ABS (offset);
4464   tzminute = (gint) ((ABS (offset) - tzhour) * 60);
4465
4466   return g_strdup_printf ("\"%04d-%02d-%02dT%02d:%02d:%02d.%06d"
4467       "%c%02d%02d\"", gst_date_time_get_year (date),
4468       gst_date_time_get_month (date), gst_date_time_get_day (date),
4469       gst_date_time_get_hour (date), gst_date_time_get_minute (date),
4470       gst_date_time_get_second (date), gst_date_time_get_microsecond (date),
4471       offset >= 0 ? '+' : '-', tzhour, tzminute);
4472 }
4473
4474 static gboolean
4475 gst_value_deserialize_date_time (GValue * dest, const gchar * s)
4476 {
4477   gint year, month, day, hour, minute, second, usecond;
4478   gchar signal;
4479   gint offset = 0;
4480   gfloat tzoffset = 0;
4481   gint ret;
4482
4483   if (!s || strcmp (s, "null") == 0) {
4484     return FALSE;
4485   }
4486
4487   ret = sscanf (s, "%04d-%02d-%02dT%02d:%02d:%02d.%06d%c%04d",
4488       &year, &month, &day, &hour, &minute, &second, &usecond, &signal, &offset);
4489   if (ret >= 9) {
4490     tzoffset = (offset / 100) + ((offset % 100) / 60.0);
4491     if (signal == '-')
4492       tzoffset = -tzoffset;
4493   } else
4494     return FALSE;
4495
4496   g_value_take_boxed (dest, gst_date_time_new (tzoffset, year, month, day, hour,
4497           minute, second + (usecond / 1000000.0)));
4498   return TRUE;
4499 }
4500
4501 static void
4502 gst_value_transform_date_string (const GValue * src_value, GValue * dest_value)
4503 {
4504   dest_value->data[0].v_pointer = gst_value_serialize_date (src_value);
4505 }
4506
4507 static void
4508 gst_value_transform_string_date (const GValue * src_value, GValue * dest_value)
4509 {
4510   gst_value_deserialize_date (dest_value, src_value->data[0].v_pointer);
4511 }
4512
4513 static void
4514 gst_value_transform_object_string (const GValue * src_value,
4515     GValue * dest_value)
4516 {
4517   GstObject *obj;
4518   gchar *str;
4519
4520   obj = g_value_get_object (src_value);
4521   if (obj) {
4522     str =
4523         g_strdup_printf ("(%s) %s", G_OBJECT_TYPE_NAME (obj),
4524         GST_OBJECT_NAME (obj));
4525   } else {
4526     str = g_strdup ("NULL");
4527   }
4528
4529   dest_value->data[0].v_pointer = str;
4530 }
4531
4532 static GTypeInfo _info = {
4533   0,
4534   NULL,
4535   NULL,
4536   NULL,
4537   NULL,
4538   NULL,
4539   0,
4540   0,
4541   NULL,
4542   NULL,
4543 };
4544
4545 static GTypeFundamentalInfo _finfo = {
4546   0
4547 };
4548
4549 #define FUNC_VALUE_GET_TYPE(type, name)                         \
4550 GType gst_ ## type ## _get_type (void)                          \
4551 {                                                               \
4552   static volatile GType gst_ ## type ## _type = 0;                       \
4553                                                                 \
4554   if (g_once_init_enter (&gst_ ## type ## _type)) {             \
4555     GType _type;                                        \
4556     _info.value_table = & _gst_ ## type ## _value_table;        \
4557     _type = g_type_register_fundamental (       \
4558         g_type_fundamental_next (),                             \
4559         name, &_info, &_finfo, 0);                              \
4560     g_once_init_leave(&gst_ ## type ## _type, _type);   \
4561   }                                                             \
4562                                                                 \
4563   return gst_ ## type ## _type;                                 \
4564 }
4565
4566 static const GTypeValueTable _gst_int_range_value_table = {
4567   gst_value_init_int_range,
4568   NULL,
4569   gst_value_copy_int_range,
4570   NULL,
4571   (char *) "ii",
4572   gst_value_collect_int_range,
4573   (char *) "pp",
4574   gst_value_lcopy_int_range
4575 };
4576
4577 FUNC_VALUE_GET_TYPE (int_range, "GstIntRange");
4578
4579 static const GTypeValueTable _gst_int64_range_value_table = {
4580   gst_value_init_int64_range,
4581   NULL,
4582   gst_value_copy_int64_range,
4583   NULL,
4584   (char *) "qq",
4585   gst_value_collect_int64_range,
4586   (char *) "pp",
4587   gst_value_lcopy_int64_range
4588 };
4589
4590 FUNC_VALUE_GET_TYPE (int64_range, "GstInt64Range");
4591
4592 static const GTypeValueTable _gst_double_range_value_table = {
4593   gst_value_init_double_range,
4594   NULL,
4595   gst_value_copy_double_range,
4596   NULL,
4597   (char *) "dd",
4598   gst_value_collect_double_range,
4599   (char *) "pp",
4600   gst_value_lcopy_double_range
4601 };
4602
4603 FUNC_VALUE_GET_TYPE (double_range, "GstDoubleRange");
4604
4605 static const GTypeValueTable _gst_fraction_range_value_table = {
4606   gst_value_init_fraction_range,
4607   gst_value_free_fraction_range,
4608   gst_value_copy_fraction_range,
4609   NULL,
4610   (char *) "iiii",
4611   gst_value_collect_fraction_range,
4612   (char *) "pppp",
4613   gst_value_lcopy_fraction_range
4614 };
4615
4616 FUNC_VALUE_GET_TYPE (fraction_range, "GstFractionRange");
4617
4618 static const GTypeValueTable _gst_value_list_value_table = {
4619   gst_value_init_list_or_array,
4620   gst_value_free_list_or_array,
4621   gst_value_copy_list_or_array,
4622   gst_value_list_or_array_peek_pointer,
4623   (char *) "p",
4624   gst_value_collect_list_or_array,
4625   (char *) "p",
4626   gst_value_lcopy_list_or_array
4627 };
4628
4629 FUNC_VALUE_GET_TYPE (value_list, "GstValueList");
4630
4631 static const GTypeValueTable _gst_value_array_value_table = {
4632   gst_value_init_list_or_array,
4633   gst_value_free_list_or_array,
4634   gst_value_copy_list_or_array,
4635   gst_value_list_or_array_peek_pointer,
4636   (char *) "p",
4637   gst_value_collect_list_or_array,
4638   (char *) "p",
4639   gst_value_lcopy_list_or_array
4640 };
4641
4642 FUNC_VALUE_GET_TYPE (value_array, "GstValueArray");
4643
4644 static const GTypeValueTable _gst_fraction_value_table = {
4645   gst_value_init_fraction,
4646   NULL,
4647   gst_value_copy_fraction,
4648   NULL,
4649   (char *) "ii",
4650   gst_value_collect_fraction,
4651   (char *) "pp",
4652   gst_value_lcopy_fraction
4653 };
4654
4655 FUNC_VALUE_GET_TYPE (fraction, "GstFraction");
4656
4657
4658 GType
4659 gst_date_get_type (void)
4660 {
4661   static GType gst_date_type = 0;
4662
4663   if (G_UNLIKELY (gst_date_type == 0)) {
4664     /* FIXME 0.11: we require GLib 2.8 already
4665      * Not using G_TYPE_DATE here on purpose, even if we could
4666      * if GLIB_CHECK_VERSION(2,8,0) was true: we don't want the
4667      * serialised strings to have different type strings depending
4668      * on what version is used, so FIXME when we require GLib-2.8 */
4669     gst_date_type = g_boxed_type_register_static ("GstDate",
4670         (GBoxedCopyFunc) gst_date_copy, (GBoxedFreeFunc) g_date_free);
4671   }
4672
4673   return gst_date_type;
4674 }
4675
4676 GType
4677 gst_date_time_get_type (void)
4678 {
4679   static GType gst_date_time_type = 0;
4680
4681   if (G_UNLIKELY (gst_date_time_type == 0)) {
4682     gst_date_time_type = g_boxed_type_register_static ("GstDateTime",
4683         (GBoxedCopyFunc) gst_date_time_ref,
4684         (GBoxedFreeFunc) gst_date_time_unref);
4685   }
4686
4687   return gst_date_time_type;
4688 }
4689
4690
4691 void
4692 _gst_value_initialize (void)
4693 {
4694   gst_value_table = g_array_new (FALSE, FALSE, sizeof (GstValueTable));
4695   gst_value_hash = g_hash_table_new (NULL, NULL);
4696   gst_value_union_funcs = g_array_new (FALSE, FALSE,
4697       sizeof (GstValueUnionInfo));
4698   gst_value_intersect_funcs = g_array_new (FALSE, FALSE,
4699       sizeof (GstValueIntersectInfo));
4700   gst_value_subtract_funcs = g_array_new (FALSE, FALSE,
4701       sizeof (GstValueSubtractInfo));
4702
4703   {
4704     static GstValueTable gst_value = {
4705       0,
4706       gst_value_compare_int_range,
4707       gst_value_serialize_int_range,
4708       gst_value_deserialize_int_range,
4709     };
4710
4711     gst_value.type = gst_int_range_get_type ();
4712     gst_value_register (&gst_value);
4713   }
4714
4715   {
4716     static GstValueTable gst_value = {
4717       0,
4718       gst_value_compare_int64_range,
4719       gst_value_serialize_int64_range,
4720       gst_value_deserialize_int64_range,
4721     };
4722
4723     gst_value.type = gst_int64_range_get_type ();
4724     gst_value_register (&gst_value);
4725   }
4726
4727   {
4728     static GstValueTable gst_value = {
4729       0,
4730       gst_value_compare_double_range,
4731       gst_value_serialize_double_range,
4732       gst_value_deserialize_double_range,
4733     };
4734
4735     gst_value.type = gst_double_range_get_type ();
4736     gst_value_register (&gst_value);
4737   }
4738
4739   {
4740     static GstValueTable gst_value = {
4741       0,
4742       gst_value_compare_fraction_range,
4743       gst_value_serialize_fraction_range,
4744       gst_value_deserialize_fraction_range,
4745     };
4746
4747     gst_value.type = gst_fraction_range_get_type ();
4748     gst_value_register (&gst_value);
4749   }
4750
4751   {
4752     static GstValueTable gst_value = {
4753       0,
4754       gst_value_compare_list,
4755       gst_value_serialize_list,
4756       gst_value_deserialize_list,
4757     };
4758
4759     gst_value.type = gst_value_list_get_type ();
4760     gst_value_register (&gst_value);
4761   }
4762
4763   {
4764     static GstValueTable gst_value = {
4765       0,
4766       gst_value_compare_array,
4767       gst_value_serialize_array,
4768       gst_value_deserialize_array,
4769     };
4770
4771     gst_value.type = gst_value_array_get_type ();
4772     gst_value_register (&gst_value);
4773   }
4774
4775   {
4776 #if 0
4777     static const GTypeValueTable value_table = {
4778       gst_value_init_buffer,
4779       NULL,
4780       gst_value_copy_buffer,
4781       NULL,
4782       "i",
4783       NULL,                     /*gst_value_collect_buffer, */
4784       "p",
4785       NULL                      /*gst_value_lcopy_buffer */
4786     };
4787 #endif
4788     static GstValueTable gst_value = {
4789       0,
4790       gst_value_compare_buffer,
4791       gst_value_serialize_buffer,
4792       gst_value_deserialize_buffer,
4793     };
4794
4795     gst_value.type = GST_TYPE_BUFFER;
4796     gst_value_register (&gst_value);
4797   }
4798   {
4799     static GstValueTable gst_value = {
4800       0,
4801       gst_value_compare_fraction,
4802       gst_value_serialize_fraction,
4803       gst_value_deserialize_fraction,
4804     };
4805
4806     gst_value.type = gst_fraction_get_type ();
4807     gst_value_register (&gst_value);
4808   }
4809   {
4810     static GstValueTable gst_value = {
4811       0,
4812       NULL,
4813       gst_value_serialize_caps,
4814       gst_value_deserialize_caps,
4815     };
4816
4817     gst_value.type = GST_TYPE_CAPS;
4818     gst_value_register (&gst_value);
4819   }
4820   {
4821     static GstValueTable gst_value = {
4822       0,
4823       NULL,
4824       gst_value_serialize_structure,
4825       gst_value_deserialize_structure,
4826     };
4827
4828     gst_value.type = GST_TYPE_STRUCTURE;
4829     gst_value_register (&gst_value);
4830   }
4831   {
4832     static GstValueTable gst_value = {
4833       0,
4834       gst_value_compare_date,
4835       gst_value_serialize_date,
4836       gst_value_deserialize_date,
4837     };
4838
4839     gst_value.type = gst_date_get_type ();
4840     gst_value_register (&gst_value);
4841   }
4842   {
4843     static GstValueTable gst_value = {
4844       0,
4845       gst_value_compare_date_time,
4846       gst_value_serialize_date_time,
4847       gst_value_deserialize_date_time,
4848     };
4849
4850     gst_value.type = gst_date_time_get_type ();
4851     gst_value_register (&gst_value);
4852   }
4853
4854   REGISTER_SERIALIZATION (G_TYPE_DOUBLE, double);
4855   REGISTER_SERIALIZATION (G_TYPE_FLOAT, float);
4856
4857   REGISTER_SERIALIZATION (G_TYPE_STRING, string);
4858   REGISTER_SERIALIZATION (G_TYPE_BOOLEAN, boolean);
4859   REGISTER_SERIALIZATION (G_TYPE_ENUM, enum);
4860
4861   REGISTER_SERIALIZATION (G_TYPE_FLAGS, flags);
4862
4863   REGISTER_SERIALIZATION (G_TYPE_INT, int);
4864
4865   REGISTER_SERIALIZATION (G_TYPE_INT64, int64);
4866   REGISTER_SERIALIZATION (G_TYPE_LONG, long);
4867
4868   REGISTER_SERIALIZATION (G_TYPE_UINT, uint);
4869   REGISTER_SERIALIZATION (G_TYPE_UINT64, uint64);
4870   REGISTER_SERIALIZATION (G_TYPE_ULONG, ulong);
4871
4872   REGISTER_SERIALIZATION (G_TYPE_UCHAR, uchar);
4873
4874   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
4875       gst_value_transform_int_range_string);
4876   g_value_register_transform_func (GST_TYPE_INT64_RANGE, G_TYPE_STRING,
4877       gst_value_transform_int64_range_string);
4878   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
4879       gst_value_transform_double_range_string);
4880   g_value_register_transform_func (GST_TYPE_FRACTION_RANGE, G_TYPE_STRING,
4881       gst_value_transform_fraction_range_string);
4882   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
4883       gst_value_transform_list_string);
4884   g_value_register_transform_func (GST_TYPE_ARRAY, G_TYPE_STRING,
4885       gst_value_transform_array_string);
4886   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_STRING,
4887       gst_value_transform_fraction_string);
4888   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_FRACTION,
4889       gst_value_transform_string_fraction);
4890   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_DOUBLE,
4891       gst_value_transform_fraction_double);
4892   g_value_register_transform_func (GST_TYPE_FRACTION, G_TYPE_FLOAT,
4893       gst_value_transform_fraction_float);
4894   g_value_register_transform_func (G_TYPE_DOUBLE, GST_TYPE_FRACTION,
4895       gst_value_transform_double_fraction);
4896   g_value_register_transform_func (G_TYPE_FLOAT, GST_TYPE_FRACTION,
4897       gst_value_transform_float_fraction);
4898   g_value_register_transform_func (GST_TYPE_DATE, G_TYPE_STRING,
4899       gst_value_transform_date_string);
4900   g_value_register_transform_func (G_TYPE_STRING, GST_TYPE_DATE,
4901       gst_value_transform_string_date);
4902   g_value_register_transform_func (GST_TYPE_OBJECT, G_TYPE_STRING,
4903       gst_value_transform_object_string);
4904
4905   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
4906       gst_value_intersect_int_int_range);
4907   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
4908       gst_value_intersect_int_range_int_range);
4909   gst_value_register_intersect_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
4910       gst_value_intersect_int64_int64_range);
4911   gst_value_register_intersect_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
4912       gst_value_intersect_int64_range_int64_range);
4913   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
4914       gst_value_intersect_double_double_range);
4915   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE,
4916       GST_TYPE_DOUBLE_RANGE, gst_value_intersect_double_range_double_range);
4917   gst_value_register_intersect_func (GST_TYPE_ARRAY,
4918       GST_TYPE_ARRAY, gst_value_intersect_array);
4919   gst_value_register_intersect_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
4920       gst_value_intersect_fraction_fraction_range);
4921   gst_value_register_intersect_func (GST_TYPE_FRACTION_RANGE,
4922       GST_TYPE_FRACTION_RANGE,
4923       gst_value_intersect_fraction_range_fraction_range);
4924
4925   gst_value_register_subtract_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
4926       gst_value_subtract_int_int_range);
4927   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, G_TYPE_INT,
4928       gst_value_subtract_int_range_int);
4929   gst_value_register_subtract_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
4930       gst_value_subtract_int_range_int_range);
4931   gst_value_register_subtract_func (G_TYPE_INT64, GST_TYPE_INT64_RANGE,
4932       gst_value_subtract_int64_int64_range);
4933   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, G_TYPE_INT64,
4934       gst_value_subtract_int64_range_int64);
4935   gst_value_register_subtract_func (GST_TYPE_INT64_RANGE, GST_TYPE_INT64_RANGE,
4936       gst_value_subtract_int64_range_int64_range);
4937   gst_value_register_subtract_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
4938       gst_value_subtract_double_double_range);
4939   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_DOUBLE,
4940       gst_value_subtract_double_range_double);
4941   gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
4942       GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
4943
4944   gst_value_register_subtract_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
4945       gst_value_subtract_fraction_fraction_range);
4946   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE, GST_TYPE_FRACTION,
4947       gst_value_subtract_fraction_range_fraction);
4948   gst_value_register_subtract_func (GST_TYPE_FRACTION_RANGE,
4949       GST_TYPE_FRACTION_RANGE,
4950       gst_value_subtract_fraction_range_fraction_range);
4951
4952   /* see bug #317246, #64994, #65041 */
4953   {
4954     volatile GType date_type = G_TYPE_DATE;
4955
4956     g_type_name (date_type);
4957   }
4958
4959   gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
4960       gst_value_union_int_int_range);
4961   gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
4962       gst_value_union_int_range_int_range);
4963
4964 #if 0
4965   /* Implement these if needed */
4966   gst_value_register_union_func (GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE,
4967       gst_value_union_fraction_fraction_range);
4968   gst_value_register_union_func (GST_TYPE_FRACTION_RANGE,
4969       GST_TYPE_FRACTION_RANGE, gst_value_union_fraction_range_fraction_range);
4970 #endif
4971 }