gstcaps.c 29.3 KB
Newer Older
David Schleef's avatar
David Schleef committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* GStreamer
 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>

#include <gst/gst.h>

27
28
29
30
31
32
33
34
35
36
37
38
#define CAPS_POISON(caps) do{ \
  GstCaps *_newcaps = gst_caps_copy (caps); \
  gst_caps_free(caps); \
  caps = _newcaps; \
} while (0)
#define STRUCTURE_POISON(structure) do{ \
  GstStructure *_newstruct = gst_structure_copy (structure); \
  gst_structure_free(structure); \
  structure = _newstruct; \
} while (0)


David Schleef's avatar
David Schleef committed
39
static void _gst_caps_transform_to_string (const GValue *src_value,
David Schleef's avatar
David Schleef committed
40
    GValue *dest_value);
David Schleef's avatar
David Schleef committed
41
42
43
44
45
static void _gst_caps_value_init (GValue *value);
static void _gst_caps_value_free (GValue *value);
static void _gst_caps_value_copy (const GValue *src, GValue *dest);
static gpointer _gst_caps_value_peek_pointer (const GValue *value);
static gboolean _gst_caps_from_string_inplace (GstCaps *caps,
David Schleef's avatar
David Schleef committed
46
47
48
    const gchar *string);


David Schleef's avatar
David Schleef committed
49
GType _gst_caps_type;
David Schleef's avatar
David Schleef committed
50

David Schleef's avatar
David Schleef committed
51
void _gst_caps_initialize (void)
David Schleef's avatar
David Schleef committed
52
53
{
  static const GTypeValueTable type_value_table = {
David Schleef's avatar
David Schleef committed
54
55
56
57
    _gst_caps_value_init,
    _gst_caps_value_free,
    _gst_caps_value_copy,
    _gst_caps_value_peek_pointer,
David Schleef's avatar
David Schleef committed
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
    NULL,
    NULL,
    NULL,
    NULL,
  };
  static const GTypeInfo caps2_info = {
    0,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    0,
    0,
    NULL,
    &type_value_table,
  };

David Schleef's avatar
David Schleef committed
76
  _gst_caps_type = g_type_register_static (G_TYPE_BOXED, "GstCaps",
David Schleef's avatar
David Schleef committed
77
78
      &caps2_info, 0);

David Schleef's avatar
David Schleef committed
79
80
  g_value_register_transform_func (_gst_caps_type, G_TYPE_STRING,
      _gst_caps_transform_to_string);
David Schleef's avatar
David Schleef committed
81
82
}

David Schleef's avatar
David Schleef committed
83
GType gst_caps_get_type (void)
David Schleef's avatar
David Schleef committed
84
{
David Schleef's avatar
David Schleef committed
85
  return _gst_caps_type;
David Schleef's avatar
David Schleef committed
86
87
88
}

/* creation/deletion */
89
90
91
92
93
94
95
96
97

/**
 * gst_caps_new_empty:
 *
 * Creates a new #GstCaps that is empty.  That is, the returned
 * #GstCaps contains no media formats.
 *
 * Returns: the new #GstCaps
 */
David Schleef's avatar
David Schleef committed
98
GstCaps *gst_caps_new_empty (void)
David Schleef's avatar
David Schleef committed
99
{
David Schleef's avatar
David Schleef committed
100
  GstCaps *caps = g_new0(GstCaps, 1);
David Schleef's avatar
David Schleef committed
101

David Schleef's avatar
David Schleef committed
102
  caps->type = _gst_caps_type;
David Schleef's avatar
David Schleef committed
103
104
105
106
107
  caps->structs = g_ptr_array_new();

  return caps;
}

108
109
110
111
112
113
114
115
/**
 * gst_caps_new_empty:
 *
 * Creates a new #GstCaps that indicates that it is compatible with
 * any media format.
 *
 * Returns: the new #GstCaps
 */
David Schleef's avatar
David Schleef committed
116
GstCaps *gst_caps_new_any (void)
David Schleef's avatar
David Schleef committed
117
{
David Schleef's avatar
David Schleef committed
118
  GstCaps *caps = g_new0(GstCaps, 1);
David Schleef's avatar
David Schleef committed
119

David Schleef's avatar
David Schleef committed
120
  caps->type = _gst_caps_type;
David Schleef's avatar
David Schleef committed
121
  caps->structs = g_ptr_array_new();
David Schleef's avatar
David Schleef committed
122
  caps->flags = GST_CAPS_FLAGS_ANY;
David Schleef's avatar
David Schleef committed
123
124
125
126

  return caps;
}

127
128
129
130
131
132
133
134
135
136
137
/**
 * gst_caps_new_simple:
 * @media_type: the media type of the structure
 * @...: additional arguments
 *
 * Creates a new #GstCaps that contains one #GstStructure.  The
 * structure is defined by the arguments, which have the same format
 * as @gst_structure_new().
 *
 * Returns: the new #GstCaps
 */
David Schleef's avatar
David Schleef committed
138
GstCaps *gst_caps_new_simple (const char *media_type, const char *fieldname,
David Schleef's avatar
David Schleef committed
139
140
    ...)
{
David Schleef's avatar
David Schleef committed
141
  GstCaps *caps;
David Schleef's avatar
David Schleef committed
142
143
144
  GstStructure *structure;
  va_list var_args;

David Schleef's avatar
David Schleef committed
145
146
  caps = g_new0(GstCaps, 1);
  caps->type = _gst_caps_type;
David Schleef's avatar
David Schleef committed
147
148
149
150
151
152
  caps->structs = g_ptr_array_new();

  va_start (var_args, fieldname);
  structure = gst_structure_new_valist (media_type, fieldname, var_args);
  va_end (var_args);

David Schleef's avatar
David Schleef committed
153
  gst_caps_append_structure (caps, structure);
David Schleef's avatar
David Schleef committed
154
155
156
157
  
  return caps;
}

158
159
160
161
162
163
164
165
166
167
168
/**
 * gst_caps_new_full:
 * @struct1: the first structure to add
 * @...: additional structures to add
 *
 * Creates a new #GstCaps and adds all the structures listed as
 * arguments.  The list must be NULL-terminated.  The structures
 * are not copied; the returned #GstCaps owns the structures.
 *
 * Returns: the new #GstCaps
 */
