PR #24047 opened by AYOUB NABIL BOUBAGRAT (ayoubnabil)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24047
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24047.patch

i'm starting work on block switching for the AC-3 encoder as part of #23317.
this first commit adds short MDCT support for both the float and fixed-point 
encoders.
i'll add the remaining block switching support in follow-up commits.
this only targets AC-3 for now.



>From 79ba410f0e7b9363e60a3fb47eeb5a5d824cb6bd Mon Sep 17 00:00:00 2001
From: Ayoub Nabil Boubagrat <[email protected]>
Date: Fri, 7 Aug 2026 23:00:00 +0200
Subject: [PATCH] avcodec/ac3enc: add short transform support

Signed-off-by: Ayoub Nabil Boubagrat 
<[email protected]>
---
 libavcodec/ac3enc.c          |  1 +
 libavcodec/ac3enc.h          |  3 ++
 libavcodec/ac3enc_fixed.c    | 10 ++++--
 libavcodec/ac3enc_float.c    | 16 ++++++++--
 libavcodec/ac3enc_template.c | 60 ++++++++++++++++++++++++++++++++++--
 5 files changed, 83 insertions(+), 7 deletions(-)

diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c
index 0482d9ee58..9dcb173784 100644
--- a/libavcodec/ac3enc.c
+++ b/libavcodec/ac3enc.c
@@ -2184,6 +2184,7 @@ av_cold int ff_ac3_encode_close(AVCodecContext *avctx)
 
     ff_af_queue_close(&s->afq);
     av_tx_uninit(&s->tx);
+    av_tx_uninit(&s->tx_short);
 
     return 0;
 }
