PR #25203 opened by Nathan Moinvaziri (nmoinvaz) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25203 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25203.patch
Every coefficient that needs an escape code called `cbrtf()` from libm while `quantize_and_encode_band_cost_template()` priced a band, which was a quarter of the encode time with the default NMR coder. 1. Look up `c * cbrtf(c)` for the 8192 escape magnitudes in a table built once at init. 2. In `nmr_trellis_step_c()`, compute the range of predecessors within `SCALE_MAX_DIFF` before the inner loop, instead of testing the scalefactor difference of every candidate inside it. Both commits keep the bitstream identical. Packet MD5s match master for the twoloop, fast and NMR coders from 64k to 512k, VBR, mono, 5.1, 44.1 kHz and with PNS, IS, TNS and M/S enabled. The FATE AAC encode tests and `checkasm-aacencdsp` pass. The decoder's `ff_cbrt_tab` holds the same values computed in double, but 2989 of its 8192 entries differ from `c * cbrtf(c)` by up to 2 ulp, so reusing it would change the output. | 52 s stereo, 48 kHz | master | this PR | time | |---|---|---|---| | `-b:a 96k` | 1.72 s | 1.19 s | -31% | | `-b:a 128k` | 1.89 s | 1.31 s | -31% | | `-b:a 256k` | 2.38 s | 1.52 s | -36% | | `-q:a 2` | 2.55 s | 1.83 s | -28% | Measured on an i7-1185G7 with GCC 16. >From 2b0d4a2fc61a4dcee5b140e901fc643e244b8667 Mon Sep 17 00:00:00 2001 From: Nathan Moinvaziri <[email protected]> Date: Sun, 18 Oct 2026 12:45:18 -0700 Subject: [PATCH 1/2] avcodec/aaccoder: look up the reconstruction of escape values Pricing an escape value called cbrtf() from libm for every coefficient, which cost a quarter of the encode time with the default coder. A table of c * cbrtf(c) over the 8192 escape magnitudes, built once, keeps the output identical and makes encoding about 30% faster. --- libavcodec/aaccoder.c | 11 ++++++++++- libavcodec/aacenc.c | 3 +++ libavcodec/aacenc.h | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libavcodec/aaccoder.c b/libavcodec/aaccoder.c index 4f30a57e5c..bb2e7f9f9e 100644 --- a/libavcodec/aaccoder.c +++ b/libavcodec/aaccoder.c @@ -61,6 +61,15 @@ #include "libavcodec/aaccoder_trellis.h" #include "libavcodec/aaccoder_nmr.h" +/* c * cbrtf(c), the reconstruction of every escape magnitude c */ +static float esc_pow43[1 << 13]; + +av_cold void ff_aac_coder_init_tables(void) +{ + for (int c = 0; c < FF_ARRAY_ELEMS(esc_pow43); c++) + esc_pow43[c] = c * cbrtf(c); +} + typedef float (*quantize_and_encode_band_func)(struct AACEncContext *s, PutBitContext *pb, const float *in, float *quant, const float *scaled, int size, int scale_idx, int cb, @@ -138,7 +147,7 @@ static av_always_inline float quantize_and_encode_band_cost_template( curbits += 21; } else { int c = av_clip_uintp2(quant(t, Q, ROUNDING), 13); - quantized = c*cbrtf(c)*IQ; + quantized = esc_pow43[c]*IQ; curbits += av_log2(c)*2 - 4 + 1; } } else { diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index d4b4a1e4f9..5b1e3eff0f 100644 --- a/libavcodec/aacenc.c +++ b/libavcodec/aacenc.c @@ -36,6 +36,7 @@ #include "libavutil/float_dsp.h" #include "libavutil/mem.h" #include "libavutil/opt.h" +#include "libavutil/thread.h" #include "avcodec.h" #include "codec_internal.h" #include "encode.h" @@ -1822,6 +1823,7 @@ static av_cold int check_height_ext(AVCodecContext *avctx, AACEncContext *s) static av_cold int aac_encode_init(AVCodecContext *avctx) { + static AVOnce init_static_once = AV_ONCE_INIT; AACEncContext *s = avctx->priv_data; int i, ret = 0; int chcfg; @@ -1980,6 +1982,7 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) // Initialize static tables ff_aac_float_common_init(); + ff_thread_once(&init_static_once, ff_aac_coder_init_tables); if ((ret = dsp_init(avctx, s)) < 0) return ret; diff --git a/libavcodec/aacenc.h b/libavcodec/aacenc.h index 057c2a59d4..a8f69e7051 100644 --- a/libavcodec/aacenc.h +++ b/libavcodec/aacenc.h @@ -160,6 +160,8 @@ typedef struct AACCoefficientsEncoder { extern const AACCoefficientsEncoder ff_aac_coders[]; +void ff_aac_coder_init_tables(void); + typedef struct AACQuantizeBandCostCacheEntry { float rd; float energy; -- 2.54.0 >From 3ae3338cc83153aafc9a98bbac88d47c92ea7d5d Mon Sep 17 00:00:00 2001 From: Nathan Moinvaziri <[email protected]> Date: Sun, 18 Oct 2026 12:50:28 -0700 Subject: [PATCH 2/2] avcodec/aacencdsp: bound the trellis predecessors by the sf difference Each step tested the scalefactor difference of every previous candidate inside the loop. Computing the range of predecessors within the allowed difference first keeps the output identical and makes AAC encoding about 3.5% faster. --- libavcodec/aacencdsp.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libavcodec/aacencdsp.c b/libavcodec/aacencdsp.c index 5ccc7e8fc8..bd9827b804 100644 --- a/libavcodec/aacencdsp.c +++ b/libavcodec/aacencdsp.c @@ -21,6 +21,7 @@ #include "config.h" +#include "libavutil/common.h" #include "libavutil/macros.h" #include "aacencdsp.h" @@ -53,15 +54,17 @@ static void nmr_trellis_step_c(float *dp, uint8_t *bp, const float *dpp, const float *node, const float *lamsf, int n_cur, int n_prev, int base, int step, int mdiff) { + /* d = base + (o - op) * step lies in [-mdiff, mdiff] for op in [o - dlo, o + dhi] */ + const int dlo = FFUDIV(mdiff - base, step); + const int dhi = FFUDIV(mdiff + base, step); + for (int o = 0; o < n_cur; o++) { + const int op_end = FFMIN(n_prev, o + dhi + 1); + const int edge = base + o * step + mdiff; int best = -1; float bestc = FLT_MAX; - for (int op = 0; op < n_prev; op++) { - int d = base + (o - op) * step; - float c; - if (d < -mdiff || d > mdiff) - continue; - c = dpp[op] + lamsf[d + mdiff]; + for (int op = FFMAX(0, o - dlo); op < op_end; op++) { + float c = dpp[op] + lamsf[edge - op * step]; if (c < bestc) { bestc = c; best = op; -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
