mirror of https://git.ffmpeg.org/ffmpeg.git
640 lines
27 KiB
C
640 lines
27 KiB
C
/*
|
|
* AAC decoder
|
|
* Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org )
|
|
* Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com )
|
|
* Copyright (c) 2008-2013 Alex Converse <alex.converse@gmail.com>
|
|
*
|
|
* AAC LATM decoder
|
|
* Copyright (c) 2008-2010 Paul Kendall <paul@kcbbs.gen.nz>
|
|
* Copyright (c) 2010 Janne Grunau <janne-libav@jannau.net>
|
|
*
|
|
* AAC decoder fixed-point implementation
|
|
* Copyright (c) 2013
|
|
* MIPS Technologies, Inc., California.
|
|
*
|
|
* This file is part of FFmpeg.
|
|
*
|
|
* FFmpeg is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* FFmpeg is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with FFmpeg; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "aacdec.h"
|
|
#include "libavcodec/lpc_functions.h"
|
|
|
|
#include "libavcodec/aactab.h"
|
|
|
|
/**
|
|
* Convert integer scalefactors to the decoder's native expected
|
|
* scalefactor values.
|
|
*/
|
|
static void AAC_RENAME(dequant_scalefactors)(SingleChannelElement *sce)
|
|
{
|
|
IndividualChannelStream *ics = &sce->ics;
|
|
const enum BandType *band_type = sce->band_type;
|
|
const int *band_type_run_end = sce->band_type_run_end;
|
|
const int *sfo = sce->sfo;
|
|
INTFLOAT *sf = sce->AAC_RENAME(sf);
|
|
|
|
int g, i, idx = 0;
|
|
for (g = 0; g < ics->num_window_groups; g++) {
|
|
for (i = 0; i < ics->max_sfb;) {
|
|
int run_end = band_type_run_end[idx];
|
|
switch (band_type[idx]) {
|
|
case ZERO_BT:
|
|
for (; i < run_end; i++, idx++)
|
|
sf[idx] = FIXR(0.);
|
|
break;
|
|
case INTENSITY_BT: /* fallthrough */
|
|
case INTENSITY_BT2:
|
|
for (; i < run_end; i++, idx++) {
|
|
#if USE_FIXED
|
|
sf[idx] = 100 - sfo[idx];
|
|
#else
|
|
sf[idx] = ff_aac_pow2sf_tab[-sfo[idx] + POW_SF2_ZERO];
|
|
#endif /* USE_FIXED */
|
|
}
|
|
break;
|
|
case NOISE_BT:
|
|
for (; i < run_end; i++, idx++) {
|
|
#if USE_FIXED
|
|
sf[idx] = -(100 + sfo[idx]);
|
|
#else
|
|
sf[idx] = -ff_aac_pow2sf_tab[sfo[idx] + POW_SF2_ZERO];
|
|
#endif /* USE_FIXED */
|
|
}
|
|
break;
|
|
default:
|
|
for (; i < run_end; i++, idx++) {
|
|
#if USE_FIXED
|
|
sf[idx] = -sfo[idx];
|
|
#else
|
|
sf[idx] = -ff_aac_pow2sf_tab[sfo[idx] - 100 + POW_SF2_ZERO];
|
|
#endif /* USE_FIXED */
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mid/Side stereo decoding; reference: 4.6.8.1.3.
|
|
*/
|
|
static void AAC_RENAME(apply_mid_side_stereo)(AACDecContext *ac, ChannelElement *cpe)
|
|
{
|
|
const IndividualChannelStream *ics = &cpe->ch[0].ics;
|
|
INTFLOAT *ch0 = cpe->ch[0].AAC_RENAME(coeffs);
|
|
INTFLOAT *ch1 = cpe->ch[1].AAC_RENAME(coeffs);
|
|
int g, i, group, idx = 0;
|
|
const uint16_t *offsets = ics->swb_offset;
|
|
for (g = 0; g < ics->num_window_groups; g++) {
|
|
for (i = 0; i < ics->max_sfb; i++, idx++) {
|
|
if (cpe->ms_mask[idx] &&
|
|
cpe->ch[0].band_type[idx] < NOISE_BT &&
|
|
cpe->ch[1].band_type[idx] < NOISE_BT) {
|
|
#if USE_FIXED
|
|
for (group = 0; group < ics->group_len[g]; group++) {
|
|
ac->fdsp->butterflies_fixed(ch0 + group * 128 + offsets[i],
|
|
ch1 + group * 128 + offsets[i],
|
|
offsets[i+1] - offsets[i]);
|
|
#else
|
|
for (group = 0; group < ics->group_len[g]; group++) {
|
|
ac->fdsp->butterflies_float(ch0 + group * 128 + offsets[i],
|
|
ch1 + group * 128 + offsets[i],
|
|
offsets[i+1] - offsets[i]);
|
|
#endif /* USE_FIXED */
|
|
}
|
|
}
|
|
}
|
|
ch0 += ics->group_len[g] * 128;
|
|
ch1 += ics->group_len[g] * 128;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* intensity stereo decoding; reference: 4.6.8.2.3
|
|
*
|
|
* @param ms_present Indicates mid/side stereo presence. [0] mask is all 0s;
|
|
* [1] mask is decoded from bitstream; [2] mask is all 1s;
|
|
* [3] reserved for scalable AAC
|
|
*/
|
|
static void AAC_RENAME(apply_intensity_stereo)(AACDecContext *ac,
|
|
ChannelElement *cpe, int ms_present)
|
|
{
|
|
const IndividualChannelStream *ics = &cpe->ch[1].ics;
|
|
SingleChannelElement *sce1 = &cpe->ch[1];
|
|
INTFLOAT *coef0 = cpe->ch[0].AAC_RENAME(coeffs), *coef1 = cpe->ch[1].AAC_RENAME(coeffs);
|
|
const uint16_t *offsets = ics->swb_offset;
|
|
int g, group, i, idx = 0;
|
|
int c;
|
|
INTFLOAT scale;
|
|
for (g = 0; g < ics->num_window_groups; g++) {
|
|
for (i = 0; i < ics->max_sfb;) {
|
|
if (sce1->band_type[idx] == INTENSITY_BT ||
|
|
sce1->band_type[idx] == INTENSITY_BT2) {
|
|
const int bt_run_end = sce1->band_type_run_end[idx];
|
|
for (; i < bt_run_end; i++, idx++) {
|
|
c = -1 + 2 * (sce1->band_type[idx] - 14);
|
|
if (ms_present)
|
|
c *= 1 - 2 * cpe->ms_mask[idx];
|
|
scale = c * sce1->AAC_RENAME(sf)[idx];
|
|
for (group = 0; group < ics->group_len[g]; group++)
|
|
#if USE_FIXED
|
|
subband_scale(coef1 + group * 128 + offsets[i],
|
|
coef0 + group * 128 + offsets[i],
|
|
scale,
|
|
23,
|
|
offsets[i + 1] - offsets[i] ,ac->avctx);
|
|
#else
|
|
ac->fdsp->vector_fmul_scalar(coef1 + group * 128 + offsets[i],
|
|
coef0 + group * 128 + offsets[i],
|
|
scale,
|
|
offsets[i + 1] - offsets[i]);
|
|
#endif /* USE_FIXED */
|
|
}
|
|
} else {
|
|
int bt_run_end = sce1->band_type_run_end[idx];
|
|
idx += bt_run_end - i;
|
|
i = bt_run_end;
|
|
}
|
|
}
|
|
coef0 += ics->group_len[g] * 128;
|
|
coef1 += ics->group_len[g] * 128;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Decode Temporal Noise Shaping filter coefficients and apply all-pole filters; reference: 4.6.9.3.
|
|
*
|
|
* @param decode 1 if tool is used normally, 0 if tool is used in LTP.
|
|
* @param coef spectral coefficients
|
|
*/
|
|
static void AAC_RENAME(apply_tns)(void *_coef_param, TemporalNoiseShaping *tns,
|
|
IndividualChannelStream *ics, int decode)
|
|
{
|
|
const int mmm = FFMIN(ics->tns_max_bands, ics->max_sfb);
|
|
int w, filt, m, i;
|
|
int bottom, top, order, start, end, size, inc;
|
|
INTFLOAT *coef_param = _coef_param;
|
|
INTFLOAT lpc[TNS_MAX_ORDER];
|
|
INTFLOAT tmp[TNS_MAX_ORDER+1];
|
|
UINTFLOAT *coef = coef_param;
|
|
|
|
if(!mmm)
|
|
return;
|
|
|
|
for (w = 0; w < ics->num_windows; w++) {
|
|
bottom = ics->num_swb;
|
|
for (filt = 0; filt < tns->n_filt[w]; filt++) {
|
|
top = bottom;
|
|
bottom = FFMAX(0, top - tns->length[w][filt]);
|
|
order = tns->order[w][filt];
|
|
if (order == 0)
|
|
continue;
|
|
|
|
// tns_decode_coef
|
|
compute_lpc_coefs(tns->AAC_RENAME(coef)[w][filt], order, lpc, 0, 0, 0);
|
|
|
|
start = ics->swb_offset[FFMIN(bottom, mmm)];
|
|
end = ics->swb_offset[FFMIN( top, mmm)];
|
|
if ((size = end - start) <= 0)
|
|
continue;
|
|
if (tns->direction[w][filt]) {
|
|
inc = -1;
|
|
start = end - 1;
|
|
} else {
|
|
inc = 1;
|
|
}
|
|
start += w * 128;
|
|
|
|
if (decode) {
|
|
// ar filter
|
|
for (m = 0; m < size; m++, start += inc)
|
|
for (i = 1; i <= FFMIN(m, order); i++)
|
|
coef[start] -= AAC_MUL26((INTFLOAT)coef[start - i * inc], lpc[i - 1]);
|
|
} else {
|
|
// ma filter
|
|
for (m = 0; m < size; m++, start += inc) {
|
|
tmp[0] = coef[start];
|
|
for (i = 1; i <= FFMIN(m, order); i++)
|
|
coef[start] += AAC_MUL26(tmp[i], lpc[i - 1]);
|
|
for (i = order; i > 0; i--)
|
|
tmp[i] = tmp[i - 1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Apply windowing and MDCT to obtain the spectral
|
|
* coefficient from the predicted sample by LTP.
|
|
*/
|
|
static inline void AAC_RENAME(windowing_and_mdct_ltp)(AACDecContext *ac,
|
|
INTFLOAT *out, INTFLOAT *in,
|
|
IndividualChannelStream *ics)
|
|
{
|
|
const INTFLOAT *lwindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_long_1024) : AAC_RENAME2(sine_1024);
|
|
const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128);
|
|
const INTFLOAT *lwindow_prev = ics->use_kb_window[1] ? AAC_RENAME2(aac_kbd_long_1024) : AAC_RENAME2(sine_1024);
|
|
const INTFLOAT *swindow_prev = ics->use_kb_window[1] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128);
|
|
|
|
if (ics->window_sequence[0] != LONG_STOP_SEQUENCE) {
|
|
ac->fdsp->vector_fmul(in, in, lwindow_prev, 1024);
|
|
} else {
|
|
memset(in, 0, 448 * sizeof(*in));
|
|
ac->fdsp->vector_fmul(in + 448, in + 448, swindow_prev, 128);
|
|
}
|
|
if (ics->window_sequence[0] != LONG_START_SEQUENCE) {
|
|
ac->fdsp->vector_fmul_reverse(in + 1024, in + 1024, lwindow, 1024);
|
|
} else {
|
|
ac->fdsp->vector_fmul_reverse(in + 1024 + 448, in + 1024 + 448, swindow, 128);
|
|
memset(in + 1024 + 576, 0, 448 * sizeof(*in));
|
|
}
|
|
ac->mdct_ltp_fn(ac->mdct_ltp, out, in, sizeof(INTFLOAT));
|
|
}
|
|
|
|
/**
|
|
* Apply the long term prediction
|
|
*/
|
|
static void AAC_RENAME(apply_ltp)(AACDecContext *ac, SingleChannelElement *sce)
|
|
{
|
|
const LongTermPrediction *ltp = &sce->ics.ltp;
|
|
const uint16_t *offsets = sce->ics.swb_offset;
|
|
int i, sfb;
|
|
|
|
if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) {
|
|
INTFLOAT *predTime = sce->AAC_RENAME(output);
|
|
INTFLOAT *predFreq = ac->AAC_RENAME(buf_mdct);
|
|
int16_t num_samples = 2048;
|
|
|
|
if (ltp->lag < 1024)
|
|
num_samples = ltp->lag + 1024;
|
|
for (i = 0; i < num_samples; i++)
|
|
predTime[i] = AAC_MUL30(sce->AAC_RENAME(ltp_state)[i + 2048 - ltp->lag], ltp->AAC_RENAME(coef));
|
|
memset(&predTime[i], 0, (2048 - i) * sizeof(*predTime));
|
|
|
|
AAC_RENAME(windowing_and_mdct_ltp)(ac, predFreq, predTime, &sce->ics);
|
|
|
|
if (sce->tns.present)
|
|
AAC_RENAME(apply_tns)(predFreq, &sce->tns, &sce->ics, 0);
|
|
|
|
for (sfb = 0; sfb < FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB); sfb++)
|
|
if (ltp->used[sfb])
|
|
for (i = offsets[sfb]; i < offsets[sfb + 1]; i++)
|
|
sce->AAC_RENAME(coeffs)[i] += (UINTFLOAT)predFreq[i];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update the LTP buffer for next frame
|
|
*/
|
|
static void AAC_RENAME(update_ltp)(AACDecContext *ac, SingleChannelElement *sce)
|
|
{
|
|
IndividualChannelStream *ics = &sce->ics;
|
|
INTFLOAT *saved = sce->AAC_RENAME(saved);
|
|
INTFLOAT *saved_ltp = sce->AAC_RENAME(coeffs);
|
|
const INTFLOAT *lwindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_long_1024) : AAC_RENAME2(sine_1024);
|
|
const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128);
|
|
int i;
|
|
|
|
if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
|
|
memcpy(saved_ltp, saved, 512 * sizeof(*saved_ltp));
|
|
memset(saved_ltp + 576, 0, 448 * sizeof(*saved_ltp));
|
|
ac->fdsp->vector_fmul_reverse(saved_ltp + 448, ac->AAC_RENAME(buf_mdct) + 960, &swindow[64], 64);
|
|
|
|
for (i = 0; i < 64; i++)
|
|
saved_ltp[i + 512] = AAC_MUL31(ac->AAC_RENAME(buf_mdct)[1023 - i], swindow[63 - i]);
|
|
} else if (1 && ics->window_sequence[0] == LONG_START_SEQUENCE) {
|
|
memcpy(saved_ltp, ac->AAC_RENAME(buf_mdct) + 512, 448 * sizeof(*saved_ltp));
|
|
memset(saved_ltp + 576, 0, 448 * sizeof(*saved_ltp));
|
|
ac->fdsp->vector_fmul_reverse(saved_ltp + 448, ac->AAC_RENAME(buf_mdct) + 960, &swindow[64], 64);
|
|
|
|
for (i = 0; i < 64; i++)
|
|
saved_ltp[i + 512] = AAC_MUL31(ac->AAC_RENAME(buf_mdct)[1023 - i], swindow[63 - i]);
|
|
} else if (1) { // LONG_STOP or ONLY_LONG
|
|
ac->fdsp->vector_fmul_reverse(saved_ltp, ac->AAC_RENAME(buf_mdct) + 512, &lwindow[512], 512);
|
|
|
|
for (i = 0; i < 512; i++)
|
|
saved_ltp[i + 512] = AAC_MUL31(ac->AAC_RENAME(buf_mdct)[1023 - i], lwindow[511 - i]);
|
|
}
|
|
|
|
memcpy(sce->AAC_RENAME(ltp_state), sce->AAC_RENAME(ltp_state)+1024,
|
|
1024 * sizeof(*sce->AAC_RENAME(ltp_state)));
|
|
memcpy(sce->AAC_RENAME(ltp_state) + 1024, sce->AAC_RENAME(output),
|
|
1024 * sizeof(*sce->AAC_RENAME(ltp_state)));
|
|
memcpy(sce->AAC_RENAME(ltp_state) + 2048, saved_ltp,
|
|
1024 * sizeof(*sce->AAC_RENAME(ltp_state)));
|
|
}
|
|
|
|
/**
|
|
* Conduct IMDCT and windowing.
|
|
*/
|
|
static void AAC_RENAME(imdct_and_windowing)(AACDecContext *ac, SingleChannelElement *sce)
|
|
{
|
|
IndividualChannelStream *ics = &sce->ics;
|
|
INTFLOAT *in = sce->AAC_RENAME(coeffs);
|
|
INTFLOAT *out = sce->AAC_RENAME(output);
|
|
INTFLOAT *saved = sce->AAC_RENAME(saved);
|
|
const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128);
|
|
const INTFLOAT *lwindow_prev = ics->use_kb_window[1] ? AAC_RENAME2(aac_kbd_long_1024) : AAC_RENAME2(sine_1024);
|
|
const INTFLOAT *swindow_prev = ics->use_kb_window[1] ? AAC_RENAME2(aac_kbd_short_128) : AAC_RENAME2(sine_128);
|
|
INTFLOAT *buf = ac->AAC_RENAME(buf_mdct);
|
|
INTFLOAT *temp = ac->AAC_RENAME(temp);
|
|
int i;
|
|
|
|
// imdct
|
|
if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
|
|
for (i = 0; i < 1024; i += 128)
|
|
ac->mdct128_fn(ac->mdct128, buf + i, in + i, sizeof(INTFLOAT));
|
|
} else {
|
|
ac->mdct1024_fn(ac->mdct1024, buf, in, sizeof(INTFLOAT));
|
|
}
|
|
|
|
/* window overlapping
|
|
* NOTE: To simplify the overlapping code, all 'meaningless' short to long
|
|
* and long to short transitions are considered to be short to short
|
|
* transitions. This leaves just two cases (long to long and short to short)
|
|
* with a little special sauce for EIGHT_SHORT_SEQUENCE.
|
|
*/
|
|
if ((ics->window_sequence[1] == ONLY_LONG_SEQUENCE || ics->window_sequence[1] == LONG_STOP_SEQUENCE) &&
|
|
(ics->window_sequence[0] == ONLY_LONG_SEQUENCE || ics->window_sequence[0] == LONG_START_SEQUENCE)) {
|
|
ac->fdsp->vector_fmul_window( out, saved, buf, lwindow_prev, 512);
|
|
} else {
|
|
memcpy( out, saved, 448 * sizeof(*out));
|
|
|
|
if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
|
|
ac->fdsp->vector_fmul_window(out + 448 + 0*128, saved + 448, buf + 0*128, swindow_prev, 64);
|
|
ac->fdsp->vector_fmul_window(out + 448 + 1*128, buf + 0*128 + 64, buf + 1*128, swindow, 64);
|
|
ac->fdsp->vector_fmul_window(out + 448 + 2*128, buf + 1*128 + 64, buf + 2*128, swindow, 64);
|
|
ac->fdsp->vector_fmul_window(out + 448 + 3*128, buf + 2*128 + 64, buf + 3*128, swindow, 64);
|
|
ac->fdsp->vector_fmul_window(temp, buf + 3*128 + 64, buf + 4*128, swindow, 64);
|
|
memcpy( out + 448 + 4*128, temp, 64 * sizeof(*out));
|
|
} else {
|
|
ac->fdsp->vector_fmul_window(out + 448, saved + 448, buf, swindow_prev, 64);
|
|
memcpy( out + 576, buf + 64, 448 * sizeof(*out));
|
|
}
|
|
}
|
|
|
|
// buffer update
|
|
if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
|
|
memcpy( saved, temp + 64, 64 * sizeof(*saved));
|
|
ac->fdsp->vector_fmul_window(saved + 64, buf + 4*128 + 64, buf + 5*128, swindow, 64);
|
|
ac->fdsp->vector_fmul_window(saved + 192, buf + 5*128 + 64, buf + 6*128, swindow, 64);
|
|
ac->fdsp->vector_fmul_window(saved + 320, buf + 6*128 + 64, buf + 7*128, swindow, 64);
|
|
memcpy( saved + 448, buf + 7*128 + 64, 64 * sizeof(*saved));
|
|
} else if (ics->window_sequence[0] == LONG_START_SEQUENCE) {
|
|
memcpy( saved, buf + 512, 448 * sizeof(*saved));
|
|
memcpy( saved + 448, buf + 7*128 + 64, 64 * sizeof(*saved));
|
|
} else { // LONG_STOP or ONLY_LONG
|
|
memcpy( saved, buf + 512, 512 * sizeof(*saved));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Conduct IMDCT and windowing.
|
|
*/
|
|
static void AAC_RENAME(imdct_and_windowing_960)(AACDecContext *ac, SingleChannelElement *sce)
|
|
{
|
|
IndividualChannelStream *ics = &sce->ics;
|
|
INTFLOAT *in = sce->AAC_RENAME(coeffs);
|
|
INTFLOAT *out = sce->AAC_RENAME(output);
|
|
INTFLOAT *saved = sce->AAC_RENAME(saved);
|
|
const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME(aac_kbd_short_120) : AAC_RENAME(sine_120);
|
|
const INTFLOAT *lwindow_prev = ics->use_kb_window[1] ? AAC_RENAME(aac_kbd_long_960) : AAC_RENAME(sine_960);
|
|
const INTFLOAT *swindow_prev = ics->use_kb_window[1] ? AAC_RENAME(aac_kbd_short_120) : AAC_RENAME(sine_120);
|
|
INTFLOAT *buf = ac->AAC_RENAME(buf_mdct);
|
|
INTFLOAT *temp = ac->AAC_RENAME(temp);
|
|
int i;
|
|
|
|
// imdct
|
|
if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
|
|
for (i = 0; i < 8; i++)
|
|
ac->mdct120_fn(ac->mdct120, buf + i * 120, in + i * 128, sizeof(INTFLOAT));
|
|
} else {
|
|
ac->mdct960_fn(ac->mdct960, buf, in, sizeof(INTFLOAT));
|
|
}
|
|
|
|
/* window overlapping
|
|
* NOTE: To simplify the overlapping code, all 'meaningless' short to long
|
|
* and long to short transitions are considered to be short to short
|
|
* transitions. This leaves just two cases (long to long and short to short)
|
|
* with a little special sauce for EIGHT_SHORT_SEQUENCE.
|
|
*/
|
|
|
|
if ((ics->window_sequence[1] == ONLY_LONG_SEQUENCE || ics->window_sequence[1] == LONG_STOP_SEQUENCE) &&
|
|
(ics->window_sequence[0] == ONLY_LONG_SEQUENCE || ics->window_sequence[0] == LONG_START_SEQUENCE)) {
|
|
ac->fdsp->vector_fmul_window( out, saved, buf, lwindow_prev, 480);
|
|
} else {
|
|
memcpy( out, saved, 420 * sizeof(*out));
|
|
|
|
if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
|
|
ac->fdsp->vector_fmul_window(out + 420 + 0*120, saved + 420, buf + 0*120, swindow_prev, 60);
|
|
ac->fdsp->vector_fmul_window(out + 420 + 1*120, buf + 0*120 + 60, buf + 1*120, swindow, 60);
|
|
ac->fdsp->vector_fmul_window(out + 420 + 2*120, buf + 1*120 + 60, buf + 2*120, swindow, 60);
|
|
ac->fdsp->vector_fmul_window(out + 420 + 3*120, buf + 2*120 + 60, buf + 3*120, swindow, 60);
|
|
ac->fdsp->vector_fmul_window(temp, buf + 3*120 + 60, buf + 4*120, swindow, 60);
|
|
memcpy( out + 420 + 4*120, temp, 60 * sizeof(*out));
|
|
} else {
|
|
ac->fdsp->vector_fmul_window(out + 420, saved + 420, buf, swindow_prev, 60);
|
|
memcpy( out + 540, buf + 60, 420 * sizeof(*out));
|
|
}
|
|
}
|
|
|
|
// buffer update
|
|
if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
|
|
memcpy( saved, temp + 60, 60 * sizeof(*saved));
|
|
ac->fdsp->vector_fmul_window(saved + 60, buf + 4*120 + 60, buf + 5*120, swindow, 60);
|
|
ac->fdsp->vector_fmul_window(saved + 180, buf + 5*120 + 60, buf + 6*120, swindow, 60);
|
|
ac->fdsp->vector_fmul_window(saved + 300, buf + 6*120 + 60, buf + 7*120, swindow, 60);
|
|
memcpy( saved + 420, buf + 7*120 + 60, 60 * sizeof(*saved));
|
|
} else if (ics->window_sequence[0] == LONG_START_SEQUENCE) {
|
|
memcpy( saved, buf + 480, 420 * sizeof(*saved));
|
|
memcpy( saved + 420, buf + 7*120 + 60, 60 * sizeof(*saved));
|
|
} else { // LONG_STOP or ONLY_LONG
|
|
memcpy( saved, buf + 480, 480 * sizeof(*saved));
|
|
}
|
|
}
|
|
static void AAC_RENAME(imdct_and_windowing_ld)(AACDecContext *ac, SingleChannelElement *sce)
|
|
{
|
|
IndividualChannelStream *ics = &sce->ics;
|
|
INTFLOAT *in = sce->AAC_RENAME(coeffs);
|
|
INTFLOAT *out = sce->AAC_RENAME(output);
|
|
INTFLOAT *saved = sce->AAC_RENAME(saved);
|
|
INTFLOAT *buf = ac->AAC_RENAME(buf_mdct);
|
|
|
|
// imdct
|
|
ac->mdct512_fn(ac->mdct512, buf, in, sizeof(INTFLOAT));
|
|
|
|
// window overlapping
|
|
if (ics->use_kb_window[1]) {
|
|
// AAC LD uses a low overlap sine window instead of a KBD window
|
|
memcpy(out, saved, 192 * sizeof(*out));
|
|
ac->fdsp->vector_fmul_window(out + 192, saved + 192, buf, AAC_RENAME2(sine_128), 64);
|
|
memcpy( out + 320, buf + 64, 192 * sizeof(*out));
|
|
} else {
|
|
ac->fdsp->vector_fmul_window(out, saved, buf, AAC_RENAME2(sine_512), 256);
|
|
}
|
|
|
|
// buffer update
|
|
memcpy(saved, buf + 256, 256 * sizeof(*saved));
|
|
}
|
|
|
|
static void AAC_RENAME(imdct_and_windowing_eld)(AACDecContext *ac, SingleChannelElement *sce)
|
|
{
|
|
UINTFLOAT *in = sce->AAC_RENAME(coeffs);
|
|
INTFLOAT *out = sce->AAC_RENAME(output);
|
|
INTFLOAT *saved = sce->AAC_RENAME(saved);
|
|
INTFLOAT *buf = ac->AAC_RENAME(buf_mdct);
|
|
int i;
|
|
const int n = ac->oc[1].m4ac.frame_length_short ? 480 : 512;
|
|
const int n2 = n >> 1;
|
|
const int n4 = n >> 2;
|
|
const INTFLOAT *const window = n == 480 ? AAC_RENAME(ff_aac_eld_window_480) :
|
|
AAC_RENAME(ff_aac_eld_window_512);
|
|
|
|
// Inverse transform, mapped to the conventional IMDCT by
|
|
// Chivukula, R.K.; Reznik, Y.A.; Devarajan, V.,
|
|
// "Efficient algorithms for MPEG-4 AAC-ELD, AAC-LD and AAC-LC filterbanks,"
|
|
// International Conference on Audio, Language and Image Processing, ICALIP 2008.
|
|
// URL: http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4590245&isnumber=4589950
|
|
for (i = 0; i < n2; i+=2) {
|
|
INTFLOAT temp;
|
|
temp = in[i ]; in[i ] = -in[n - 1 - i]; in[n - 1 - i] = temp;
|
|
temp = -in[i + 1]; in[i + 1] = in[n - 2 - i]; in[n - 2 - i] = temp;
|
|
}
|
|
|
|
if (n == 480)
|
|
ac->mdct480_fn(ac->mdct480, buf, in, sizeof(INTFLOAT));
|
|
else
|
|
ac->mdct512_fn(ac->mdct512, buf, in, sizeof(INTFLOAT));
|
|
|
|
for (i = 0; i < n; i+=2) {
|
|
buf[i + 0] = -(UINTFLOAT)(USE_FIXED + 1)*buf[i + 0];
|
|
buf[i + 1] = (UINTFLOAT)(USE_FIXED + 1)*buf[i + 1];
|
|
}
|
|
// Like with the regular IMDCT at this point we still have the middle half
|
|
// of a transform but with even symmetry on the left and odd symmetry on
|
|
// the right
|
|
|
|
// window overlapping
|
|
// The spec says to use samples [0..511] but the reference decoder uses
|
|
// samples [128..639].
|
|
for (i = n4; i < n2; i ++) {
|
|
out[i - n4] = AAC_MUL31( buf[ n2 - 1 - i] , window[i - n4]) +
|
|
AAC_MUL31( saved[ i + n2] , window[i + n - n4]) +
|
|
AAC_MUL31(-saved[n + n2 - 1 - i] , window[i + 2*n - n4]) +
|
|
AAC_MUL31(-saved[ 2*n + n2 + i] , window[i + 3*n - n4]);
|
|
}
|
|
for (i = 0; i < n2; i ++) {
|
|
out[n4 + i] = AAC_MUL31( buf[ i] , window[i + n2 - n4]) +
|
|
AAC_MUL31(-saved[ n - 1 - i] , window[i + n2 + n - n4]) +
|
|
AAC_MUL31(-saved[ n + i] , window[i + n2 + 2*n - n4]) +
|
|
AAC_MUL31( saved[2*n + n - 1 - i] , window[i + n2 + 3*n - n4]);
|
|
}
|
|
for (i = 0; i < n4; i ++) {
|
|
out[n2 + n4 + i] = AAC_MUL31( buf[ i + n2] , window[i + n - n4]) +
|
|
AAC_MUL31(-saved[n2 - 1 - i] , window[i + 2*n - n4]) +
|
|
AAC_MUL31(-saved[n + n2 + i] , window[i + 3*n - n4]);
|
|
}
|
|
|
|
// buffer update
|
|
memmove(saved + n, saved, 2 * n * sizeof(*saved));
|
|
memcpy( saved, buf, n * sizeof(*saved));
|
|
}
|
|
|
|
static void AAC_RENAME(clip_output)(AACDecContext *ac, ChannelElement *che,
|
|
int type, int samples)
|
|
{
|
|
#if USE_FIXED
|
|
/* preparation for resampler */
|
|
for (int j = 0; j < samples; j++){
|
|
che->ch[0].output_fixed[j] = (int32_t)av_clip64((int64_t)che->ch[0].output_fixed[j]*128,
|
|
INT32_MIN, INT32_MAX-0x8000)+0x8000;
|
|
if (type == TYPE_CPE || (type == TYPE_SCE && ac->oc[1].m4ac.ps == 1))
|
|
che->ch[1].output_fixed[j] = (int32_t)av_clip64((int64_t)che->ch[1].output_fixed[j]*128,
|
|
INT32_MIN, INT32_MAX-0x8000)+0x8000;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static inline void reset_all_predictors(PredictorState *ps)
|
|
{
|
|
int i;
|
|
for (i = 0; i < MAX_PREDICTORS; i++)
|
|
reset_predict_state(&ps[i]);
|
|
}
|
|
|
|
static inline void reset_predictor_group(PredictorState *ps, int group_num)
|
|
{
|
|
int i;
|
|
for (i = group_num - 1; i < MAX_PREDICTORS; i += 30)
|
|
reset_predict_state(&ps[i]);
|
|
}
|
|
|
|
/**
|
|
* Apply AAC-Main style frequency domain prediction.
|
|
*/
|
|
static void AAC_RENAME(apply_prediction)(AACDecContext *ac, SingleChannelElement *sce)
|
|
{
|
|
int sfb, k;
|
|
|
|
if (!sce->ics.predictor_initialized) {
|
|
reset_all_predictors(sce->AAC_RENAME(predictor_state));
|
|
sce->ics.predictor_initialized = 1;
|
|
}
|
|
|
|
if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) {
|
|
for (sfb = 0;
|
|
sfb < ff_aac_pred_sfb_max[ac->oc[1].m4ac.sampling_index];
|
|
sfb++) {
|
|
for (k = sce->ics.swb_offset[sfb];
|
|
k < sce->ics.swb_offset[sfb + 1];
|
|
k++) {
|
|
predict(&sce->AAC_RENAME(predictor_state)[k],
|
|
&sce->AAC_RENAME(coeffs)[k],
|
|
sce->ics.predictor_present &&
|
|
sce->ics.prediction_used[sfb]);
|
|
}
|
|
}
|
|
if (sce->ics.predictor_reset_group)
|
|
reset_predictor_group(sce->AAC_RENAME(predictor_state),
|
|
sce->ics.predictor_reset_group);
|
|
} else
|
|
reset_all_predictors(sce->AAC_RENAME(predictor_state));
|
|
}
|
|
|
|
const AACDecDSP AAC_RENAME(aac_dsp) = {
|
|
.init = &AAC_RENAME(init),
|
|
|
|
.dequant_scalefactors = &AAC_RENAME(dequant_scalefactors),
|
|
.apply_mid_side_stereo = &AAC_RENAME(apply_mid_side_stereo),
|
|
.apply_intensity_stereo = &AAC_RENAME(apply_intensity_stereo),
|
|
.apply_tns = &AAC_RENAME(apply_tns),
|
|
.apply_ltp = &AAC_RENAME(apply_ltp),
|
|
.update_ltp = &AAC_RENAME(update_ltp),
|
|
|
|
.apply_prediction = AAC_RENAME(apply_prediction),
|
|
|
|
.imdct_and_windowing = AAC_RENAME(imdct_and_windowing),
|
|
.imdct_and_windowing_960 = AAC_RENAME(imdct_and_windowing_960),
|
|
.imdct_and_windowing_ld = AAC_RENAME(imdct_and_windowing_ld),
|
|
.imdct_and_windowing_eld = AAC_RENAME(imdct_and_windowing_eld),
|
|
|
|
.apply_dependent_coupling = AAC_RENAME(apply_dependent_coupling),
|
|
.apply_independent_coupling = AAC_RENAME(apply_independent_coupling),
|
|
|
|
.clip_output = AAC_RENAME(clip_output),
|
|
};
|