From efa54c902f9413eee080dec3ec8cdc480c9ea6ce Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Thu, 10 Apr 2025 21:07:00 +0200
Subject: [PATCH 10/15] avcodec/mpegaudioenc_{fixed,float}: Merge encoders

Most of the encoders is the same. So deduplicate them.
This reduces code size from 22410B to 12637B here.
The data in mpegaudiotab.h is also automatically deduplicated.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/Makefile                           |   4 +-
 ...mpegaudioenc_template.c => mpegaudioenc.c} | 207 +++++++++++-------
 libavcodec/mpegaudioenc_fixed.c               |  39 ----
 libavcodec/mpegaudioenc_float.c               |  40 ----
 4 files changed, 134 insertions(+), 156 deletions(-)
 rename libavcodec/{mpegaudioenc_template.c => mpegaudioenc.c} (84%)
 delete mode 100644 libavcodec/mpegaudioenc_fixed.c
 delete mode 100644 libavcodec/mpegaudioenc_float.c

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 3c3ac640e0..98501f9797 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -529,10 +529,10 @@ OBJS-$(CONFIG_MOVTEXT_ENCODER)         += movtextenc.o ass_split.o
 OBJS-$(CONFIG_MP1_DECODER)             += mpegaudiodec_fixed.o
 OBJS-$(CONFIG_MP1FLOAT_DECODER)        += mpegaudiodec_float.o
 OBJS-$(CONFIG_MP2_DECODER)             += mpegaudiodec_fixed.o
-OBJS-$(CONFIG_MP2_ENCODER)             += mpegaudioenc_float.o mpegaudio.o \
+OBJS-$(CONFIG_MP2_ENCODER)             += mpegaudioenc.o mpegaudio.o \
                                           mpegaudiodata.o mpegaudiodsp_data.o \
                                           mpegaudiotabs.o
-OBJS-$(CONFIG_MP2FIXED_ENCODER)        += mpegaudioenc_fixed.o mpegaudio.o \
+OBJS-$(CONFIG_MP2FIXED_ENCODER)        += mpegaudioenc.o mpegaudio.o \
                                           mpegaudiodata.o mpegaudiodsp_data.o \
                                           mpegaudiotabs.o
 OBJS-$(CONFIG_MP2FLOAT_DECODER)        += mpegaudiodec_float.o
diff --git a/libavcodec/mpegaudioenc_template.c b/libavcodec/mpegaudioenc.c
similarity index 84%
rename from libavcodec/mpegaudioenc_template.c
rename to libavcodec/mpegaudioenc.c
index 12f5c7b9cd..35347d386c 100644
--- a/libavcodec/mpegaudioenc_template.c
+++ b/libavcodec/mpegaudioenc.c
@@ -24,10 +24,14 @@
  * The simplest mpeg audio layer 2 encoder.
  */
 
+#include "config.h"
+#include "config_components.h"
+
 #include "libavutil/avassert.h"
 #include "libavutil/channel_layout.h"
 
 #include "avcodec.h"
+#include "codec_internal.h"
 #include "encode.h"
 #include "put_bits.h"
 
