[PR] WIP: avcodec/ac3enc: add short transform support (PR #24047)

AYOUB NABIL BOUBAGRAT via ffmpeg-devel <[email protected]>
Newsgroups gmane.comp.video.ffmpeg.devel
Message-ID <178613711413.59.10857670543659032250@29965ddac10e>
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]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.