Add support for fixed-point MDCT sizes other than 512.

Originally committed as revision 26046 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Justin Ruggles 2010-12-17 20:52:27 +00:00
parent 234b70d346
commit 86c9673bab
1 changed files with 64 additions and 36 deletions

View File

@ -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 <n4; i++)
rot[i] = -in[i + 3*n4];
memcpy(&rot[n4], &in[0], 3*n4*sizeof(*in));
/* pre rotation */
for (i = 0; i < MDCT_SAMPLES/4; i++) {
re = ((int)rot[ 2*i] - (int)rot[MDCT_SAMPLES -1-2*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;
}