diff --git a/libavcodec/ac3enc.h b/libavcodec/ac3enc.h
index 3e92af17f0..20d199b800 100644
--- a/libavcodec/ac3enc.h
+++ b/libavcodec/ac3enc.h
@@ -137,6 +137,7 @@ typedef struct AC3Block {
     uint16_t *qmant[AC3_MAX_CHANNELS];          ///< quantized mantissas
     uint8_t  *cpl_coord_exp[AC3_MAX_CHANNELS];  ///< coupling coord exponents  
         (cplcoexp)
     uint8_t  *cpl_coord_mant[AC3_MAX_CHANNELS]; ///< coupling coord mantissas  
         (cplcomant)
+    uint8_t  block_switch[AC3_MAX_CHANNELS];    ///< block switch flags        
         (blksw)
     uint8_t  new_rematrixing_strategy;          ///< send new rematrixing 
flags in this block
     int      num_rematrixing_bands;             ///< number of rematrixing 
bands
     uint8_t  rematrixing_flags[4];              ///< rematrixing flags
@@ -170,6 +171,8 @@ typedef struct AC3EncodeContext {
     AC3DSPContext ac3dsp;                   ///< AC-3 optimized functions
     AVTXContext *tx;                        ///< FFT context for MDCT 
calculation
     av_tx_fn tx_fn;
+    AVTXContext *tx_short;                  ///< FFT context for short MDCT 
calculation
+    av_tx_fn tx_fn_short;
 
     AC3Block blocks[AC3_MAX_BLOCKS];        ///< per-block info
 
diff --git a/libavcodec/ac3enc_fixed.c b/libavcodec/ac3enc_fixed.c
index 876bb6bbc6..c2880f2c43 100644
--- a/libavcodec/ac3enc_fixed.c
+++ b/libavcodec/ac3enc_fixed.c
@@ -79,6 +79,7 @@ static av_cold int ac3_fixed_mdct_init(AVCodecContext *avctx, 
AC3EncodeContext *
     const float scale = -1.0f;
 
     int32_t *iwin = s->mdct_window_fixed;
+    int ret;
 
     ff_kbd_window_init(fwin, 5.0, AC3_BLOCK_SIZE);
     for (int i = 0; i < AC3_BLOCK_SIZE; i++)
@@ -88,8 +89,13 @@ static av_cold int ac3_fixed_mdct_init(AVCodecContext 
*avctx, AC3EncodeContext *
     if (!s->fdsp)
         return AVERROR(ENOMEM);
 
-    return av_tx_init(&s->tx, &s->tx_fn, AV_TX_INT32_MDCT, 0,
-                      AC3_BLOCK_SIZE, &scale, 0);
+    ret = av_tx_init(&s->tx, &s->tx_fn, AV_TX_INT32_MDCT, 0,
+                     AC3_BLOCK_SIZE, &scale, 0);
+    if (ret < 0)
+        return ret;
+
+    return av_tx_init(&s->tx_short, &s->tx_fn_short, AV_TX_INT32_MDCT, 0,
+                      AC3_BLOCK_SIZE / 2, &scale, 0);
 }
 
 
diff --git a/libavcodec/ac3enc_float.c b/libavcodec/ac3enc_float.c
index 974c38ac25..990bfed878 100644
--- a/libavcodec/ac3enc_float.c
+++ b/libavcodec/ac3enc_float.c
@@ -85,12 +85,22 @@ static void sum_square_butterfly(AC3EncodeContext *s, float 
sum[4],
  */
 static av_cold int ac3_float_mdct_init(AC3EncodeContext *s)
 {
-    const float scale = -2.0 / AC3_WINDOW_SIZE;
+    const float scale       = -2.0 / AC3_WINDOW_SIZE;
+    /* A/52 uses -2/N with N=256 for each short transform. */
+    const float short_scale = -4.0 / AC3_WINDOW_SIZE;
+    int ret;
 
     ff_kbd_window_init(s->mdct_window_float, 5.0, AC3_BLOCK_SIZE);
 
-    return av_tx_init(&s->tx, &s->tx_fn, AV_TX_FLOAT_MDCT, 0,
-                      AC3_BLOCK_SIZE, &scale, 0);
+    ret = av_tx_init(&s->tx, &s->tx_fn, AV_TX_FLOAT_MDCT, 0,
+                     AC3_BLOCK_SIZE, &scale, 0);
+    if (ret < 0)
+        return ret;
+    if (s->eac3)
+        return 0;
+
+    return av_tx_init(&s->tx_short, &s->tx_fn_short, AV_TX_FLOAT_MDCT, 0,
+                      AC3_BLOCK_SIZE / 2, &short_scale, 0);
 }
 
 
diff --git a/libavcodec/ac3enc_template.c b/libavcodec/ac3enc_template.c
index 5331b45cb9..d7a0fc1055 100644
--- a/libavcodec/ac3enc_template.c
+++ b/libavcodec/ac3enc_template.c
@@ -44,6 +44,59 @@
 #define RENAME(element) element ## _fixed
 #endif
 
+/*
+ * Apply the two short MDCTs and interleave their coefficients.
+ */
+static void apply_short_mdct(AC3EncodeContext *s, CoefType *coef,
+                             const SampleType *samples)
+{
+    const int quarter        = AC3_BLOCK_SIZE / 4;
+    const int half           = AC3_BLOCK_SIZE / 2;
+    const int three_quarters = 3 * AC3_BLOCK_SIZE / 4;
+    LOCAL_ALIGNED_32(SampleType, input,  [AC3_BLOCK_SIZE]);
+    LOCAL_ALIGNED_32(CoefType,   output, [AC3_MAX_COEFS]);
+
+    /* AVTX implements the alpha=0 MDCT. The alpha=-1 transform in A/52
+     * Section 8.2.3.2 is equivalent to [x[N/4..N-1], -x[0..N/4-1]],
+     * while the alpha=+1 transform starts at the last quarter of the
+     * 2N-sample window. */
+#if AC3ENC_FLOAT
+    memcpy(input, samples + quarter, three_quarters * sizeof(*input));
+    for (int i = 0; i < quarter; i++)
+        input[three_quarters + i] = -samples[i];
+#else
+    /* The fixed MDCT scale cannot exceed one, so apply its factor of two to
+     * the input. FixedDSP scales the product of S32 input and the Q22 window
+     * by 2^-31, limiting the windowed samples to 2^22. Doubling them here
+     * therefore remains within 2^23. */
+    for (int i = 0; i < three_quarters; i++)
+        input[i] = 2 * samples[quarter + i];
+    for (int i = 0; i < quarter; i++)
+        input[three_quarters + i] = -2 * samples[i];
+#endif
+
+    s->tx_fn_short(s->tx_short, output, input, sizeof(*input));
+
+#if AC3ENC_FLOAT
+    for (int i = 0; i < quarter; i++)
+        input[i] = -samples[AC3_WINDOW_SIZE - quarter + i];
+    memcpy(input + quarter, samples + AC3_BLOCK_SIZE,
+           three_quarters * sizeof(*input));
+#else
+    for (int i = 0; i < quarter; i++)
+        input[i] = -2 * samples[AC3_WINDOW_SIZE - quarter + i];
+    for (int i = 0; i < three_quarters; i++)
+        input[quarter + i] = 2 * samples[AC3_BLOCK_SIZE + i];
+#endif
+
+    s->tx_fn_short(s->tx_short, output + half, input, sizeof(*input));
+
+    for (int i = 0; i < half; i++) {
+        coef[2 * i    ] = output[i];
+        coef[2 * i + 1] = output[half + i];
+    }
+}
+
 /*
  * Apply the MDCT to input samples to generate frequency coefficients.
  * This applies the KBD window and normalizes the input to reduce precision
@@ -69,8 +122,11 @@ static void apply_mdct(AC3EncodeContext *s, uint8_t * const 
*samples)
                                          input_samples1,
                                          s->RENAME(mdct_window), 
AC3_BLOCK_SIZE);
 
-            s->tx_fn(s->tx, block->mdct_coef[ch+1],
-                     windowed_samples, sizeof(*windowed_samples));
+            if (block->block_switch[ch + 1])
+                apply_short_mdct(s, block->mdct_coef[ch + 1], 
windowed_samples);
+            else
+                s->tx_fn(s->tx, block->mdct_coef[ch + 1],
+                         windowed_samples, sizeof(*windowed_samples));
             input_samples0  = input_samples1;
             input_samples1 += AC3_BLOCK_SIZE;
         } while (++blk < s->num_blocks);
-- 
2.52.0

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

Reply via email to