5ab72588f89df2d35708ed42f6e66505a2251e96
[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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include <string.h>
24
25 #include <gst/gst.h>
26 #include <gobject/gvaluecollector.h>
27
28 typedef struct _GstValueCompareInfo GstValueCompareInfo;
29 struct _GstValueCompareInfo {
30   GType type;
31   GstValueCompareFunc func;
32 };
33
34 typedef struct _GstValueUnionInfo GstValueUnionInfo;
35 struct _GstValueUnionInfo {
36   GType type1;
37   GType type2;
38   GstValueUnionFunc func;
39 };
40
41 typedef struct _GstValueIntersectInfo GstValueIntersectInfo;
42 struct _GstValueIntersectInfo {
43   GType type1;
44   GType type2;
45   GstValueIntersectFunc func;
46 };
47
48 GType gst_type_fourcc;
49 GType gst_type_int_range;
50 GType gst_type_double_range;
51 GType gst_type_list;
52
53 GArray *gst_value_compare_funcs;
54 GArray *gst_value_union_funcs;
55 GArray *gst_value_intersect_funcs;
56
57 /* list */
58
59 static void
60 gst_value_init_list (GValue *value)
61 {
62   value->data[0].v_pointer = g_array_new (FALSE, TRUE, sizeof(GValue));
63 }
64
65 static GArray *
66 gst_value_list_array_copy (const GArray *src)
67 {
68   GArray *dest;
69   gint i;
70   
71   dest = g_array_sized_new (FALSE, TRUE, sizeof(GValue), src->len);
72   g_array_set_size (dest, src->len);
73   for (i = 0; i < src->len; i++) {
74     g_value_init (&g_array_index(dest, GValue, i), G_VALUE_TYPE (&g_array_index(src, GValue, i)));
75     g_value_copy (&g_array_index(src, GValue, i), &g_array_index(dest, GValue, i));
76   }
77
78   return dest;
79 }
80
81 static void
82 gst_value_copy_list (const GValue *src_value, GValue *dest_value)
83 {
84   dest_value->data[0].v_pointer = gst_value_list_array_copy ((GArray *) src_value->data[0].v_pointer);
85 }
86
87 static void
88 gst_value_free_list (GValue *value)
89 {
90   gint i;
91   GArray *src = (GArray *) value->data[0].v_pointer;
92   
93   if ((value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) == 0) {
94     for (i = 0; i < src->len; i++) {
95       g_value_unset (&g_array_index(src, GValue, i));
96     }
97     g_array_free (src, TRUE);
98   }
99 }
100
101 static gpointer
102 gst_value_list_peek_pointer (const GValue *value)
103 {
104   return value->data[0].v_pointer;
105 }
106
107 static gchar *
108 gst_value_collect_list (GValue *value, guint n_collect_values,
109     GTypeCValue *collect_values, guint collect_flags)
110 {
111   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
112     value->data[0].v_pointer = collect_values[0].v_pointer;
113     value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
114   } else {
115     value->data[0].v_pointer = gst_value_list_array_copy ((GArray *) collect_values[0].v_pointer);
116   }
117   return NULL;
118 }
119
120 static gchar *
121 gst_value_lcopy_list (const GValue *value, guint n_collect_values,
122     GTypeCValue *collect_values, guint collect_flags)
123 {
124   GArray **dest = collect_values[0].v_pointer;
125   if (!dest)
126     return g_strdup_printf ("value location for `%s' passed as NULL",
127         G_VALUE_TYPE_NAME (value));
128   if (!value->data[0].v_pointer)  
129     return g_strdup_printf ("invalid value given for `%s'",
130         G_VALUE_TYPE_NAME (value));
131   if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
132     *dest = (GArray *) value->data[0].v_pointer;
133   } else {
134     *dest = gst_value_list_array_copy ((GArray *) value->data[0].v_pointer);
135   }
136   return NULL;
137 }
138
139 void 
140 gst_value_list_prepend_value (GValue *value, const GValue *prepend_value)
141 {
142   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
143
144   g_array_prepend_vals ((GArray *) value->data[0].v_pointer, prepend_value, 1);
145 }
146
147 void 
148 gst_value_list_append_value (GValue *value, const GValue *append_value)
149 {
150   g_return_if_fail (GST_VALUE_HOLDS_LIST (value));
151
152   g_array_append_vals ((GArray *) value->data[0].v_pointer, append_value, 1);
153 }
154
155 guint 
156 gst_value_list_get_size (const GValue *value)
157 {
158   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), 0);
159
160   return ((GArray *) value->data[0].v_pointer)->len;
161 }
162
163 const GValue *
164 gst_value_list_get_value (const GValue *value, guint index)
165 {
166   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value), NULL);
167   g_return_val_if_fail (index < gst_value_list_get_size (value), NULL);
168
169   return (const GValue *) &g_array_index ((GArray *) value->data[0].v_pointer, GValue, index);
170 }
171
172 /**
173  * gst_value_list_concat:
174  * @dest: an uninitialized #GValue to take the result
175  * @value1: first value to put into the union
176  * @value2: second value to put into the union
177  *
178  * Concatenates copies of value1 and value2 into a list. dest will be 
179  * initialized to the type GST_TYPE_LIST.
180  */
181 void
182 gst_value_list_concat (GValue *dest, const GValue *value1, const GValue *value2)
183 {
184   guint i, value1_length, value2_length;
185   GArray *array;
186
187   g_return_if_fail (dest != NULL);
188   g_return_if_fail (G_VALUE_TYPE (dest) == 0);
189   g_return_if_fail (G_IS_VALUE (value1));
190   g_return_if_fail (G_IS_VALUE (value2));
191   
192   value1_length = (GST_VALUE_HOLDS_LIST (value1) ? gst_value_list_get_size (value1) : 1);
193   value2_length = (GST_VALUE_HOLDS_LIST (value2) ? gst_value_list_get_size (value2) : 1);
194   g_value_init (dest, GST_TYPE_LIST);
195   array = (GArray *) dest->data[0].v_pointer;
196   g_array_set_size (array, value1_length + value2_length);
197   
198   if (GST_VALUE_HOLDS_LIST (value1)) {
199     for (i = 0; i < value1_length; i++) {
200       g_value_init (&g_array_index(array, GValue, i), G_VALUE_TYPE (gst_value_list_get_value (value1, i)));
201       g_value_copy (gst_value_list_get_value (value1, i), &g_array_index(array, GValue, i));
202     }
203   } else {
204     g_value_init (&g_array_index(array, GValue, 0), G_VALUE_TYPE (value1));
205     g_value_copy (value1, &g_array_index(array, GValue, 0));
206   }
207   
208   if (GST_VALUE_HOLDS_LIST (value2)) {
209     for (i = 0; i < value2_length; i++) {
210       g_value_init (&g_array_index(array, GValue, i + value1_length), G_VALUE_TYPE (gst_value_list_get_value (value2, i)));
211       g_value_copy (gst_value_list_get_value (value2, i), &g_array_index(array, GValue, i + value1_length));
212     }
213   } else {
214     g_value_init (&g_array_index(array, GValue, value1_length), G_VALUE_TYPE (value2));
215     g_value_copy (value2, &g_array_index(array, GValue, value1_length));
216   }
217 }
218
219 /* fourcc */
220
221 static void 
222 gst_value_init_fourcc (GValue *value)
223 {
224   value->data[0].v_int = 0;
225 }
226
227 static void
228 gst_value_copy_fourcc (const GValue *src_value, GValue *dest_value)
229 {
230   dest_value->data[0].v_int = src_value->data[0].v_int;
231 }
232
233 static gchar *
234 gst_value_collect_fourcc (GValue *value, guint n_collect_values,
235     GTypeCValue *collect_values, guint collect_flags)
236 {
237   value->data[0].v_int = collect_values[0].v_int;
238
239   return NULL;
240 }
241
242 static gchar *
243 gst_value_lcopy_fourcc (const GValue *value, guint n_collect_values,
244     GTypeCValue *collect_values, guint collect_flags)
245 {
246   guint32 *fourcc_p = collect_values[0].v_pointer;
247
248   if (!fourcc_p)
249     return g_strdup_printf ("value location for `%s' passed as NULL",
250         G_VALUE_TYPE_NAME (value));
251
252   *fourcc_p = value->data[0].v_int;
253
254   return NULL;
255 }
256
257 void
258 gst_value_set_fourcc (GValue *value, guint32 fourcc)
259 {
260   g_return_if_fail (GST_VALUE_HOLDS_FOURCC (value));
261
262   value->data[0].v_int = fourcc;
263 }
264
265 guint32
266 gst_value_get_fourcc (const GValue *value)
267 {
268   g_return_val_if_fail (GST_VALUE_HOLDS_FOURCC (value), 0);
269
270   return value->data[0].v_int;
271 }
272
273 /* int range */
274
275 static void 
276 gst_value_init_int_range (GValue *value)
277 {
278   value->data[0].v_int = 0;
279   value->data[1].v_int = 0;
280 }
281
282 static void
283 gst_value_copy_int_range (const GValue *src_value, GValue *dest_value)
284 {
285   dest_value->data[0].v_int = src_value->data[0].v_int;
286   dest_value->data[1].v_int = src_value->data[1].v_int;
287 }
288
289 static gchar *
290 gst_value_collect_int_range (GValue *value, guint n_collect_values,
291     GTypeCValue *collect_values, guint collect_flags)
292 {
293   /* FIXME */
294   value->data[0].v_int = collect_values[0].v_int;
295   value->data[1].v_int = collect_values[1].v_int;
296
297   return NULL;
298 }
299
300 static gchar *
301 gst_value_lcopy_int_range (const GValue *value, guint n_collect_values,
302     GTypeCValue *collect_values, guint collect_flags)
303 {
304   guint32 *int_range_start = collect_values[0].v_pointer;
305   guint32 *int_range_end = collect_values[1].v_pointer;
306
307   if (!int_range_start)
308     return g_strdup_printf ("start value location for `%s' passed as NULL",
309         G_VALUE_TYPE_NAME (value));
310   if (!int_range_end)
311     return g_strdup_printf ("end value location for `%s' passed as NULL",
312         G_VALUE_TYPE_NAME (value));
313
314   *int_range_start = value->data[0].v_int;
315   *int_range_end = value->data[1].v_int;
316
317   return NULL;
318 }
319
320 void
321 gst_value_set_int_range (GValue *value, int start, int end)
322 {
323   g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value));
324
325   value->data[0].v_int = start;
326   value->data[1].v_int = end;
327 }
328
329 int
330 gst_value_get_int_range_min (const GValue *value)
331 {
332   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
333
334   return value->data[0].v_int;
335 }
336
337 int
338 gst_value_get_int_range_max (const GValue *value)
339 {
340   g_return_val_if_fail (GST_VALUE_HOLDS_INT_RANGE (value), 0);
341
342   return value->data[1].v_int;
343 }
344
345 /* double range */
346
347 static void 
348 gst_value_init_double_range (GValue *value)
349 {
350   value->data[0].v_double = 0;
351   value->data[1].v_double = 0;
352 }
353
354 static void
355 gst_value_copy_double_range (const GValue *src_value, GValue *dest_value)
356 {
357   dest_value->data[0].v_double = src_value->data[0].v_double;
358   dest_value->data[1].v_double = src_value->data[1].v_double;
359 }
360
361 static gchar *
362 gst_value_collect_double_range (GValue *value, guint n_collect_values,
363     GTypeCValue *collect_values, guint collect_flags)
364 {
365   value->data[0].v_double = collect_values[0].v_double;
366   value->data[1].v_double = collect_values[1].v_double;
367
368   return NULL;
369 }
370
371 static gchar *
372 gst_value_lcopy_double_range (const GValue *value, guint n_collect_values,
373     GTypeCValue *collect_values, guint collect_flags)
374 {
375   gdouble *double_range_start = collect_values[0].v_pointer;
376   gdouble *double_range_end = collect_values[1].v_pointer;
377
378   if (!double_range_start)
379     return g_strdup_printf ("start value location for `%s' passed as NULL",
380         G_VALUE_TYPE_NAME (value));
381   if (!double_range_end)
382     return g_strdup_printf ("end value location for `%s' passed as NULL",
383         G_VALUE_TYPE_NAME (value));
384
385   *double_range_start = value->data[0].v_double;
386   *double_range_end = value->data[1].v_double;
387
388   return NULL;
389 }
390
391 void
392 gst_value_set_double_range (GValue *value, double start, double end)
393 {
394   g_return_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value));
395
396   value->data[0].v_double = start;
397   value->data[1].v_double = end;
398 }
399
400 double
401 gst_value_get_double_range_min (const GValue *value)
402 {
403   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
404
405   return value->data[0].v_double;
406 }
407
408 double
409 gst_value_get_double_range_max (const GValue *value)
410 {
411   g_return_val_if_fail (GST_VALUE_HOLDS_DOUBLE_RANGE (value), 0);
412
413   return value->data[1].v_double;
414 }
415
416 /* GstCaps */
417
418 void
419 gst_value_set_caps (GValue *value, const GstCaps *caps)
420 {
421   g_return_if_fail (GST_VALUE_HOLDS_CAPS (value));
422
423   value->data[0].v_pointer = gst_caps_copy (caps);
424 }
425
426 const GstCaps *
427 gst_value_get_caps (const GValue *value)
428 {
429   g_return_val_if_fail (GST_VALUE_HOLDS_CAPS (value), 0);
430
431   return value->data[0].v_pointer;
432 }
433
434 /* fourcc */
435
436 static void
437 gst_value_transform_fourcc_string (const GValue *src_value,
438     GValue *dest_value)
439 {
440   guint32 fourcc = src_value->data[0].v_int;
441
442   if (g_ascii_isprint ((fourcc>>0) & 0xff) &&
443       g_ascii_isprint ((fourcc>>8) & 0xff) &&
444       g_ascii_isprint ((fourcc>>16) & 0xff) &&
445       g_ascii_isprint ((fourcc>>24) & 0xff)){
446     dest_value->data[0].v_pointer = g_strdup_printf(
447         GST_FOURCC_FORMAT, GST_FOURCC_ARGS(fourcc));
448   } else {
449     dest_value->data[0].v_pointer = g_strdup_printf("0x%08x", fourcc);
450   }
451 }
452
453 static void
454 gst_value_transform_int_range_string (const GValue *src_value,
455     GValue *dest_value)
456 {
457   dest_value->data[0].v_pointer = g_strdup_printf("[%d,%d]",
458       (int)src_value->data[0].v_int, (int)src_value->data[1].v_int);
459 }
460
461 static void
462 gst_value_transform_double_range_string (const GValue *src_value,
463     GValue *dest_value)
464 {
465   dest_value->data[0].v_pointer = g_strdup_printf("[%g,%g]",
466       src_value->data[0].v_double, src_value->data[1].v_double);
467 }
468
469 static void
470 gst_value_transform_list_string (const GValue *src_value,
471     GValue *dest_value)
472 {
473   GValue *list_value;
474   GArray *array;
475   GString *s;
476   int i;
477   char *list_s;
478
479   array = src_value->data[0].v_pointer;
480
481   s = g_string_new("{ ");
482   for(i=0;i<array->len;i++){
483     list_value = &g_array_index(array, GValue, i);
484
485     if (i != 0) {
486       g_string_append (s, ", ");
487     }
488     list_s = g_strdup_value_contents (list_value);
489     g_string_append (s, list_s);
490     g_free (list_s);
491   }
492   g_string_append (s, " }");
493
494   dest_value->data[0].v_pointer = g_string_free (s, FALSE);
495 }
496
497 /* comparison functions */
498
499 static int
500 gst_value_compare_boolean (const GValue *value1, const GValue *value2)
501 {
502   /* FIXME: ds, can we assume that those values are only TRUE and FALSE? */
503   if (value1->data[0].v_int == value2->data[0].v_int)
504     return GST_VALUE_EQUAL;
505   return GST_VALUE_UNORDERED;
506 }
507
508 static int
509 gst_value_compare_int (const GValue *value1, const GValue *value2)
510 {
511   if (value1->data[0].v_int > value2->data[0].v_int)
512     return GST_VALUE_GREATER_THAN;
513   if (value1->data[0].v_int < value2->data[0].v_int)
514     return GST_VALUE_LESS_THAN;
515   return GST_VALUE_EQUAL;
516 }
517
518 static int
519 gst_value_compare_double (const GValue *value1, const GValue *value2)
520 {
521   if (value1->data[0].v_double > value2->data[0].v_double)
522     return GST_VALUE_GREATER_THAN;
523   if (value1->data[0].v_double < value2->data[0].v_double)
524     return GST_VALUE_LESS_THAN;
525   if (value1->data[0].v_double == value2->data[0].v_double)
526     return GST_VALUE_EQUAL;
527   return GST_VALUE_UNORDERED;
528 }
529
530 static int
531 gst_value_compare_float (const GValue *value1, const GValue *value2)
532 {
533   if (value1->data[0].v_float > value2->data[0].v_float)
534     return GST_VALUE_GREATER_THAN;
535   if (value1->data[0].v_float < value2->data[0].v_float)
536     return GST_VALUE_LESS_THAN;
537   if (value1->data[0].v_float == value2->data[0].v_float)
538     return GST_VALUE_EQUAL;
539   return GST_VALUE_UNORDERED;
540 }
541
542 static int
543 gst_value_compare_string (const GValue *value1, const GValue *value2)
544 {
545   int x = strcmp(value1->data[0].v_pointer, value2->data[0].v_pointer);
546   if(x<0) return GST_VALUE_LESS_THAN;
547   if(x>0) return GST_VALUE_GREATER_THAN;
548   return GST_VALUE_EQUAL;
549 }
550
551 static int
552 gst_value_compare_fourcc (const GValue *value1, const GValue *value2)
553 {
554   if (value2->data[0].v_int == value1->data[0].v_int) return GST_VALUE_EQUAL;
555   return GST_VALUE_UNORDERED;
556 }
557
558 static int
559 gst_value_compare_int_range (const GValue *value1, const GValue *value2)
560 {
561   if (value2->data[0].v_int == value1->data[0].v_int &&
562       value2->data[0].v_int == value1->data[0].v_int) return GST_VALUE_EQUAL;
563   return GST_VALUE_UNORDERED;
564 }
565
566 static int
567 gst_value_compare_double_range (const GValue *value1, const GValue *value2)
568 {
569   if (value2->data[0].v_double == value1->data[0].v_double &&
570       value2->data[0].v_double == value1->data[0].v_double)
571     return GST_VALUE_EQUAL;
572   return GST_VALUE_UNORDERED;
573 }
574
575 static int
576 gst_value_compare_list (const GValue *value1, const GValue *value2)
577 {
578   int i,j;
579   GArray *array1 = value1->data[0].v_pointer;
580   GArray *array2 = value2->data[0].v_pointer;
581   GValue *v1;
582   GValue *v2;
583
584   if (array1->len != array2->len) return GST_VALUE_UNORDERED;
585
586   for(i=0;i<array1->len;i++){
587     v1 = &g_array_index (array1, GValue, i);
588     for(j=0;j<array1->len;j++){
589       v2 = &g_array_index (array2, GValue, j);
590       if (gst_value_compare(v1, v2) == GST_VALUE_EQUAL) break;
591     }
592     if (j==array1->len) {
593       return GST_VALUE_UNORDERED;
594     }
595   }
596
597   return GST_VALUE_EQUAL;
598 }
599
600 gboolean
601 gst_value_can_compare (const GValue *value1, const GValue *value2)
602 {
603   GstValueCompareInfo *compare_info;
604   int i;
605
606   if(G_VALUE_TYPE(value1) != G_VALUE_TYPE(value2))return FALSE;
607   for(i=0;i<gst_value_compare_funcs->len;i++){
608     compare_info = &g_array_index(gst_value_compare_funcs,
609         GstValueCompareInfo, i);
610     if(compare_info->type == G_VALUE_TYPE(value1)) return TRUE;
611   }
612
613   return FALSE;
614 }
615
616 int
617 gst_value_compare (const GValue *value1, const GValue *value2)
618 {
619   GstValueCompareInfo *compare_info;
620   int i;
621
622   if (G_VALUE_TYPE(value1) != G_VALUE_TYPE(value2)) return GST_VALUE_UNORDERED;
623
624   for(i=0;i<gst_value_compare_funcs->len;i++){
625     compare_info = &g_array_index(gst_value_compare_funcs,
626         GstValueCompareInfo, i);
627     if(compare_info->type != G_VALUE_TYPE(value1)) continue;
628
629     return compare_info->func(value1, value2);
630   }
631
632   g_critical("unable to compare values of type %s\n",
633       g_type_name (G_VALUE_TYPE (value1)));
634   return GST_VALUE_UNORDERED;
635 }
636
637 void
638 gst_value_register_compare_func (GType type, GstValueCompareFunc func)
639 {
640   GstValueCompareInfo compare_info;
641
642   compare_info.type = type;
643   compare_info.func = func;
644
645   g_array_append_val(gst_value_compare_funcs, compare_info);
646 }
647
648 /* union */
649
650 gboolean
651 gst_value_can_union (const GValue *value1, const GValue *value2)
652 {
653   GstValueUnionInfo *union_info;
654   int i;
655
656   for(i=0;i<gst_value_union_funcs->len;i++){
657     union_info = &g_array_index(gst_value_union_funcs, GstValueUnionInfo, i);
658     if(union_info->type1 == G_VALUE_TYPE(value1) &&
659         union_info->type2 == G_VALUE_TYPE(value2)) return TRUE;
660   }
661
662   return FALSE;
663 }
664
665 gboolean
666 gst_value_union (GValue *dest, const GValue *value1, const GValue *value2)
667 {
668   GstValueUnionInfo *union_info;
669   int i;
670
671   for(i=0;i<gst_value_union_funcs->len;i++){
672     union_info = &g_array_index(gst_value_union_funcs, GstValueUnionInfo, i);
673     if(union_info->type1 == G_VALUE_TYPE(value1) &&
674         union_info->type2 == G_VALUE_TYPE(value2)) {
675       return union_info->func(dest, value1, value2);
676     }
677   }
678   
679   gst_value_list_concat (dest, value1, value2);
680   return TRUE;
681 }
682
683 void
684 gst_value_register_union_func (GType type1, GType type2, GstValueUnionFunc func)
685 {
686   GstValueUnionInfo union_info;
687
688   union_info.type1 = type1;
689   union_info.type2 = type2;
690   union_info.func = func;
691
692   g_array_append_val(gst_value_union_funcs, union_info);
693 }
694
695 /* intersection */
696
697 static gboolean
698 gst_value_intersect_int_int_range (GValue *dest, const GValue *src1,
699     const GValue *src2)
700 {
701   g_return_val_if_fail(G_VALUE_TYPE(src1) == G_TYPE_INT, FALSE);
702   g_return_val_if_fail(G_VALUE_TYPE(src2) == GST_TYPE_INT_RANGE, FALSE);
703
704   if (src2->data[0].v_int <= src1->data[0].v_int &&
705       src2->data[1].v_int >= src1->data[0].v_int){
706     g_value_init(dest, G_TYPE_INT);
707     g_value_copy(src1, dest);
708     return TRUE;
709   }
710
711   return FALSE;
712 }
713
714 static gboolean
715 gst_value_intersect_int_range_int_range (GValue *dest, const GValue *src1,
716     const GValue *src2)
717 {
718   int min;
719   int max;
720
721   g_return_val_if_fail(G_VALUE_TYPE(src1) == GST_TYPE_INT_RANGE, FALSE);
722   g_return_val_if_fail(G_VALUE_TYPE(src2) == GST_TYPE_INT_RANGE, FALSE);
723
724   min = MAX(src1->data[0].v_int, src2->data[0].v_int);
725   max = MIN(src1->data[1].v_int, src2->data[1].v_int);
726
727   if(min < max){
728     g_value_init(dest, GST_TYPE_INT_RANGE);
729     gst_value_set_int_range(dest, min, max);
730     return TRUE;
731   }
732   if(min == max){
733     g_value_init(dest, G_TYPE_INT);
734     g_value_set_int(dest, min);
735     return TRUE;
736   }
737
738   return FALSE;
739 }
740
741 static gboolean
742 gst_value_intersect_double_double_range (GValue *dest, const GValue *src1,
743     const GValue *src2)
744 {
745   g_return_val_if_fail(G_VALUE_TYPE(src1) == G_TYPE_DOUBLE, FALSE);
746   g_return_val_if_fail(G_VALUE_TYPE(src2) == GST_TYPE_DOUBLE_RANGE, FALSE);
747
748   if (src2->data[0].v_double <= src1->data[0].v_double &&
749       src2->data[1].v_double >= src1->data[0].v_double){
750     g_value_init(dest, G_TYPE_DOUBLE);
751     g_value_copy(src1, dest);
752     return TRUE;
753   }
754
755   return FALSE;
756 }
757
758 static gboolean
759 gst_value_intersect_double_range_double_range (GValue *dest, const GValue *src1,
760     const GValue *src2)
761 {
762   double min;
763   double max;
764
765   g_return_val_if_fail(G_VALUE_TYPE(src1) == GST_TYPE_DOUBLE_RANGE, FALSE);
766   g_return_val_if_fail(G_VALUE_TYPE(src2) == GST_TYPE_DOUBLE_RANGE, FALSE);
767
768   min = MAX(src1->data[0].v_double, src2->data[0].v_double);
769   max = MIN(src1->data[1].v_double, src2->data[1].v_double);
770
771   if(min < max){
772     g_value_init(dest, GST_TYPE_DOUBLE_RANGE);
773     gst_value_set_double_range(dest, min, max);
774     return TRUE;
775   }
776   if(min == max){
777     g_value_init(dest, G_TYPE_DOUBLE);
778     g_value_set_int(dest, min);
779     return TRUE;
780   }
781
782   return FALSE;
783 }
784
785 static gboolean
786 gst_value_intersect_list (GValue *dest, const GValue *value1, const GValue *value2)
787 {
788   guint i, size;
789   GValue intersection = { 0, };
790   gboolean ret = FALSE;
791   
792   g_return_val_if_fail (GST_VALUE_HOLDS_LIST (value1), FALSE);
793
794   size = gst_value_list_get_size (value1);
795   for (i = 0; i < size; i++) {
796     const GValue *cur = gst_value_list_get_value (value1, i);
797
798     if (gst_value_intersect (&intersection, cur, value2)) {
799       /* append value */
800       if (!ret) {
801         g_value_init (dest, G_VALUE_TYPE(&intersection));
802         g_value_copy (dest, &intersection);
803         ret = TRUE;
804       } else if (GST_VALUE_HOLDS_LIST (dest)) {
805         gst_value_list_append_value (dest, &intersection);
806       } else {
807         GValue temp = {0, };
808
809         g_value_init (&temp, G_VALUE_TYPE(dest));
810         g_value_copy (dest, &temp);
811         g_value_unset (dest);
812         gst_value_list_concat (dest, &temp, &intersection);
813       }
814       g_value_unset (&intersection);
815     }
816   }
817
818   return ret;
819 }
820
821 gboolean
822 gst_value_can_intersect (const GValue *value1, const GValue *value2)
823 {
824   GstValueIntersectInfo *intersect_info;
825   int i;
826
827   /* special cases */
828   if (GST_VALUE_HOLDS_LIST (value1) || 
829       GST_VALUE_HOLDS_LIST (value2))
830     return TRUE;
831
832   for(i=0;i<gst_value_intersect_funcs->len;i++){
833     intersect_info = &g_array_index(gst_value_intersect_funcs,
834         GstValueIntersectInfo, i);
835     if(intersect_info->type1 == G_VALUE_TYPE(value1) &&
836         intersect_info->type2 == G_VALUE_TYPE(value2)) return TRUE;
837   }
838
839   return gst_value_can_compare (value1, value2);
840 }
841
842 gboolean
843 gst_value_intersect (GValue *dest, const GValue *value1, const GValue *value2)
844 {
845   GstValueIntersectInfo *intersect_info;
846   int i;
847   int ret = FALSE;
848
849   /* special cases first */
850   if (GST_VALUE_HOLDS_LIST (value1))
851     return gst_value_intersect_list (dest, value1, value2);
852   if (GST_VALUE_HOLDS_LIST (value2))
853     return gst_value_intersect_list (dest, value2, value1);
854     
855   for(i=0;i<gst_value_intersect_funcs->len;i++){
856     intersect_info = &g_array_index(gst_value_intersect_funcs,
857         GstValueIntersectInfo, i);
858     if(intersect_info->type1 == G_VALUE_TYPE(value1) &&
859         intersect_info->type2 == G_VALUE_TYPE(value2)) {
860       ret = intersect_info->func(dest, value1, value2);
861       return ret;
862     }
863     if(intersect_info->type1 == G_VALUE_TYPE(value2) &&
864         intersect_info->type2 == G_VALUE_TYPE(value1)) {
865       ret = intersect_info->func(dest, value2, value1);
866       return ret;
867     }
868   }
869
870   if(gst_value_compare(value1, value2) == GST_VALUE_EQUAL){
871     g_value_init(dest, G_VALUE_TYPE(value1));
872     g_value_copy(value1, dest);
873     ret = TRUE;
874   }
875
876   return ret;
877 }
878
879 void
880 gst_value_register_intersect_func (GType type1, GType type2,
881     GstValueIntersectFunc func)
882 {
883   GstValueIntersectInfo intersect_info;
884
885   intersect_info.type1 = type1;
886   intersect_info.type2 = type2;
887   intersect_info.func = func;
888
889   g_array_append_val(gst_value_intersect_funcs, intersect_info);
890 }
891
892 void
893 _gst_value_initialize (void)
894 {
895   GTypeInfo info = {
896     0,
897     NULL,
898     NULL,
899     NULL,
900     NULL,
901     NULL,
902     0,
903     0,
904     NULL,
905     NULL,
906   };
907   //const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };
908
909   {
910     static const GTypeValueTable value_table = {
911       gst_value_init_fourcc,
912       NULL,
913       gst_value_copy_fourcc,
914       NULL,
915       "i",
916       gst_value_collect_fourcc,
917       "p",
918       gst_value_lcopy_fourcc
919     };
920     info.value_table = &value_table;
921     gst_type_fourcc = g_type_register_static (G_TYPE_BOXED, "GstFourcc", &info, 0);
922   }
923
924   {
925     static const GTypeValueTable value_table = {
926       gst_value_init_int_range,
927       NULL,
928       gst_value_copy_int_range,
929       NULL,
930       "ii",
931       gst_value_collect_int_range,
932       "pp",
933       gst_value_lcopy_int_range
934     };
935     info.value_table = &value_table;
936     gst_type_int_range = g_type_register_static (G_TYPE_BOXED, "GstIntRange", &info, 0);
937   }
938
939   {
940     static const GTypeValueTable value_table = {
941       gst_value_init_double_range,
942       NULL,
943       gst_value_copy_double_range,
944       NULL,
945       "dd",
946       gst_value_collect_double_range,
947       "pp",
948       gst_value_lcopy_double_range
949     };
950     info.value_table = &value_table;
951     gst_type_double_range = g_type_register_static (G_TYPE_BOXED, "GstDoubleRange", &info, 0);
952   }
953   
954   {
955     static const GTypeValueTable value_table = {
956       gst_value_init_list,
957       gst_value_free_list,
958       gst_value_copy_list,
959       gst_value_list_peek_pointer,
960       "p",
961       gst_value_collect_list,
962       "p",
963       gst_value_lcopy_list
964     };
965     info.value_table = &value_table;
966     gst_type_list = g_type_register_static (G_TYPE_BOXED, "GstValueList", &info, 0);
967   }
968
969   g_value_register_transform_func (GST_TYPE_FOURCC, G_TYPE_STRING,
970       gst_value_transform_fourcc_string);
971   g_value_register_transform_func (GST_TYPE_INT_RANGE, G_TYPE_STRING,
972       gst_value_transform_int_range_string);
973   g_value_register_transform_func (GST_TYPE_DOUBLE_RANGE, G_TYPE_STRING,
974       gst_value_transform_double_range_string);
975   g_value_register_transform_func (GST_TYPE_LIST, G_TYPE_STRING,
976       gst_value_transform_list_string);
977
978   gst_value_compare_funcs = g_array_new(FALSE, FALSE,
979       sizeof(GstValueCompareInfo));
980
981   gst_value_register_compare_func (G_TYPE_BOOLEAN, gst_value_compare_boolean);
982   gst_value_register_compare_func (G_TYPE_INT, gst_value_compare_int);
983   gst_value_register_compare_func (G_TYPE_FLOAT, gst_value_compare_float);
984   gst_value_register_compare_func (G_TYPE_DOUBLE, gst_value_compare_double);
985   gst_value_register_compare_func (G_TYPE_STRING, gst_value_compare_string);
986   gst_value_register_compare_func (GST_TYPE_FOURCC, gst_value_compare_fourcc);
987   gst_value_register_compare_func (GST_TYPE_INT_RANGE, gst_value_compare_int_range);
988   gst_value_register_compare_func (GST_TYPE_DOUBLE_RANGE, gst_value_compare_double_range);
989   gst_value_register_compare_func (GST_TYPE_LIST, gst_value_compare_list);
990
991   gst_value_union_funcs = g_array_new(FALSE, FALSE,
992       sizeof(GstValueUnionInfo));
993
994   gst_value_intersect_funcs = g_array_new(FALSE, FALSE,
995       sizeof(GstValueIntersectInfo));
996
997   gst_value_register_intersect_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
998       gst_value_intersect_int_int_range);
999   gst_value_register_intersect_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,
1000       gst_value_intersect_int_range_int_range);
1001   gst_value_register_intersect_func (G_TYPE_DOUBLE, GST_TYPE_DOUBLE_RANGE,
1002       gst_value_intersect_double_double_range);
1003   gst_value_register_intersect_func (GST_TYPE_DOUBLE_RANGE, GST_TYPE_DOUBLE_RANGE,
1004       gst_value_intersect_double_range_double_range);
1005 }
1006
1007