[FFmpeg-cvslog] aacenc: remove ANMR coder

Lynne git at videolan.org
Wed Feb 26 18:12:21 EET 2025


ffmpeg | branch: master | Lynne <dev at lynne.ee> | Sat Feb  8 05:22:16 2025 +0100| [b3d73df80d722ca329a2747ac5dba4476bd82e99] | committer: Lynne

aacenc: remove ANMR coder

If there's ever a rework of the AAC encoder, it won't start from here.
The codec, with all its oddities and tweaks needed to acheive good quality
has strayed far from the academic work upon which this coder was based on.
Its been 20 years since this paper was released, and no known existing
implementations, open-source or proprietary that we know of, are based on it.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=b3d73df80d722ca329a2747ac5dba4476bd82e99
---

 libavcodec/aaccoder.c | 287 --------------------------------------------------
 libavcodec/aacenc.c   |   7 --
 libavcodec/aacenc.h   |   1 -
 3 files changed, 295 deletions(-)

diff --git a/libavcodec/aaccoder.c b/libavcodec/aaccoder.c
index 478eda86f3..96915c9731 100644
--- a/libavcodec/aaccoder.c
+++ b/libavcodec/aaccoder.c
@@ -292,120 +292,6 @@ typedef struct BandCodingPath {
     int run;
 } BandCodingPath;
 
-/**
- * Encode band info for single window group bands.
- */
-static void encode_window_bands_info(AACEncContext *s, SingleChannelElement *sce,
-                                     int win, int group_len, const float lambda)
-{
-    BandCodingPath path[120][CB_TOT_ALL];
-    int w, swb, cb, start, size;
-    int i, j;
-    const int max_sfb  = sce->ics.max_sfb;
-    const int run_bits = sce->ics.num_windows == 1 ? 5 : 3;
-    const int run_esc  = (1 << run_bits) - 1;
-    int idx, ppos, count;
-    int stackrun[120], stackcb[120], stack_len;
-    float next_minrd = INFINITY;
-    int next_mincb = 0;
-
-    s->aacdsp.abs_pow34(s->scoefs, sce->coeffs, 1024);
-    start = win*128;
-    for (cb = 0; cb < CB_TOT_ALL; cb++) {
-        path[0][cb].cost     = 0.0f;
-        path[0][cb].prev_idx = -1;
-        path[0][cb].run      = 0;
-    }
-    for (swb = 0; swb < max_sfb; swb++) {
-        size = sce->ics.swb_sizes[swb];
-        if (sce->zeroes[win*16 + swb]) {
-            for (cb = 0; cb < CB_TOT_ALL; cb++) {
-                path[swb+1][cb].prev_idx = cb;
-                path[swb+1][cb].cost     = path[swb][cb].cost;
-                path[swb+1][cb].run      = path[swb][cb].run + 1;
-            }
-        } else {
-            float minrd = next_minrd;
-            int mincb = next_mincb;
-            next_minrd = INFINITY;
-            next_mincb = 0;
-            for (cb = 0; cb < CB_TOT_ALL; cb++) {
-                float cost_stay_here, cost_get_here;
-                float rd = 0.0f;
-                if (cb >= 12 && sce->band_type[win*16+swb] < aac_cb_out_map[cb] ||
-                    cb  < aac_cb_in_map[sce->band_type[win*16+swb]] && sce->band_type[win*16+swb] > aac_cb_out_map[cb]) {
-                    path[swb+1][cb].prev_idx = -1;
-                    path[swb+1][cb].cost     = INFINITY;
-                    path[swb+1][cb].run      = path[swb][cb].run + 1;
-                    continue;
-                }
-                for (w = 0; w < group_len; w++) {
-                    FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(win+w)*16+swb];
-                    rd += quantize_band_cost(s, &sce->coeffs[start + w*128],
-                                             &s->scoefs[start + w*128], size,
-                                             sce->sf_idx[(win+w)*16+swb], aac_cb_out_map[cb],
-                                             lambda / band->threshold, INFINITY, NULL, NULL);
-                }
-                cost_stay_here = path[swb][cb].cost + rd;
-                cost_get_here  = minrd              + rd + run_bits + 4;
-                if (   run_value_bits[sce->ics.num_windows == 8][path[swb][cb].run]
-                    != run_value_bits[sce->ics.num_windows == 8][path[swb][cb].run+1])
-                    cost_stay_here += run_bits;
-                if (cost_get_here < cost_stay_here) {
-                    path[swb+1][cb].prev_idx = mincb;
-                    path[swb+1][cb].cost     = cost_get_here;
-                    path[swb+1][cb].run      = 1;
-                } else {
-                    path[swb+1][cb].prev_idx = cb;
-                    path[swb+1][cb].cost     = cost_stay_here;
-                    path[swb+1][cb].run      = path[swb][cb].run + 1;
-                }
-                if (path[swb+1][cb].cost < next_minrd) {
-                    next_minrd = path[swb+1][cb].cost;
-                    next_mincb = cb;
-                }
-            }
-        }
-        start += sce->ics.swb_sizes[swb];
-    }
-
-    //convert resulting path from backward-linked list
-    stack_len = 0;
-    idx       = 0;
-    for (cb = 1; cb < CB_TOT_ALL; cb++)
-        if (path[max_sfb][cb].cost < path[max_sfb][idx].cost)
-            idx = cb;
-    ppos = max_sfb;
-    while (ppos > 0) {
-        av_assert1(idx >= 0);
-        cb = idx;
-        stackrun[stack_len] = path[ppos][cb].run;
-        stackcb [stack_len] = cb;
-        idx = path[ppos-path[ppos][cb].run+1][cb].prev_idx;
-        ppos -= path[ppos][cb].run;
-        stack_len++;
-    }
-    //perform actual band info encoding
-    start = 0;
-    for (i = stack_len - 1; i >= 0; i--) {
-        cb = aac_cb_out_map[stackcb[i]];
-        put_bits(&s->pb, 4, cb);
-        count = stackrun[i];
-        memset(sce->zeroes + win*16 + start, !cb, count);
-        //XXX: memset when band_type is also uint8_t
-        for (j = 0; j < count; j++) {
-            sce->band_type[win*16 + start] = cb;
-            start++;
-        }
-        while (count >= run_esc) {
-            put_bits(&s->pb, run_bits, run_esc);
-            count -= run_esc;
-        }
-        put_bits(&s->pb, run_bits, count);
-    }
-}
-
-
 typedef struct TrellisPath {
     float cost;
     int prev;
@@ -453,166 +339,6 @@ static void set_special_band_scalefactors(AACEncContext *s, SingleChannelElement
     }
 }
 
