From 2c22b194c8c6c7c134db7eb35c9feef81f5fec4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= <remi@remlab.net> Date: Fri, 21 Dec 2012 20:33:45 +0200 Subject: [PATCH] format: add missing conversions between U8, S16N, FL32, S32N and FL64 And simplify accordingly. --- modules/audio_filter/Modules.am | 4 +- modules/audio_filter/converter/format.c | 485 +++++++++++++++--------- 2 files changed, 312 insertions(+), 177 deletions(-) diff --git a/modules/audio_filter/Modules.am b/modules/audio_filter/Modules.am index da4626c82e3a..4963a39c1a87 100644 --- a/modules/audio_filter/Modules.am +++ b/modules/audio_filter/Modules.am @@ -51,7 +51,9 @@ SOURCES_a52tofloat32 = converter/a52tofloat32.c SOURCES_dtstospdif = converter/dtstospdif.c SOURCES_dtstofloat32 = converter/dtstofloat32.c SOURCES_mpgatofixed32 = converter/mpgatofixed32.c -SOURCES_audio_format = converter/format.c +libaudio_format_plugin_la_SOURCES = converter/format.c +libaudio_format_plugin_la_CFLAGS = $(AM_CFLAGS) +libaudio_format_plugin_la_LIBADD = $(AM_LIBADD) $(LIBM) libvlc_LTLIBRARIES += \ liba52tospdif_plugin.la \ diff --git a/modules/audio_filter/converter/format.c b/modules/audio_filter/converter/format.c index 372ce7bf5350..db3faf68c25f 100644 --- a/modules/audio_filter/converter/format.c +++ b/modules/audio_filter/converter/format.c @@ -31,6 +31,7 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif +#include <math.h> #include <assert.h> #include <vlc_common.h> @@ -43,35 +44,22 @@ * Module descriptor *****************************************************************************/ static int Open(vlc_object_t *); -static void Close(vlc_object_t *); vlc_module_begin() set_description(N_("Audio filter for PCM format conversion")) set_category(CAT_AUDIO) set_subcategory(SUBCAT_AUDIO_MISC) set_capability("audio converter", 1) - set_callbacks(Open, Close) + set_callbacks(Open, NULL) vlc_module_end() /***************************************************************************** * Local prototypes *****************************************************************************/ -static block_t *Filter(filter_t *, block_t *); +typedef block_t *(*cvt_t)(filter_t *, block_t *); +static cvt_t FindConversion(vlc_fourcc_t src, vlc_fourcc_t dst); -typedef block_t *(*cvt_direct_t)(filter_t *, block_t *); -typedef void (*cvt_indirect_t)(block_t *, const block_t *); - -struct filter_sys_t { - cvt_direct_t directs[2]; - cvt_indirect_t indirects[2]; - unsigned indirects_ratio[2][2]; -}; - -static cvt_direct_t FindDirect(vlc_fourcc_t src, vlc_fourcc_t dst); -static cvt_indirect_t FindIndirect(vlc_fourcc_t src, vlc_fourcc_t dst); - -/* */ static int Open(vlc_object_t *object) { filter_t *filter = (filter_t *)object; @@ -84,54 +72,9 @@ static int Open(vlc_object_t *object) if (src->i_codec == dst->i_codec) return VLC_EGENERIC; - cvt_direct_t direct = FindDirect(src->i_codec, dst->i_codec); - if (direct) { - filter->pf_audio_filter = direct; - filter->p_sys = NULL; - goto end; - } - - /* */ - filter_sys_t *sys = malloc(sizeof(*sys)); - if (!sys) - return VLC_ENOMEM; - - /* Find the cost minimal conversion */ - for (unsigned mask = 0; mask <= 0x01; mask ++) { - memset(sys, 0, sizeof(*sys)); - - vlc_fourcc_t fsrc = src->i_codec; - vlc_fourcc_t fdst = dst->i_codec; - - const bool has_middle = mask & 0x01; - for (int i = 0; fsrc != fdst && i < 1 + has_middle; i++) { - /* XXX Hardcoded middle format: native 16 bits */ - vlc_fourcc_t ftarget = has_middle && i == 0 ? VLC_CODEC_S16N : fdst; - sys->directs[i] = FindDirect(fsrc, ftarget); - if (!sys->directs[i]) { - sys->indirects[i] = FindIndirect(fsrc, ftarget); - if (!sys->indirects[i]) - break; - sys->indirects_ratio[i][0] = aout_BitsPerSample(fsrc) / 8; - sys->indirects_ratio[i][1] = aout_BitsPerSample(ftarget) / 8; - } - fsrc = ftarget; - } - if (fsrc != fdst) - continue; - - /* We have a full conversion */ - filter->pf_audio_filter = Filter; - filter->p_sys = sys; - goto end; - } - free(sys); - return VLC_EGENERIC; - -end: - dst->audio = src->audio; - dst->audio.i_format = dst->i_codec; - aout_FormatPrepare(&dst->audio); + filter->pf_audio_filter = FindConversion(src->i_codec, dst->i_codec); + if (filter->pf_audio_filter == NULL) + return VLC_EGENERIC; msg_Dbg(filter, "%4.4s->%4.4s, bits per sample: %i->%i", (char *)&src->i_codec, (char *)&dst->i_codec, @@ -139,68 +82,167 @@ end: return VLC_SUCCESS; } -/* */ -static void Close(vlc_object_t *object) + +/*** from U8 ***/ +static block_t *U8toS16(filter_t *filter, block_t *bsrc) { - filter_t *filter = (filter_t *)object; - free(filter->p_sys); + block_t *bdst = block_Alloc(bsrc->i_buffer * 2); + if (unlikely(bdst == NULL)) + goto out; + + uint8_t *src = (uint8_t *)bsrc->p_buffer; + int16_t *dst = (int16_t *)bdst->p_buffer; + for (size_t i = bsrc->i_buffer; i--;) + *dst++ = ((*src++) - 128) << 8; +out: + block_Release(bsrc); + VLC_UNUSED(filter); + return bdst; } -/* */ -static block_t *Filter(filter_t *filter, block_t *block) +static block_t *U8toFl32(filter_t *filter, block_t *bsrc) { - filter_sys_t *sys = filter->p_sys; - - for (int i = 0; i < 2; i++) { - if (sys->directs[i]) { - block = sys->directs[i](filter, block); - } else if (sys->indirects[i]) { - int dst_size = sys->indirects_ratio[i][1] * - (block->i_buffer / sys->indirects_ratio[i][0]); - block_t *out = filter_NewAudioBuffer(filter, dst_size); - if (!out) { - block_Release(block); - return NULL; - } - out->i_nb_samples = block->i_nb_samples; - out->i_dts = block->i_dts; - out->i_pts = block->i_pts; - out->i_length = block->i_length; - - sys->indirects[i](out, block); - - block_Release(block); - block = out; - } - } + block_t *bdst = block_Alloc(bsrc->i_buffer * 4); + if (unlikely(bdst == NULL)) + goto out; - return block; + uint8_t *src = (uint8_t *)bsrc->p_buffer; + float *dst = (float *)bdst->p_buffer; + for (size_t i = bsrc->i_buffer; i--;) + *dst++ = ((float)((*src++) - 128)) / 128.f; +out: + block_Release(bsrc); + VLC_UNUSED(filter); + return bdst; } -/* */ +static block_t *U8toS32(filter_t *filter, block_t *bsrc) +{ + block_t *bdst = block_Alloc(bsrc->i_buffer * 4); + if (unlikely(bdst == NULL)) + goto out; + + uint8_t *src = (uint8_t *)bsrc->p_buffer; + int32_t *dst = (int32_t *)bdst->p_buffer; + for (size_t i = bsrc->i_buffer; i--;) + *dst++ = ((*src++) - 128) << 24; +out: + block_Release(bsrc); + VLC_UNUSED(filter); + return bdst; +} + +static block_t *U8toFl64(filter_t *filter, block_t *bsrc) +{ + block_t *bdst = block_Alloc(bsrc->i_buffer * 8); + if (unlikely(bdst == NULL)) + goto out; + + uint8_t *src = (uint8_t *)bsrc->p_buffer; + double *dst = (double *)bdst->p_buffer; + for (size_t i = bsrc->i_buffer; i--;) + *dst++ = ((double)((*src++) - 128)) / 128.; +out: + block_Release(bsrc); + VLC_UNUSED(filter); + return bdst; +} + + +/*** from S16N ***/ static block_t *S16toU8(filter_t *filter, block_t *b) { VLC_UNUSED(filter); int16_t *src = (int16_t *)b->p_buffer; uint8_t *dst = (uint8_t *)src; - for (int i = b->i_buffer / 2; i--;) + for (size_t i = b->i_buffer / 2; i--;) *dst++ = ((*src++) + 32768) >> 8; b->i_buffer /= 2; return b; } -static block_t *S32toS16(filter_t *filter, block_t *b) +static block_t *S16toFl32(filter_t *filter, block_t *bsrc) { + block_t *bdst = block_Alloc(bsrc->i_buffer * 2); + if (unlikely(bdst == NULL)) + goto out; + + int16_t *src = (int16_t *)bsrc->p_buffer; + float *dst = (float *)bdst->p_buffer; + for (size_t i = bsrc->i_buffer / 2; i--;) +#if 0 + /* Slow version */ + *dst++ = (float)*src++ / 32768.f; +#else + { /* This is Walken's trick based on IEEE float format. On my PIII + * this takes 16 seconds to perform one billion conversions, instead + * of 19 seconds for the above division. */ + union { float f; int32_t i; } u; + u.i = *src++ + 0x43c00000; + *dst++ = u.f - 384.0; + } +#endif +out: + block_Release(bsrc); VLC_UNUSED(filter); - int32_t *src = (int32_t *)b->p_buffer; - int16_t *dst = (int16_t *)src; - for (int i = b->i_buffer / 4; i--;) - *dst++ = (*src++) >> 16; + return bdst; +} - b->i_buffer /= 2; +static block_t *S16toS32(filter_t *filter, block_t *bsrc) +{ + block_t *bdst = block_Alloc(bsrc->i_buffer * 2); + if (unlikely(bdst == NULL)) + goto out; + + int16_t *src = (int16_t *)bsrc->p_buffer; + int32_t *dst = (int32_t *)bdst->p_buffer; + for (int i = bsrc->i_buffer / 2; i--;) + *dst++ = *src++ << 16; +out: + block_Release(bsrc); + VLC_UNUSED(filter); + return bdst; +} + +static block_t *S16toFl64(filter_t *filter, block_t *bsrc) +{ + block_t *bdst = block_Alloc(bsrc->i_buffer * 4); + if (unlikely(bdst == NULL)) + goto out; + + int16_t *src = (int16_t *)bsrc->p_buffer; + float *dst = (float *)bdst->p_buffer; + for (size_t i = bsrc->i_buffer / 2; i--;) + *dst++ = (double)*src++ / 32768.; +out: + block_Release(bsrc); + VLC_UNUSED(filter); + return bdst; +} + + +/*** from FL32 ***/ +static block_t *Fl32toU8(filter_t *filter, block_t *b) +{ + float *src = (float *)b->p_buffer; + uint8_t *dst = (uint8_t *)src; + for (size_t i = b->i_buffer / 4; i--;) + { + float s = *(src++) * 128.f; + if (s >= 127.f) + *(dst++) = 255; + else + if (s <= -128.f) + *(dst++) = 0; + else + *(dst++) = lroundf(s) + 128; + } + b->i_buffer /= 4; + VLC_UNUSED(filter); return b; } + static block_t *Fl32toS16(filter_t *filter, block_t *b) { VLC_UNUSED(filter); @@ -211,10 +253,10 @@ static block_t *Fl32toS16(filter_t *filter, block_t *b) /* Slow version. */ if (*src >= 1.0) *dst = 32767; else if (*src < -1.0) *dst = -32768; - else *dst = *src * 32768.0; + else *dst = lroundf(*src * 32768.f); src++; dst++; #else - /* This is walken's trick based on IEEE float format. */ + /* This is Walken's trick based on IEEE float format. */ union { float f; int32_t i; } u; u.f = *src++ + 384.0; if (u.i > 0x43c07fff) @@ -225,104 +267,205 @@ static block_t *Fl32toS16(filter_t *filter, block_t *b) *dst++ = u.i - 0x43c00000; #endif } - b->i_buffer /= 2; return b; } -static block_t *Fl64toS16(filter_t *filter, block_t *b) + +static block_t *Fl32toS32(filter_t *filter, block_t *b) { - VLC_UNUSED(filter); - double *src = (double *)b->p_buffer; - int16_t *dst = (int16_t *)src; - for (int i = b->i_buffer / 8; i--;) { - const double v = *src++; - /* Slow version. */ - if (v >= 1.0) - *dst++ = 32767; - else if (v < -1.0) - *dst++ = -32768; + float *src = (float *)b->p_buffer; + int32_t *dst = (int32_t *)src; + for (size_t i = b->i_buffer / 4; i--;) + { + float s = *(src++) * 2147483648.f; + if (s >= 2147483647.f) + *(dst++) = 2147483647; + else + if (s <= -2147483648.f) + *(dst++) = -2147483648; else - *dst++ = v * 32768.0; + *(dst++) = lroundf(s); } + VLC_UNUSED(filter); + return b; +} + +static block_t *Fl32toFl64(filter_t *filter, block_t *bsrc) +{ + block_t *bdst = block_Alloc(bsrc->i_buffer * 2); + if (unlikely(bdst == NULL)) + goto out; + + float *src = (float *)bsrc->p_buffer; + double *dst = (double *)bdst->p_buffer; + for (size_t i = bsrc->i_buffer / 4; i--;) + *(dst++) = *(src++); +out: + block_Release(bsrc); + VLC_UNUSED(filter); + return bdst; +} + + +/*** from S32N ***/ +static block_t *S32toU8(filter_t *filter, block_t *b) +{ + VLC_UNUSED(filter); + int32_t *src = (int32_t *)b->p_buffer; + uint8_t *dst = (uint8_t *)src; + for (size_t i = b->i_buffer / 4; i--;) + *dst++ = ((*src++) >> 24) + 128; b->i_buffer /= 4; return b; } + +static block_t *S32toS16(filter_t *filter, block_t *b) +{ + VLC_UNUSED(filter); + int32_t *src = (int32_t *)b->p_buffer; + int16_t *dst = (int16_t *)src; + for (size_t i = b->i_buffer / 4; i--;) + *dst++ = (*src++) >> 16; + + b->i_buffer /= 2; + return b; +} + static block_t *S32toFl32(filter_t *filter, block_t *b) { VLC_UNUSED(filter); int32_t *src = (int32_t*)b->p_buffer; float *dst = (float *)src; for (int i = b->i_buffer / 4; i--;) - *dst++ = (float)(*src++) / 2147483648.0; + *dst++ = (float)(*src++) / 2147483648.f; return b; } -/* */ -static void U8toS16(block_t *bdst, const block_t *bsrc) +static block_t *S32toFl64(filter_t *filter, block_t *bsrc) { - uint8_t *src = (uint8_t *)bsrc->p_buffer; - int16_t *dst = (int16_t *)bdst->p_buffer; - for (int i = bsrc->i_buffer; i--;) - *dst++ = ((*src++) - 128) << 8; + block_t *bdst = block_Alloc(bsrc->i_buffer * 2); + if (unlikely(bdst == NULL)) + goto out; + + int32_t *src = (int32_t*)bsrc->p_buffer; + double *dst = (double *)bdst->p_buffer; + for (size_t i = bsrc->i_buffer / 4; i--;) + *dst++ = (double)(*src++) / 2147483648.; +out: + VLC_UNUSED(filter); + block_Release(bsrc); + return bdst; } -static void S16toS32(block_t *bdst, const block_t *bsrc) + +/*** from FL64 ***/ +static block_t *Fl64toU8(filter_t *filter, block_t *b) { - int16_t *src = (int16_t *)bsrc->p_buffer; - int32_t *dst = (int32_t *)bdst->p_buffer; - for (int i = bsrc->i_buffer / 2; i--;) - *dst++ = *src++ << 16; + double *src = (double *)b->p_buffer; + uint8_t *dst = (uint8_t *)src; + for (size_t i = b->i_buffer / 8; i--;) + { + float s = *(src++) * 128.f; + if (s >= 127.) + *(dst++) = 255; + else + if (s <= -128.) + *(dst++) = 0; + else + *(dst++) = lround(s) + 128; + } + b->i_buffer /= 8; + VLC_UNUSED(filter); + return b; } -static void S16toFl32(block_t *bdst, const block_t *bsrc) + +static block_t *Fl64toS16(filter_t *filter, block_t *b) { - int16_t *src = (int16_t *)bsrc->p_buffer; - float *dst = (float *)bdst->p_buffer; - for (int i = bsrc->i_buffer / 2; i--;) { -#if 0 - /* Slow version */ - *dst++ = (float)*src++ / 32768.0; -#else - /* This is walken's trick based on IEEE float format. On my PIII - * this takes 16 seconds to perform one billion conversions, instead - * of 19 seconds for the above division. */ - union { float f; int32_t i; } u; - u.i = *src++ + 0x43c00000; - *dst++ = u.f - 384.0; -#endif + VLC_UNUSED(filter); + double *src = (double *)b->p_buffer; + int16_t *dst = (int16_t *)src; + for (size_t i = b->i_buffer / 8; i--;) { + const double v = *src++ * 32768.; + /* Slow version. */ + if (v >= 32767.) + *dst++ = 32767; + else if (v < -32768.) + *dst++ = -32768; + else + *dst++ = lround(v); } + b->i_buffer /= 4; + return b; +} + +static block_t *Fl64toFl32(filter_t *filter, block_t *b) +{ + double *src = (double *)b->p_buffer; + float *dst = (float *)src; + for (size_t i = b->i_buffer / 8; i--;) + *(dst++) = *(src++); + + VLC_UNUSED(filter); + return b; } +static block_t *Fl64toS32(filter_t *filter, block_t *b) +{ + double *src = (double *)b->p_buffer; + int32_t *dst = (int32_t *)src; + for (size_t i = b->i_buffer / 8; i--;) + { + float s = *(src++) * 2147483648.; + if (s >= 2147483647.) + *(dst++) = 2147483647; + else + if (s <= -2147483648.) + *(dst++) = -2147483648; + else + *(dst++) = lround(s); + } + VLC_UNUSED(filter); + return b; +} + + +/* */ /* */ static const struct { vlc_fourcc_t src; vlc_fourcc_t dst; - cvt_direct_t convert; + cvt_t convert; } cvt_directs[] = { - { VLC_CODEC_FL64, VLC_CODEC_S16N, Fl64toS16 }, - { VLC_CODEC_S32N, VLC_CODEC_FL32, S32toFl32 }, + { VLC_CODEC_U8, VLC_CODEC_S16N, U8toS16 }, + { VLC_CODEC_U8, VLC_CODEC_FL32, U8toFl32 }, + { VLC_CODEC_U8, VLC_CODEC_S32N, U8toS32 }, + { VLC_CODEC_U8, VLC_CODEC_FL64, U8toFl64 }, + + { VLC_CODEC_S16N, VLC_CODEC_U8, S16toU8 }, + { VLC_CODEC_S16N, VLC_CODEC_FL32, S16toFl32 }, + { VLC_CODEC_S16N, VLC_CODEC_S32N, S16toS32 }, + { VLC_CODEC_S16N, VLC_CODEC_FL32, S16toFl64 }, + + { VLC_CODEC_FL32, VLC_CODEC_U8, Fl32toU8 }, + { VLC_CODEC_FL32, VLC_CODEC_S16N, Fl32toS16 }, + { VLC_CODEC_FL32, VLC_CODEC_S32N, Fl32toS32 }, + { VLC_CODEC_FL32, VLC_CODEC_FL64, Fl32toFl64 }, + + { VLC_CODEC_S32N, VLC_CODEC_U8, S32toU8 }, + { VLC_CODEC_S32N, VLC_CODEC_S16N, S32toS16 }, + { VLC_CODEC_S32N, VLC_CODEC_FL32, S32toFl32 }, + { VLC_CODEC_S32N, VLC_CODEC_FL64, S32toFl64 }, + + { VLC_CODEC_FL64, VLC_CODEC_U8, Fl64toU8 }, + { VLC_CODEC_FL64, VLC_CODEC_S16N, Fl64toS16 }, + { VLC_CODEC_FL64, VLC_CODEC_FL32, Fl64toFl32 }, + { VLC_CODEC_FL64, VLC_CODEC_S32N, Fl64toS32 }, - { VLC_CODEC_S32N, VLC_CODEC_S16N, S32toS16 }, - { VLC_CODEC_FL32, VLC_CODEC_S16N, Fl32toS16 }, - - { VLC_CODEC_S16N, VLC_CODEC_U8, S16toU8 }, - - { 0, 0, NULL } -}; - -static const struct { - vlc_fourcc_t src; - vlc_fourcc_t dst; - cvt_indirect_t convert; -} cvt_indirects[] = { - { VLC_CODEC_S16N, VLC_CODEC_S32N, S16toS32 }, - { VLC_CODEC_S16N, VLC_CODEC_FL32, S16toFl32 }, - - { VLC_CODEC_U8, VLC_CODEC_S16N, U8toS16 }, { 0, 0, NULL } }; -static cvt_direct_t FindDirect(vlc_fourcc_t src, vlc_fourcc_t dst) +static cvt_t FindConversion(vlc_fourcc_t src, vlc_fourcc_t dst) { for (int i = 0; cvt_directs[i].convert; i++) { if (cvt_directs[i].src == src && @@ -331,13 +474,3 @@ static cvt_direct_t FindDirect(vlc_fourcc_t src, vlc_fourcc_t dst) } return NULL; } -static cvt_indirect_t FindIndirect(vlc_fourcc_t src, vlc_fourcc_t dst) -{ - for (int i = 0; cvt_indirects[i].convert; i++) { - if (cvt_indirects[i].src == src && - cvt_indirects[i].dst == dst) - return cvt_indirects[i].convert; - } - return NULL; -} - -- GitLab