audioconvert: plug caps leak
[platform/upstream/gstreamer.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) 2011 Wim Taymans <wim.taymans at gmail 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,format=S8,channels=2 ! 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, gsize * size);
80 static GstCaps *gst_audio_convert_transform_caps (GstBaseTransform * base,
81     GstPadDirection direction, GstCaps * caps, GstCaps * filter);
82 static GstCaps *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
95 /* AudioConvert signals and args */
96 enum
97 {
98   /* FILL ME */
99   LAST_SIGNAL
100 };
101
102 enum
103 {
104   ARG_0,
105   ARG_DITHERING,
106   ARG_NOISE_SHAPING,
107 };
108
109 #define DEBUG_INIT \
110   GST_DEBUG_CATEGORY_INIT (audio_convert_debug, "audioconvert", 0, "audio conversion element"); \
111   GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
112 #define gst_audio_convert_parent_class parent_class
113 G_DEFINE_TYPE_WITH_CODE (GstAudioConvert, gst_audio_convert,
114     GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
115
116 /*** GSTREAMER PROTOTYPES *****************************************************/
117
118 #define STATIC_CAPS \
119 GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_FORMATS_ALL) \
120     ", layout = (string) interleaved")
121
122 static GstStaticPadTemplate gst_audio_convert_src_template =
123 GST_STATIC_PAD_TEMPLATE ("src",
124     GST_PAD_SRC,
125     GST_PAD_ALWAYS,
126     STATIC_CAPS);
127
128 static GstStaticPadTemplate gst_audio_convert_sink_template =
129 GST_STATIC_PAD_TEMPLATE ("sink",
130     GST_PAD_SINK,
131     GST_PAD_ALWAYS,
132     STATIC_CAPS);
133
134 #define GST_TYPE_AUDIO_CONVERT_DITHERING (gst_audio_convert_dithering_get_type ())
135 static GType
136 gst_audio_convert_dithering_get_type (void)
137 {
138   static GType gtype = 0;
139
140   if (gtype == 0) {
141     static const GEnumValue values[] = {
142       {DITHER_NONE, "No dithering",
143           "none"},
144       {DITHER_RPDF, "Rectangular dithering", "rpdf"},
145       {DITHER_TPDF, "Triangular dithering (default)", "tpdf"},
146       {DITHER_TPDF_HF, "High frequency triangular dithering", "tpdf-hf"},
147       {0, NULL, NULL}
148     };
149
150     gtype = g_enum_register_static ("GstAudioConvertDithering", values);
151   }
152   return gtype;
153 }
154
155 #define GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING (gst_audio_convert_ns_get_type ())
156 static GType
157 gst_audio_convert_ns_get_type (void)
158 {
159   static GType gtype = 0;
160
161   if (gtype == 0) {
162     static const GEnumValue values[] = {
163       {NOISE_SHAPING_NONE, "No noise shaping (default)",
164           "none"},
165       {NOISE_SHAPING_ERROR_FEEDBACK, "Error feedback", "error-feedback"},
166       {NOISE_SHAPING_SIMPLE, "Simple 2-pole noise shaping", "simple"},
167       {NOISE_SHAPING_MEDIUM, "Medium 5-pole noise shaping", "medium"},
168       {NOISE_SHAPING_HIGH, "High 8-pole noise shaping", "high"},
169       {0, NULL, NULL}
170     };
171
172     gtype = g_enum_register_static ("GstAudioConvertNoiseShaping", values);
173   }
174   return gtype;
175 }
176
177
178 /*** TYPE FUNCTIONS ***********************************************************/
179 static void
180 gst_audio_convert_class_init (GstAudioConvertClass * klass)
181 {
182   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
183   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
184   GstBaseTransformClass *basetransform_class = GST_BASE_TRANSFORM_CLASS (klass);
185
186   gobject_class->dispose = gst_audio_convert_dispose;
187   gobject_class->set_property = gst_audio_convert_set_property;
188   gobject_class->get_property = gst_audio_convert_get_property;
189
190   g_object_class_install_property (gobject_class, ARG_DITHERING,
191       g_param_spec_enum ("dithering", "Dithering",
192           "Selects between different dithering methods.",
193           GST_TYPE_AUDIO_CONVERT_DITHERING, DITHER_TPDF,
194           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
195
196   g_object_class_install_property (gobject_class, ARG_NOISE_SHAPING,
197       g_param_spec_enum ("noise-shaping", "Noise shaping",
198           "Selects between different noise shaping methods.",
199           GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING, NOISE_SHAPING_NONE,
200           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
201
202   gst_element_class_add_pad_template (element_class,
203       gst_static_pad_template_get (&gst_audio_convert_src_template));
204   gst_element_class_add_pad_template (element_class,
205       gst_static_pad_template_get (&gst_audio_convert_sink_template));
206   gst_element_class_set_details_simple (element_class,
207       "Audio converter", "Filter/Converter/Audio",
208       "Convert audio to different formats", "Benjamin Otte <otte@gnome.org>");
209
210   basetransform_class->get_unit_size =
211       GST_DEBUG_FUNCPTR (gst_audio_convert_get_unit_size);
212   basetransform_class->transform_caps =
213       GST_DEBUG_FUNCPTR (gst_audio_convert_transform_caps);
214   basetransform_class->fixate_caps =
215       GST_DEBUG_FUNCPTR (gst_audio_convert_fixate_caps);
216   basetransform_class->set_caps =
217       GST_DEBUG_FUNCPTR (gst_audio_convert_set_caps);
218   basetransform_class->transform_ip =
219       GST_DEBUG_FUNCPTR (gst_audio_convert_transform_ip);
220   basetransform_class->transform =
221       GST_DEBUG_FUNCPTR (gst_audio_convert_transform);
222
223   basetransform_class->passthrough_on_same_caps = TRUE;
224 }
225
226 static void
227 gst_audio_convert_init (GstAudioConvert * this)
228 {
229   this->dither = DITHER_TPDF;
230   this->ns = NOISE_SHAPING_NONE;
231   memset (&this->ctx, 0, sizeof (AudioConvertCtx));
232
233   gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (this), TRUE);
234 }
235
236 static void
237 gst_audio_convert_dispose (GObject * obj)
238 {
239   GstAudioConvert *this = GST_AUDIO_CONVERT (obj);
240
241   audio_convert_clean_context (&this->ctx);
242
243   G_OBJECT_CLASS (parent_class)->dispose (obj);
244 }
245
246 /*** GSTREAMER FUNCTIONS ******************************************************/
247
248 /* BaseTransform vmethods */
249 static gboolean
250 gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
251     gsize * size)
252 {
253   GstAudioInfo info;
254
255   g_assert (size);
256
257   if (!gst_audio_info_from_caps (&info, caps))
258     goto parse_error;
259
260   *size = info.bpf;
261   GST_INFO_OBJECT (base, "unit_size = %" G_GSIZE_FORMAT, *size);
262
263   return TRUE;
264
265 parse_error:
266   {
267     GST_INFO_OBJECT (base, "failed to parse caps to get unit_size");
268     return FALSE;
269   }
270 }
271
272 /* copies the given caps */
273 static GstCaps *
274 gst_audio_convert_caps_remove_format_info (GstCaps * caps)
275 {
276   GstStructure *st;
277   gint i, n;
278   GstCaps *res;
279   guint64 channel_mask;
280
281   res = gst_caps_new_empty ();
282
283   n = gst_caps_get_size (caps);
284   for (i = 0; i < n; i++) {
285     st = gst_caps_get_structure (caps, i);
286
287     /* If this is already expressed by the existing caps
288      * skip this structure */
289     if (i > 0 && gst_caps_is_subset_structure (res, st))
290       continue;
291
292     st = gst_structure_copy (st);
293     gst_structure_remove_field (st, "format");
294
295     /* Only remove the channels and channel-mask for non-NONE layouts */
296     if (gst_structure_get (st, "channel-mask", GST_TYPE_BITMASK, &channel_mask,
297             NULL)) {
298       if (channel_mask != 0)
299         gst_structure_remove_fields (st, "channel-mask", "channels", NULL);
300     } else {
301       gst_structure_remove_fields (st, "channel-mask", "channels", NULL);
302     }
303
304     gst_caps_append_structure (res, st);
305   }
306
307   return res;
308 }
309
310 /* The caps can be transformed into any other caps with format info removed.
311  * However, we should prefer passthrough, so if passthrough is possible,
312  * put it first in the list. */
313 static GstCaps *
314 gst_audio_convert_transform_caps (GstBaseTransform * btrans,
315     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
316 {
317   GstCaps *tmp, *tmp2;
318   GstCaps *result;
319
320   /* Get all possible caps that we can transform to */
321   tmp = gst_audio_convert_caps_remove_format_info (caps);
322
323   if (filter) {
324     tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
325     gst_caps_unref (tmp);
326     tmp = tmp2;
327   }
328
329   result = tmp;
330
331   GST_DEBUG_OBJECT (btrans, "transformed %" GST_PTR_FORMAT " into %"
332       GST_PTR_FORMAT, caps, result);
333
334   return result;
335 }
336
337 static const GstAudioChannelPosition default_positions[8][8] = {
338   /* 1 channel */
339   {
340         GST_AUDIO_CHANNEL_POSITION_MONO,
341       },
342   /* 2 channels */
343   {
344         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
345         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
346       },
347   /* 3 channels (2.1) */
348   {
349         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
350         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
351         GST_AUDIO_CHANNEL_POSITION_LFE1,
352       },
353   /* 4 channels (4.0) */
354   {
355         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
356         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
357         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
358         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
359       },
360   /* 5 channels */
361   {
362         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
363         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
364         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
365         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
366         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
367       },
368   /* 6 channels (5.1) */
369   {
370         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
371         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
372         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
373         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
374         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
375         GST_AUDIO_CHANNEL_POSITION_LFE1,
376       },
377   /* 7 channels (6.1) */
378   {
379         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
380         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
381         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
382         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
383         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
384         GST_AUDIO_CHANNEL_POSITION_LFE1,
385         GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
386       },
387   /* 8 channels (7.1) */
388   {
389         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
390         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
391         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
392         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
393         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
394         GST_AUDIO_CHANNEL_POSITION_LFE1,
395         GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
396         GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
397       }
398 };
399
400 static gint
401 n_bits_set (guint64 x)
402 {
403   gint i;
404   gint c = 0;
405   guint64 y = 1;
406
407   for (i = 0; i < 64; i++) {
408     if (x & y)
409       c++;
410     y <<= 1;
411   }
412
413   return c;
414 }
415
416 static guint64
417 find_suitable_mask (guint64 mask, gint n_chans)
418 {
419   guint64 intersection;
420   gint i;
421
422   i = 0;
423
424   g_assert (n_bits_set (mask) >= n_chans);
425
426   intersection = mask;
427   do {
428     intersection = intersection & ((~G_GUINT64_CONSTANT (0)) >> i);
429     i++;
430   } while (n_bits_set (intersection) > n_chans && i < 64);
431
432   if (i < 64)
433     return intersection;
434   return 0;
435 }
436
437 static void
438 gst_audio_convert_fixate_channels (GstBaseTransform * base, GstStructure * ins,
439     GstStructure * outs)
440 {
441   gint in_chans, out_chans;
442   guint64 in_mask = 0, out_mask = 0;
443   gboolean has_in_mask = FALSE, has_out_mask = FALSE;
444
445   if (!gst_structure_get_int (ins, "channels", &in_chans))
446     return;                     /* this shouldn't really happen, should it? */
447
448   if (!gst_structure_has_field (outs, "channels")) {
449     /* we could try to get the implied number of channels from the layout,
450      * but that seems overdoing it for a somewhat exotic corner case */
451     gst_structure_remove_field (outs, "channel-mask");
452     return;
453   }
454
455   /* ok, let's fixate the channels if they are not fixated yet */
456   gst_structure_fixate_field_nearest_int (outs, "channels", in_chans);
457
458   if (!gst_structure_get_int (outs, "channels", &out_chans)) {
459     /* shouldn't really happen ... */
460     gst_structure_remove_field (outs, "channel-mask");
461     return;
462   }
463
464   /* get the channel layout of the output if any */
465   has_out_mask = gst_structure_has_field (outs, "channel-mask");
466   if (has_out_mask) {
467     gst_structure_get (outs, "channel-mask", GST_TYPE_BITMASK, &out_mask, NULL);
468   } else {
469     /* channels == 1 => MONO */
470     if (out_chans == 2) {
471       out_mask =
472           GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
473           GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT);
474       has_out_mask = TRUE;
475       gst_structure_set (outs, "channel-mask", GST_TYPE_BITMASK, out_mask,
476           NULL);
477     }
478   }
479
480   /* get the channel layout of the input if any */
481   has_in_mask = gst_structure_has_field (ins, "channel-mask");
482   if (has_in_mask) {
483     gst_structure_get (ins, "channel-mask", GST_TYPE_BITMASK, &in_mask, NULL);
484   } else {
485     /* channels == 1 => MONO */
486     if (in_chans == 2) {
487       in_mask =
488           GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
489           GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT);
490       has_in_mask = TRUE;
491     } else if (in_chans > 2)
492       g_warning ("%s: Upstream caps contain no channel mask",
493           GST_ELEMENT_NAME (base));
494   }
495
496   if (!has_out_mask && out_chans == 1 && (in_chans != out_chans
497           || !has_in_mask))
498     return;                     /* nothing to do, default layout will be assumed */
499
500   if (in_chans == out_chans && (has_in_mask || in_chans == 1)) {
501     /* same number of channels and no output layout: just use input layout */
502     if (!has_out_mask) {
503       /* in_chans == 1 handled above already */
504       gst_structure_set (outs, "channel-mask", GST_TYPE_BITMASK, in_mask, NULL);
505       return;
506     }
507
508     /* If both masks are the same we're done, this includes the NONE layout case */
509     if (in_mask == out_mask)
510       return;
511
512     /* if output layout is fixed already and looks sane, we're done */
513     if (n_bits_set (out_mask) == out_chans)
514       return;
515
516     if (n_bits_set (out_mask) < in_chans) {
517       /* Not much we can do here, this shouldn't just happen */
518       g_warning ("%s: Invalid downstream channel-mask with too few bits set",
519           GST_ELEMENT_NAME (base));
520     } else {
521       guint64 intersection;
522
523       /* if the output layout is not fixed, check if the output layout contains
524        * the input layout */
525       intersection = in_mask & out_mask;
526       if (n_bits_set (intersection) >= in_chans) {
527         gst_structure_set (outs, "channel-mask", GST_TYPE_BITMASK, in_mask,
528             NULL);
529         return;
530       }
531
532       /* output layout is not fixed and does not contain the input layout, so
533        * just pick the first possibility */
534       intersection = find_suitable_mask (out_mask, out_chans);
535       if (intersection) {
536         gst_structure_set (outs, "channel-mask", GST_TYPE_BITMASK, intersection,
537             NULL);
538         return;
539       }
540     }
541
542     /* ... else fall back to default layout (NB: out_layout is NULL here) */
543     GST_WARNING_OBJECT (base, "unexpected output channel layout");
544   } else {
545     guint64 intersection;
546
547     /* number of input channels != number of output channels:
548      * if this value contains a list of channel layouts (or even worse: a list
549      * with another list), just pick the first value and repeat until we find a
550      * channel position array or something else that's not a list; we assume
551      * the input if half-way sane and don't try to fall back on other list items
552      * if the first one is something unexpected or non-channel-pos-array-y */
553     if (n_bits_set (out_mask) >= out_chans) {
554       intersection = find_suitable_mask (out_mask, out_chans);
555       gst_structure_set (outs, "channel-mask", GST_TYPE_BITMASK, intersection,
556           NULL);
557       return;
558     }
559
560     /* what now?! Just ignore what we're given and use default positions */
561     GST_WARNING_OBJECT (base, "invalid or unexpected channel-positions");
562   }
563
564   /* missing or invalid output layout and we can't use the input layout for
565    * one reason or another, so just pick a default layout (we could be smarter
566    * and try to add/remove channels from the input layout, or pick a default
567    * layout based on LFE-presence in input layout, but let's save that for
568    * another day) */
569   if (out_chans > 0 && out_chans <= G_N_ELEMENTS (default_positions[0])) {
570     gint i;
571
572     GST_DEBUG_OBJECT (base, "using default channel layout as fallback");
573
574     out_mask = 0;
575     for (i = 0; i < out_chans; i++)
576       out_mask |= G_GUINT64_CONSTANT (1) << default_positions[out_chans - 1][i];
577
578     gst_structure_set (outs, "channel-mask", GST_TYPE_BITMASK, out_mask, NULL);
579   } else {
580     GST_ERROR_OBJECT (base, "Have no default layout for %d channels",
581         out_chans);
582   }
583 }
584
585 /* try to keep as many of the structure members the same by fixating the
586  * possible ranges; this way we convert the least amount of things as possible
587  */
588 static GstCaps *
589 gst_audio_convert_fixate_caps (GstBaseTransform * base,
590     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
591 {
592   GstStructure *ins, *outs;
593   GstCaps *result;
594
595   GST_DEBUG_OBJECT (base, "trying to fixate othercaps %" GST_PTR_FORMAT
596       " based on caps %" GST_PTR_FORMAT, othercaps, caps);
597
598   result = gst_caps_intersect (othercaps, caps);
599   if (gst_caps_is_empty (result)) {
600     if (result)
601       gst_caps_unref (result);
602     result = othercaps;
603   } else {
604     gst_caps_unref (othercaps);
605   }
606
607   /* fixate remaining fields */
608   result = gst_caps_make_writable (result);
609
610   ins = gst_caps_get_structure (caps, 0);
611   outs = gst_caps_get_structure (result, 0);
612
613   gst_audio_convert_fixate_channels (base, ins, outs);
614   result = gst_caps_fixate (result);
615
616   GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, result);
617
618   return result;
619 }
620
621 static gboolean
622 gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
623     GstCaps * outcaps)
624 {
625   GstAudioConvert *this = GST_AUDIO_CONVERT (base);
626   GstAudioInfo in_info;
627   GstAudioInfo out_info;
628
629   GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
630       GST_PTR_FORMAT, incaps, outcaps);
631
632   if (!gst_audio_info_from_caps (&in_info, incaps))
633     goto invalid_in;
634   if (!gst_audio_info_from_caps (&out_info, outcaps))
635     goto invalid_out;
636
637   if (!audio_convert_prepare_context (&this->ctx, &in_info, &out_info,
638           this->dither, this->ns))
639     goto no_converter;
640
641   return TRUE;
642
643   /* ERRORS */
644 invalid_in:
645   {
646     GST_ERROR_OBJECT (base, "invalid input caps");
647     return FALSE;
648   }
649 invalid_out:
650   {
651     GST_ERROR_OBJECT (base, "invalid output caps");
652     return FALSE;
653   }
654 no_converter:
655   {
656     GST_ERROR_OBJECT (base, "could not find converter");
657     return FALSE;
658   }
659 }
660
661 static GstFlowReturn
662 gst_audio_convert_transform_ip (GstBaseTransform * base, GstBuffer * buf)
663 {
664   /* nothing to do here */
665   return GST_FLOW_OK;
666 }
667
668 static GstFlowReturn
669 gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
670     GstBuffer * outbuf)
671 {
672   GstFlowReturn ret;
673   GstAudioConvert *this = GST_AUDIO_CONVERT (base);
674   GstMapInfo srcmap, dstmap;
675   gint insize, outsize;
676
677   gint samples;
678
679   /* get amount of samples to convert. */
680   samples = gst_buffer_get_size (inbuf) / this->ctx.in.bpf;
681
682   /* get in/output sizes, to see if the buffers we got are of correct
683    * sizes */
684   if (!audio_convert_get_sizes (&this->ctx, samples, &insize, &outsize))
685     goto error;
686
687   if (insize == 0 || outsize == 0)
688     return GST_FLOW_OK;
689
690   /* get src and dst data */
691   gst_buffer_map (inbuf, &srcmap, GST_MAP_READ);
692   gst_buffer_map (outbuf, &dstmap, GST_MAP_WRITE);
693
694   /* check in and outsize */
695   if (srcmap.size < insize)
696     goto wrong_size;
697   if (dstmap.size < outsize)
698     goto wrong_size;
699
700   /* and convert the samples */
701   if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
702     if (!audio_convert_convert (&this->ctx, srcmap.data, dstmap.data,
703             samples, gst_buffer_is_writable (inbuf)))
704       goto convert_error;
705   } else {
706     /* Create silence buffer */
707     gst_audio_format_fill_silence (this->ctx.out.finfo, dstmap.data, outsize);
708   }
709   ret = GST_FLOW_OK;
710
711 done:
712   gst_buffer_unmap (outbuf, &dstmap);
713   gst_buffer_unmap (inbuf, &srcmap);
714
715   return ret;
716
717   /* ERRORS */
718 error:
719   {
720     GST_ELEMENT_ERROR (this, STREAM, FORMAT,
721         (NULL), ("cannot get input/output sizes for %d samples", samples));
722     return GST_FLOW_ERROR;
723   }
724 wrong_size:
725   {
726     GST_ELEMENT_ERROR (this, STREAM, FORMAT,
727         (NULL),
728         ("input/output buffers are of wrong size in: %" G_GSIZE_FORMAT " < %d"
729             " or out: %" G_GSIZE_FORMAT " < %d",
730             srcmap.size, insize, dstmap.size, outsize));
731     ret = GST_FLOW_ERROR;
732     goto done;
733   }
734 convert_error:
735   {
736     GST_ELEMENT_ERROR (this, STREAM, FORMAT,
737         (NULL), ("error while converting"));
738     ret = GST_FLOW_ERROR;
739     goto done;
740   }
741 }
742
743 static void
744 gst_audio_convert_set_property (GObject * object, guint prop_id,
745     const GValue * value, GParamSpec * pspec)
746 {
747   GstAudioConvert *this = GST_AUDIO_CONVERT (object);
748
749   switch (prop_id) {
750     case ARG_DITHERING:
751       this->dither = g_value_get_enum (value);
752       break;
753     case ARG_NOISE_SHAPING:
754       this->ns = g_value_get_enum (value);
755       break;
756     default:
757       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
758       break;
759   }
760 }
761
762 static void
763 gst_audio_convert_get_property (GObject * object, guint prop_id,
764     GValue * value, GParamSpec * pspec)
765 {
766   GstAudioConvert *this = GST_AUDIO_CONVERT (object);
767
768   switch (prop_id) {
769     case ARG_DITHERING:
770       g_value_set_enum (value, this->dither);
771       break;
772     case ARG_NOISE_SHAPING:
773       g_value_set_enum (value, this->ns);
774       break;
775     default:
776       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
777       break;
778   }
779 }