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 while (!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 alignement */
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_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 gst_audio_quantize_samples (convert->quant, in, out, num_samples);
586
587 audio_chain_set_samples (chain, out, num_samples);
588
589 return TRUE;
590 }
591
592 #define MAKE_INTERLEAVE_FUNC(type) \
593 static inline void \
594 interleave_##type (const type * in[], type * out[], \
595 gsize num_samples, gint channels) \
596 { \
597 gsize s; \
598 gint c; \
599 for (s = 0; s < num_samples; s++) { \
600 for (c = 0; c < channels; c++) { \
601 out[0][s * channels + c] = in[c][s]; \
602 } \
603 } \
604 }
605
606 #define MAKE_DEINTERLEAVE_FUNC(type) \
607 static inline void \
608 deinterleave_##type (const type * in[], type * out[], \
609 gsize num_samples, gint channels) \
610 { \
611 gsize s; \
612 gint c; \
613 for (s = 0; s < num_samples; s++) { \
614 for (c = 0; c < channels; c++) { \
615 out[c][s] = in[0][s * channels + c]; \
616 } \
617 } \
618 }
619
620 MAKE_INTERLEAVE_FUNC (gint16);
621 MAKE_INTERLEAVE_FUNC (gint32);
622 MAKE_INTERLEAVE_FUNC (gfloat);
623 MAKE_INTERLEAVE_FUNC (gdouble);
624 MAKE_DEINTERLEAVE_FUNC (gint16);
625 MAKE_DEINTERLEAVE_FUNC (gint32);
626 MAKE_DEINTERLEAVE_FUNC (gfloat);
627 MAKE_DEINTERLEAVE_FUNC (gdouble);
628
629 static gboolean
do_change_layout(AudioChain * chain,gpointer user_data)630 do_change_layout (AudioChain * chain, gpointer user_data)
631 {
632 GstAudioConverter *convert = user_data;
633 GstAudioFormat format = convert->chlayout_format;
634 GstAudioLayout out_layout = convert->chlayout_target;
635 gint channels = convert->chlayout_channels;
636 gsize num_samples;
637 gpointer *in, *out;
638
639 in = audio_chain_get_samples (chain->prev, &num_samples);
640 out = (chain->allow_ip ? in : audio_chain_alloc_samples (chain, num_samples));
641
642 if (out_layout == GST_AUDIO_LAYOUT_INTERLEAVED) {
643 /* interleave */
644 GST_LOG ("interleaving %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
645 switch (format) {
646 case GST_AUDIO_FORMAT_S16:
647 interleave_gint16 ((const gint16 **) in, (gint16 **) out,
648 num_samples, channels);
649 break;
650 case GST_AUDIO_FORMAT_S32:
651 interleave_gint32 ((const gint32 **) in, (gint32 **) out,
652 num_samples, channels);
653 break;
654 case GST_AUDIO_FORMAT_F32:
655 interleave_gfloat ((const gfloat **) in, (gfloat **) out,
656 num_samples, channels);
657 break;
658 case GST_AUDIO_FORMAT_F64:
659 interleave_gdouble ((const gdouble **) in, (gdouble **) out,
660 num_samples, channels);
661 break;
662 default:
663 g_assert_not_reached ();
664 break;
665 }
666 } else {
667 /* deinterleave */
668 GST_LOG ("deinterleaving %p, %p %" G_GSIZE_FORMAT, in, out, num_samples);
669 switch (format) {
670 case GST_AUDIO_FORMAT_S16:
671 deinterleave_gint16 ((const gint16 **) in, (gint16 **) out,
672 num_samples, channels);
673 break;
674 case GST_AUDIO_FORMAT_S32:
675 deinterleave_gint32 ((const gint32 **) in, (gint32 **) out,
676 num_samples, channels);
677 break;
678 case GST_AUDIO_FORMAT_F32:
679 deinterleave_gfloat ((const gfloat **) in, (gfloat **) out,
680 num_samples, channels);
681 break;
682 case GST_AUDIO_FORMAT_F64:
683 deinterleave_gdouble ((const gdouble **) in, (gdouble **) out,
684 num_samples, channels);
685 break;
686 default:
687 g_assert_not_reached ();
688 break;
689 }
690 }
691
692 audio_chain_set_samples (chain, out, num_samples);
693 return TRUE;
694 }
695
696 static gboolean
is_intermediate_format(GstAudioFormat format)697 is_intermediate_format (GstAudioFormat format)
698 {
699 return (format == GST_AUDIO_FORMAT_S16 ||
700 format == GST_AUDIO_FORMAT_S32 ||
701 format == GST_AUDIO_FORMAT_F32 || format == GST_AUDIO_FORMAT_F64);
702 }
703
704 static AudioChain *
chain_unpack(GstAudioConverter * convert)705 chain_unpack (GstAudioConverter * convert)
706 {
707 AudioChain *prev;
708 GstAudioInfo *in = &convert->in;
709 GstAudioInfo *out = &convert->out;
710 gboolean same_format;
711
712 same_format = in->finfo->format == out->finfo->format;
713
714 /* do not unpack if we have the same input format as the output format
715 * and it is a possible intermediate format */
716 if (same_format && is_intermediate_format (in->finfo->format)) {
717 convert->current_format = in->finfo->format;
718 } else {
719 convert->current_format = in->finfo->unpack_format;
720 }
721 convert->current_layout = in->layout;
722 convert->current_channels = in->channels;
723
724 convert->in_default = convert->current_format == in->finfo->format;
725
726 GST_INFO ("unpack format %s to %s",
727 gst_audio_format_to_string (in->finfo->format),
728 gst_audio_format_to_string (convert->current_format));
729
730 prev = audio_chain_new (NULL, convert);
731 prev->allow_ip = prev->finfo->width <= in->finfo->width;
732 prev->pass_alloc = FALSE;
733 audio_chain_set_make_func (prev, do_unpack, convert, NULL);
734
735 return prev;
736 }
737
738 static AudioChain *
chain_convert_in(GstAudioConverter * convert,AudioChain * prev)739 chain_convert_in (GstAudioConverter * convert, AudioChain * prev)
740 {
741 gboolean in_int, out_int;
742 GstAudioInfo *in = &convert->in;
743 GstAudioInfo *out = &convert->out;
744
745 in_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo);
746 out_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo);
747
748 if (in_int && !out_int) {
749 GST_INFO ("convert S32 to F64");
750 convert->convert_in = (AudioConvertFunc) audio_orc_s32_to_double;
751 convert->current_format = GST_AUDIO_FORMAT_F64;
752
753 prev = audio_chain_new (prev, convert);
754 prev->allow_ip = FALSE;
755 prev->pass_alloc = FALSE;
756 audio_chain_set_make_func (prev, do_convert_in, convert, NULL);
757 }
758 return prev;
759 }
760
761 static gboolean
check_mix_matrix(guint in_channels,guint out_channels,const GValue * value)762 check_mix_matrix (guint in_channels, guint out_channels, const GValue * value)
763 {
764 guint i, j;
765
766 /* audio-channel-mixer will generate an identity matrix */
767 if (gst_value_array_get_size (value) == 0)
768 return TRUE;
769
770 if (gst_value_array_get_size (value) != out_channels) {
771 GST_ERROR ("Invalid mix matrix size, should be %d", out_channels);
772 goto fail;
773 }
774
775 for (j = 0; j < out_channels; j++) {
776 const GValue *row = gst_value_array_get_value (value, j);
777
778 if (gst_value_array_get_size (row) != in_channels) {
779 GST_ERROR ("Invalid mix matrix row size, should be %d", in_channels);
780 goto fail;
781 }
782
783 for (i = 0; i < in_channels; i++) {
784 const GValue *itm;
785
786 itm = gst_value_array_get_value (row, i);
787 if (!G_VALUE_HOLDS_FLOAT (itm)) {
788 GST_ERROR ("Invalid mix matrix element type, should be float");
789 goto fail;
790 }
791 }
792 }
793
794 return TRUE;
795
796 fail:
797 return FALSE;
798 }
799
800 static gfloat **
mix_matrix_from_g_value(guint in_channels,guint out_channels,const GValue * value)801 mix_matrix_from_g_value (guint in_channels, guint out_channels,
802 const GValue * value)
803 {
804 guint i, j;
805 gfloat **matrix = g_new (gfloat *, in_channels);
806
807 for (i = 0; i < in_channels; i++)
808 matrix[i] = g_new (gfloat, out_channels);
809
810 for (j = 0; j < out_channels; j++) {
811 const GValue *row = gst_value_array_get_value (value, j);
812
813 for (i = 0; i < in_channels; i++) {
814 const GValue *itm;
815 gfloat coefficient;
816
817 itm = gst_value_array_get_value (row, i);
818 coefficient = g_value_get_float (itm);
819 matrix[i][j] = coefficient;
820 }
821 }
822
823 return matrix;
824 }
825
826 static AudioChain *
chain_mix(GstAudioConverter * convert,AudioChain * prev)827 chain_mix (GstAudioConverter * convert, AudioChain * prev)
828 {
829 GstAudioInfo *in = &convert->in;
830 GstAudioInfo *out = &convert->out;
831 GstAudioFormat format = convert->current_format;
832 const GValue *opt_matrix = GET_OPT_MIX_MATRIX (convert);
833 GstAudioChannelMixerFlags flags = 0;
834
835 convert->current_channels = out->channels;
836
837 /* keep the input layout */
838 if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
839 flags |= GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_IN;
840 flags |= GST_AUDIO_CHANNEL_MIXER_FLAGS_NON_INTERLEAVED_OUT;
841 }
842
843 if (opt_matrix) {
844 gfloat **matrix = NULL;
845
846 if (gst_value_array_get_size (opt_matrix))
847 matrix =
848 mix_matrix_from_g_value (in->channels, out->channels, opt_matrix);
849
850 convert->mix =
851 gst_audio_channel_mixer_new_with_matrix (flags, format, in->channels,
852 out->channels, matrix);
853 } else {
854 flags |=
855 GST_AUDIO_INFO_IS_UNPOSITIONED (in) ?
856 GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_IN : 0;
857 flags |=
858 GST_AUDIO_INFO_IS_UNPOSITIONED (out) ?
859 GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_OUT : 0;
860
861 convert->mix =
862 gst_audio_channel_mixer_new (flags, format, in->channels, in->position,
863 out->channels, out->position);
864 }
865
866 convert->mix_passthrough =
867 gst_audio_channel_mixer_is_passthrough (convert->mix);
868 GST_INFO ("mix format %s, passthrough %d, in_channels %d, out_channels %d",
869 gst_audio_format_to_string (format), convert->mix_passthrough,
870 in->channels, out->channels);
871
872 if (!convert->mix_passthrough) {
873 prev = audio_chain_new (prev, convert);
874 prev->allow_ip = FALSE;
875 prev->pass_alloc = FALSE;
876 audio_chain_set_make_func (prev, do_mix, convert, NULL);
877 }
878 return prev;
879 }
880
881 static AudioChain *
chain_resample(GstAudioConverter * convert,AudioChain * prev)882 chain_resample (GstAudioConverter * convert, AudioChain * prev)
883 {
884 GstAudioInfo *in = &convert->in;
885 GstAudioInfo *out = &convert->out;
886 GstAudioResamplerMethod method;
887 GstAudioResamplerFlags flags;
888 GstAudioFormat format = convert->current_format;
889 gint channels = convert->current_channels;
890 gboolean variable_rate;
891
892 variable_rate = convert->flags & GST_AUDIO_CONVERTER_FLAG_VARIABLE_RATE;
893
894 if (in->rate != out->rate || variable_rate) {
895 method = GET_OPT_RESAMPLER_METHOD (convert);
896
897 flags = 0;
898 if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
899 flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_IN;
900 }
901 /* if the resampler is activated, it is optimal to change layout here */
902 if (out->layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) {
903 flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED_OUT;
904 }
905 convert->current_layout = out->layout;
906
907 if (variable_rate)
908 flags |= GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE;
909
910 convert->resampler =
911 gst_audio_resampler_new (method, flags, format, channels, in->rate,
912 out->rate, convert->config);
913
914 prev = audio_chain_new (prev, convert);
915 prev->allow_ip = FALSE;
916 prev->pass_alloc = FALSE;
917 audio_chain_set_make_func (prev, do_resample, convert, NULL);
918 }
919 return prev;
920 }
921
922 static AudioChain *
chain_convert_out(GstAudioConverter * convert,AudioChain * prev)923 chain_convert_out (GstAudioConverter * convert, AudioChain * prev)
924 {
925 gboolean in_int, out_int;
926 GstAudioInfo *in = &convert->in;
927 GstAudioInfo *out = &convert->out;
928
929 in_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo);
930 out_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo);
931
932 if (!in_int && out_int) {
933 convert->convert_out = (AudioConvertFunc) audio_orc_double_to_s32;
934 convert->current_format = GST_AUDIO_FORMAT_S32;
935
936 GST_INFO ("convert F64 to S32");
937 prev = audio_chain_new (prev, convert);
938 prev->allow_ip = TRUE;
939 prev->pass_alloc = FALSE;
940 audio_chain_set_make_func (prev, do_convert_out, convert, NULL);
941 }
942 return prev;
943 }
944
945 static AudioChain *
chain_quantize(GstAudioConverter * convert,AudioChain * prev)946 chain_quantize (GstAudioConverter * convert, AudioChain * prev)
947 {
948 const GstAudioFormatInfo *cur_finfo;
949 GstAudioInfo *out = &convert->out;
950 gint in_depth, out_depth;
951 gboolean in_int, out_int;
952 GstAudioDitherMethod dither;
953 GstAudioNoiseShapingMethod ns;
954
955 dither = GET_OPT_DITHER_METHOD (convert);
956 ns = GET_OPT_NOISE_SHAPING_METHOD (convert);
957
958 cur_finfo = gst_audio_format_get_info (convert->current_format);
959
960 in_depth = GST_AUDIO_FORMAT_INFO_DEPTH (cur_finfo);
961 out_depth = GST_AUDIO_FORMAT_INFO_DEPTH (out->finfo);
962 GST_INFO ("depth in %d, out %d", in_depth, out_depth);
963
964 in_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (cur_finfo);
965 out_int = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo);
966
967 /* Don't dither or apply noise shaping if target depth is bigger than 20 bits
968 * as DA converters only can do a SNR up to 20 bits in reality.
969 * Also don't dither or apply noise shaping if target depth is larger than
970 * source depth. */
971 if (out_depth > 20 || (in_int && out_depth >= in_depth)) {
972 dither = GST_AUDIO_DITHER_NONE;
973 ns = GST_AUDIO_NOISE_SHAPING_NONE;
974 GST_INFO ("using no dither and noise shaping");
975 } else {
976 GST_INFO ("using dither %d and noise shaping %d", dither, ns);
977 /* Use simple error feedback when output sample rate is smaller than
978 * 32000 as the other methods might move the noise to audible ranges */
979 if (ns > GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK && out->rate < 32000)
980 ns = GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK;
981 }
982 /* we still want to run the quantization step when reducing bits to get
983 * the rounding correct */
984 if (out_int && out_depth < 32
985 && convert->current_format == GST_AUDIO_FORMAT_S32) {
986 GST_INFO ("quantize to %d bits, dither %d, ns %d", out_depth, dither, ns);
987 convert->quant =
988 gst_audio_quantize_new (dither, ns, 0, convert->current_format,
989 out->channels, 1U << (32 - out_depth));
990
991 prev = audio_chain_new (prev, convert);
992 prev->allow_ip = TRUE;
993 prev->pass_alloc = TRUE;
994 audio_chain_set_make_func (prev, do_quantize, convert, NULL);
995 }
996 return prev;
997 }
998
999 static AudioChain *
chain_change_layout(GstAudioConverter * convert,AudioChain * prev)1000 chain_change_layout (GstAudioConverter * convert, AudioChain * prev)
1001 {
1002 GstAudioInfo *out = &convert->out;
1003
1004 if (convert->current_layout != out->layout) {
1005 convert->current_layout = out->layout;
1006
1007 /* if there is only 1 channel, layouts are identical */
1008 if (convert->current_channels > 1) {
1009 convert->chlayout_target = convert->current_layout;
1010 convert->chlayout_format = convert->current_format;
1011 convert->chlayout_channels = convert->current_channels;
1012
1013 prev = audio_chain_new (prev, convert);
1014 prev->allow_ip = FALSE;
1015 prev->pass_alloc = FALSE;
1016 audio_chain_set_make_func (prev, do_change_layout, convert, NULL);
1017 }
1018 }
1019 return prev;
1020 }
1021
1022 static AudioChain *
chain_pack(GstAudioConverter * convert,AudioChain * prev)1023 chain_pack (GstAudioConverter * convert, AudioChain * prev)
1024 {
1025 GstAudioInfo *out = &convert->out;
1026 GstAudioFormat format = convert->current_format;
1027
1028 convert->current_format = out->finfo->format;
1029
1030 convert->out_default = format == out->finfo->format;
1031 GST_INFO ("pack format %s to %s", gst_audio_format_to_string (format),
1032 gst_audio_format_to_string (out->finfo->format));
1033
1034 return prev;
1035 }
1036
1037 static void
setup_allocators(GstAudioConverter * convert)1038 setup_allocators (GstAudioConverter * convert)
1039 {
1040 AudioChain *chain;
1041 AudioChainAllocFunc alloc_func;
1042 gboolean allow_ip;
1043
1044 /* start with using dest if we can directly write into it */
1045 if (convert->out_default) {
1046 alloc_func = get_output_samples;
1047 allow_ip = FALSE;
1048 } else {
1049 alloc_func = get_temp_samples;
1050 allow_ip = TRUE;
1051 }
1052 /* now walk backwards, we try to write into the dest samples directly
1053 * and keep track if the source needs to be writable */
1054 for (chain = convert->chain_end; chain; chain = chain->prev) {
1055 chain->alloc_func = alloc_func;
1056 chain->alloc_data = convert;
1057 chain->allow_ip = allow_ip && chain->allow_ip;
1058 GST_LOG ("chain %p: %d %d", chain, allow_ip, chain->allow_ip);
1059
1060 if (!chain->pass_alloc) {
1061 /* can't pass allocator, make new temp line allocator */
1062 alloc_func = get_temp_samples;
1063 allow_ip = TRUE;
1064 }
1065 }
1066 }
1067
1068 static gboolean
converter_passthrough(GstAudioConverter * convert,GstAudioConverterFlags flags,gpointer in[],gsize in_frames,gpointer out[],gsize out_frames)1069 converter_passthrough (GstAudioConverter * convert,
1070 GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1071 gpointer out[], gsize out_frames)
1072 {
1073 gint i;
1074 AudioChain *chain;
1075 gsize samples;
1076
1077 /* in-place passthrough -> do nothing */
1078 if (in == out) {
1079 g_assert (convert->in_place);
1080 return TRUE;
1081 }
1082
1083 chain = convert->chain_end;
1084
1085 samples = in_frames * chain->inc;
1086
1087 GST_LOG ("passthrough: %" G_GSIZE_FORMAT " / %" G_GSIZE_FORMAT " samples",
1088 in_frames, samples);
1089
1090 if (in) {
1091 gsize bytes;
1092
1093 bytes = samples * (convert->in.bpf / convert->in.channels);
1094
1095 for (i = 0; i < chain->blocks; i++) {
1096 if (out[i] == in[i]) {
1097 g_assert (convert->in_place);
1098 continue;
1099 }
1100
1101 memcpy (out[i], in[i], bytes);
1102 }
1103 } else {
1104 for (i = 0; i < chain->blocks; i++)
1105 gst_audio_format_fill_silence (convert->in.finfo, out[i], samples);
1106 }
1107 return TRUE;
1108 }
1109
1110 /* perform LE<->BE conversion on a block of @count 16-bit samples
1111 * dst may equal src for in-place conversion
1112 */
1113 static void
converter_swap_endian_16(gpointer dst,const gpointer src,gint count)1114 converter_swap_endian_16 (gpointer dst, const gpointer src, gint count)
1115 {
1116 guint16 *out = dst;
1117 const guint16 *in = src;
1118 gint i;
1119
1120 for (i = 0; i < count; i++)
1121 out[i] = GUINT16_SWAP_LE_BE (in[i]);
1122 }
1123
1124 /* perform LE<->BE conversion on a block of @count 24-bit samples
1125 * dst may equal src for in-place conversion
1126 *
1127 * naive algorithm, which performs better with -O3 and worse with -O2
1128 * than the commented out optimized algorithm below
1129 */
1130 static void
converter_swap_endian_24(gpointer dst,const gpointer src,gint count)1131 converter_swap_endian_24 (gpointer dst, const gpointer src, gint count)
1132 {
1133 guint8 *out = dst;
1134 const guint8 *in = src;
1135 gint i;
1136
1137 count *= 3;
1138
1139 for (i = 0; i < count; i += 3) {
1140 guint8 x = in[i + 0];
1141 out[i + 0] = in[i + 2];
1142 out[i + 1] = in[i + 1];
1143 out[i + 2] = x;
1144 }
1145 }
1146
1147 /* the below code performs better with -O2 but worse with -O3 */
1148 #if 0
1149 /* perform LE<->BE conversion on a block of @count 24-bit samples
1150 * dst may equal src for in-place conversion
1151 *
1152 * assumes that dst and src are 32-bit aligned
1153 */
1154 static void
1155 converter_swap_endian_24 (gpointer dst, const gpointer src, gint count)
1156 {
1157 guint32 *out = dst;
1158 const guint32 *in = src;
1159 guint8 *out8;
1160 const guint8 *in8;
1161 gint i;
1162
1163 /* first convert 24-bit samples in multiples of 4 reading 3x 32-bits in one cycle
1164 *
1165 * input: A1 B1 C1 A2 , B2 C2 A3 B3 , C3 A4 B4 C4
1166 * 32-bit endian swap: A2 C1 B1 A1 , B3 A3 C2 B2 , C4 B4 A4 C3
1167 * <-- x --> <-- y --> , <-- z -->
1168 *
1169 * desired output: C1 B1 A1 C2 , B2 A2 C3 B3 , A3 C4 B4 A4
1170 */
1171 for (i = 0; i < count / 4; i++, in += 3, out += 3) {
1172 guint32 x, y, z;
1173
1174 x = GUINT32_SWAP_LE_BE (in[0]);
1175 y = GUINT32_SWAP_LE_BE (in[1]);
1176 z = GUINT32_SWAP_LE_BE (in[2]);
1177
1178 #if G_BYTE_ORDER == G_BIG_ENDIAN
1179 out[0] = (x << 8) + ((y >> 8) & 0xff);
1180 out[1] = (in[1] & 0xff0000ff) + ((x >> 8) & 0xff0000) + ((z << 8) & 0xff00);
1181 out[2] = (z >> 8) + ((y << 8) & 0xff000000);
1182 #else
1183 out[0] = (x >> 8) + ((y << 8) & 0xff000000);
1184 out[1] = (in[1] & 0xff0000ff) + ((x << 8) & 0xff00) + ((z >> 8) & 0xff0000);
1185 out[2] = (z << 8) + ((y >> 8) & 0xff);
1186 #endif
1187 }
1188
1189 /* convert the remainder less efficiently */
1190 for (out8 = (guint8 *) out, in8 = (const guint8 *) in, i = 0; i < (count & 3);
1191 i++) {
1192 guint8 x = in8[i + 0];
1193 out8[i + 0] = in8[i + 2];
1194 out8[i + 1] = in8[i + 1];
1195 out8[i + 2] = x;
1196 }
1197 }
1198 #endif
1199
1200 /* perform LE<->BE conversion on a block of @count 32-bit samples
1201 * dst may equal src for in-place conversion
1202 */
1203 static void
converter_swap_endian_32(gpointer dst,const gpointer src,gint count)1204 converter_swap_endian_32 (gpointer dst, const gpointer src, gint count)
1205 {
1206 guint32 *out = dst;
1207 const guint32 *in = src;
1208 gint i;
1209
1210 for (i = 0; i < count; i++)
1211 out[i] = GUINT32_SWAP_LE_BE (in[i]);
1212 }
1213
1214 /* perform LE<->BE conversion on a block of @count 64-bit samples
1215 * dst may equal src for in-place conversion
1216 */
1217 static void
converter_swap_endian_64(gpointer dst,const gpointer src,gint count)1218 converter_swap_endian_64 (gpointer dst, const gpointer src, gint count)
1219 {
1220 guint64 *out = dst;
1221 const guint64 *in = src;
1222 gint i;
1223
1224 for (i = 0; i < count; i++)
1225 out[i] = GUINT64_SWAP_LE_BE (in[i]);
1226 }
1227
1228 /* the worker function to perform endian-conversion only
1229 * assuming finfo and foutinfo have the same depth
1230 */
1231 static gboolean
converter_endian(GstAudioConverter * convert,GstAudioConverterFlags flags,gpointer in[],gsize in_frames,gpointer out[],gsize out_frames)1232 converter_endian (GstAudioConverter * convert,
1233 GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1234 gpointer out[], gsize out_frames)
1235 {
1236 gint i;
1237 AudioChain *chain;
1238 gsize samples;
1239
1240 chain = convert->chain_end;
1241 samples = in_frames * chain->inc;
1242
1243 GST_LOG ("convert endian: %" G_GSIZE_FORMAT " / %" G_GSIZE_FORMAT " samples",
1244 in_frames, samples);
1245
1246 if (in) {
1247 for (i = 0; i < chain->blocks; i++)
1248 convert->swap_endian (out[i], in[i], samples);
1249 } else {
1250 for (i = 0; i < chain->blocks; i++)
1251 gst_audio_format_fill_silence (convert->in.finfo, out[i], samples);
1252 }
1253 return TRUE;
1254 }
1255
1256 static gboolean
converter_generic(GstAudioConverter * convert,GstAudioConverterFlags flags,gpointer in[],gsize in_frames,gpointer out[],gsize out_frames)1257 converter_generic (GstAudioConverter * convert,
1258 GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1259 gpointer out[], gsize out_frames)
1260 {
1261 AudioChain *chain;
1262 gpointer *tmp;
1263 gint i;
1264 gsize produced;
1265
1266 chain = convert->chain_end;
1267
1268 convert->in_writable = flags & GST_AUDIO_CONVERTER_FLAG_IN_WRITABLE;
1269 convert->in_data = in;
1270 convert->in_frames = in_frames;
1271 convert->out_data = out;
1272 convert->out_frames = out_frames;
1273
1274 /* get frames to pack */
1275 tmp = audio_chain_get_samples (chain, &produced);
1276
1277 if (!convert->out_default) {
1278 GST_LOG ("pack %p, %p %" G_GSIZE_FORMAT, tmp, out, produced);
1279 /* and pack if needed */
1280 for (i = 0; i < chain->blocks; i++)
1281 convert->out.finfo->pack_func (convert->out.finfo, 0, tmp[i], out[i],
1282 produced * chain->inc);
1283 }
1284 return TRUE;
1285 }
1286
1287 static gboolean
converter_resample(GstAudioConverter * convert,GstAudioConverterFlags flags,gpointer in[],gsize in_frames,gpointer out[],gsize out_frames)1288 converter_resample (GstAudioConverter * convert,
1289 GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1290 gpointer out[], gsize out_frames)
1291 {
1292 gst_audio_resampler_resample (convert->resampler, in, in_frames, out,
1293 out_frames);
1294
1295 return TRUE;
1296 }
1297
1298 #define GST_AUDIO_FORMAT_IS_ENDIAN_CONVERSION(info1, info2) \
1299 ( \
1300 !(((info1)->flags ^ (info2)->flags) & (~GST_AUDIO_FORMAT_FLAG_UNPACK)) && \
1301 (info1)->endianness != (info2)->endianness && \
1302 (info1)->width == (info2)->width && \
1303 (info1)->depth == (info2)->depth \
1304 )
1305
1306 /**
1307 * gst_audio_converter_new:
1308 * @flags: extra #GstAudioConverterFlags
1309 * @in_info: a source #GstAudioInfo
1310 * @out_info: a destination #GstAudioInfo
1311 * @config: (transfer full) (nullable): a #GstStructure with configuration options
1312 *
1313 * Create a new #GstAudioConverter that is able to convert between @in and @out
1314 * audio formats.
1315 *
1316 * @config contains extra configuration options, see #GST_AUDIO_CONVERTER_OPT_*
1317 * parameters for details about the options and values.
1318 *
1319 * Returns: a #GstAudioConverter or %NULL if conversion is not possible.
1320 */
1321 GstAudioConverter *
gst_audio_converter_new(GstAudioConverterFlags flags,GstAudioInfo * in_info,GstAudioInfo * out_info,GstStructure * config)1322 gst_audio_converter_new (GstAudioConverterFlags flags, GstAudioInfo * in_info,
1323 GstAudioInfo * out_info, GstStructure * config)
1324 {
1325 GstAudioConverter *convert;
1326 AudioChain *prev;
1327 const GValue *opt_matrix = NULL;
1328
1329 g_return_val_if_fail (in_info != NULL, FALSE);
1330 g_return_val_if_fail (out_info != NULL, FALSE);
1331
1332 if (config)
1333 opt_matrix =
1334 gst_structure_get_value (config, GST_AUDIO_CONVERTER_OPT_MIX_MATRIX);
1335
1336 if (opt_matrix
1337 && !check_mix_matrix (in_info->channels, out_info->channels, opt_matrix))
1338 goto invalid_mix_matrix;
1339
1340 if ((GST_AUDIO_INFO_CHANNELS (in_info) != GST_AUDIO_INFO_CHANNELS (out_info))
1341 && (GST_AUDIO_INFO_IS_UNPOSITIONED (in_info)
1342 || GST_AUDIO_INFO_IS_UNPOSITIONED (out_info))
1343 && !opt_matrix)
1344 goto unpositioned;
1345
1346 convert = g_slice_new0 (GstAudioConverter);
1347
1348 convert->flags = flags;
1349 convert->in = *in_info;
1350 convert->out = *out_info;
1351
1352 /* default config */
1353 convert->config = gst_structure_new_empty ("GstAudioConverter");
1354 if (config)
1355 gst_audio_converter_update_config (convert, 0, 0, config);
1356
1357 GST_INFO ("unitsizes: %d -> %d", in_info->bpf, out_info->bpf);
1358
1359 /* step 1, unpack */
1360 prev = chain_unpack (convert);
1361 /* step 2, optional convert from S32 to F64 for channel mix */
1362 prev = chain_convert_in (convert, prev);
1363 /* step 3, channel mix */
1364 prev = chain_mix (convert, prev);
1365 /* step 4, resample */
1366 prev = chain_resample (convert, prev);
1367 /* step 5, optional convert for quantize */
1368 prev = chain_convert_out (convert, prev);
1369 /* step 6, optional quantize */
1370 prev = chain_quantize (convert, prev);
1371 /* step 7, change layout */
1372 prev = chain_change_layout (convert, prev);
1373 /* step 8, pack */
1374 convert->chain_end = chain_pack (convert, prev);
1375
1376 convert->convert = converter_generic;
1377 convert->in_place = FALSE;
1378 convert->passthrough = FALSE;
1379
1380 /* optimize */
1381 if (convert->mix_passthrough) {
1382 if (out_info->finfo->format == in_info->finfo->format) {
1383 if (convert->resampler == NULL) {
1384 if (out_info->layout == in_info->layout) {
1385 GST_INFO ("same formats, same layout, no resampler and "
1386 "passthrough mixing -> passthrough");
1387 convert->convert = converter_passthrough;
1388 convert->in_place = TRUE;
1389 convert->passthrough = TRUE;
1390 }
1391 } else {
1392 if (is_intermediate_format (in_info->finfo->format)) {
1393 GST_INFO ("same formats, and passthrough mixing -> only resampling");
1394 convert->convert = converter_resample;
1395 }
1396 }
1397 } else if (GST_AUDIO_FORMAT_IS_ENDIAN_CONVERSION (out_info->finfo,
1398 in_info->finfo)) {
1399 if (convert->resampler == NULL && out_info->layout == in_info->layout) {
1400 GST_INFO ("no resampler, passthrough mixing -> only endian conversion");
1401 convert->convert = converter_endian;
1402 convert->in_place = TRUE;
1403
1404 switch (GST_AUDIO_INFO_WIDTH (in_info)) {
1405 case 16:
1406 GST_DEBUG ("initializing 16-bit endian conversion");
1407 convert->swap_endian = converter_swap_endian_16;
1408 break;
1409 case 24:
1410 GST_DEBUG ("initializing 24-bit endian conversion");
1411 convert->swap_endian = converter_swap_endian_24;
1412 break;
1413 case 32:
1414 GST_DEBUG ("initializing 32-bit endian conversion");
1415 convert->swap_endian = converter_swap_endian_32;
1416 break;
1417 case 64:
1418 GST_DEBUG ("initializing 64-bit endian conversion");
1419 convert->swap_endian = converter_swap_endian_64;
1420 break;
1421 default:
1422 GST_ERROR ("unsupported sample width for endian conversion");
1423 g_assert_not_reached ();
1424 }
1425 }
1426 }
1427 }
1428
1429 setup_allocators (convert);
1430
1431 return convert;
1432
1433 /* ERRORS */
1434 unpositioned:
1435 {
1436 GST_WARNING ("unpositioned channels");
1437 return NULL;
1438 }
1439
1440 invalid_mix_matrix:
1441 {
1442 GST_WARNING ("Invalid mix matrix");
1443 return NULL;
1444 }
1445 }
1446
1447 /**
1448 * gst_audio_converter_free:
1449 * @convert: a #GstAudioConverter
1450 *
1451 * Free a previously allocated @convert instance.
1452 */
1453 void
gst_audio_converter_free(GstAudioConverter * convert)1454 gst_audio_converter_free (GstAudioConverter * convert)
1455 {
1456 AudioChain *chain;
1457
1458 g_return_if_fail (convert != NULL);
1459
1460 /* walk the chain backwards and free all elements */
1461 for (chain = convert->chain_end; chain;) {
1462 AudioChain *prev = chain->prev;
1463 audio_chain_free (chain);
1464 chain = prev;
1465 }
1466
1467 if (convert->quant)
1468 gst_audio_quantize_free (convert->quant);
1469 if (convert->mix)
1470 gst_audio_channel_mixer_free (convert->mix);
1471 if (convert->resampler)
1472 gst_audio_resampler_free (convert->resampler);
1473 gst_audio_info_init (&convert->in);
1474 gst_audio_info_init (&convert->out);
1475
1476 gst_structure_free (convert->config);
1477
1478 g_slice_free (GstAudioConverter, convert);
1479 }
1480
1481 /**
1482 * gst_audio_converter_get_out_frames:
1483 * @convert: a #GstAudioConverter
1484 * @in_frames: number of input frames
1485 *
1486 * Calculate how many output frames can be produced when @in_frames input
1487 * frames are given to @convert.
1488 *
1489 * Returns: the number of output frames
1490 */
1491 gsize
gst_audio_converter_get_out_frames(GstAudioConverter * convert,gsize in_frames)1492 gst_audio_converter_get_out_frames (GstAudioConverter * convert,
1493 gsize in_frames)
1494 {
1495 if (convert->resampler)
1496 return gst_audio_resampler_get_out_frames (convert->resampler, in_frames);
1497 else
1498 return in_frames;
1499 }
1500
1501 /**
1502 * gst_audio_converter_get_in_frames:
1503 * @convert: a #GstAudioConverter
1504 * @out_frames: number of output frames
1505 *
1506 * Calculate how many input frames are currently needed by @convert to produce
1507 * @out_frames of output frames.
1508 *
1509 * Returns: the number of input frames
1510 */
1511 gsize
gst_audio_converter_get_in_frames(GstAudioConverter * convert,gsize out_frames)1512 gst_audio_converter_get_in_frames (GstAudioConverter * convert,
1513 gsize out_frames)
1514 {
1515 if (convert->resampler)
1516 return gst_audio_resampler_get_in_frames (convert->resampler, out_frames);
1517 else
1518 return out_frames;
1519 }
1520
1521 /**
1522 * gst_audio_converter_get_max_latency:
1523 * @convert: a #GstAudioConverter
1524 *
1525 * Get the maximum number of input frames that the converter would
1526 * need before producing output.
1527 *
1528 * Returns: the latency of @convert as expressed in the number of
1529 * frames.
1530 */
1531 gsize
gst_audio_converter_get_max_latency(GstAudioConverter * convert)1532 gst_audio_converter_get_max_latency (GstAudioConverter * convert)
1533 {
1534 if (convert->resampler)
1535 return gst_audio_resampler_get_max_latency (convert->resampler);
1536 else
1537 return 0;
1538 }
1539
1540 /**
1541 * gst_audio_converter_reset:
1542 * @convert: a #GstAudioConverter
1543 *
1544 * Reset @convert to the state it was when it was first created, clearing
1545 * any history it might currently have.
1546 */
1547 void
gst_audio_converter_reset(GstAudioConverter * convert)1548 gst_audio_converter_reset (GstAudioConverter * convert)
1549 {
1550 if (convert->resampler)
1551 gst_audio_resampler_reset (convert->resampler);
1552 if (convert->quant)
1553 gst_audio_quantize_reset (convert->quant);
1554 }
1555
1556 /**
1557 * gst_audio_converter_samples:
1558 * @convert: a #GstAudioConverter
1559 * @flags: extra #GstAudioConverterFlags
1560 * @in: input frames
1561 * @in_frames: number of input frames
1562 * @out: output frames
1563 * @out_frames: number of output frames
1564 *
1565 * Perform the conversion with @in_frames in @in to @out_frames in @out
1566 * using @convert.
1567 *
1568 * In case the samples are interleaved, @in and @out must point to an
1569 * array with a single element pointing to a block of interleaved samples.
1570 *
1571 * If non-interleaved samples are used, @in and @out must point to an
1572 * array with pointers to memory blocks, one for each channel.
1573 *
1574 * @in may be %NULL, in which case @in_frames of silence samples are processed
1575 * by the converter.
1576 *
1577 * This function always produces @out_frames of output and consumes @in_frames of
1578 * input. Use gst_audio_converter_get_out_frames() and
1579 * gst_audio_converter_get_in_frames() to make sure @in_frames and @out_frames
1580 * are matching and @in and @out point to enough memory.
1581 *
1582 * Returns: %TRUE is the conversion could be performed.
1583 */
1584 gboolean
gst_audio_converter_samples(GstAudioConverter * convert,GstAudioConverterFlags flags,gpointer in[],gsize in_frames,gpointer out[],gsize out_frames)1585 gst_audio_converter_samples (GstAudioConverter * convert,
1586 GstAudioConverterFlags flags, gpointer in[], gsize in_frames,
1587 gpointer out[], gsize out_frames)
1588 {
1589 g_return_val_if_fail (convert != NULL, FALSE);
1590 g_return_val_if_fail (out != NULL, FALSE);
1591
1592 if (in_frames == 0) {
1593 GST_LOG ("skipping empty buffer");
1594 return TRUE;
1595 }
1596 return convert->convert (convert, flags, in, in_frames, out, out_frames);
1597 }
1598
1599 /**
1600 * gst_audio_converter_convert:
1601 * @convert: a #GstAudioConverter
1602 * @flags: extra #GstAudioConverterFlags
1603 * @in: (array length=in_size) (element-type guint8): input data
1604 * @in_size: size of @in
1605 * @out: (out) (array length=out_size) (element-type guint8): a pointer where
1606 * the output data will be written
1607 * @out_size: (out): a pointer where the size of @out will be written
1608 *
1609 * Convenience wrapper around gst_audio_converter_samples(), which will
1610 * perform allocation of the output buffer based on the result from
1611 * gst_audio_converter_get_out_frames().
1612 *
1613 * Returns: %TRUE is the conversion could be performed.
1614 *
1615 * Since: 1.14
1616 */
1617 gboolean
gst_audio_converter_convert(GstAudioConverter * convert,GstAudioConverterFlags flags,gpointer in,gsize in_size,gpointer * out,gsize * out_size)1618 gst_audio_converter_convert (GstAudioConverter * convert,
1619 GstAudioConverterFlags flags, gpointer in, gsize in_size,
1620 gpointer * out, gsize * out_size)
1621 {
1622 gsize in_frames;
1623 gsize out_frames;
1624
1625 g_return_val_if_fail (convert != NULL, FALSE);
1626 g_return_val_if_fail (flags ^ GST_AUDIO_CONVERTER_FLAG_IN_WRITABLE, FALSE);
1627
1628 in_frames = in_size / convert->in.bpf;
1629 out_frames = gst_audio_converter_get_out_frames (convert, in_frames);
1630
1631 *out_size = out_frames * convert->out.bpf;
1632 *out = g_malloc0 (*out_size);
1633
1634 return gst_audio_converter_samples (convert, flags, &in, in_frames, out,
1635 out_frames);
1636 }
1637
1638 /**
1639 * gst_audio_converter_supports_inplace:
1640 * @convert: a #GstAudioConverter
1641 *
1642 * Returns whether the audio converter can perform the conversion in-place.
1643 * The return value would be typically input to gst_base_transform_set_in_place()
1644 *
1645 * Returns: %TRUE when the conversion can be done in place.
1646 */
1647 gboolean
gst_audio_converter_supports_inplace(GstAudioConverter * convert)1648 gst_audio_converter_supports_inplace (GstAudioConverter * convert)
1649 {
1650 return convert->in_place;
1651 }
1652
1653 /**
1654 * gst_audio_converter_is_passthrough:
1655 *
1656 * Returns whether the audio converter will operate in passthrough mode.
1657 * The return value would be typically input to gst_base_transform_set_passthrough()
1658 *
1659 * Returns: %TRUE when no conversion will actually occur.
1660 *
1661 * Since: 1.16
1662 */
1663 gboolean
gst_audio_converter_is_passthrough(GstAudioConverter * convert)1664 gst_audio_converter_is_passthrough (GstAudioConverter * convert)
1665 {
1666 return convert->passthrough;
1667 }
1668