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 \
122 "audio/x-raw-float, " \
123 "rate = (int) [ 1, MAX ], " \
124 "channels = (int) [ 1, MAX ], " \
125 "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
126 "width = (int) 64;" \
127 "audio/x-raw-float, " \
128 "rate = (int) [ 1, MAX ], " \
129 "channels = (int) [ 1, MAX ], " \
130 "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
131 "width = (int) 32;" \
132 "audio/x-raw-int, " \
133 "rate = (int) [ 1, MAX ], " \
134 "channels = (int) [ 1, MAX ], " \
135 "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
136 "width = (int) 32, " \
137 "depth = (int) [ 1, 32 ], " \
138 "signed = (boolean) { true, false }; " \
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) 24, " \
144 "depth = (int) [ 1, 24 ], " "signed = (boolean) { true, false }; " \
145 "audio/x-raw-int, " \
146 "rate = (int) [ 1, MAX ], " \
147 "channels = (int) [ 1, MAX ], " \
148 "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
149 "width = (int) 16, " \
150 "depth = (int) [ 1, 16 ], " \
151 "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) 8, " \
157 "depth = (int) [ 1, 8 ], " \
158 "signed = (boolean) { true, false } " \
161 static GstStaticPadTemplate gst_audio_convert_src_template =
162 GST_STATIC_PAD_TEMPLATE ("src",
167 static GstStaticPadTemplate gst_audio_convert_sink_template =
168 GST_STATIC_PAD_TEMPLATE ("sink",
173 #define GST_TYPE_AUDIO_CONVERT_DITHERING (gst_audio_convert_dithering_get_type ())
175 gst_audio_convert_dithering_get_type (void)
177 static GType gtype = 0;
180 static const GEnumValue values[] = {
181 {DITHER_NONE, "No dithering",
183 {DITHER_RPDF, "Rectangular dithering", "rpdf"},
184 {DITHER_TPDF, "Triangular dithering (default)", "tpdf"},
185 {DITHER_TPDF_HF, "High frequency triangular dithering", "tpdf-hf"},
189 gtype = g_enum_register_static ("GstAudioConvertDithering", values);
194 #define GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING (gst_audio_convert_ns_get_type ())
196 gst_audio_convert_ns_get_type (void)
198 static GType gtype = 0;
201 static const GEnumValue values[] = {
202 {NOISE_SHAPING_NONE, "No noise shaping (default)",
204 {NOISE_SHAPING_ERROR_FEEDBACK, "Error feedback", "error-feedback"},
205 {NOISE_SHAPING_SIMPLE, "Simple 2-pole noise shaping", "simple"},
206 {NOISE_SHAPING_MEDIUM, "Medium 5-pole noise shaping", "medium"},
207 {NOISE_SHAPING_HIGH, "High 8-pole noise shaping", "high"},
211 gtype = g_enum_register_static ("GstAudioConvertNoiseShaping", values);
217 /*** TYPE FUNCTIONS ***********************************************************/
220 gst_audio_convert_base_init (gpointer g_class)
222 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
224 gst_element_class_add_pad_template (element_class,
225 gst_static_pad_template_get (&gst_audio_convert_src_template));
226 gst_element_class_add_pad_template (element_class,
227 gst_static_pad_template_get (&gst_audio_convert_sink_template));
228 gst_element_class_set_details_simple (element_class,
229 "Audio converter", "Filter/Converter/Audio",
230 "Convert audio to different formats", "Benjamin Otte <otte@gnome.org>");
234 gst_audio_convert_class_init (GstAudioConvertClass * klass)
236 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
237 GstBaseTransformClass *basetransform_class = GST_BASE_TRANSFORM_CLASS (klass);
239 gobject_class->dispose = gst_audio_convert_dispose;
240 gobject_class->set_property = gst_audio_convert_set_property;
241 gobject_class->get_property = gst_audio_convert_get_property;
243 g_object_class_install_property (gobject_class, ARG_DITHERING,
244 g_param_spec_enum ("dithering", "Dithering",
245 "Selects between different dithering methods.",
246 GST_TYPE_AUDIO_CONVERT_DITHERING, DITHER_TPDF,
247 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
249 g_object_class_install_property (gobject_class, ARG_NOISE_SHAPING,
250 g_param_spec_enum ("noise-shaping", "Noise shaping",
251 "Selects between different noise shaping methods.",
252 GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING, NOISE_SHAPING_NONE,
253 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
255 basetransform_class->get_unit_size =
256 GST_DEBUG_FUNCPTR (gst_audio_convert_get_unit_size);
257 basetransform_class->transform_caps =
258 GST_DEBUG_FUNCPTR (gst_audio_convert_transform_caps);
259 basetransform_class->fixate_caps =
260 GST_DEBUG_FUNCPTR (gst_audio_convert_fixate_caps);
261 basetransform_class->set_caps =
262 GST_DEBUG_FUNCPTR (gst_audio_convert_set_caps);
263 basetransform_class->transform_ip =
264 GST_DEBUG_FUNCPTR (gst_audio_convert_transform_ip);
265 basetransform_class->transform =
266 GST_DEBUG_FUNCPTR (gst_audio_convert_transform);
268 basetransform_class->passthrough_on_same_caps = TRUE;
272 gst_audio_convert_init (GstAudioConvert * this, GstAudioConvertClass * g_class)
274 this->dither = DITHER_TPDF;
275 this->ns = NOISE_SHAPING_NONE;
276 memset (&this->ctx, 0, sizeof (AudioConvertCtx));
278 gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (this), TRUE);
282 gst_audio_convert_dispose (GObject * obj)
284 GstAudioConvert *this = GST_AUDIO_CONVERT (obj);
286 audio_convert_clean_context (&this->ctx);
288 G_OBJECT_CLASS (parent_class)->dispose (obj);
291 /*** GSTREAMER FUNCTIONS ******************************************************/
293 /* convert the given GstCaps to our format */
295 gst_audio_convert_parse_caps (const GstCaps * caps, AudioConvertFmt * fmt)
297 GstStructure *structure = gst_caps_get_structure (caps, 0);
299 GST_DEBUG ("parse caps %p and %" GST_PTR_FORMAT, caps, caps);
301 g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
302 g_return_val_if_fail (fmt != NULL, FALSE);
305 audio_convert_clean_fmt (fmt);
307 fmt->endianness = G_BYTE_ORDER;
309 (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0);
311 /* parse common fields */
312 if (!gst_structure_get_int (structure, "channels", &fmt->channels))
314 if (!(fmt->pos = gst_audio_get_channel_positions (structure)))
317 fmt->unpositioned_layout = FALSE;
318 structure_has_fixed_channel_positions (structure, &fmt->unpositioned_layout);
320 if (!gst_structure_get_int (structure, "width", &fmt->width))
322 if (!gst_structure_get_int (structure, "rate", &fmt->rate))
324 /* width != 8 needs an endianness field */
325 if (fmt->width != 8) {
326 if (!gst_structure_get_int (structure, "endianness", &fmt->endianness))
331 /* int specific fields */
332 if (!gst_structure_get_boolean (structure, "signed", &fmt->sign))
334 if (!gst_structure_get_int (structure, "depth", &fmt->depth))
337 /* depth cannot be bigger than the width */
338 if (fmt->depth > fmt->width)
342 fmt->unit_size = (fmt->width * fmt->channels) / 8;
349 GST_DEBUG ("could not get some values from structure");
350 audio_convert_clean_fmt (fmt);
355 GST_DEBUG ("width > depth, not allowed - make us advertise correct fmt");
356 audio_convert_clean_fmt (fmt);
361 /* BaseTransform vmethods */
363 gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
366 AudioConvertFmt fmt = { 0 };
370 if (!gst_audio_convert_parse_caps (caps, &fmt))
373 GST_INFO_OBJECT (base, "unit_size = %u", fmt.unit_size);
374 *size = fmt.unit_size;
376 audio_convert_clean_fmt (&fmt);
382 GST_INFO_OBJECT (base, "failed to parse caps to get unit_size");
387 /* Set widths (a list); multiples of 8 between min and max */
389 set_structure_widths (GstStructure * s, int min, int max)
396 gst_structure_set (s, "width", G_TYPE_INT, min, NULL);
400 g_value_init (&list, GST_TYPE_LIST);
401 g_value_init (&val, G_TYPE_INT);
402 for (width = min; width <= max; width += 8) {
403 g_value_set_int (&val, width);
404 gst_value_list_append_value (&list, &val);
406 gst_structure_set_value (s, "width", &list);
407 g_value_unset (&val);
408 g_value_unset (&list);
411 /* Set widths of 32 bits and 64 bits (as list) */
413 set_structure_widths_32_and_64 (GstStructure * s)
418 g_value_init (&list, GST_TYPE_LIST);
419 g_value_init (&val, G_TYPE_INT);
420 g_value_set_int (&val, 32);
421 gst_value_list_append_value (&list, &val);
422 g_value_set_int (&val, 64);
423 gst_value_list_append_value (&list, &val);
424 gst_structure_set_value (s, "width", &list);
425 g_value_unset (&val);
426 g_value_unset (&list);
429 /* Modify the structure so that things that must always have a single
430 * value (for float), or can always be losslessly converted (for int), have
431 * appropriate values.
433 static GstStructure *
434 make_lossless_changes (GstStructure * s, gboolean isfloat)
439 const gint endian[] = { G_LITTLE_ENDIAN, G_BIG_ENDIAN };
440 const gboolean booleans[] = { TRUE, FALSE };
442 g_value_init (&list, GST_TYPE_LIST);
443 g_value_init (&val, G_TYPE_INT);
444 for (i = 0; i < 2; i++) {
445 g_value_set_int (&val, endian[i]);
446 gst_value_list_append_value (&list, &val);
448 gst_structure_set_value (s, "endianness", &list);
449 g_value_unset (&val);
450 g_value_unset (&list);
453 /* float doesn't have a depth or signedness field and only supports
454 * widths of 32 and 64 bits */
455 gst_structure_remove_field (s, "depth");
456 gst_structure_remove_field (s, "signed");
457 set_structure_widths_32_and_64 (s);
459 /* int supports signed and unsigned. GValues are a pain */
460 g_value_init (&list, GST_TYPE_LIST);
461 g_value_init (&val, G_TYPE_BOOLEAN);
462 for (i = 0; i < 2; i++) {
463 g_value_set_boolean (&val, booleans[i]);
464 gst_value_list_append_value (&list, &val);
466 gst_structure_set_value (s, "signed", &list);
467 g_value_unset (&val);
468 g_value_unset (&list);
475 strip_width_64 (GstStructure * s)
477 const GValue *v = gst_structure_get_value (s, "width");
478 GValue widths = { 0 };
480 if (GST_VALUE_HOLDS_LIST (v)) {
482 int len = gst_value_list_get_size (v);
484 g_value_init (&widths, GST_TYPE_LIST);
486 for (i = 0; i < len; i++) {
487 const GValue *width = gst_value_list_get_value (v, i);
489 if (g_value_get_int (width) != 64)
490 gst_value_list_append_value (&widths, width);
492 gst_structure_set_value (s, "width", &widths);
493 g_value_unset (&widths);
497 /* Little utility function to create a related structure for float/int */
499 append_with_other_format (GstCaps * caps, GstStructure * s, gboolean isfloat)
504 s2 = gst_structure_copy (s);
505 gst_structure_set_name (s2, "audio/x-raw-int");
506 s = make_lossless_changes (s2, FALSE);
507 /* If 64 bit float was allowed; remove width 64: we don't support it for
510 gst_caps_append_structure (caps, s2);
512 s2 = gst_structure_copy (s);
513 gst_structure_set_name (s2, "audio/x-raw-float");
514 s = make_lossless_changes (s2, TRUE);
515 gst_caps_append_structure (caps, s2);
520 structure_has_fixed_channel_positions (GstStructure * s,
521 gboolean * unpositioned_layout)
523 GstAudioChannelPosition *pos;
527 if (!gst_structure_get_int (s, "channels", &channels))
528 return FALSE; /* probably a range */
530 val = gst_structure_get_value (s, "channel-positions");
531 if ((val == NULL || !gst_value_is_fixed (val)) && channels <= 8) {
532 GST_LOG ("no or unfixed channel-positions in %" GST_PTR_FORMAT, s);
534 } else if (val == NULL || !gst_value_is_fixed (val)) {
535 GST_LOG ("implicit undefined channel-positions");
536 *unpositioned_layout = TRUE;
540 pos = gst_audio_get_channel_positions (s);
541 if (pos && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) {
542 GST_LOG ("fixed undefined channel-positions in %" GST_PTR_FORMAT, s);
543 *unpositioned_layout = TRUE;
545 GST_LOG ("fixed defined channel-positions in %" GST_PTR_FORMAT, s);
546 *unpositioned_layout = FALSE;
553 /* Audioconvert can perform all conversions on audio except for resampling.
554 * However, there are some conversions we _prefer_ not to do. For example, it's
555 * better to convert format (float<->int, endianness, etc) than the number of
556 * channels, as the latter conversion is not lossless.
558 * So, we return, in order (assuming input caps have only one structure;
559 * which is enforced by basetransform):
560 * - input caps with a different format (lossless conversions).
561 * - input caps with a different format (slightly lossy conversions).
562 * - input caps with a different number of channels (very lossy!)
565 gst_audio_convert_transform_caps (GstBaseTransform * base,
566 GstPadDirection direction, GstCaps * caps)
569 GstStructure *s, *structure;
570 gboolean isfloat, allow_mixing;
571 gint width, depth, channels = 0;
572 const gchar *fields_used[] = {
573 "width", "depth", "rate", "channels", "endianness", "signed"
575 const gchar *structure_name;
578 g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL);
580 structure = gst_caps_get_structure (caps, 0);
581 structure_name = gst_structure_get_name (structure);
583 isfloat = strcmp (structure_name, "audio/x-raw-float") == 0;
585 /* We operate on a version of the original structure with any additional
587 s = gst_structure_empty_new (structure_name);
588 for (i = 0; i < sizeof (fields_used) / sizeof (*fields_used); i++) {
589 if (gst_structure_has_field (structure, fields_used[i]))
590 gst_structure_set_value (s, fields_used[i],
591 gst_structure_get_value (structure, fields_used[i]));
595 /* Commonly, depth is left out: set it equal to width if we have a fixed
597 if (!gst_structure_has_field (s, "depth") &&
598 gst_structure_get_int (s, "width", &width))
599 gst_structure_set (s, "depth", G_TYPE_INT, width, NULL);
602 ret = gst_caps_new_empty ();
604 /* All lossless conversions */
605 s = make_lossless_changes (s, isfloat);
606 gst_caps_append_structure (ret, s);
608 /* Same, plus a float<->int conversion */
609 append_with_other_format (ret, s, isfloat);
610 GST_DEBUG_OBJECT (base, " step1: (%d) %" GST_PTR_FORMAT,
611 gst_caps_get_size (ret), ret);
613 /* We don't mind increasing width/depth/channels, but reducing them is
614 * Very Bad. Only available if width, depth, channels are already fixed. */
615 s = gst_structure_copy (s);
617 if (gst_structure_get_int (structure, "width", &width))
618 set_structure_widths (s, width, 32);
619 if (gst_structure_get_int (structure, "depth", &depth)) {
621 gst_structure_set (s, "depth", G_TYPE_INT, 32, NULL);
623 gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, depth, 32, NULL);
628 if (gst_structure_get_int (structure, "channels", &channels)) {
629 gboolean unpositioned;
631 /* we don't support mixing for channels without channel positions */
632 if (structure_has_fixed_channel_positions (structure, &unpositioned))
633 allow_mixing = (unpositioned == FALSE);
637 gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
638 if (gst_structure_has_field (structure, "channel-positions"))
639 gst_structure_set_value (s, "channel-positions",
640 gst_structure_get_value (structure, "channel-positions"));
643 gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 11, NULL);
644 else if (channels == 11)
645 gst_structure_set (s, "channels", G_TYPE_INT, 11, NULL);
647 gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, channels, 11, NULL);
648 gst_structure_remove_field (s, "channel-positions");
650 gst_caps_append_structure (ret, s);
652 /* Same, plus a float<->int conversion */
653 append_with_other_format (ret, s, isfloat);
655 /* We'll reduce depth if we must. We reduce as low as 16 bits (for integer);
656 * reducing to less than this is even worse than dropping channels. We only
657 * do this if we haven't already done the equivalent above. */
658 if (!gst_structure_get_int (structure, "width", &width) || width > 16) {
660 GstStructure *s2 = gst_structure_copy (s);
662 set_structure_widths_32_and_64 (s2);
663 append_with_other_format (ret, s2, TRUE);
664 gst_structure_free (s2);
666 s = gst_structure_copy (s);
667 set_structure_widths (s, 16, 32);
668 gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, 16, 32, NULL);
669 gst_caps_append_structure (ret, s);
673 /* Channel conversions to fewer channels is only done if needed - generally
674 * it's very bad to drop channels entirely.
676 s = gst_structure_copy (s);
678 gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 11, NULL);
679 gst_structure_remove_field (s, "channel-positions");
681 /* allow_mixing can only be FALSE if we got a fixed number of channels */
682 gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL);
683 if (gst_structure_has_field (structure, "channel-positions"))
684 gst_structure_set_value (s, "channel-positions",
685 gst_structure_get_value (structure, "channel-positions"));
687 gst_caps_append_structure (ret, s);
689 /* Same, plus a float<->int conversion */
690 append_with_other_format (ret, s, isfloat);
692 /* And, finally, for integer only, we allow conversion to any width/depth we
693 * support: this should be equivalent to our (non-float) template caps. (the
694 * floating point case should be being handled just above) */
695 s = gst_structure_copy (s);
696 set_structure_widths (s, 8, 32);
697 gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, 1, 32, NULL);
700 append_with_other_format (ret, s, TRUE);
701 gst_structure_free (s);
703 gst_caps_append_structure (ret, s);
705 GST_DEBUG_OBJECT (base, "Caps transformed to %" GST_PTR_FORMAT, ret);
710 static const GstAudioChannelPosition default_positions[8][8] = {
713 GST_AUDIO_CHANNEL_POSITION_FRONT_MONO,
717 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
718 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
720 /* 3 channels (2.1) */
722 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
723 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
724 GST_AUDIO_CHANNEL_POSITION_LFE, /* or FRONT_CENTER for 3.0? */
726 /* 4 channels (4.0 or 3.1?) */
728 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
729 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
730 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
731 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
735 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
736 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
737 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
738 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
739 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
743 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
744 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
745 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
746 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
747 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
748 GST_AUDIO_CHANNEL_POSITION_LFE,
752 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
753 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
754 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
755 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
756 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
757 GST_AUDIO_CHANNEL_POSITION_LFE,
758 GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
762 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
763 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
764 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
765 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
766 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
767 GST_AUDIO_CHANNEL_POSITION_LFE,
768 GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
769 GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
773 static const GValue *
774 find_suitable_channel_layout (const GValue * val, guint chans)
776 /* if output layout is fixed already and looks sane, we're done */
777 if (GST_VALUE_HOLDS_ARRAY (val) && gst_value_array_get_size (val) == chans)
780 /* if it's a list, go through it recursively and return the first
781 * sane-enough looking value we find */
782 if (GST_VALUE_HOLDS_LIST (val)) {
785 for (i = 0; i < gst_value_list_get_size (val); ++i) {
786 const GValue *v, *ret;
788 v = gst_value_list_get_value (val, i);
789 if ((ret = find_suitable_channel_layout (v, chans)))
798 gst_audio_convert_fixate_channels (GstBaseTransform * base, GstStructure * ins,
801 const GValue *in_layout, *out_layout;
802 gint in_chans, out_chans;
804 if (!gst_structure_get_int (ins, "channels", &in_chans))
805 return; /* this shouldn't really happen, should it? */
807 if (!gst_structure_has_field (outs, "channels")) {
808 /* we could try to get the implied number of channels from the layout,
809 * but that seems overdoing it for a somewhat exotic corner case */
810 gst_structure_remove_field (outs, "channel-positions");
814 /* ok, let's fixate the channels if they are not fixated yet */
815 gst_structure_fixate_field_nearest_int (outs, "channels", in_chans);
817 if (!gst_structure_get_int (outs, "channels", &out_chans)) {
818 /* shouldn't really happen ... */
819 gst_structure_remove_field (outs, "channel-positions");
823 /* check if the output has a channel layout (or a list of layouts) */
824 out_layout = gst_structure_get_value (outs, "channel-positions");
826 /* get the channel layout of the input if any */
827 in_layout = gst_structure_get_value (ins, "channel-positions");
829 if (out_layout == NULL) {
830 if (out_chans <= 2 && (in_chans != out_chans || in_layout == NULL))
831 return; /* nothing to do, default layout will be assumed */
832 GST_WARNING_OBJECT (base, "downstream caps contain no channel layout");
835 if (in_chans == out_chans && in_layout != NULL) {
838 /* same number of channels and no output layout: just use input layout */
839 if (out_layout == NULL) {
840 gst_structure_set_value (outs, "channel-positions", in_layout);
844 /* if output layout is fixed already and looks sane, we're done */
845 if (GST_VALUE_HOLDS_ARRAY (out_layout) &&
846 gst_value_array_get_size (out_layout) == out_chans) {
850 /* if the output layout is not fixed, check if the output layout contains
851 * the input layout */
852 if (gst_value_intersect (&res, in_layout, out_layout)) {
853 gst_structure_set_value (outs, "channel-positions", in_layout);
854 g_value_unset (&res);
858 /* output layout is not fixed and does not contain the input layout, so
859 * just pick the first layout in the list (it should be a list ...) */
860 if ((out_layout = find_suitable_channel_layout (out_layout, out_chans))) {
861 gst_structure_set_value (outs, "channel-positions", out_layout);
865 /* ... else fall back to default layout (NB: out_layout is NULL here) */
866 GST_WARNING_OBJECT (base, "unexpected output channel layout");
869 /* number of input channels != number of output channels:
870 * if this value contains a list of channel layouts (or even worse: a list
871 * with another list), just pick the first value and repeat until we find a
872 * channel position array or something else that's not a list; we assume
873 * the input if half-way sane and don't try to fall back on other list items
874 * if the first one is something unexpected or non-channel-pos-array-y */
875 if (out_layout != NULL && GST_VALUE_HOLDS_LIST (out_layout))
876 out_layout = find_suitable_channel_layout (out_layout, out_chans);
878 if (out_layout != NULL) {
879 if (GST_VALUE_HOLDS_ARRAY (out_layout) &&
880 gst_value_array_get_size (out_layout) == out_chans) {
881 /* looks sane enough, let's use it */
882 gst_structure_set_value (outs, "channel-positions", out_layout);
886 /* what now?! Just ignore what we're given and use default positions */
887 GST_WARNING_OBJECT (base, "invalid or unexpected channel-positions");
890 /* missing or invalid output layout and we can't use the input layout for
891 * one reason or another, so just pick a default layout (we could be smarter
892 * and try to add/remove channels from the input layout, or pick a default
893 * layout based on LFE-presence in input layout, but let's save that for
895 if (out_chans > 0 && out_chans <= G_N_ELEMENTS (default_positions[0])) {
896 GST_DEBUG_OBJECT (base, "using default channel layout as fallback");
897 gst_audio_set_channel_positions (outs, default_positions[out_chans - 1]);
901 /* try to keep as many of the structure members the same by fixating the
902 * possible ranges; this way we convert the least amount of things as possible
905 gst_audio_convert_fixate_caps (GstBaseTransform * base,
906 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
908 GstStructure *ins, *outs;
909 gint rate, endianness, depth, width;
912 g_return_if_fail (gst_caps_is_fixed (caps));
914 GST_DEBUG_OBJECT (base, "trying to fixate othercaps %" GST_PTR_FORMAT
915 " based on caps %" GST_PTR_FORMAT, othercaps, caps);
917 ins = gst_caps_get_structure (caps, 0);
918 outs = gst_caps_get_structure (othercaps, 0);
920 gst_audio_convert_fixate_channels (base, ins, outs);
922 if (gst_structure_get_int (ins, "rate", &rate)) {
923 if (gst_structure_has_field (outs, "rate")) {
924 gst_structure_fixate_field_nearest_int (outs, "rate", rate);
927 if (gst_structure_get_int (ins, "endianness", &endianness)) {
928 if (gst_structure_has_field (outs, "endianness")) {
929 gst_structure_fixate_field_nearest_int (outs, "endianness", endianness);
932 if (gst_structure_get_int (ins, "width", &width)) {
933 if (gst_structure_has_field (outs, "width")) {
934 gst_structure_fixate_field_nearest_int (outs, "width", width);
937 /* this is not allowed */
940 if (gst_structure_get_int (ins, "depth", &depth)) {
941 if (gst_structure_has_field (outs, "depth")) {
942 gst_structure_fixate_field_nearest_int (outs, "depth", depth);
945 /* set depth as width */
946 if (gst_structure_has_field (outs, "depth")) {
947 gst_structure_fixate_field_nearest_int (outs, "depth", width);
951 if (gst_structure_get_boolean (ins, "signed", &signedness)) {
952 if (gst_structure_has_field (outs, "signed")) {
953 gst_structure_fixate_field_boolean (outs, "signed", signedness);
957 GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
961 gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
964 AudioConvertFmt in_ac_caps = { 0 };
965 AudioConvertFmt out_ac_caps = { 0 };
966 GstAudioConvert *this = GST_AUDIO_CONVERT (base);
968 GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
969 GST_PTR_FORMAT, incaps, outcaps);
971 if (!gst_audio_convert_parse_caps (incaps, &in_ac_caps))
973 if (!gst_audio_convert_parse_caps (outcaps, &out_ac_caps))
976 if (!audio_convert_prepare_context (&this->ctx, &in_ac_caps, &out_ac_caps,
977 this->dither, this->ns))
989 gst_audio_convert_transform_ip (GstBaseTransform * base, GstBuffer * buf)
991 /* nothing to do here */
996 gst_audio_convert_create_silence_buffer (GstAudioConvert * this, gpointer dst,
999 if (this->ctx.out.is_int && !this->ctx.out.sign) {
1002 switch (this->ctx.out.width) {
1004 guint8 zero = 0x80 >> (8 - this->ctx.out.depth);
1006 memset (dst, zero, size);
1010 guint16 *data = (guint16 *) dst;
1011 guint16 zero = 0x8000 >> (16 - this->ctx.out.depth);
1013 if (this->ctx.out.endianness == G_LITTLE_ENDIAN)
1014 zero = GUINT16_TO_LE (zero);
1016 zero = GUINT16_TO_BE (zero);
1020 for (i = 0; i < size; i++)
1025 guint32 zero = 0x800000 >> (24 - this->ctx.out.depth);
1026 guint8 *data = (guint8 *) dst;
1028 if (this->ctx.out.endianness == G_LITTLE_ENDIAN) {
1029 for (i = 0; i < size; i += 3) {
1030 data[i] = zero & 0xff;
1031 data[i + 1] = (zero >> 8) & 0xff;
1032 data[i + 2] = (zero >> 16) & 0xff;
1035 for (i = 0; i < size; i += 3) {
1036 data[i + 2] = zero & 0xff;
1037 data[i + 1] = (zero >> 8) & 0xff;
1038 data[i] = (zero >> 16) & 0xff;
1044 guint32 *data = (guint32 *) dst;
1045 guint32 zero = (0x80000000 >> (32 - this->ctx.out.depth));
1047 if (this->ctx.out.endianness == G_LITTLE_ENDIAN)
1048 zero = GUINT32_TO_LE (zero);
1050 zero = GUINT32_TO_BE (zero);
1054 for (i = 0; i < size; i++)
1059 memset (dst, 0, size);
1060 g_return_if_reached ();
1064 memset (dst, 0, size);
1068 static GstFlowReturn
1069 gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
1072 GstAudioConvert *this = GST_AUDIO_CONVERT (base);
1073 gint insize, outsize;
1077 GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, base, "converting audio from %"
1078 GST_PTR_FORMAT " to %" GST_PTR_FORMAT, GST_BUFFER_CAPS (inbuf),
1079 GST_BUFFER_CAPS (outbuf));
1081 /* get amount of samples to convert. */
1082 samples = GST_BUFFER_SIZE (inbuf) / this->ctx.in.unit_size;
1084 /* get in/output sizes, to see if the buffers we got are of correct
1086 if (!audio_convert_get_sizes (&this->ctx, samples, &insize, &outsize))
1089 if (insize == 0 || outsize == 0)
1092 /* check in and outsize */
1093 if (GST_BUFFER_SIZE (inbuf) < insize)
1095 if (GST_BUFFER_SIZE (outbuf) < outsize)
1098 /* get src and dst data */
1099 src = GST_BUFFER_DATA (inbuf);
1100 dst = GST_BUFFER_DATA (outbuf);
1102 /* and convert the samples */
1103 if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
1104 if (!audio_convert_convert (&this->ctx, src, dst,
1105 samples, gst_buffer_is_writable (inbuf)))
1108 /* Create silence buffer */
1109 gst_audio_convert_create_silence_buffer (this, dst, outsize);
1112 GST_BUFFER_SIZE (outbuf) = outsize;
1119 GST_ELEMENT_ERROR (this, STREAM, FORMAT,
1120 (NULL), ("cannot get input/output sizes for %d samples", samples));
1121 return GST_FLOW_ERROR;
1125 GST_ELEMENT_ERROR (this, STREAM, FORMAT,
1127 ("input/output buffers are of wrong size in: %d < %d or out: %d < %d",
1128 GST_BUFFER_SIZE (inbuf), insize, GST_BUFFER_SIZE (outbuf),
1130 return GST_FLOW_ERROR;
1134 GST_ELEMENT_ERROR (this, STREAM, FORMAT,
1135 (NULL), ("error while converting"));
1136 return GST_FLOW_ERROR;
1141 gst_audio_convert_set_property (GObject * object, guint prop_id,
1142 const GValue * value, GParamSpec * pspec)
1144 GstAudioConvert *this = GST_AUDIO_CONVERT (object);
1148 this->dither = g_value_get_enum (value);
1150 case ARG_NOISE_SHAPING:
1151 this->ns = g_value_get_enum (value);
1154 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1160 gst_audio_convert_get_property (GObject * object, guint prop_id,
1161 GValue * value, GParamSpec * pspec)
1163 GstAudioConvert *this = GST_AUDIO_CONVERT (object);
1167 g_value_set_enum (value, this->dither);
1169 case ARG_NOISE_SHAPING:
1170 g_value_set_enum (value, this->ns);
1173 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);