David Schleef's avatar
David Schleef committed
169
GstCaps *gst_caps_new_full (GstStructure *struct1, ...)
David Schleef's avatar
David Schleef committed
170
{
David Schleef's avatar
David Schleef committed
171
  GstCaps *caps;
David Schleef's avatar
David Schleef committed
172
173
174
  va_list var_args;

  va_start (var_args, struct1);
David Schleef's avatar
David Schleef committed
175
  caps = gst_caps_new_full_valist (struct1, var_args);
David Schleef's avatar
David Schleef committed
176
177
178
179
180
  va_end (var_args);

  return caps;
}

181
182
183
184
185
186
187
188
189
190
191
/**
 * gst_caps_new_full_valist:
 * @struct1: the first structure to add
 * @var_args: additional structures to add
 *
 * Creates a new #GstCaps and adds all the structures listed as
 * arguments.  The list must be NULL-terminated.  The structures
 * are not copied; the returned #GstCaps owns the structures.
 *
 * Returns: the new #GstCaps
 */
David Schleef's avatar
David Schleef committed
192
GstCaps *gst_caps_new_full_valist (GstStructure *structure,
David Schleef's avatar
David Schleef committed
193
194
    va_list var_args)
{
David Schleef's avatar
David Schleef committed
195
  GstCaps *caps;
David Schleef's avatar
David Schleef committed
196

David Schleef's avatar
David Schleef committed
197
198
  caps = g_new0(GstCaps, 1);
  caps->type = _gst_caps_type;
David Schleef's avatar
David Schleef committed
199
200
201
  caps->structs = g_ptr_array_new();

  while(structure){
David Schleef's avatar
David Schleef committed
202
203
    gst_caps_append_structure (caps, structure);
    structure = va_arg (var_args, GstStructure *);
David Schleef's avatar
David Schleef committed
204
205
206
207
208
  }

  return caps;
}

209
210
211
212
213
214
215
216
217
/**
 * gst_caps_copy:
 * @caps: the #GstCaps to copy
 *
 * Deeply copies a #GstCaps, including all structures and all the
 * structures' values.
 *
 * Returns: the new #GstCaps
 */
David Schleef's avatar
David Schleef committed
218
GstCaps *gst_caps_copy (const GstCaps *caps)
David Schleef's avatar
David Schleef committed
219
{
David Schleef's avatar
David Schleef committed
220
  GstCaps *newcaps;
David Schleef's avatar
David Schleef committed
221
222
223
  GstStructure *structure;
  int i;

David Schleef's avatar
David Schleef committed
224
225
226
227
  g_return_val_if_fail(caps != NULL, NULL);

  newcaps = g_new0(GstCaps, 1);
  newcaps->type = _gst_caps_type;
David Schleef's avatar
David Schleef committed
228
229
230
231
  newcaps->flags = caps->flags;
  newcaps->structs = g_ptr_array_new();

  for(i=0;i<caps->structs->len;i++){
David Schleef's avatar
David Schleef committed
232
233
    structure = gst_caps_get_structure (caps, i);
    gst_caps_append_structure (newcaps, gst_structure_copy(structure));
David Schleef's avatar
David Schleef committed
234
235
236
237
238
  }

  return newcaps;
}

239
240
241
242
243
244
245
/**
 * gst_caps_free:
 * @caps: the #GstCaps to free
 *
 * Frees a #GstCaps and all its structures and the structures'
 * values.
 */
David Schleef's avatar
David Schleef committed
246
void gst_caps_free (GstCaps *caps)
David Schleef's avatar
David Schleef committed
247
248
249
250
{
  GstStructure *structure;
  int i;
  
David Schleef's avatar
David Schleef committed
251
252
  g_return_if_fail(caps != NULL);

David Schleef's avatar
David Schleef committed
253
  for(i=0;i<caps->structs->len;i++){
David Schleef's avatar
David Schleef committed
254
    structure = gst_caps_get_structure (caps, i);
David Schleef's avatar
David Schleef committed
255
256
257
    gst_structure_free (structure);
  }
  g_ptr_array_free(caps->structs, TRUE);
David Schleef's avatar
David Schleef committed
258
259
260
#ifdef USE_POISONING
  memset (caps, 0xff, sizeof(GstCaps));
#endif
David Schleef's avatar
David Schleef committed
261
262
263
  g_free(caps);
}

264
265
266
267
268
269
270
271
/**
 * gst_static_caps_get:
 * @static_caps: the #GstStaticCaps to convert
 *
 * Converts a #GstStaticCaps to a #GstCaps.
 *
 * Returns: the new #GstCaps
 */
David Schleef's avatar
David Schleef committed
272
const GstCaps *gst_static_caps_get (GstStaticCaps *static_caps)
David Schleef's avatar
David Schleef committed
273
{
David Schleef's avatar
David Schleef committed
274
275
  GstCaps *caps = (GstCaps *)static_caps;
  gboolean ret;
David Schleef's avatar
David Schleef committed
276
277

  if (caps->type == 0) {
David Schleef's avatar
David Schleef committed
278
279
280
281
282
283
284
    caps->type = _gst_caps_type;
    caps->structs = g_ptr_array_new();
    ret = _gst_caps_from_string_inplace (caps, static_caps->string);

    if (!ret) {
      g_critical ("Could not convert static caps \"%s\"", static_caps->string);
    }
David Schleef's avatar
David Schleef committed
285
286
287
288
289
290
  }

  return caps;
}

/* manipulation */
291
292
293
294
295
296
297
298
299
300

/**
 * gst_caps_append:
 * @caps1: the #GstCaps that will be appended to
 * @caps2: the #GstCaps to append
 *
 * Appends the structures contained in @caps2 to @caps1.  The structures
 * in @caps2 are not copied -- they are transferred to @caps1, and then
 * @caps2 is freed.
 */
David Schleef's avatar
David Schleef committed
301
void gst_caps_append (GstCaps *caps1, GstCaps *caps2)
David Schleef's avatar
David Schleef committed
302
303
304
{
  GstStructure *structure;
  int i;
305
306
307
308

  g_return_if_fail (caps1 != NULL);
  g_return_if_fail (caps2 != NULL);

309
310
311
#ifdef USE_POISONING
  CAPS_POISON (caps2);
#endif
David Schleef's avatar
David Schleef committed
312
  for(i=0;i<caps2->structs->len;i++){
David Schleef's avatar
David Schleef committed
313
314
    structure = gst_caps_get_structure (caps2, i);
    gst_caps_append_structure (caps1, structure);
David Schleef's avatar
David Schleef committed
315
316
  }
  g_ptr_array_free(caps2->structs, TRUE);
David Schleef's avatar
David Schleef committed
317
318
319
#ifdef USE_POISONING
  memset (caps2, 0xff, sizeof(GstCaps));
#endif
David Schleef's avatar
David Schleef committed
320
321
322
  g_free(caps2);
}

