Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / gst / audioconvert / gstaudioconvert.c
1 /* GStreamer
2  * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
3  * Copyright (C) 2005 Thomas Vander Stichele <thomas at apestaart dot org>
4  * Copyright (C) 2005 Wim Taymans <wim at fluendo dot com>
5  *
6  * gstaudioconvert.c: Convert audio to different audio formats automatically
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /**
25  * SECTION:element-audioconvert
26  *
27  * Audioconvert converts raw audio buffers between various possible formats.
28  * It supports integer to float conversion, width/depth conversion,
29  * signedness and endianness conversion and channel transformations.
30  *
31  * <refsect2>
32  * <title>Example launch line</title>
33  * |[
34  * gst-launch -v -m audiotestsrc ! audioconvert ! audio/x-raw-int,channels=2,width=8,depth=8 ! level ! fakesink silent=TRUE
35  * ]| This pipeline converts audio to 8-bit.  The level element shows that
36  * the output levels still match the one for a sine wave.
37  * |[
38  * gst-launch -v -m audiotestsrc ! audioconvert ! vorbisenc ! fakesink silent=TRUE
39  * ]| The vorbis encoder takes float audio data instead of the integer data
40  * generated by audiotestsrc.
41  * </refsect2>
42  *
43  * Last reviewed on 2006-03-02 (0.10.4)
44  */
45
46 /*
47  * design decisions:
48  * - audioconvert converts buffers in a set of supported caps. If it supports
49  *   a caps, it supports conversion from these caps to any other caps it
50  *   supports. (example: if it does A=>B and A=>C, it also does B=>C)
51  * - audioconvert does not save state between buffers. Every incoming buffer is
52  *   converted and the converted buffer is pushed out.
53  * conclusion:
54  * audioconvert is not supposed to be a one-element-does-anything solution for
55  * audio conversions.
56  */
57
58 #ifdef HAVE_CONFIG_H
59 #include "config.h"
60 #endif
61
62 #include <string.h>
63
64 #include "gstaudioconvert.h"
65 #include "gstchannelmix.h"
66 #include "gstaudioquantize.h"
67 #include "plugin.h"
68
69 GST_DEBUG_CATEGORY (audio_convert_debug);
70 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
71
72 /*** DEFINITIONS **************************************************************/
73
74 /* type functions */
75 static void gst_audio_convert_dispose (GObject * obj);
76
77 /* gstreamer functions */
78 static gboolean gst_audio_convert_get_unit_size (GstBaseTransform * base,
79     GstCaps * caps, guint * size);
80 static GstCaps *gst_audio_convert_transform_caps (GstBaseTransform * base,
81     GstPadDirection direction, GstCaps * caps);
82 static void gst_audio_convert_fixate_caps (GstBaseTransform * base,
83     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
84 static gboolean gst_audio_convert_set_caps (GstBaseTransform * base,
85     GstCaps * incaps, GstCaps * outcaps);
86 static GstFlowReturn gst_audio_convert_transform (GstBaseTransform * base,
87     GstBuffer * inbuf, GstBuffer * outbuf);
88 static GstFlowReturn gst_audio_convert_transform_ip (GstBaseTransform * base,
89     GstBuffer * buf);
90 static void gst_audio_convert_set_property (GObject * object, guint prop_id,
91     const GValue * value, GParamSpec * pspec);
92 static void gst_audio_convert_get_property (GObject * object, guint prop_id,
93     GValue * value, GParamSpec * pspec);
94 static gboolean structure_has_fixed_channel_positions (GstStructure * s,
95     gboolean * unpositioned_layout);
96
97 /* AudioConvert signals and args */
98 enum
99 {
100   /* FILL ME */
101   LAST_SIGNAL
102 };
103
104 enum
105 {
106   ARG_0,
107   ARG_DITHERING,
108   ARG_NOISE_SHAPING,
109 };
110
111 #define DEBUG_INIT(bla) \
112   GST_DEBUG_CATEGORY_INIT (audio_convert_debug, "audioconvert", 0, "audio conversion element"); \
113   GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
114
115 GST_BOILERPLATE_FULL (GstAudioConvert, gst_audio_convert, GstBaseTransform,
116     GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
117
118 /*** GSTREAMER PROTOTYPES *****************************************************/
119
120 #define STATIC_CAPS \
121 GST_STATIC_CAPS ( \
122   "audio/x-raw-float, " \
123     "rate = (int) [ 1, MAX ], " \
124     "channels = (int) [ 1, MAX ], " \
125     "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
126     "width = (int) 64;" \
127   "audio/x-raw-float, " \
128     "rate = (int) [ 1, MAX ], " \
129     "channels = (int) [ 1, MAX ], " \
130     "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
131     "width = (int) 32;" \
132   "audio/x-raw-int, " \
133     "rate = (int) [ 1, MAX ], " \
134     "channels = (int) [ 1, MAX ], " \
135     "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
136     "width = (int) 32, " \
137     "depth = (int) [ 1, 32 ], " \
138     "signed = (boolean) { true, false }; " \
139   "audio/x-raw-int, "   \
140     "rate = (int) [ 1, MAX ], " \
141     "channels = (int) [ 1, MAX ], "       \
142     "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "        \
143     "width = (int) 24, "        \
144     "depth = (int) [ 1, 24 ], " "signed = (boolean) { true, false }; "  \
145   "audio/x-raw-int, " \
146     "rate = (int) [ 1, MAX ], " \
147     "channels = (int) [ 1, MAX ], " \
148     "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
149     "width = (int) 16, " \
150     "depth = (int) [ 1, 16 ], " \
151     "signed = (boolean) { true, false }; " \
152   "audio/x-raw-int, " \
153     "rate = (int) [ 1, MAX ], " \
154     "channels = (int) [ 1, MAX ], " \
155     "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
156     "width = (int) 8, " \
157     "depth = (int) [ 1, 8 ], " \
158     "signed = (boolean) { true, false } " \
159 )
160
161 static GstStaticPadTemplate gst_audio_convert_src_template =
162 GST_STATIC_PAD_TEMPLATE ("src",
163     GST_PAD_SRC,
164     GST_PAD_ALWAYS,
165     STATIC_CAPS);
166
167 static GstStaticPadTemplate gst_audio_convert_sink_template =
168 GST_STATIC_PAD_TEMPLATE ("sink",
169     GST_PAD_SINK,
170     GST_PAD_ALWAYS,
171     STATIC_CAPS);
172
173 #define GST_TYPE_AUDIO_CONVERT_DITHERING (gst_audio_convert_dithering_get_type ())
174 static GType
175 gst_audio_convert_dithering_get_type (void)
176 {
177   static GType gtype = 0;
178
179   if (gtype == 0) {
180     static const GEnumValue values[] = {
181       {DITHER_NONE, "No dithering",
182           "none"},
183       {DITHER_RPDF, "Rectangular dithering", "rpdf"},
184       {DITHER_TPDF, "Triangular dithering (default)", "tpdf"},
185       {DITHER_TPDF_HF, "High frequency triangular dithering", "tpdf-hf"},
186       {0, NULL, NULL}
187     };
188
189     gtype = g_enum_register_static ("GstAudioConvertDithering", values);
190   }
191   return gtype;
192 }
193
194 #define GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING (gst_audio_convert_ns_get_type ())
195 static GType
196 gst_audio_convert_ns_get_type (void)
197 {
198   static GType gtype = 0;
199
200   if (gtype == 0) {
201     static const GEnumValue values[] = {
202       {NOISE_SHAPING_NONE, "No noise shaping (default)",
203           "none"},
204       {NOISE_SHAPING_ERROR_FEEDBACK, "Error feedback", "error-feedback"},
205       {NOISE_SHAPING_SIMPLE, "Simple 2-pole noise shaping", "simple"},
206       {NOISE_SHAPING_MEDIUM, "Medium 5-pole noise shaping", "medium"},
207       {NOISE_SHAPING_HIGH, "High 8-pole noise shaping", "high"},
208       {0, NULL, NULL}
209     };
210
211     gtype = g_enum_register_static ("GstAudioConvertNoiseShaping", values);
212   }
213   return gtype;
214 }
215
216
217 /*** TYPE FUNCTIONS ***********************************************************/
218
219 static void
220 gst_audio_convert_base_init (gpointer g_class)
221 {
222   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
223
224   gst_element_class_add_pad_template (element_class,
225       gst_static_pad_template_get (&gst_audio_convert_src_template));
226   gst_element_class_add_pad_template (element_class,
227       gst_static_pad_template_get (&gst_audio_convert_sink_template));
228   gst_element_class_set_details_simple (element_class,
229       "Audio converter", "Filter/Converter/Audio",
230       "Convert audio to different formats", "Benjamin Otte <otte@gnome.org>");
231 }
232
233 static void
234 gst_audio_convert_class_init (GstAudioConvertClass * klass)
235 {
236   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
237   GstBaseTransformClass *basetransform_class = GST_BASE_TRANSFORM_CLASS (klass);
238
239   gobject_class->dispose = gst_audio_convert_dispose;
240   gobject_class->set_property = gst_audio_convert_set_property;
241   gobject_class->get_property = gst_audio_convert_get_property;
242
243   g_object_class_install_property (gobject_class, ARG_DITHERING,
244       g_param_spec_enum ("dithering", "Dithering",
245           "Selects between different dithering methods.",
246           GST_TYPE_AUDIO_CONVERT_DITHERING, DITHER_TPDF,
247           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
248
249   g_object_class_install_property (gobject_class, ARG_NOISE_SHAPING,
250       g_param_spec_enum ("noise-shaping", "Noise shaping",
251           "Selects between different noise shaping methods.",
252           GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING, NOISE_SHAPING_NONE,
253           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
254
255   basetransform_class->get_unit_size =
256       GST_DEBUG_FUNCPTR (gst_audio_convert_get_unit_size);
257   basetransform_class->transform_caps =
258       GST_DEBUG_FUNCPTR (gst_audio_convert_transform_caps);
259   basetransform_class->fixate_caps =
260       GST_DEBUG_FUNCPTR (gst_audio_convert_fixate_caps);
261   basetransform_class->set_caps =
262       GST_DEBUG_FUNCPTR (gst_audio_convert_set_caps);
263   basetransform_class->transform_ip =
264       GST_DEBUG_FUNCPTR (gst_audio_convert_transform_ip);
265   basetransform_class->transform =
266       GST_DEBUG_FUNCPTR (gst_audio_convert_transform);
267
268   basetransform_class->passthrough_on_same_caps = TRUE;
269 }
270
271 static void
272 gst_audio_convert_init (GstAudioConvert * this, GstAudioConvertClass * g_class)
273 {
274   this->dither = DITHER_TPDF;
275   this->ns = NOISE_SHAPING_NONE;
276   memset (&this->ctx, 0, sizeof (AudioConvertCtx));
277
278   gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (this), TRUE);
279 }
280
281 static void
282 gst_audio_convert_dispose (GObject * obj)
283 {
284   GstAudioConvert *this = GST_AUDIO_CONVERT (obj);
285
286   audio_convert_clean_context (&this->ctx);
287
288   G_OBJECT_CLASS (parent_class)->dispose (obj);
289 }
290
291 /*** GSTREAMER FUNCTIONS ******************************************************/
292
293 /* convert the given GstCaps to our format */
294 static gboolean
295 gst_audio_convert_parse_caps (const GstCaps * caps, AudioConvertFmt * fmt)
296 {
297   GstStructure *structure = gst_caps_get_structure (caps, 0);
298
299   GST_DEBUG ("parse caps %p and %" GST_PTR_FORMAT, caps, caps);
300
301   g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
302   g_return_val_if_fail (fmt != NULL, FALSE);
303
304   /* cleanup old */
305   audio_convert_clean_fmt (fmt);
306
307   fmt->endianness = G_BYTE_ORDER;
308   fmt->is_int =
309       (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0);
310
311   /* parse common fields */
312   if (!gst_structure_get_int (structure, "channels", &fmt->channels))
313     goto no_values;
314   if (!(fmt->pos = gst_audio_get_channel_positions (structure)))
315     goto no_values;
316
317   fmt->unpositioned_layout = FALSE;
318   structure_has_fixed_channel_positions (structure, &fmt->unpositioned_layout);
319
320   if (!gst_structure_get_int (structure, "width", &fmt->width))
321     goto no_values;
322   if (!gst_structure_get_int (structure, "rate", &fmt->rate))
323     goto no_values;
324   /* width != 8 needs an endianness field */
325   if (fmt->width != 8) {
326     if (!gst_structure_get_int (structure, "endianness", &fmt->endianness))
327       goto no_values;
328   }
329
330   if (fmt->is_int) {
331     /* int specific fields */
332     if (!gst_structure_get_boolean (structure, "signed", &fmt->sign))
333       goto no_values;
334     if (!gst_structure_get_int (structure, "depth", &fmt->depth))
335       goto no_values;
336
337     /* depth cannot be bigger than the width */
338     if (fmt->depth > fmt->width)
339       goto not_allowed;
340   }
341
342   fmt->unit_size = (fmt->width * fmt->channels) / 8;
343
344   return TRUE;
345
346   /* ERRORS */
347 no_values:
348   {
349     GST_DEBUG ("could not get some values from structure");
350     audio_convert_clean_fmt (fmt);
351     return FALSE;
352   }
353 not_allowed:
354   {
355     GST_DEBUG ("width > depth, not allowed - make us advertise correct fmt");
356     audio_convert_clean_fmt (fmt);
357     return FALSE;
358   }
359 }
360
361 /* BaseTransform vmethods */
362 static gboolean
363 gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
364     guint * size)
365 {
366   AudioConvertFmt fmt = { 0 };
367
368   g_assert (size);
369
370   if (!gst_audio_convert_parse_caps (caps, &fmt))
371     goto parse_error;
372
373   GST_INFO_OBJECT (base, "unit_size = %u", fmt.unit_size);
374   *size = fmt.unit_size;
375
376   audio_convert_clean_fmt (&fmt);
377
378   return TRUE;
379
380 parse_error:
381   {
382     GST_INFO_OBJECT (base, "failed to parse caps to get unit_size");
383     return FALSE;
384   }
385 }
386
387 /* Set widths (a list); multiples of 8 between min and max */
388 static void
389 set_structure_widths (GstStructure * s, int min, int max)
390 {
391   GValue list = { 0 };
392   GValue val = { 0 };
393   int width;
394
395   if (min == max) {
396     gst_structure_set (s, "width", G_TYPE_INT, min, NULL);
397     return;
398   }
399
400   g_value_init (&list, GST_TYPE_LIST);
401   g_value_init (&val, G_TYPE_INT);
402   for (width = min; width <= max; width += 8) {
403     g_value_set_int (&val, width);
404     gst_value_list_append_value (&list, &val);
405   }
406   gst_structure_set_value (s, "width", &list);
407   g_value_unset (&val);
408   g_value_unset (&list);
409 }
410
411 /* Set widths of 32 bits and 64 bits (as list) */
412 static void
413 set_structure_widths_32_and_64 (GstStructure * s)
414 {
415   GValue list = { 0 };
416   GValue val = { 0 };
417
418   g_value_init (&list, GST_TYPE_LIST);
419   g_value_init (&val, G_TYPE_INT);
420   g_value_set_int (&val, 32);
421   gst_value_list_append_value (&list, &val);
422   g_value_set_int (&val, 64);
423   gst_value_list_append_value (&list, &val);
424   gst_structure_set_value (s, "width", &list);
425   g_value_unset (&val);
426   g_value_unset (&list);
427 }
428
429 /* Modify the structure so that things that must always have a single
430  * value (for float), or can always be losslessly converted (for int), have
431  * appropriate values.
432  */
433 static GstStructure *
434 make_lossless_changes (GstStructure * s, gboolean isfloat)
435 {
436   GValue list = { 0 };
437   GValue val = { 0 };
438   int i;
439   const gint endian[] = { G_LITTLE_ENDIAN, G_BIG_ENDIAN };
440   const gboolean booleans[] = { TRUE, FALSE };
441
442   g_value_init (&list, GST_TYPE_LIST);
443   g_value_init (&val, G_TYPE_INT);
444   for (i = 0; i < 2; i++) {
445     g_value_set_int (&val, endian[i]);
446     gst_value_list_append_value (&list, &val);
447   }
448   gst_structure_set_value (s, "endianness", &list);
449   g_value_unset (&val);
450   g_value_unset (&list);
451
452   if (isfloat) {
453     /* float doesn't have a depth or signedness field and only supports
454      * widths of 32 and 64 bits */
455     gst_structure_remove_field (s, "depth");
456     gst_structure_remove_field (s, "signed");
457     set_structure_widths_32_and_64 (s);
458   } else {
459     /* int supports signed and unsigned. GValues are a pain */
460     g_value_init (&list, GST_TYPE_LIST);
461     g_value_init (&val, G_TYPE_BOOLEAN);
462     for (i = 0; i < 2; i++) {
463       g_value_set_boolean (&val, booleans[i]);
464       gst_value_list_append_value (&list, &val);
465     }
466     gst_structure_set_value (s, "signed", &list);
467     g_value_unset (&val);
468     g_value_unset (&list);
469   }
470
471   return s;
472 }
473
474 static void
475 strip_width_64 (GstStructure * s)
476 {
477   const GValue *v = gst_structure_get_value (s, "width");
478   GValue widths = { 0 };
479
480   if (GST_VALUE_HOLDS_LIST (v)) {
481     int i;
482     int len = gst_value_list_get_size (v);
483
484     g_value_init (&widths, GST_TYPE_LIST);
485
486     for (i = 0; i < len; i++) {
487       const GValue *width = gst_value_list_get_value (v, i);
488
489       if (g_value_get_int (width) != 64)
490         gst_value_list_append_value (&widths, width);
491     }
492     gst_structure_set_value (s, "width", &widths);
493     g_value_unset (&widths);
494   }
495 }
496
497 /* Little utility function to create a related structure for float/int */
498 static void
499 append_with_other_format (GstCaps * caps, GstStructure * s, gboolean isfloat)
500 {
501   GstStructure *s2;
502
503   if (isfloat) {
504     s2 = gst_structure_copy (s);
505     gst_structure_set_name (s2, "audio/x-raw-int");
506     s = make_lossless_changes (s2, FALSE);
507     /* If 64 bit float was allowed; remove width 64: we don't support it for 
508      * integer*/
509     strip_width_64 (s);
510     gst_caps_append_structure (caps, s2);
511   } else {
512     s2 = gst_structure_copy (s);
513     gst_structure_set_name (s2, "audio/x-raw-float");
514     s = make_lossless_changes (s2, TRUE);
515     gst_caps_append_structure (caps, s2);
516   }
517 }
518
519 static gboolean
520 structure_has_fixed_channel_positions (GstStructure * s,
521     gboolean * unpositioned_layout)
522 {
523   GstAudioChannelPosition *pos;
524   const GValue *val;
525   gint channels = 0;
526
527   if (!gst_structure_get_int (s, "channels", &channels))
528     return FALSE;               /* probably a range */
529
530   val = gst_structure_get_value (s, "channel-positions");
531   if ((val == NULL || !gst_value_is_fixed (val)) && channels <= 8) {
532     GST_LOG ("no or unfixed channel-positions in %" GST_PTR_FORMAT, s);
533     return FALSE;
534   } else if (val == NULL || !gst_value_is_fixed (val)) {
535     GST_LOG ("implicit undefined channel-positions");
536     *unpositioned_layout = TRUE;
537     return TRUE;
538   }
539
540   pos = gst_audio_get_channel_positions (s);
541   if (pos && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) {
542     GST_LOG ("fixed undefined channel-positions in %" GST_PTR_FORMAT, s);
543     *unpositioned_layout = TRUE;
544   } else {
545     GST_LOG ("fixed defined channel-positions in %" GST_PTR_FORMAT, s);
546     *unpositioned_layout = FALSE;
547   }
548   g_free (pos);
549
550   return TRUE;
551 }
552
553 /* Audioconvert can perform all conversions on audio except for resampling. 
554  * However, there are some conversions we _prefer_ not to do. For example, it's
555  * better to convert format (float<->int, endianness, etc) than the number of
556  * channels, as the latter conversion is not lossless.
557  *
558  * So, we return, in order (assuming input caps have only one structure; 
559  * which is enforced by basetransform):
560  *  - input caps with a different format (lossless conversions).
561  *  - input caps with a different format (slightly lossy conversions).
562  *  - input caps with a different number of channels (very lossy!)
563  */
564 static GstCaps *
565 gst_audio_convert_transform_caps (GstBaseTransform * base,
566     GstPadDirection direction, GstCaps * caps)
567 {
568   GstCaps *ret;
569   GstStructure *s, *structure;
570   gboolean isfloat, allow_mixing;
571   gint width, depth, channels = 0;
572   const gchar *fields_used[] = {
573     "width", "depth", "rate", "channels", "endianness", "signed"
574   };
575   const gchar *structure_name;
576   int i;
577
578   g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL);
579
580   structure = gst_caps_get_structure (caps, 0);
581   structure_name = gst_structure_get_name (structure);
582
583   isfloat = strcmp (structure_name, "audio/x-raw-float") == 0;
584
585   /* We operate on a version of the original structure with any additional
586    * fields absent */
587   s = gst_structure_empty_new (structure_name);
588   for (i = 0; i < sizeof (fields_used) / sizeof (*fields_used); i++) {
589     if (gst_structure_has_field (structure, fields_used[i]))
590       gst_structure_set_value (s, fields_used[i],
591           gst_structure_get_value (structure, fields_used[i]));
592   }
593
594   if (!isfloat) {
595     /* Commonly, depth is left out: set it equal to width if we have a fixed
596      * width, if so */
597     if (!gst_structure_has_field (s, "depth") &&
598         gst_structure_get_int (s, "width", &width))
599       gst_structure_set (s, "depth", G_TYPE_INT, width, NULL);
600   }
601
602   ret = gst_caps_new_empty ();
603
604   /* All lossless conversions */
605   s = make_lossless_changes (s, isfloat);
606   gst_caps_append_structure (ret, s);
607
608   /* Same, plus a float<->int conversion */
609   append_with_other_format (ret, s, isfloat);
610   GST_DEBUG_OBJECT (base, "  step1: (%d) %" GST_PTR_FORMAT,
611       gst_caps_get_size (ret), ret);
612
613   /* We don't mind increasing width/depth/channels, but reducing them is 
614    * Very Bad. Only available if width, depth, channels are already fixed. */
615   s = gst_structure_copy (s);
616   if (!isfloat) {
617     if (gst_structure_get_int (structure, "width", &width))
618       set_structure_widths (s, width, 32);
619     if (gst_structure_get_int (structure, "depth", &depth)) {
620       if (depth == 32)
621         gst_structure_set (s, "depth", G_TYPE_INT, 32, NULL);
622       else
623         gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, depth, 32, NULL);
624     }
625   }
626
627   allow_mixing = TRUE;
628   if (gst_structure_get_int (structure, "channels", &channels)) {
629     gboolean unpositioned;
630
631     /* we don't support mixing for channels without channel positions */
632     if (structure_has_fixed_channel_positions (structure, &unpositioned))
633       allow_mixing = (unpositioned == FALSE);
634   }
635
636   if (!allow_mixing) {
637     gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
638     if (gst_structure_has_field (structure, "channel-positions"))
639       gst_structure_set_value (s, "channel-positions",
640           gst_structure_get_value (structure, "channel-positions"));
641   } else {
642     if (channels == 0)
643       gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 11, NULL);
644     else if (channels == 11)
645       gst_structure_set (s, "channels", G_TYPE_INT, 11, NULL);
646     else
647       gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, channels, 11, NULL);
648     gst_structure_remove_field (s, "channel-positions");
649   }
650   gst_caps_append_structure (ret, s);
651
652   /* Same, plus a float<->int conversion */
653   append_with_other_format (ret, s, isfloat);
654
655   /* We'll reduce depth if we must. We reduce as low as 16 bits (for integer); 
656    * reducing to less than this is even worse than dropping channels. We only 
657    * do this if we haven't already done the equivalent above. */
658   if (!gst_structure_get_int (structure, "width", &width) || width > 16) {
659     if (isfloat) {
660       GstStructure *s2 = gst_structure_copy (s);
661
662       set_structure_widths_32_and_64 (s2);
663       append_with_other_format (ret, s2, TRUE);
664       gst_structure_free (s2);
665     } else {
666       s = gst_structure_copy (s);
667       set_structure_widths (s, 16, 32);
668       gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, 16, 32, NULL);
669       gst_caps_append_structure (ret, s);
670     }
671   }
672
673   /* Channel conversions to fewer channels is only done if needed - generally
674    * it's very bad to drop channels entirely.
675    */
676   s = gst_structure_copy (s);
677   if (allow_mixing) {
678     gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 11, NULL);
679     gst_structure_remove_field (s, "channel-positions");
680   } else {
681     /* allow_mixing can only be FALSE if we got a fixed number of channels */
682     gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
683     if (gst_structure_has_field (structure, "channel-positions"))
684       gst_structure_set_value (s, "channel-positions",
685           gst_structure_get_value (structure, "channel-positions"));
686   }
687   gst_caps_append_structure (ret, s);
688
689   /* Same, plus a float<->int conversion */
690   append_with_other_format (ret, s, isfloat);
691
692   /* And, finally, for integer only, we allow conversion to any width/depth we
693    * support: this should be equivalent to our (non-float) template caps. (the
694    * floating point case should be being handled just above) */
695   s = gst_structure_copy (s);
696   set_structure_widths (s, 8, 32);
697   gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, 1, 32, NULL);
698
699   if (isfloat) {
700     append_with_other_format (ret, s, TRUE);
701     gst_structure_free (s);
702   } else
703     gst_caps_append_structure (ret, s);
704
705   GST_DEBUG_OBJECT (base, "Caps transformed to %" GST_PTR_FORMAT, ret);
706
707   return ret;
708 }
709
710 static const GstAudioChannelPosition default_positions[8][8] = {
711   /* 1 channel */
712   {
713         GST_AUDIO_CHANNEL_POSITION_FRONT_MONO,
714       },
715   /* 2 channels */
716   {
717         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
718         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
719       },
720   /* 3 channels (2.1) */
721   {
722         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
723         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
724         GST_AUDIO_CHANNEL_POSITION_LFE, /* or FRONT_CENTER for 3.0? */
725       },
726   /* 4 channels (4.0 or 3.1?) */
727   {
728         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
729         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
730         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
731         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
732       },
733   /* 5 channels */
734   {
735         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
736         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
737         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
738         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
739         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
740       },
741   /* 6 channels */
742   {
743         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
744         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
745         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
746         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
747         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
748         GST_AUDIO_CHANNEL_POSITION_LFE,
749       },
750   /* 7 channels */
751   {
752         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
753         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
754         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
755         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
756         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
757         GST_AUDIO_CHANNEL_POSITION_LFE,
758         GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
759       },
760   /* 8 channels */
761   {
762         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
763         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
764         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
765         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
766         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
767         GST_AUDIO_CHANNEL_POSITION_LFE,
768         GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
769         GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
770       }
771 };
772
773 static const GValue *
774 find_suitable_channel_layout (const GValue * val, guint chans)
775 {
776   /* if output layout is fixed already and looks sane, we're done */
777   if (GST_VALUE_HOLDS_ARRAY (val) && gst_value_array_get_size (val) == chans)
778     return val;
779
780   /* if it's a list, go through it recursively and return the first
781    * sane-enough looking value we find */
782   if (GST_VALUE_HOLDS_LIST (val)) {
783     gint i;
784
785     for (i = 0; i < gst_value_list_get_size (val); ++i) {
786       const GValue *v, *ret;
787
788       v = gst_value_list_get_value (val, i);
789       if ((ret = find_suitable_channel_layout (v, chans)))
790         return ret;
791     }
792   }
793
794   return NULL;
795 }
796
797 static void
798 gst_audio_convert_fixate_channels (GstBaseTransform * base, GstStructure * ins,
799     GstStructure * outs)
800 {
801   const GValue *in_layout, *out_layout;
802   gint in_chans, out_chans;
803
804   if (!gst_structure_get_int (ins, "channels", &in_chans))
805     return;                     /* this shouldn't really happen, should it? */
806
807   if (!gst_structure_has_field (outs, "channels")) {
808     /* we could try to get the implied number of channels from the layout,
809      * but that seems overdoing it for a somewhat exotic corner case */
810     gst_structure_remove_field (outs, "channel-positions");
811     return;
812   }
813
814   /* ok, let's fixate the channels if they are not fixated yet */
815   gst_structure_fixate_field_nearest_int (outs, "channels", in_chans);
816
817   if (!gst_structure_get_int (outs, "channels", &out_chans)) {
818     /* shouldn't really happen ... */
819     gst_structure_remove_field (outs, "channel-positions");
820     return;
821   }
822
823   /* check if the output has a channel layout (or a list of layouts) */
824   out_layout = gst_structure_get_value (outs, "channel-positions");
825
826   /* get the channel layout of the input if any */
827   in_layout = gst_structure_get_value (ins, "channel-positions");
828
829   if (out_layout == NULL) {
830     if (out_chans <= 2 && (in_chans != out_chans || in_layout == NULL))
831       return;                   /* nothing to do, default layout will be assumed */
832     GST_WARNING_OBJECT (base, "downstream caps contain no channel layout");
833   }
834
835   if (in_chans == out_chans && in_layout != NULL) {
836     GValue res = { 0, };
837
838     /* same number of channels and no output layout: just use input layout */
839     if (out_layout == NULL) {
840       gst_structure_set_value (outs, "channel-positions", in_layout);
841       return;
842     }
843
844     /* if output layout is fixed already and looks sane, we're done */
845     if (GST_VALUE_HOLDS_ARRAY (out_layout) &&
846         gst_value_array_get_size (out_layout) == out_chans) {
847       return;
848     }
849
850     /* if the output layout is not fixed, check if the output layout contains
851      * the input layout */
852     if (gst_value_intersect (&res, in_layout, out_layout)) {
853       gst_structure_set_value (outs, "channel-positions", in_layout);
854       g_value_unset (&res);
855       return;
856     }
857
858     /* output layout is not fixed and does not contain the input layout, so
859      * just pick the first layout in the list (it should be a list ...) */
860     if ((out_layout = find_suitable_channel_layout (out_layout, out_chans))) {
861       gst_structure_set_value (outs, "channel-positions", out_layout);
862       return;
863     }
864
865     /* ... else fall back to default layout (NB: out_layout is NULL here) */
866     GST_WARNING_OBJECT (base, "unexpected output channel layout");
867   }
868
869   /* number of input channels != number of output channels:
870    * if this value contains a list of channel layouts (or even worse: a list
871    * with another list), just pick the first value and repeat until we find a
872    * channel position array or something else that's not a list; we assume
873    * the input if half-way sane and don't try to fall back on other list items
874    * if the first one is something unexpected or non-channel-pos-array-y */
875   if (out_layout != NULL && GST_VALUE_HOLDS_LIST (out_layout))
876     out_layout = find_suitable_channel_layout (out_layout, out_chans);
877
878   if (out_layout != NULL) {
879     if (GST_VALUE_HOLDS_ARRAY (out_layout) &&
880         gst_value_array_get_size (out_layout) == out_chans) {
881       /* looks sane enough, let's use it */
882       gst_structure_set_value (outs, "channel-positions", out_layout);
883       return;
884     }
885
886     /* what now?! Just ignore what we're given and use default positions */
887     GST_WARNING_OBJECT (base, "invalid or unexpected channel-positions");
888   }
889
890   /* missing or invalid output layout and we can't use the input layout for
891    * one reason or another, so just pick a default layout (we could be smarter
892    * and try to add/remove channels from the input layout, or pick a default
893    * layout based on LFE-presence in input layout, but let's save that for
894    * another day) */
895   if (out_chans > 0 && out_chans <= G_N_ELEMENTS (default_positions[0])) {
896     GST_DEBUG_OBJECT (base, "using default channel layout as fallback");
897     gst_audio_set_channel_positions (outs, default_positions[out_chans - 1]);
898   }
899 }
900
901 /* try to keep as many of the structure members the same by fixating the
902  * possible ranges; this way we convert the least amount of things as possible
903  */
904 static void
905 gst_audio_convert_fixate_caps (GstBaseTransform * base,
906     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
907 {
908   GstStructure *ins, *outs;
909   gint rate, endianness, depth, width;
910   gboolean signedness;
911
912   g_return_if_fail (gst_caps_is_fixed (caps));
913
914   GST_DEBUG_OBJECT (base, "trying to fixate othercaps %" GST_PTR_FORMAT
915       " based on caps %" GST_PTR_FORMAT, othercaps, caps);
916
917   ins = gst_caps_get_structure (caps, 0);
918   outs = gst_caps_get_structure (othercaps, 0);
919
920   gst_audio_convert_fixate_channels (base, ins, outs);
921
922   if (gst_structure_get_int (ins, "rate", &rate)) {
923     if (gst_structure_has_field (outs, "rate")) {
924       gst_structure_fixate_field_nearest_int (outs, "rate", rate);
925     }
926   }
927   if (gst_structure_get_int (ins, "endianness", &endianness)) {
928     if (gst_structure_has_field (outs, "endianness")) {
929       gst_structure_fixate_field_nearest_int (outs, "endianness", endianness);
930     }
931   }
932   if (gst_structure_get_int (ins, "width", &width)) {
933     if (gst_structure_has_field (outs, "width")) {
934       gst_structure_fixate_field_nearest_int (outs, "width", width);
935     }
936   } else {
937     /* this is not allowed */
938   }
939
940   if (gst_structure_get_int (ins, "depth", &depth)) {
941     if (gst_structure_has_field (outs, "depth")) {
942       gst_structure_fixate_field_nearest_int (outs, "depth", depth);
943     }
944   } else {
945     /* set depth as width */
946     if (gst_structure_has_field (outs, "depth")) {
947       gst_structure_fixate_field_nearest_int (outs, "depth", width);
948     }
949   }
950
951   if (gst_structure_get_boolean (ins, "signed", &signedness)) {
952     if (gst_structure_has_field (outs, "signed")) {
953       gst_structure_fixate_field_boolean (outs, "signed", signedness);
954     }
955   }
956
957   GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
958 }
959
960 static gboolean
961 gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
962     GstCaps * outcaps)
963 {
964   AudioConvertFmt in_ac_caps = { 0 };
965   AudioConvertFmt out_ac_caps = { 0 };
966   GstAudioConvert *this = GST_AUDIO_CONVERT (base);
967
968   GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
969       GST_PTR_FORMAT, incaps, outcaps);
970
971   if (!gst_audio_convert_parse_caps (incaps, &in_ac_caps))
972     return FALSE;
973   if (!gst_audio_convert_parse_caps (outcaps, &out_ac_caps))
974     return FALSE;
975
976   if (!audio_convert_prepare_context (&this->ctx, &in_ac_caps, &out_ac_caps,
977           this->dither, this->ns))
978     goto no_converter;
979
980   return TRUE;
981
982 no_converter:
983   {
984     return FALSE;
985   }
986 }
987
988 static GstFlowReturn
989 gst_audio_convert_transform_ip (GstBaseTransform * base, GstBuffer * buf)
990 {
991   /* nothing to do here */
992   return GST_FLOW_OK;
993 }
994
995 static void
996 gst_audio_convert_create_silence_buffer (GstAudioConvert * this, gpointer dst,
997     gint size)
998 {
999   if (this->ctx.out.is_int && !this->ctx.out.sign) {
1000     gint i;
1001
1002     switch (this->ctx.out.width) {
1003       case 8:{
1004         guint8 zero = 0x80 >> (8 - this->ctx.out.depth);
1005
1006         memset (dst, zero, size);
1007         break;
1008       }
1009       case 16:{
1010         guint16 *data = (guint16 *) dst;
1011         guint16 zero = 0x8000 >> (16 - this->ctx.out.depth);
1012
1013         if (this->ctx.out.endianness == G_LITTLE_ENDIAN)
1014           zero = GUINT16_TO_LE (zero);
1015         else
1016           zero = GUINT16_TO_BE (zero);
1017
1018         size /= 2;
1019
1020         for (i = 0; i < size; i++)
1021           data[i] = zero;
1022         break;
1023       }
1024       case 24:{
1025         guint32 zero = 0x800000 >> (24 - this->ctx.out.depth);
1026         guint8 *data = (guint8 *) dst;
1027
1028         if (this->ctx.out.endianness == G_LITTLE_ENDIAN) {
1029           for (i = 0; i < size; i += 3) {
1030             data[i] = zero & 0xff;
1031             data[i + 1] = (zero >> 8) & 0xff;
1032             data[i + 2] = (zero >> 16) & 0xff;
1033           }
1034         } else {
1035           for (i = 0; i < size; i += 3) {
1036             data[i + 2] = zero & 0xff;
1037             data[i + 1] = (zero >> 8) & 0xff;
1038             data[i] = (zero >> 16) & 0xff;
1039           }
1040         }
1041         break;
1042       }
1043       case 32:{
1044         guint32 *data = (guint32 *) dst;
1045         guint32 zero = (0x80000000 >> (32 - this->ctx.out.depth));
1046
1047         if (this->ctx.out.endianness == G_LITTLE_ENDIAN)
1048           zero = GUINT32_TO_LE (zero);
1049         else
1050           zero = GUINT32_TO_BE (zero);
1051
1052         size /= 4;
1053
1054         for (i = 0; i < size; i++)
1055           data[i] = zero;
1056         break;
1057       }
1058       default:
1059         memset (dst, 0, size);
1060         g_return_if_reached ();
1061         break;
1062     }
1063   } else {
1064     memset (dst, 0, size);
1065   }
1066 }
1067
1068 static GstFlowReturn
1069 gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
1070     GstBuffer * outbuf)
1071 {
1072   GstAudioConvert *this = GST_AUDIO_CONVERT (base);
1073   gint insize, outsize;
1074   gint samples;
1075   gpointer src, dst;
1076
1077   GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, base, "converting audio from %"
1078       GST_PTR_FORMAT " to %" GST_PTR_FORMAT, GST_BUFFER_CAPS (inbuf),
1079       GST_BUFFER_CAPS (outbuf));
1080
1081   /* get amount of samples to convert. */
1082   samples = GST_BUFFER_SIZE (inbuf) / this->ctx.in.unit_size;
1083
1084   /* get in/output sizes, to see if the buffers we got are of correct
1085    * sizes */
1086   if (!audio_convert_get_sizes (&this->ctx, samples, &insize, &outsize))
1087     goto error;
1088
1089   if (insize == 0 || outsize == 0)
1090     return GST_FLOW_OK;
1091
1092   /* check in and outsize */
1093   if (GST_BUFFER_SIZE (inbuf) < insize)
1094     goto wrong_size;
1095   if (GST_BUFFER_SIZE (outbuf) < outsize)
1096     goto wrong_size;
1097
1098   /* get src and dst data */
1099   src = GST_BUFFER_DATA (inbuf);
1100   dst = GST_BUFFER_DATA (outbuf);
1101
1102   /* and convert the samples */
1103   if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
1104     if (!audio_convert_convert (&this->ctx, src, dst,
1105             samples, gst_buffer_is_writable (inbuf)))
1106       goto convert_error;
1107   } else {
1108     /* Create silence buffer */
1109     gst_audio_convert_create_silence_buffer (this, dst, outsize);
1110   }
1111
1112   GST_BUFFER_SIZE (outbuf) = outsize;
1113
1114   return GST_FLOW_OK;
1115
1116   /* ERRORS */
1117 error:
1118   {
1119     GST_ELEMENT_ERROR (this, STREAM, FORMAT,
1120         (NULL), ("cannot get input/output sizes for %d samples", samples));
1121     return GST_FLOW_ERROR;
1122   }
1123 wrong_size:
1124   {
1125     GST_ELEMENT_ERROR (this, STREAM, FORMAT,
1126         (NULL),
1127         ("input/output buffers are of wrong size in: %d < %d or out: %d < %d",
1128             GST_BUFFER_SIZE (inbuf), insize, GST_BUFFER_SIZE (outbuf),
1129             outsize));
1130     return GST_FLOW_ERROR;
1131   }
1132 convert_error:
1133   {
1134     GST_ELEMENT_ERROR (this, STREAM, FORMAT,
1135         (NULL), ("error while converting"));
1136     return GST_FLOW_ERROR;
1137   }
1138 }
1139
1140 static void
1141 gst_audio_convert_set_property (GObject * object, guint prop_id,
1142     const GValue * value, GParamSpec * pspec)
1143 {
1144   GstAudioConvert *this = GST_AUDIO_CONVERT (object);
1145
1146   switch (prop_id) {
1147     case ARG_DITHERING:
1148       this->dither = g_value_get_enum (value);
1149       break;
1150     case ARG_NOISE_SHAPING:
1151       this->ns = g_value_get_enum (value);
1152       break;
1153     default:
1154       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1155       break;
1156   }
1157 }
1158
1159 static void
1160 gst_audio_convert_get_property (GObject * object, guint prop_id,
1161     GValue * value, GParamSpec * pspec)
1162 {
1163   GstAudioConvert *this = GST_AUDIO_CONVERT (object);
1164
1165   switch (prop_id) {
1166     case ARG_DITHERING:
1167       g_value_set_enum (value, this->dither);
1168       break;
1169     case ARG_NOISE_SHAPING:
1170       g_value_set_enum (value, this->ns);
1171       break;
1172     default:
1173       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1174       break;
1175   }
1176 }