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