323
324
325
326
327
328
329
330
/**
 * gst_caps_append_structure:
 * @caps: the #GstCaps that will be appended to
 * @structure: the #GstStructure to append
 *
 * Appends @structure to @caps1.  The structure is not copied; @caps1
 * becomes the owner of @structure.
 */
David Schleef's avatar
David Schleef committed
331
void gst_caps_append_structure (GstCaps *caps, GstStructure *structure)
David Schleef's avatar
David Schleef committed
332
{
David Schleef's avatar
David Schleef committed
333
334
  g_return_if_fail(caps != NULL);

335
  if (structure){
336
#if 0
337
#ifdef USE_POISONING
338
    STRUCTURE_POISON (structure);
339
#endif
340
#endif
David Schleef's avatar
David Schleef committed
341
    g_ptr_array_add (caps->structs, structure);
David Schleef's avatar
David Schleef committed
342
343
344
  }
}

345
346
347
348
349
350
/**
 * gst_caps_split_one:
 * @caps: 
 *
 * Returns:
 */
David Schleef's avatar
David Schleef committed
351
GstCaps *gst_caps_split_one (GstCaps *caps)
David Schleef's avatar
David Schleef committed
352
353
{
  /* FIXME */
354
  g_critical ("unimplemented");
David Schleef's avatar
David Schleef committed
355
356
357
358

  return NULL;
}

359
360
361
362
363
364
/**
 * gst_caps_split_one:
 * @caps: a #GstCaps
 *
 * Returns: the number of structures that @caps contains
 */
David Schleef's avatar
David Schleef committed
365
int gst_caps_get_size (const GstCaps *caps)
David Schleef's avatar
David Schleef committed
366
{
David Schleef's avatar
David Schleef committed
367
368
369
370
371
  g_return_val_if_fail (caps != NULL, 0);

  return caps->structs->len;
}

372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
/**
 * gst_caps_get_structure:
 * @caps: a #GstCaps
 * @index: the index of the structure
 *
 * Finds the structure in @caps that has the index @index, and 
 * returns it.
 *
 * WARNING: This function takes a const GstCaps *, but returns a
 * non-const GstStructure *.  This is for programming convenience --
 * the caller should be aware that structures inside a constant
 * @GstCaps should not be modified.
 *
 * Returns: a pointer to the #GstStructure corresponding to @index
 */
David Schleef's avatar
David Schleef committed
387
388
389
390
391
392
GstStructure *gst_caps_get_structure (const GstCaps *caps, int index)
{
  g_return_val_if_fail (caps != NULL, NULL);
  g_return_val_if_fail (index >= 0, NULL);
  g_return_val_if_fail (index < caps->structs->len, NULL);

David Schleef's avatar
David Schleef committed
393
394
395
  return g_ptr_array_index(caps->structs, index);
}

396
397
398
399
400
401
402
403
404
/**
 * gst_caps_copy_1:
 * @caps: the @GstCaps to copy
 *
 * Creates a new @GstCaps and appends a copy of the first structure
 * contained in @caps.
 *
 * Returns: the new @GstCaps
 */
David Schleef's avatar
David Schleef committed
405
GstCaps *gst_caps_copy_1 (const GstCaps *caps)
David Schleef's avatar
David Schleef committed
406
{
David Schleef's avatar
David Schleef committed
407
  GstCaps *newcaps;
David Schleef's avatar
David Schleef committed
408
409
  GstStructure *structure;

David Schleef's avatar
David Schleef committed
410
411
412
413
  g_return_val_if_fail(caps != NULL, NULL);

  newcaps = g_new0(GstCaps, 1);
  newcaps->type = _gst_caps_type;
David Schleef's avatar
David Schleef committed
414
415
416
417
  newcaps->flags = caps->flags;
  newcaps->structs = g_ptr_array_new();

  if (caps->structs->len > 0){
David Schleef's avatar
David Schleef committed
418
419
    structure = gst_caps_get_structure (caps, 0);
    gst_caps_append_structure (newcaps, gst_structure_copy(structure));
David Schleef's avatar
David Schleef committed
420
421
422
423
424
  }

  return newcaps;
}

425
426
427
428
429
430
431
432
433
434
/**
 * gst_caps_set_simple:
 * @caps: the @GstCaps to set
 * @field: first field to set
 * @...: additional parameters
 *
 * Sets fields in a simple #GstCaps.  A simple #GstCaps is one that
 * only has one structure.  The arguments must be passed in the same
 * manner as @gst_structure_set(), and be NULL-terminated.
 */
David Schleef's avatar
David Schleef committed
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
void gst_caps_set_simple (GstCaps *caps, char *field, ...)
{
  GstStructure *structure;
  va_list var_args;

  g_return_if_fail (caps != NULL);
  g_return_if_fail (caps->structs->len == 1);

  structure = gst_caps_get_structure (caps, 0);

  va_start (var_args, field);
  gst_structure_set_valist (structure, field, var_args);
  va_end(var_args);
}

450
451
452
453
454
455
456
457
458
459
/**
 * gst_caps_set_simple_valist:
 * @caps: the @GstCaps to copy
 * @field: first field to set
 * @varargs: additional parameters
 *
 * Sets fields in a simple #GstCaps.  A simple #GstCaps is one that
 * only has one structure.  The arguments must be passed in the same
 * manner as @gst_structure_set(), and be NULL-terminated.
 */
David Schleef's avatar
David Schleef committed
460
461
462
463
464
465
466
467
468
469
470
471
void gst_caps_set_simple_valist (GstCaps *caps, char *field, va_list varargs)
{
  GstStructure *structure;

  g_return_if_fail (caps != NULL);
  g_return_if_fail (caps->structs->len != 1);

  structure = gst_caps_get_structure (caps, 0);

  gst_structure_set_valist (structure, field, varargs);
}

David Schleef's avatar
David Schleef committed
472
/* tests */
473
474
475
476
477
478
479

