Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / gst-libs / gst / audio / multichannel.c
1 /* GStreamer Multichannel-Audio helper functions
2  * (c) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
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  * SECTION:gstmultichannel
21  * @short_description: Support for multichannel audio elements
22  *
23  * This module contains some helper functions and a enum to work with
24  * multichannel audio.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "multichannel.h"
32
33 #define GST_AUDIO_CHANNEL_POSITIONS_FIELD_NAME "channel-positions"
34
35 /**
36  * gst_audio_check_channel_positions:
37  * @pos: An array of #GstAudioChannelPosition.
38  * @channels: The number of elements in @pos.
39  *
40  * This functions checks if the given channel positions are valid. Channel
41  * positions are valid if:
42  * <itemizedlist>
43  *   <listitem><para>No channel positions appears twice or all positions are %GST_AUDIO_CHANNEL_POSITION_NONE.
44  *   </para></listitem>
45  *   <listitem><para>Either all or none of the channel positions are %GST_AUDIO_CHANNEL_POSITION_NONE.
46  *   </para></listitem>
47  *   <listitem><para>%GST_AUDIO_CHANNEL_POSITION_FRONT_MONO and %GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT or %GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT don't appear together in the given positions.
48  *   </para></listitem>
49  * </itemizedlist>
50  *
51  * Since: 0.10.20
52  *
53  * Returns: %TRUE if the given channel positions are valid
54  * and %FALSE otherwise.
55  */
56 gboolean
57 gst_audio_check_channel_positions (const GstAudioChannelPosition * pos,
58     guint channels)
59 {
60   gint i, n;
61
62   const struct
63   {
64     const GstAudioChannelPosition pos1[2];
65     const GstAudioChannelPosition pos2[1];
66   } conf[] = {
67     /* front: mono <-> stereo */
68     { {
69     GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
70             GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
71     GST_AUDIO_CHANNEL_POSITION_FRONT_MONO}}, { {
72     GST_AUDIO_CHANNEL_POSITION_INVALID}}
73   };
74
75   g_return_val_if_fail (pos != NULL, FALSE);
76   g_return_val_if_fail (channels > 0, FALSE);
77
78   /* check for invalid channel positions */
79   for (n = 0; n < channels; n++) {
80     if (pos[n] <= GST_AUDIO_CHANNEL_POSITION_INVALID ||
81         pos[n] >= GST_AUDIO_CHANNEL_POSITION_NUM) {
82       GST_WARNING ("Channel position %d for channel %d is invalid", pos[n], n);
83       return FALSE;
84     }
85   }
86
87   /* either all channel positions are NONE or all are defined,
88    * but having only some channel positions NONE and others not
89    * is not allowed */
90   if (pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) {
91     for (n = 1; n < channels; ++n) {
92       if (pos[n] != GST_AUDIO_CHANNEL_POSITION_NONE) {
93         GST_WARNING ("Either all channel positions must be defined, or all "
94             "be set to NONE, having only some defined is not allowed");
95         return FALSE;
96       }
97     }
98     /* all positions are NONE, we are done here */
99     return TRUE;
100   }
101
102   /* check for multiple position occurrences */
103   for (i = GST_AUDIO_CHANNEL_POSITION_INVALID + 1;
104       i < GST_AUDIO_CHANNEL_POSITION_NUM; i++) {
105     gint count = 0;
106
107     for (n = 0; n < channels; n++) {
108       if (pos[n] == i)
109         count++;
110     }
111
112     /* NONE may not occur mixed with other channel positions */
113     if (i == GST_AUDIO_CHANNEL_POSITION_NONE && count > 0) {
114       GST_WARNING ("Either all channel positions must be defined, or all "
115           "be set to NONE, having only some defined is not allowed");
116       return FALSE;
117     }
118
119     if (count > 1) {
120       GST_WARNING ("Channel position %d occurred %d times, not allowed",
121           i, count);
122       return FALSE;
123     }
124   }
125
126   /* check for position conflicts */
127   for (i = 0; conf[i].pos1[0] != GST_AUDIO_CHANNEL_POSITION_INVALID; i++) {
128     gboolean found1 = FALSE, found2 = FALSE;
129
130     for (n = 0; n < channels; n++) {
131       if (pos[n] == conf[i].pos1[0] || pos[n] == conf[i].pos1[1])
132         found1 = TRUE;
133       else if (pos[n] == conf[i].pos2[0])
134         found2 = TRUE;
135     }
136
137     if (found1 && found2) {
138       GST_WARNING ("Found conflicting channel positions %d/%d and %d",
139           conf[i].pos1[0], conf[i].pos1[1], conf[i].pos2[0]);
140       return FALSE;
141     }
142   }
143
144   return TRUE;
145 }
146
147 /* FIXME: these default positions may or may not be correct. In any
148  * case, they are mostly just a fallback for buggy plugins, so it
149  * should not really matter too much */
150 #define NUM_DEF_CHANS  8
151 static const GstAudioChannelPosition
152     default_positions[NUM_DEF_CHANS][NUM_DEF_CHANS] = {
153   /* 1 channel */
154   {
155         GST_AUDIO_CHANNEL_POSITION_FRONT_MONO,
156       },
157   /* 2 channels */
158   {
159         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
160         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
161       },
162   /* 3 channels (2.1) */
163   {
164         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
165         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
166         GST_AUDIO_CHANNEL_POSITION_LFE, /* or FRONT_CENTER for 3.0? */
167       },
168   /* 4 channels (4.0 or 3.1?) */
169   {
170         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
171         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
172         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
173         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
174       },
175   /* 5 channels */
176   {
177         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
178         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
179         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
180         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
181         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
182       },
183   /* 6 channels */
184   {
185         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
186         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
187         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
188         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
189         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
190         GST_AUDIO_CHANNEL_POSITION_LFE,
191       },
192   /* 7 channels */
193   {
194         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
195         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
196         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
197         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
198         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
199         GST_AUDIO_CHANNEL_POSITION_LFE,
200         GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
201       },
202   /* 8 channels */
203   {
204         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
205         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
206         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
207         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
208         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
209         GST_AUDIO_CHANNEL_POSITION_LFE,
210         GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
211         GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
212       }
213 };
214
215 /**
216  * gst_audio_get_channel_positions:
217  * @str: A #GstStructure to retrieve channel positions from.
218  *
219  * Retrieves a number of (fixed!) audio channel positions from
220  * the provided #GstStructure and returns it as a newly allocated
221  * array. The caller should g_free () this array. The caller
222  * should also check that the members in this #GstStructure are
223  * indeed "fixed" before calling this function.
224  *
225  * Returns: a newly allocated array containing the channel
226  * positions as provided in the given #GstStructure. Returns
227  * NULL on error.
228  */
229
230 GstAudioChannelPosition *
231 gst_audio_get_channel_positions (GstStructure * str)
232 {
233   GstAudioChannelPosition *pos;
234
235   gint channels, n;
236
237   const GValue *pos_val_arr, *pos_val_entry;
238
239   gboolean res;
240
241   GType t;
242
243   /* get number of channels, general type checkups */
244   g_return_val_if_fail (str != NULL, NULL);
245   res = gst_structure_get_int (str, "channels", &channels);
246   g_return_val_if_fail (res, NULL);
247   g_return_val_if_fail (channels > 0, NULL);
248   pos_val_arr = gst_structure_get_value (str,
249       GST_AUDIO_CHANNEL_POSITIONS_FIELD_NAME);
250
251   /* The following checks are here to retain compatibility for plugins not
252    * implementing this field. They expect that channels=1 implies mono
253    * and channels=2 implies stereo, so we follow that. */
254   if (pos_val_arr == NULL) {
255     /* channel layouts for 1 and 2 channels are implicit, don't warn */
256     if (channels > 2) {
257       g_warning ("Failed to retrieve channel layout from caps. This usually "
258           "means there is a GStreamer element that does not implement "
259           "multichannel audio correctly. Please file a bug.");
260     }
261
262     /* just return some default channel layout if we have one */
263     if (channels >= 1 && channels <= NUM_DEF_CHANS) {
264       const GstAudioChannelPosition *p;
265
266       p = default_positions[channels - 1];
267       return g_memdup (p, channels * sizeof (GstAudioChannelPosition));
268     }
269
270     return NULL;
271   }
272
273   g_return_val_if_fail (gst_value_array_get_size (pos_val_arr) == channels,
274       NULL);
275   for (n = 0; n < channels; n++) {
276     t = G_VALUE_TYPE (gst_value_array_get_value (pos_val_arr, n));
277     g_return_val_if_fail (t == GST_TYPE_AUDIO_CHANNEL_POSITION, NULL);
278   }
279
280   /* ... and fill array */
281   pos = g_new (GstAudioChannelPosition, channels);
282   for (n = 0; n < channels; n++) {
283     pos_val_entry = gst_value_array_get_value (pos_val_arr, n);
284     pos[n] = g_value_get_enum (pos_val_entry);
285   }
286
287   if (!gst_audio_check_channel_positions (pos, channels)) {
288     g_free (pos);
289     return NULL;
290   }
291
292   return pos;
293 }
294
295 /**
296  * gst_audio_set_channel_positions:
297  * @str: A #GstStructure to set channel positions on.
298  * @pos: an array of channel positions. The number of members
299  *       in this array should be equal to the (fixed!) number
300  *       of the "channels" field in the given #GstStructure.
301  *
302  * Adds a "channel-positions" field to the given #GstStructure,
303  * which will represent the channel positions as given in the
304  * provided #GstAudioChannelPosition array.
305  */
306
307 void
308 gst_audio_set_channel_positions (GstStructure * str,
309     const GstAudioChannelPosition * pos)
310 {
311   GValue pos_val_arr = { 0 }, pos_val_entry = {
312   0};
313   gint channels, n;
314
315   gboolean res;
316
317   /* get number of channels, checkups */
318   g_return_if_fail (str != NULL);
319   g_return_if_fail (pos != NULL);
320   res = gst_structure_get_int (str, "channels", &channels);
321   g_return_if_fail (res);
322   g_return_if_fail (channels > 0);
323   if (!gst_audio_check_channel_positions (pos, channels))
324     return;
325
326   /* build gvaluearray from positions */
327   g_value_init (&pos_val_entry, GST_TYPE_AUDIO_CHANNEL_POSITION);
328   g_value_init (&pos_val_arr, GST_TYPE_ARRAY);
329   for (n = 0; n < channels; n++) {
330     g_value_set_enum (&pos_val_entry, pos[n]);
331     gst_value_array_append_value (&pos_val_arr, &pos_val_entry);
332   }
333   g_value_unset (&pos_val_entry);
334
335   /* add to structure */
336   gst_structure_set_value (str,
337       GST_AUDIO_CHANNEL_POSITIONS_FIELD_NAME, &pos_val_arr);
338   g_value_unset (&pos_val_arr);
339 }
340
341 /**
342  * gst_audio_set_structure_channel_positions_list:
343  * @str: #GstStructure to set the list of channel positions
344  *       on.
345  * @pos: the array containing one or more possible audio
346  *       channel positions that we should add in each value
347  *       of the array in the given structure.
348  * @num_positions: the number of values in pos.
349  *
350  * Sets a (possibly non-fixed) list of possible audio channel
351  * positions (given in pos) on the given structure. The
352  * structure, after this function has been called, will contain
353  * a "channel-positions" field with an array of the size of
354  * the "channels" field value in the given structure (note
355  * that this means that the channels field in the provided
356  * structure should be fixed!). Each value in the array will
357  * contain each of the values given in the pos array.
358  */
359
360 void
361 gst_audio_set_structure_channel_positions_list (GstStructure * str,
362     const GstAudioChannelPosition * pos, gint num_positions)
363 {
364   gint channels, n, c;
365   GValue pos_val_arr = { 0 }, pos_val_list = {
366   0}, pos_val_entry = {
367   0};
368   gboolean res;
369
370   /* get number of channels, general type checkups */
371   g_return_if_fail (str != NULL);
372   g_return_if_fail (num_positions > 0);
373   g_return_if_fail (pos != NULL);
374   res = gst_structure_get_int (str, "channels", &channels);
375   g_return_if_fail (res);
376   g_return_if_fail (channels > 0);
377
378   /* create the array of lists */
379   g_value_init (&pos_val_arr, GST_TYPE_ARRAY);
380   g_value_init (&pos_val_entry, GST_TYPE_AUDIO_CHANNEL_POSITION);
381   for (n = 0; n < channels; n++) {
382     g_value_init (&pos_val_list, GST_TYPE_LIST);
383     for (c = 0; c < num_positions; c++) {
384       g_value_set_enum (&pos_val_entry, pos[c]);
385       gst_value_list_append_value (&pos_val_list, &pos_val_entry);
386     }
387     gst_value_array_append_value (&pos_val_arr, &pos_val_list);
388     g_value_unset (&pos_val_list);
389   }
390   g_value_unset (&pos_val_entry);
391   gst_structure_set_value (str, GST_AUDIO_CHANNEL_POSITIONS_FIELD_NAME,
392       &pos_val_arr);
393   g_value_unset (&pos_val_arr);
394 }
395
396 /*
397  * Helper function for below. The structure will be conserved,
398  * but might be cut down. Any additional structures that were
399  * created will be stored in the returned caps.
400  */
401
402 static GstCaps *
403 add_list_to_struct (GstStructure * str,
404     const GstAudioChannelPosition * pos, gint num_positions)
405 {
406   GstCaps *caps = gst_caps_new_empty ();
407
408   const GValue *chan_val;
409
410   chan_val = gst_structure_get_value (str, "channels");
411   if (G_VALUE_TYPE (chan_val) == G_TYPE_INT) {
412     gst_audio_set_structure_channel_positions_list (str, pos, num_positions);
413   } else if (G_VALUE_TYPE (chan_val) == GST_TYPE_LIST) {
414     gint size;
415
416     const GValue *sub_val;
417
418     size = gst_value_list_get_size (chan_val);
419     sub_val = gst_value_list_get_value (chan_val, 0);
420     gst_structure_set_value (str, "channels", sub_val);
421     gst_caps_append (caps, add_list_to_struct (str, pos, num_positions));
422     while (--size > 0) {
423       str = gst_structure_copy (str);
424       sub_val = gst_value_list_get_value (chan_val, size);
425       gst_structure_set_value (str, "channels", sub_val);
426       gst_caps_append (caps, add_list_to_struct (str, pos, num_positions));
427       gst_caps_append_structure (caps, str);
428     }
429   } else if (G_VALUE_TYPE (chan_val) == GST_TYPE_INT_RANGE) {
430     gint min, max;
431
432     min = gst_value_get_int_range_min (chan_val);
433     max = gst_value_get_int_range_max (chan_val);
434
435     gst_structure_set (str, "channels", G_TYPE_INT, min, NULL);
436     gst_audio_set_structure_channel_positions_list (str, pos, num_positions);
437     for (++min; min < max; min++) {
438       str = gst_structure_copy (str);
439       gst_structure_set (str, "channels", G_TYPE_INT, min, NULL);
440       gst_audio_set_structure_channel_positions_list (str, pos, num_positions);
441       gst_caps_append_structure (caps, str);
442     }
443   } else {
444     g_warning ("Unexpected value type '%s' for channels field",
445         GST_STR_NULL (g_type_name (G_VALUE_TYPE (chan_val))));
446   }
447
448   return caps;
449 }
450
451 /**
452  * gst_audio_set_caps_channel_positions_list:
453  * @caps: #GstCaps to set the list of channel positions on.
454  * @pos: the array containing one or more possible audio
455  *       channel positions that we should add in each value
456  *       of the array in the given structure.
457  * @num_positions: the number of values in pos.
458  *
459  * Sets a (possibly non-fixed) list of possible audio channel
460  * positions (given in pos) on the given caps. Each of the
461  * structures of the caps, after this function has been called,
462  * will contain a "channel-positions" field with an array.
463  * Each value in the array will contain each of the values given
464  * in the pos array. Note that the size of the caps might be
465  * increased by this, since each structure with a "channel-
466  * positions" field needs to have a fixed "channels" field.
467  * The input caps is not required to have this.
468  */
469
470 void
471 gst_audio_set_caps_channel_positions_list (GstCaps * caps,
472     const GstAudioChannelPosition * pos, gint num_positions)
473 {
474   gint size, n;
475
476   /* get number of channels, general type checkups */
477   g_return_if_fail (caps != NULL);
478   g_return_if_fail (num_positions > 0);
479   g_return_if_fail (pos != NULL);
480
481   size = gst_caps_get_size (caps);
482   for (n = 0; n < size; n++) {
483     gst_caps_append (caps, add_list_to_struct (gst_caps_get_structure (caps,
484                 n), pos, num_positions));
485   }
486 }
487
488 /**
489  * gst_audio_fixate_channel_positions:
490  * @str: a #GstStructure containing a (possibly unfixed)
491  *       "channel-positions" field.
492  *
493  * Custom fixate function. Elements that implement some sort of
494  * channel conversion algorithm should use this function for
495  * fixating on GstAudioChannelPosition properties. It will take
496  * care of equal channel positioning (left/right). Caller g_free()s
497  * the return value. The input properties may be (and are supposed
498  * to be) unfixed.
499  * Note that this function is mostly a hack because we currently
500  * have no way to add default fixation functions for new GTypes.
501  *
502  * Returns: fixed values that the caller could use as a fixed
503  * set of #GstAudioChannelPosition values.
504  */
505
506 GstAudioChannelPosition *
507 gst_audio_fixate_channel_positions (GstStructure * str)
508 {
509   GstAudioChannelPosition *pos;
510
511   gint channels, n, num_unfixed = 0, i, c;
512
513   const GValue *pos_val_arr, *pos_val_entry, *pos_val;
514
515   gboolean res, is_stereo = TRUE;
516
517   GType t;
518
519   /*
520    * We're going to do this cluelessly. We'll make an array of values that
521    * conflict with each other and, for each iteration in this array, pick
522    * either one until all unknown values are filled. This might not work in
523    * corner cases but should work OK for the general case.
524    */
525   const struct
526   {
527     const GstAudioChannelPosition pos1[2];
528     const GstAudioChannelPosition pos2[1];
529   } conf[] = {
530     /* front: mono <-> stereo */
531     {
532       {
533       GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
534             GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
535     GST_AUDIO_CHANNEL_POSITION_FRONT_MONO}}, { {
536     GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
537             GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, {
538     GST_AUDIO_CHANNEL_POSITION_INVALID}}, { {
539     GST_AUDIO_CHANNEL_POSITION_INVALID, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
540     GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}}, { {
541     GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
542             GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
543     GST_AUDIO_CHANNEL_POSITION_INVALID}}, { {
544     GST_AUDIO_CHANNEL_POSITION_INVALID, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
545     GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}}, { {
546     GST_AUDIO_CHANNEL_POSITION_INVALID, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
547     GST_AUDIO_CHANNEL_POSITION_LFE}}, { {
548     GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
549             GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, {
550     GST_AUDIO_CHANNEL_POSITION_INVALID}}, { {
551     GST_AUDIO_CHANNEL_POSITION_INVALID, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
552     GST_AUDIO_CHANNEL_POSITION_INVALID}}
553   };
554   struct
555   {
556     gint num_opt[3];
557     guint num_opts[3];
558     gboolean is_fixed[3];
559     gint choice;                /* -1 is none, 0 is the two, 1 is the one */
560   } opt;
561
562   /* get number of channels, general type checkups */
563   g_return_val_if_fail (str != NULL, NULL);
564   res = gst_structure_get_int (str, "channels", &channels);
565   g_return_val_if_fail (res, NULL);
566   g_return_val_if_fail (channels > 0, NULL);
567
568   /* 0.8.x mono/stereo checks */
569   pos_val_arr = gst_structure_get_value (str,
570       GST_AUDIO_CHANNEL_POSITIONS_FIELD_NAME);
571   if (!pos_val_arr && (channels == 1 || channels == 2)) {
572     pos = g_new (GstAudioChannelPosition, channels);
573     if (channels == 1) {
574       pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_MONO;
575     } else {
576       pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
577       pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
578     }
579     return pos;
580   }
581   g_return_val_if_fail (pos_val_arr != NULL, NULL);
582   g_return_val_if_fail (gst_value_array_get_size (pos_val_arr) == channels,
583       NULL);
584   for (n = 0; n < channels; n++) {
585     t = G_VALUE_TYPE (gst_value_array_get_value (pos_val_arr, n));
586     g_return_val_if_fail (t == GST_TYPE_LIST ||
587         t == GST_TYPE_AUDIO_CHANNEL_POSITION, NULL);
588   }
589
590   /* all unknown, to start with */
591   pos = g_new (GstAudioChannelPosition, channels);
592   for (n = 0; n < channels; n++)
593     pos[n] = GST_AUDIO_CHANNEL_POSITION_INVALID;
594   num_unfixed = channels;
595
596   /* Iterate the array of conflicting values */
597   for (i = 0; conf[i].pos1[0] != GST_AUDIO_CHANNEL_POSITION_INVALID ||
598       conf[i].pos2[0] != GST_AUDIO_CHANNEL_POSITION_INVALID; i++) {
599     /* front/center only important if not mono (obviously) */
600     if (conf[i].pos1[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER &&
601         !is_stereo)
602       continue;
603
604     /* init values */
605     for (n = 0; n < 3; n++) {
606       opt.num_opt[n] = -1;
607       opt.num_opts[n] = -1;
608       opt.is_fixed[n] = FALSE;
609     }
610
611     /* Now, we'll see for each channel if it allows for any of the values in
612      * the set of conflicting audio channel positions and keep scores. */
613     for (n = 0; n < channels; n++) {
614       /* if the channel is already taken, don't bother */
615       if (pos[n] != GST_AUDIO_CHANNEL_POSITION_INVALID)
616         continue;
617
618       pos_val_entry = gst_value_array_get_value (pos_val_arr, n);
619       t = G_VALUE_TYPE (pos_val_entry);
620       if (t == GST_TYPE_LIST) {
621         /* This algorhythm is suboptimal. */
622         for (c = 0; c < gst_value_list_get_size (pos_val_entry); c++) {
623           pos_val = gst_value_list_get_value (pos_val_entry, c);
624           if (g_value_get_enum (pos_val) == conf[i].pos1[0] &&
625               opt.num_opts[0] > gst_value_list_get_size (pos_val_entry) &&
626               !opt.is_fixed[0]) {
627             /* Now test if the old position of num_opt[0] also allows for
628              * the other channel (which was skipped previously). If so,
629              * keep score. */
630             if (opt.num_opt[0] != -1) {
631               gint c1;
632
633               pos_val_entry = gst_value_array_get_value (pos_val_arr,
634                   opt.num_opt[0]);
635               if (G_VALUE_TYPE (pos_val_entry) == GST_TYPE_LIST) {
636                 for (c1 = 0; c1 < gst_value_list_get_size (pos_val_entry); c1++) {
637                   pos_val = gst_value_list_get_value (pos_val_entry, c1);
638                   if (g_value_get_enum (pos_val) == conf[i].pos1[1] &&
639                       opt.num_opts[1] > opt.num_opts[0] && !opt.is_fixed[1]) {
640                     opt.num_opts[1] = opt.num_opts[0];
641                     opt.num_opt[1] = opt.num_opt[0];
642                   }
643                 }
644                 pos_val = gst_value_list_get_value (pos_val_entry, c);
645               }
646               pos_val_entry = gst_value_array_get_value (pos_val_arr, n);
647             }
648
649             /* and save values */
650             opt.num_opts[0] = gst_value_list_get_size (pos_val_entry);
651             opt.num_opt[0] = n;
652           } else if (g_value_get_enum (pos_val) == conf[i].pos1[1] &&
653               opt.num_opts[1] > gst_value_list_get_size (pos_val_entry) &&
654               !opt.is_fixed[1] && n != opt.num_opt[0]) {
655             opt.num_opts[1] = gst_value_list_get_size (pos_val_entry);
656             opt.num_opt[1] = n;
657           }
658
659           /* 2 goes separately, because 0/1 vs. 2 are separate */
660           if (g_value_get_enum (pos_val) == conf[i].pos2[0] &&
661               opt.num_opts[2] > gst_value_list_get_size (pos_val_entry) &&
662               !opt.is_fixed[2]) {
663             opt.num_opts[2] = gst_value_list_get_size (pos_val_entry);
664             opt.num_opt[2] = n;
665           }
666         }
667       } else {
668         if (g_value_get_enum (pos_val_entry) == conf[i].pos1[0]) {
669           opt.num_opt[0] = n;
670           opt.is_fixed[0] = TRUE;
671         } else if (g_value_get_enum (pos_val_entry) == conf[i].pos1[1]) {
672           opt.num_opt[1] = n;
673           opt.is_fixed[1] = TRUE;
674         } else if (g_value_get_enum (pos_val_entry) == conf[i].pos2[0]) {
675           opt.num_opt[2] = n;
676           opt.is_fixed[2] = TRUE;
677         }
678       }
679     }
680
681     /* check our results and choose either one */
682     if ((opt.is_fixed[0] || opt.is_fixed[1]) && opt.is_fixed[2]) {
683       g_warning ("Pre-fixated on both %d/%d and %d - conflict!",
684           conf[i].pos1[0], conf[i].pos1[1], conf[i].pos2[0]);
685       g_free (pos);
686       return NULL;
687     } else if ((opt.is_fixed[0] && opt.num_opt[1] == -1) ||
688         (opt.is_fixed[1] && opt.num_opt[0] == -1)) {
689       g_warning ("Pre-fixated one side, but other side n/a of %d/%d",
690           conf[i].pos1[0], conf[i].pos1[1]);
691       g_free (pos);
692       return NULL;
693     } else if (opt.is_fixed[0] || opt.is_fixed[1]) {
694       opt.choice = 0;
695     } else if (opt.is_fixed[2]) {
696       opt.choice = 1;
697     } else if (opt.num_opt[0] != -1 && opt.num_opt[1] != -1) {
698       opt.choice = 0;
699     } else if (opt.num_opt[2] != -1) {
700       opt.choice = 1;
701     } else {
702       opt.choice = -1;
703     }
704
705     /* stereo? Note that we keep is_stereo to TRUE if we didn't decide on
706      * any arrangement. The mono/stereo channels might be handled elsewhere
707      * which is clearly outside the scope of this element, so we cannot
708      * know and expect the application to handle that then. */
709     if (conf[i].pos2[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO &&
710         opt.choice == 1) {
711       is_stereo = FALSE;
712     }
713
714     /* now actually decide what we'll do and fixate on that */
715     if (opt.choice == 0) {
716       g_assert (conf[i].pos1[0] != GST_AUDIO_CHANNEL_POSITION_INVALID &&
717           conf[i].pos1[1] != GST_AUDIO_CHANNEL_POSITION_INVALID);
718       pos[opt.num_opt[0]] = conf[i].pos1[0];
719       pos[opt.num_opt[1]] = conf[i].pos1[1];
720       num_unfixed -= 2;
721     } else if (opt.choice == 1) {
722       g_assert (conf[i].pos2[0] != GST_AUDIO_CHANNEL_POSITION_INVALID);
723       pos[opt.num_opt[2]] = conf[i].pos2[0];
724       num_unfixed--;
725     }
726   }
727
728   /* safety check */
729   if (num_unfixed > 0) {
730     g_warning ("%d unfixed channel positions left after fixation!",
731         num_unfixed);
732     g_free (pos);
733     return NULL;
734   }
735
736   if (!gst_audio_check_channel_positions (pos, channels)) {
737     g_free (pos);
738     return NULL;
739   }
740
741   return pos;
742 }