[FFmpeg-devel] [PATCH] avcodec/aacenc: add high energy check to exclude unsuitable bands from PNS (PR #20521)

2025-09-14 Thread Agent45 via ffmpeg-devel
PR #20521 opened by Agent45
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20521
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20521.patch

Add a maximum energy check in mark_pns() , adapted from search_for_pns(). 
Extremely high-energy bands should be excluded early from PNS to prevent harsh 
artifacts.  
This resolves issue #20200.


>From b116bf897cb68a076f19304e728d957835d32b2a Mon Sep 17 00:00:00 2001
From: Agent45 
Date: Sun, 14 Sep 2025 21:03:37 +
Subject: [PATCH] avcodec/aacenc: add high energy check to exclude unsuitable
 bands from PNS

Add a maximum energy check in mark_pns() , adapted from search_for_pns().
Extremely high-energy bands should be excluded early from PNS to prevent harsh 
artifacts.
This resolves issue #20200.
---
 libavcodec/aaccoder.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/libavcodec/aaccoder.c b/libavcodec/aaccoder.c
index 7f1c4cdcc1..346338331d 100644
--- a/libavcodec/aaccoder.c
+++ b/libavcodec/aaccoder.c
@@ -636,6 +636,7 @@ static void mark_pns(AACEncContext *s, AVCodecContext 
*avctx, SingleChannelEleme
 int bandwidth, cutoff;
 const float lambda = s->lambda;
 const float freq_mult = avctx->sample_rate*0.5f/wlen;
+const float thr_mult = NOISE_LAMBDA_REPLACE*(100.0f/lambda);
 const float spread_threshold = FFMIN(0.75f, 
NOISE_SPREAD_THRESHOLD*FFMAX(0.5f, lambda/100.f));
 const float pns_transient_energy_r = FFMIN(0.7f, lambda / 140.f);
 
@@ -690,7 +691,10 @@ static void mark_pns(AACEncContext *s, AVCodecContext 
*avctx, SingleChannelEleme
  * 3. on short window groups, all windows have similar energy 
(variations in energy would be destroyed by PNS)
  */
 sce->pns_ener[w*16+g] = sfb_energy;
-if (sfb_energy < threshold*sqrtf(1.5f/freq_boost) || spread < 
spread_threshold || min_energy < pns_transient_energy_r * max_energy) {
+if (sfb_energy < threshold*sqrtf(1.5f/freq_boost) ||
+   sfb_energy > 100.0f * 
threshold*thr_mult*freq_boost ||
+   spread < spread_threshold ||
+   min_energy < pns_transient_energy_r * 
max_energy) {
 sce->can_pns[w*16+g] = 0;
 } else {
 sce->can_pns[w*16+g] = 1;
-- 
2.49.1

___
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]


[FFmpeg-devel] [PATCH] avcodec/aacenc: add bitrate threshold for PNS and improve attack detection (PR #20815)

2025-11-01 Thread Agent45 via ffmpeg-devel
PR #20815 opened by Agent45
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20815
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20815.patch

- Fixes indexing errors in attack detection logic and introduces a state flag 
(next_attack0_zero) to stabilize attack[0] prediction across frames. This 
reduces vertical line artifacts in periodic signals such as trumpet.
- Changes PSY_LAME_NUM_SUBBLOCKS from 3 to 2 to ensure full coverage of all 
1024 MDCT samples, with each subblock containing exactly 64 samples—matching 
LAME’s empirical design. And adjust attack threshold presets. This improves the 
handling of periodic signals, especially under low bitrate conditions.
- Disables PNS when the per-channel bitrate exceeds 64 kbps. This avoids 
unnecessary noise substitution in high-bitrate scenarios where it may degrade 
quality.
This resolves issue #20200.


From 458a942481151ede27478e6ac6d9d2866d438b84 Mon Sep 17 00:00:00 2001
From: Agent45 
Date: Sat, 1 Nov 2025 19:49:05 +
Subject: [PATCH 1/2] avcodec/aacenc: add bitrate threshold for PNS

---
 libavcodec/aaccoder.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/libavcodec/aaccoder.c b/libavcodec/aaccoder.c
index 7f1c4cdcc1..ddebdfd53d 100644
--- a/libavcodec/aaccoder.c
+++ b/libavcodec/aaccoder.c
@@ -58,6 +58,9 @@
  * replace low energy non zero bands */
 #define NOISE_LAMBDA_REPLACE 1.948f
 
+/* Bitrate threshold (in bits/sec/channel) above which PNS is disabled. */
+#define PNS_BITRATE_LIMIT 64000.0f
+
 #include "libavcodec/aaccoder_trellis.h"
 
 typedef float (*quantize_and_encode_band_func)(struct AACEncContext *s, 
PutBitContext *pb,
@@ -513,6 +516,7 @@ static void search_for_pns(AACEncContext *s, AVCodecContext 
*avctx, SingleChanne
 ? (refbits * rate_bandwidth_multiplier * avctx->sample_rate / 1024)
 : (avctx->bit_rate / avctx->ch_layout.nb_channels);
 
+   int pns_at_low_bitrate = frame_bit_rate < PNS_BITRATE_LIMIT;
 frame_bit_rate *= 1.15f;
 
 if (avctx->cutoff > 0) {
@@ -536,7 +540,7 @@ static void search_for_pns(AACEncContext *s, AVCodecContext 
*avctx, SingleChanne
 const int start = wstart+sce->ics.swb_offset[g];
 const float freq = (start-wstart)*freq_mult;
 const float freq_boost = FFMAX(0.88f*freq/NOISE_LOW_LIMIT, 1.0f);
-if (freq < NOISE_LOW_LIMIT || (start-wstart) >= cutoff) {
+if (!pns_at_low_bitrate || freq < NOISE_LOW_LIMIT || 
(start-wstart) >= cutoff) {
 if (!sce->zeroes[w*16+g])
 prev_sf = sce->sf_idx[w*16+g];
 continue;
@@ -649,6 +653,7 @@ static void mark_pns(AACEncContext *s, AVCodecContext 
*avctx, SingleChannelEleme
 ? (refbits * rate_bandwidth_multiplier * avctx->sample_rate / 1024)
 : (avctx->bit_rate / avctx->ch_layout.nb_channels);
 
+   int pns_at_low_bitrate = frame_bit_rate < PNS_BITRATE_LIMIT;
 frame_bit_rate *= 1.15f;
 
 if (avctx->cutoff > 0) {
@@ -667,7 +672,7 @@ static void mark_pns(AACEncContext *s, AVCodecContext 
*avctx, SingleChannelEleme
 const int start = sce->ics.swb_offset[g];
 const float freq = start*freq_mult;
 const float freq_boost = FFMAX(0.88f*freq/NOISE_LOW_LIMIT, 1.0f);
-if (freq < NOISE_LOW_LIMIT || start >= cutoff) {
+if (!pns_at_low_bitrate || freq < NOISE_LOW_LIMIT || start >= 
cutoff) {
 sce->can_pns[w*16+g] = 0;
 continue;
 }
-- 
2.49.1


From 81a985d6a92eb411ba495fb05a3a962d181649ea Mon Sep 17 00:00:00 2001
From: Agent45 
Date: Sat, 1 Nov 2025 20:41:24 +
Subject: [PATCH 2/2] avcodec/aacpsy: fix attack detection logic and subblock
 indexing
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Fix several indexing errors in attack detection logic and refine transient 
handling in the AAC psychoacoustic model.

- Change PSY_LAME_NUM_SUBBLOCKS from 3 to 2 to ensure full coverage of all 1024 
MDCT samples, with each subblock containing exactly 1024 / (8 * 2) = 64 
samples—matching LAME’s empirical design.
- Introduce next_attack0_zero state flag to stabilize attack[0] prediction 
across frames.
- Adjust attack threshold presets.

These changes improve the handling of periodic signals such as trumpet, 
especially under low bitrate conditions.
---
 libavcodec/aacpsy.c | 64 +++--
 1 file changed, 33 insertions(+), 31 deletions(-)

diff --git a/libavcodec/aacpsy.c b/libavcodec/aacpsy.c
index ed03cb68ac..f91ba45a52 100644
--- a/libavcodec/aacpsy.c
+++ b/libavcodec/aacpsy.c
@@ -97,7 +97,7 @@ enum {
 #define AAC_BLOCK_SIZE_LONG 1024///< long block size
 #define AAC_BLOCK_SIZE_SHORT 128///< short block size
 #define AAC_NUM_BLOCKS_SHORT 8  ///< number of blocks in a short sequence
-#define PSY_LAME_NUM_SUBBLOCKS 3///< Number of sub-blocks in each short 
block
+#define PSY_LAME_NUM_SUBBLOCKS 2///< Num