-static void search_for_quantizers_anmr(AVCodecContext *avctx, AACEncContext *s,
-                                       SingleChannelElement *sce,
-                                       const float lambda)
-{
-    int q, w, w2, g, start = 0;
-    int i, j;
-    int idx;
-    TrellisPath paths[TRELLIS_STAGES][TRELLIS_STATES];
-    int bandaddr[TRELLIS_STAGES];
-    int minq;
-    float mincost;
-    float q0f = FLT_MAX, q1f = 0.0f, qnrgf = 0.0f;
-    int q0, q1, qcnt = 0;
-
-    for (i = 0; i < 1024; i++) {
-        float t = fabsf(sce->coeffs[i]);
-        if (t > 0.0f) {
-            q0f = FFMIN(q0f, t);
-            q1f = FFMAX(q1f, t);
-            qnrgf += t*t;
-            qcnt++;
-        }
-    }
-
-    if (!qcnt) {
-        memset(sce->sf_idx, 0, sizeof(sce->sf_idx));
-        memset(sce->zeroes, 1, sizeof(sce->zeroes));
-        return;
-    }
-
-    //minimum scalefactor index is when minimum nonzero coefficient after quantizing is not clipped
-    q0 = av_clip(coef2minsf(q0f), 0, SCALE_MAX_POS-1);
-    //maximum scalefactor index is when maximum coefficient after quantizing is still not zero
-    q1 = av_clip(coef2maxsf(q1f), 1, SCALE_MAX_POS);
-    if (q1 - q0 > 60) {
-        int q0low  = q0;
-        int q1high = q1;
-        //minimum scalefactor index is when maximum nonzero coefficient after quantizing is not clipped
-        int qnrg = av_clip_uint8(log2f(sqrtf(qnrgf/qcnt))*4 - 31 + SCALE_ONE_POS - SCALE_DIV_512);
-        q1 = qnrg + 30;
-        q0 = qnrg - 30;
-        if (q0 < q0low) {
-            q1 += q0low - q0;
-            q0  = q0low;
-        } else if (q1 > q1high) {
-            q0 -= q1 - q1high;
-            q1  = q1high;
-        }
-    }
-    // q0 == q1 isn't really a legal situation
-    if (q0 == q1) {
-        // the following is indirect but guarantees q1 != q0 && q1 near q0
-        q1 = av_clip(q0+1, 1, SCALE_MAX_POS);
-        q0 = av_clip(q1-1, 0, SCALE_MAX_POS - 1);
-    }
-
-    for (i = 0; i < TRELLIS_STATES; i++) {
-        paths[0][i].cost    = 0.0f;
-        paths[0][i].prev    = -1;
-    }
-    for (j = 1; j < TRELLIS_STAGES; j++) {
-        for (i = 0; i < TRELLIS_STATES; i++) {
-            paths[j][i].cost    = INFINITY;
-            paths[j][i].prev    = -2;
-        }
-    }
-    idx = 1;
-    s->aacdsp.abs_pow34(s->scoefs, sce->coeffs, 1024);
-    for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
-        start = w*128;
-        for (g = 0; g < sce->ics.num_swb; g++) {
-            const float *coefs = &sce->coeffs[start];
-            float qmin, qmax;
-            int nz = 0;
-
-            bandaddr[idx] = w * 16 + g;
-            qmin = INT_MAX;
-            qmax = 0.0f;
-            for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
-                FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g];
-                if (band->energy <= band->threshold || band->threshold == 0.0f) {
-                    sce->zeroes[(w+w2)*16+g] = 1;
-                    continue;
-                }
-                sce->zeroes[(w+w2)*16+g] = 0;
-                nz = 1;
-                for (i = 0; i < sce->ics.swb_sizes[g]; i++) {
-                    float t = fabsf(coefs[w2*128+i]);
-                    if (t > 0.0f)
-                        qmin = FFMIN(qmin, t);
-                    qmax = FFMAX(qmax, t);
-                }
-            }
-            if (nz) {
-                int minscale, maxscale;
-                float minrd = INFINITY;
-                float maxval;
-                //minimum scalefactor index is when minimum nonzero coefficient after quantizing is not clipped
-                minscale = coef2minsf(qmin);
-                //maximum scalefactor index is when maximum coefficient after quantizing is still not zero
-                maxscale = coef2maxsf(qmax);
-                minscale = av_clip(minscale - q0, 0, TRELLIS_STATES - 1);
-                maxscale = av_clip(maxscale - q0, 0, TRELLIS_STATES);
-                if (minscale == maxscale) {
-                    maxscale = av_clip(minscale+1, 1, TRELLIS_STATES);
-                    minscale = av_clip(maxscale-1, 0, TRELLIS_STATES - 1);
-                }
-                maxval = find_max_val(sce->ics.group_len[w], sce->ics.swb_sizes[g], s->scoefs+start);
-                for (q = minscale; q < maxscale; q++) {
-                    float dist = 0;
-                    int cb = find_min_book(maxval, sce->sf_idx[w*16+g]);
-                    for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
-                        FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g];
-                        dist += quantize_band_cost(s, coefs + w2*128, s->scoefs + start + w2*128, sce->ics.swb_sizes[g],
-                                                   q + q0, cb, lambda / band->threshold, INFINITY, NULL, NULL);
-                    }
-                    minrd = FFMIN(minrd, dist);
-
-                    for (i = 0; i < q1 - q0; i++) {
-                        float cost;
-                        cost = paths[idx - 1][i].cost + dist
-                               + ff_aac_scalefactor_bits[q - i + SCALE_DIFF_ZERO];
-                        if (cost < paths[idx][q].cost) {
-                            paths[idx][q].cost    = cost;
-                            paths[idx][q].prev    = i;
-                        }
-                    }
-                }
-            } else {
-                for (q = 0; q < q1 - q0; q++) {
-                    paths[idx][q].cost = paths[idx - 1][q].cost + 1;
-                    paths[idx][q].prev = q;
-                }
-            }
-            sce->zeroes[w*16+g] = !nz;
-            start += sce->ics.swb_sizes[g];
-            idx++;
-        }
-    }
-    idx--;
-    mincost = paths[idx][0].cost;
-    minq    = 0;
-    for (i = 1; i < TRELLIS_STATES; i++) {
-        if (paths[idx][i].cost < mincost) {
-            mincost = paths[idx][i].cost;
-            minq = i;
-        }
-    }
-    while (idx) {
-        sce->sf_idx[bandaddr[idx]] = minq + q0;
-        minq = FFMAX(paths[idx][minq].prev, 0);
-        idx--;
-    }
-    //set the same quantizers inside window groups
-    for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w])
-        for (g = 0; g < sce->ics.num_swb; g++)
-            for (w2 = 1; w2 < sce->ics.group_len[w]; w2++)
-                sce->sf_idx[(w+w2)*16+g] = sce->sf_idx[w*16+g];
-}
-
 static void search_for_quantizers_fast(AVCodecContext *avctx, AACEncContext *s,
                                        SingleChannelElement *sce,
                                        const float lambda)
