expand tabs
[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) 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  * <refsect2>
28  * Audioconvert converts raw audio buffers between various possible formats.
29  * It supports integer to float conversion, width/depth conversion,
30  * signedness and endianness conversion.
31  * <title>Example launch line</title>
32  * <para>
33  * <programlisting>
34  * gst-launch -v -m audiotestsrc ! audioconvert ! audio/x-raw-int,channels=2,width=8,depth=8 ! level ! fakesink silent=TRUE
35  * </programlisting>
36  * This pipeline converts audio to 8-bit.  The level element shows that
37  * the output levels still match the one for a sine wave.
38  * </para>
39  * <para>
40  * <programlisting>
41  * gst-launch -v -m audiotestsrc ! audioconvert ! vorbisenc ! fakesink silent=TRUE
42  * </programlisting>
43  * The vorbis encoder takes float audio data instead of the integer data
44  * generated by audiotestsrc.
45  * </para>
46  * </refsect2>
47  */
48
49 /*
50  * design decisions:
51  * - audioconvert converts buffers in a set of supported caps. If it supports
52  *   a caps, it supports conversion from these caps to any other caps it
53  *   supports. (example: if it does A=>B and A=>C, it also does B=>C)
54  * - audioconvert does not save state between buffers. Every incoming buffer is
55  *   converted and the converted buffer is pushed out.
56  * conclusion:
57  * audioconvert is not supposed to be a one-element-does-anything solution for
58  * audio conversions.
59  */
60
61 #ifdef HAVE_CONFIG_H
62 #include "config.h"
63 #endif
64
65 #include <string.h>
66
67 #include "gstaudioconvert.h"
68 #include "gstchannelmix.h"
69 #include "plugin.h"
70
71 GST_DEBUG_CATEGORY (audio_convert_debug);
72
73 /*** DEFINITIONS **************************************************************/
74
75 static GstElementDetails audio_convert_details = {
76   "Audio Conversion",
77   "Filter/Converter/Audio",
78   "Convert audio to different formats",
79   "Benjamin Otte <in7y118@public.uni-hamburg.de>",
80 };
81
82 /* type functions */
83 static void gst_audio_convert_dispose (GObject * obj);
84
85 /* gstreamer functions */
86 static gboolean gst_audio_convert_get_unit_size (GstBaseTransform * base,
87     GstCaps * caps, guint * size);
88 static GstCaps *gst_audio_convert_transform_caps (GstBaseTransform * base,
89     GstPadDirection direction, GstCaps * caps);
90 static void gst_audio_convert_fixate_caps (GstBaseTransform * base,
91     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
92 static gboolean gst_audio_convert_set_caps (GstBaseTransform * base,
93     GstCaps * incaps, GstCaps * outcaps);
94 static GstFlowReturn gst_audio_convert_transform (GstBaseTransform * base,
95     GstBuffer * inbuf, GstBuffer * outbuf);
96 static GstFlowReturn gst_audio_convert_transform_ip (GstBaseTransform * base,
97     GstBuffer * buf);
98
99 /* AudioConvert signals and args */
100 enum
101 {
102   /* FILL ME */
103   LAST_SIGNAL
104 };
105
106 enum
107 {
108   ARG_0,
109   ARG_AGGRESSIVE
110 };
111
112 #define DEBUG_INIT(bla) \
113   GST_DEBUG_CATEGORY_INIT (audio_convert_debug, "audioconvert", 0, "audio conversion element");
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, 8 ], " \
125     "endianness = (int) BYTE_ORDER, " \
126     "width = (int) 32;" \
127   "audio/x-raw-int, " \
128     "rate = (int) [ 1, MAX ], " \
129     "channels = (int) [ 1, 8 ], " \
130     "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
131     "width = (int) 32, " \
132     "depth = (int) [ 1, 32 ], " \
133     "signed = (boolean) { true, false }; " \
134   "audio/x-raw-int, "   \
135     "rate = (int) [ 1, MAX ], " \
136     "channels = (int) [ 1, 8 ], "       \
137     "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "        \
138     "width = (int) 24, "        \
139     "depth = (int) [ 1, 24 ], " "signed = (boolean) { true, false }; "  \
140   "audio/x-raw-int, " \
141     "rate = (int) [ 1, MAX ], " \
142     "channels = (int) [ 1, 8 ], " \
143     "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
144     "width = (int) 16, " \
145     "depth = (int) [ 1, 16 ], " \
146     "signed = (boolean) { true, false }; " \
147   "audio/x-raw-int, " \
148     "rate = (int) [ 1, MAX ], " \
149     "channels = (int) [ 1, 8 ], " \
150     "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
151     "width = (int) 8, " \
152     "depth = (int) [ 1, 8 ], " \
153     "signed = (boolean) { true, false } " \
154 )
155
156 static GstAudioChannelPosition *supported_positions;
157
158 static GstStaticCaps gst_audio_convert_static_caps = STATIC_CAPS;
159
160 static GstStaticPadTemplate gst_audio_convert_src_template =
161 GST_STATIC_PAD_TEMPLATE ("src",
162     GST_PAD_SRC,
163     GST_PAD_ALWAYS,
164     STATIC_CAPS);
165
166 static GstStaticPadTemplate gst_audio_convert_sink_template =
167 GST_STATIC_PAD_TEMPLATE ("sink",
168     GST_PAD_SINK,
169     GST_PAD_ALWAYS,
170     STATIC_CAPS);
171
172 /*** TYPE FUNCTIONS ***********************************************************/
173
174 static void
175 gst_audio_convert_base_init (gpointer g_class)
176 {
177   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
178
179   gst_element_class_add_pad_template (element_class,
180       gst_static_pad_template_get (&gst_audio_convert_src_template));
181   gst_element_class_add_pad_template (element_class,
182       gst_static_pad_template_get (&gst_audio_convert_sink_template));
183   gst_element_class_set_details (element_class, &audio_convert_details);
184 }
185
186 static void
187 gst_audio_convert_class_init (GstAudioConvertClass * klass)
188 {
189   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
190   gint i;
191
192   gobject_class->dispose = gst_audio_convert_dispose;
193
194   supported_positions = g_new0 (GstAudioChannelPosition,
195       GST_AUDIO_CHANNEL_POSITION_NUM);
196   for (i = 0; i < GST_AUDIO_CHANNEL_POSITION_NUM; i++)
197     supported_positions[i] = i;
198
199   GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
200       GST_DEBUG_FUNCPTR (gst_audio_convert_get_unit_size);
201   GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
202       GST_DEBUG_FUNCPTR (gst_audio_convert_transform_caps);
203   GST_BASE_TRANSFORM_CLASS (klass)->fixate_caps =
204       GST_DEBUG_FUNCPTR (gst_audio_convert_fixate_caps);
205   GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
206       GST_DEBUG_FUNCPTR (gst_audio_convert_set_caps);
207   GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
208       GST_DEBUG_FUNCPTR (gst_audio_convert_transform_ip);
209   GST_BASE_TRANSFORM_CLASS (klass)->transform =
210       GST_DEBUG_FUNCPTR (gst_audio_convert_transform);
211
212   GST_BASE_TRANSFORM_CLASS (klass)->passthrough_on_same_caps = TRUE;
213 }
214
215 static void
216 gst_audio_convert_init (GstAudioConvert * this, GstAudioConvertClass * g_class)
217 {
218 }
219
220 static void
221 gst_audio_convert_dispose (GObject * obj)
222 {
223   GstAudioConvert *this = GST_AUDIO_CONVERT (obj);
224
225   audio_convert_clean_context (&this->ctx);
226
227   G_OBJECT_CLASS (parent_class)->dispose (obj);
228 }
229
230 /*** GSTREAMER FUNCTIONS ******************************************************/
231
232 /* convert the given GstCaps to our format */
233 static gboolean
234 gst_audio_convert_parse_caps (const GstCaps * caps, AudioConvertFmt * fmt)
235 {
236   GstStructure *structure = gst_caps_get_structure (caps, 0);
237
238   GST_DEBUG ("parse caps %p and %" GST_PTR_FORMAT, caps, caps);
239
240   g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
241   g_return_val_if_fail (fmt != NULL, FALSE);
242
243   /* cleanup old */
244   audio_convert_clean_fmt (fmt);
245
246   fmt->endianness = G_BYTE_ORDER;
247   fmt->is_int =
248       (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0);
249
250   /* parse common fields */
251   if (!gst_structure_get_int (structure, "channels", &fmt->channels))
252     goto no_values;
253   if (!(fmt->pos = gst_audio_get_channel_positions (structure)))
254     goto no_values;
255   if (!gst_structure_get_int (structure, "width", &fmt->width))
256     goto no_values;
257   if (!gst_structure_get_int (structure, "rate", &fmt->rate))
258     goto no_values;
259
260   if (fmt->is_int) {
261     /* int specific fields */
262     if (!gst_structure_get_boolean (structure, "signed", &fmt->sign))
263       goto no_values;
264     if (!gst_structure_get_int (structure, "depth", &fmt->depth))
265       goto no_values;
266
267     /* width != 8 can have an endianness field */
268     if (fmt->width != 8) {
269       if (!gst_structure_get_int (structure, "endianness", &fmt->endianness))
270         goto no_values;
271     }
272     /* depth cannot be bigger than the width */
273     if (fmt->depth > fmt->width)
274       goto not_allowed;
275   }
276
277   fmt->unit_size = (fmt->width * fmt->channels) / 8;
278
279   return TRUE;
280
281   /* ERRORS */
282 no_values:
283   {
284     GST_DEBUG ("could not get some values from structure");
285     audio_convert_clean_fmt (fmt);
286     return FALSE;
287   }
288 not_allowed:
289   {
290     GST_DEBUG ("width > depth, not allowed - make us advertise correct fmt");
291     audio_convert_clean_fmt (fmt);
292     return FALSE;
293   }
294 }
295
296 /* BaseTransform vmethods */
297 static gboolean
298 gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
299     guint * size)
300 {
301   AudioConvertFmt fmt = { 0 };
302
303   g_return_val_if_fail (size, FALSE);
304
305   if (!gst_audio_convert_parse_caps (caps, &fmt))
306     goto parse_error;
307
308   *size = fmt.unit_size;
309
310   audio_convert_clean_fmt (&fmt);
311
312   return TRUE;
313
314 parse_error:
315   {
316     return FALSE;
317   }
318 }
319
320 /* audioconvert can convert anything except sample rate; so return template
321  * caps with rate fixed */
322 /* FIXME:
323  * it would be smart here to return the caps with the same width as the first
324  */
325 static GstCaps *
326 gst_audio_convert_transform_caps (GstBaseTransform * base,
327     GstPadDirection direction, GstCaps * caps)
328 {
329   int i;
330   const GValue *rate;
331   GstCaps *ret;
332   GstStructure *structure;
333
334   g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL);
335
336   structure = gst_caps_get_structure (caps, 0);
337
338   ret = gst_static_caps_get (&gst_audio_convert_static_caps);
339
340   /* if rate not set, we return the template */
341   if (!(rate = gst_structure_get_value (structure, "rate")))
342     return ret;
343
344   /* else, write rate in the template caps */
345   ret = gst_caps_make_writable (ret);
346
347   for (i = 0; i < gst_caps_get_size (ret); ++i) {
348     structure = gst_caps_get_structure (ret, i);
349     gst_structure_set_value (structure, "rate", rate);
350   }
351   return ret;
352 }
353
354 /* try to keep as many of the structure members the same by fixating the
355  * possible ranges; this way we convert the least amount of things as possible
356  */
357 static void
358 gst_audio_convert_fixate_caps (GstBaseTransform * base,
359     GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
360 {
361   GstStructure *ins, *outs;
362   gint rate, endianness, depth, width, channels;
363   gboolean signedness;
364
365   g_return_if_fail (gst_caps_is_fixed (caps));
366
367   GST_DEBUG_OBJECT (base, "trying to fixate othercaps %" GST_PTR_FORMAT
368       " based on caps %" GST_PTR_FORMAT, othercaps, caps);
369
370   ins = gst_caps_get_structure (caps, 0);
371   outs = gst_caps_get_structure (othercaps, 0);
372
373   if (gst_structure_get_int (ins, "channels", &channels)) {
374     if (gst_structure_has_field (outs, "channels")) {
375       gst_structure_fixate_field_nearest_int (outs, "channels", channels);
376     }
377   }
378   if (gst_structure_get_int (ins, "rate", &rate)) {
379     if (gst_structure_has_field (outs, "rate")) {
380       gst_structure_fixate_field_nearest_int (outs, "rate", rate);
381     }
382   }
383   if (gst_structure_get_int (ins, "endianness", &endianness)) {
384     if (gst_structure_has_field (outs, "endianness")) {
385       gst_structure_fixate_field_nearest_int (outs, "endianness", endianness);
386     }
387   }
388   if (gst_structure_get_int (ins, "width", &width)) {
389     if (gst_structure_has_field (outs, "width")) {
390       gst_structure_fixate_field_nearest_int (outs, "width", width);
391     }
392   } else {
393     /* this is not allowed */
394   }
395
396   if (gst_structure_get_int (ins, "depth", &depth)) {
397     if (gst_structure_has_field (outs, "depth")) {
398       gst_structure_fixate_field_nearest_int (outs, "depth", depth);
399     }
400   } else {
401     /* set depth as width */
402     if (gst_structure_has_field (outs, "depth")) {
403       gst_structure_fixate_field_nearest_int (outs, "depth", width);
404     }
405   }
406
407   if (gst_structure_get_boolean (ins, "signed", &signedness)) {
408     if (gst_structure_has_field (outs, "signed")) {
409       gst_structure_fixate_field_boolean (outs, "signed", signedness);
410     }
411   }
412
413   GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
414 }
415
416 static gboolean
417 gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
418     GstCaps * outcaps)
419 {
420   AudioConvertFmt in_ac_caps = { 0 };
421   AudioConvertFmt out_ac_caps = { 0 };
422   GstAudioConvert *this = GST_AUDIO_CONVERT (base);
423
424   GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
425       GST_PTR_FORMAT, incaps, outcaps);
426
427   if (!gst_audio_convert_parse_caps (incaps, &in_ac_caps))
428     return FALSE;
429   if (!gst_audio_convert_parse_caps (outcaps, &out_ac_caps))
430     return FALSE;
431
432   if (!audio_convert_prepare_context (&this->ctx, &in_ac_caps, &out_ac_caps))
433     goto no_converter;
434
435   return TRUE;
436
437 no_converter:
438   {
439     return FALSE;
440   }
441 }
442
443 static GstFlowReturn
444 gst_audio_convert_transform_ip (GstBaseTransform * base, GstBuffer * buf)
445 {
446   /* nothing to do here */
447   return GST_FLOW_OK;
448 }
449
450 static GstFlowReturn
451 gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
452     GstBuffer * outbuf)
453 {
454   GstAudioConvert *this = GST_AUDIO_CONVERT (base);
455   gboolean res;
456   gint insize, outsize;
457   gint samples;
458   gpointer src, dst;
459
460   /* get amount of samples to convert. */
461   samples = GST_BUFFER_SIZE (inbuf) / this->ctx.in.unit_size;
462
463   /* get in/output sizes, to see if the buffers we got are of correct
464    * sizes */
465   if (!(res = audio_convert_get_sizes (&this->ctx, samples, &insize, &outsize)))
466     goto error;
467
468   /* check in and outsize */
469   if (GST_BUFFER_SIZE (inbuf) < insize)
470     goto wrong_size;
471   if (GST_BUFFER_SIZE (outbuf) < outsize)
472     goto wrong_size;
473
474   /* get src and dst data */
475   src = GST_BUFFER_DATA (inbuf);
476   dst = GST_BUFFER_DATA (outbuf);
477
478   /* and convert the samples */
479   if (!(res = audio_convert_convert (&this->ctx, src, dst,
480               samples, gst_buffer_is_writable (inbuf))))
481     goto convert_error;
482
483   GST_BUFFER_SIZE (outbuf) = outsize;
484
485   return GST_FLOW_OK;
486
487   /* ERRORS */
488 error:
489   {
490     GST_ELEMENT_ERROR (this, STREAM, NOT_IMPLEMENTED,
491         ("cannot get input/output sizes for %d samples", samples),
492         ("cannot get input/output sizes for %d samples", samples));
493     return GST_FLOW_ERROR;
494   }
495 wrong_size:
496   {
497     GST_ELEMENT_ERROR (this, STREAM, NOT_IMPLEMENTED,
498         ("input/output buffers are of wrong size in: %d < %d or out: %d < %d",
499             GST_BUFFER_SIZE (inbuf), insize, GST_BUFFER_SIZE (outbuf), outsize),
500         ("input/output buffers are of wrong size in: %d < %d or out: %d < %d",
501             GST_BUFFER_SIZE (inbuf), insize, GST_BUFFER_SIZE (outbuf),
502             outsize));
503     return GST_FLOW_ERROR;
504   }
505 convert_error:
506   {
507     GST_ELEMENT_ERROR (this, STREAM, NOT_IMPLEMENTED,
508         ("error while converting"), ("error while converting"));
509     return GST_FLOW_ERROR;
510   }
511 }