/**
 * gst_caps_is_any:
 * @caps: the @GstCaps to test
 *
 * Returns: TRUE if @caps represents any format.
 */
David Schleef's avatar
David Schleef committed
480
gboolean gst_caps_is_any (const GstCaps *caps)
David Schleef's avatar
David Schleef committed
481
{
David Schleef's avatar
David Schleef committed
482
483
484
  g_return_val_if_fail(caps != NULL, FALSE);

  return (caps->flags & GST_CAPS_FLAGS_ANY);
David Schleef's avatar
David Schleef committed
485
486
}

487
488
489
490
491
492
/**
 * gst_caps_is_empty:
 * @caps: the @GstCaps to test
 *
 * Returns: TRUE if @caps represents no formats.
 */
David Schleef's avatar
David Schleef committed
493
gboolean gst_caps_is_empty (const GstCaps *caps)
David Schleef's avatar
David Schleef committed
494
{
David Schleef's avatar
David Schleef committed
495
496
497
  g_return_val_if_fail(caps != NULL, FALSE);

  if (caps->flags & GST_CAPS_FLAGS_ANY) return FALSE;
David Schleef's avatar
David Schleef committed
498
499
500
501

  return (caps->structs == NULL) || (caps->structs->len == 0);
}

502
503
504
505
506
507
/**
 * gst_caps_is_chained:
 * @caps: the @GstCaps to test
 *
 * Returns: TRUE if @caps contains more than one structure
 */
David Schleef's avatar
David Schleef committed
508
gboolean gst_caps_is_chained (const GstCaps *caps)
David Schleef's avatar
David Schleef committed
509
{
David Schleef's avatar
David Schleef committed
510
511
  g_return_val_if_fail(caps != NULL, FALSE);

David Schleef's avatar
David Schleef committed
512
513
514
  return (caps->structs->len > 1);
}

David Schleef's avatar
David Schleef committed
515
516
static gboolean
_gst_caps_is_fixed_foreach (GQuark field_id, GValue *value, gpointer unused)
David Schleef's avatar
David Schleef committed
517
{
David Schleef's avatar
David Schleef committed
518
519
520
521
522
  GType type = G_VALUE_TYPE (value);
  if (G_TYPE_IS_FUNDAMENTAL (type)) return TRUE;
  if (type == GST_TYPE_FOURCC) return TRUE;
  return FALSE;
}
David Schleef's avatar
David Schleef committed
523

524
525
526
527
528
529
530
531
532
533
/**
 * gst_caps_is_fixed:
 * @caps: the @GstCaps to test
 *
 * Fixed @GstCaps describe exactly one format, that is, they have exactly
 * one structure, and each field in the structure describes a fixed type.
 * Examples of non-fixed types are GST_TYPE_INT_RANGE and GST_TYPE_LIST.
 *
 * Returns: TRUE if @caps is fixed
 */
David Schleef's avatar
David Schleef committed
534
535
536
gboolean gst_caps_is_fixed (const GstCaps *caps)
{
  GstStructure *structure;
David Schleef's avatar
David Schleef committed
537

David Schleef's avatar
David Schleef committed
538
  g_return_val_if_fail(caps != NULL, FALSE);
David Schleef's avatar
David Schleef committed
539

David Schleef's avatar
David Schleef committed
540
  if (caps->structs->len != 1) return FALSE;
David Schleef's avatar
David Schleef committed
541

David Schleef's avatar
David Schleef committed
542
  structure = gst_caps_get_structure (caps, 0);
David Schleef's avatar
David Schleef committed
543

David Schleef's avatar
David Schleef committed
544
  return gst_structure_foreach (structure, _gst_caps_is_fixed_foreach, NULL);
David Schleef's avatar
David Schleef committed
545
546
}

547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
static gboolean
_gst_structure_is_equal_foreach (GQuark field_id, 
    GValue *val2, gpointer data)
{
  GstStructure *struct1 = (GstStructure *) data;
  const GValue *val1 = gst_structure_id_get_value (struct1, field_id);

  if (val1 == NULL) return FALSE;
  if (gst_value_compare (val1, val2) == GST_VALUE_EQUAL) {
    return TRUE;
  }

  return FALSE;
}

562
563
564
565
566
567
568
569
570
571
/**
 * gst_caps_is_equal_fixed:
 * @caps1: the #GstCaps to test
 * @caps2: the #GstCaps to test
 *
 * Tests if two #GstCaps are equal.  This function only works on fixed
 * #GstCaps.
 *
 * Returns: TRUE if the arguments represent the same format
 */
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
gboolean gst_caps_is_equal_fixed (const GstCaps *caps1, const GstCaps *caps2)
{
  GstStructure *struct1, *struct2;

  g_return_val_if_fail (gst_caps_is_fixed(caps1), FALSE);
  g_return_val_if_fail (gst_caps_is_fixed(caps2), FALSE);

  struct1 = gst_caps_get_structure (caps1, 0);
  struct2 = gst_caps_get_structure (caps2, 0);

  if (struct1->name != struct2->name) {
    return FALSE;
  }
  if (struct1->fields->len != struct2->fields->len) {
    return FALSE;
  }

  return gst_structure_foreach (struct1, _gst_structure_is_equal_foreach,
      struct2);
}

David Schleef's avatar
David Schleef committed
593
594
595
static gboolean
_gst_structure_field_has_compatible (GQuark field_id, 
    GValue *val2, gpointer data)
David Schleef's avatar
David Schleef committed
596
{
David Schleef's avatar
David Schleef committed
597
598
599
  GValue dest = { 0 };
  GstStructure *struct1 = (GstStructure *) data;
  const GValue *val1 = gst_structure_id_get_value (struct1, field_id);
David Schleef's avatar
David Schleef committed
600

David Schleef's avatar
David Schleef committed
601
602
603
604
  if (val1 == NULL) return FALSE;
  if (gst_value_intersect (&dest, val1, val2)) {
    g_value_unset (&dest);
    return TRUE;
David Schleef's avatar
David Schleef committed
605
606
  }

David Schleef's avatar
David Schleef committed
607
608
  return FALSE;
}
David Schleef's avatar
David Schleef committed
609

