source: trunk/third/gstreamer/gst/gstcaps.c @ 21448

Revision 21448, 39.0 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21447, which included commits to RCS files with non-trunk default branches.
Line 
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#include <signal.h>
25
26#include "gst_private.h"
27#include <gst/gst.h>
28
29#define CAPS_POISON(caps) G_STMT_START{ \
30  if (caps) { \
31    GstCaps *_newcaps = gst_caps_copy (caps); \
32    gst_caps_free(caps); \
33    caps = _newcaps; \
34  } \
35} G_STMT_END
36#define STRUCTURE_POISON(structure) G_STMT_START{ \
37  if (structure) { \
38    GstStructure *_newstruct = gst_structure_copy (structure); \
39    gst_structure_free(structure); \
40    structure = _newstruct; \
41  } \
42} G_STMT_END
43
44
45static void gst_caps_transform_to_string (const GValue * src_value,
46    GValue * dest_value);
47static gboolean gst_caps_from_string_inplace (GstCaps * caps,
48    const gchar * string);
49static GstCaps *gst_caps_copy_conditional (const GstCaps * src);
50
51GType
52gst_caps_get_type (void)
53{
54  static GType gst_caps_type = 0;
55
56  if (!gst_caps_type) {
57    gst_caps_type = g_boxed_type_register_static ("GstCaps",
58        (GBoxedCopyFunc) gst_caps_copy_conditional,
59        (GBoxedFreeFunc) gst_caps_free);
60
61    g_value_register_transform_func (gst_caps_type,
62        G_TYPE_STRING, gst_caps_transform_to_string);
63  }
64
65  return gst_caps_type;
66}
67
68/* creation/deletion */
69
70/**
71 * gst_caps_new_empty:
72 *
73 * Creates a new #GstCaps that is empty.  That is, the returned
74 * #GstCaps contains no media formats.
75 *
76 * Returns: the new #GstCaps
77 */
78GstCaps *
79gst_caps_new_empty (void)
80{
81  GstCaps *caps = g_new0 (GstCaps, 1);
82
83  caps->type = GST_TYPE_CAPS;
84  caps->structs = g_ptr_array_new ();
85
86  return caps;
87}
88
89/**
90 * gst_caps_new_any:
91 *
92 * Creates a new #GstCaps that indicates that it is compatible with
93 * any media format.
94 *
95 * Returns: the new #GstCaps
96 */
97GstCaps *
98gst_caps_new_any (void)
99{
100  GstCaps *caps = gst_caps_new_empty ();
101
102  caps->flags = GST_CAPS_FLAGS_ANY;
103
104  return caps;
105}
106
107/**
108 * gst_caps_new_simple:
109 * @media_type: the media type of the structure
110 * @fieldname: first field to set
111 * @...: additional arguments
112 *
113 * Creates a new #GstCaps that contains one #GstStructure.  The
114 * structure is defined by the arguments, which have the same format
115 * as @gst_structure_new().
116 *
117 * Returns: the new #GstCaps
118 */
119GstCaps *
120gst_caps_new_simple (const char *media_type, const char *fieldname, ...)
121{
122  GstCaps *caps;
123  GstStructure *structure;
124  va_list var_args;
125
126  caps = gst_caps_new_empty ();
127
128  va_start (var_args, fieldname);
129  structure = gst_structure_new_valist (media_type, fieldname, var_args);
130  va_end (var_args);
131
132  gst_caps_append_structure (caps, structure);
133
134  return caps;
135}
136
137/**
138 * gst_caps_new_full:
139 * @struct1: the first structure to add
140 * @...: additional structures to add
141 *
142 * Creates a new #GstCaps and adds all the structures listed as
143 * arguments.  The list must be NULL-terminated.  The structures
144 * are not copied; the returned #GstCaps owns the structures.
145 *
146 * Returns: the new #GstCaps
147 */
148GstCaps *
149gst_caps_new_full (GstStructure * struct1, ...)
150{
151  GstCaps *caps;
152  va_list var_args;
153
154  va_start (var_args, struct1);
155  caps = gst_caps_new_full_valist (struct1, var_args);
156  va_end (var_args);
157
158  return caps;
159}
160
161/**
162 * gst_caps_new_full_valist:
163 * @structure: the first structure to add
164 * @var_args: additional structures to add
165 *
166 * Creates a new #GstCaps and adds all the structures listed as
167 * arguments.  The list must be NULL-terminated.  The structures
168 * are not copied; the returned #GstCaps owns the structures.
169 *
170 * Returns: the new #GstCaps
171 */
172GstCaps *
173gst_caps_new_full_valist (GstStructure * structure, va_list var_args)
174{
175  GstCaps *caps;
176
177  caps = gst_caps_new_empty ();
178
179  while (structure) {
180    gst_caps_append_structure (caps, structure);
181    structure = va_arg (var_args, GstStructure *);
182  }
183
184  return caps;
185}
186
187/**
188 * gst_caps_copy:
189 * @caps: the #GstCaps to copy
190 *
191 * Deeply copies a #GstCaps, including all structures and all the
192 * structures' values.
193 *
194 * Returns: the new #GstCaps
195 */
196GstCaps *
197gst_caps_copy (const GstCaps * caps)
198{
199  GstCaps *newcaps;
200  GstStructure *structure;
201  int i;
202
203  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
204
205  newcaps = gst_caps_new_empty ();
206  newcaps->flags = caps->flags;
207
208  for (i = 0; i < caps->structs->len; i++) {
209    structure = gst_caps_get_structure (caps, i);
210    gst_caps_append_structure (newcaps, gst_structure_copy (structure));
211  }
212
213  return newcaps;
214}
215
216/**
217 * gst_caps_free:
218 * @caps: the #GstCaps to free
219 *
220 * Frees a #GstCaps and all its structures and the structures'
221 * values.
222 */
223void
224gst_caps_free (GstCaps * caps)
225{
226  GstStructure *structure;
227  int i;
228
229  g_return_if_fail (GST_IS_CAPS (caps));
230
231  for (i = 0; i < caps->structs->len; i++) {
232    structure = gst_caps_get_structure (caps, i);
233    gst_structure_free (structure);
234  }
235  g_ptr_array_free (caps->structs, TRUE);
236#ifdef USE_POISONING
237  memset (caps, 0xff, sizeof (GstCaps));
238#endif
239  g_free (caps);
240}
241
242/**
243 * gst_static_caps_get:
244 * @static_caps: the #GstStaticCaps to convert
245 *
246 * Converts a #GstStaticCaps to a #GstCaps.
247 *
248 * Returns: the new #GstCaps
249 */
250const GstCaps *
251gst_static_caps_get (GstStaticCaps * static_caps)
252{
253  GstCaps *caps = (GstCaps *) static_caps;
254  gboolean ret;
255
256  if (caps->type == 0) {
257    caps->type = GST_TYPE_CAPS;
258    caps->structs = g_ptr_array_new ();
259    ret = gst_caps_from_string_inplace (caps, static_caps->string);
260
261    if (!ret) {
262      g_critical ("Could not convert static caps \"%s\"", static_caps->string);
263    }
264  }
265
266  return caps;
267}
268
269/* manipulation */
270
271/**
272 * gst_caps_append:
273 * @caps1: the #GstCaps that will be appended to
274 * @caps2: the #GstCaps to append
275 *
276 * Appends the structures contained in @caps2 to @caps1.  The structures
277 * in @caps2 are not copied -- they are transferred to @caps1, and then
278 * @caps2 is freed.
279 */
280void
281gst_caps_append (GstCaps * caps1, GstCaps * caps2)
282{
283  GstStructure *structure;
284  int i;
285
286  g_return_if_fail (GST_IS_CAPS (caps1));
287  g_return_if_fail (GST_IS_CAPS (caps2));
288
289#ifdef USE_POISONING
290  CAPS_POISON (caps2);
291#endif
292  if (gst_caps_is_any (caps1) || gst_caps_is_any (caps2)) {
293    /* FIXME: this leaks */
294    caps1->flags |= GST_CAPS_FLAGS_ANY;
295    for (i = 0; i < caps2->structs->len; i++) {
296      structure = gst_caps_get_structure (caps2, i);
297      gst_structure_remove_all_fields (structure);
298    }
299  } else {
300    for (i = 0; i < caps2->structs->len; i++) {
301      structure = gst_caps_get_structure (caps2, i);
302      gst_caps_append_structure (caps1, structure);
303    }
304  }
305  g_ptr_array_free (caps2->structs, TRUE);
306#ifdef USE_POISONING
307  memset (caps2, 0xff, sizeof (GstCaps));
308#endif
309  g_free (caps2);
310}
311
312/**
313 * gst_caps_append_structure:
314 * @caps: the #GstCaps that will be appended to
315 * @structure: the #GstStructure to append
316 *
317 * Appends @structure to @caps.  The structure is not copied; @caps
318 * becomes the owner of @structure.
319 */
320void
321gst_caps_append_structure (GstCaps * caps, GstStructure * structure)
322{
323  g_return_if_fail (GST_IS_CAPS (caps));
324
325  if (structure) {
326#if 0
327#ifdef USE_POISONING
328    STRUCTURE_POISON (structure);
329#endif
330#endif
331    g_ptr_array_add (caps->structs, structure);
332  }
333}
334
335static GstStructure *
336gst_caps_remove_and_get_structure (GstCaps * caps, guint idx)
337{
338  /* don't use index_fast, gst_caps_simplify relies on the order */
339  return g_ptr_array_remove_index (caps->structs, idx);
340}
341
342/*
343 * gst_caps_remove_structure:
344 * @caps: the #GstCaps to remove from
345 * @idx: Index of the structure to remove
346 *
347 * removes the stucture with the given index from the list of structures
348 * contained in @caps.
349 */
350void
351gst_caps_remove_structure (GstCaps * caps, guint idx)
352{
353  GstStructure *structure;
354
355  g_return_if_fail (caps != NULL);
356  g_return_if_fail (idx <= gst_caps_get_size (caps));
357
358  structure = gst_caps_remove_and_get_structure (caps, idx);
359  gst_structure_free (structure);
360}
361
362/**
363 * gst_caps_split_one:
364 * @caps: a #GstCaps
365 *
366 * This function is not implemented.
367 *
368 * Returns: NULL
369 */
370GstCaps *
371gst_caps_split_one (GstCaps * caps)
372{
373  /* FIXME */
374  g_critical ("unimplemented");
375
376  return NULL;
377}
378
379/**
380 * gst_caps_get_size:
381 * @caps: a #GstCaps
382 *
383 * Gets the number of structures contained in @caps.
384 *
385 * Returns: the number of structures that @caps contains
386 */
387int
388gst_caps_get_size (const GstCaps * caps)
389{
390  g_return_val_if_fail (GST_IS_CAPS (caps), 0);
391
392  return caps->structs->len;
393}
394
395/**
396 * gst_caps_get_structure:
397 * @caps: a #GstCaps
398 * @index: the index of the structure
399 *
400 * Finds the structure in @caps that has the index @index, and
401 * returns it.
402 *
403 * WARNING: This function takes a const GstCaps *, but returns a
404 * non-const GstStructure *.  This is for programming convenience --
405 * the caller should be aware that structures inside a constant
406 * @GstCaps should not be modified.
407 *
408 * Returns: a pointer to the #GstStructure corresponding to @index
409 */
410GstStructure *
411gst_caps_get_structure (const GstCaps * caps, int index)
412{
413  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
414  g_return_val_if_fail (index >= 0, NULL);
415  g_return_val_if_fail (index < caps->structs->len, NULL);
416
417  return g_ptr_array_index (caps->structs, index);
418}
419
420/**
421 * gst_caps_copy_1:
422 * @caps: the @GstCaps to copy
423 *
424 * Creates a new @GstCaps and appends a copy of the first structure
425 * contained in @caps.
426 *
427 * Returns: the new @GstCaps
428 */
429GstCaps *
430gst_caps_copy_1 (const GstCaps * caps)
431{
432  GstCaps *newcaps;
433  GstStructure *structure;
434
435  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
436
437  newcaps = gst_caps_new_empty ();
438  newcaps->flags = caps->flags;
439
440  if (caps->structs->len > 0) {
441    structure = gst_caps_get_structure (caps, 0);
442    gst_caps_append_structure (newcaps, gst_structure_copy (structure));
443  }
444
445  return newcaps;
446}
447
448/**
449 * gst_caps_set_simple:
450 * @caps: the @GstCaps to set
451 * @field: first field to set
452 * @...: additional parameters
453 *
454 * Sets fields in a simple #GstCaps.  A simple #GstCaps is one that
455 * only has one structure.  The arguments must be passed in the same
456 * manner as @gst_structure_set(), and be NULL-terminated.
457 */
458void
459gst_caps_set_simple (GstCaps * caps, char *field, ...)
460{
461  GstStructure *structure;
462  va_list var_args;
463
464  g_return_if_fail (GST_IS_CAPS (caps));
465  g_return_if_fail (caps->structs->len == 1);
466
467  structure = gst_caps_get_structure (caps, 0);
468
469  va_start (var_args, field);
470  gst_structure_set_valist (structure, field, var_args);
471  va_end (var_args);
472}
473
474/**
475 * gst_caps_set_simple_valist:
476 * @caps: the @GstCaps to copy
477 * @field: first field to set
478 * @varargs: additional parameters
479 *
480 * Sets fields in a simple #GstCaps.  A simple #GstCaps is one that
481 * only has one structure.  The arguments must be passed in the same
482 * manner as @gst_structure_set(), and be NULL-terminated.
483 */
484void
485gst_caps_set_simple_valist (GstCaps * caps, char *field, va_list varargs)
486{
487  GstStructure *structure;
488
489  g_return_if_fail (GST_IS_CAPS (caps));
490  g_return_if_fail (caps->structs->len != 1);
491
492  structure = gst_caps_get_structure (caps, 0);
493
494  gst_structure_set_valist (structure, field, varargs);
495}
496
497/* tests */
498
499/**
500 * gst_caps_is_any:
501 * @caps: the @GstCaps to test
502 *
503 * Determines if @caps represents any media format.
504 *
505 * Returns: TRUE if @caps represents any format.
506 */
507gboolean
508gst_caps_is_any (const GstCaps * caps)
509{
510  g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
511
512  return (caps->flags & GST_CAPS_FLAGS_ANY);
513}
514
515/**
516 * gst_caps_is_empty:
517 * @caps: the @GstCaps to test
518 *
519 * Determines if @caps represents no media formats.
520 *
521 * Returns: TRUE if @caps represents no formats.
522 */
523gboolean
524gst_caps_is_empty (const GstCaps * caps)
525{
526  g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
527
528  if (caps->flags & GST_CAPS_FLAGS_ANY)
529    return FALSE;
530
531  return (caps->structs == NULL) || (caps->structs->len == 0);
532}
533
534/**
535 * gst_caps_is_chained:
536 * @caps: the @GstCaps to test
537 *
538 * Determines if @caps contains multiple #GstStructures.
539 *
540 * This function is deprecated, and should not be used in new code.
541 * Use #gst_caps_is_simple() instead.
542 *
543 * Returns: TRUE if @caps contains more than one structure
544 */
545gboolean
546gst_caps_is_chained (const GstCaps * caps)
547{
548  g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
549
550  return (caps->structs->len > 1);
551}
552
553static gboolean
554gst_caps_is_fixed_foreach (GQuark field_id, GValue * value, gpointer unused)
555{
556  return gst_value_is_fixed (value);
557}
558
559/**
560 * gst_caps_is_fixed:
561 * @caps: the @GstCaps to test
562 *
563 * Fixed @GstCaps describe exactly one format, that is, they have exactly
564 * one structure, and each field in the structure describes a fixed type.
565 * Examples of non-fixed types are GST_TYPE_INT_RANGE and GST_TYPE_LIST.
566 *
567 * Returns: TRUE if @caps is fixed
568 */
569gboolean
570gst_caps_is_fixed (const GstCaps * caps)
571{
572  GstStructure *structure;
573
574  g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
575
576  if (caps->structs->len != 1)
577    return FALSE;
578
579  structure = gst_caps_get_structure (caps, 0);
580
581  return gst_structure_foreach (structure, gst_caps_is_fixed_foreach, NULL);
582}
583
584static gboolean
585gst_structure_is_equal_foreach (GQuark field_id, GValue * val2, gpointer data)
586{
587  GstStructure *struct1 = (GstStructure *) data;
588  const GValue *val1 = gst_structure_id_get_value (struct1, field_id);
589
590  if (val1 == NULL)
591    return FALSE;
592  if (gst_value_compare (val1, val2) == GST_VALUE_EQUAL) {
593    return TRUE;
594  }
595
596  return FALSE;
597}
598
599/**
600 * gst_caps_is_equal_fixed:
601 * @caps1: the #GstCaps to test
602 * @caps2: the #GstCaps to test
603 *
604 * Tests if two #GstCaps are equal.  This function only works on fixed
605 * #GstCaps.
606 *
607 * Returns: TRUE if the arguments represent the same format
608 */
609gboolean
610gst_caps_is_equal_fixed (const GstCaps * caps1, const GstCaps * caps2)
611{
612  GstStructure *struct1, *struct2;
613
614  g_return_val_if_fail (gst_caps_is_fixed (caps1), FALSE);
615  g_return_val_if_fail (gst_caps_is_fixed (caps2), FALSE);
616
617  struct1 = gst_caps_get_structure (caps1, 0);
618  struct2 = gst_caps_get_structure (caps2, 0);
619
620  if (struct1->name != struct2->name) {
621    return FALSE;
622  }
623  if (struct1->fields->len != struct2->fields->len) {
624    return FALSE;
625  }
626
627  return gst_structure_foreach (struct1, gst_structure_is_equal_foreach,
628      struct2);
629}
630
631/**
632 * gst_caps_is_always_compatible:
633 * @caps1: the #GstCaps to test
634 * @caps2: the #GstCaps to test
635 *
636 * A given #GstCaps structure is always compatible with another if
637 * every media format that is in the first is also contained in the
638 * second.  That is, @caps1 is a subset of @caps2.
639 *
640 * Returns: TRUE if @caps1 is a subset of @caps2.
641 */
642gboolean
643gst_caps_is_always_compatible (const GstCaps * caps1, const GstCaps * caps2)
644{
645  g_return_val_if_fail (GST_IS_CAPS (caps1), FALSE);
646  g_return_val_if_fail (GST_IS_CAPS (caps2), FALSE);
647
648  return gst_caps_is_subset (caps1, caps2);
649}
650
651/**
652 * gst_caps_is_subset:
653 * @subset: a #GstCaps
654 * @superset: a potentially greater #GstCaps
655 *
656 * Checks if all caps represented by @subset are also represented by @superset
657 * <note>This function does not work reliably if optional properties for caps
658 * are included on one caps and omitted on the other.</note>
659 *
660 * Returns: TRUE if @subset is a subset of @superset
661 */
662gboolean
663gst_caps_is_subset (const GstCaps * subset, const GstCaps * superset)
664{
665  GstCaps *caps;
666  gboolean ret;
667
668  g_return_val_if_fail (subset != NULL, FALSE);
669  g_return_val_if_fail (superset != NULL, FALSE);
670
671  if (gst_caps_is_empty (subset) || gst_caps_is_any (superset))
672    return TRUE;
673  if (gst_caps_is_any (subset) || gst_caps_is_empty (superset))
674    return FALSE;
675
676  caps = gst_caps_subtract (subset, superset);
677  ret = gst_caps_is_empty (caps);
678  gst_caps_free (caps);
679  return ret;
680}
681
682/**
683 * gst_caps_is_equal:
684 * @caps1: a #GstCaps
685 * @caps2: another #GstCaps
686 *
687 * Checks if the given caps represent the same set of caps.
688 * <note>This function does not work reliably if optional properties for caps
689 * are included on one caps and omitted on the other.</note>
690 *
691 * Returns: TRUE if both caps are equal
692 */
693gboolean
694gst_caps_is_equal (const GstCaps * caps1, const GstCaps * caps2)
695{
696  g_return_val_if_fail (caps1 != NULL, FALSE);
697  g_return_val_if_fail (caps2 != NULL, FALSE);
698
699  if (gst_caps_is_fixed (caps1) && gst_caps_is_fixed (caps2))
700    return gst_caps_is_equal_fixed (caps1, caps2);
701
702  return gst_caps_is_subset (caps1, caps2) && gst_caps_is_subset (caps2, caps1);
703}
704
705typedef struct
706{
707  GstStructure *dest;
708  const GstStructure *intersect;
709  gboolean first_run;
710}
711IntersectData;
712
713static gboolean
714gst_caps_structure_intersect_field (GQuark id, GValue * val1, gpointer data)
715{
716  IntersectData *idata = (IntersectData *) data;
717  GValue dest_value = { 0 };
718  const GValue *val2 = gst_structure_id_get_value (idata->intersect, id);
719
720  if (val2 == NULL) {
721    gst_structure_id_set_value (idata->dest, id, val1);
722  } else if (idata->first_run) {
723    if (gst_value_intersect (&dest_value, val1, val2)) {
724      gst_structure_id_set_value (idata->dest, id, &dest_value);
725      g_value_unset (&dest_value);
726    } else {
727      return FALSE;
728    }
729  }
730
731  return TRUE;
732}
733
734static GstStructure *
735gst_caps_structure_intersect (const GstStructure * struct1,
736    const GstStructure * struct2)
737{
738  IntersectData data;
739
740  g_return_val_if_fail (struct1 != NULL, NULL);
741  g_return_val_if_fail (struct2 != NULL, NULL);
742
743  if (struct1->name != struct2->name)
744    return NULL;
745
746  data.dest = gst_structure_id_empty_new (struct1->name);
747  data.intersect = struct2;
748  data.first_run = TRUE;
749  if (!gst_structure_foreach ((GstStructure *) struct1,
750          gst_caps_structure_intersect_field, &data))
751    goto error;
752
753  data.intersect = struct1;
754  data.first_run = FALSE;
755  if (!gst_structure_foreach ((GstStructure *) struct2,
756          gst_caps_structure_intersect_field, &data))
757    goto error;
758
759  return data.dest;
760
761error:
762  gst_structure_free (data.dest);
763  return NULL;
764}
765
766#if 0
767static GstStructure *
768gst_caps_structure_union (const GstStructure * struct1,
769    const GstStructure * struct2)
770{
771  int i;
772  GstStructure *dest;
773  const GstStructureField *field1;
774  const GstStructureField *field2;
775  int ret;
776
777  /* FIXME this doesn't actually work */
778
779  if (struct1->name != struct2->name)
780    return NULL;
781
782  dest = gst_structure_id_empty_new (struct1->name);
783
784  for (i = 0; i < struct1->fields->len; i++) {
785    GValue dest_value = { 0 };
786
787    field1 = GST_STRUCTURE_FIELD (struct1, i);
788    field2 = gst_structure_id_get_field (struct2, field1->name);
789
790    if (field2 == NULL) {
791      continue;
792    } else {
793      if (gst_value_union (&dest_value, &field1->value, &field2->value)) {
794        gst_structure_set_value (dest, g_quark_to_string (field1->name),
795            &dest_value);
796      } else {
797        ret = gst_value_compare (&field1->value, &field2->value);
798      }
799    }
800  }
801
802  return dest;
803}
804#endif
805
806/* operations */
807
808/**
809 * gst_caps_intersect:
810 * @caps1: a #GstCaps to intersect
811 * @caps2: a #GstCaps to intersect
812 *
813 * Creates a new #GstCaps that contains all the formats that are common
814 * to both @caps1 and @caps2.
815 *
816 * Returns: the new #GstCaps
817 */
818GstCaps *
819gst_caps_intersect (const GstCaps * caps1, const GstCaps * caps2)
820{
821  int i, j;
822  GstStructure *struct1;
823  GstStructure *struct2;
824  GstCaps *dest;
825
826  g_return_val_if_fail (GST_IS_CAPS (caps1), NULL);
827  g_return_val_if_fail (GST_IS_CAPS (caps2), NULL);
828
829  if (gst_caps_is_empty (caps1) || gst_caps_is_empty (caps2)) {
830    return gst_caps_new_empty ();
831  }
832  if (gst_caps_is_any (caps1))
833    return gst_caps_copy (caps2);
834  if (gst_caps_is_any (caps2))
835    return gst_caps_copy (caps1);
836
837  dest = gst_caps_new_empty ();
838  for (i = 0; i < caps1->structs->len; i++) {
839    struct1 = gst_caps_get_structure (caps1, i);
840    for (j = 0; j < caps2->structs->len; j++) {
841      GstStructure *istruct;
842
843      struct2 = gst_caps_get_structure (caps2, j);
844      istruct = gst_caps_structure_intersect (struct1, struct2);
845
846      gst_caps_append_structure (dest, istruct);
847    }
848  }
849
850  gst_caps_do_simplify (dest);
851  return dest;
852}
853
854typedef struct
855{
856  const GstStructure *subtract_from;
857  GSList *put_into;
858}
859SubtractionEntry;
860
861
862gboolean
863gst_caps_structure_subtract_field (GQuark field_id, GValue * value,
864    gpointer user_data)
865{
866  SubtractionEntry *e = user_data;
867  GValue subtraction = { 0, };
868  const GValue *other;
869  GstStructure *structure;
870
871  other = gst_structure_id_get_value (e->subtract_from, field_id);
872  if (!other) {
873    return FALSE;
874  }
875  if (!gst_value_subtract (&subtraction, other, value))
876    return TRUE;
877  if (gst_value_compare (&subtraction, other) == GST_VALUE_EQUAL) {
878    g_value_unset (&subtraction);
879    return FALSE;
880  } else {
881    structure = gst_structure_copy (e->subtract_from);
882    gst_structure_id_set_value (structure, field_id, &subtraction);
883    g_value_unset (&subtraction);
884    e->put_into = g_slist_prepend (e->put_into, structure);
885    return TRUE;
886  }
887}
888
889static gboolean
890gst_caps_structure_subtract (GSList ** into, const GstStructure * minuend,
891    const GstStructure * subtrahend)
892{
893  SubtractionEntry e;
894  gboolean ret;
895
896  e.subtract_from = minuend;
897  e.put_into = NULL;
898
899  ret = gst_structure_foreach ((GstStructure *) subtrahend,
900      gst_caps_structure_subtract_field, &e);
901  if (ret) {
902    *into = e.put_into;
903  } else {
904    GSList *walk;
905
906    for (walk = e.put_into; walk; walk = g_slist_next (walk)) {
907      gst_structure_free (walk->data);
908    }
909    g_slist_free (e.put_into);
910  }
911  return ret;
912}
913
914/**
915 * gst_caps_subtract:
916 * @minuend: #GstCaps to substract from
917 * @subtrahend: #GstCaps to substract
918 *
919 * Subtracts the @subtrahend from the @minuend.
920 * <note>This function does not work reliably if optional properties for caps
921 * are included on one caps and omitted on the other.</note>
922 *
923 * Returns: the resulting caps
924 */
925GstCaps *
926gst_caps_subtract (const GstCaps * minuend, const GstCaps * subtrahend)
927{
928  int i, j;
929  GstStructure *min;
930  GstStructure *sub;
931  GstCaps *dest = NULL, *src;
932
933  g_return_val_if_fail (minuend != NULL, NULL);
934  g_return_val_if_fail (subtrahend != NULL, NULL);
935
936  if (gst_caps_is_empty (minuend) || gst_caps_is_any (subtrahend)) {
937    return gst_caps_new_empty ();
938  }
939  if (gst_caps_is_empty (subtrahend))
940    return gst_caps_copy (minuend);
941
942  /* FIXME: Do we want this here or above?
943     The reason we need this is that there is no definition about what
944     ANY means for specific types, so it's not possible to reduce ANY partially
945     You can only remove everything or nothing and that is done above.
946     Note: there's a test that checks this behaviour. */
947  g_return_val_if_fail (!gst_caps_is_any (minuend), NULL);
948  g_assert (subtrahend->structs->len > 0);
949
950  src = gst_caps_copy (minuend);
951  for (i = 0; i < subtrahend->structs->len; i++) {
952    sub = gst_caps_get_structure (subtrahend, i);
953    if (dest) {
954      gst_caps_free (src);
955      src = dest;
956    }
957    dest = gst_caps_new_empty ();
958    for (j = 0; j < src->structs->len; j++) {
959      min = gst_caps_get_structure (src, j);
960      if (gst_structure_get_name_id (min) == gst_structure_get_name_id (sub)) {
961        GSList *list;
962
963        if (gst_caps_structure_subtract (&list, min, sub)) {
964          GSList *walk;
965
966          for (walk = list; walk; walk = g_slist_next (walk)) {
967            gst_caps_append_structure (dest, (GstStructure *) walk->data);
968          }
969          g_slist_free (list);
970        } else {
971          gst_caps_append_structure (dest, gst_structure_copy (min));
972        }
973      } else {
974        gst_caps_append_structure (dest, gst_structure_copy (min));
975      }
976    }
977    if (gst_caps_is_empty (dest)) {
978      gst_caps_free (src);
979      return dest;
980    }
981  }
982
983  gst_caps_free (src);
984  gst_caps_do_simplify (dest);
985  return dest;
986}
987
988/**
989 * gst_caps_union:
990 * @caps1: a #GstCaps to union
991 * @caps2: a #GstCaps to union
992 *
993 * Creates a new #GstCaps that contains all the formats that are in
994 * either @caps1 and @caps2.
995 *
996 * Returns: the new #GstCaps
997 */
998GstCaps *
999gst_caps_union (const GstCaps * caps1, const GstCaps * caps2)
1000{
1001  GstCaps *dest1;
1002  GstCaps *dest2;
1003
1004  if (gst_caps_is_any (caps1) || gst_caps_is_any (caps2))
1005    return gst_caps_new_any ();
1006
1007  dest1 = gst_caps_copy (caps1);
1008  dest2 = gst_caps_copy (caps2);
1009  gst_caps_append (dest1, dest2);
1010
1011  gst_caps_do_simplify (dest1);
1012  return dest1;
1013}
1014
1015typedef struct _NormalizeForeach
1016{
1017  GstCaps *caps;
1018  GstStructure *structure;
1019}
1020NormalizeForeach;
1021
1022static gboolean
1023gst_caps_normalize_foreach (GQuark field_id, GValue * value, gpointer ptr)
1024{
1025  NormalizeForeach *nf = (NormalizeForeach *) ptr;
1026  GValue val = { 0 };
1027  int i;
1028
1029  if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
1030    for (i = 1; i < gst_value_list_get_size (value); i++) {
1031      const GValue *v = gst_value_list_get_value (value, i);
1032      GstStructure *structure = gst_structure_copy (nf->structure);
1033
1034      gst_structure_id_set_value (structure, field_id, v);
1035      gst_caps_append_structure (nf->caps, structure);
1036    }
1037
1038    gst_value_init_and_copy (&val, gst_value_list_get_value (value, 0));
1039    gst_structure_id_set_value (nf->structure, field_id, &val);
1040    g_value_unset (&val);
1041
1042    return FALSE;
1043  }
1044  return TRUE;
1045}
1046
1047/**
1048 * gst_caps_normalize:
1049 * @caps: a #GstCaps to normalize
1050 *
1051 * Creates a new #GstCaps that represents the same set of formats as
1052 * @caps, but contains no lists.  Each list is expanded into separate
1053 * @GstStructures.
1054 *
1055 * Returns: the new #GstCaps
1056 */
1057GstCaps *
1058gst_caps_normalize (const GstCaps * caps)
1059{
1060  NormalizeForeach nf;
1061  GstCaps *newcaps;
1062  int i;
1063
1064  g_return_val_if_fail (GST_IS_CAPS (caps), NULL);
1065
1066  newcaps = gst_caps_copy (caps);
1067  nf.caps = newcaps;
1068
1069  for (i = 0; i < newcaps->structs->len; i++) {
1070    nf.structure = gst_caps_get_structure (newcaps, i);
1071
1072    while (!gst_structure_foreach (nf.structure,
1073            gst_caps_normalize_foreach, &nf));
1074  }
1075
1076  return newcaps;
1077}
1078
1079static gint
1080gst_caps_compare_structures (gconstpointer one, gconstpointer two)
1081{
1082  gint ret;
1083  const GstStructure *struct1 = *((const GstStructure **) one);
1084  const GstStructure *struct2 = *((const GstStructure **) two);
1085
1086  /* FIXME: this orders aphabetically, but ordering the quarks might be faster
1087     So what's the best way? */
1088  ret = strcmp (gst_structure_get_name (struct1),
1089      gst_structure_get_name (struct2));
1090  if (ret)
1091    return ret;
1092
1093  return gst_structure_n_fields (struct1) - gst_structure_n_fields (struct2);
1094}
1095
1096/**
1097 * gst_caps_simplify:
1098 * @caps: a #GstCaps to simplify
1099 *
1100 * Creates a new #GstCaps that represents the same set of formats as
1101 * @caps, but simpler.  Component structures that are identical are
1102 * merged.  Component structures that have ranges or lists that can
1103 * be merged are also merged.
1104 *
1105 * Returns: the new #GstCaps
1106 */
1107GstCaps *
1108gst_caps_simplify (const GstCaps * caps)
1109{
1110  GstCaps *ret;
1111
1112  g_return_val_if_fail (caps != NULL, NULL);
1113
1114  ret = gst_caps_copy (caps);
1115  gst_caps_do_simplify (ret);
1116
1117  return ret;
1118}
1119
1120typedef struct
1121{
1122  GQuark name;
1123  GValue value;
1124  GstStructure *compare;
1125}
1126UnionField;
1127
1128static gboolean
1129gst_caps_structure_figure_out_union (GQuark field_id, GValue * value,
1130    gpointer user_data)
1131{
1132  UnionField *u = user_data;
1133  const GValue *val = gst_structure_id_get_value (u->compare, field_id);
1134
1135  if (!val) {
1136    if (u->name)
1137      g_value_unset (&u->value);
1138    return FALSE;
1139  }
1140  if (gst_value_compare (val, value) == GST_VALUE_EQUAL)
1141    return TRUE;
1142  if (u->name) {
1143    g_value_unset (&u->value);
1144    return FALSE;
1145  }
1146  u->name = field_id;
1147  gst_value_union (&u->value, val, value);
1148  return TRUE;
1149}
1150
1151static gboolean
1152gst_caps_structure_simplify (GstStructure ** result,
1153    const GstStructure * simplify, GstStructure * compare)
1154{
1155  GSList *list;
1156  UnionField field = { 0, {0,}, NULL };
1157
1158  /* try to subtract to get a real subset */
1159  if (gst_caps_structure_subtract (&list, simplify, compare)) {
1160    switch (g_slist_length (list)) {
1161      case 0:
1162        *result = NULL;
1163        return TRUE;
1164      case 1:
1165        *result = list->data;
1166        g_slist_free (list);
1167        return TRUE;
1168      default:
1169      {
1170        GSList *walk;
1171
1172        for (walk = list; walk; walk = g_slist_next (walk)) {
1173          gst_structure_free (walk->data);
1174        }
1175        g_slist_free (list);
1176        break;
1177      }
1178    }
1179  }
1180
1181  /* try to union both structs */
1182  field.compare = compare;
1183  if (gst_structure_foreach ((GstStructure *) simplify,
1184          gst_caps_structure_figure_out_union, &field)) {
1185    gboolean ret = FALSE;
1186
1187    /* now we know all of simplify's fields are the same in compare
1188     * but at most one field: field.name */
1189    if (G_IS_VALUE (&field.value)) {
1190      if (gst_structure_n_fields (simplify) == gst_structure_n_fields (compare)) {
1191        gst_structure_id_set_value (compare, field.name, &field.value);
1192        *result = NULL;
1193        ret = TRUE;
1194      }
1195      g_value_unset (&field.value);
1196    } else if (gst_structure_n_fields (simplify) <=
1197        gst_structure_n_fields (compare)) {
1198      /* compare is just more specific, will be optimized away later */
1199      /* FIXME: do this here? */
1200      GST_LOG ("found a case that will be optimized later.");
1201    } else {
1202      gchar *one = gst_structure_to_string (simplify);
1203      gchar *two = gst_structure_to_string (compare);
1204
1205      GST_ERROR
1206          ("caps mismatch: structures %s and %s claim to be possible to unify, but aren't",
1207          one, two);
1208      g_free (one);
1209      g_free (two);
1210    }
1211    return ret;
1212  }
1213
1214  return FALSE;
1215}
1216
1217/**
1218 * gst_caps_do_simplify:
1219 * @caps: a #GstCaps to simplify
1220 *
1221 * Modifies the given @caps inplace into a representation that represents the
1222 * same set of formats, but in a simpler form.  Component structures that are
1223 * identical are merged.  Component structures that have values that can be
1224 * merged are also merged.
1225 *
1226 * Returns: TRUE, if the caps could be simplified
1227 */
1228gboolean
1229gst_caps_do_simplify (GstCaps * caps)
1230{
1231  GstStructure *simplify, *compare, *result;
1232  gint i, j, start;
1233  gboolean changed = FALSE;
1234
1235  g_return_val_if_fail (caps != NULL, FALSE);
1236
1237  if (gst_caps_get_size (caps) < 2)
1238    return FALSE;
1239
1240  g_ptr_array_sort (caps->structs, gst_caps_compare_structures);
1241
1242  start = caps->structs->len - 1;
1243  for (i = caps->structs->len - 1; i >= 0; i--) {
1244    simplify = gst_caps_get_structure (caps, i);
1245    if (gst_structure_get_name_id (simplify) !=
1246        gst_structure_get_name_id (gst_caps_get_structure (caps, start)))
1247      start = i;
1248    for (j = start; j >= 0; j--) {
1249      if (j == i)
1250        continue;
1251      compare = gst_caps_get_structure (caps, j);
1252      if (gst_structure_get_name_id (simplify) !=
1253          gst_structure_get_name_id (compare)) {
1254        break;
1255      }
1256      if (gst_caps_structure_simplify (&result, simplify, compare)) {
1257#if 0
1258        g_print ("%s  -  %s  =  %s\n",
1259            gst_structure_to_string (simplify),
1260            gst_structure_to_string (compare),
1261            result ? gst_structure_to_string (result) : "---");
1262#endif
1263        if (result) {
1264          gst_structure_free (simplify);
1265          g_ptr_array_index (caps->structs, i) = result;
1266          simplify = result;
1267        } else {
1268          gst_caps_remove_structure (caps, i);
1269          start--;
1270          break;
1271        }
1272        changed = TRUE;
1273      }
1274    }
1275  }
1276
1277  if (!changed)
1278    return FALSE;
1279
1280  /* gst_caps_do_simplify (caps); */
1281  return TRUE;
1282}
1283
1284#ifndef GST_DISABLE_LOADSAVE
1285/**
1286 * gst_caps_save_thyself:
1287 * @caps: a #GstCaps structure
1288 * @parent: a XML parent node
1289 *
1290 * Serializes a #GstCaps to XML and adds it as a child node of @parent.
1291 *
1292 * Returns: a XML node pointer
1293 */
1294xmlNodePtr
1295gst_caps_save_thyself (const GstCaps * caps, xmlNodePtr parent)
1296{
1297  char *s = gst_caps_to_string (caps);
1298
1299  xmlNewChild (parent, NULL, "caps", s);
1300  g_free (s);
1301  return parent;
1302}
1303
1304/**
1305 * gst_caps_load_thyself:
1306 * @parent: a XML node
1307 *
1308 * Creates a #GstCaps from its XML serialization.
1309 *
1310 * Returns: a new #GstCaps structure
1311 */
1312GstCaps *
1313gst_caps_load_thyself (xmlNodePtr parent)
1314{
1315  if (strcmp ("caps", parent->name) == 0) {
1316    return gst_caps_from_string (xmlNodeGetContent (parent));
1317  }
1318
1319  return NULL;
1320}
1321#endif
1322
1323/* utility */
1324
1325/**
1326 * gst_caps_replace:
1327 * @caps: a pointer to #GstCaps
1328 * @newcaps: a #GstCaps to replace *caps
1329 *
1330 * Replaces *caps with @newcaps.  Frees the #GstCaps in the location
1331 * pointed to by @caps, if applicable, then modifies @caps to point to
1332 * @newcaps.
1333 */
1334void
1335gst_caps_replace (GstCaps ** caps, GstCaps * newcaps)
1336{
1337#if 0                           /* disable this, since too many plugins rely on undefined behavior */
1338#ifdef USE_POISONING
1339  //if (newcaps) CAPS_POISON (newcaps);
1340#endif
1341#endif
1342  if (*caps)
1343    gst_caps_free (*caps);
1344  *caps = newcaps;
1345}
1346
1347/**
1348 * gst_caps_to_string:
1349 * @caps: a #GstCaps
1350 *
1351 * Converts @caps to a string representation.  This string representation
1352 * can be converted back to a #GstCaps by #gst_caps_from_string.
1353 *
1354 * Returns: a newly allocated string representing @caps.
1355 */
1356gchar *
1357gst_caps_to_string (const GstCaps * caps)
1358{
1359  int i;
1360  GstStructure *structure;
1361  GString *s;
1362  char *sstr;
1363
1364  /* NOTE:  This function is potentially called by the debug system,
1365   * so any calls to gst_log() (and GST_DEBUG(), GST_LOG(), etc.)
1366   * should be careful to avoid recursion.  This includes any functions
1367   * called by gst_caps_to_string.  In particular, calls should
1368   * not use the GST_PTR_FORMAT extension.  */
1369
1370  /* FIXME does this leak? */
1371
1372  if (caps == NULL) {
1373    return g_strdup ("NULL");
1374  }
1375  if (gst_caps_is_any (caps)) {
1376    return g_strdup ("ANY");
1377  }
1378  if (gst_caps_is_empty (caps)) {
1379    return g_strdup ("EMPTY");
1380  }
1381  s = g_string_new ("");
1382  structure = gst_caps_get_structure (caps, 0);
1383  sstr = gst_structure_to_string (structure);
1384  g_string_append (s, sstr);
1385  g_free (sstr);
1386
1387  for (i = 1; i < caps->structs->len; i++) {
1388    structure = gst_caps_get_structure (caps, i);
1389
1390    g_string_append (s, "; ");
1391    sstr = gst_structure_to_string (structure);
1392    g_string_append (s, sstr);
1393    g_free (sstr);
1394  }
1395
1396  return g_string_free (s, FALSE);
1397}
1398
1399static gboolean
1400gst_caps_from_string_inplace (GstCaps * caps, const gchar * string)
1401{
1402  GstStructure *structure;
1403  gchar *s;
1404
1405  g_return_val_if_fail (string, FALSE);
1406  if (strcmp ("ANY", string) == 0) {
1407    caps->flags = GST_CAPS_FLAGS_ANY;
1408    return TRUE;
1409  }
1410  if (strcmp ("EMPTY", string) == 0) {
1411    return TRUE;
1412  }
1413
1414  structure = gst_structure_from_string (string, &s);
1415  if (structure == NULL) {
1416    return FALSE;
1417  }
1418  gst_caps_append_structure (caps, structure);
1419
1420  while (*s == ';') {
1421    s++;
1422    while (g_ascii_isspace (*s))
1423      s++;
1424    structure = gst_structure_from_string (s, &s);
1425    if (structure == NULL) {
1426      return FALSE;
1427    }
1428    gst_caps_append_structure (caps, structure);
1429    while (g_ascii_isspace (*s))
1430      s++;
1431  }
1432
1433  if (*s != 0) {
1434    return FALSE;
1435  }
1436
1437  return TRUE;
1438}
1439
1440/**
1441 * gst_caps_from_string:
1442 * @string: a string to convert to #GstCaps
1443 *
1444 * Converts @caps from a string representation.
1445 *
1446 * Returns: a newly allocated #GstCaps
1447 */
1448GstCaps *
1449gst_caps_from_string (const gchar * string)
1450{
1451  GstCaps *caps;
1452
1453  caps = gst_caps_new_empty ();
1454  if (gst_caps_from_string_inplace (caps, string)) {
1455    return caps;
1456  } else {
1457    gst_caps_free (caps);
1458    return NULL;
1459  }
1460}
1461
1462static void
1463gst_caps_transform_to_string (const GValue * src_value, GValue * dest_value)
1464{
1465  g_return_if_fail (G_IS_VALUE (src_value));
1466  g_return_if_fail (G_IS_VALUE (dest_value));
1467  g_return_if_fail (G_VALUE_HOLDS (src_value, GST_TYPE_CAPS));
1468  g_return_if_fail (G_VALUE_HOLDS (dest_value, G_TYPE_STRING)
1469      || G_VALUE_HOLDS (dest_value, G_TYPE_POINTER));
1470
1471  dest_value->data[0].v_pointer =
1472      gst_caps_to_string (src_value->data[0].v_pointer);
1473}
1474
1475static GstCaps *
1476gst_caps_copy_conditional (const GstCaps * src)
1477{
1478  if (src) {
1479    return gst_caps_copy (src);
1480  } else {
1481    return NULL;
1482  }
1483}
1484
1485/* fixate utility functions */
1486
1487/**
1488 * gst_caps_structure_fixate_field_nearest_int:
1489 * @structure: a #GstStructure
1490 * @field_name: a field in @structure
1491 * @target: the target value of the fixation
1492 *
1493 * Fixates a #GstStructure by changing the given field to the nearest
1494 * integer to @target that is a subset of the existing field.
1495 *
1496 * Returns: TRUE if the structure could be fixated
1497 */
1498gboolean
1499gst_caps_structure_fixate_field_nearest_int (GstStructure * structure,
1500    const char *field_name, int target)
1501{
1502  const GValue *value;
1503
1504  g_return_val_if_fail (gst_structure_has_field (structure, field_name), FALSE);
1505
1506  value = gst_structure_get_value (structure, field_name);
1507
1508  if (G_VALUE_TYPE (value) == G_TYPE_INT) {
1509    /* already fixed */
1510    return FALSE;
1511  } else if (G_VALUE_TYPE (value) == GST_TYPE_INT_RANGE) {
1512    int x;
1513
1514    x = gst_value_get_int_range_min (value);
1515    if (target < x)
1516      target = x;
1517    x = gst_value_get_int_range_max (value);
1518    if (target > x)
1519      target = x;
1520    gst_structure_set (structure, field_name, G_TYPE_INT, target, NULL);
1521    return TRUE;
1522  } else if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
1523    const GValue *list_value;
1524    int i, n;
1525    int best = 0;
1526    int best_index = -1;
1527
1528    n = gst_value_list_get_size (value);
1529    for (i = 0; i < n; i++) {
1530      list_value = gst_value_list_get_value (value, i);
1531      if (G_VALUE_TYPE (list_value) == G_TYPE_INT) {
1532        int x = g_value_get_int (list_value);
1533
1534        if (best_index == -1 || (ABS (target - x) < ABS (target - best))) {
1535          best_index = i;
1536          best = x;
1537        }
1538      }
1539    }
1540    if (best_index != -1) {
1541      gst_structure_set (structure, field_name, G_TYPE_INT, best, NULL);
1542      return TRUE;
1543    }
1544    return FALSE;
1545  }
1546
1547  return FALSE;
1548}
1549
1550/**
1551 * gst_caps_structure_fixate_field_nearest_double:
1552 * @structure: a #GstStructure
1553 * @field_name: a field in @structure
1554 * @target: the target value of the fixation
1555 *
1556 * Fixates a #GstStructure by changing the given field to the nearest
1557 * double to @target that is a subset of the existing field.
1558 *
1559 * Returns: TRUE if the structure could be fixated
1560 */
1561gboolean
1562gst_caps_structure_fixate_field_nearest_double (GstStructure * structure,
1563    const char *field_name, double target)
1564{
1565  const GValue *value;
1566
1567  g_return_val_if_fail (gst_structure_has_field (structure, field_name), FALSE);
1568
1569  value = gst_structure_get_value (structure, field_name);
1570
1571  if (G_VALUE_TYPE (value) == G_TYPE_DOUBLE) {
1572    /* already fixed */
1573    return FALSE;
1574  } else if (G_VALUE_TYPE (value) == GST_TYPE_DOUBLE_RANGE) {
1575    double x;
1576
1577    x = gst_value_get_double_range_min (value);
1578    if (target < x)
1579      target = x;
1580    x = gst_value_get_double_range_max (value);
1581    if (target > x)
1582      target = x;
1583    gst_structure_set (structure, field_name, G_TYPE_DOUBLE, target, NULL);
1584    return TRUE;
1585  } else if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
1586    const GValue *list_value;
1587    int i, n;
1588    double best = 0;
1589    int best_index = -1;
1590
1591    n = gst_value_list_get_size (value);
1592    for (i = 0; i < n; i++) {
1593      list_value = gst_value_list_get_value (value, i);
1594      if (G_VALUE_TYPE (list_value) == G_TYPE_DOUBLE) {
1595        double x = g_value_get_double (list_value);
1596
1597        if (best_index == -1 || (ABS (target - x) < ABS (target - best))) {
1598          best_index = i;
1599          best = x;
1600        }
1601      }
1602    }
1603    if (best_index != -1) {
1604      gst_structure_set (structure, field_name, G_TYPE_DOUBLE, best, NULL);
1605      return TRUE;
1606    }
1607    return FALSE;
1608  }
1609
1610  return FALSE;
1611
1612}
Note: See TracBrowser for help on using the repository browser.