2 * Copyright (C) 2005 Wim Taymans <wim at fluendo dot com>
3 * (C) 2015 Wim Taymans <wim.taymans@gmail.com>
5 * audioconverter.c: Convert audio to different audio formats automatically
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
30 #include "audio-converter.h"
31 #include "gstaudiopack.h"
34 * SECTION:gstaudioconverter
35 * @title: GstAudioConverter
36 * @short_description: Generic audio conversion
38 * This object is used to convert audio samples from one format to another.
39 * The object can perform conversion of:
41 * * audio format with optional dithering and noise shaping
45 * * audio channels and channel layout
49 #ifndef GST_DISABLE_GST_DEBUG
50 #define GST_CAT_DEFAULT ensure_debug_category()
51 static GstDebugCategory *
52 ensure_debug_category (void)
54 static gsize cat_gonce = 0;
56 if (g_once_init_enter (&cat_gonce)) {
59 cat_done = (gsize) _gst_debug_category_new ("audio-converter", 0,
60 "audio-converter object");
62 g_once_init_leave (&cat_gonce, cat_done);
65 return (GstDebugCategory *) cat_gonce;
68 #define ensure_debug_category() /* NOOP */
69 #endif /* GST_DISABLE_GST_DEBUG */
71 typedef struct _AudioChain AudioChain;
73 typedef void (*AudioConvertFunc) (gpointer dst, const gpointer src, gint count);
74 typedef gboolean (*AudioConvertSamplesFunc) (GstAudioConverter * convert,
75 GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
76 gpointer out[], gsize out_frames);
77 typedef void (*AudioConvertEndianFunc) (gpointer dst, const gpointer src,
80 /* int/int int/float float/int float/float
82 * unpack S32 S32 F64 F64
84 * channel mix S32 F64 F64 F64
87 * pack S32 F64 S32 F64
94 struct _GstAudioConverter
101 GstAudioConverterFlags flags;
102 GstAudioFormat current_format;
103 GstAudioLayout current_layout;
104 gint current_channels;
106 gboolean in_writable;
112 gboolean in_place; /* the conversion can be done in place; returned by gst_audio_converter_supports_inplace() */
114 gboolean passthrough;
121 AudioConvertFunc convert_in;
124 gboolean mix_passthrough;
125 GstAudioChannelMixer *mix;
128 GstAudioResampler *resampler;
131 AudioConvertFunc convert_out;
134 GstAudioQuantize *quant;
137 GstAudioFormat chlayout_format;
138 GstAudioLayout chlayout_target;
139 gint chlayout_channels;
142 gboolean out_default;
143 AudioChain *chain_end; /* NULL for empty chain or points to the last element in the chain */
146 AudioConvertEndianFunc swap_endian;
148 AudioConvertSamplesFunc convert;
151 static GstAudioConverter *
152 gst_audio_converter_copy (GstAudioConverter * convert)
154 GstAudioConverter *res =
155 gst_audio_converter_new (convert->flags, &convert->in, &convert->out,
161 G_DEFINE_BOXED_TYPE (GstAudioConverter, gst_audio_converter,
162 (GBoxedCopyFunc) gst_audio_converter_copy,
163 (GBoxedFreeFunc) gst_audio_converter_free);
165 typedef gboolean (*AudioChainFunc) (AudioChain * chain, gpointer user_data);
166 typedef gpointer *(*AudioChainAllocFunc) (AudioChain * chain, gsize num_samples,
173 AudioChainFunc make_func;
174 gpointer make_func_data;
175 GDestroyNotify make_func_notify;
177 const GstAudioFormatInfo *finfo;
185 AudioChainAllocFunc alloc_func;
189 gsize allocated_samples;
196 audio_chain_new (AudioChain * prev, GstAudioConverter * convert)
200 chain = g_slice_new0 (AudioChain);
203 if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
205 chain->blocks = convert->current_channels;
207 chain->inc = convert->current_channels;
210 chain->finfo = gst_audio_format_get_info (convert->current_format);
211 chain->stride = (chain->finfo->width * chain->inc) / 8;
217 audio_chain_set_make_func (AudioChain * chain,
218 AudioChainFunc make_func, gpointer user_data, GDestroyNotify notify)
220 chain->make_func = make_func;
221 chain->make_func_data = user_data;
222 chain->make_func_notify = notify;
226 audio_chain_free (AudioChain * chain)
228 GST_LOG ("free chain %p", chain);
229 if (chain->make_func_notify)
230 chain->make_func_notify (chain->make_func_data);
232 g_slice_free (AudioChain, chain);
236 audio_chain_alloc_samples (AudioChain * chain, gsize num_samples)
238 return chain->alloc_func (chain, num_samples, chain->alloc_data);
242 audio_chain_set_samples (AudioChain * chain, gpointer * samples,
245 GST_LOG ("set samples %p %" G_GSIZE_FORMAT, samples, num_samples);
247 chain->samples = samples;
248 chain->num_samples = num_samples;
252 audio_chain_get_samples (AudioChain * chain, gsize * avail)
257 chain->make_func (chain, chain->make_func_data);
259 res = chain->samples;
260 *avail = chain->num_samples;
261 chain->samples = NULL;
267 get_opt_uint (GstAudioConverter * convert, const gchar * opt, guint def)
270 if (!gst_structure_get_uint (convert->config, opt, &res))
276 get_opt_enum (GstAudioConverter * convert, const gchar * opt, GType type,
280 if (!gst_structure_get_enum (convert->config, opt, type, &res))
285 static const GValue *
286 get_opt_value (GstAudioConverter * convert, const gchar * opt)
288 return gst_structure_get_value (convert->config, opt);
291 #define DEFAULT_OPT_RESAMPLER_METHOD GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL
292 #define DEFAULT_OPT_DITHER_METHOD GST_AUDIO_DITHER_NONE
293 #define DEFAULT_OPT_DITHER_THRESHOLD 20
294 #define DEFAULT_OPT_NOISE_SHAPING_METHOD GST_AUDIO_NOISE_SHAPING_NONE
295 #define DEFAULT_OPT_QUANTIZATION 1
297 #define GET_OPT_RESAMPLER_METHOD(c) get_opt_enum(c, \
298 GST_AUDIO_CONVERTER_OPT_RESAMPLER_METHOD, GST_TYPE_AUDIO_RESAMPLER_METHOD, \
299 DEFAULT_OPT_RESAMPLER_METHOD)
300 #define GET_OPT_DITHER_METHOD(c) get_opt_enum(c, \
301 GST_AUDIO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_AUDIO_DITHER_METHOD, \
302 DEFAULT_OPT_DITHER_METHOD)
303 #define GET_OPT_DITHER_THRESHOLD(c) get_opt_uint(c, \
304 GST_AUDIO_CONVERTER_OPT_DITHER_THRESHOLD, DEFAULT_OPT_DITHER_THRESHOLD)
305 #define GET_OPT_NOISE_SHAPING_METHOD(c) get_opt_enum(c, \
306 GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD, GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, \
307 DEFAULT_OPT_NOISE_SHAPING_METHOD)
308 #define GET_OPT_QUANTIZATION(c) get_opt_uint(c, \
309 GST_AUDIO_CONVERTER_OPT_QUANTIZATION, DEFAULT_OPT_QUANTIZATION)
310 #define GET_OPT_MIX_MATRIX(c) get_opt_value(c, \
311 GST_AUDIO_CONVERTER_OPT_MIX_MATRIX)
314 copy_config (GQuark field_id, const GValue * value, gpointer user_data)
316 GstAudioConverter *convert = user_data;
318 gst_structure_id_set_value (convert->config, field_id, value);
324 * gst_audio_converter_update_config:
325 * @convert: a #GstAudioConverter
326 * @in_rate: input rate
327 * @out_rate: output rate
328 * @config: (transfer full) (allow-none): a #GstStructure or %NULL
330 * Set @in_rate, @out_rate and @config as extra configuration for @convert.
332 * @in_rate and @out_rate specify the new sample rates of input and output
333 * formats. A value of 0 leaves the sample rate unchanged.
335 * @config can be %NULL, in which case, the current configuration is not
338 * If the parameters in @config can not be set exactly, this function returns
339 * %FALSE and will try to update as much state as possible. The new state can
340 * then be retrieved and refined with gst_audio_converter_get_config().
342 * Look at the `GST_AUDIO_CONVERTER_OPT_*` fields to check valid configuration
345 * Returns: %TRUE when the new parameters could be set
348 gst_audio_converter_update_config (GstAudioConverter * convert,
349 gint in_rate, gint out_rate, GstStructure * config)
351 g_return_val_if_fail (convert != NULL, FALSE);
352 g_return_val_if_fail ((in_rate == 0 && out_rate == 0) ||
353 convert->flags & GST_AUDIO_CONVERTER_FLAG_VARIABLE_RATE, FALSE);
355 GST_LOG ("new rate %d -> %d", in_rate, out_rate);
358 in_rate = convert->in.rate;
360 out_rate = convert->out.rate;
362 convert->in.rate = in_rate;
363 convert->out.rate = out_rate;
365 if (convert->resampler)
366 gst_audio_resampler_update (convert->resampler, in_rate, out_rate, config);
369 gst_structure_foreach (config, copy_config, convert);
370 gst_structure_free (config);
377 * gst_audio_converter_get_config:
378 * @convert: a #GstAudioConverter
379 * @in_rate: (out) (optional): result input rate
380 * @out_rate: (out) (optional): result output rate
382 * Get the current configuration of @convert.
384 * Returns: (transfer none):
385 * a #GstStructure that remains valid for as long as @convert is valid
386 * or until gst_audio_converter_update_config() is called.
389 gst_audio_converter_get_config (GstAudioConverter * convert,
390 gint * in_rate, gint * out_rate)
392 g_return_val_if_fail (convert != NULL, NULL);
395 *in_rate = convert->in.rate;
397 *out_rate = convert->out.rate;
399 return convert->config;
403 get_output_samples (AudioChain * chain, gsize num_samples, gpointer user_data)
405 GstAudioConverter *convert = user_data;
407 GST_LOG ("output samples %p %" G_GSIZE_FORMAT, convert->out_data,
410 return convert->out_data;
413 #define MEM_ALIGN(m,a) ((gint8 *)((guintptr)((gint8 *)(m) + ((a)-1)) & ~((a)-1)))
417 get_temp_samples (AudioChain * chain, gsize num_samples, gpointer user_data)
419 if (num_samples > chain->allocated_samples) {
422 gsize stride = GST_ROUND_UP_N (num_samples * chain->stride, ALIGN);
423 /* first part contains the pointers, second part the data, add some extra bytes
425 gsize needed = (stride + sizeof (gpointer)) * chain->blocks + ALIGN - 1;
427 GST_DEBUG ("alloc samples %d %" G_GSIZE_FORMAT " %" G_GSIZE_FORMAT,
428 chain->stride, num_samples, needed);
429 chain->tmp = g_realloc (chain->tmp, needed);
430 chain->allocated_samples = num_samples;
432 /* pointer to the data, make sure it's 16 bytes aligned */
433 s = MEM_ALIGN (&chain->tmp[chain->blocks], ALIGN);
435 /* set up the pointers */
436 for (i = 0; i < chain->blocks; i++)
437 chain->tmp[i] = s + i * stride;
439 GST_LOG ("temp samples %p %" G_GSIZE_FORMAT, chain->tmp, num_samples);
445 do_unpack (AudioChain * chain, gpointer user_data)
447 GstAudioConverter *convert = user_data;
450 gboolean in_writable;
452 in_writable = convert->in_writable;
453 num_samples = convert->in_frames;
455 if (!chain->allow_ip || !in_writable || !convert->in_default) {
458 if (in_writable && chain->allow_ip) {
459 tmp = convert->in_data;
460 GST_LOG ("unpack in-place %p, %" G_GSIZE_FORMAT, tmp, num_samples);
462 tmp = audio_chain_alloc_samples (chain, num_samples);
463 GST_LOG ("unpack to tmp %p, %" G_GSIZE_FORMAT, tmp, num_samples);
466 if (convert->in_data) {
467 for (i = 0; i < chain->blocks; i++) {
468 if (convert->in_default) {
469 GST_LOG ("copy %p, %p, %" G_GSIZE_FORMAT, tmp[i], convert->in_data[i],
471 memcpy (tmp[i], convert->in_data[i], num_samples * chain->stride);
473 GST_LOG ("unpack %p, %p, %" G_GSIZE_FORMAT, tmp[i],
474 convert->in_data[i], num_samples);
475 convert->in.finfo->unpack_func (convert->in.finfo,
476 GST_AUDIO_PACK_FLAG_TRUNCATE_RANGE, tmp[i], convert->in_data[i],
477 num_samples * chain->inc);
481 for (i = 0; i < chain->blocks; i++) {
482 gst_audio_format_info_fill_silence (chain->finfo, tmp[i],
483 num_samples * chain->inc);
487 tmp = convert->in_data;
488 GST_LOG ("get in samples %p", tmp);
490 audio_chain_set_samples (chain, tmp, num_samples);
496 do_convert_in (AudioChain * chain, gpointer user_data)
499 GstAudioConverter *convert = user_data;
503 in = audio_chain_get_samples (chain->prev, &num_samples);
504 out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
505 GST_LOG ("convert in %p, %p, %" G_GSIZE_FORMAT, in, out, num_samples);
507 for (i = 0; i < chain->blocks; i++)
508 convert->convert_in (out[i], in[i], num_samples * chain->inc);
510 audio_chain_set_samples (chain, out, num_samples);
516 do_mix (AudioChain * chain, gpointer user_data)
519 GstAudioConverter *convert = user_data;
522 in = audio_chain_get_samples (chain->prev, &num_samples);
523 out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
524 GST_LOG ("mix %p, %p, %" G_GSIZE_FORMAT, in, out, num_samples);
526 gst_audio_channel_mixer_samples (convert->mix, in, out, num_samples);
528 audio_chain_set_samples (chain, out, num_samples);
534 do_resample (AudioChain * chain, gpointer user_data)
536 GstAudioConverter *convert = user_data;
538 gsize in_frames, out_frames;
540 in = audio_chain_get_samples (chain->prev, &in_frames);
541 out_frames = convert->out_frames;
542 out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, out_frames));
544 GST_LOG ("resample %p %p,%" G_GSIZE_FORMAT " %" G_GSIZE_FORMAT, in,
545 out, in_frames, out_frames);
547 gst_audio_resampler_resample (convert->resampler, in, in_frames, out,
550 audio_chain_set_samples (chain, out, out_frames);
556 do_convert_out (AudioChain * chain, gpointer user_data)
558 GstAudioConverter *convert = user_data;
563 in = audio_chain_get_samples (chain->prev, &num_samples);
564 out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
565 GST_LOG ("convert out %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
567 for (i = 0; i < chain->blocks; i++)
568 convert->convert_out (out[i], in[i], num_samples * chain->inc);
570 audio_chain_set_samples (chain, out, num_samples);
576 do_quantize (AudioChain * chain, gpointer user_data)
578 GstAudioConverter *convert = user_data;
582 in = audio_chain_get_samples (chain->prev, &num_samples);
583 out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
584 GST_LOG ("quantize %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
587 gst_audio_quantize_samples (convert->quant, in, out, num_samples);
589 audio_chain_set_samples (chain, out, num_samples);
594 #define MAKE_INTERLEAVE_FUNC(type) \
596 interleave_##type (const type * in[], type * out[], \
597 gsize num_samples, gint channels) \
601 for (s = 0; s < num_samples; s++) { \
602 for (c = 0; c < channels; c++) { \
603 out[0][s * channels + c] = in[c][s]; \
608 #define MAKE_DEINTERLEAVE_FUNC(type) \
610 deinterleave_##type (const type * in[], type * out[], \
611 gsize num_samples, gint channels) \
615 for (s = 0; s < num_samples; s++) { \
616 for (c = 0; c < channels; c++) { \
617 out[c][s] = in[0][s * channels + c]; \
622 MAKE_INTERLEAVE_FUNC (gint16);
623 MAKE_INTERLEAVE_FUNC (gint32);
624 MAKE_INTERLEAVE_FUNC (gfloat);
625 MAKE_INTERLEAVE_FUNC (gdouble);
626 MAKE_DEINTERLEAVE_FUNC (gint16);
627 MAKE_DEINTERLEAVE_FUNC (gint32);
628 MAKE_DEINTERLEAVE_FUNC (gfloat);
629 MAKE_DEINTERLEAVE_FUNC (gdouble);
632 do_change_layout (AudioChain * chain, gpointer user_data)
634 GstAudioConverter *convert = user_data;
635 GstAudioFormat format = convert->chlayout_format;
636 GstAudioLayout out_layout = convert->chlayout_target;
637 gint channels = convert->chlayout_channels;
641 in = audio_chain_get_samples (chain->prev, &num_samples);
642 out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
644 if (out_layout == GST_AUDIO_LAYOUT_INTERLEAVED) {
646 GST_LOG ("interleaving %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
648 case GST_AUDIO_FORMAT_S16:
649 interleave_gint16 ((const gint16 **) in, (gint16 **) out,
650 num_samples, channels);
652 case GST_AUDIO_FORMAT_S32:
653 interleave_gint32 ((const gint32 **) in, (gint32 **) out,
654 num_samples, channels);
656 case GST_AUDIO_FORMAT_F32:
657 interleave_gfloat ((const gfloat **) in, (gfloat **) out,
658 num_samples, channels);
660 case GST_AUDIO_FORMAT_F64:
661 interleave_gdouble ((const gdouble **) in, (gdouble **) out,
662 num_samples, channels);
665 g_assert_not_reached ();
670 GST_LOG ("deinterleaving %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
672 case GST_AUDIO_FORMAT_S16:
673 deinterleave_gint16 ((const gint16 **) in, (gint16 **) out,
674 num_samples, channels);
676 case GST_AUDIO_FORMAT_S32:
677 deinterleave_gint32 ((const gint32 **) in, (gint32 **) out,
678 num_samples, channels);
680 case GST_AUDIO_FORMAT_F32:
681 deinterleave_gfloat ((const gfloat **) in, (gfloat **) out,
682 num_samples, channels);
684 case GST_AUDIO_FORMAT_F64:
685 deinterleave_gdouble ((const gdouble **) in, (gdouble **) out,
686 num_samples, channels);
689 g_assert_not_reached ();
694 audio_chain_set_samples (chain, out, num_samples);
699 is_intermediate_format (GstAudioFormat format)
701 return (format == GST_AUDIO_FORMAT_S16 ||
702 format == GST_AUDIO_FORMAT_S32 ||
703 format == GST_AUDIO_FORMAT_F32 || format == GST_AUDIO_FORMAT_F64);
707 chain_unpack (GstAudioConverter * convert)
710 GstAudioInfo *in = &convert->in;
711 GstAudioInfo *out = &convert->out;
712 gboolean same_format;
714 same_format = in->finfo->format == out->finfo->format;
716 /* do not unpack if we have the same input format as the output format
717 * and it is a possible intermediate format */
718 if (same_format && is_intermediate_format (in->finfo->format)) {
719 convert->current_format = in->finfo->format;
721 convert->current_format = in->finfo->unpack_format;
723 convert->current_layout = in->layout;
724 convert->current_channels = in->channels;
726 convert->in_default = convert->current_format == in->finfo->format;
728 GST_INFO ("unpack format %s to %s",
729 gst_audio_format_to_string (in->finfo->format),
730 gst_audio_format_to_string (convert->current_format));
732 prev = audio_chain_new (NULL, convert);
733 prev->allow_ip = prev->finfo->width <= in->finfo->width;
734 prev->pass_alloc = FALSE;
735 audio_chain_set_make_func (prev, do_unpack, convert, NULL);
741 chain_convert_in (GstAudioConverter * convert, AudioChain * prev)
743 gboolean in_int, out_int;
744 GstAudioInfo *in = &convert->in;
745 GstAudioInfo *out = &convert->out;
747 in_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo);
748 out_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo);
750 if (in_int && !out_int) {
751 GST_INFO ("convert S32 to F64");
752 convert->convert_in = (AudioConvertFunc) audio_orc_s32_to_double;
753 convert->current_format = GST_AUDIO_FORMAT_F64;
755 prev = audio_chain_new (prev, convert);
756 prev->allow_ip = FALSE;
757 prev->pass_alloc = FALSE;
758 audio_chain_set_make_func (prev, do_convert_in, convert, NULL);
764 check_mix_matrix (guint in_channels, guint out_channels, const GValue * value)
768 /* audio-channel-mixer will generate an identity matrix */
769 if (gst_value_array_get_size (value) == 0)
772 if (gst_value_array_get_size (value) != out_channels) {
773 GST_ERROR ("Invalid mix matrix size, should be %d", out_channels);
777 for (j = 0; j < out_channels; j++) {
778 const GValue *row = gst_value_array_get_value (value, j);
780 if (gst_value_array_get_size (row) != in_channels) {
781 GST_ERROR ("Invalid mix matrix row size, should be %d", in_channels);
785 for (i = 0; i < in_channels; i++) {
788 itm = gst_value_array_get_value (row, i);
789 if (!G_VALUE_HOLDS_FLOAT (itm)) {
790 GST_ERROR ("Invalid mix matrix element type, should be float");
803 mix_matrix_from_g_value (guint in_channels, guint out_channels,
804 const GValue * value)
807 gfloat **matrix = g_new (gfloat *, in_channels);
809 for (i = 0; i < in_channels; i++)
810 matrix[i] = g_new (gfloat, out_channels);
812 for (j = 0; j < out_channels; j++) {
813 const GValue *row = gst_value_array_get_value (value, j);
815 for (i = 0; i < in_channels; i++) {
819 itm = gst_value_array_get_value (row, i);
820 coefficient = g_value_get_float (itm);
821 matrix[i][j] = coefficient;
829 chain_mix (GstAudioConverter * convert, AudioChain * prev)
831 GstAudioInfo *in = &convert->in;
832 GstAudioInfo *out = &convert->out;
833 GstAudioFormat format = convert->current_format;
834 const GValue *opt_matrix = GET_OPT_MIX_MATRIX (convert);
835 GstAudioChannelMixerFlags flags = 0;
837 convert->current_channels = out->channels;
839 /* keep the input layout */
840 if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
841 flags |= GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN;
842 flags |= GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT;
846 gfloat **matrix = NULL;
848 if (gst_value_array_get_size (opt_matrix))
850 mix_matrix_from_g_value (in->channels, out->channels, opt_matrix);
853 gst_audio_channel_mixer_new_with_matrix (flags, format, in->channels,
854 out->channels, matrix);
857 GST_AUDIO_INFO_IS_UNPOSITIONED (in) ?
858 GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_IN : 0;
860 GST_AUDIO_INFO_IS_UNPOSITIONED (out) ?
861 GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_OUT : 0;
864 gst_audio_channel_mixer_new (flags, format, in->channels, in->position,
865 out->channels, out->position);
868 convert->mix_passthrough =
869 gst_audio_channel_mixer_is_passthrough (convert->mix);
870 GST_INFO ("mix format %s, passthrough %d, in_channels %d, out_channels %d",
871 gst_audio_format_to_string (format), convert->mix_passthrough,
872 in->channels, out->channels);
874 if (!convert->mix_passthrough) {
875 prev = audio_chain_new (prev, convert);
876 prev->allow_ip = FALSE;
877 prev->pass_alloc = FALSE;
878 audio_chain_set_make_func (prev, do_mix, convert, NULL);
884 chain_resample (GstAudioConverter * convert, AudioChain * prev)
886 GstAudioInfo *in = &convert->in;
887 GstAudioInfo *out = &convert->out;
888 GstAudioResamplerMethod method;
889 GstAudioResamplerFlags flags;
890 GstAudioFormat format = convert->current_format;
891 gint channels = convert->current_channels;
892 gboolean variable_rate;
894 variable_rate = convert->flags & GST_AUDIO_CONVERTER_FLAG_VARIABLE_RATE;
896 if (in->rate != out->rate || variable_rate) {
897 method = GET_OPT_RESAMPLER_METHOD (convert);
900 if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
901 flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_IN;
903 /* if the resampler is activated, it is optimal to change layout here */
904 if (out->layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
905 flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_OUT;
907 convert->current_layout = out->layout;
910 flags |= GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE;
913 gst_audio_resampler_new (method, flags, format, channels, in->rate,
914 out->rate, convert->config);
916 prev = audio_chain_new (prev, convert);
917 prev->allow_ip = FALSE;
918 prev->pass_alloc = FALSE;
919 audio_chain_set_make_func (prev, do_resample, convert, NULL);
925 chain_convert_out (GstAudioConverter * convert, AudioChain * prev)
927 gboolean in_int, out_int;
928 GstAudioInfo *in = &convert->in;
929 GstAudioInfo *out = &convert->out;
931 in_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo);
932 out_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo);
934 if (!in_int && out_int) {
935 convert->convert_out = (AudioConvertFunc) audio_orc_double_to_s32;
936 convert->current_format = GST_AUDIO_FORMAT_S32;
938 GST_INFO ("convert F64 to S32");
939 prev = audio_chain_new (prev, convert);
940 prev->allow_ip = TRUE;
941 prev->pass_alloc = FALSE;
942 audio_chain_set_make_func (prev, do_convert_out, convert, NULL);
948 chain_quantize (GstAudioConverter * convert, AudioChain * prev)
950 const GstAudioFormatInfo *cur_finfo;
951 GstAudioInfo *out = &convert->out;
952 gint in_depth, out_depth;
953 gboolean in_int, out_int;
954 GstAudioDitherMethod dither;
955 guint dither_threshold;
956 GstAudioNoiseShapingMethod ns;
958 dither = GET_OPT_DITHER_METHOD (convert);
959 dither_threshold = GET_OPT_DITHER_THRESHOLD (convert);
960 ns = GET_OPT_NOISE_SHAPING_METHOD (convert);
962 cur_finfo = gst_audio_format_get_info (convert->current_format);
964 in_depth = GST_AUDIO_FORMAT_INFO_DEPTH (cur_finfo);
965 out_depth = GST_AUDIO_FORMAT_INFO_DEPTH (out->finfo);
966 GST_INFO ("depth in %d, out %d", in_depth, out_depth);
968 in_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (cur_finfo);
969 out_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo);
971 /* Don't dither or apply noise shaping if target depth is bigger than 20 bits
972 * as DA converters only can do a SNR up to 20 bits in reality.
973 * Also don't dither or apply noise shaping if target depth is larger than
975 if (out_depth > dither_threshold || (in_int && out_depth >= in_depth)) {
976 dither = GST_AUDIO_DITHER_NONE;
977 ns = GST_AUDIO_NOISE_SHAPING_NONE;
978 GST_INFO ("using no dither and noise shaping");
980 GST_INFO ("using dither %d and noise shaping %d", dither, ns);
981 /* Use simple error feedback when output sample rate is smaller than
982 * 32000 as the other methods might move the noise to audible ranges */
983 if (ns > GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK && out->rate < 32000)
984 ns = GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK;
986 /* we still want to run the quantization step when reducing bits to get
987 * the rounding correct */
988 if (out_int && out_depth < 32
989 && convert->current_format == GST_AUDIO_FORMAT_S32) {
990 GST_INFO ("quantize to %d bits, dither %d, ns %d", out_depth, dither, ns);
992 gst_audio_quantize_new (dither, ns, 0, convert->current_format,
993 out->channels, 1U << (32 - out_depth));
995 prev = audio_chain_new (prev, convert);
996 prev->allow_ip = TRUE;
997 prev->pass_alloc = TRUE;
998 audio_chain_set_make_func (prev, do_quantize, convert, NULL);
1004 chain_change_layout (GstAudioConverter * convert, AudioChain * prev)
1006 GstAudioInfo *out = &convert->out;
1008 if (convert->current_layout != out->layout) {
1009 convert->current_layout = out->layout;
1011 /* if there is only 1 channel, layouts are identical */
1012 if (convert->current_channels > 1) {
1013 convert->chlayout_target = convert->current_layout;
1014 convert->chlayout_format = convert->current_format;
1015 convert->chlayout_channels = convert->current_channels;
1017 prev = audio_chain_new (prev, convert);
1018 prev->allow_ip = FALSE;
1019 prev->pass_alloc = FALSE;
1020 audio_chain_set_make_func (prev, do_change_layout, convert, NULL);
1027 chain_pack (GstAudioConverter * convert, AudioChain * prev)
1029 GstAudioInfo *out = &convert->out;
1030 GstAudioFormat format = convert->current_format;
1032 convert->current_format = out->finfo->format;
1034 convert->out_default = format == out->finfo->format;
1035 GST_INFO ("pack format %s to %s", gst_audio_format_to_string (format),
1036 gst_audio_format_to_string (out->finfo->format));
1042 setup_allocators (GstAudioConverter * convert)
1045 AudioChainAllocFunc alloc_func;
1048 /* start with using dest if we can directly write into it */
1049 if (convert->out_default) {
1050 alloc_func = get_output_samples;
1053 alloc_func = get_temp_samples;
1056 /* now walk backwards, we try to write into the dest samples directly
1057 * and keep track if the source needs to be writable */
1058 for (chain = convert->chain_end; chain; chain = chain->prev) {
1059 chain->alloc_func = alloc_func;
1060 chain->alloc_data = convert;
1061 chain->allow_ip = allow_ip && chain->allow_ip;
1062 GST_LOG ("chain %p: %d %d", chain, allow_ip, chain->allow_ip);
1064 if (!chain->pass_alloc) {
1065 /* can't pass allocator, make new temp line allocator */
1066 alloc_func = get_temp_samples;
1073 converter_passthrough (GstAudioConverter * convert,
1074 GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1075 gpointer out[], gsize out_frames)
1081 /* in-place passthrough -> do nothing */
1083 g_assert (convert->in_place);
1087 chain = convert->chain_end;
1089 samples = in_frames * chain->inc;
1091 GST_LOG ("passthrough: %" G_GSIZE_FORMAT " / %" G_GSIZE_FORMAT " samples",
1092 in_frames, samples);
1097 bytes = samples * (convert->in.bpf / convert->in.channels);
1099 for (i = 0; i < chain->blocks; i++) {
1100 if (out[i] == in[i]) {
1101 g_assert (convert->in_place);
1105 memcpy (out[i], in[i], bytes);
1108 for (i = 0; i < chain->blocks; i++)
1109 gst_audio_format_info_fill_silence (convert->in.finfo, out[i], samples);
1114 /* perform LE<->BE conversion on a block of @count 16-bit samples
1115 * dst may equal src for in-place conversion
1118 converter_swap_endian_16 (gpointer dst, const gpointer src, gint count)
1121 const guint16 *in = src;
1124 for (i = 0; i < count; i++)
1125 out[i] = GUINT16_SWAP_LE_BE (in[i]);
1128 /* perform LE<->BE conversion on a block of @count 24-bit samples
1129 * dst may equal src for in-place conversion
1131 * naive algorithm, which performs better with -O3 and worse with -O2
1132 * than the commented out optimized algorithm below
1135 converter_swap_endian_24 (gpointer dst, const gpointer src, gint count)
1138 const guint8 *in = src;
1143 for (i = 0; i < count; i += 3) {
1144 guint8 x = in[i + 0];
1145 out[i + 0] = in[i + 2];
1146 out[i + 1] = in[i + 1];
1151 /* the below code performs better with -O2 but worse with -O3 */
1153 /* perform LE<->BE conversion on a block of @count 24-bit samples
1154 * dst may equal src for in-place conversion
1156 * assumes that dst and src are 32-bit aligned
1159 converter_swap_endian_24 (gpointer dst, const gpointer src, gint count)
1162 const guint32 *in = src;
1167 /* first convert 24-bit samples in multiples of 4 reading 3x 32-bits in one cycle
1169 * input: A1 B1 C1 A2 , B2 C2 A3 B3 , C3 A4 B4 C4
1170 * 32-bit endian swap: A2 C1 B1 A1 , B3 A3 C2 B2 , C4 B4 A4 C3
1171 * <-- x --> <-- y --> , <-- z -->
1173 * desired output: C1 B1 A1 C2 , B2 A2 C3 B3 , A3 C4 B4 A4
1175 for (i = 0; i < count / 4; i++, in += 3, out += 3) {
1178 x = GUINT32_SWAP_LE_BE (in[0]);
1179 y = GUINT32_SWAP_LE_BE (in[1]);
1180 z = GUINT32_SWAP_LE_BE (in[2]);
1182 #if G_BYTE_ORDER == G_BIG_ENDIAN
1183 out[0] = (x << 8) + ((y >> 8) & 0xff);
1184 out[1] = (in[1] & 0xff0000ff) + ((x >> 8) & 0xff0000) + ((z << 8) & 0xff00);
1185 out[2] = (z >> 8) + ((y << 8) & 0xff000000);
1187 out[0] = (x >> 8) + ((y << 8) & 0xff000000);
1188 out[1] = (in[1] & 0xff0000ff) + ((x << 8) & 0xff00) + ((z >> 8) & 0xff0000);
1189 out[2] = (z << 8) + ((y >> 8) & 0xff);
1193 /* convert the remainder less efficiently */
1194 for (out8 = (guint8 *) out, in8 = (const guint8 *) in, i = 0; i < (count & 3);
1196 guint8 x = in8[i + 0];
1197 out8[i + 0] = in8[i + 2];
1198 out8[i + 1] = in8[i + 1];
1204 /* perform LE<->BE conversion on a block of @count 32-bit samples
1205 * dst may equal src for in-place conversion
1208 converter_swap_endian_32 (gpointer dst, const gpointer src, gint count)
1211 const guint32 *in = src;
1214 for (i = 0; i < count; i++)
1215 out[i] = GUINT32_SWAP_LE_BE (in[i]);
1218 /* perform LE<->BE conversion on a block of @count 64-bit samples
1219 * dst may equal src for in-place conversion
1222 converter_swap_endian_64 (gpointer dst, const gpointer src, gint count)
1225 const guint64 *in = src;
1228 for (i = 0; i < count; i++)
1229 out[i] = GUINT64_SWAP_LE_BE (in[i]);
1232 /* the worker function to perform endian-conversion only
1233 * assuming finfo and foutinfo have the same depth
1236 converter_endian (GstAudioConverter * convert,
1237 GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1238 gpointer out[], gsize out_frames)
1244 chain = convert->chain_end;
1245 samples = in_frames * chain->inc;
1247 GST_LOG ("convert endian: %" G_GSIZE_FORMAT " / %" G_GSIZE_FORMAT " samples",
1248 in_frames, samples);
1251 for (i = 0; i < chain->blocks; i++)
1252 convert->swap_endian (out[i], in[i], samples);
1254 for (i = 0; i < chain->blocks; i++)
1255 gst_audio_format_info_fill_silence (convert->in.finfo, out[i], samples);
1261 converter_generic (GstAudioConverter * convert,
1262 GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1263 gpointer out[], gsize out_frames)
1270 chain = convert->chain_end;
1272 convert->in_writable = flags & GST_AUDIO_CONVERTER_FLAG_IN_WRITABLE;
1273 convert->in_data = in;
1274 convert->in_frames = in_frames;
1275 convert->out_data = out;
1276 convert->out_frames = out_frames;
1278 /* get frames to pack */
1279 tmp = audio_chain_get_samples (chain, &produced);
1281 if (!convert->out_default && tmp && out) {
1282 GST_LOG ("pack %p, %p %" G_GSIZE_FORMAT, tmp, out, produced);
1283 /* and pack if needed */
1284 for (i = 0; i < chain->blocks; i++)
1285 convert->out.finfo->pack_func (convert->out.finfo, 0, tmp[i], out[i],
1286 produced * chain->inc);
1292 converter_resample (GstAudioConverter * convert,
1293 GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1294 gpointer out[], gsize out_frames)
1296 gst_audio_resampler_resample (convert->resampler, in, in_frames, out,
1302 #define GST_AUDIO_FORMAT_IS_ENDIAN_CONVERSION(info1, info2) \
1304 !(((info1)->flags ^ (info2)->flags) & (~GST_AUDIO_FORMAT_FLAG_UNPACK)) && \
1305 (info1)->endianness != (info2)->endianness && \
1306 (info1)->width == (info2)->width && \
1307 (info1)->depth == (info2)->depth \
1311 * gst_audio_converter_new:
1312 * @flags: extra #GstAudioConverterFlags
1313 * @in_info: a source #GstAudioInfo
1314 * @out_info: a destination #GstAudioInfo
1315 * @config: (transfer full) (nullable): a #GstStructure with configuration options
1317 * Create a new #GstAudioConverter that is able to convert between @in and @out
1320 * @config contains extra configuration options, see `GST_AUDIO_CONVERTER_OPT_*`
1321 * parameters for details about the options and values.
1323 * Returns: (nullable): a #GstAudioConverter or %NULL if conversion is not possible.
1326 gst_audio_converter_new (GstAudioConverterFlags flags, GstAudioInfo * in_info,
1327 GstAudioInfo * out_info, GstStructure * config)
1329 GstAudioConverter *convert;
1331 const GValue *opt_matrix = NULL;
1333 g_return_val_if_fail (in_info != NULL, FALSE);
1334 g_return_val_if_fail (out_info != NULL, FALSE);
1338 gst_structure_get_value (config, GST_AUDIO_CONVERTER_OPT_MIX_MATRIX);
1341 && !check_mix_matrix (in_info->channels, out_info->channels, opt_matrix))
1342 goto invalid_mix_matrix;
1344 if ((GST_AUDIO_INFO_CHANNELS (in_info) != GST_AUDIO_INFO_CHANNELS (out_info))
1345 && (GST_AUDIO_INFO_IS_UNPOSITIONED (in_info)
1346 || GST_AUDIO_INFO_IS_UNPOSITIONED (out_info))
1350 convert = g_slice_new0 (GstAudioConverter);
1352 convert->flags = flags;
1353 convert->in = *in_info;
1354 convert->out = *out_info;
1356 /* default config */
1357 convert->config = gst_structure_new_empty ("GstAudioConverter");
1359 gst_audio_converter_update_config (convert, 0, 0, config);
1361 GST_INFO ("unitsizes: %d -> %d", in_info->bpf, out_info->bpf);
1363 /* step 1, unpack */
1364 prev = chain_unpack (convert);
1365 /* step 2, optional convert from S32 to F64 for channel mix */
1366 prev = chain_convert_in (convert, prev);
1367 /* step 3, channel mix */
1368 prev = chain_mix (convert, prev);
1369 /* step 4, resample */
1370 prev = chain_resample (convert, prev);
1371 /* step 5, optional convert for quantize */
1372 prev = chain_convert_out (convert, prev);
1373 /* step 6, optional quantize */
1374 prev = chain_quantize (convert, prev);
1375 /* step 7, change layout */
1376 prev = chain_change_layout (convert, prev);
1378 convert->chain_end = chain_pack (convert, prev);
1380 convert->convert = converter_generic;
1381 convert->in_place = FALSE;
1382 convert->passthrough = FALSE;
1385 if (convert->mix_passthrough) {
1386 if (out_info->finfo->format == in_info->finfo->format) {
1387 if (convert->resampler == NULL) {
1388 if (out_info->layout == in_info->layout) {
1389 GST_INFO ("same formats, same layout, no resampler and "
1390 "passthrough mixing -> passthrough");
1391 convert->convert = converter_passthrough;
1392 convert->in_place = TRUE;
1393 convert->passthrough = TRUE;
1396 if (is_intermediate_format (in_info->finfo->format)) {
1397 GST_INFO ("same formats, and passthrough mixing -> only resampling");
1398 convert->convert = converter_resample;
1401 } else if (GST_AUDIO_FORMAT_IS_ENDIAN_CONVERSION (out_info->finfo,
1403 if (convert->resampler == NULL && out_info->layout == in_info->layout) {
1404 GST_INFO ("no resampler, passthrough mixing -> only endian conversion");
1405 convert->convert = converter_endian;
1406 convert->in_place = TRUE;
1408 switch (GST_AUDIO_INFO_WIDTH (in_info)) {
1410 GST_DEBUG ("initializing 16-bit endian conversion");
1411 convert->swap_endian = converter_swap_endian_16;
1414 GST_DEBUG ("initializing 24-bit endian conversion");
1415 convert->swap_endian = converter_swap_endian_24;
1418 GST_DEBUG ("initializing 32-bit endian conversion");
1419 convert->swap_endian = converter_swap_endian_32;
1422 GST_DEBUG ("initializing 64-bit endian conversion");
1423 convert->swap_endian = converter_swap_endian_64;
1426 GST_ERROR ("unsupported sample width for endian conversion");
1427 g_assert_not_reached ();
1433 setup_allocators (convert);
1440 GST_WARNING ("unpositioned channels");
1441 g_clear_pointer (&config, gst_structure_free);
1447 GST_WARNING ("Invalid mix matrix");
1448 g_clear_pointer (&config, gst_structure_free);
1454 * gst_audio_converter_free:
1455 * @convert: a #GstAudioConverter
1457 * Free a previously allocated @convert instance.
1460 gst_audio_converter_free (GstAudioConverter * convert)
1464 g_return_if_fail (convert != NULL);
1466 /* walk the chain backwards and free all elements */
1467 for (chain = convert->chain_end; chain;) {
1468 AudioChain *prev = chain->prev;
1469 audio_chain_free (chain);
1474 gst_audio_quantize_free (convert->quant);
1476 gst_audio_channel_mixer_free (convert->mix);
1477 if (convert->resampler)
1478 gst_audio_resampler_free (convert->resampler);
1479 gst_audio_info_init (&convert->in);
1480 gst_audio_info_init (&convert->out);
1482 gst_structure_free (convert->config);
1484 g_slice_free (GstAudioConverter, convert);
1488 * gst_audio_converter_get_out_frames:
1489 * @convert: a #GstAudioConverter
1490 * @in_frames: number of input frames
1492 * Calculate how many output frames can be produced when @in_frames input
1493 * frames are given to @convert.
1495 * Returns: the number of output frames
1498 gst_audio_converter_get_out_frames (GstAudioConverter * convert,
1501 if (convert->resampler)
1502 return gst_audio_resampler_get_out_frames (convert->resampler, in_frames);
1508 * gst_audio_converter_get_in_frames:
1509 * @convert: a #GstAudioConverter
1510 * @out_frames: number of output frames
1512 * Calculate how many input frames are currently needed by @convert to produce
1513 * @out_frames of output frames.
1515 * Returns: the number of input frames
1518 gst_audio_converter_get_in_frames (GstAudioConverter * convert,
1521 if (convert->resampler)
1522 return gst_audio_resampler_get_in_frames (convert->resampler, out_frames);
1528 * gst_audio_converter_get_max_latency:
1529 * @convert: a #GstAudioConverter
1531 * Get the maximum number of input frames that the converter would
1532 * need before producing output.
1534 * Returns: the latency of @convert as expressed in the number of
1538 gst_audio_converter_get_max_latency (GstAudioConverter * convert)
1540 if (convert->resampler)
1541 return gst_audio_resampler_get_max_latency (convert->resampler);
1547 * gst_audio_converter_reset:
1548 * @convert: a #GstAudioConverter
1550 * Reset @convert to the state it was when it was first created, clearing
1551 * any history it might currently have.
1554 gst_audio_converter_reset (GstAudioConverter * convert)
1556 if (convert->resampler)
1557 gst_audio_resampler_reset (convert->resampler);
1559 gst_audio_quantize_reset (convert->quant);
1563 * gst_audio_converter_samples:
1564 * @convert: a #GstAudioConverter
1565 * @flags: extra #GstAudioConverterFlags
1567 * @in_frames: number of input frames
1568 * @out: output frames
1569 * @out_frames: number of output frames
1571 * Perform the conversion with @in_frames in @in to @out_frames in @out
1574 * In case the samples are interleaved, @in and @out must point to an
1575 * array with a single element pointing to a block of interleaved samples.
1577 * If non-interleaved samples are used, @in and @out must point to an
1578 * array with pointers to memory blocks, one for each channel.
1580 * @in may be %NULL, in which case @in_frames of silence samples are processed
1583 * This function always produces @out_frames of output and consumes @in_frames of
1584 * input. Use gst_audio_converter_get_out_frames() and
1585 * gst_audio_converter_get_in_frames() to make sure @in_frames and @out_frames
1586 * are matching and @in and @out point to enough memory.
1588 * Returns: %TRUE is the conversion could be performed.
1591 gst_audio_converter_samples (GstAudioConverter * convert,
1592 GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1593 gpointer out[], gsize out_frames)
1595 g_return_val_if_fail (convert != NULL, FALSE);
1596 g_return_val_if_fail (out != NULL, FALSE);
1598 if (in_frames == 0) {
1599 GST_LOG ("skipping empty buffer");
1602 return convert->convert (convert, flags, in, in_frames, out, out_frames);
1606 * gst_audio_converter_convert:
1607 * @convert: a #GstAudioConverter
1608 * @flags: extra #GstAudioConverterFlags
1609 * @in: (array length=in_size) (element-type guint8): input data
1610 * @in_size: size of @in
1611 * @out: (out) (array length=out_size) (element-type guint8): a pointer where
1612 * the output data will be written
1613 * @out_size: (out): a pointer where the size of @out will be written
1615 * Convenience wrapper around gst_audio_converter_samples(), which will
1616 * perform allocation of the output buffer based on the result from
1617 * gst_audio_converter_get_out_frames().
1619 * Returns: %TRUE is the conversion could be performed.
1624 gst_audio_converter_convert (GstAudioConverter * convert,
1625 GstAudioConverterFlags flags, gpointer in, gsize in_size,
1626 gpointer * out, gsize * out_size)
1631 g_return_val_if_fail (convert != NULL, FALSE);
1632 g_return_val_if_fail (flags ^ GST_AUDIO_CONVERTER_FLAG_IN_WRITABLE, FALSE);
1634 in_frames = in_size / convert->in.bpf;
1635 out_frames = gst_audio_converter_get_out_frames (convert, in_frames);
1637 *out_size = out_frames * convert->out.bpf;
1638 *out = g_malloc0 (*out_size);
1640 return gst_audio_converter_samples (convert, flags, &in, in_frames, out,
1645 * gst_audio_converter_supports_inplace:
1646 * @convert: a #GstAudioConverter
1648 * Returns whether the audio converter can perform the conversion in-place.
1649 * The return value would be typically input to gst_base_transform_set_in_place()
1651 * Returns: %TRUE when the conversion can be done in place.
1656 gst_audio_converter_supports_inplace (GstAudioConverter * convert)
1658 return convert->in_place;
1662 * gst_audio_converter_is_passthrough:
1664 * Returns whether the audio converter will operate in passthrough mode.
1665 * The return value would be typically input to gst_base_transform_set_passthrough()
1667 * Returns: %TRUE when no conversion will actually occur.
1672 gst_audio_converter_is_passthrough (GstAudioConverter * convert)
1674 return convert->passthrough;