David Schleef's avatar
David Schleef committed
610
611
612
613
614
static gboolean
_gst_cap_is_always_compatible (const GstStructure *struct1,
    const GstStructure *struct2)
{
  if(struct1->name != struct2->name){
David Schleef's avatar
David Schleef committed
615
616
617
    return FALSE;
  }

David Schleef's avatar
David Schleef committed
618
619
620
  /* the reversed order is important */
  return gst_structure_foreach ((GstStructure *) struct2, 
      _gst_structure_field_has_compatible, (gpointer) struct1);
David Schleef's avatar
David Schleef committed
621
622
}

David Schleef's avatar
David Schleef committed
623
624
625
static gboolean
_gst_caps_cap_is_always_compatible (const GstStructure *struct1,
    const GstCaps *caps2)
David Schleef's avatar
David Schleef committed
626
627
628
629
{
  int i;

  for(i=0;i<caps2->structs->len;i++){
David Schleef's avatar
David Schleef committed
630
    GstStructure *struct2 = gst_caps_get_structure (caps2, i);
David Schleef's avatar
David Schleef committed
631
632
633
634
635
636
637
638
639

    if (_gst_cap_is_always_compatible (struct1, struct2)) {
      return TRUE;
    }
  }

  return FALSE;
}

640
641
642
643
644
645
646
/**
 * gst_caps_is_always_compatible
 * @caps1: the #GstCaps to test
 * @caps2: the #GstCaps to test
 *
 * Returns: TRUE if @caps1 is a subset of @caps2.
 */
David Schleef's avatar
David Schleef committed
647
648
gboolean
gst_caps_is_always_compatible (const GstCaps *caps1, const GstCaps *caps2)
David Schleef's avatar
David Schleef committed
649
650
651
{
  int i;

David Schleef's avatar
David Schleef committed
652
653
654
655
656
657
658
659
660
661
662
  g_return_val_if_fail (caps1 != NULL, FALSE);
  g_return_val_if_fail (caps2 != NULL, FALSE);
  /* FIXME: is this right ? */
  g_return_val_if_fail (!gst_caps_is_empty (caps1), FALSE);
  g_return_val_if_fail (!gst_caps_is_empty (caps2), FALSE);
  
  if (gst_caps_is_any (caps2))
    return TRUE;
  if (gst_caps_is_any (caps1))
    return FALSE;
  
David Schleef's avatar
David Schleef committed
663
  for(i=0;i<caps1->structs->len;i++) {
David Schleef's avatar
David Schleef committed
664
    GstStructure *struct1 = gst_caps_get_structure (caps1, i);
David Schleef's avatar
David Schleef committed
665
666
667
668
669
670
671
672
673
674

    if (_gst_caps_cap_is_always_compatible(struct1, caps2) == FALSE){
      return FALSE;
    }

  }

  return FALSE;
}

David Schleef's avatar
David Schleef committed
675
typedef struct {
David Schleef's avatar
David Schleef committed
676
  GstStructure *dest;
David Schleef's avatar
David Schleef committed
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
  const GstStructure *intersect;
  gboolean first_run;
} IntersectData;

static gboolean
gst_caps_structure_intersect_field (GQuark id, GValue *val1, gpointer data)
{
  IntersectData *idata = (IntersectData *) data;
  GValue dest_value = { 0 };
  const GValue *val2 = gst_structure_id_get_value (idata->intersect, id);

  if (val2 == NULL) {
    gst_structure_id_set_value (idata->dest, id, val1);
  } else if (idata->first_run) {
    if (gst_value_intersect (&dest_value, val1, val2)) {
      gst_structure_id_set_value (idata->dest, id, &dest_value);
      g_value_unset (&dest_value);
David Schleef's avatar
David Schleef committed
694
    } else {
David Schleef's avatar
David Schleef committed
695
      return FALSE;
David Schleef's avatar
David Schleef committed
696
697
    }
  }
David Schleef's avatar
David Schleef committed
698
699
700
  
  return TRUE;
}
David Schleef's avatar
David Schleef committed
701

David Schleef's avatar
David Schleef committed
702
703
704
705
static GstStructure *gst_caps_structure_intersect (const GstStructure *struct1,
    const GstStructure *struct2)
{
  IntersectData data;
David Schleef's avatar
David Schleef committed
706

David Schleef's avatar
David Schleef committed
707
708
  g_return_val_if_fail(struct1 != NULL, NULL);
  g_return_val_if_fail(struct2 != NULL, NULL);
David Schleef's avatar
David Schleef committed
709

David Schleef's avatar
David Schleef committed
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
  if (struct1->name != struct2->name) return NULL;

  data.dest = gst_structure_id_empty_new (struct1->name);
  data.intersect = struct2;
  data.first_run = TRUE;
  if (!gst_structure_foreach ((GstStructure *) struct1, 
	gst_caps_structure_intersect_field, &data))
    goto error;
  
  data.intersect = struct1;
  data.first_run = FALSE;
  if (!gst_structure_foreach ((GstStructure *) struct2, 
	gst_caps_structure_intersect_field, &data))
    goto error;

  return data.dest;

error:
  gst_structure_free (data.dest);
  return NULL;
David Schleef's avatar
David Schleef committed
730
731
732
}

#if 0
David Schleef's avatar
David Schleef committed
733
static GstStructure *gst_caps_structure_union (const GstStructure *struct1,
David Schleef's avatar
David Schleef committed
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
    const GstStructure *struct2)
{
  int i;
  GstStructure *dest;
  const GstStructureField *field1;
  const GstStructureField *field2;
  int ret;

  /* FIXME this doesn't actually work */

  if (struct1->name != struct2->name) return NULL;

  dest = gst_structure_id_empty_new (struct1->name);

  for(i=0;i<struct1->fields->len;i++){
    GValue dest_value = { 0 };

    field1 = GST_STRUCTURE_FIELD (struct1, i);
    field2 = gst_structure_id_get_field (struct2, field1->name);

    if (field2 == NULL) {
      continue;
    } else {
      if (gst_value_union (&dest_value, &field1->value, &field2->value)) {
	gst_structure_set_value (dest, g_quark_to_string(field1->name),
	    &dest_value);
      } else {
	ret = gst_value_compare (&field1->value, &field2->value);
      }
    }
  }

  return dest;
}
#endif

/* operations */
771
772
773
774
775
776
777
778
779
780
781

/**
 * gst_caps_intersect:
 * @caps1: a #GstCaps to intersect
 * @caps2: a #GstCaps to intersect
 *
 * Creates a new #GstCaps that contains all the formats that are common
 * to both @caps1 and @caps2.
 *
 * Returns: the new #GstCaps
 */