@@ -1115,19 +841,6 @@ static void search_for_ms(AACEncContext *s, ChannelElement *cpe)
 }
 
 const AACCoefficientsEncoder ff_aac_coders[AAC_CODER_NB] = {
-    [AAC_CODER_ANMR] = {
-        search_for_quantizers_anmr,
-        encode_window_bands_info,
-        quantize_and_encode_band,
-        ff_aac_encode_tns_info,
-        ff_aac_apply_tns,
-        set_special_band_scalefactors,
-        search_for_pns,
-        mark_pns,
-        ff_aac_search_for_tns,
-        search_for_ms,
-        ff_aac_search_for_is,
-    },
     [AAC_CODER_TWOLOOP] = {
         search_for_quantizers_twoloop,
         codebook_trellis_rate,
diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c
index 5ed54dbcb3..673bcea5d8 100644
--- a/libavcodec/aacenc.c
+++ b/libavcodec/aacenc.c
@@ -1269,12 +1269,6 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
 
     /* Coder limitations */
     s->coder = &ff_aac_coders[s->options.coder];
-    if (s->options.coder == AAC_CODER_ANMR) {
-        ERROR_IF(avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL,
-                 "The ANMR coder is considered experimental, add -strict -2 to enable!\n");
-        s->options.intensity_stereo = 0;
-        s->options.pns = 0;
-    }
 
     /* M/S introduces horrible artifacts with multichannel files, this is temporary */
     if (s->channels > 3)
@@ -1315,7 +1309,6 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
 #define AACENC_FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM
 static const AVOption aacenc_options[] = {
     {"aac_coder", "Coding algorithm", offsetof(AACEncContext, options.coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_TWOLOOP}, 0, AAC_CODER_NB-1, AACENC_FLAGS, .unit = "coder"},
-        {"anmr",     "ANMR method",               0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_ANMR},    INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "coder"},
         {"twoloop",  "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "coder"},
         {"fast",     "Fast search",               0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST},    INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "coder"},
     {"aac_ms", "Force M/S stereo coding", offsetof(AACEncContext, options.mid_side), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AACENC_FLAGS},
diff --git a/libavcodec/aacenc.h b/libavcodec/aacenc.h
index 360402a06e..241d75025a 100644
--- a/libavcodec/aacenc.h
+++ b/libavcodec/aacenc.h
@@ -42,7 +42,6 @@
 #define CLIP_AVOIDANCE_FACTOR 0.95f
 
 typedef enum AACCoder {
-    AAC_CODER_ANMR = 0,
     AAC_CODER_TWOLOOP,
     AAC_CODER_FAST,
 



More information about the ffmpeg-cvslog mailing list