This is an automated email from the git hooks/post-receive script.
Git pushed a commit to branch master
in repository ffmpeg.
The following commit(s) were added to refs/heads/master by this push:
new c1b19ee69f aacdec: add support for 960-frame HE-AAC (DAB+) decoding
c1b19ee69f is described below
commit c1b19ee69f2142bb4b098936cc7421d80b3db7e4
Author: Lynne <[email protected]>
AuthorDate: Fri Apr 17 15:51:05 2026 +0200
Commit: Lynne <[email protected]>
CommitDate: Fri Apr 17 16:46:52 2026 +0200
aacdec: add support for 960-frame HE-AAC (DAB+) decoding
Finally, after so many years. I'm sure there's good DAB+ content
out there being broadcast. Go and listen to it.
---
Changelog | 1 +
libavcodec/aac/aacdec.c | 17 ++--------
libavcodec/aac/aacdec.h | 7 ++--
libavcodec/aac/aacdec_usac.c | 2 +-
libavcodec/aacsbr.h | 12 ++++---
libavcodec/aacsbr_template.c | 81 +++++++++++++++++++++++---------------------
libavcodec/sbr.h | 4 +--
7 files changed, 60 insertions(+), 64 deletions(-)
diff --git a/Changelog b/Changelog
index d399c0a8c1..0e9a078db5 100644
--- a/Changelog
+++ b/Changelog
@@ -6,6 +6,7 @@ version <next>:
- LCEVC track muxing support in MP4 muxer
- Playdate video encoder and muxer
- Add v360_vulkan filter
+- HE-AAC 960 decoding (DAB+)
version 8.1:
diff --git a/libavcodec/aac/aacdec.c b/libavcodec/aac/aacdec.c
index b8d53036d4..1de98684b0 100644
--- a/libavcodec/aac/aacdec.c
+++ b/libavcodec/aac/aacdec.c
@@ -889,12 +889,6 @@ static int decode_ga_specific_config(AACDecContext *ac,
AVCodecContext *avctx,
int tags = 0;
m4ac->frame_length_short = get_bits1(gb);
- if (m4ac->frame_length_short && m4ac->sbr == 1) {
- avpriv_report_missing_feature(avctx, "SBR with 960 frame length");
- if (ac) ac->warned_960_sbr = 1;
- m4ac->sbr = 0;
- m4ac->ps = 0;
- }
if (get_bits1(gb)) // dependsOnCoreCoder
skip_bits(gb, 14); // coreCoderDelay
@@ -1950,13 +1944,6 @@ static int decode_extension_payload(AACDecContext *ac,
GetBitContext *gb, int cn
if (!che) {
av_log(ac->avctx, AV_LOG_ERROR, "SBR was found before the first
channel element.\n");
return res;
- } else if (ac->oc[1].m4ac.frame_length_short) {
- if (!ac->warned_960_sbr)
- avpriv_report_missing_feature(ac->avctx,
- "SBR with 960 frame length");
- ac->warned_960_sbr = 1;
- skip_bits_long(gb, 8 * cnt - 4);
- return res;
} else if (!ac->oc[1].m4ac.sbr) {
av_log(ac->avctx, AV_LOG_ERROR, "SBR signaled to be not-present
but was found in the bitstream.\n");
skip_bits_long(gb, 8 * cnt - 4);
@@ -1977,7 +1964,8 @@ static int decode_extension_payload(AACDecContext *ac,
GetBitContext *gb, int cn
ac->avctx->profile = AV_PROFILE_AAC_HE;
}
- ac->proc.sbr_decode_extension(ac, che, gb, crc_flag, cnt, elem_type);
+ ac->proc.sbr_decode_extension(ac, che, gb, crc_flag, cnt, elem_type,
+ ac->oc[1].m4ac.frame_length_short);
if (ac->oc[1].m4ac.ps == 1 && !ac->warned_he_aac_mono) {
av_log(ac->avctx, AV_LOG_VERBOSE, "Treating HE-AAC mono as
stereo.\n");
@@ -2087,6 +2075,7 @@ static void spectral_to_sample(AACDecContext *ac, int
samples)
}
if (ac->oc[1].m4ac.sbr > 0) {
ac->proc.sbr_apply(ac, che, type,
+ ac->oc[1].m4ac.frame_length_short,
che->ch[0].output,
che->ch[1].output);
}
diff --git a/libavcodec/aac/aacdec.h b/libavcodec/aac/aacdec.h
index 9785576680..c67246e287 100644
--- a/libavcodec/aac/aacdec.h
+++ b/libavcodec/aac/aacdec.h
@@ -433,9 +433,9 @@ typedef struct AACDecProc {
int (*sbr_ctx_alloc_init)(AACDecContext *ac, ChannelElement **che, int
id_aac);
int (*sbr_decode_extension)(AACDecContext *ac, ChannelElement *che,
- GetBitContext *gb, int crc, int cnt, int
id_aac);
- void (*sbr_apply)(AACDecContext *ac, ChannelElement *che,
- int id_aac, void /* INTFLOAT */ *L, void /* INTFLOAT */
*R);
+ GetBitContext *gb, int crc, int cnt, int
id_aac, int fl960);
+ void (*sbr_apply)(AACDecContext *ac, ChannelElement *che, int id_aac, int
fl960,
+ void /* INTFLOAT */ *L, void /* INTFLOAT */ *R);
void (*sbr_ctx_close)(ChannelElement *che);
} AACDecProc;
@@ -557,7 +557,6 @@ struct AACDecContext {
OutputConfiguration oc[2];
int warned_num_aac_frames;
- int warned_960_sbr;
unsigned warned_71_wide;
int warned_gain_control;
int warned_he_aac_mono;
diff --git a/libavcodec/aac/aacdec_usac.c b/libavcodec/aac/aacdec_usac.c
index 4d57fbfff7..0f1bb50a99 100644
--- a/libavcodec/aac/aacdec_usac.c
+++ b/libavcodec/aac/aacdec_usac.c
@@ -1671,7 +1671,7 @@ static int decode_usac_core_coder(AACDecContext *ac,
AACUSACConfig *usac,
spectrum_decode(ac, usac, che, core_nb_channels);
if (ac->oc[1].m4ac.sbr > 0) {
- ac->proc.sbr_apply(ac, che, nb_channels == 2 ? TYPE_CPE : TYPE_SCE,
+ ac->proc.sbr_apply(ac, che, nb_channels == 2 ? TYPE_CPE : TYPE_SCE, 0,
che->ch[0].output,
che->ch[1].output);
}
diff --git a/libavcodec/aacsbr.h b/libavcodec/aacsbr.h
index 3958b43b91..afc8ad188a 100644
--- a/libavcodec/aacsbr.h
+++ b/libavcodec/aacsbr.h
@@ -84,9 +84,11 @@ void ff_aac_sbr_ctx_close_fixed(ChannelElement *che);
/** Decode one SBR element. */
int ff_aac_sbr_decode_extension(AACDecContext *ac, ChannelElement *che,
- GetBitContext *gb, int crc, int cnt, int
id_aac);
+ GetBitContext *gb, int crc, int cnt, int
id_aac,
+ int fl960);
int ff_aac_sbr_decode_extension_fixed(AACDecContext *ac, ChannelElement *che,
- GetBitContext *gb, int crc, int cnt, int
id_aac);
+ GetBitContext *gb, int crc, int cnt, int
id_aac,
+ int fl960);
/** Due to channel allocation not being known upon SBR parameter transmission,
* supply the parameters separately.
@@ -101,9 +103,11 @@ int ff_aac_sbr_decode_usac_data(AACDecContext *ac,
ChannelElement *che,
/** Apply one SBR element to one AAC element. */
void ff_aac_sbr_apply(AACDecContext *ac, ChannelElement *che,
- int id_aac, void /* float */ *L, void /* float */ *R);
+ int id_aac, int fl960,
+ void /* float */ *L, void /* float */ *R);
void ff_aac_sbr_apply_fixed(AACDecContext *ac, ChannelElement *che,
- int id_aac, void /* int */ *L, void /* int */ *R);
+ int id_aac, int fl960,
+ void /* int */ *L, void /* int */ *R);
FF_VISIBILITY_POP_HIDDEN
diff --git a/libavcodec/aacsbr_template.c b/libavcodec/aacsbr_template.c
index 31d2d844c4..c10f5f312d 100644
--- a/libavcodec/aacsbr_template.c
+++ b/libavcodec/aacsbr_template.c
@@ -636,12 +636,11 @@ static const int8_t ceil_log2[] = {
};
static int read_sbr_grid(AACDecContext *ac, SpectralBandReplication *sbr,
- GetBitContext *gb, SBRData *ch_data)
+ GetBitContext *gb, SBRData *ch_data, int numTimeSlots)
{
int i;
int bs_pointer = 0;
- // frameLengthFlag ? 15 : 16; 960 sample length frames unsupported; this
value is numTimeSlots
- int abs_bord_trail = 16;
+ int abs_bord_trail = numTimeSlots;
int num_rel_lead, num_rel_trail;
unsigned bs_num_env_old = ch_data->bs_num_env;
int bs_frame_class, bs_num_env;
@@ -991,15 +990,15 @@ static void read_sbr_extension(AACDecContext *ac,
SpectralBandReplication *sbr,
}
static int read_sbr_single_channel_element(AACDecContext *ac,
- SpectralBandReplication *sbr,
- GetBitContext *gb)
+ SpectralBandReplication *sbr,
+ GetBitContext *gb, int numTimeSlots)
{
int ret;
if (get_bits1(gb)) // bs_data_extra
skip_bits(gb, 4); // bs_reserved
- if (read_sbr_grid(ac, sbr, gb, &sbr->data[0]))
+ if (read_sbr_grid(ac, sbr, gb, &sbr->data[0], numTimeSlots))
return -1;
read_sbr_dtdf(sbr, gb, &sbr->data[0], 0);
read_sbr_invf(sbr, gb, &sbr->data[0]);
@@ -1015,8 +1014,8 @@ static int read_sbr_single_channel_element(AACDecContext
*ac,
}
static int read_sbr_channel_pair_element(AACDecContext *ac,
- SpectralBandReplication *sbr,
- GetBitContext *gb)
+ SpectralBandReplication *sbr,
+ GetBitContext *gb, int numTimeSlots)
{
int ret;
@@ -1024,7 +1023,7 @@ static int read_sbr_channel_pair_element(AACDecContext
*ac,
skip_bits(gb, 8); // bs_reserved
if ((sbr->bs_coupling = get_bits1(gb))) {
- if (read_sbr_grid(ac, sbr, gb, &sbr->data[0]))
+ if (read_sbr_grid(ac, sbr, gb, &sbr->data[0], numTimeSlots))
return -1;
copy_sbr_grid(&sbr->data[1], &sbr->data[0]);
read_sbr_dtdf(sbr, gb, &sbr->data[0], 0);
@@ -1041,8 +1040,8 @@ static int read_sbr_channel_pair_element(AACDecContext
*ac,
if((ret = read_sbr_noise(ac, sbr, gb, &sbr->data[1], 1)) < 0)
return ret;
} else {
- if (read_sbr_grid(ac, sbr, gb, &sbr->data[0]) ||
- read_sbr_grid(ac, sbr, gb, &sbr->data[1]))
+ if (read_sbr_grid(ac, sbr, gb, &sbr->data[0], numTimeSlots) ||
+ read_sbr_grid(ac, sbr, gb, &sbr->data[1], numTimeSlots))
return -1;
read_sbr_dtdf(sbr, gb, &sbr->data[0], 0);
read_sbr_dtdf(sbr, gb, &sbr->data[1], 0);
@@ -1067,7 +1066,7 @@ static int read_sbr_channel_pair_element(AACDecContext
*ac,
}
static unsigned int read_sbr_data(AACDecContext *ac, SpectralBandReplication
*sbr,
- GetBitContext *gb, int id_aac)
+ GetBitContext *gb, int id_aac, int
numTimeSlots)
{
unsigned int cnt = get_bits_count(gb);
@@ -1075,12 +1074,12 @@ static unsigned int read_sbr_data(AACDecContext *ac,
SpectralBandReplication *sb
sbr->ready_for_dequant = 1;
if (id_aac == TYPE_SCE || id_aac == TYPE_CCE) {
- if (read_sbr_single_channel_element(ac, sbr, gb)) {
+ if (read_sbr_single_channel_element(ac, sbr, gb, numTimeSlots)) {
sbr_turnoff(sbr);
return get_bits_count(gb) - cnt;
}
} else if (id_aac == TYPE_CPE) {
- if (read_sbr_channel_pair_element(ac, sbr, gb)) {
+ if (read_sbr_channel_pair_element(ac, sbr, gb, numTimeSlots)) {
sbr_turnoff(sbr);
return get_bits_count(gb) - cnt;
}
@@ -1133,12 +1132,13 @@ static void sbr_reset(AACDecContext *ac,
SpectralBandReplication *sbr)
*/
int AAC_RENAME(ff_aac_sbr_decode_extension)(AACDecContext *ac, ChannelElement
*che,
GetBitContext *gb_host, int crc,
- int cnt, int id_aac)
+ int cnt, int id_aac, int fl960)
{
SpectralBandReplication *sbr = get_sbr(che);
unsigned int num_sbr_bits = 0, num_align_bits;
unsigned bytes_read;
GetBitContext gbc = *gb_host, *gb = &gbc;
+ int numTimeSlots = fl960 ? 15 : 16;
skip_bits_long(gb_host, cnt*8 - 4);
sbr->reset = 0;
@@ -1166,7 +1166,7 @@ int AAC_RENAME(ff_aac_sbr_decode_extension)(AACDecContext
*ac, ChannelElement *c
sbr_reset(ac, sbr);
if (sbr->start)
- num_sbr_bits += read_sbr_data(ac, sbr, gb, id_aac);
+ num_sbr_bits += read_sbr_data(ac, sbr, gb, id_aac, numTimeSlots);
num_align_bits = ((cnt << 3) - 4 - num_sbr_bits) & 7;
bytes_read = ((num_sbr_bits + num_align_bits + 4) >> 3);
@@ -1272,7 +1272,7 @@ int ff_aac_sbr_decode_usac_data(AACDecContext *ac,
ChannelElement *che,
if (sbr_ch == 1) { /* sbr_single_channel_element */
/* if (harmonicSBR) ... */
- if (read_sbr_grid(ac, sbr, gb, &sbr->data[0]))
+ if (read_sbr_grid(ac, sbr, gb, &sbr->data[0], 16))
return -1;
read_sbr_dtdf(sbr, gb, &sbr->data[0], indep_flag);
@@ -1291,7 +1291,7 @@ int ff_aac_sbr_decode_usac_data(AACDecContext *ac,
ChannelElement *che,
/* if (harmonicSBR) ... */
- if (read_sbr_grid(ac, sbr, gb, &sbr->data[0]))
+ if (read_sbr_grid(ac, sbr, gb, &sbr->data[0], 16))
return -1;
copy_sbr_grid(&sbr->data[1], &sbr->data[0]);
@@ -1323,9 +1323,9 @@ int ff_aac_sbr_decode_usac_data(AACDecContext *ac,
ChannelElement *che,
/* if (harmonicSBR) ... */
- if (read_sbr_grid(ac, sbr, gb, &sbr->data[0]))
+ if (read_sbr_grid(ac, sbr, gb, &sbr->data[0], 16))
return -1;
- if (read_sbr_grid(ac, sbr, gb, &sbr->data[1]))
+ if (read_sbr_grid(ac, sbr, gb, &sbr->data[1], 16))
return -1;
read_sbr_dtdf(sbr, gb, &sbr->data[0], indep_flag);
@@ -1369,16 +1369,17 @@ static void sbr_qmf_analysis(AVFloatDSPContext *dsp,
AVTXContext *mdct,
av_tx_fn mdct_fn,
#endif /* USE_FIXED */
SBRDSPContext *sbrdsp, const INTFLOAT *in,
INTFLOAT *x,
- INTFLOAT z[320], INTFLOAT W[2][32][32][2], int
buf_idx)
+ INTFLOAT z[320], INTFLOAT W[2][32][32][2], int
buf_idx,
+ int numTimeSlots)
{
int i;
#if USE_FIXED
int j;
#endif
- memcpy(x , x+1024, (320-32)*sizeof(x[0]));
- memcpy(x+288, in, 1024*sizeof(x[0]));
- for (i = 0; i < 32; i++) { // numTimeSlots*RATE = 16*2 as 960 sample frames
- // are not supported
+ int nb = numTimeSlots * 64;
+ memcpy(x , x+nb, (320-32)*sizeof(x[0]));
+ memcpy(x+288, in, nb*sizeof(x[0]));
+ for (i = 0; i < numTimeSlots*2; i++) { // RATE*numTimeSlots = 2* 16 or 15
dsp->vector_fmul_reverse(z, sbr_qmf_window_ds, x, 320);
sbrdsp->sum64x5(z);
sbrdsp->qmf_pre_shuffle(z);
@@ -1417,13 +1418,14 @@ static void sbr_qmf_synthesis(AVTXContext *mdct,
av_tx_fn mdct_fn,
#endif /* USE_FIXED */
INTFLOAT *out, INTFLOAT X[2][38][64],
INTFLOAT mdct_buf[2][64],
- INTFLOAT *v0, int *v_off, const unsigned int div)
+ INTFLOAT *v0, int *v_off, int numTimeSlots,
+ const unsigned int div)
{
int i, n;
const INTFLOAT *sbr_qmf_window = div ? sbr_qmf_window_ds :
sbr_qmf_window_us;
const int step = 128 >> div;
INTFLOAT *v;
- for (i = 0; i < 32; i++) {
+ for (i = 0; i < numTimeSlots*2; i++) {
if (*v_off < step) {
int saved_samples = (1280 - 128) >> div;
memcpy(&v0[SBR_SYNTHESIS_BUF_SIZE - saved_samples], v0,
saved_samples * sizeof(INTFLOAT));
@@ -1463,11 +1465,11 @@ static void sbr_qmf_synthesis(AVTXContext *mdct,
av_tx_fn mdct_fn,
/// Generate the subband filtered lowband
static int sbr_lf_gen(SpectralBandReplication *sbr,
INTFLOAT X_low[32][40][2], const INTFLOAT
W[2][32][32][2],
- int buf_idx)
+ int buf_idx, int numTimeSlots)
{
int i, k;
const int t_HFGen = 8;
- const int i_f = 32;
+ const int i_f = numTimeSlots*2;
memset(X_low, 0, 32*sizeof(*X_low));
for (k = 0; k < sbr->kx[1]; k++) {
for (i = t_HFGen; i < i_f + t_HFGen; i++) {
@@ -1523,10 +1525,10 @@ static int sbr_hf_gen(AACDecContext *ac,
SpectralBandReplication *sbr,
/// Generate the subband filtered lowband
static int sbr_x_gen(SpectralBandReplication *sbr, INTFLOAT X[2][38][64],
const INTFLOAT Y0[38][64][2], const INTFLOAT
Y1[38][64][2],
- const INTFLOAT X_low[32][40][2], int ch)
+ const INTFLOAT X_low[32][40][2], int ch, int numTimeSlots)
{
int k, i;
- const int i_f = 32;
+ const int i_f = numTimeSlots*2;
const int i_Temp = FFMAX(2*sbr->data[ch].t_env_num_env_old - i_f, 0);
memset(X, 0, 2*sizeof(*X));
for (k = 0; k < sbr->kx[0]; k++) {
@@ -1681,7 +1683,7 @@ static void sbr_env_estimate(AAC_FLOAT (*e_curr)[48],
INTFLOAT X_high[64][40][2]
}
void AAC_RENAME(ff_aac_sbr_apply)(AACDecContext *ac, ChannelElement *che,
- int id_aac, void *L_, void *R_)
+ int id_aac, int fl960, void *L_, void *R_)
{
INTFLOAT *L = L_, *R = R_;
SpectralBandReplication *sbr = get_sbr(che);
@@ -1689,6 +1691,7 @@ void AAC_RENAME(ff_aac_sbr_apply)(AACDecContext *ac,
ChannelElement *che,
int ch;
int nch = (id_aac == TYPE_CPE) ? 2 : 1;
int err;
+ int numTimeSlots = fl960 ? 15 : 16;
if (id_aac != sbr->id_aac) {
av_log(ac->avctx, id_aac == TYPE_LFE ? AV_LOG_VERBOSE : AV_LOG_WARNING,
@@ -1718,10 +1721,10 @@ void AAC_RENAME(ff_aac_sbr_apply)(AACDecContext *ac,
ChannelElement *che,
sbr_qmf_analysis(ac->fdsp, sbr->mdct_ana, sbr->mdct_ana_fn, &sbr->dsp,
ch ? R : L, sbr->data[ch].analysis_filterbank_samples,
(INTFLOAT*)sbr->qmf_filter_scratch,
- sbr->data[ch].W, sbr->data[ch].Ypos);
+ sbr->data[ch].W, sbr->data[ch].Ypos, numTimeSlots);
sbr->c.sbr_lf_gen(sbr, sbr->X_low,
(const INTFLOAT (*)[32][32][2]) sbr->data[ch].W,
- sbr->data[ch].Ypos);
+ sbr->data[ch].Ypos, numTimeSlots);
sbr->data[ch].Ypos ^= 1;
if (sbr->start) {
sbr->c.sbr_hf_inverse_filter(&sbr->dsp, sbr->alpha0, sbr->alpha1,
@@ -1749,9 +1752,9 @@ void AAC_RENAME(ff_aac_sbr_apply)(AACDecContext *ac,
ChannelElement *che,
/* synthesis */
sbr->c.sbr_x_gen(sbr, sbr->X[ch],
- (const INTFLOAT (*)[64][2])
sbr->data[ch].Y[1-sbr->data[ch].Ypos],
- (const INTFLOAT (*)[64][2]) sbr->data[ch].Y[
sbr->data[ch].Ypos],
- (const INTFLOAT (*)[40][2]) sbr->X_low, ch);
+ (const INTFLOAT (*)[64][2])
sbr->data[ch].Y[1-sbr->data[ch].Ypos],
+ (const INTFLOAT (*)[64][2]) sbr->data[ch].Y[
sbr->data[ch].Ypos],
+ (const INTFLOAT (*)[40][2]) sbr->X_low, ch,
numTimeSlots);
}
if (ac->oc[1].m4ac.ps == 1) {
@@ -1767,13 +1770,13 @@ void AAC_RENAME(ff_aac_sbr_apply)(AACDecContext *ac,
ChannelElement *che,
L, sbr->X[0], sbr->qmf_filter_scratch,
sbr->data[0].synthesis_filterbank_samples,
&sbr->data[0].synthesis_filterbank_samples_offset,
- downsampled);
+ numTimeSlots, downsampled);
if (nch == 2)
sbr_qmf_synthesis(sbr->mdct, sbr->mdct_fn, &sbr->dsp, ac->fdsp,
R, sbr->X[1], sbr->qmf_filter_scratch,
sbr->data[1].synthesis_filterbank_samples,
&sbr->data[1].synthesis_filterbank_samples_offset,
- downsampled);
+ numTimeSlots, downsampled);
}
static void aacsbr_func_ptr_init(AACSBRContext *c)
diff --git a/libavcodec/sbr.h b/libavcodec/sbr.h
index 40bb30e04d..ae7208c416 100644
--- a/libavcodec/sbr.h
+++ b/libavcodec/sbr.h
@@ -124,14 +124,14 @@ typedef struct SpectralBandReplication
SpectralBandReplication;
typedef struct AACSBRContext {
int (*sbr_lf_gen)(SpectralBandReplication *sbr,
INTFLOAT X_low[32][40][2], const INTFLOAT
W[2][32][32][2],
- int buf_idx);
+ int buf_idx, int numTimeSlots);
void (*sbr_hf_assemble)(INTFLOAT Y1[38][64][2],
const INTFLOAT X_high[64][40][2],
SpectralBandReplication *sbr, SBRData *ch_data,
const int e_a[2]);
int (*sbr_x_gen)(SpectralBandReplication *sbr, INTFLOAT X[2][38][64],
const INTFLOAT Y0[38][64][2], const INTFLOAT
Y1[38][64][2],
- const INTFLOAT X_low[32][40][2], int ch);
+ const INTFLOAT X_low[32][40][2], int ch, int
numTimeSlots);
void (*sbr_hf_inverse_filter)(SBRDSPContext *dsp,
INTFLOAT (*alpha0)[2], INTFLOAT (*alpha1)[2],
const INTFLOAT X_low[32][40][2], int k0);
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]