@@ -52,6 +56,7 @@ typedef struct MpegAudioContext {
     int bitrate_index; /* bit rate */
     int freq_index;
     int frame_size; /* frame size, in bits, without padding */
+    int is_fixed;
     /* padding computation */
     int frame_frac, frame_frac_incr, do_padding;
     short samples_buf[MPA_MAX_CHANNELS][SAMPLES_BUF_SIZE]; /* buffer for filter */
@@ -65,15 +70,18 @@ typedef struct MpegAudioContext {
     int16_t filter_bank[512];
     int scale_factor_table[64];
     unsigned char scale_diff_table[128];
-#if USE_FLOATS
-    float scale_factor_inv_table[64];
-#else
-    int8_t scale_factor_shift[64];
-    unsigned short scale_factor_mult[64];
-#endif
+    union {
+        float scale_factor_inv_table[64];
+        struct {
+            int8_t scale_factor_shift[64];
+            unsigned short scale_factor_mult[64];
+        };
+    };
     unsigned short total_quant_bits[17]; /* total number of bits per allocation group */
 } MpegAudioContext;
 
+#define IS_FIXED(s) (CONFIG_MP2_ENCODER && CONFIG_MP2FIXED_ENCODER ? (s)->is_fixed : CONFIG_MP2FIXED_ENCODER)
+
 static av_cold int MPA_encode_init(AVCodecContext *avctx)
 {
     MpegAudioContext *s = avctx->priv_data;
@@ -157,13 +165,13 @@ static av_cold int MPA_encode_init(AVCodecContext *avctx)
         if (v <= 0)
             v = 1;
         s->scale_factor_table[i] = v;
-#if USE_FLOATS
-        s->scale_factor_inv_table[i] = exp2(-(3 - i) / 3.0) / (float)(1 << 20);
-#else
+        if (IS_FIXED(s)) {
 #define P 15
-        s->scale_factor_shift[i] = 21 - P - (i / 3);
-        s->scale_factor_mult[i] = (1 << P) * exp2((i % 3) / 3.0);
-#endif
+            s->scale_factor_shift[i] = 21 - P - (i / 3);
+            s->scale_factor_mult[i]  = (1 << P) * exp2((i % 3) / 3.0);
+        } else {
+            s->scale_factor_inv_table[i] = exp2(-(3 - i) / 3.0) / (float)(1 << 20);
+        }
     }
     for(i=0;i<128;i++) {
         v = i - 64;
@@ -592,6 +600,70 @@ static void compute_bit_allocation(MpegAudioContext *s,
     av_assert0(*padding >= 0);
 }
 
+/// Quantization & write sub band samples
+static av_always_inline void encode_subbands(MpegAudioContext *const s,
+                                             PutBitContext *const p,
+                                             const uint8_t bit_alloc[MPA_MAX_CHANNELS][SBLIMIT],
+                                             int is_fixed)
+{
+    for (int k = 0; k < 3; ++k) {
+        for (int l = 0; l < 12; l += 3) {
+            for (int i = 0, j = 0; i < s->sblimit; ++i) {
+                const int bit_alloc_bits = s->alloc_table[j];
+                for (int ch = 0; ch < s->nb_channels; ++ch) {
+                    const int b = bit_alloc[ch][i];
+                    if (b) {
+                        /* we encode 3 sub band samples of the same sub band at a time */
+                        const int qindex = s->alloc_table[j + b];
+                        const int steps  = ff_mpa_quant_steps[qindex];
+                        int q[3];
+
+                        for (int m = 0; m < 3; ++m) {
+                            const int sample = s->sb_samples[ch][k][l + m][i];
+                            /* divide by scale factor */
+                            if (!is_fixed) {
+                                float a = (float)sample * s->scale_factor_inv_table[s->scale_factors[ch][i][k]];
+                                q[m] = (int)((a + 1.0) * steps * 0.5);
+                            } else {
+                                const int e     = s->scale_factors[ch][i][k];
+                                const int shift = s->scale_factor_shift[e];
+                                const int mult  = s->scale_factor_mult[e];
+                                int q1;
+
+                                /* normalize to P bits */
+                                if (shift < 0)
+                                    q1 = sample * (1 << -shift);
+                                else
+                                    q1 = sample >> shift;
+                                q1 = (q1 * mult) >> P;
+                                q1 += 1 << P;
+                                if (q1 < 0)
+                                    q1 = 0;
+                                q[m] = (q1 * (unsigned)steps) >> (P + 1);
+                            }
+                            if (q[m] >= steps)
+                                q[m] = steps - 1;
+                            av_assert2(q[m] >= 0 && q[m] < steps);
+                        }
+                        const int bits = ff_mpa_quant_bits[qindex];
+                        if (bits < 0) {
+                            /* group the 3 values to save bits */
+                            put_bits(p, -bits,
+                                     q[0] + steps * (q[1] + steps * q[2]));
+                        } else {
+                            put_bits(p, bits, q[0]);
+                            put_bits(p, bits, q[1]);
+                            put_bits(p, bits, q[2]);
+                        }
+                    }
+                }
+                /* next subband in alloc table */
+                j += 1 << bit_alloc_bits;
+            }
+        }
+    }
+}
+
 /*
  * Output the MPEG audio layer 2 frame. Note how the code is small
  * compared to other encoders :-)
@@ -600,9 +672,8 @@ static void encode_frame(MpegAudioContext *s,
                          unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT],
                          int padding)
 {
-    int i, j, k, l, bit_alloc_bits, b, ch;
+    int i, j, bit_alloc_bits, ch;
     unsigned char *sf;
-    int q[3];
     PutBitContext *p = &s->pb;
 
     /* header */
@@ -663,69 +734,14 @@ static void encode_frame(MpegAudioContext *s,
         }
     }
 
-    /* quantization & write sub band samples */
-
-    for(k=0;k<3;k++) {
-        for(l=0;l<12;l+=3) {
-            j = 0;
-            for(i=0;i<s->sblimit;i++) {
-                bit_alloc_bits = s->alloc_table[j];
-                for(ch=0;ch<s->nb_channels;ch++) {
-                    b = bit_alloc[ch][i];
-                    if (b) {
-                        int qindex, steps, m, sample, bits;
-                        /* we encode 3 sub band samples of the same sub band at a time */
-                        qindex = s->alloc_table[j+b];
-                        steps = ff_mpa_quant_steps[qindex];
-                        for(m=0;m<3;m++) {
-                            sample = s->sb_samples[ch][k][l + m][i];
-                            /* divide by scale factor */
-#if USE_FLOATS
-                            {
-                                float a;
-                                a = (float)sample * s->scale_factor_inv_table[s->scale_factors[ch][i][k]];
-                                q[m] = (int)((a + 1.0) * steps * 0.5);
-                            }
+#if CONFIG_SMALL
+    encode_subbands(s, p, bit_alloc, IS_FIXED(s));
 #else
-                            {
-                                int q1, e, shift, mult;
-                                e = s->scale_factors[ch][i][k];
-                                shift = s->scale_factor_shift[e];
-                                mult = s->scale_factor_mult[e];
-
-                                /* normalize to P bits */
-                                if (shift < 0)
-                                    q1 = sample * (1 << -shift);
-                                else
-                                    q1 = sample >> shift;
-                                q1 = (q1 * mult) >> P;
-                                q1 += 1 << P;
-                                if (q1 < 0)
-                                    q1 = 0;
-                                q[m] = (q1 * (unsigned)steps) >> (P + 1);
-                            }
+    if (IS_FIXED(s))
+        encode_subbands(s, p, bit_alloc, 1);
+    else
+        encode_subbands(s, p, bit_alloc, 0);
 #endif
-                            if (q[m] >= steps)
-                                q[m] = steps - 1;
-                            av_assert2(q[m] >= 0 && q[m] < steps);
-                        }
-                        bits = ff_mpa_quant_bits[qindex];
-                        if (bits < 0) {
-                            /* group the 3 values to save bits */
-                            put_bits(p, -bits,
-                                     q[0] + steps * (q[1] + steps * q[2]));
-                        } else {
-                            put_bits(p, bits, q[0]);
-                            put_bits(p, bits, q[1]);
-                            put_bits(p, bits, q[2]);
-                        }
-                    }
-                }
-                /* next subband in alloc table */
-                j += 1 << bit_alloc_bits;
-            }
-        }
-    }
 
     /* padding */
     for(i=0;i<padding;i++)
@@ -777,3 +793,44 @@ static const FFCodecDefault mp2_defaults[] = {
     { NULL },
 };
 
+#if CONFIG_MP2_ENCODER
+const FFCodec ff_mp2_encoder = {
+    .p.name                = "mp2",
+    CODEC_LONG_NAME("MP2 (MPEG audio layer 2)"),
+    .p.type                = AVMEDIA_TYPE_AUDIO,
+    .p.id                  = AV_CODEC_ID_MP2,
+    .p.capabilities        = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
+    .priv_data_size        = sizeof(MpegAudioContext),
+    .init                  = MPA_encode_init,
+    FF_CODEC_ENCODE_CB(MPA_encode_frame),
+    CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16),
+    CODEC_SAMPLERATES(44100, 48000, 32000, 22050, 24000, 16000),
+    CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO),
+    .defaults              = mp2_defaults,
+};
+#endif
+
+#if CONFIG_MP2FIXED_ENCODER
+static av_cold int mpa_fixed_encode_init(AVCodecContext *avctx)
+{
+    MpegAudioContext *s = avctx->priv_data;
+
+    s->is_fixed = 1;
+    return MPA_encode_init(avctx);
+}
+
+const FFCodec ff_mp2fixed_encoder = {
+    .p.name                = "mp2fixed",
+    CODEC_LONG_NAME("MP2 fixed point (MPEG audio layer 2)"),
+    .p.type                = AVMEDIA_TYPE_AUDIO,
+    .p.id                  = AV_CODEC_ID_MP2,
+    .p.capabilities        = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
+    .priv_data_size        = sizeof(MpegAudioContext),
+    .init                  = mpa_fixed_encode_init,
+    FF_CODEC_ENCODE_CB(MPA_encode_frame),
+    CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16),
+    CODEC_SAMPLERATES(44100, 48000, 32000, 22050, 24000, 16000),
+    CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO),
+    .defaults              = mp2_defaults,
+};
+#endif
diff --git a/libavcodec/mpegaudioenc_fixed.c b/libavcodec/mpegaudioenc_fixed.c
deleted file mode 100644
index a9faa7e059..0000000000
--- a/libavcodec/mpegaudioenc_fixed.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * The simplest mpeg audio layer 2 encoder
- * Copyright (c) 2000, 2001 Fabrice Bellard
- *
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "libavutil/channel_layout.h"
-#include "codec_internal.h"
-#include "mpegaudioenc_template.c"
-
-const FFCodec ff_mp2fixed_encoder = {
-    .p.name                = "mp2fixed",
-    CODEC_LONG_NAME("MP2 fixed point (MPEG audio layer 2)"),
-    .p.type                = AVMEDIA_TYPE_AUDIO,
-    .p.id                  = AV_CODEC_ID_MP2,
-    .p.capabilities        = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
-    .priv_data_size        = sizeof(MpegAudioContext),
-    .init                  = MPA_encode_init,
-    FF_CODEC_ENCODE_CB(MPA_encode_frame),
-    CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16),
-    CODEC_SAMPLERATES(44100, 48000, 32000, 22050, 24000, 16000),
-    CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO),
-    .defaults              = mp2_defaults,
-};
diff --git a/libavcodec/mpegaudioenc_float.c b/libavcodec/mpegaudioenc_float.c
deleted file mode 100644
index 5ff67960b5..0000000000
--- a/libavcodec/mpegaudioenc_float.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * The simplest mpeg audio layer 2 encoder
- * Copyright (c) 2000, 2001 Fabrice Bellard
- *
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "libavutil/channel_layout.h"
-#define USE_FLOATS 1
-#include "codec_internal.h"
-#include "mpegaudioenc_template.c"
-
-const FFCodec ff_mp2_encoder = {
-    .p.name                = "mp2",
-    CODEC_LONG_NAME("MP2 (MPEG audio layer 2)"),
-    .p.type                = AVMEDIA_TYPE_AUDIO,
-    .p.id                  = AV_CODEC_ID_MP2,
-    .p.capabilities        = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
-    .priv_data_size        = sizeof(MpegAudioContext),
-    .init                  = MPA_encode_init,
-    FF_CODEC_ENCODE_CB(MPA_encode_frame),
-    CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16),
-    CODEC_SAMPLERATES(44100, 48000, 32000, 22050, 24000, 16000),
-    CODEC_CH_LAYOUTS(AV_CHANNEL_LAYOUT_MONO, AV_CHANNEL_LAYOUT_STEREO),
-    .defaults              = mp2_defaults,
-};
-- 
2.45.2