[FFmpeg-devel] [PATCH] aacenc_tns: clamp filter direction energy measurement

Thierry Foucu tfoucu at gmail.com
Mon Jun 30 22:52:00 EEST 2025


On Fri, Feb 7, 2025 at 7:36 PM Lynne <dev at lynne.ee> wrote:

> The issue is that:
>
> float en[2];
> ...
> tns->n_filt[w] = is8 ? 1 : order != TNS_MAX_ORDER ? 2 : 3;
> for (g = 0; g < tns->n_filt[w]; g++) {
>     tns->direction[w][g] = slant != 2 ? slant : en[g] < en[!g];
>
> When using the AAC Main profile, n_filt = 3, and slant is by
> default 2 (normal long frames), g can go above 1.
>
> en is the evolution of energy in the frequency domain for every
> band at the given window. E.g. whether the energy is concentrated
> at the top of each band, or the bottom.
>
> For 2-pole filters, its straightforward.
> For 3-pole filters, we need more than 2 measurements.
>
> This commit properly implements support for 3-pole filters, by measuring
> the band energy across three areas.
>
> Do note that even xHE-AAC caps n_filt to 2, and only AAC Main allows
> n_filt == 3.
>
> Fixes https://trac.ffmpeg.org/ticket/11418
> ---
>  libavcodec/aacenc_tns.c | 33 ++++++++++++++++++++++++---------
>  1 file changed, 24 insertions(+), 9 deletions(-)
>
> diff --git a/libavcodec/aacenc_tns.c b/libavcodec/aacenc_tns.c
> index fa3cd2af39..f9bc033b26 100644
> --- a/libavcodec/aacenc_tns.c
> +++ b/libavcodec/aacenc_tns.c
> @@ -173,6 +173,7 @@ void ff_aac_search_for_tns(AACEncContext *s,
> SingleChannelElement *sce)
>                        sce->ics.window_sequence[0] == LONG_START_SEQUENCE
> ? 0 : 2;
>      const int sfb_len = sfb_end - sfb_start;
>      const int coef_len = sce->ics.swb_offset[sfb_end] -
> sce->ics.swb_offset[sfb_start];
> +    const int n_filt = is8 ? 1 : order != TNS_MAX_ORDER ? 2 : 3;
>
>      if (coef_len <= 0 || sfb_len <= 0) {
>          sce->tns.present = 0;
> @@ -180,16 +181,30 @@ void ff_aac_search_for_tns(AACEncContext *s,
> SingleChannelElement *sce)
>      }
>
>      for (w = 0; w < sce->ics.num_windows; w++) {
> -        float en[2] = {0.0f, 0.0f};
> +        float en[4] = {0.0f, 0.0f, 0.0f, 0.0f};
>          int oc_start = 0;
>          int coef_start = sce->ics.swb_offset[sfb_start];
>
> -        for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end; g++) {
> -            FFPsyBand *band = &s->psy.ch
> [s->cur_channel].psy_bands[w*16+g];
> -            if (g > sfb_start + (sfb_len/2))
> -                en[1] += band->energy;
> -            else
> -                en[0] += band->energy;
> +        if (n_filt == 2) {
> +            for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end;
> g++) {
> +                FFPsyBand *band = &s->psy.ch
> [s->cur_channel].psy_bands[w*16+g];
> +                    if (g > sfb_start + (sfb_len/2))
> +                        en[1] += band->energy; /* End */
> +                    else
> +                        en[0] += band->energy; /* Start */
> +            }
> +            en[2] = en[0];
> +        } else {
> +            for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end;
> g++) {
> +                FFPsyBand *band = &s->psy.ch
> [s->cur_channel].psy_bands[w*16+g];
> +                    if (g > sfb_start + (sfb_len/2) + (sfb_len/4))
> +                        en[2] += band->energy; /* End */
> +                    else if (g > sfb_start + (sfb_len/2) - (sfb_len/4))
> +                        en[1] += band->energy; /* Middle */
> +                    else
> +                        en[0] += band->energy; /* Start */
> +            }
> +            en[3] = en[0];
>          }
>
>          /* LPC */
> @@ -199,9 +214,9 @@ void ff_aac_search_for_tns(AACEncContext *s,
> SingleChannelElement *sce)
>          if (!order || !isfinite(gain) || gain < TNS_GAIN_THRESHOLD_LOW ||
> gain > TNS_GAIN_THRESHOLD_HIGH)
>              continue;
>
> -        tns->n_filt[w] = is8 ? 1 : order != TNS_MAX_ORDER ? 2 : 3;
> +        tns->n_filt[w] = n_filt;
>          for (g = 0; g < tns->n_filt[w]; g++) {
> -            tns->direction[w][g] = slant != 2 ? slant : en[g] < en[!g];
> +            tns->direction[w][g] = slant != 2 ? slant : en[g] < en[g + 1];
>              tns->order[w][g] = order/tns->n_filt[w];
>              tns->length[w][g] = sfb_len/tns->n_filt[w];
>              quantize_coefs(&coefs[oc_start], tns->coef_idx[w][g],
> tns->coef[w][g],
> --
> 2.47.2
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".
>

Any chance to have this patch submitted to close the issue?

thanks.
-- 

Thierry Foucu


More information about the ffmpeg-devel mailing list