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
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.
32 * <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
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.
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.
43 * Last reviewed on 2006-03-02 (0.10.4)
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.
54 * audioconvert is not supposed to be a one-element-does-anything solution for
64 #include "gstaudioconvert.h"
65 #include "gstchannelmix.h"
66 #include "gstaudioquantize.h"
69 GST_DEBUG_CATEGORY (audio_convert_debug);
70 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
72 /*** DEFINITIONS **************************************************************/
75 static void gst_audio_convert_dispose (GObject * obj);
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,
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);
97 /* AudioConvert signals and args */
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");
115 GST_BOILERPLATE_FULL (GstAudioConvert, gst_audio_convert, GstBaseTransform,
116 GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
118 /*** GSTREAMER PROTOTYPES *****************************************************/
120 #define STATIC_CAPS \
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 } " \
168 static GstStaticPadTemplate gst_audio_convert_src_template =
169 GST_STATIC_PAD_TEMPLATE ("src",
174 static GstStaticPadTemplate gst_audio_convert_sink_template =
175 GST_STATIC_PAD_TEMPLATE ("sink",
180 #define GST_TYPE_AUDIO_CONVERT_DITHERING (gst_audio_convert_dithering_get_type ())
182 gst_audio_convert_dithering_get_type (void)
184 static GType gtype = 0;
187 static const GEnumValue values[] = {
188 {DITHER_NONE, "No dithering",
190 {DITHER_RPDF, "Rectangular dithering", "rpdf"},
191 {DITHER_TPDF, "Triangular dithering (default)", "tpdf"},
192 {DITHER_TPDF_HF, "High frequency triangular dithering", "tpdf-hf"},
196 gtype = g_enum_register_static ("GstAudioConvertDithering", values);
201 #define GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING (gst_audio_convert_ns_get_type ())
203 gst_audio_convert_ns_get_type (void)
205 static GType gtype = 0;
208 static const GEnumValue values[] = {
209 {NOISE_SHAPING_NONE, "No noise shaping (default)",
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"},
218 gtype = g_enum_register_static ("GstAudioConvertNoiseShaping", values);
224 /*** TYPE FUNCTIONS ***********************************************************/
227 gst_audio_convert_base_init (gpointer g_class)
229 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
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>");
241 gst_audio_convert_class_init (GstAudioConvertClass * klass)
243 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
244 GstBaseTransformClass *basetransform_class = GST_BASE_TRANSFORM_CLASS (klass);
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;
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));
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));
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);
275 basetransform_class->passthrough_on_same_caps = TRUE;
279 gst_audio_convert_init (GstAudioConvert * this, GstAudioConvertClass * g_class)
281 this->dither = DITHER_TPDF;
282 this->ns = NOISE_SHAPING_NONE;
283 memset (&this->ctx, 0, sizeof (AudioConvertCtx));
285 gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (this), TRUE);
289 gst_audio_convert_dispose (GObject * obj)
291 GstAudioConvert *this = GST_AUDIO_CONVERT (obj);
293 audio_convert_clean_context (&this->ctx);
295 G_OBJECT_CLASS (parent_class)->dispose (obj);
298 /*** GSTREAMER FUNCTIONS ******************************************************/
300 /* convert the given GstCaps to our format */
302 gst_audio_convert_parse_caps (const GstCaps * caps, AudioConvertFmt * fmt)
304 GstStructure *structure = gst_caps_get_structure (caps, 0);
306 GST_DEBUG ("parse caps %p and %" GST_PTR_FORMAT, caps, caps);
308 g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
309 g_return_val_if_fail (fmt != NULL, FALSE);
312 audio_convert_clean_fmt (fmt);
314 fmt->endianness = G_BYTE_ORDER;
316 (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0) ||
317 (strcmp (gst_structure_get_name (structure), "audio/x-lpcm") == 0);
319 /* parse common fields */
320 if (!gst_structure_get_int (structure, "channels", &fmt->channels))
322 if (!(fmt->pos = gst_audio_get_channel_positions (structure)))
325 fmt->unpositioned_layout = FALSE;
326 structure_has_fixed_channel_positions (structure, &fmt->unpositioned_layout);
328 if (!gst_structure_get_int (structure, "width", &fmt->width))
330 if (!gst_structure_get_int (structure, "rate", &fmt->rate))
332 /* width != 8 needs an endianness field */
333 if (fmt->width != 8) {
334 if (!gst_structure_get_int (structure, "endianness", &fmt->endianness))
339 /* int specific fields */
340 if (!gst_structure_get_boolean (structure, "signed", &fmt->sign))
342 if (!gst_structure_get_int (structure, "depth", &fmt->depth))
345 /* depth cannot be bigger than the width */
346 if (fmt->depth > fmt->width)
350 fmt->unit_size = (fmt->width * fmt->channels) / 8;
357 GST_DEBUG ("could not get some values from structure");
358 audio_convert_clean_fmt (fmt);
363 GST_DEBUG ("width > depth, not allowed - make us advertise correct fmt");
364 audio_convert_clean_fmt (fmt);
369 /* BaseTransform vmethods */
371 gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
374 AudioConvertFmt fmt = { 0 };
378 if (!gst_audio_convert_parse_caps (caps, &fmt))
381 GST_INFO_OBJECT (base, "unit_size = %u", fmt.unit_size);
382 *size = fmt.unit_size;
384 audio_convert_clean_fmt (&fmt);
390 GST_INFO_OBJECT (base, "failed to parse caps to get unit_size");
395 /* Set widths (a list); multiples of 8 between min and max */
397 set_structure_widths (GstStructure * s, int min, int max)
404 gst_structure_set (s, "width", G_TYPE_INT, min, NULL);
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);
414 gst_structure_set_value (s, "width", &list);
415 g_value_unset (&val);
416 g_value_unset (&list);
419 /* Set widths of 32 bits and 64 bits (as list) */
421 set_structure_widths_32_and_64 (GstStructure * s)
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);
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.
441 static GstStructure *
442 make_lossless_changes (GstStructure * s, gboolean isfloat)
447 const gint endian[] = { G_LITTLE_ENDIAN, G_BIG_ENDIAN };
448 const gboolean booleans[] = { TRUE, FALSE };
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);
456 gst_structure_set_value (s, "endianness", &list);
457 g_value_unset (&val);
458 g_value_unset (&list);
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);
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);
474 gst_structure_set_value (s, "signed", &list);
475 g_value_unset (&val);
476 g_value_unset (&list);
483 strip_width_64 (GstStructure * s)
485 const GValue *v = gst_structure_get_value (s, "width");
486 GValue widths = { 0 };
488 if (GST_VALUE_HOLDS_LIST (v)) {
490 int len = gst_value_list_get_size (v);
492 g_value_init (&widths, GST_TYPE_LIST);
494 for (i = 0; i < len; i++) {
495 const GValue *width = gst_value_list_get_value (v, i);
497 if (g_value_get_int (width) != 64)
498 gst_value_list_append_value (&widths, width);
500 gst_structure_set_value (s, "width", &widths);
501 g_value_unset (&widths);
505 /* Little utility function to create a related structure for float/int */
507 append_with_other_format (GstCaps * caps, GstStructure * s, gboolean 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
518 gst_caps_append_structure (caps, s2);
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);
528 structure_has_fixed_channel_positions (GstStructure * s,
529 gboolean * unpositioned_layout)
531 GstAudioChannelPosition *pos;
535 if (!gst_structure_get_int (s, "channels", &channels))
536 return FALSE; /* probably a range */
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);
542 } else if (val == NULL || !gst_value_is_fixed (val)) {
543 GST_LOG ("implicit undefined channel-positions");
544 *unpositioned_layout = TRUE;
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;
553 GST_LOG ("fixed defined channel-positions in %" GST_PTR_FORMAT, s);
554 *unpositioned_layout = FALSE;
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.
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!)
573 gst_audio_convert_transform_caps (GstBaseTransform * base,
574 GstPadDirection direction, GstCaps * caps)
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"
583 const gchar *structure_name;
586 g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL);
588 structure = gst_caps_get_structure (caps, 0);
589 structure_name = gst_structure_get_name (structure);
591 isfloat = strcmp (structure_name, "audio/x-raw-float") == 0;
593 /* We operate on a version of the original structure with any additional
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]));
603 /* Commonly, depth is left out: set it equal to width if we have a fixed
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);
610 ret = gst_caps_new_empty ();
612 /* All lossless conversions */
613 s = make_lossless_changes (s, isfloat);
614 gst_caps_append_structure (ret, s);
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);
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);
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)) {
629 gst_structure_set (s, "depth", G_TYPE_INT, 32, NULL);
631 gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, depth, 32, NULL);
636 if (gst_structure_get_int (structure, "channels", &channels)) {
637 gboolean unpositioned;
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);
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"));
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);
655 gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, channels, 11, NULL);
656 gst_structure_remove_field (s, "channel-positions");
658 gst_caps_append_structure (ret, s);
660 /* Same, plus a float<->int conversion */
661 append_with_other_format (ret, s, isfloat);
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) {
668 GstStructure *s2 = gst_structure_copy (s);
670 set_structure_widths_32_and_64 (s2);
671 append_with_other_format (ret, s2, TRUE);
672 gst_structure_free (s2);
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);
681 /* Channel conversions to fewer channels is only done if needed - generally
682 * it's very bad to drop channels entirely.
684 s = gst_structure_copy (s);
686 gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 11, NULL);
687 gst_structure_remove_field (s, "channel-positions");
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"));
695 gst_caps_append_structure (ret, s);
697 /* Same, plus a float<->int conversion */
698 append_with_other_format (ret, s, isfloat);
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);
708 append_with_other_format (ret, s, TRUE);
709 gst_structure_free (s);
711 gst_caps_append_structure (ret, s);
713 GST_DEBUG_OBJECT (base, "Caps transformed to %" GST_PTR_FORMAT, ret);
718 static const GstAudioChannelPosition default_positions[8][8] = {
721 GST_AUDIO_CHANNEL_POSITION_FRONT_MONO,
725 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
726 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
728 /* 3 channels (2.1) */
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? */
734 /* 4 channels (4.0 or 3.1?) */
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,
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,
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,
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,
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,
781 static const GValue *
782 find_suitable_channel_layout (const GValue * val, guint chans)
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)
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)) {
793 for (i = 0; i < gst_value_list_get_size (val); ++i) {
794 const GValue *v, *ret;
796 v = gst_value_list_get_value (val, i);
797 if ((ret = find_suitable_channel_layout (v, chans)))
806 gst_audio_convert_fixate_channels (GstBaseTransform * base, GstStructure * ins,
809 const GValue *in_layout, *out_layout;
810 gint in_chans, out_chans;
812 if (!gst_structure_get_int (ins, "channels", &in_chans))
813 return; /* this shouldn't really happen, should it? */
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");
822 /* ok, let's fixate the channels if they are not fixated yet */
823 gst_structure_fixate_field_nearest_int (outs, "channels", in_chans);
825 if (!gst_structure_get_int (outs, "channels", &out_chans)) {
826 /* shouldn't really happen ... */
827 gst_structure_remove_field (outs, "channel-positions");
831 /* check if the output has a channel layout (or a list of layouts) */
832 out_layout = gst_structure_get_value (outs, "channel-positions");
834 /* get the channel layout of the input if any */
835 in_layout = gst_structure_get_value (ins, "channel-positions");
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");
843 if (in_chans == out_chans && in_layout != NULL) {
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);
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) {
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);
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);
873 /* ... else fall back to default layout (NB: out_layout is NULL here) */
874 GST_WARNING_OBJECT (base, "unexpected output channel layout");
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);
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);
894 /* what now?! Just ignore what we're given and use default positions */
895 GST_WARNING_OBJECT (base, "invalid or unexpected channel-positions");
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
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]);
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
913 gst_audio_convert_fixate_caps (GstBaseTransform * base,
914 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
916 GstStructure *ins, *outs;
917 gint rate, endianness, depth, width;
920 g_return_if_fail (gst_caps_is_fixed (caps));
922 GST_DEBUG_OBJECT (base, "trying to fixate othercaps %" GST_PTR_FORMAT
923 " based on caps %" GST_PTR_FORMAT, othercaps, caps);
925 ins = gst_caps_get_structure (caps, 0);
926 outs = gst_caps_get_structure (othercaps, 0);
928 gst_audio_convert_fixate_channels (base, ins, outs);
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);
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);
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);
945 /* this is not allowed */
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);
953 /* set depth as width */
954 if (gst_structure_has_field (outs, "depth")) {
955 gst_structure_fixate_field_nearest_int (outs, "depth", width);
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);
965 GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
969 gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
972 AudioConvertFmt in_ac_caps = { 0 };
973 AudioConvertFmt out_ac_caps = { 0 };
974 GstAudioConvert *this = GST_AUDIO_CONVERT (base);
976 GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
977 GST_PTR_FORMAT, incaps, outcaps);
979 if (!gst_audio_convert_parse_caps (incaps, &in_ac_caps))
981 if (!gst_audio_convert_parse_caps (outcaps, &out_ac_caps))
984 if (!audio_convert_prepare_context (&this->ctx, &in_ac_caps, &out_ac_caps,
985 this->dither, this->ns))
997 gst_audio_convert_transform_ip (GstBaseTransform * base, GstBuffer * buf)
999 /* nothing to do here */
1004 gst_audio_convert_create_silence_buffer (GstAudioConvert * this, gpointer dst,
1007 if (this->ctx.out.is_int && !this->ctx.out.sign) {
1010 switch (this->ctx.out.width) {
1012 guint8 zero = 0x80 >> (8 - this->ctx.out.depth);
1014 memset (dst, zero, size);
1018 guint16 *data = (guint16 *) dst;
1019 guint16 zero = 0x8000 >> (16 - this->ctx.out.depth);
1021 if (this->ctx.out.endianness == G_LITTLE_ENDIAN)
1022 zero = GUINT16_TO_LE (zero);
1024 zero = GUINT16_TO_BE (zero);
1028 for (i = 0; i < size; i++)
1033 guint32 zero = 0x800000 >> (24 - this->ctx.out.depth);
1034 guint8 *data = (guint8 *) dst;
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;
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;
1052 guint32 *data = (guint32 *) dst;
1053 guint32 zero = (0x80000000 >> (32 - this->ctx.out.depth));
1055 if (this->ctx.out.endianness == G_LITTLE_ENDIAN)
1056 zero = GUINT32_TO_LE (zero);
1058 zero = GUINT32_TO_BE (zero);
1062 for (i = 0; i < size; i++)
1067 memset (dst, 0, size);
1068 g_return_if_reached ();
1072 memset (dst, 0, size);
1076 static GstFlowReturn
1077 gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
1080 GstAudioConvert *this = GST_AUDIO_CONVERT (base);
1081 gint insize, outsize;
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));
1089 /* get amount of samples to convert. */
1090 samples = GST_BUFFER_SIZE (inbuf) / this->ctx.in.unit_size;
1092 /* get in/output sizes, to see if the buffers we got are of correct
1094 if (!audio_convert_get_sizes (&this->ctx, samples, &insize, &outsize))
1097 if (insize == 0 || outsize == 0)
1100 /* check in and outsize */
1101 if (GST_BUFFER_SIZE (inbuf) < insize)
1103 if (GST_BUFFER_SIZE (outbuf) < outsize)
1106 /* get src and dst data */
1107 src = GST_BUFFER_DATA (inbuf);
1108 dst = GST_BUFFER_DATA (outbuf);
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)))
1116 /* Create silence buffer */
1117 gst_audio_convert_create_silence_buffer (this, dst, outsize);
1120 GST_BUFFER_SIZE (outbuf) = outsize;
1127 GST_ELEMENT_ERROR (this, STREAM, FORMAT,
1128 (NULL), ("cannot get input/output sizes for %d samples", samples));
1129 return GST_FLOW_ERROR;
1133 GST_ELEMENT_ERROR (this, STREAM, FORMAT,
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),
1138 return GST_FLOW_ERROR;
1142 GST_ELEMENT_ERROR (this, STREAM, FORMAT,
1143 (NULL), ("error while converting"));
1144 return GST_FLOW_ERROR;
1149 gst_audio_convert_set_property (GObject * object, guint prop_id,
1150 const GValue * value, GParamSpec * pspec)
1152 GstAudioConvert *this = GST_AUDIO_CONVERT (object);
1156 this->dither = g_value_get_enum (value);
1158 case ARG_NOISE_SHAPING:
1159 this->ns = g_value_get_enum (value);
1162 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1168 gst_audio_convert_get_property (GObject * object, guint prop_id,
1169 GValue * value, GParamSpec * pspec)
1171 GstAudioConvert *this = GST_AUDIO_CONVERT (object);
1175 g_value_set_enum (value, this->dither);
1177 case ARG_NOISE_SHAPING:
1178 g_value_set_enum (value, this->ns);
1181 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);