David Schleef's avatar
David Schleef committed
782
GstCaps *gst_caps_intersect (const GstCaps *caps1, const GstCaps *caps2)
David Schleef's avatar
David Schleef committed
783
784
785
786
{
  int i,j;
  GstStructure *struct1;
  GstStructure *struct2;
David Schleef's avatar
David Schleef committed
787
  GstCaps *dest;
788
789
790
#if 0
  GstCaps *caps;
#endif
David Schleef's avatar
David Schleef committed
791
792
793
794
795
796
797
798
799

  g_return_val_if_fail (caps1 != NULL, NULL);
  g_return_val_if_fail (caps2 != NULL, NULL);

  if (gst_caps_is_empty (caps1) || gst_caps_is_empty (caps2)){
    return gst_caps_new_empty ();
  }
  if (gst_caps_is_any (caps1)) return gst_caps_copy (caps2);
  if (gst_caps_is_any (caps2)) return gst_caps_copy (caps1);
David Schleef's avatar
David Schleef committed
800

David Schleef's avatar
David Schleef committed
801
  dest = gst_caps_new_empty();
David Schleef's avatar
David Schleef committed
802
  for(i=0;i<caps1->structs->len;i++){
David Schleef's avatar
David Schleef committed
803
804
805
    struct1 = gst_caps_get_structure (caps1, i);
    for(j=0;j<caps2->structs->len;j++){
      GstStructure *istruct;
David Schleef's avatar
David Schleef committed
806

David Schleef's avatar
David Schleef committed
807
808
809
810
      struct2 = gst_caps_get_structure (caps2, j);
      istruct = gst_caps_structure_intersect (struct1, struct2);

      gst_caps_append_structure(dest, istruct);
David Schleef's avatar
David Schleef committed
811
812
813
    }
  }

David Schleef's avatar
David Schleef committed
814
815
816
#if 0
  caps = gst_caps_simplify (dest);
  gst_caps_free (dest);
David Schleef's avatar
David Schleef committed
817

David Schleef's avatar
David Schleef committed
818
819
  return caps;
#else
David Schleef's avatar
David Schleef committed
820
  return dest;
David Schleef's avatar
David Schleef committed
821
#endif
David Schleef's avatar
David Schleef committed
822
823
}

824
825
826
827
828
829
830
831
832
833
/**
 * gst_caps_union:
 * @caps1: a #GstCaps to union
 * @caps2: a #GstCaps to union
 *
 * Creates a new #GstCaps that contains all the formats that are in
 * either @caps1 and @caps2.
 *
 * Returns: the new #GstCaps
 */
David Schleef's avatar
David Schleef committed
834
GstCaps *gst_caps_union (const GstCaps *caps1, const GstCaps *caps2)
David Schleef's avatar
David Schleef committed
835
{
David Schleef's avatar
David Schleef committed
836
837
  GstCaps *dest1;
  GstCaps *dest2;
David Schleef's avatar
David Schleef committed
838

David Schleef's avatar
David Schleef committed
839
840
841
  dest1 = gst_caps_copy (caps1);
  dest2 = gst_caps_copy (caps2);
  gst_caps_append (dest1, dest2);
David Schleef's avatar
David Schleef committed
842
843
844
845
846
847

  /* FIXME: need a simplify function */

  return dest1;
}

David Schleef's avatar
David Schleef committed
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
typedef struct _NormalizeForeach {
  GstCaps *caps;
  GstStructure *structure;
} NormalizeForeach;

static gboolean
_gst_caps_normalize_foreach (GQuark field_id, GValue *value, gpointer ptr)
{
  NormalizeForeach *nf = (NormalizeForeach *) ptr;
  GValue val = { 0 };
  int i;

  if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
    for (i=1; i<gst_value_list_get_size (value); i++) {
      const GValue *v = gst_value_list_get_value (value, i);
      GstStructure *structure = gst_structure_copy (nf->structure);

      gst_structure_id_set_value (structure, field_id, v);
      gst_caps_append_structure (nf->caps, structure);
    }

    gst_value_init_and_copy (&val, gst_value_list_get_value (value, 0));
    gst_structure_id_set_value (nf->structure, field_id, &val);
    g_value_unset (&val);

    return FALSE;
  }
  return TRUE;
}

878
879
880
881
882
883
884
885
886
887
/**
 * gst_caps_normalize:
 * @caps: a #GstCaps to normalize
 *
 * Creates a new #GstCaps that represents the same set of formats as
 * @caps, but contains no lists.  Each list is expanded into separate
 * @GstStructures.
 *
 * Returns: the new #GstCaps
 */
David Schleef's avatar
David Schleef committed
888
GstCaps *gst_caps_normalize (const GstCaps *caps)
David Schleef's avatar
David Schleef committed
889
{
David Schleef's avatar
David Schleef committed
890
891
892
  NormalizeForeach nf;
  GstCaps *newcaps;
  int i;
David Schleef's avatar
David Schleef committed
893

David Schleef's avatar
David Schleef committed
894
895
896
897
898
899
900
901
902
903
904
905
906
  g_return_val_if_fail(caps != NULL, NULL);

  newcaps = gst_caps_copy (caps);
  nf.caps = newcaps;

  for(i=0;i<newcaps->structs->len;i++){
    nf.structure = gst_caps_get_structure (newcaps, i);

    while (!gst_structure_foreach (nf.structure, _gst_caps_normalize_foreach,
          &nf));
  }

  return newcaps;
David Schleef's avatar
David Schleef committed
907
908
}

909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
static gboolean
simplify_foreach (GQuark field_id, GValue *value, gpointer user_data)
{
  GstStructure *s2 = (GstStructure *) user_data;
  const GValue *v2;

  v2 = gst_structure_id_get_value (s2, field_id);
  if (v2 == NULL) return FALSE;

  if (gst_value_compare (value, v2) == GST_VALUE_EQUAL) return TRUE;
  return FALSE;
}

static gboolean
gst_caps_structure_simplify (GstStructure *struct1, const GstStructure *struct2)
{
  /* FIXME this is just a simple compare.  Better would be to merge
   * the two structures */
  if (struct1->name != struct2->name) return FALSE;
  if (struct1->fields->len != struct2->fields->len) return FALSE;

  return gst_structure_foreach (struct1, simplify_foreach, (void *)struct2);
}

