mirror of https://git.ffmpeg.org/ffmpeg.git
Use the new RDFT code in the QDM2 decoder.
Originally committed as revision 16865 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
6860254044
commit
63cae55d62
|
@ -1018,7 +1018,7 @@ nellymoser_decoder_select="fft mdct"
|
||||||
nellymoser_encoder_select="fft mdct"
|
nellymoser_encoder_select="fft mdct"
|
||||||
png_decoder_select="zlib"
|
png_decoder_select="zlib"
|
||||||
png_encoder_select="zlib"
|
png_encoder_select="zlib"
|
||||||
qdm2_decoder_select="fft mdct"
|
qdm2_decoder_select="fft mdct rdft"
|
||||||
rv10_encoder_select="aandct"
|
rv10_encoder_select="aandct"
|
||||||
rv20_encoder_select="aandct"
|
rv20_encoder_select="aandct"
|
||||||
shorten_decoder_select="golomb"
|
shorten_decoder_select="golomb"
|
||||||
|
|
|
@ -97,10 +97,14 @@ typedef struct QDM2SubPNode {
|
||||||
struct QDM2SubPNode *next; ///< pointer to next packet in the list, NULL if leaf node
|
struct QDM2SubPNode *next; ///< pointer to next packet in the list, NULL if leaf node
|
||||||
} QDM2SubPNode;
|
} QDM2SubPNode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float re;
|
||||||
|
float im;
|
||||||
|
} QDM2Complex;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float level;
|
float level;
|
||||||
float *samples_im;
|
QDM2Complex *complex;
|
||||||
float *samples_re;
|
|
||||||
const float *table;
|
const float *table;
|
||||||
int phase;
|
int phase;
|
||||||
int phase_shift;
|
int phase_shift;
|
||||||
|
@ -118,14 +122,7 @@ typedef struct {
|
||||||
} FFTCoefficient;
|
} FFTCoefficient;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float re;
|
DECLARE_ALIGNED_16(QDM2Complex, complex[MPA_MAX_CHANNELS][256]);
|
||||||
float im;
|
|
||||||
} QDM2Complex;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
DECLARE_ALIGNED_16(QDM2Complex, complex[256 + 1]);
|
|
||||||
float samples_im[MPA_MAX_CHANNELS][256];
|
|
||||||
float samples_re[MPA_MAX_CHANNELS][256];
|
|
||||||
} QDM2FFT;
|
} QDM2FFT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -166,8 +163,7 @@ typedef struct {
|
||||||
int fft_coefs_min_index[5];
|
int fft_coefs_min_index[5];
|
||||||
int fft_coefs_max_index[5];
|
int fft_coefs_max_index[5];
|
||||||
int fft_level_exp[6];
|
int fft_level_exp[6];
|
||||||
FFTContext fft_ctx;
|
RDFTContext rdft_ctx;
|
||||||
FFTComplex exptab[128];
|
|
||||||
QDM2FFT fft;
|
QDM2FFT fft;
|
||||||
|
|
||||||
/// I/O data
|
/// I/O data
|
||||||
|
@ -1507,10 +1503,10 @@ static void qdm2_fft_generate_tone (QDM2Context *q, FFTTone *tone)
|
||||||
|
|
||||||
/* generate FFT coefficients for tone */
|
/* generate FFT coefficients for tone */
|
||||||
if (tone->duration >= 3 || tone->cutoff >= 3) {
|
if (tone->duration >= 3 || tone->cutoff >= 3) {
|
||||||
tone->samples_im[0] += c.im;
|
tone->complex[0].im += c.im;
|
||||||
tone->samples_re[0] += c.re;
|
tone->complex[0].re += c.re;
|
||||||
tone->samples_im[1] -= c.im;
|
tone->complex[1].im -= c.im;
|
||||||
tone->samples_re[1] -= c.re;
|
tone->complex[1].re -= c.re;
|
||||||
} else {
|
} else {
|
||||||
f[1] = -tone->table[4];
|
f[1] = -tone->table[4];
|
||||||
f[0] = tone->table[3] - tone->table[0];
|
f[0] = tone->table[3] - tone->table[0];
|
||||||
|
@ -1519,12 +1515,12 @@ static void qdm2_fft_generate_tone (QDM2Context *q, FFTTone *tone)
|
||||||
f[4] = tone->table[0] - tone->table[1];
|
f[4] = tone->table[0] - tone->table[1];
|
||||||
f[5] = tone->table[2];
|
f[5] = tone->table[2];
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
tone->samples_re[fft_cutoff_index_table[tone->cutoff][i]] += c.re * f[i];
|
tone->complex[fft_cutoff_index_table[tone->cutoff][i]].re += c.re * f[i];
|
||||||
tone->samples_im[fft_cutoff_index_table[tone->cutoff][i]] += c.im *((tone->cutoff <= i) ? -f[i] : f[i]);
|
tone->complex[fft_cutoff_index_table[tone->cutoff][i]].im += c.im *((tone->cutoff <= i) ? -f[i] : f[i]);
|
||||||
}
|
}
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
tone->samples_re[i] += c.re * f[i+2];
|
tone->complex[i].re += c.re * f[i+2];
|
||||||
tone->samples_im[i] += c.im * f[i+2];
|
tone->complex[i].im += c.im * f[i+2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1542,8 +1538,7 @@ static void qdm2_fft_tone_synthesizer (QDM2Context *q, int sub_packet)
|
||||||
const double iscale = 0.25 * M_PI;
|
const double iscale = 0.25 * M_PI;
|
||||||
|
|
||||||
for (ch = 0; ch < q->channels; ch++) {
|
for (ch = 0; ch < q->channels; ch++) {
|
||||||
memset(q->fft.samples_im[ch], 0, q->fft_size * sizeof(float));
|
memset(q->fft.complex[ch], 0, q->fft_size * sizeof(QDM2Complex));
|
||||||
memset(q->fft.samples_re[ch], 0, q->fft_size * sizeof(float));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1561,10 +1556,10 @@ static void qdm2_fft_tone_synthesizer (QDM2Context *q, int sub_packet)
|
||||||
|
|
||||||
c.re = level * cos(q->fft_coefs[i].phase * iscale);
|
c.re = level * cos(q->fft_coefs[i].phase * iscale);
|
||||||
c.im = level * sin(q->fft_coefs[i].phase * iscale);
|
c.im = level * sin(q->fft_coefs[i].phase * iscale);
|
||||||
q->fft.samples_re[ch][q->fft_coefs[i].offset + 0] += c.re;
|
q->fft.complex[ch][q->fft_coefs[i].offset + 0].re += c.re;
|
||||||
q->fft.samples_im[ch][q->fft_coefs[i].offset + 0] += c.im;
|
q->fft.complex[ch][q->fft_coefs[i].offset + 0].im += c.im;
|
||||||
q->fft.samples_re[ch][q->fft_coefs[i].offset + 1] -= c.re;
|
q->fft.complex[ch][q->fft_coefs[i].offset + 1].re -= c.re;
|
||||||
q->fft.samples_im[ch][q->fft_coefs[i].offset + 1] -= c.im;
|
q->fft.complex[ch][q->fft_coefs[i].offset + 1].im -= c.im;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* generate existing FFT tones */
|
/* generate existing FFT tones */
|
||||||
|
@ -1594,8 +1589,7 @@ static void qdm2_fft_tone_synthesizer (QDM2Context *q, int sub_packet)
|
||||||
tone.cutoff = (offset >= 60) ? 3 : 2;
|
tone.cutoff = (offset >= 60) ? 3 : 2;
|
||||||
|
|
||||||
tone.level = (q->fft_coefs[j].exp < 0) ? 0.0 : fft_tone_level_table[q->superblocktype_2_3 ? 0 : 1][q->fft_coefs[j].exp & 63];
|
tone.level = (q->fft_coefs[j].exp < 0) ? 0.0 : fft_tone_level_table[q->superblocktype_2_3 ? 0 : 1][q->fft_coefs[j].exp & 63];
|
||||||
tone.samples_im = &q->fft.samples_im[ch][offset];
|
tone.complex = &q->fft.complex[ch][offset];
|
||||||
tone.samples_re = &q->fft.samples_re[ch][offset];
|
|
||||||
tone.table = fft_tone_sample_table[i][q->fft_coefs[j].offset - (offset << four_i)];
|
tone.table = fft_tone_sample_table[i][q->fft_coefs[j].offset - (offset << four_i)];
|
||||||
tone.phase = 64 * q->fft_coefs[j].phase - (offset << 8) - 128;
|
tone.phase = 64 * q->fft_coefs[j].phase - (offset << 8) - 128;
|
||||||
tone.phase_shift = (2 * q->fft_coefs[j].offset + 1) << (7 - four_i);
|
tone.phase_shift = (2 * q->fft_coefs[j].offset + 1) << (7 - four_i);
|
||||||
|
@ -1612,37 +1606,14 @@ static void qdm2_fft_tone_synthesizer (QDM2Context *q, int sub_packet)
|
||||||
|
|
||||||
static void qdm2_calculate_fft (QDM2Context *q, int channel, int sub_packet)
|
static void qdm2_calculate_fft (QDM2Context *q, int channel, int sub_packet)
|
||||||
{
|
{
|
||||||
const int n = 1 << (q->fft_order - 1);
|
const float gain = (q->channels == 1 && q->nb_channels == 2) ? 0.5f : 1.0f;
|
||||||
const int n2 = n >> 1;
|
int i;
|
||||||
const float gain = (q->channels == 1 && q->nb_channels == 2) ? 0.25f : 0.50f;
|
q->fft.complex[channel][0].re *= 2.0f;
|
||||||
float c, s, f0, f1, f2, f3;
|
q->fft.complex[channel][0].im = 0.0f;
|
||||||
int i, j;
|
ff_rdft_calc(&q->rdft_ctx, (FFTSample *)q->fft.complex[channel]);
|
||||||
|
|
||||||
/* prerotation (or something like that) */
|
|
||||||
for (i=1; i < n2; i++) {
|
|
||||||
j = (n - i);
|
|
||||||
c = q->exptab[i].re;
|
|
||||||
s = -q->exptab[i].im;
|
|
||||||
f0 = (q->fft.samples_re[channel][i] - q->fft.samples_re[channel][j]) * gain;
|
|
||||||
f1 = (q->fft.samples_im[channel][i] + q->fft.samples_im[channel][j]) * gain;
|
|
||||||
f2 = (q->fft.samples_re[channel][i] + q->fft.samples_re[channel][j]) * gain;
|
|
||||||
f3 = (q->fft.samples_im[channel][i] - q->fft.samples_im[channel][j]) * gain;
|
|
||||||
q->fft.complex[i].re = s * f0 - c * f1 + f2;
|
|
||||||
q->fft.complex[i].im = c * f0 + s * f1 + f3;
|
|
||||||
q->fft.complex[j].re = -s * f0 + c * f1 + f2;
|
|
||||||
q->fft.complex[j].im = c * f0 + s * f1 - f3;
|
|
||||||
}
|
|
||||||
|
|
||||||
q->fft.complex[ 0].re = q->fft.samples_re[channel][ 0] * gain * 2.0;
|
|
||||||
q->fft.complex[ 0].im = q->fft.samples_re[channel][ 0] * gain * 2.0;
|
|
||||||
q->fft.complex[n2].re = q->fft.samples_re[channel][n2] * gain * 2.0;
|
|
||||||
q->fft.complex[n2].im = -q->fft.samples_im[channel][n2] * gain * 2.0;
|
|
||||||
|
|
||||||
ff_fft_permute(&q->fft_ctx, (FFTComplex *) q->fft.complex);
|
|
||||||
ff_fft_calc (&q->fft_ctx, (FFTComplex *) q->fft.complex);
|
|
||||||
/* add samples to output buffer */
|
/* add samples to output buffer */
|
||||||
for (i = 0; i < ((q->fft_frame_size + 15) & ~15); i++)
|
for (i = 0; i < ((q->fft_frame_size + 15) & ~15); i++)
|
||||||
q->output_buffer[q->channels * i + channel] += ((float *) q->fft.complex)[i];
|
q->output_buffer[q->channels * i + channel] += ((float *) q->fft.complex[channel])[i] * gain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1761,8 +1732,6 @@ static int qdm2_decode_init(AVCodecContext *avctx)
|
||||||
uint8_t *extradata;
|
uint8_t *extradata;
|
||||||
int extradata_size;
|
int extradata_size;
|
||||||
int tmp_val, tmp, size;
|
int tmp_val, tmp, size;
|
||||||
int i;
|
|
||||||
float alpha;
|
|
||||||
|
|
||||||
/* extradata parsing
|
/* extradata parsing
|
||||||
|
|
||||||
|
@ -1910,19 +1879,13 @@ static int qdm2_decode_init(AVCodecContext *avctx)
|
||||||
else
|
else
|
||||||
s->coeff_per_sb_select = 2;
|
s->coeff_per_sb_select = 2;
|
||||||
|
|
||||||
// Fail on unknown fft order, if it's > 9 it can overflow s->exptab[]
|
// Fail on unknown fft order
|
||||||
if ((s->fft_order < 7) || (s->fft_order > 9)) {
|
if ((s->fft_order < 7) || (s->fft_order > 9)) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "Unknown FFT order (%d), contact the developers!\n", s->fft_order);
|
av_log(avctx, AV_LOG_ERROR, "Unknown FFT order (%d), contact the developers!\n", s->fft_order);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ff_fft_init(&s->fft_ctx, s->fft_order - 1, 1);
|
ff_rdft_init(&s->rdft_ctx, s->fft_order, IRDFT);
|
||||||
|
|
||||||
for (i = 1; i < (1 << (s->fft_order - 2)); i++) {
|
|
||||||
alpha = 2 * M_PI * (float)i / (float)(1 << (s->fft_order - 1));
|
|
||||||
s->exptab[i].re = cos(alpha);
|
|
||||||
s->exptab[i].im = sin(alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
qdm2_init(s);
|
qdm2_init(s);
|
||||||
|
|
||||||
|
@ -1937,7 +1900,7 @@ static int qdm2_decode_close(AVCodecContext *avctx)
|
||||||
{
|
{
|
||||||
QDM2Context *s = avctx->priv_data;
|
QDM2Context *s = avctx->priv_data;
|
||||||
|
|
||||||
ff_fft_end(&s->fft_ctx);
|
ff_rdft_end(&s->rdft_ctx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue