• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2005 Wim Taymans <wim at fluendo dot com>
3  *           (C) 2015 Wim Taymans <wim.taymans@gmail.com>
4  *
5  * audioconverter.c: Convert audio to different audio formats automatically
6  *
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.
11  *
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.
16  *
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.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include <math.h>
28 #include <string.h>
29 
30 #include "audio-converter.h"
31 #include "gstaudiopack.h"
32 
33 /**
34  * SECTION:gstaudioconverter
35  * @title: GstAudioConverter
36  * @short_description: Generic audio conversion
37  *
38  * This object is used to convert audio samples from one format to another.
39  * The object can perform conversion of:
40  *
41  *  * audio format with optional dithering and noise shaping
42  *
43  *  * audio samplerate
44  *
45  *  * audio channels and channel layout
46  *
47  */
48 
49 #ifndef GST_DISABLE_GST_DEBUG
50 #define GST_CAT_DEFAULT ensure_debug_category()
51 static GstDebugCategory *
ensure_debug_category(void)52 ensure_debug_category (void)
53 {
54   static gsize cat_gonce = 0;
55 
56   if (g_once_init_enter (&cat_gonce)) {
57     gsize cat_done;
58 
59     cat_done = (gsize) _gst_debug_category_new ("audio-converter", 0,
60         "audio-converter object");
61 
62     g_once_init_leave (&cat_gonce, cat_done);
63   }
64 
65   return (GstDebugCategory *) cat_gonce;
66 }
67 #else
68 #define ensure_debug_category() /* NOOP */
69 #endif /* GST_DISABLE_GST_DEBUG */
70 
71 typedef struct _AudioChain AudioChain;
72 
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,
78     gint count);
79 
80 /*                           int/int    int/float  float/int float/float
81  *
82  *  unpack                     S32          S32         F64       F64
83  *  convert                               S32->F64
84  *  channel mix                S32          F64         F64       F64
85  *  convert                                           F64->S32
86  *  quantize                   S32                      S32
87  *  pack                       S32          F64         S32       F64
88  *
89  *
90  *  interleave
91  *  deinterleave
92  *  resample
93  */
94 struct _GstAudioConverter
95 {
96   GstAudioInfo in;
97   GstAudioInfo out;
98 
99   GstStructure *config;
100 
101   GstAudioConverterFlags flags;
102   GstAudioFormat current_format;
103   GstAudioLayout current_layout;
104   gint current_channels;
105 
106   gboolean in_writable;
107   gpointer *in_data;
108   gsize in_frames;
109   gpointer *out_data;
110   gsize out_frames;
111 
112   gboolean in_place;            /* the conversion can be done in place; returned by gst_audio_converter_supports_inplace() */
113 
114   gboolean passthrough;
115 
116   /* unpack */
117   gboolean in_default;
118   gboolean unpack_ip;
119 
120   /* convert in */
121   AudioConvertFunc convert_in;
122 
123   /* channel mix */
124   gboolean mix_passthrough;
125   GstAudioChannelMixer *mix;
126 
127   /* resample */
128   GstAudioResampler *resampler;
129 
130   /* convert out */
131   AudioConvertFunc convert_out;
132 
133   /* quant */
134   GstAudioQuantize *quant;
135 
136   /* change layout */
137   GstAudioFormat chlayout_format;
138   GstAudioLayout chlayout_target;
139   gint chlayout_channels;
140 
141   /* pack */
142   gboolean out_default;
143   AudioChain *chain_end;        /* NULL for empty chain or points to the last element in the chain */
144 
145   /* endian swap */
146   AudioConvertEndianFunc swap_endian;
147 
148   AudioConvertSamplesFunc convert;
149 };
150 
151 static GstAudioConverter *
gst_audio_converter_copy(GstAudioConverter * convert)152 gst_audio_converter_copy (GstAudioConverter * convert)
153 {
154   GstAudioConverter *res =
155       gst_audio_converter_new (convert->flags, &convert->in, &convert->out,
156       convert->config);
157 
158   return res;
159 }
160 
161 G_DEFINE_BOXED_TYPE (GstAudioConverter, gst_audio_converter,
162     (GBoxedCopyFunc) gst_audio_converter_copy,
163     (GBoxedFreeFunc) gst_audio_converter_free);
164 
165 typedef gboolean (*AudioChainFunc) (AudioChain * chain, gpointer user_data);
166 typedef gpointer *(*AudioChainAllocFunc) (AudioChain * chain, gsize num_samples,
167     gpointer user_data);
168 
169 struct _AudioChain
170 {
171   AudioChain *prev;
172 
173   AudioChainFunc make_func;
174   gpointer make_func_data;
175   GDestroyNotify make_func_notify;
176 
177   const GstAudioFormatInfo *finfo;
178   gint stride;
179   gint inc;
180   gint blocks;
181 
182   gboolean pass_alloc;
183   gboolean allow_ip;
184 
185   AudioChainAllocFunc alloc_func;
186   gpointer alloc_data;
187 
188   gpointer *tmp;
189   gsize allocated_samples;
190 
191   gpointer *samples;
192   gsize num_samples;
193 };
194 
195 static AudioChain *
audio_chain_new(AudioChain * prev,GstAudioConverter * convert)196 audio_chain_new (AudioChain * prev, GstAudioConverter * convert)
197 {
198   AudioChain *chain;
199 
200   chain = g_slice_new0 (AudioChain);
201   chain->prev = prev;
202 
203   if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
204     chain->inc = 1;
205     chain->blocks = convert->current_channels;
206   } else {
207     chain->inc = convert->current_channels;
208     chain->blocks = 1;
209   }
210   chain->finfo = gst_audio_format_get_info (convert->current_format);
211   chain->stride = (chain->finfo->width * chain->inc) / 8;
212 
213   return chain;
214 }
215 
216 static void
audio_chain_set_make_func(AudioChain * chain,AudioChainFunc make_func,gpointer user_data,GDestroyNotify notify)217 audio_chain_set_make_func (AudioChain * chain,
218     AudioChainFunc make_func, gpointer user_data, GDestroyNotify notify)
219 {
220   chain->make_func = make_func;
221   chain->make_func_data = user_data;
222   chain->make_func_notify = notify;
223 }
224 
225 static void
audio_chain_free(AudioChain * chain)226 audio_chain_free (AudioChain * chain)
227 {
228   GST_LOG ("free chain %p", chain);
229   if (chain->make_func_notify)
230     chain->make_func_notify (chain->make_func_data);
231   g_free (chain->tmp);
232   g_slice_free (AudioChain, chain);
233 }
234 
235 static gpointer *
audio_chain_alloc_samples(AudioChain * chain,gsize num_samples)236 audio_chain_alloc_samples (AudioChain * chain, gsize num_samples)
237 {
238   return chain->alloc_func (chain, num_samples, chain->alloc_data);
239 }
240 
241 static void
audio_chain_set_samples(AudioChain * chain,gpointer * samples,gsize num_samples)242 audio_chain_set_samples (AudioChain * chain, gpointer * samples,
243     gsize num_samples)
244 {
245   GST_LOG ("set samples %p %" G_GSIZE_FORMAT, samples, num_samples);
246 
247   chain->samples = samples;
248   chain->num_samples = num_samples;
249 }
250 
251 static gpointer *
audio_chain_get_samples(AudioChain * chain,gsize * avail)252 audio_chain_get_samples (AudioChain * chain, gsize * avail)
253 {
254   gpointer *res;
255 
256   if (!chain->samples)
257     chain->make_func (chain, chain->make_func_data);
258 
259   res = chain->samples;
260   *avail = chain->num_samples;
261   chain->samples = NULL;
262 
263   return res;
264 }
265 
266 /*
267 static guint
268 get_opt_uint (GstAudioConverter * convert, const gchar * opt, guint def)
269 {
270   guint res;
271   if (!gst_structure_get_uint (convert->config, opt, &res))
272     res = def;
273   return res;
274 }
275 */
276 
277 static gint
get_opt_enum(GstAudioConverter * convert,const gchar * opt,GType type,gint def)278 get_opt_enum (GstAudioConverter * convert, const gchar * opt, GType type,
279     gint def)
280 {
281   gint res;
282   if (!gst_structure_get_enum (convert->config, opt, type, &res))
283     res = def;
284   return res;
285 }
286 
287 static const GValue *
get_opt_value(GstAudioConverter * convert,const gchar * opt)288 get_opt_value (GstAudioConverter * convert, const gchar * opt)
289 {
290   return gst_structure_get_value (convert->config, opt);
291 }
292 
293 #define DEFAULT_OPT_RESAMPLER_METHOD GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL
294 #define DEFAULT_OPT_DITHER_METHOD GST_AUDIO_DITHER_NONE
295 #define DEFAULT_OPT_NOISE_SHAPING_METHOD GST_AUDIO_NOISE_SHAPING_NONE
296 #define DEFAULT_OPT_QUANTIZATION 1
297 
298 #define GET_OPT_RESAMPLER_METHOD(c) get_opt_enum(c, \
299     GST_AUDIO_CONVERTER_OPT_RESAMPLER_METHOD, GST_TYPE_AUDIO_RESAMPLER_METHOD, \
300     DEFAULT_OPT_RESAMPLER_METHOD)
301 #define GET_OPT_DITHER_METHOD(c) get_opt_enum(c, \
302     GST_AUDIO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_AUDIO_DITHER_METHOD, \
303     DEFAULT_OPT_DITHER_METHOD)
304 #define GET_OPT_NOISE_SHAPING_METHOD(c) get_opt_enum(c, \
305     GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD, GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, \
306     DEFAULT_OPT_NOISE_SHAPING_METHOD)
307 #define GET_OPT_QUANTIZATION(c) get_opt_uint(c, \
308     GST_AUDIO_CONVERTER_OPT_QUANTIZATION, DEFAULT_OPT_QUANTIZATION)
309 #define GET_OPT_MIX_MATRIX(c) get_opt_value(c, \
310     GST_AUDIO_CONVERTER_OPT_MIX_MATRIX)
311 
312 static gboolean
copy_config(GQuark field_id,const GValue * value,gpointer user_data)313 copy_config (GQuark field_id, const GValue * value, gpointer user_data)
314 {
315   GstAudioConverter *convert = user_data;
316 
317   gst_structure_id_set_value (convert->config, field_id, value);
318 
319   return TRUE;
320 }
321 
322 /**
323  * gst_audio_converter_update_config:
324  * @convert: a #GstAudioConverter
325  * @in_rate: input rate
326  * @out_rate: output rate
327  * @config: (transfer full) (allow-none): a #GstStructure or %NULL
328  *
329  * Set @in_rate, @out_rate and @config as extra configuration for @convert.
330  *
331  * @in_rate and @out_rate specify the new sample rates of input and output
332  * formats. A value of 0 leaves the sample rate unchanged.
333  *
334  * @config can be %NULL, in which case, the current configuration is not
335  * changed.
336  *
337  * If the parameters in @config can not be set exactly, this function returns
338  * %FALSE and will try to update as much state as possible. The new state can
339  * then be retrieved and refined with gst_audio_converter_get_config().
340  *
341  * Look at the `GST_AUDIO_CONVERTER_OPT_*` fields to check valid configuration
342  * option and values.
343  *
344  * Returns: %TRUE when the new parameters could be set
345  */
346 gboolean
gst_audio_converter_update_config(GstAudioConverter * convert,gint in_rate,gint out_rate,GstStructure * config)347 gst_audio_converter_update_config (GstAudioConverter * convert,
348     gint in_rate, gint out_rate, GstStructure * config)
349 {
350   g_return_val_if_fail (convert != NULL, FALSE);
351   g_return_val_if_fail ((in_rate == 0 && out_rate == 0) ||
352       convert->flags & GST_AUDIO_CONVERTER_FLAG_VARIABLE_RATE, FALSE);
353 
354   GST_LOG ("new rate %d -> %d", in_rate, out_rate);
355 
356   if (in_rate <= 0)
357     in_rate = convert->in.rate;
358   if (out_rate <= 0)
359     out_rate = convert->out.rate;
360 
361   convert->in.rate = in_rate;
362   convert->out.rate = out_rate;
363 
364   if (convert->resampler)
365     gst_audio_resampler_update (convert->resampler, in_rate, out_rate, config);
366 
367   if (config) {
368     gst_structure_foreach (config, copy_config, convert);
369     gst_structure_free (config);
370   }
371 
372   return TRUE;
373 }
374 
375 /**
376  * gst_audio_converter_get_config:
377  * @convert: a #GstAudioConverter
378  * @in_rate: (out) (optional): result input rate
379  * @out_rate: (out) (optional): result output rate
380  *
381  * Get the current configuration of @convert.
382  *
383  * Returns: (transfer none):
384  *   a #GstStructure that remains valid for as long as @convert is valid
385  *   or until gst_audio_converter_update_config() is called.
386  */
387 const GstStructure *
gst_audio_converter_get_config(GstAudioConverter * convert,gint * in_rate,gint * out_rate)388 gst_audio_converter_get_config (GstAudioConverter * convert,
389     gint * in_rate, gint * out_rate)
390 {
391   g_return_val_if_fail (convert != NULL, NULL);
392 
393   if (in_rate)
394     *in_rate = convert->in.rate;
395   if (out_rate)
396     *out_rate = convert->out.rate;
397 
398   return convert->config;
399 }
400 
401 static gpointer *
get_output_samples(AudioChain * chain,gsize num_samples,gpointer user_data)402 get_output_samples (AudioChain * chain, gsize num_samples, gpointer user_data)
403 {
404   GstAudioConverter *convert = user_data;
405 
406   GST_LOG ("output samples %p %" G_GSIZE_FORMAT, convert->out_data,
407       num_samples);
408 
409   return convert->out_data;
410 }
411 
412 #define MEM_ALIGN(m,a) ((gint8 *)((guintptr)((gint8 *)(m) + ((a)-1)) & ~((a)-1)))
413 #define ALIGN 16
414 
415 static gpointer *
get_temp_samples(AudioChain * chain,gsize num_samples,gpointer user_data)416 get_temp_samples (AudioChain * chain, gsize num_samples, gpointer user_data)
417 {
418   if (num_samples > chain->allocated_samples) {
419     gint i;
420     gint8 *s;
421     gsize stride = GST_ROUND_UP_N (num_samples * chain->stride, ALIGN);
422     /* first part contains the pointers, second part the data, add some extra bytes
423      * for alignment */
424     gsize needed = (stride + sizeof (gpointer)) * chain->blocks + ALIGN - 1;
425 
426     GST_DEBUG ("alloc samples %d %" G_GSIZE_FORMAT " %" G_GSIZE_FORMAT,
427         chain->stride, num_samples, needed);
428     chain->tmp = g_realloc (chain->tmp, needed);
429     chain->allocated_samples = num_samples;
430 
431     /* pointer to the data, make sure it's 16 bytes aligned */
432     s = MEM_ALIGN (&chain->tmp[chain->blocks], ALIGN);
433 
434     /* set up the pointers */
435     for (i = 0; i < chain->blocks; i++)
436       chain->tmp[i] = s + i * stride;
437   }
438   GST_LOG ("temp samples %p %" G_GSIZE_FORMAT, chain->tmp, num_samples);
439 
440   return chain->tmp;
441 }
442 
443 static gboolean
do_unpack(AudioChain * chain,gpointer user_data)444 do_unpack (AudioChain * chain, gpointer user_data)
445 {
446   GstAudioConverter *convert = user_data;
447   gsize num_samples;
448   gpointer *tmp;
449   gboolean in_writable;
450 
451   in_writable = convert->in_writable;
452   num_samples = convert->in_frames;
453 
454   if (!chain->allow_ip || !in_writable || !convert->in_default) {
455     gint i;
456 
457     if (in_writable && chain->allow_ip) {
458       tmp = convert->in_data;
459       GST_LOG ("unpack in-place %p, %" G_GSIZE_FORMAT, tmp, num_samples);
460     } else {
461       tmp = audio_chain_alloc_samples (chain, num_samples);
462       GST_LOG ("unpack to tmp %p, %" G_GSIZE_FORMAT, tmp, num_samples);
463     }
464 
465     if (convert->in_data) {
466       for (i = 0; i < chain->blocks; i++) {
467         if (convert->in_default) {
468           GST_LOG ("copy %p, %p, %" G_GSIZE_FORMAT, tmp[i], convert->in_data[i],
469               num_samples);
470           memcpy (tmp[i], convert->in_data[i], num_samples * chain->stride);
471         } else {
472           GST_LOG ("unpack %p, %p, %" G_GSIZE_FORMAT, tmp[i],
473               convert->in_data[i], num_samples);
474           convert->in.finfo->unpack_func (convert->in.finfo,
475               GST_AUDIO_PACK_FLAG_TRUNCATE_RANGE, tmp[i], convert->in_data[i],
476               num_samples * chain->inc);
477         }
478       }
479     } else {
480       for (i = 0; i < chain->blocks; i++) {
481         gst_audio_format_info_fill_silence (chain->finfo, tmp[i],
482             num_samples * chain->inc);
483       }
484     }
485   } else {
486     tmp = convert->in_data;
487     GST_LOG ("get in samples %p", tmp);
488   }
489   audio_chain_set_samples (chain, tmp, num_samples);
490 
491   return TRUE;
492 }
493 
494 static gboolean
do_convert_in(AudioChain * chain,gpointer user_data)495 do_convert_in (AudioChain * chain, gpointer user_data)
496 {
497   gsize num_samples;
498   GstAudioConverter *convert = user_data;
499   gpointer *in, *out;
500   gint i;
501 
502   in = audio_chain_get_samples (chain->prev, &num_samples);
503   out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
504   GST_LOG ("convert in %p, %p, %" G_GSIZE_FORMAT, in, out, num_samples);
505 
506   for (i = 0; i < chain->blocks; i++)
507     convert->convert_in (out[i], in[i], num_samples * chain->inc);
508 
509   audio_chain_set_samples (chain, out, num_samples);
510 
511   return TRUE;
512 }
513 
514 static gboolean
do_mix(AudioChain * chain,gpointer user_data)515 do_mix (AudioChain * chain, gpointer user_data)
516 {
517   gsize num_samples;
518   GstAudioConverter *convert = user_data;
519   gpointer *in, *out;
520 
521   in = audio_chain_get_samples (chain->prev, &num_samples);
522   out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
523   GST_LOG ("mix %p, %p, %" G_GSIZE_FORMAT, in, out, num_samples);
524 
525   gst_audio_channel_mixer_samples (convert->mix, in, out, num_samples);
526 
527   audio_chain_set_samples (chain, out, num_samples);
528 
529   return TRUE;
530 }
531 
532 static gboolean
do_resample(AudioChain * chain,gpointer user_data)533 do_resample (AudioChain * chain, gpointer user_data)
534 {
535   GstAudioConverter *convert = user_data;
536   gpointer *in, *out;
537   gsize in_frames, out_frames;
538 
539   in = audio_chain_get_samples (chain->prev, &in_frames);
540   out_frames = convert->out_frames;
541   out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, out_frames));
542 
543   GST_LOG ("resample %p %p,%" G_GSIZE_FORMAT " %" G_GSIZE_FORMAT, in,
544       out, in_frames, out_frames);
545 
546   gst_audio_resampler_resample (convert->resampler, in, in_frames, out,
547       out_frames);
548 
549   audio_chain_set_samples (chain, out, out_frames);
550 
551   return TRUE;
552 }
553 
554 static gboolean
do_convert_out(AudioChain * chain,gpointer user_data)555 do_convert_out (AudioChain * chain, gpointer user_data)
556 {
557   GstAudioConverter *convert = user_data;
558   gsize num_samples;
559   gpointer *in, *out;
560   gint i;
561 
562   in = audio_chain_get_samples (chain->prev, &num_samples);
563   out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
564   GST_LOG ("convert out %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
565 
566   for (i = 0; i < chain->blocks; i++)
567     convert->convert_out (out[i], in[i], num_samples * chain->inc);
568 
569   audio_chain_set_samples (chain, out, num_samples);
570 
571   return TRUE;
572 }
573 
574 static gboolean
do_quantize(AudioChain * chain,gpointer user_data)575 do_quantize (AudioChain * chain, gpointer user_data)
576 {
577   GstAudioConverter *convert = user_data;
578   gsize num_samples;
579   gpointer *in, *out;
580 
581   in = audio_chain_get_samples (chain->prev, &num_samples);
582   out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
583   GST_LOG ("quantize %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
584 
585   if (in && out)
586     gst_audio_quantize_samples (convert->quant, in, out, num_samples);
587 
588   audio_chain_set_samples (chain, out, num_samples);
589 
590   return TRUE;
591 }
592 
593 #define MAKE_INTERLEAVE_FUNC(type) \
594 static inline void \
595 interleave_##type (const type * in[], type * out[], \
596     gsize num_samples, gint channels) \
597 { \
598   gsize s; \
599   gint c; \
600   for (s = 0; s < num_samples; s++) { \
601     for (c = 0; c < channels; c++) { \
602       out[0][s * channels + c] = in[c][s]; \
603     } \
604   } \
605 }
606 
607 #define MAKE_DEINTERLEAVE_FUNC(type) \
608 static inline void \
609 deinterleave_##type (const type * in[], type * out[], \
610     gsize num_samples, gint channels) \
611 { \
612   gsize s; \
613   gint c; \
614   for (s = 0; s < num_samples; s++) { \
615     for (c = 0; c < channels; c++) { \
616       out[c][s] = in[0][s * channels + c]; \
617     } \
618   } \
619 }
620 
621 MAKE_INTERLEAVE_FUNC (gint16);
622 MAKE_INTERLEAVE_FUNC (gint32);
623 MAKE_INTERLEAVE_FUNC (gfloat);
624 MAKE_INTERLEAVE_FUNC (gdouble);
625 MAKE_DEINTERLEAVE_FUNC (gint16);
626 MAKE_DEINTERLEAVE_FUNC (gint32);
627 MAKE_DEINTERLEAVE_FUNC (gfloat);
628 MAKE_DEINTERLEAVE_FUNC (gdouble);
629 
630 static gboolean
do_change_layout(AudioChain * chain,gpointer user_data)631 do_change_layout (AudioChain * chain, gpointer user_data)
632 {
633   GstAudioConverter *convert = user_data;
634   GstAudioFormat format = convert->chlayout_format;
635   GstAudioLayout out_layout = convert->chlayout_target;
636   gint channels = convert->chlayout_channels;
637   gsize num_samples;
638   gpointer *in, *out;
639 
640   in = audio_chain_get_samples (chain->prev, &num_samples);
641   out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
642 
643   if (out_layout == GST_AUDIO_LAYOUT_INTERLEAVED) {
644     /* interleave */
645     GST_LOG ("interleaving %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
646     switch (format) {
647       case GST_AUDIO_FORMAT_S16:
648         interleave_gint16 ((const gint16 **) in, (gint16 **) out,
649             num_samples, channels);
650         break;
651       case GST_AUDIO_FORMAT_S32:
652         interleave_gint32 ((const gint32 **) in, (gint32 **) out,
653             num_samples, channels);
654         break;
655       case GST_AUDIO_FORMAT_F32:
656         interleave_gfloat ((const gfloat **) in, (gfloat **) out,
657             num_samples, channels);
658         break;
659       case GST_AUDIO_FORMAT_F64:
660         interleave_gdouble ((const gdouble **) in, (gdouble **) out,
661             num_samples, channels);
662         break;
663       default:
664         g_assert_not_reached ();
665         break;
666     }
667   } else {
668     /* deinterleave */
669     GST_LOG ("deinterleaving %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
670     switch (format) {
671       case GST_AUDIO_FORMAT_S16:
672         deinterleave_gint16 ((const gint16 **) in, (gint16 **) out,
673             num_samples, channels);
674         break;
675       case GST_AUDIO_FORMAT_S32:
676         deinterleave_gint32 ((const gint32 **) in, (gint32 **) out,
677             num_samples, channels);
678         break;
679       case GST_AUDIO_FORMAT_F32:
680         deinterleave_gfloat ((const gfloat **) in, (gfloat **) out,
681             num_samples, channels);
682         break;
683       case GST_AUDIO_FORMAT_F64:
684         deinterleave_gdouble ((const gdouble **) in, (gdouble **) out,
685             num_samples, channels);
686         break;
687       default:
688         g_assert_not_reached ();
689         break;
690     }
691   }
692 
693   audio_chain_set_samples (chain, out, num_samples);
694   return TRUE;
695 }
696 
697 static gboolean
is_intermediate_format(GstAudioFormat format)698 is_intermediate_format (GstAudioFormat format)
699 {
700   return (format == GST_AUDIO_FORMAT_S16 ||
701       format == GST_AUDIO_FORMAT_S32 ||
702       format == GST_AUDIO_FORMAT_F32 || format == GST_AUDIO_FORMAT_F64);
703 }
704 
705 static AudioChain *
chain_unpack(GstAudioConverter * convert)706 chain_unpack (GstAudioConverter * convert)
707 {
708   AudioChain *prev;
709   GstAudioInfo *in = &convert->in;
710   GstAudioInfo *out = &convert->out;
711   gboolean same_format;
712 
713   same_format = in->finfo->format == out->finfo->format;
714 
715   /* do not unpack if we have the same input format as the output format
716    * and it is a possible intermediate format */
717   if (same_format && is_intermediate_format (in->finfo->format)) {
718     convert->current_format = in->finfo->format;
719   } else {
720     convert->current_format = in->finfo->unpack_format;
721   }
722   convert->current_layout = in->layout;
723   convert->current_channels = in->channels;
724 
725   convert->in_default = convert->current_format == in->finfo->format;
726 
727   GST_INFO ("unpack format %s to %s",
728       gst_audio_format_to_string (in->finfo->format),
729       gst_audio_format_to_string (convert->current_format));
730 
731   prev = audio_chain_new (NULL, convert);
732   prev->allow_ip = prev->finfo->width <= in->finfo->width;
733   prev->pass_alloc = FALSE;
734   audio_chain_set_make_func (prev, do_unpack, convert, NULL);
735 
736   return prev;
737 }
738 
739 static AudioChain *
chain_convert_in(GstAudioConverter * convert,AudioChain * prev)740 chain_convert_in (GstAudioConverter * convert, AudioChain * prev)
741 {
742   gboolean in_int, out_int;
743   GstAudioInfo *in = &convert->in;
744   GstAudioInfo *out = &convert->out;
745 
746   in_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo);
747   out_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo);
748 
749   if (in_int && !out_int) {
750     GST_INFO ("convert S32 to F64");
751     convert->convert_in = (AudioConvertFunc) audio_orc_s32_to_double;
752     convert->current_format = GST_AUDIO_FORMAT_F64;
753 
754     prev = audio_chain_new (prev, convert);
755     prev->allow_ip = FALSE;
756     prev->pass_alloc = FALSE;
757     audio_chain_set_make_func (prev, do_convert_in, convert, NULL);
758   }
759   return prev;
760 }
761 
762 static gboolean
check_mix_matrix(guint in_channels,guint out_channels,const GValue * value)763 check_mix_matrix (guint in_channels, guint out_channels, const GValue * value)
764 {
765   guint i, j;
766 
767   /* audio-channel-mixer will generate an identity matrix */
768   if (gst_value_array_get_size (value) == 0)
769     return TRUE;
770 
771   if (gst_value_array_get_size (value) != out_channels) {
772     GST_ERROR ("Invalid mix matrix size, should be %d", out_channels);
773     goto fail;
774   }
775 
776   for (j = 0; j < out_channels; j++) {
777     const GValue *row = gst_value_array_get_value (value, j);
778 
779     if (gst_value_array_get_size (row) != in_channels) {
780       GST_ERROR ("Invalid mix matrix row size, should be %d", in_channels);
781       goto fail;
782     }
783 
784     for (i = 0; i < in_channels; i++) {
785       const GValue *itm;
786 
787       itm = gst_value_array_get_value (row, i);
788       if (!G_VALUE_HOLDS_FLOAT (itm)) {
789         GST_ERROR ("Invalid mix matrix element type, should be float");
790         goto fail;
791       }
792     }
793   }
794 
795   return TRUE;
796 
797 fail:
798   return FALSE;
799 }
800 
801 static gfloat **
mix_matrix_from_g_value(guint in_channels,guint out_channels,const GValue * value)802 mix_matrix_from_g_value (guint in_channels, guint out_channels,
803     const GValue * value)
804 {
805   guint i, j;
806   gfloat **matrix = g_new (gfloat *, in_channels);
807 
808   for (i = 0; i < in_channels; i++)
809     matrix[i] = g_new (gfloat, out_channels);
810 
811   for (j = 0; j < out_channels; j++) {
812     const GValue *row = gst_value_array_get_value (value, j);
813 
814     for (i = 0; i < in_channels; i++) {
815       const GValue *itm;
816       gfloat coefficient;
817 
818       itm = gst_value_array_get_value (row, i);
819       coefficient = g_value_get_float (itm);
820       matrix[i][j] = coefficient;
821     }
822   }
823 
824   return matrix;
825 }
826 
827 static AudioChain *
chain_mix(GstAudioConverter * convert,AudioChain * prev)828 chain_mix (GstAudioConverter * convert, AudioChain * prev)
829 {
830   GstAudioInfo *in = &convert->in;
831   GstAudioInfo *out = &convert->out;
832   GstAudioFormat format = convert->current_format;
833   const GValue *opt_matrix = GET_OPT_MIX_MATRIX (convert);
834   GstAudioChannelMixerFlags flags = 0;
835 
836   convert->current_channels = out->channels;
837 
838   /* keep the input layout */
839   if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
840     flags |= GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN;
841     flags |= GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT;
842   }
843 
844   if (opt_matrix) {
845     gfloat **matrix = NULL;
846 
847     if (gst_value_array_get_size (opt_matrix))
848       matrix =
849           mix_matrix_from_g_value (in->channels, out->channels, opt_matrix);
850 
851     convert->mix =
852         gst_audio_channel_mixer_new_with_matrix (flags, format, in->channels,
853         out->channels, matrix);
854   } else {
855     flags |=
856         GST_AUDIO_INFO_IS_UNPOSITIONED (in) ?
857         GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_IN : 0;
858     flags |=
859         GST_AUDIO_INFO_IS_UNPOSITIONED (out) ?
860         GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_OUT : 0;
861 
862     convert->mix =
863         gst_audio_channel_mixer_new (flags, format, in->channels, in->position,
864         out->channels, out->position);
865   }
866 
867   convert->mix_passthrough =
868       gst_audio_channel_mixer_is_passthrough (convert->mix);
869   GST_INFO ("mix format %s, passthrough %d, in_channels %d, out_channels %d",
870       gst_audio_format_to_string (format), convert->mix_passthrough,
871       in->channels, out->channels);
872 
873   if (!convert->mix_passthrough) {
874     prev = audio_chain_new (prev, convert);
875     prev->allow_ip = FALSE;
876     prev->pass_alloc = FALSE;
877     audio_chain_set_make_func (prev, do_mix, convert, NULL);
878   }
879   return prev;
880 }
881 
882 static AudioChain *
chain_resample(GstAudioConverter * convert,AudioChain * prev)883 chain_resample (GstAudioConverter * convert, AudioChain * prev)
884 {
885   GstAudioInfo *in = &convert->in;
886   GstAudioInfo *out = &convert->out;
887   GstAudioResamplerMethod method;
888   GstAudioResamplerFlags flags;
889   GstAudioFormat format = convert->current_format;
890   gint channels = convert->current_channels;
891   gboolean variable_rate;
892 
893   variable_rate = convert->flags & GST_AUDIO_CONVERTER_FLAG_VARIABLE_RATE;
894 
895   if (in->rate != out->rate || variable_rate) {
896     method = GET_OPT_RESAMPLER_METHOD (convert);
897 
898     flags = 0;
899     if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
900       flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_IN;
901     }
902     /* if the resampler is activated, it is optimal to change layout here */
903     if (out->layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
904       flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_OUT;
905     }
906     convert->current_layout = out->layout;
907 
908     if (variable_rate)
909       flags |= GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE;
910 
911     convert->resampler =
912         gst_audio_resampler_new (method, flags, format, channels, in->rate,
913         out->rate, convert->config);
914 
915     prev = audio_chain_new (prev, convert);
916     prev->allow_ip = FALSE;
917     prev->pass_alloc = FALSE;
918     audio_chain_set_make_func (prev, do_resample, convert, NULL);
919   }
920   return prev;
921 }
922 
923 static AudioChain *
chain_convert_out(GstAudioConverter * convert,AudioChain * prev)924 chain_convert_out (GstAudioConverter * convert, AudioChain * prev)
925 {
926   gboolean in_int, out_int;
927   GstAudioInfo *in = &convert->in;
928   GstAudioInfo *out = &convert->out;
929 
930   in_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo);
931   out_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo);
932 
933   if (!in_int && out_int) {
934     convert->convert_out = (AudioConvertFunc) audio_orc_double_to_s32;
935     convert->current_format = GST_AUDIO_FORMAT_S32;
936 
937     GST_INFO ("convert F64 to S32");
938     prev = audio_chain_new (prev, convert);
939     prev->allow_ip = TRUE;
940     prev->pass_alloc = FALSE;
941     audio_chain_set_make_func (prev, do_convert_out, convert, NULL);
942   }
943   return prev;
944 }
945 
946 static AudioChain *
chain_quantize(GstAudioConverter * convert,AudioChain * prev)947 chain_quantize (GstAudioConverter * convert, AudioChain * prev)
948 {
949   const GstAudioFormatInfo *cur_finfo;
950   GstAudioInfo *out = &convert->out;
951   gint in_depth, out_depth;
952   gboolean in_int, out_int;
953   GstAudioDitherMethod dither;
954   GstAudioNoiseShapingMethod ns;
955 
956   dither = GET_OPT_DITHER_METHOD (convert);
957   ns = GET_OPT_NOISE_SHAPING_METHOD (convert);
958 
959   cur_finfo = gst_audio_format_get_info (convert->current_format);
960 
961   in_depth = GST_AUDIO_FORMAT_INFO_DEPTH (cur_finfo);
962   out_depth = GST_AUDIO_FORMAT_INFO_DEPTH (out->finfo);
963   GST_INFO ("depth in %d, out %d", in_depth, out_depth);
964 
965   in_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (cur_finfo);
966   out_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo);
967 
968   /* Don't dither or apply noise shaping if target depth is bigger than 20 bits
969    * as DA converters only can do a SNR up to 20 bits in reality.
970    * Also don't dither or apply noise shaping if target depth is larger than
971    * source depth. */
972   if (out_depth > 20 || (in_int && out_depth >= in_depth)) {
973     dither = GST_AUDIO_DITHER_NONE;
974     ns = GST_AUDIO_NOISE_SHAPING_NONE;
975     GST_INFO ("using no dither and noise shaping");
976   } else {
977     GST_INFO ("using dither %d and noise shaping %d", dither, ns);
978     /* Use simple error feedback when output sample rate is smaller than
979      * 32000 as the other methods might move the noise to audible ranges */
980     if (ns > GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK && out->rate < 32000)
981       ns = GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK;
982   }
983   /* we still want to run the quantization step when reducing bits to get
984    * the rounding correct */
985   if (out_int && out_depth < 32
986       && convert->current_format == GST_AUDIO_FORMAT_S32) {
987     GST_INFO ("quantize to %d bits, dither %d, ns %d", out_depth, dither, ns);
988     convert->quant =
989         gst_audio_quantize_new (dither, ns, 0, convert->current_format,
990         out->channels, 1U << (32 - out_depth));
991 
992     prev = audio_chain_new (prev, convert);
993     prev->allow_ip = TRUE;
994     prev->pass_alloc = TRUE;
995     audio_chain_set_make_func (prev, do_quantize, convert, NULL);
996   }
997   return prev;
998 }
999 
1000 static AudioChain *
chain_change_layout(GstAudioConverter * convert,AudioChain * prev)1001 chain_change_layout (GstAudioConverter * convert, AudioChain * prev)
1002 {
1003   GstAudioInfo *out = &convert->out;
1004 
1005   if (convert->current_layout != out->layout) {
1006     convert->current_layout = out->layout;
1007 
1008     /* if there is only 1 channel, layouts are identical */
1009     if (convert->current_channels > 1) {
1010       convert->chlayout_target = convert->current_layout;
1011       convert->chlayout_format = convert->current_format;
1012       convert->chlayout_channels = convert->current_channels;
1013 
1014       prev = audio_chain_new (prev, convert);
1015       prev->allow_ip = FALSE;
1016       prev->pass_alloc = FALSE;
1017       audio_chain_set_make_func (prev, do_change_layout, convert, NULL);
1018     }
1019   }
1020   return prev;
1021 }
1022 
1023 static AudioChain *
chain_pack(GstAudioConverter * convert,AudioChain * prev)1024 chain_pack (GstAudioConverter * convert, AudioChain * prev)
1025 {
1026   GstAudioInfo *out = &convert->out;
1027   GstAudioFormat format = convert->current_format;
1028 
1029   convert->current_format = out->finfo->format;
1030 
1031   convert->out_default = format == out->finfo->format;
1032   GST_INFO ("pack format %s to %s", gst_audio_format_to_string (format),
1033       gst_audio_format_to_string (out->finfo->format));
1034 
1035   return prev;
1036 }
1037 
1038 static void
setup_allocators(GstAudioConverter * convert)1039 setup_allocators (GstAudioConverter * convert)
1040 {
1041   AudioChain *chain;
1042   AudioChainAllocFunc alloc_func;
1043   gboolean allow_ip;
1044 
1045   /* start with using dest if we can directly write into it */
1046   if (convert->out_default) {
1047     alloc_func = get_output_samples;
1048     allow_ip = FALSE;
1049   } else {
1050     alloc_func = get_temp_samples;
1051     allow_ip = TRUE;
1052   }
1053   /* now walk backwards, we try to write into the dest samples directly
1054    * and keep track if the source needs to be writable */
1055   for (chain = convert->chain_end; chain; chain = chain->prev) {
1056     chain->alloc_func = alloc_func;
1057     chain->alloc_data = convert;
1058     chain->allow_ip = allow_ip && chain->allow_ip;
1059     GST_LOG ("chain %p: %d %d", chain, allow_ip, chain->allow_ip);
1060 
1061     if (!chain->pass_alloc) {
1062       /* can't pass allocator, make new temp line allocator */
1063       alloc_func = get_temp_samples;
1064       allow_ip = TRUE;
1065     }
1066   }
1067 }
1068 
1069 static gboolean
converter_passthrough(GstAudioConverter * convert,GstAudioConverterFlags flags,gpointer in[],gsize in_frames,gpointer out[],gsize out_frames)1070 converter_passthrough (GstAudioConverter * convert,
1071     GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1072     gpointer out[], gsize out_frames)
1073 {
1074   gint i;
1075   AudioChain *chain;
1076   gsize samples;
1077 
1078   /* in-place passthrough -> do nothing */
1079   if (in == out) {
1080     g_assert (convert->in_place);
1081     return TRUE;
1082   }
1083 
1084   chain = convert->chain_end;
1085 
1086   samples = in_frames * chain->inc;
1087 
1088   GST_LOG ("passthrough: %" G_GSIZE_FORMAT " / %" G_GSIZE_FORMAT " samples",
1089       in_frames, samples);
1090 
1091   if (in) {
1092     gsize bytes;
1093 
1094     bytes = samples * (convert->in.bpf / convert->in.channels);
1095 
1096     for (i = 0; i < chain->blocks; i++) {
1097       if (out[i] == in[i]) {
1098         g_assert (convert->in_place);
1099         continue;
1100       }
1101 
1102       memcpy (out[i], in[i], bytes);
1103     }
1104   } else {
1105     for (i = 0; i < chain->blocks; i++)
1106       gst_audio_format_info_fill_silence (convert->in.finfo, out[i], samples);
1107   }
1108   return TRUE;
1109 }
1110 
1111 /* perform LE<->BE conversion on a block of @count 16-bit samples
1112  * dst may equal src for in-place conversion
1113  */
1114 static void
converter_swap_endian_16(gpointer dst,const gpointer src,gint count)1115 converter_swap_endian_16 (gpointer dst, const gpointer src, gint count)
1116 {
1117   guint16 *out = dst;
1118   const guint16 *in = src;
1119   gint i;
1120 
1121   for (i = 0; i < count; i++)
1122     out[i] = GUINT16_SWAP_LE_BE (in[i]);
1123 }
1124 
1125 /* perform LE<->BE conversion on a block of @count 24-bit samples
1126  * dst may equal src for in-place conversion
1127  *
1128  * naive algorithm, which performs better with -O3 and worse with -O2
1129  * than the commented out optimized algorithm below
1130  */
1131 static void
converter_swap_endian_24(gpointer dst,const gpointer src,gint count)1132 converter_swap_endian_24 (gpointer dst, const gpointer src, gint count)
1133 {
1134   guint8 *out = dst;
1135   const guint8 *in = src;
1136   gint i;
1137 
1138   count *= 3;
1139 
1140   for (i = 0; i < count; i += 3) {
1141     guint8 x = in[i + 0];
1142     out[i + 0] = in[i + 2];
1143     out[i + 1] = in[i + 1];
1144     out[i + 2] = x;
1145   }
1146 }
1147 
1148 /* the below code performs better with -O2 but worse with -O3 */
1149 #if 0
1150 /* perform LE<->BE conversion on a block of @count 24-bit samples
1151  * dst may equal src for in-place conversion
1152  *
1153  * assumes that dst and src are 32-bit aligned
1154  */
1155 static void
1156 converter_swap_endian_24 (gpointer dst, const gpointer src, gint count)
1157 {
1158   guint32 *out = dst;
1159   const guint32 *in = src;
1160   guint8 *out8;
1161   const guint8 *in8;
1162   gint i;
1163 
1164   /* first convert 24-bit samples in multiples of 4 reading 3x 32-bits in one cycle
1165    *
1166    * input:               A1 B1 C1 A2 , B2 C2 A3 B3 , C3 A4 B4 C4
1167    * 32-bit endian swap:  A2 C1 B1 A1 , B3 A3 C2 B2 , C4 B4 A4 C3
1168    *                      <--  x  -->   <--  y  --> , <--  z  -->
1169    *
1170    * desired output:      C1 B1 A1 C2 , B2 A2 C3 B3 , A3 C4 B4 A4
1171    */
1172   for (i = 0; i < count / 4; i++, in += 3, out += 3) {
1173     guint32 x, y, z;
1174 
1175     x = GUINT32_SWAP_LE_BE (in[0]);
1176     y = GUINT32_SWAP_LE_BE (in[1]);
1177     z = GUINT32_SWAP_LE_BE (in[2]);
1178 
1179 #if G_BYTE_ORDER == G_BIG_ENDIAN
1180     out[0] = (x << 8) + ((y >> 8) & 0xff);
1181     out[1] = (in[1] & 0xff0000ff) + ((x >> 8) & 0xff0000) + ((z << 8) & 0xff00);
1182     out[2] = (z >> 8) + ((y << 8) & 0xff000000);
1183 #else
1184     out[0] = (x >> 8) + ((y << 8) & 0xff000000);
1185     out[1] = (in[1] & 0xff0000ff) + ((x << 8) & 0xff00) + ((z >> 8) & 0xff0000);
1186     out[2] = (z << 8) + ((y >> 8) & 0xff);
1187 #endif
1188   }
1189 
1190   /* convert the remainder less efficiently */
1191   for (out8 = (guint8 *) out, in8 = (const guint8 *) in, i = 0; i < (count & 3);
1192       i++) {
1193     guint8 x = in8[i + 0];
1194     out8[i + 0] = in8[i + 2];
1195     out8[i + 1] = in8[i + 1];
1196     out8[i + 2] = x;
1197   }
1198 }
1199 #endif
1200 
1201 /* perform LE<->BE conversion on a block of @count 32-bit samples
1202  * dst may equal src for in-place conversion
1203  */
1204 static void
converter_swap_endian_32(gpointer dst,const gpointer src,gint count)1205 converter_swap_endian_32 (gpointer dst, const gpointer src, gint count)
1206 {
1207   guint32 *out = dst;
1208   const guint32 *in = src;
1209   gint i;
1210 
1211   for (i = 0; i < count; i++)
1212     out[i] = GUINT32_SWAP_LE_BE (in[i]);
1213 }
1214 
1215 /* perform LE<->BE conversion on a block of @count 64-bit samples
1216  * dst may equal src for in-place conversion
1217  */
1218 static void
converter_swap_endian_64(gpointer dst,const gpointer src,gint count)1219 converter_swap_endian_64 (gpointer dst, const gpointer src, gint count)
1220 {
1221   guint64 *out = dst;
1222   const guint64 *in = src;
1223   gint i;
1224 
1225   for (i = 0; i < count; i++)
1226     out[i] = GUINT64_SWAP_LE_BE (in[i]);
1227 }
1228 
1229 /* the worker function to perform endian-conversion only
1230  * assuming finfo and foutinfo have the same depth
1231  */
1232 static gboolean
converter_endian(GstAudioConverter * convert,GstAudioConverterFlags flags,gpointer in[],gsize in_frames,gpointer out[],gsize out_frames)1233 converter_endian (GstAudioConverter * convert,
1234     GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1235     gpointer out[], gsize out_frames)
1236 {
1237   gint i;
1238   AudioChain *chain;
1239   gsize samples;
1240 
1241   chain = convert->chain_end;
1242   samples = in_frames * chain->inc;
1243 
1244   GST_LOG ("convert endian: %" G_GSIZE_FORMAT " / %" G_GSIZE_FORMAT " samples",
1245       in_frames, samples);
1246 
1247   if (in) {
1248     for (i = 0; i < chain->blocks; i++)
1249       convert->swap_endian (out[i], in[i], samples);
1250   } else {
1251     for (i = 0; i < chain->blocks; i++)
1252       gst_audio_format_info_fill_silence (convert->in.finfo, out[i], samples);
1253   }
1254   return TRUE;
1255 }
1256 
1257 static gboolean
converter_generic(GstAudioConverter * convert,GstAudioConverterFlags flags,gpointer in[],gsize in_frames,gpointer out[],gsize out_frames)1258 converter_generic (GstAudioConverter * convert,
1259     GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1260     gpointer out[], gsize out_frames)
1261 {
1262   AudioChain *chain;
1263   gpointer *tmp;
1264   gint i;
1265   gsize produced;
1266 
1267   chain = convert->chain_end;
1268 
1269   convert->in_writable = flags & GST_AUDIO_CONVERTER_FLAG_IN_WRITABLE;
1270   convert->in_data = in;
1271   convert->in_frames = in_frames;
1272   convert->out_data = out;
1273   convert->out_frames = out_frames;
1274 
1275   /* get frames to pack */
1276   tmp = audio_chain_get_samples (chain, &produced);
1277 
1278   if (!convert->out_default && tmp && out) {
1279     GST_LOG ("pack %p, %p %" G_GSIZE_FORMAT, tmp, out, produced);
1280     /* and pack if needed */
1281     for (i = 0; i < chain->blocks; i++)
1282       convert->out.finfo->pack_func (convert->out.finfo, 0, tmp[i], out[i],
1283           produced * chain->inc);
1284   }
1285   return TRUE;
1286 }
1287 
1288 static gboolean
converter_resample(GstAudioConverter * convert,GstAudioConverterFlags flags,gpointer in[],gsize in_frames,gpointer out[],gsize out_frames)1289 converter_resample (GstAudioConverter * convert,
1290     GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1291     gpointer out[], gsize out_frames)
1292 {
1293   gst_audio_resampler_resample (convert->resampler, in, in_frames, out,
1294       out_frames);
1295 
1296   return TRUE;
1297 }
1298 
1299 #define GST_AUDIO_FORMAT_IS_ENDIAN_CONVERSION(info1, info2) \
1300 		( \
1301 			!(((info1)->flags ^ (info2)->flags) & (~GST_AUDIO_FORMAT_FLAG_UNPACK)) && \
1302 			(info1)->endianness != (info2)->endianness && \
1303 			(info1)->width == (info2)->width && \
1304 			(info1)->depth == (info2)->depth \
1305 		)
1306 
1307 /**
1308  * gst_audio_converter_new:
1309  * @flags: extra #GstAudioConverterFlags
1310  * @in_info: a source #GstAudioInfo
1311  * @out_info: a destination #GstAudioInfo
1312  * @config: (transfer full) (nullable): a #GstStructure with configuration options
1313  *
1314  * Create a new #GstAudioConverter that is able to convert between @in and @out
1315  * audio formats.
1316  *
1317  * @config contains extra configuration options, see `GST_AUDIO_CONVERTER_OPT_*`
1318  * parameters for details about the options and values.
1319  *
1320  * Returns: a #GstAudioConverter or %NULL if conversion is not possible.
1321  */
1322 GstAudioConverter *
gst_audio_converter_new(GstAudioConverterFlags flags,GstAudioInfo * in_info,GstAudioInfo * out_info,GstStructure * config)1323 gst_audio_converter_new (GstAudioConverterFlags flags, GstAudioInfo * in_info,
1324     GstAudioInfo * out_info, GstStructure * config)
1325 {
1326   GstAudioConverter *convert;
1327   AudioChain *prev;
1328   const GValue *opt_matrix = NULL;
1329 
1330   g_return_val_if_fail (in_info != NULL, FALSE);
1331   g_return_val_if_fail (out_info != NULL, FALSE);
1332 
1333   if (config)
1334     opt_matrix =
1335         gst_structure_get_value (config, GST_AUDIO_CONVERTER_OPT_MIX_MATRIX);
1336 
1337   if (opt_matrix
1338       && !check_mix_matrix (in_info->channels, out_info->channels, opt_matrix))
1339     goto invalid_mix_matrix;
1340 
1341   if ((GST_AUDIO_INFO_CHANNELS (in_info) != GST_AUDIO_INFO_CHANNELS (out_info))
1342       && (GST_AUDIO_INFO_IS_UNPOSITIONED (in_info)
1343           || GST_AUDIO_INFO_IS_UNPOSITIONED (out_info))
1344       && !opt_matrix)
1345     goto unpositioned;
1346 
1347   convert = g_slice_new0 (GstAudioConverter);
1348 
1349   convert->flags = flags;
1350   convert->in = *in_info;
1351   convert->out = *out_info;
1352 
1353   /* default config */
1354   convert->config = gst_structure_new_empty ("GstAudioConverter");
1355   if (config)
1356     gst_audio_converter_update_config (convert, 0, 0, config);
1357 
1358   GST_INFO ("unitsizes: %d -> %d", in_info->bpf, out_info->bpf);
1359 
1360   /* step 1, unpack */
1361   prev = chain_unpack (convert);
1362   /* step 2, optional convert from S32 to F64 for channel mix */
1363   prev = chain_convert_in (convert, prev);
1364   /* step 3, channel mix */
1365   prev = chain_mix (convert, prev);
1366   /* step 4, resample */
1367   prev = chain_resample (convert, prev);
1368   /* step 5, optional convert for quantize */
1369   prev = chain_convert_out (convert, prev);
1370   /* step 6, optional quantize */
1371   prev = chain_quantize (convert, prev);
1372   /* step 7, change layout */
1373   prev = chain_change_layout (convert, prev);
1374   /* step 8, pack */
1375   convert->chain_end = chain_pack (convert, prev);
1376 
1377   convert->convert = converter_generic;
1378   convert->in_place = FALSE;
1379   convert->passthrough = FALSE;
1380 
1381   /* optimize */
1382   if (convert->mix_passthrough) {
1383     if (out_info->finfo->format == in_info->finfo->format) {
1384       if (convert->resampler == NULL) {
1385         if (out_info->layout == in_info->layout) {
1386           GST_INFO ("same formats, same layout, no resampler and "
1387               "passthrough mixing -> passthrough");
1388           convert->convert = converter_passthrough;
1389           convert->in_place = TRUE;
1390           convert->passthrough = TRUE;
1391         }
1392       } else {
1393         if (is_intermediate_format (in_info->finfo->format)) {
1394           GST_INFO ("same formats, and passthrough mixing -> only resampling");
1395           convert->convert = converter_resample;
1396         }
1397       }
1398     } else if (GST_AUDIO_FORMAT_IS_ENDIAN_CONVERSION (out_info->finfo,
1399             in_info->finfo)) {
1400       if (convert->resampler == NULL && out_info->layout == in_info->layout) {
1401         GST_INFO ("no resampler, passthrough mixing -> only endian conversion");
1402         convert->convert = converter_endian;
1403         convert->in_place = TRUE;
1404 
1405         switch (GST_AUDIO_INFO_WIDTH (in_info)) {
1406           case 16:
1407             GST_DEBUG ("initializing 16-bit endian conversion");
1408             convert->swap_endian = converter_swap_endian_16;
1409             break;
1410           case 24:
1411             GST_DEBUG ("initializing 24-bit endian conversion");
1412             convert->swap_endian = converter_swap_endian_24;
1413             break;
1414           case 32:
1415             GST_DEBUG ("initializing 32-bit endian conversion");
1416             convert->swap_endian = converter_swap_endian_32;
1417             break;
1418           case 64:
1419             GST_DEBUG ("initializing 64-bit endian conversion");
1420             convert->swap_endian = converter_swap_endian_64;
1421             break;
1422           default:
1423             GST_ERROR ("unsupported sample width for endian conversion");
1424             g_assert_not_reached ();
1425         }
1426       }
1427     }
1428   }
1429 
1430   setup_allocators (convert);
1431 
1432   return convert;
1433 
1434   /* ERRORS */
1435 unpositioned:
1436   {
1437     GST_WARNING ("unpositioned channels");
1438     g_clear_pointer (&config, gst_structure_free);
1439     return NULL;
1440   }
1441 
1442 invalid_mix_matrix:
1443   {
1444     GST_WARNING ("Invalid mix matrix");
1445     g_clear_pointer (&config, gst_structure_free);
1446     return NULL;
1447   }
1448 }
1449 
1450 /**
1451  * gst_audio_converter_free:
1452  * @convert: a #GstAudioConverter
1453  *
1454  * Free a previously allocated @convert instance.
1455  */
1456 void
gst_audio_converter_free(GstAudioConverter * convert)1457 gst_audio_converter_free (GstAudioConverter * convert)
1458 {
1459   AudioChain *chain;
1460 
1461   g_return_if_fail (convert != NULL);
1462 
1463   /* walk the chain backwards and free all elements */
1464   for (chain = convert->chain_end; chain;) {
1465     AudioChain *prev = chain->prev;
1466     audio_chain_free (chain);
1467     chain = prev;
1468   }
1469 
1470   if (convert->quant)
1471     gst_audio_quantize_free (convert->quant);
1472   if (convert->mix)
1473     gst_audio_channel_mixer_free (convert->mix);
1474   if (convert->resampler)
1475     gst_audio_resampler_free (convert->resampler);
1476   gst_audio_info_init (&convert->in);
1477   gst_audio_info_init (&convert->out);
1478 
1479   gst_structure_free (convert->config);
1480 
1481   g_slice_free (GstAudioConverter, convert);
1482 }
1483 
1484 /**
1485  * gst_audio_converter_get_out_frames:
1486  * @convert: a #GstAudioConverter
1487  * @in_frames: number of input frames
1488  *
1489  * Calculate how many output frames can be produced when @in_frames input
1490  * frames are given to @convert.
1491  *
1492  * Returns: the number of output frames
1493  */
1494 gsize
gst_audio_converter_get_out_frames(GstAudioConverter * convert,gsize in_frames)1495 gst_audio_converter_get_out_frames (GstAudioConverter * convert,
1496     gsize in_frames)
1497 {
1498   if (convert->resampler)
1499     return gst_audio_resampler_get_out_frames (convert->resampler, in_frames);
1500   else
1501     return in_frames;
1502 }
1503 
1504 /**
1505  * gst_audio_converter_get_in_frames:
1506  * @convert: a #GstAudioConverter
1507  * @out_frames: number of output frames
1508  *
1509  * Calculate how many input frames are currently needed by @convert to produce
1510  * @out_frames of output frames.
1511  *
1512  * Returns: the number of input frames
1513  */
1514 gsize
gst_audio_converter_get_in_frames(GstAudioConverter * convert,gsize out_frames)1515 gst_audio_converter_get_in_frames (GstAudioConverter * convert,
1516     gsize out_frames)
1517 {
1518   if (convert->resampler)
1519     return gst_audio_resampler_get_in_frames (convert->resampler, out_frames);
1520   else
1521     return out_frames;
1522 }
1523 
1524 /**
1525  * gst_audio_converter_get_max_latency:
1526  * @convert: a #GstAudioConverter
1527  *
1528  * Get the maximum number of input frames that the converter would
1529  * need before producing output.
1530  *
1531  * Returns: the latency of @convert as expressed in the number of
1532  * frames.
1533  */
1534 gsize
gst_audio_converter_get_max_latency(GstAudioConverter * convert)1535 gst_audio_converter_get_max_latency (GstAudioConverter * convert)
1536 {
1537   if (convert->resampler)
1538     return gst_audio_resampler_get_max_latency (convert->resampler);
1539   else
1540     return 0;
1541 }
1542 
1543 /**
1544  * gst_audio_converter_reset:
1545  * @convert: a #GstAudioConverter
1546  *
1547  * Reset @convert to the state it was when it was first created, clearing
1548  * any history it might currently have.
1549  */
1550 void
gst_audio_converter_reset(GstAudioConverter * convert)1551 gst_audio_converter_reset (GstAudioConverter * convert)
1552 {
1553   if (convert->resampler)
1554     gst_audio_resampler_reset (convert->resampler);
1555   if (convert->quant)
1556     gst_audio_quantize_reset (convert->quant);
1557 }
1558 
1559 /**
1560  * gst_audio_converter_samples:
1561  * @convert: a #GstAudioConverter
1562  * @flags: extra #GstAudioConverterFlags
1563  * @in: input frames
1564  * @in_frames: number of input frames
1565  * @out: output frames
1566  * @out_frames: number of output frames
1567  *
1568  * Perform the conversion with @in_frames in @in to @out_frames in @out
1569  * using @convert.
1570  *
1571  * In case the samples are interleaved, @in and @out must point to an
1572  * array with a single element pointing to a block of interleaved samples.
1573  *
1574  * If non-interleaved samples are used, @in and @out must point to an
1575  * array with pointers to memory blocks, one for each channel.
1576  *
1577  * @in may be %NULL, in which case @in_frames of silence samples are processed
1578  * by the converter.
1579  *
1580  * This function always produces @out_frames of output and consumes @in_frames of
1581  * input. Use gst_audio_converter_get_out_frames() and
1582  * gst_audio_converter_get_in_frames() to make sure @in_frames and @out_frames
1583  * are matching and @in and @out point to enough memory.
1584  *
1585  * Returns: %TRUE is the conversion could be performed.
1586  */
1587 gboolean
gst_audio_converter_samples(GstAudioConverter * convert,GstAudioConverterFlags flags,gpointer in[],gsize in_frames,gpointer out[],gsize out_frames)1588 gst_audio_converter_samples (GstAudioConverter * convert,
1589     GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1590     gpointer out[], gsize out_frames)
1591 {
1592   g_return_val_if_fail (convert != NULL, FALSE);
1593   g_return_val_if_fail (out != NULL, FALSE);
1594 
1595   if (in_frames == 0) {
1596     GST_LOG ("skipping empty buffer");
1597     return TRUE;
1598   }
1599   return convert->convert (convert, flags, in, in_frames, out, out_frames);
1600 }
1601 
1602 /**
1603  * gst_audio_converter_convert:
1604  * @convert: a #GstAudioConverter
1605  * @flags: extra #GstAudioConverterFlags
1606  * @in: (array length=in_size) (element-type guint8): input data
1607  * @in_size: size of @in
1608  * @out: (out) (array length=out_size) (element-type guint8): a pointer where
1609  *  the output data will be written
1610  * @out_size: (out): a pointer where the size of @out will be written
1611  *
1612  * Convenience wrapper around gst_audio_converter_samples(), which will
1613  * perform allocation of the output buffer based on the result from
1614  * gst_audio_converter_get_out_frames().
1615  *
1616  * Returns: %TRUE is the conversion could be performed.
1617  *
1618  * Since: 1.14
1619  */
1620 gboolean
gst_audio_converter_convert(GstAudioConverter * convert,GstAudioConverterFlags flags,gpointer in,gsize in_size,gpointer * out,gsize * out_size)1621 gst_audio_converter_convert (GstAudioConverter * convert,
1622     GstAudioConverterFlags flags, gpointer in, gsize in_size,
1623     gpointer * out, gsize * out_size)
1624 {
1625   gsize in_frames;
1626   gsize out_frames;
1627 
1628   g_return_val_if_fail (convert != NULL, FALSE);
1629   g_return_val_if_fail (flags ^ GST_AUDIO_CONVERTER_FLAG_IN_WRITABLE, FALSE);
1630 
1631   in_frames = in_size / convert->in.bpf;
1632   out_frames = gst_audio_converter_get_out_frames (convert, in_frames);
1633 
1634   *out_size = out_frames * convert->out.bpf;
1635   *out = g_malloc0 (*out_size);
1636 
1637   return gst_audio_converter_samples (convert, flags, &in, in_frames, out,
1638       out_frames);
1639 }
1640 
1641 /**
1642  * gst_audio_converter_supports_inplace:
1643  * @convert: a #GstAudioConverter
1644  *
1645  * Returns whether the audio converter can perform the conversion in-place.
1646  * The return value would be typically input to gst_base_transform_set_in_place()
1647  *
1648  * Returns: %TRUE when the conversion can be done in place.
1649  *
1650  * Since: 1.12
1651  */
1652 gboolean
gst_audio_converter_supports_inplace(GstAudioConverter * convert)1653 gst_audio_converter_supports_inplace (GstAudioConverter * convert)
1654 {
1655   return convert->in_place;
1656 }
1657 
1658 /**
1659  * gst_audio_converter_is_passthrough:
1660  *
1661  * Returns whether the audio converter will operate in passthrough mode.
1662  * The return value would be typically input to gst_base_transform_set_passthrough()
1663  *
1664  * Returns: %TRUE when no conversion will actually occur.
1665  *
1666  * Since: 1.16
1667  */
1668 gboolean
gst_audio_converter_is_passthrough(GstAudioConverter * convert)1669 gst_audio_converter_is_passthrough (GstAudioConverter * convert)
1670 {
1671   return convert->passthrough;
1672 }
1673