933
934
935
936
937
938
939
940
941
942
943
/**
 * gst_caps_simplify:
 * @caps: a #GstCaps to simplify
 *
 * Creates a new #GstCaps that represents the same set of formats as
 * @caps, but simpler.  Component structures that are identical are
 * merged.  Component structures that have ranges or lists that can
 * be merged are also merged.
 *
 * Returns: the new #GstCaps
 */
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
GstCaps *gst_caps_simplify (const GstCaps *caps)
{
  int i;
  int j;
  GstCaps *newcaps;
  GstStructure *structure;
  GstStructure *struct2;

  if (gst_caps_get_size (caps) < 2) {
    return gst_caps_copy (caps);
  }

  newcaps = gst_caps_new_empty ();

  for(i=0;i<gst_caps_get_size (caps);i++){
    structure = gst_caps_get_structure (caps, i);

    for(j=0;j<gst_caps_get_size (newcaps);j++){
      struct2 = gst_caps_get_structure (caps, i);
      if (gst_caps_structure_simplify (struct2, structure)) {
        break;
      }
    }
    if (j==gst_caps_get_size (newcaps)) {
      gst_caps_append_structure (newcaps, gst_structure_copy(structure));
    }
  }

  return newcaps;
}

David Schleef's avatar
David Schleef committed
975
#ifndef GST_DISABLE_LOADSAVE
David Schleef's avatar
David Schleef committed
976
xmlNodePtr gst_caps_save_thyself (const GstCaps *caps, xmlNodePtr parent)
David Schleef's avatar
David Schleef committed
977
978
979
980
981
{

  return 0;
}

David Schleef's avatar
David Schleef committed
982
GstCaps *gst_caps_load_thyself (xmlNodePtr parent)
David Schleef's avatar
David Schleef committed
983
984
985
986
987
988
989
{

  return NULL;
}
#endif

/* utility */
990
991
992
993
994
995
996
997
998
999

/**
 * gst_caps_replace:
 * @caps: a pointer to #GstCaps
 * @newcaps: a #GstCaps to replace *caps
 *
 * Replaces *caps with @newcaps.  Frees the #GstCaps in the location
 * pointed to by @caps, if applicable, then modifies @caps to point to
 * @newcaps.
 */
David Schleef's avatar
David Schleef committed
1000
void gst_caps_replace (GstCaps **caps, GstCaps *newcaps)
David Schleef's avatar
David Schleef committed
1001
{
1002
#if 0 /* disable this, since too many plugins rely on undefined behavior */
1003
#ifdef USE_POISONING
1004
1005
  //if (newcaps) CAPS_POISON (newcaps);
#endif
1006
#endif
David Schleef's avatar
David Schleef committed
1007
1008
  if (*caps) gst_caps_free(*caps);
  *caps = newcaps;
David Schleef's avatar
David Schleef committed
1009
1010
}

1011
1012
1013
1014
1015
1016
1017
1018
1019
/**
 * gst_caps_to_string:
 * @caps: a #GstCaps
 *
 * Converts @caps to a string representation.  This string representation
 * can be converted back to a #GstCaps by #gst_caps_from_string().
 *
 * Returns: a string representing @caps
 */
David Schleef's avatar
David Schleef committed
1020
gchar *gst_caps_to_string (const GstCaps *caps)
David Schleef's avatar
David Schleef committed
1021
1022
1023
1024
1025
{
  int i;
  GstStructure *structure;
  GString *s;

1026
1027
1028
1029
1030
1031
  /* NOTE:  This function is potentially called by the debug system,
   * so any calls to gst_log() (and GST_DEBUG(), GST_LOG(), etc.)
   * should be careful to avoid recursion.  This includes any functions
   * called by gst_caps_to_string.  In particular, calls should
   * not use the GST_PTR_FORMAT extension.  */

David Schleef's avatar
David Schleef committed
1032
1033
  /* FIXME does this leak? */

David Schleef's avatar
David Schleef committed
1034
1035
1036
1037
  if (caps == NULL) {
    return g_strdup("NULL");
  }
  if(gst_caps_is_any(caps)){
David Schleef's avatar
David Schleef committed
1038
1039
    return g_strdup("ANY");
  }
David Schleef's avatar
David Schleef committed
1040
  if(gst_caps_is_empty(caps)){
David Schleef's avatar
David Schleef committed
1041
1042
1043
    return g_strdup("EMPTY");
  }
  s = g_string_new("");
David Schleef's avatar
David Schleef committed
1044
  structure = gst_caps_get_structure (caps, 0);
David Schleef's avatar
David Schleef committed
1045
1046
1047
  g_string_append(s, gst_structure_to_string(structure));

  for(i=1;i<caps->structs->len;i++){
David Schleef's avatar
David Schleef committed
1048
    structure = gst_caps_get_structure (caps, i);
David Schleef's avatar
David Schleef committed
1049
1050
1051
1052
1053
1054
1055
1056

    g_string_append(s, "; ");
    g_string_append(s, gst_structure_to_string(structure));
  }

  return g_string_free(s, FALSE);
}

David Schleef's avatar
David Schleef committed
1057
static gboolean _gst_caps_from_string_inplace (GstCaps *caps,
David Schleef's avatar
David Schleef committed
1058
1059
1060
    const gchar *string)
{
  GstStructure *structure;
David Schleef's avatar
David Schleef committed
1061
  gchar *s;
David Schleef's avatar
David Schleef committed
1062
1063

  if (strcmp("ANY", string)==0) {
David Schleef's avatar
David Schleef committed
1064
1065
    caps->flags = GST_CAPS_FLAGS_ANY;
    return TRUE;
David Schleef's avatar
David Schleef committed
1066
1067
  }
  if (strcmp("NONE", string)==0) {
David Schleef's avatar
David Schleef committed
1068
    return TRUE;
David Schleef's avatar
David Schleef committed
1069
1070
  }

David Schleef's avatar
David Schleef committed
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
  structure = gst_structure_from_string(string, &s);
  if (structure == NULL) {
    return FALSE;
  }
  gst_caps_append_structure (caps, structure);

  while (*s == ';') {
    s++;
    while (g_ascii_isspace(*s))s++;
    structure = gst_structure_from_string(s, &s);
    if (structure == NULL) {
      return FALSE;
    }
    gst_caps_append_structure (caps, structure);
    while (g_ascii_isspace(*s))s++;
  }

  if (*s != 0){
    return FALSE;
  }

  return TRUE;
David Schleef's avatar
David Schleef committed
1093
1094
}

