From 86c9673bab6d1fccf32ef69010568a8d0d6e17d5 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Fri, 17 Dec 2010 20:52:27 +0000 Subject: [PATCH] Add support for fixed-point MDCT sizes other than 512. Originally committed as revision 26046 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/ac3enc.c | 100 ++++++++++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 36 deletions(-) diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c index 65c16680ff..15d038a5b6 100644 --- a/libavcodec/ac3enc.c +++ b/libavcodec/ac3enc.c @@ -37,9 +37,6 @@ #include "audioconvert.h" -#define MDCT_NBITS 9 -#define MDCT_SAMPLES (1 << MDCT_NBITS) - /** Maximum number of exponent groups. +1 for separate DC exponent. */ #define AC3_MAX_EXP_GROUPS 85 @@ -60,6 +57,11 @@ typedef struct IComplex { typedef struct AC3MDCTContext { AVCodecContext *avctx; ///< parent context for av_log() + int nbits; ///< log2(transform size) + int16_t *costab; ///< FFT cos table + int16_t *sintab; ///< FFT sin table + int16_t *xcos1; ///< MDCT cos table + int16_t *xsin1; ///< MDCT sin table int16_t *rot_tmp; ///< temp buffer for pre-rotated samples IComplex *cplx_tmp; ///< temp buffer for complex pre-rotated samples } AC3MDCTContext; @@ -145,12 +147,6 @@ typedef struct AC3EncodeContext { } AC3EncodeContext; -/** MDCT and FFT tables */ -static int16_t costab[64]; -static int16_t sintab[64]; -static int16_t xcos1[128]; -static int16_t xsin1[128]; - /** * LUT for number of exponent groups. * exponent_group_tab[exponent strategy-1][number of coefficients] @@ -209,6 +205,11 @@ static void deinterleave_input_samples(AC3EncodeContext *s, */ static av_cold void mdct_end(AC3MDCTContext *mdct) { + mdct->nbits = 0; + av_freep(&mdct->costab); + av_freep(&mdct->sintab); + av_freep(&mdct->xcos1); + av_freep(&mdct->xsin1); av_freep(&mdct->rot_tmp); av_freep(&mdct->cplx_tmp); } @@ -219,7 +220,7 @@ static av_cold void mdct_end(AC3MDCTContext *mdct) * Initialize FFT tables. * @param ln log2(FFT size) */ -static av_cold void fft_init(int ln) +static av_cold int fft_init(AC3MDCTContext *mdct, int ln) { int i, n, n2; float alpha; @@ -227,11 +228,21 @@ static av_cold void fft_init(int ln) n = 1 << ln; n2 = n >> 1; + FF_ALLOC_OR_GOTO(mdct->avctx, mdct->costab, n2 * sizeof(*mdct->costab), + fft_alloc_fail); + FF_ALLOC_OR_GOTO(mdct->avctx, mdct->sintab, n2 * sizeof(*mdct->sintab), + fft_alloc_fail); + for (i = 0; i < n2; i++) { alpha = 2.0 * M_PI * i / n; - costab[i] = FIX15(cos(alpha)); - sintab[i] = FIX15(sin(alpha)); + mdct->costab[i] = FIX15(cos(alpha)); + mdct->sintab[i] = FIX15(sin(alpha)); } + + return 0; +fft_alloc_fail: + mdct_end(mdct); + return AVERROR(ENOMEM); } @@ -241,13 +252,21 @@ static av_cold void fft_init(int ln) */ static av_cold int mdct_init(AC3MDCTContext *mdct, int nbits) { - int i, n, n4; + int i, n, n4, ret; n = 1 << nbits; n4 = n >> 2; - fft_init(nbits - 2); + mdct->nbits = nbits; + + ret = fft_init(mdct, nbits - 2); + if (ret) + return ret; + FF_ALLOC_OR_GOTO(mdct->avctx, mdct->xcos1, n4 * sizeof(*mdct->xcos1), + mdct_alloc_fail); + FF_ALLOC_OR_GOTO(mdct->avctx, mdct->xsin1 , n4 * sizeof(*mdct->xsin1), + mdct_alloc_fail); FF_ALLOC_OR_GOTO(mdct->avctx, mdct->rot_tmp, n * sizeof(*mdct->rot_tmp), mdct_alloc_fail); FF_ALLOC_OR_GOTO(mdct->avctx, mdct->cplx_tmp, n4 * sizeof(*mdct->cplx_tmp), @@ -255,12 +274,13 @@ static av_cold int mdct_init(AC3MDCTContext *mdct, int nbits) for (i = 0; i < n4; i++) { float alpha = 2.0 * M_PI * (i + 1.0 / 8.0) / n; - xcos1[i] = FIX15(-cos(alpha)); - xsin1[i] = FIX15(-sin(alpha)); + mdct->xcos1[i] = FIX15(-cos(alpha)); + mdct->xsin1[i] = FIX15(-sin(alpha)); } return 0; mdct_alloc_fail: + mdct_end(mdct); return AVERROR(ENOMEM); } @@ -293,7 +313,7 @@ mdct_alloc_fail: * @param z complex input/output samples * @param ln log2(FFT size) */ -static void fft(IComplex *z, int ln) +static void fft(AC3MDCTContext *mdct, IComplex *z, int ln) { int j, l, np, np2; int nblocks, nloops; @@ -345,7 +365,7 @@ static void fft(IComplex *z, int ln) p++; q++; for(l = nblocks; l < np2; l += nblocks) { - CMUL(tmp_re, tmp_im, costab[l], -sintab[l], q->re, q->im); + CMUL(tmp_re, tmp_im, mdct->costab[l], -mdct->sintab[l], q->re, q->im); BF(p->re, p->im, q->re, q->im, p->re, p->im, tmp_re, tmp_im); p++; @@ -367,29 +387,33 @@ static void fft(IComplex *z, int ln) */ static void mdct512(AC3MDCTContext *mdct, int32_t *out, int16_t *in) { - int i, re, im; + int i, re, im, n, n2, n4; int16_t *rot = mdct->rot_tmp; IComplex *x = mdct->cplx_tmp; + n = 1 << mdct->nbits; + n2 = n >> 1; + n4 = n >> 2; + /* shift to simplify computations */ - for (i = 0; i < MDCT_SAMPLES/4; i++) - rot[i] = -in[i + 3*MDCT_SAMPLES/4]; - memcpy(&rot[MDCT_SAMPLES/4], &in[0], 3*MDCT_SAMPLES/4*sizeof(*in)); + for (i = 0; i > 1; - im = -((int)rot[MDCT_SAMPLES/2+2*i] - (int)rot[MDCT_SAMPLES/2-1-2*i]) >> 1; - CMUL(x[i].re, x[i].im, re, im, -xcos1[i], xsin1[i]); + for (i = 0; i < n4; i++) { + re = ((int)rot[ 2*i] - (int)rot[ n-1-2*i]) >> 1; + im = -((int)rot[n2+2*i] - (int)rot[n2-1-2*i]) >> 1; + CMUL(x[i].re, x[i].im, re, im, -mdct->xcos1[i], mdct->xsin1[i]); } - fft(x, MDCT_NBITS - 2); + fft(mdct, x, mdct->nbits - 2); /* post rotation */ - for (i = 0; i < MDCT_SAMPLES/4; i++) { + for (i = 0; i < n4; i++) { re = x[i].re; im = x[i].im; - CMUL(out[MDCT_SAMPLES/2-1-2*i], out[2*i], re, im, xsin1[i], xcos1[i]); + CMUL(out[n2-1-2*i], out[2*i], re, im, mdct->xsin1[i], mdct->xcos1[i]); } } @@ -1824,10 +1848,12 @@ init_fail: #include "libavutil/lfg.h" +#define MDCT_NBITS 9 +#define MDCT_SAMPLES (1 << MDCT_NBITS) #define FN (MDCT_SAMPLES/4) -static void fft_test(AVLFG *lfg) +static void fft_test(AC3MDCTContext *mdct, AVLFG *lfg) { IComplex in[FN], in1[FN]; int k, n, i; @@ -1838,7 +1864,7 @@ static void fft_test(AVLFG *lfg) in[i].im = av_lfg_get(lfg) % 65535 - 32767; in1[i] = in[i]; } - fft(in, 7); + fft(mdct, in, 7); /* do it by hand */ for (k = 0; k < FN; k++) { @@ -1855,7 +1881,7 @@ static void fft_test(AVLFG *lfg) } -static void mdct_test(AVLFG *lfg) +static void mdct_test(AC3MDCTContext *mdct, AVLFG *lfg) { int16_t input[MDCT_SAMPLES]; int32_t output[AC3_MAX_COEFS]; @@ -1869,7 +1895,7 @@ static void mdct_test(AVLFG *lfg) input1[i] = input[i]; } - mdct512(output, input); + mdct512(mdct, output, input); /* do it by hand */ for (k = 0; k < AC3_MAX_COEFS; k++) { @@ -1897,12 +1923,14 @@ static void mdct_test(AVLFG *lfg) int main(void) { AVLFG lfg; + AC3MDCTContext mdct; + mdct.avctx = NULL; av_log_set_level(AV_LOG_DEBUG); - mdct_init(9); + mdct_init(&mdct, 9); - fft_test(&lfg); - mdct_test(&lfg); + fft_test(&mdct, &lfg); + mdct_test(&mdct, &lfg); return 0; }