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>
6 * gstaudioconvert.c: Convert audio to different audio formats automatically
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.
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.
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.
25 * SECTION:element-audioconvert
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>
34 * gst-launch -v -m audiotestsrc ! audioconvert ! audio/x-raw-int,channels=2,width=8,depth=8 ! level ! fakesink silent=TRUE
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.
41 * gst-launch -v -m audiotestsrc ! audioconvert ! vorbisenc ! fakesink silent=TRUE
43 * The vorbis encoder takes float audio data instead of the integer data
44 * generated by audiotestsrc.
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.
57 * audioconvert is not supposed to be a one-element-does-anything solution for
67 #include "gstaudioconvert.h"
68 #include "gstchannelmix.h"
71 GST_DEBUG_CATEGORY (audio_convert_debug);
73 /*** DEFINITIONS **************************************************************/
75 static GstElementDetails audio_convert_details = {
77 "Filter/Converter/Audio",
78 "Convert audio to different formats",
79 "Benjamin Otte <in7y118@public.uni-hamburg.de>",
83 static void gst_audio_convert_dispose (GObject * obj);
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,
99 /* AudioConvert signals and args */
112 #define DEBUG_INIT(bla) \
113 GST_DEBUG_CATEGORY_INIT (audio_convert_debug, "audioconvert", 0, "audio conversion element");
115 GST_BOILERPLATE_FULL (GstAudioConvert, gst_audio_convert, GstBaseTransform,
116 GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
118 /*** GSTREAMER PROTOTYPES *****************************************************/
120 #define 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 } " \
156 static GstAudioChannelPosition *supported_positions;
158 static GstStaticCaps gst_audio_convert_static_caps = STATIC_CAPS;
160 static GstStaticPadTemplate gst_audio_convert_src_template =
161 GST_STATIC_PAD_TEMPLATE ("src",
166 static GstStaticPadTemplate gst_audio_convert_sink_template =
167 GST_STATIC_PAD_TEMPLATE ("sink",
172 /*** TYPE FUNCTIONS ***********************************************************/
175 gst_audio_convert_base_init (gpointer g_class)
177 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
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);
187 gst_audio_convert_class_init (GstAudioConvertClass * klass)
189 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
192 gobject_class->dispose = gst_audio_convert_dispose;
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;
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);
212 GST_BASE_TRANSFORM_CLASS (klass)->passthrough_on_same_caps = TRUE;
216 gst_audio_convert_init (GstAudioConvert * this, GstAudioConvertClass * g_class)
221 gst_audio_convert_dispose (GObject * obj)
223 GstAudioConvert *this = GST_AUDIO_CONVERT (obj);
225 audio_convert_clean_context (&this->ctx);
227 G_OBJECT_CLASS (parent_class)->dispose (obj);
230 /*** GSTREAMER FUNCTIONS ******************************************************/
232 /* convert the given GstCaps to our format */
234 gst_audio_convert_parse_caps (const GstCaps * caps, AudioConvertFmt * fmt)
236 GstStructure *structure = gst_caps_get_structure (caps, 0);
238 GST_DEBUG ("parse caps %p and %" GST_PTR_FORMAT, caps, caps);
240 g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
241 g_return_val_if_fail (fmt != NULL, FALSE);
244 audio_convert_clean_fmt (fmt);
246 fmt->endianness = G_BYTE_ORDER;
248 (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0);
250 /* parse common fields */
251 if (!gst_structure_get_int (structure, "channels", &fmt->channels))
253 if (!(fmt->pos = gst_audio_get_channel_positions (structure)))
255 if (!gst_structure_get_int (structure, "width", &fmt->width))
257 if (!gst_structure_get_int (structure, "rate", &fmt->rate))
261 /* int specific fields */
262 if (!gst_structure_get_boolean (structure, "signed", &fmt->sign))
264 if (!gst_structure_get_int (structure, "depth", &fmt->depth))
267 /* width != 8 can have an endianness field */
268 if (fmt->width != 8) {
269 if (!gst_structure_get_int (structure, "endianness", &fmt->endianness))
272 /* depth cannot be bigger than the width */
273 if (fmt->depth > fmt->width)
277 fmt->unit_size = (fmt->width * fmt->channels) / 8;
284 GST_DEBUG ("could not get some values from structure");
285 audio_convert_clean_fmt (fmt);
290 GST_DEBUG ("width > depth, not allowed - make us advertise correct fmt");
291 audio_convert_clean_fmt (fmt);
296 /* BaseTransform vmethods */
298 gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
301 AudioConvertFmt fmt = { 0 };
303 g_return_val_if_fail (size, FALSE);
305 if (!gst_audio_convert_parse_caps (caps, &fmt))
308 *size = fmt.unit_size;
310 audio_convert_clean_fmt (&fmt);
320 /* audioconvert can convert anything except sample rate; so return template
321 * caps with rate fixed */
323 * it would be smart here to return the caps with the same width as the first
326 gst_audio_convert_transform_caps (GstBaseTransform * base,
327 GstPadDirection direction, GstCaps * caps)
332 GstStructure *structure;
334 g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL);
336 structure = gst_caps_get_structure (caps, 0);
338 ret = gst_static_caps_get (&gst_audio_convert_static_caps);
340 /* if rate not set, we return the template */
341 if (!(rate = gst_structure_get_value (structure, "rate")))
344 /* else, write rate in the template caps */
345 ret = gst_caps_make_writable (ret);
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);
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
358 gst_audio_convert_fixate_caps (GstBaseTransform * base,
359 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
361 GstStructure *ins, *outs;
362 gint rate, endianness, depth, width, channels;
365 g_return_if_fail (gst_caps_is_fixed (caps));
367 GST_DEBUG_OBJECT (base, "trying to fixate othercaps %" GST_PTR_FORMAT
368 " based on caps %" GST_PTR_FORMAT, othercaps, caps);
370 ins = gst_caps_get_structure (caps, 0);
371 outs = gst_caps_get_structure (othercaps, 0);
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);
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);
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);
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);
393 /* this is not allowed */
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);
401 /* set depth as width */
402 if (gst_structure_has_field (outs, "depth")) {
403 gst_structure_fixate_field_nearest_int (outs, "depth", width);
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);
413 GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
417 gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
420 AudioConvertFmt in_ac_caps = { 0 };
421 AudioConvertFmt out_ac_caps = { 0 };
422 GstAudioConvert *this = GST_AUDIO_CONVERT (base);
424 GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
425 GST_PTR_FORMAT, incaps, outcaps);
427 if (!gst_audio_convert_parse_caps (incaps, &in_ac_caps))
429 if (!gst_audio_convert_parse_caps (outcaps, &out_ac_caps))
432 if (!audio_convert_prepare_context (&this->ctx, &in_ac_caps, &out_ac_caps))
444 gst_audio_convert_transform_ip (GstBaseTransform * base, GstBuffer * buf)
446 /* nothing to do here */
451 gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
454 GstAudioConvert *this = GST_AUDIO_CONVERT (base);
456 gint insize, outsize;
460 /* get amount of samples to convert. */
461 samples = GST_BUFFER_SIZE (inbuf) / this->ctx.in.unit_size;
463 /* get in/output sizes, to see if the buffers we got are of correct
465 if (!(res = audio_convert_get_sizes (&this->ctx, samples, &insize, &outsize)))
468 /* check in and outsize */
469 if (GST_BUFFER_SIZE (inbuf) < insize)
471 if (GST_BUFFER_SIZE (outbuf) < outsize)
474 /* get src and dst data */
475 src = GST_BUFFER_DATA (inbuf);
476 dst = GST_BUFFER_DATA (outbuf);
478 /* and convert the samples */
479 if (!(res = audio_convert_convert (&this->ctx, src, dst,
480 samples, gst_buffer_is_writable (inbuf))))
483 GST_BUFFER_SIZE (outbuf) = outsize;
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;
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),
503 return GST_FLOW_ERROR;
507 GST_ELEMENT_ERROR (this, STREAM, NOT_IMPLEMENTED,
508 ("error while converting"), ("error while converting"));
509 return GST_FLOW_ERROR;