1095
1096
1097
1098
1099
1100
1101
1102
/**
 * gst_caps_from_string:
 * @caps: a string to convert to #GstCaps
 *
 * Converts @caps from a string representation.
 *
 * Returns: a new #GstCaps
 */
David Schleef's avatar
David Schleef committed
1103
GstCaps *gst_caps_from_string (const gchar *string)
David Schleef's avatar
David Schleef committed
1104
{
David Schleef's avatar
David Schleef committed
1105
  GstCaps *caps;
David Schleef's avatar
David Schleef committed
1106

David Schleef's avatar
David Schleef committed
1107
1108
1109
1110
1111
1112
1113
  caps = gst_caps_new_empty();
  if (_gst_caps_from_string_inplace (caps, string)) {
    return caps;
  } else {
    gst_caps_free (caps);
    return NULL;
  }
David Schleef's avatar
David Schleef committed
1114
1115
}

David Schleef's avatar
David Schleef committed
1116
static void _gst_caps_transform_to_string (const GValue *src_value,
David Schleef's avatar
David Schleef committed
1117
1118
1119
1120
1121
1122
    GValue *dest_value)
{
  g_return_if_fail (src_value != NULL);
  g_return_if_fail (dest_value != NULL);

  dest_value->data[0].v_pointer =
David Schleef's avatar
David Schleef committed
1123
    gst_caps_to_string (src_value->data[0].v_pointer);
David Schleef's avatar
David Schleef committed
1124
1125
}

David Schleef's avatar
David Schleef committed
1126
static void _gst_caps_value_init (GValue *value)
David Schleef's avatar
David Schleef committed
1127
{
David Schleef's avatar
David Schleef committed
1128
  value->data[0].v_pointer = gst_caps_new_empty();
David Schleef's avatar
David Schleef committed
1129
1130
}

David Schleef's avatar
David Schleef committed
1131
static void _gst_caps_value_free (GValue *value)
David Schleef's avatar
David Schleef committed
1132
{
David Schleef's avatar
David Schleef committed
1133
  if (value->data[0].v_pointer) gst_caps_free (value->data[0].v_pointer);
David Schleef's avatar
David Schleef committed
1134
1135
}

David Schleef's avatar
David Schleef committed
1136
static void _gst_caps_value_copy (const GValue *src, GValue *dest)
David Schleef's avatar
David Schleef committed
1137
{
David Schleef's avatar
David Schleef committed
1138
1139
  if (dest->data[0].v_pointer) {
    gst_caps_free (dest->data[0].v_pointer);
1140
1141
  }
  if (src->data[0].v_pointer) {
David Schleef's avatar
David Schleef committed
1142
1143
1144
1145
    dest->data[0].v_pointer = gst_caps_copy (src->data[0].v_pointer);
  } else {
    dest->data[0].v_pointer = NULL;
  }
David Schleef's avatar
David Schleef committed
1146
1147
}

David Schleef's avatar
David Schleef committed
1148
static gpointer _gst_caps_value_peek_pointer (const GValue *value)
David Schleef's avatar
David Schleef committed
1149
1150
1151
1152
{
  return value->data[0].v_pointer;
}

David Schleef's avatar
David Schleef committed
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
/* fixate utility functions */

gboolean gst_caps_structure_fixate_field_nearest_int (GstStructure *structure,
    const char *field_name, int target)
{
  const GValue *value;

  g_return_val_if_fail(gst_structure_has_field (structure, field_name), FALSE);

  value = gst_structure_get_value (structure, field_name);

  if (G_VALUE_TYPE (value) == G_TYPE_INT) {
    /* already fixed */
    return FALSE;
  } else if (G_VALUE_TYPE (value) == GST_TYPE_INT_RANGE) {
    int x;
    x = gst_value_get_int_range_min (value);
    if (target < x) target = x;
    x = gst_value_get_int_range_max (value);
    if (target > x) target = x;
    gst_structure_set (structure, field_name, G_TYPE_INT, target, NULL);
    return TRUE;
  } else if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
    const GValue *list_value;
    int i, n;
    int best = 0;
    int best_index = -1;

    n = gst_value_list_get_size (value);
    for(i=0;i<n;i++){
      list_value = gst_value_list_get_value (value, i);
      if (G_VALUE_TYPE (list_value) == G_TYPE_INT) {
	int x = g_value_get_int (list_value);
	if (best_index == -1 || (ABS(target-x) < ABS(best-x))) {
	  best_index = i;
	  best = x;
	}
      }
    }
    if(best_index != -1) {
      gst_structure_set (structure, field_name, G_TYPE_INT, best, NULL);
      return TRUE;
    }
    return FALSE;
  }

  return FALSE;
}

gboolean gst_caps_structure_fixate_field_nearest_double (GstStructure
    *structure, const char *field_name, double target)
{
  const GValue *value;

  g_return_val_if_fail(gst_structure_has_field (structure, field_name), FALSE);

  value = gst_structure_get_value (structure, field_name);

  if (G_VALUE_TYPE (value) == G_TYPE_DOUBLE) {
    /* already fixed */
    return FALSE;
  } else if (G_VALUE_TYPE (value) == GST_TYPE_DOUBLE_RANGE) {
    double x;
    x = gst_value_get_double_range_min (value);
    if (target < x) target = x;
    x = gst_value_get_double_range_max (value);
    if (target > x) target = x;
    gst_structure_set (structure, field_name, G_TYPE_DOUBLE, target, NULL);
    return TRUE;
  } else if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
    const GValue *list_value;
    int i, n;
    double best = 0;
    int best_index = -1;

    n = gst_value_list_get_size (value);
    for(i=0;i<n;i++){
      list_value = gst_value_list_get_value (value, i);
      if (G_VALUE_TYPE (list_value) == G_TYPE_DOUBLE) {
	double x = g_value_get_double (list_value);
	if (best_index == -1 || (ABS(target-x) < ABS(best-x))) {
	  best_index = i;
	  best = x;
	}
      }
    }
    if(best_index != -1) {
      gst_structure_set (structure, field_name, G_TYPE_DOUBLE, best, NULL);
      return TRUE;
    }
    return FALSE;
  }

  return FALSE;

}