1 /*****************************************************************************
2 * format.c : PCM format converter
3 *****************************************************************************
4 * Copyright (C) 2002-2005 the VideoLAN team
5 * Copyright (C) 2010 Laurent Aimar
8 * Authors: Christophe Massiot <massiot@via.ecp.fr>
9 * Gildas Bazin <gbazin@videolan.org>
10 * Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
39 #include <vlc_block.h>
40 #include <vlc_filter.h>
42 /*****************************************************************************
44 *****************************************************************************/
45 static int Open(vlc_object_t *);
46 static void Close(vlc_object_t *);
49 set_description(N_("Audio filter for PCM format conversion"))
50 set_category(CAT_AUDIO)
51 set_subcategory(SUBCAT_AUDIO_MISC)
52 set_capability("audio filter", 1)
53 set_callbacks(Open, Close)
56 /*****************************************************************************
58 *****************************************************************************/
60 static block_t *Filter(filter_t *, block_t *);
62 typedef block_t *(*cvt_direct_t)(filter_t *, block_t *);
63 typedef void (*cvt_indirect_t)(block_t *, const block_t *);
64 typedef void (*cvt_swap_t)(block_t *);
68 cvt_direct_t directs[2];
69 cvt_indirect_t indirects[2];
70 unsigned indirects_ratio[2][2];
74 static cvt_direct_t FindDirect(vlc_fourcc_t src, vlc_fourcc_t dst);
75 static cvt_indirect_t FindIndirect(vlc_fourcc_t src, vlc_fourcc_t dst);
76 static cvt_swap_t FindSwap(vlc_fourcc_t *dst, vlc_fourcc_t src);
79 static int Open(vlc_object_t *object)
81 filter_t *filter = (filter_t *)object;
83 const es_format_t *src = &filter->fmt_in;
84 es_format_t *dst = &filter->fmt_out;
86 if (!AOUT_FMTS_SIMILAR(&src->audio, &dst->audio))
88 if (src->i_codec == dst->i_codec)
91 cvt_direct_t direct = FindDirect(src->i_codec, dst->i_codec);
93 filter->pf_audio_filter = direct;
99 filter_sys_t *sys = malloc(sizeof(*sys));
103 /* Find the cost minimal conversion */
104 for (unsigned mask = 0; mask <= 0x07; mask++) {
105 memset(sys, 0, sizeof(*sys));
107 vlc_fourcc_t fsrc = src->i_codec;
108 vlc_fourcc_t fdst = dst->i_codec;
111 sys->pre = FindSwap(&fsrc, fsrc);
116 sys->post = FindSwap(&fdst, fdst);
121 const bool has_middle = mask & 0x04;
122 for (int i = 0; fsrc != fdst && i < 1 + has_middle; i++) {
123 /* XXX Hardcoded middle format: native 16 bits */
124 vlc_fourcc_t ftarget = has_middle && i == 0 ? VLC_CODEC_S16N : fdst;
125 sys->directs[i] = FindDirect(fsrc, ftarget);
126 if (!sys->directs[i]) {
127 sys->indirects[i] = FindIndirect(fsrc, ftarget);
128 if (!sys->indirects[i])
130 sys->indirects_ratio[i][0] = aout_BitsPerSample(fsrc) / 8;
131 sys->indirects_ratio[i][1] = aout_BitsPerSample(ftarget) / 8;
138 /* We have a full conversion */
139 filter->pf_audio_filter = Filter;
147 dst->audio = src->audio;
148 dst->audio.i_format = dst->i_codec;
149 aout_FormatPrepare(&dst->audio);
151 msg_Dbg(filter, "%4.4s->%4.4s, bits per sample: %i->%i",
152 (char *)&src->i_codec, (char *)&dst->i_codec,
153 src->audio.i_bitspersample, dst->audio.i_bitspersample);
158 static void Close(vlc_object_t *object)
160 filter_t *filter = (filter_t *)object;
165 static block_t *Filter(filter_t *filter, block_t *block)
167 filter_sys_t *sys = filter->p_sys;
172 for (int i = 0; i < 2; i++) {
173 if (sys->directs[i]) {
174 block = sys->directs[i](filter, block);
175 } else if (sys->indirects[i]) {
176 int dst_size = sys->indirects_ratio[i][1] *
177 (block->i_buffer / sys->indirects_ratio[i][0]);
178 block_t *out = filter_NewAudioBuffer(filter, dst_size);
180 block_Release(block);
183 out->i_nb_samples = block->i_nb_samples;
184 out->i_dts = block->i_dts;
185 out->i_pts = block->i_pts;
186 out->i_length = block->i_length;
187 out->i_rate = block->i_rate;
189 sys->indirects[i](out, block);
191 block_Release(block);
202 static block_t *S16toS8(filter_t *filter, block_t *b)
205 int16_t *src = (int16_t *)b->p_buffer;
206 int8_t *dst = (int8_t *)src;
207 for (int i = b->i_buffer / 2; i--;)
208 *dst++ = (*src++) >> 8;
213 static block_t *S16toU8(filter_t *filter, block_t *b)
216 int16_t *src = (int16_t *)b->p_buffer;
217 uint8_t *dst = (uint8_t *)src;
218 for (int i = b->i_buffer / 2; i--;)
219 *dst++ = ((*src++) + 32768) >> 8;
224 static block_t *U16toS8(filter_t *filter, block_t *b)
227 uint16_t *src = (uint16_t *)b->p_buffer;
228 int8_t *dst = (int8_t *)src;
229 for (int i = b->i_buffer / 2; i--;)
230 *dst++ = ((int)(*src++) - 32768) >> 8;
235 static block_t *U16toU8(filter_t *filter, block_t *b)
238 uint16_t *src = (uint16_t *)b->p_buffer;
239 uint8_t *dst = (uint8_t *)src;
240 for (int i = b->i_buffer / 2; i--;)
241 *dst++ = (*src++) >> 8;
247 static block_t *S16toU16(filter_t *filter, block_t *b)
250 int16_t *src = (int16_t *)b->p_buffer;
251 uint16_t *dst = (uint16_t *)src;
252 for (int i = b->i_buffer / 2; i--;)
253 *dst++ = (*src++) + 32768;
258 static block_t *U16toS16(filter_t *filter, block_t *b)
261 uint16_t *src = (uint16_t *)b->p_buffer;
262 int16_t *dst = (int16_t *)src;
263 for (int i = b->i_buffer / 2; i--;)
264 *dst++ = (int)(*src++) - 32768;
269 static block_t *S8toU8(filter_t *filter, block_t *b)
272 int8_t *src = (int8_t *)b->p_buffer;
273 uint8_t *dst = (uint8_t *)src;
274 for (int i = b->i_buffer; i--;)
275 *dst++ = ((*src++) + 128);
279 static block_t *U8toS8(filter_t *filter, block_t *b)
282 uint8_t *src = (uint8_t *)b->p_buffer;
283 int8_t *dst = (int8_t *)src;
284 for (int i = b->i_buffer; i--;)
285 *dst++ = ((*src++) - 128);
289 static block_t *S24toS16(filter_t *filter, block_t *b)
292 uint8_t *src = (uint8_t *)b->p_buffer;
293 uint8_t *dst = (uint8_t *)src;
294 for (int i = b->i_buffer / 3; i--;) {
295 #ifdef WORDS_BIGENDIAN
306 b->i_buffer = b->i_buffer * 2 / 3;
309 static block_t *S32toS16(filter_t *filter, block_t *b)
312 int32_t *src = (int32_t *)b->p_buffer;
313 int16_t *dst = (int16_t *)src;
314 for (int i = b->i_buffer / 4; i--;)
315 *dst++ = (*src++) >> 16;
320 static block_t *Fl32toS16(filter_t *filter, block_t *b)
323 float *src = (float *)b->p_buffer;
324 int16_t *dst = (int16_t *)src;
325 for (int i = b->i_buffer / 4; i--;) {
328 if (*src >= 1.0) *dst = 32767;
329 else if (*src < -1.0) *dst = -32768;
330 else *dst = *src * 32768.0;
333 /* This is walken's trick based on IEEE float format. */
334 union { float f; int32_t i; } u;
335 u.f = *src++ + 384.0;
336 if (u.i > 0x43c07fff)
338 else if (u.i < 0x43bf8000)
341 *dst++ = u.i - 0x43c00000;
348 static block_t *Fl64toS16(filter_t *filter, block_t *b)
351 double *src = (double *)b->p_buffer;
352 int16_t *dst = (int16_t *)src;
353 for (int i = b->i_buffer / 8; i--;) {
354 const double v = *src++;
361 *dst++ = v * 32768.0;
367 static block_t *S32toFl32(filter_t *filter, block_t *b)
370 int32_t *src = (int32_t*)b->p_buffer;
371 float *dst = (float *)src;
372 for (int i = b->i_buffer / 4; i--;)
373 *dst++ = (float)(*src++) / 2147483648.0;
376 static block_t *Fi32toFl32(filter_t *filter, block_t *b)
379 vlc_fixed_t *src = (vlc_fixed_t *)b->p_buffer;
380 float *dst = (float *)src;
381 for (int i = b->i_buffer / 4; i--;)
382 *dst++ = *src++ / (float)FIXED32_ONE;
385 static block_t *Fi32toS16(filter_t *filter, block_t *b)
388 vlc_fixed_t *src = (vlc_fixed_t *)b->p_buffer;
389 int16_t *dst = (int16_t *)src;
390 for (int i = b->i_buffer / 4; i--;) {
391 const vlc_fixed_t v = *src++;
392 if (v >= FIXED32_ONE)
394 else if (v <= -FIXED32_ONE)
397 *dst++ = v >> (32 - FIXED32_FRACBITS);
404 static void X8toX16(block_t *bdst, const block_t *bsrc)
406 uint8_t *src = (uint8_t *)bsrc->p_buffer;
407 uint16_t *dst = (uint16_t *)bdst->p_buffer;
408 for (int i = bsrc->i_buffer; i--;)
409 *dst++ = (*src++) << 8;
411 static void S8toU16(block_t *bdst, const block_t *bsrc)
413 int8_t *src = (int8_t *)bsrc->p_buffer;
414 uint16_t *dst = (uint16_t *)bdst->p_buffer;
415 for (int i = bsrc->i_buffer; i--;)
416 *dst++ = ((*src++) + 128) << 8;
418 static void U8toS16(block_t *bdst, const block_t *bsrc)
420 uint8_t *src = (uint8_t *)bsrc->p_buffer;
421 int16_t *dst = (int16_t *)bdst->p_buffer;
422 for (int i = bsrc->i_buffer; i--;)
423 *dst++ = ((*src++) - 128) << 8;
426 static void S16toS24(block_t *bdst, const block_t *bsrc)
428 uint8_t *src = (uint8_t *)bsrc->p_buffer;
429 uint8_t *dst = (uint8_t *)bdst->p_buffer;
431 for (int i = bsrc->i_buffer / 2; i--;) {
432 #ifdef WORDS_BIGENDIAN
443 static void S16toS32(block_t *bdst, const block_t *bsrc)
445 int16_t *src = (int16_t *)bsrc->p_buffer;
446 int32_t *dst = (int32_t *)bdst->p_buffer;
447 for (int i = bsrc->i_buffer / 2; i--;)
448 *dst++ = *src++ << 16;
450 static void S16toFl32(block_t *bdst, const block_t *bsrc)
452 int16_t *src = (int16_t *)bsrc->p_buffer;
453 float *dst = (float *)bdst->p_buffer;
454 for (int i = bsrc->i_buffer / 2; i--;) {
457 *dst++ = (float)*src++ / 32768.0;
459 /* This is walken's trick based on IEEE float format. On my PIII
460 * this takes 16 seconds to perform one billion conversions, instead
461 * of 19 seconds for the above division. */
462 union { float f; int32_t i; } u;
463 u.i = *src++ + 0x43c00000;
464 *dst++ = u.f - 384.0;
468 static void S24toFl32(block_t *bdst, const block_t *bsrc)
470 uint8_t *src = bsrc->p_buffer;
471 float *dst = (float *)bdst->p_buffer;
472 for (int i = bsrc->i_buffer / 3; i--;) {
473 #ifdef WORDS_BIGENDIAN
474 int32_t v = (src[0] << 24) | (src[1] << 16) | (src[2] << 8);
476 int32_t v = (src[0] << 8) | (src[1] << 16) | (src[2] << 24);
479 *dst++ = v / 2147483648.0;
484 #define XCHG(type, a, b) \
485 do { type _tmp = a; a = b; b = _tmp; } while(0)
486 static void Swap64(block_t *b)
488 uint8_t *data = (uint8_t *)b->p_buffer;
489 for (size_t i = 0; i < b->i_buffer / 8; i++) {
490 XCHG(uint8_t, data[0], data[7]);
491 XCHG(uint8_t, data[1], data[6]);
492 XCHG(uint8_t, data[2], data[5]);
493 XCHG(uint8_t, data[3], data[4]);
497 static void Swap32(block_t *b)
499 uint8_t *data = (uint8_t *)b->p_buffer;
500 for (size_t i = 0; i < b->i_buffer / 4; i++) {
501 XCHG(uint8_t, data[0], data[3]);
502 XCHG(uint8_t, data[1], data[2]);
506 static void Swap24(block_t *b)
508 uint8_t *data = (uint8_t *)b->p_buffer;
509 for (size_t i = 0; i < b->i_buffer / 3; i++) {
510 XCHG(uint8_t, data[0], data[2]);
514 static void Swap16(block_t *b)
516 uint8_t *data = (uint8_t *)b->p_buffer;
517 for (size_t i = 0; i < b->i_buffer / 2; i++) {
518 XCHG(uint8_t, data[0], data[1]);
524 static const struct {
527 cvt_direct_t convert;
529 { VLC_CODEC_FL64, VLC_CODEC_S16N, Fl64toS16 },
530 { VLC_CODEC_FI32, VLC_CODEC_FL32, Fi32toFl32 },
531 { VLC_CODEC_FI32, VLC_CODEC_S16N, Fi32toS16 },
532 { VLC_CODEC_S32N, VLC_CODEC_FL32, S32toFl32 },
534 { VLC_CODEC_S24N, VLC_CODEC_S16N, S24toS16 },
535 { VLC_CODEC_S32N, VLC_CODEC_S32N, S32toS16 },
536 { VLC_CODEC_FL32, VLC_CODEC_S16N, Fl32toS16 },
538 { VLC_CODEC_S16N, VLC_CODEC_S8, S16toS8 },
539 { VLC_CODEC_S16N, VLC_CODEC_U8, S16toU8 },
540 { VLC_CODEC_S16N, VLC_CODEC_U16N, S16toU16 },
542 { VLC_CODEC_U16N, VLC_CODEC_S8, U16toS8 },
543 { VLC_CODEC_U16N, VLC_CODEC_U8, U16toU8 },
544 { VLC_CODEC_U16N, VLC_CODEC_S16N, U16toS16 },
546 { VLC_CODEC_U8, VLC_CODEC_S8, U8toS8 },
547 { VLC_CODEC_S8, VLC_CODEC_U8, S8toU8 },
551 static const struct {
554 cvt_indirect_t convert;
555 } cvt_indirects[] = {
556 { VLC_CODEC_S24N, VLC_CODEC_FL32, S24toFl32 },
558 { VLC_CODEC_S16N, VLC_CODEC_S24N, S16toS24 },
559 { VLC_CODEC_S16N, VLC_CODEC_S32N, S16toS32 },
560 { VLC_CODEC_S16N, VLC_CODEC_FL32, S16toFl32 },
562 { VLC_CODEC_S8, VLC_CODEC_S16N, X8toX16 },
563 { VLC_CODEC_S8, VLC_CODEC_U16N, S8toU16 },
565 { VLC_CODEC_U8, VLC_CODEC_U16N, X8toX16 },
566 { VLC_CODEC_U8, VLC_CODEC_S16N, U8toS16 },
569 static const struct {
574 { VLC_CODEC_F64L, VLC_CODEC_F64B, Swap64 },
575 { VLC_CODEC_F32L, VLC_CODEC_F32B, Swap32 },
576 { VLC_CODEC_S32L, VLC_CODEC_S32B, Swap32 },
577 { VLC_CODEC_U32L, VLC_CODEC_U32B, Swap32 },
578 { VLC_CODEC_S24L, VLC_CODEC_S24B, Swap24 },
579 { VLC_CODEC_U24L, VLC_CODEC_U24B, Swap24 },
580 { VLC_CODEC_S16L, VLC_CODEC_S16B, Swap16 },
581 { VLC_CODEC_U16L, VLC_CODEC_U16B, Swap16 },
585 static cvt_direct_t FindDirect(vlc_fourcc_t src, vlc_fourcc_t dst)
587 for (int i = 0; cvt_directs[i].convert; i++) {
588 if (cvt_directs[i].src == src &&
589 cvt_directs[i].dst == dst)
590 return cvt_directs[i].convert;
594 static cvt_indirect_t FindIndirect(vlc_fourcc_t src, vlc_fourcc_t dst)
596 for (int i = 0; cvt_indirects[i].convert; i++) {
597 if (cvt_indirects[i].src == src &&
598 cvt_indirects[i].dst == dst)
599 return cvt_indirects[i].convert;
603 static cvt_swap_t FindSwap(vlc_fourcc_t *dst, vlc_fourcc_t src)
605 for (int i = 0; cvt_swaps[i].convert; i++) {
606 if (cvt_swaps[i].a == src) {
607 *dst = cvt_swaps[i].b;
608 return cvt_swaps[i].convert;
609 } else if (cvt_swaps[i].b == src) {
610 *dst = cvt_swaps[i].a;
611 return cvt_swaps[i].convert;