PR #22616 opened by mkver
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22616
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22616.patch


>From a0dd5e1a08c730acd4429a02c3d9135cad87126a Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 23 Mar 2026 11:47:32 +0100
Subject: [PATCH 01/12] avcodec/sbcdec: Remove AVClass* from context

This decoder has no private class.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/sbcdec.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libavcodec/sbcdec.c b/libavcodec/sbcdec.c
index d999cefd22..e7ddef7699 100644
--- a/libavcodec/sbcdec.c
+++ b/libavcodec/sbcdec.c
@@ -45,7 +45,6 @@ struct sbc_decoder_state {
 };
 
 typedef struct SBCDecContext {
-    AVClass *class;
     DECLARE_ALIGNED(SBC_ALIGN, struct sbc_frame, frame);
     DECLARE_ALIGNED(SBC_ALIGN, struct sbc_decoder_state, dsp);
 } SBCDecContext;
-- 
2.52.0


>From b0d5574195bacc81acfc460670cfadf80a462ce3 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 23 Mar 2026 12:01:41 +0100
Subject: [PATCH 02/12] avcodec/sbc: Use union to save space

One buffer is encoder-only, the other decoder-only.
Also move crc_ctx before the buffers (into padding).

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/sbc.h | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/libavcodec/sbc.h b/libavcodec/sbc.h
index 0a54f1fbbc..e0105f7338 100644
--- a/libavcodec/sbc.h
+++ b/libavcodec/sbc.h
@@ -102,16 +102,18 @@ struct sbc_frame {
     /* bit number x set means joint stereo has been used in subband x */
     uint8_t joint;
 
+    const AVCRC *crc_ctx;
+
     /* only the lower 4 bits of every element are to be used */
     DECLARE_ALIGNED(SBC_ALIGN, uint32_t, scale_factor)[2][8];
 
-    /* raw integer subband samples in the frame */
-    DECLARE_ALIGNED(SBC_ALIGN, int32_t, sb_sample_f)[16][2][8];
+    union {
+        /* raw integer subband samples in the frame - encoder only */
+        DECLARE_ALIGNED(SBC_ALIGN, int32_t, sb_sample_f)[16][2][8];
 
-    /* modified subband samples */
-    DECLARE_ALIGNED(SBC_ALIGN, int32_t, sb_sample)[16][2][8];
-
-    const AVCRC *crc_ctx;
+        /* modified subband samples - decoder only */
+        DECLARE_ALIGNED(SBC_ALIGN, int32_t, sb_sample)[16][2][8];
+    };
 };
 
 uint8_t ff_sbc_crc8(const AVCRC *crc_ctx, const uint8_t *data, size_t len);
-- 
2.52.0


>From c7b016b365ab8dbadca824a10b33d5352b91834e Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 23 Mar 2026 20:52:31 +0100
Subject: [PATCH 03/12] avcodec/x86/sbcdsp: Fix calculating four-subbands
 stereo scalefactors

sbc_calc_scalefactors uses an int32_t [16/*max blocks*/][2/*max
channels*/][8/*max subbands*/] array. The MMX version of this code
treats the two inner arrays as one [2*8] array to process
and it processes subbands*channels of them. But when subbands
is < 8 and channels is two, the entries to process are not
contiguous: One has to process 0..subbands-1 and 8..7+subbands,
yet the code processed 0..2*subbands-1.
This commit fixes this by processing entries 0..7+subbands
if there are two channels.

Before this commit, the following command line triggered an
av_assert2() in put_bits():
ffmpeg_g -i tests/data/asynth-44100-2.wav -c sbc -b:a 200k \
-sbc_delay 0.003 -f null -

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/x86/sbcdsp.asm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/x86/sbcdsp.asm b/libavcodec/x86/sbcdsp.asm
index d68d3a9ae8..d46141b40c 100644
--- a/libavcodec/x86/sbcdsp.asm
+++ b/libavcodec/x86/sbcdsp.asm
@@ -126,7 +126,7 @@ cglobal sbc_calc_scalefactors, 5, 7, 4, sb_sample_f, 
scale_factor, blocks, chann
     shl           subbandsd, 2
     cmp           channelsd, 2
     jl            .loop_1
-    shl           subbandsd, 1
+    add           subbandsd, 32
 
 .loop_1:
     sub           subbandsq, 8
-- 
2.52.0


>From e963d620565e6d72f99f91e3f99185dd75b07c5a Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 23 Mar 2026 14:36:55 +0100
Subject: [PATCH 04/12] tests/fate: Add SBC tests

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 tests/Makefile                                |  1 +
 tests/fate/sbc.mak                            | 38 +++++++++++++++++++
 tests/ref/fate/sbc-16000-1                    |  4 ++
 tests/ref/fate/sbc-44100-1                    |  4 ++
 tests/ref/fate/sbc-44100-2-joint-stereo       |  4 ++
 .../sbc-44100-2-joint-stereo-four-subbands    |  4 ++
 tests/ref/fate/sbc-44100-2-stereo             |  4 ++
 tests/ref/fate/sbc-44100-2-stereo-low-delay   |  4 ++
 tests/ref/fate/sbc-48000-1                    |  4 ++
 9 files changed, 67 insertions(+)
 create mode 100644 tests/fate/sbc.mak
 create mode 100644 tests/ref/fate/sbc-16000-1
 create mode 100644 tests/ref/fate/sbc-44100-1
 create mode 100644 tests/ref/fate/sbc-44100-2-joint-stereo
 create mode 100644 tests/ref/fate/sbc-44100-2-joint-stereo-four-subbands
 create mode 100644 tests/ref/fate/sbc-44100-2-stereo
 create mode 100644 tests/ref/fate/sbc-44100-2-stereo-low-delay
 create mode 100644 tests/ref/fate/sbc-48000-1

diff --git a/tests/Makefile b/tests/Makefile
index 4b3fa6a54a..3e119979d1 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -240,6 +240,7 @@ include $(SRC_PATH)/tests/fate/qoa.mak
 include $(SRC_PATH)/tests/fate/qt.mak
 include $(SRC_PATH)/tests/fate/qtrle.mak
 include $(SRC_PATH)/tests/fate/real.mak
+include $(SRC_PATH)/tests/fate/sbc.mak
 include $(SRC_PATH)/tests/fate/screen.mak
 include $(SRC_PATH)/tests/fate/segafilm.mak
 include $(SRC_PATH)/tests/fate/segment.mak
diff --git a/tests/fate/sbc.mak b/tests/fate/sbc.mak
new file mode 100644
index 0000000000..43d52140eb
--- /dev/null
+++ b/tests/fate/sbc.mak
@@ -0,0 +1,38 @@
+FATE_SBC_TRANSCODE-$(call ENCDEC2, SBC, PCM_S16LE, SBC, SBC_PARSER 
ARESAMPLE_FILTER WAV_DEMUXER WAV_MUXER) += \
+    $(addprefix fate-sbc-, 16000-1 44100-1 48000-1 44100-2-joint-stereo 
44100-2-stereo-low-delay 44100-2-stereo 44100-2-joint-stereo-four-subbands)
+fate-sbc-16000-1: tests/data/asynth-16000-1.wav
+fate-sbc-16000-1: CMD = enc_dec wav 
$(TARGET_PATH)/tests/data/asynth-16000-1.wav \
+        sbc "-c sbc -profile msbc" wav
+fate-sbc-16000-1: CMP_SHIFT=-146  # 73 samples
+
+fate-sbc-48000-1: tests/data/asynth-48000-1.wav
+fate-sbc-48000-1: CMD = enc_dec wav 
$(TARGET_PATH)/tests/data/asynth-48000-1.wav \
+        sbc "-c sbc -sbc_delay 0.001 -b:a 500k" wav
+fate-sbc-48000-1: CMP_SHIFT=-74 # 37 samples
+
+fate-sbc-44100-1: tests/data/asynth-44100-1.wav
+fate-sbc-44100-1: CMD = enc_dec wav 
$(TARGET_PATH)/tests/data/asynth-44100-1.wav \
+        sbc "-c sbc -b:a 250k" wav
+fate-sbc-44100-1: CMP_SHIFT=-146 # 73 samples
+
+$(filter fate-sbc-44100-2%,$(FATE_SBC_TRANSCODE-yes)): 
tests/data/asynth-44100-2.wav
+fate-sbc-44100-2-joint-stereo: CMD = enc_dec wav 
$(TARGET_PATH)/tests/data/asynth-44100-2.wav \
+        sbc "-c sbc -b:a 50k" wav
+fate-sbc-44100-2-joint-stereo: CMP_SHIFT=-292 # 73 samples
+
+fate-sbc-44100-2-joint-stereo-four-subbands: CMD = enc_dec wav 
$(TARGET_PATH)/tests/data/asynth-44100-2.wav \
+        sbc "-c sbc -b:a 450k" wav
+fate-sbc-44100-2-joint-stereo-four-subbands: CMP_SHIFT=-148 # 37 samples
+
+fate-sbc-44100-2-stereo-low-delay: CMD = enc_dec wav 
$(TARGET_PATH)/tests/data/asynth-44100-2.wav \
+        sbc "-c sbc -b:a 200k -sbc_delay 0.003" wav
+fate-sbc-44100-2-stereo-low-delay: CMP_SHIFT=-148 # 37 samples
+
+fate-sbc-44100-2-stereo: CMD = enc_dec wav 
$(TARGET_PATH)/tests/data/asynth-44100-2.wav \
+        sbc "-c sbc -b:a 200k" wav
+fate-sbc-44100-2-stereo: CMP_SHIFT=-292 # 73 samples
+
+FATE_SBC += $(FATE_SBC_TRANSCODE-yes)
+
+FATE_FFMPEG += $(FATE_SBC)
+fate-sbc: $(FATE_SBC)
diff --git a/tests/ref/fate/sbc-16000-1 b/tests/ref/fate/sbc-16000-1
new file mode 100644
index 0000000000..18d38c121a
--- /dev/null
+++ b/tests/ref/fate/sbc-16000-1
@@ -0,0 +1,4 @@
+831fd5ac5a06b75c7c28f7df8ae01843 *tests/data/fate/sbc-16000-1.sbc
+96000 tests/data/fate/sbc-16000-1.sbc
+572c6755da143f4e20ddf2036956fc7e *tests/data/fate/sbc-16000-1.out.wav
+stddev:   60.09 PSNR: 60.75 MAXDIFF:  732 bytes:   192000/   191854
diff --git a/tests/ref/fate/sbc-44100-1 b/tests/ref/fate/sbc-44100-1
new file mode 100644
index 0000000000..1f3baefa01
--- /dev/null
+++ b/tests/ref/fate/sbc-44100-1
@@ -0,0 +1,4 @@
+c29a6bf35c30734bbbd21082a6eb6a3e *tests/data/fate/sbc-44100-1.sbc
+186030 tests/data/fate/sbc-44100-1.sbc
+d3bcdaa019b88acd49f6bc93c9acdbfd *tests/data/fate/sbc-44100-1.out.wav
+stddev:  451.02 PSNR: 43.25 MAXDIFF: 5671 bytes:   529200/   529006
diff --git a/tests/ref/fate/sbc-44100-2-joint-stereo 
b/tests/ref/fate/sbc-44100-2-joint-stereo
new file mode 100644
index 0000000000..cb1add83f8
--- /dev/null
+++ b/tests/ref/fate/sbc-44100-2-joint-stereo
@@ -0,0 +1,4 @@
+a2b56cb77f3e750e64d04181e9efe5a4 *tests/data/fate/sbc-44100-2-joint-stereo.sbc
+39273 tests/data/fate/sbc-44100-2-joint-stereo.sbc
+2765842ff3325b58847bc7a6a709ff41 
*tests/data/fate/sbc-44100-2-joint-stereo.out.wav
+stddev: 5984.93 PSNR: 20.79 MAXDIFF:52173 bytes:  1058400/  1058012
diff --git a/tests/ref/fate/sbc-44100-2-joint-stereo-four-subbands 
b/tests/ref/fate/sbc-44100-2-joint-stereo-four-subbands
new file mode 100644
index 0000000000..21384a0c00
--- /dev/null
+++ b/tests/ref/fate/sbc-44100-2-joint-stereo-four-subbands
@@ -0,0 +1,4 @@
+908244c0a8d086e5f32b3d77ce58e4a4 
*tests/data/fate/sbc-44100-2-joint-stereo-four-subbands.sbc
+343122 tests/data/fate/sbc-44100-2-joint-stereo-four-subbands.sbc
+9db2f8e52608851867d0e0cf77b1dff2 
*tests/data/fate/sbc-44100-2-joint-stereo-four-subbands.out.wav
+stddev:   76.69 PSNR: 58.63 MAXDIFF: 1609 bytes:  1058400/  1058156
diff --git a/tests/ref/fate/sbc-44100-2-stereo 
b/tests/ref/fate/sbc-44100-2-stereo
new file mode 100644
index 0000000000..805bdc9603
--- /dev/null
+++ b/tests/ref/fate/sbc-44100-2-stereo
@@ -0,0 +1,4 @@
+78ff642215025d3639f499664e2233b1 *tests/data/fate/sbc-44100-2-stereo.sbc
+148824 tests/data/fate/sbc-44100-2-stereo.sbc
+ad2855b10cd2b9f4a4c5dde459e7bb74 *tests/data/fate/sbc-44100-2-stereo.out.wav
+stddev: 3515.64 PSNR: 25.41 MAXDIFF:49771 bytes:  1058400/  1058012
diff --git a/tests/ref/fate/sbc-44100-2-stereo-low-delay 
b/tests/ref/fate/sbc-44100-2-stereo-low-delay
new file mode 100644
index 0000000000..748bad98b8
--- /dev/null
+++ b/tests/ref/fate/sbc-44100-2-stereo-low-delay
@@ -0,0 +1,4 @@
+b2517da4b139e19f92c9a5791f0192e6 
*tests/data/fate/sbc-44100-2-stereo-low-delay.sbc
+148824 tests/data/fate/sbc-44100-2-stereo-low-delay.sbc
+69348f4124256eb1bc47581aab5fa23c 
*tests/data/fate/sbc-44100-2-stereo-low-delay.out.wav
+stddev: 3767.42 PSNR: 24.81 MAXDIFF:49898 bytes:  1058400/  1058156
diff --git a/tests/ref/fate/sbc-48000-1 b/tests/ref/fate/sbc-48000-1
new file mode 100644
index 0000000000..ed2d7abb15
--- /dev/null
+++ b/tests/ref/fate/sbc-48000-1
@@ -0,0 +1,4 @@
+fdfb37d00c4630f858b40524c2da7919 *tests/data/fate/sbc-48000-1.sbc
+378000 tests/data/fate/sbc-48000-1.sbc
+b729801f40be56c3c1b6d6130554079b *tests/data/fate/sbc-48000-1.out.wav
+stddev:   48.83 PSNR: 62.56 MAXDIFF:  764 bytes:   576000/   575926
-- 
2.52.0


>From 209772a0860fb4e59cb39496a81090d50c354ae2 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Mon, 23 Mar 2026 19:14:34 +0100
Subject: [PATCH 05/12] avcodec/sbcdsp: Constify

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/arm/sbcdsp_init_arm.c |  2 +-
 libavcodec/sbcdsp.c              | 16 ++++++++--------
 libavcodec/sbcdsp.h              |  6 +++---
 libavcodec/x86/sbcdsp.asm        |  2 +-
 libavcodec/x86/sbcdsp_init.c     |  2 +-
 5 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/libavcodec/arm/sbcdsp_init_arm.c b/libavcodec/arm/sbcdsp_init_arm.c
index b3a2c3d083..9463c75c2c 100644
--- a/libavcodec/arm/sbcdsp_init_arm.c
+++ b/libavcodec/arm/sbcdsp_init_arm.c
@@ -40,7 +40,7 @@ void ff_sbc_analyze_8_armv6(const int16_t *in, int32_t *out, 
const int16_t *cons
 
 void ff_sbc_analyze_4_neon(const int16_t *in, int32_t *out, const int16_t 
*consts);
 void ff_sbc_analyze_8_neon(const int16_t *in, int32_t *out, const int16_t 
*consts);
-void ff_sbc_calc_scalefactors_neon(int32_t sb_sample_f[16][2][8],
+void ff_sbc_calc_scalefactors_neon(const int32_t sb_sample_f[16][2][8],
                                    uint32_t scale_factor[2][8],
                                    int blocks, int channels, int subbands);
 int ff_sbc_calc_scalefactors_j_neon(int32_t sb_sample_f[16][2][8],
diff --git a/libavcodec/sbcdsp.c b/libavcodec/sbcdsp.c
index 5674bdc4a7..7c298c1d15 100644
--- a/libavcodec/sbcdsp.c
+++ b/libavcodec/sbcdsp.c
@@ -103,8 +103,8 @@ static void sbc_analyze_8_simd(const int16_t *in, int32_t 
*out,
     sbc_analyze_simd(in, out, consts, 8);
 }
 
-static inline void sbc_analyze_4b_4s_simd(SBCDSPContext *s,
-                                          int16_t *x, int32_t *out, int 
out_stride)
+static inline void sbc_analyze_4b_4s_simd(SBCDSPContext *s, const int16_t *x,
+                                          int32_t *out, int out_stride)
 {
     /* Analyze blocks */
     s->sbc_analyze_4(x + 12, out, sbcdsp_analysis_consts_fixed4_simd_odd);
@@ -116,8 +116,8 @@ static inline void sbc_analyze_4b_4s_simd(SBCDSPContext *s,
     s->sbc_analyze_4(x + 0, out, sbcdsp_analysis_consts_fixed4_simd_even);
 }
 
-static inline void sbc_analyze_4b_8s_simd(SBCDSPContext *s,
-                                          int16_t *x, int32_t *out, int 
out_stride)
+static inline void sbc_analyze_4b_8s_simd(SBCDSPContext *s, const int16_t *x,
+                                          int32_t *out, int out_stride)
 {
     /* Analyze blocks */
     s->sbc_analyze_8(x + 24, out, sbcdsp_analysis_consts_fixed8_simd_odd);
@@ -130,11 +130,11 @@ static inline void sbc_analyze_4b_8s_simd(SBCDSPContext 
*s,
 }
 
 static inline void sbc_analyze_1b_8s_simd_even(SBCDSPContext *s,
-                                               int16_t *x, int32_t *out,
+                                               const int16_t *x, int32_t *out,
                                                int out_stride);
 
 static inline void sbc_analyze_1b_8s_simd_odd(SBCDSPContext *s,
-                                              int16_t *x, int32_t *out,
+                                              const int16_t *x, int32_t *out,
                                               int out_stride)
 {
     s->sbc_analyze_8(x, out, sbcdsp_analysis_consts_fixed8_simd_odd);
@@ -142,7 +142,7 @@ static inline void sbc_analyze_1b_8s_simd_odd(SBCDSPContext 
*s,
 }
 
 static inline void sbc_analyze_1b_8s_simd_even(SBCDSPContext *s,
-                                               int16_t *x, int32_t *out,
+                                               const int16_t *x, int32_t *out,
                                                int out_stride)
 {
     s->sbc_analyze_8(x, out, sbcdsp_analysis_consts_fixed8_simd_even);
@@ -267,7 +267,7 @@ static int sbc_enc_process_input_8s(int position, const 
uint8_t *pcm,
     return position;
 }
 
-static void sbc_calc_scalefactors(int32_t sb_sample_f[16][2][8],
+static void sbc_calc_scalefactors(const int32_t sb_sample_f[16][2][8],
                                   uint32_t scale_factor[2][8],
                                   int blocks, int channels, int subbands)
 {
diff --git a/libavcodec/sbcdsp.h b/libavcodec/sbcdsp.h
index 20266bf25e..828ff852d1 100644
--- a/libavcodec/sbcdsp.h
+++ b/libavcodec/sbcdsp.h
@@ -53,11 +53,11 @@ struct sbc_dsp_context {
     /* Polyphase analysis filter for 4 subbands configuration,
      * it handles "increment" blocks at once */
     void (*sbc_analyze_4s)(SBCDSPContext *s,
-                           int16_t *x, int32_t *out, int out_stride);
+                           const int16_t *x, int32_t *out, int out_stride);
     /* Polyphase analysis filter for 8 subbands configuration,
      * it handles "increment" blocks at once */
     void (*sbc_analyze_8s)(SBCDSPContext *s,
-                           int16_t *x, int32_t *out, int out_stride);
+                           const int16_t *x, int32_t *out, int out_stride);
     /* Process input data (deinterleave, endian conversion, reordering),
      * depending on the number of subbands and input data byte order */
     int (*sbc_enc_process_input_4s)(int position, const uint8_t *pcm,
@@ -67,7 +67,7 @@ struct sbc_dsp_context {
                                     int16_t X[2][SBC_X_BUFFER_SIZE],
                                     int nsamples, int nchannels);
     /* Scale factors calculation */
-    void (*sbc_calc_scalefactors)(int32_t sb_sample_f[16][2][8],
+    void (*sbc_calc_scalefactors)(const int32_t sb_sample_f[16][2][8],
                                   uint32_t scale_factor[2][8],
                                   int blocks, int channels, int subbands);
     /* Scale factors calculation with joint stereo support */
diff --git a/libavcodec/x86/sbcdsp.asm b/libavcodec/x86/sbcdsp.asm
index d46141b40c..ddc1237d8f 100644
--- a/libavcodec/x86/sbcdsp.asm
+++ b/libavcodec/x86/sbcdsp.asm
@@ -115,7 +115,7 @@ cglobal sbc_analyze_8, 3, 3, 4, in, out, consts
 
 
 ;*******************************************************************
-;void ff_sbc_calc_scalefactors(int32_t sb_sample_f[16][2][8],
+;void ff_sbc_calc_scalefactors(const int32_t sb_sample_f[16][2][8],
 ;                              uint32_t scale_factor[2][8],
 ;                              int blocks, int channels, int subbands)
 ;*******************************************************************
diff --git a/libavcodec/x86/sbcdsp_init.c b/libavcodec/x86/sbcdsp_init.c
index 7416a86ac6..d959f76f8c 100644
--- a/libavcodec/x86/sbcdsp_init.c
+++ b/libavcodec/x86/sbcdsp_init.c
@@ -36,7 +36,7 @@
 
 void ff_sbc_analyze_4_mmx(const int16_t *in, int32_t *out, const int16_t 
*consts);
 void ff_sbc_analyze_8_mmx(const int16_t *in, int32_t *out, const int16_t 
*consts);
-void ff_sbc_calc_scalefactors_mmx(int32_t sb_sample_f[16][2][8],
+void ff_sbc_calc_scalefactors_mmx(const int32_t sb_sample_f[16][2][8],
                                   uint32_t scale_factor[2][8],
                                   int blocks, int channels, int subbands);
 
-- 
2.52.0


>From 7d969b3aab5a39a9184dc31103019948963242a8 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Tue, 24 Mar 2026 11:29:37 +0100
Subject: [PATCH 06/12] avcodec/sbcenc: Don't output uninitialized data

Check in init whether the parameters are valid.
This can be triggered with
ffmpeg -i tests/data/asynth-44100-2.wav -c sbc -sbc_delay 0.001 \
-b:a 100k -f null -

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/sbcenc.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/libavcodec/sbcenc.c b/libavcodec/sbcenc.c
index fb810c4c52..8534dc83ce 100644
--- a/libavcodec/sbcenc.c
+++ b/libavcodec/sbcenc.c
@@ -128,10 +128,6 @@ static size_t sbc_pack_frame(AVPacket *avpkt, struct 
sbc_frame *frame,
         avpkt->data[1] |= ((frame->subbands == 8)     & 0x01) << 0;
 
         avpkt->data[2] = frame->bitpool;
-
-        if (frame->bitpool > frame->subbands << (4 + (frame->mode == STEREO
-                                                   || frame->mode == 
JOINT_STEREO)))
-            return -5;
     }
 
     /* Can't fill in crc yet */
@@ -259,6 +255,12 @@ static av_cold int sbc_encode_init(AVCodecContext *avctx)
         if (avctx->global_quality > 0)
             frame->bitpool = avctx->global_quality / FF_QP2LAMBDA;
 
+        if (frame->bitpool > frame->subbands << (4 + (frame->mode == STEREO
+                                                   || frame->mode == 
JOINT_STEREO))) {
+            av_log(avctx, AV_LOG_ERROR, "Invalid parameter combination\n");
+            return AVERROR_PATCHWELCOME;
+        }
+
         avctx->frame_size = 4*((frame->subbands >> 3) + 1) * 4*(frame->blocks 
>> 2);
     }
 
-- 
2.52.0


>From cf0677337f2f8a21b8ba4b1b93e77d8f05cbccea Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Tue, 24 Mar 2026 11:33:50 +0100
Subject: [PATCH 07/12] avcodec/sbcenc: Use correct size for PutBitContext

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/sbcenc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/sbcenc.c b/libavcodec/sbcenc.c
index 8534dc83ce..6c59a8902c 100644
--- a/libavcodec/sbcenc.c
+++ b/libavcodec/sbcenc.c
@@ -135,7 +135,7 @@ static size_t sbc_pack_frame(AVPacket *avpkt, struct 
sbc_frame *frame,
     crc_header[1] = avpkt->data[2];
     crc_pos = 16;
 
-    init_put_bits(&pb, avpkt->data + 4, avpkt->size);
+    init_put_bits(&pb, avpkt->data + 4, avpkt->size - 4);
 
     if (frame->mode == JOINT_STEREO) {
         put_bits(&pb, frame->subbands, joint);
-- 
2.52.0


>From bb904fa672525d266b0f30b8e684dc0f43c98795 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Tue, 24 Mar 2026 13:17:39 +0100
Subject: [PATCH 08/12] avcodec/sbcenc: Remove redundant memset()

A codec's private context is zero-allocated.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/sbcenc.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libavcodec/sbcenc.c b/libavcodec/sbcenc.c
index 6c59a8902c..bc2f844789 100644
--- a/libavcodec/sbcenc.c
+++ b/libavcodec/sbcenc.c
@@ -272,7 +272,6 @@ static av_cold int sbc_encode_init(AVCodecContext *avctx)
     frame->codesize = frame->subbands * frame->blocks * 
avctx->ch_layout.nb_channels * 2;
     frame->crc_ctx = av_crc_get_table(AV_CRC_8_EBU);
 
-    memset(&sbc->dsp.X, 0, sizeof(sbc->dsp.X));
     sbc->dsp.position = (SBC_X_BUFFER_SIZE - frame->subbands * 9) & ~7;
     sbc->dsp.increment = sbc->msbc ? 1 : 4;
     ff_sbcdsp_init(&sbc->dsp);
-- 
2.52.0


>From 22f272f554771e210242258bf5a05deae234fa2d Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Tue, 24 Mar 2026 13:54:58 +0100
Subject: [PATCH 09/12] tests/checkasm: Add sbcdsp tests

Only sbc_analyze_4 and sbc_analyze_8 for now.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 tests/checkasm/Makefile   |  1 +
 tests/checkasm/checkasm.c |  3 ++
 tests/checkasm/checkasm.h |  1 +
 tests/checkasm/sbcdsp.c   | 79 +++++++++++++++++++++++++++++++++++++++
 tests/fate/checkasm.mak   |  1 +
 5 files changed, 85 insertions(+)
 create mode 100644 tests/checkasm/sbcdsp.c

diff --git a/tests/checkasm/Makefile b/tests/checkasm/Makefile
index 6c525356aa..956f139090 100644
--- a/tests/checkasm/Makefile
+++ b/tests/checkasm/Makefile
@@ -48,6 +48,7 @@ AVCODECOBJS-$(CONFIG_HEVC_DECODER)      += hevc_add_res.o 
hevc_deblock.o hevc_de
 AVCODECOBJS-$(CONFIG_PNG_DECODER)       += png.o
 AVCODECOBJS-$(CONFIG_RV34DSP)           += rv34dsp.o
 AVCODECOBJS-$(CONFIG_RV40_DECODER)      += rv40dsp.o
+AVCODECOBJS-$(CONFIG_SBC_ENCODER)       += sbcdsp.o
 AVCODECOBJS-$(CONFIG_SVQ1_ENCODER)      += svq1enc.o
 AVCODECOBJS-$(CONFIG_TAK_DECODER)       += takdsp.o
 AVCODECOBJS-$(CONFIG_UTVIDEO_DECODER)   += utvideodsp.o
diff --git a/tests/checkasm/checkasm.c b/tests/checkasm/checkasm.c
index b1504b14bb..b38e5926cb 100644
--- a/tests/checkasm/checkasm.c
+++ b/tests/checkasm/checkasm.c
@@ -249,6 +249,9 @@ static const struct {
     #if CONFIG_RV40_DECODER
         { "rv40dsp", checkasm_check_rv40dsp },
     #endif
+    #if CONFIG_SBC_ENCODER
+        { "sbcdsp", checkasm_check_sbcdsp },
+    #endif
     #if CONFIG_SVQ1_ENCODER
         { "svq1enc", checkasm_check_svq1enc },
     #endif
diff --git a/tests/checkasm/checkasm.h b/tests/checkasm/checkasm.h
index f653207363..cded57d3ea 100644
--- a/tests/checkasm/checkasm.h
+++ b/tests/checkasm/checkasm.h
@@ -135,6 +135,7 @@ void checkasm_check_pixblockdsp(void);
 void checkasm_check_pixelutils(void);
 void checkasm_check_png(void);
 void checkasm_check_qpeldsp(void);
+void checkasm_check_sbcdsp(void);
 void checkasm_check_sbrdsp(void);
 void checkasm_check_rv34dsp(void);
 void checkasm_check_rv40dsp(void);
diff --git a/tests/checkasm/sbcdsp.c b/tests/checkasm/sbcdsp.c
new file mode 100644
index 0000000000..aefe066fe2
--- /dev/null
+++ b/tests/checkasm/sbcdsp.c
@@ -0,0 +1,79 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 <stddef.h>
+#include <stdint.h>
+
+#include "checkasm.h"
+#include "libavcodec/sbcdsp.h"
+#include "libavcodec/sbcdsp_data.h"
+#include "libavutil/macros.h"
+#include "libavutil/mem_internal.h"
+
+enum {
+    SBC_MAX_SUBBANDS = 8,
+};
+
+#define randomize_buffer(buf)                        \
+do {                                                 \
+    for (size_t k = 0; k < FF_ARRAY_ELEMS(buf); ++k) \
+        buf[k] = rnd();                              \
+} while (0)
+
+static void check_sbc_analyze(SBCDSPContext *sbcdsp)
+{
+    DECLARE_ALIGNED(SBC_ALIGN, int16_t, in)[10 * SBC_MAX_SUBBANDS];
+    DECLARE_ALIGNED(SBC_ALIGN, int32_t, out_ref)[SBC_MAX_SUBBANDS];
+    DECLARE_ALIGNED(SBC_ALIGN, int32_t, out_new)[SBC_MAX_SUBBANDS];
+
+    declare_func_emms(AV_CPU_FLAG_MMX, void, const int16_t *in, int32_t *out, 
const int16_t *consts);
+
+    for (int i = 0; i < 2; ++i) {
+        if (check_func(i ? sbcdsp->sbc_analyze_8 : sbcdsp->sbc_analyze_4, 
"sbc_analyze_%u", i ? 8 : 4)) {
+            randomize_buffer(in);
+            randomize_buffer(out_ref);
+            memcpy(out_new, out_ref, sizeof(out_new));
+
+            // the input is always 16-byte aligned for sbc_analyze_8
+            // for sbc_analyze_4 it can be 0 or 8 mod 16.
+            const int16_t *const inp = i || rnd() & 1 ? in : in + 4;
+            // Use the proper const tables as random ones can cause overflow
+            #define CONST(SIZE, ODDEVEN) sbcdsp_analysis_consts_fixed ## SIZE 
## _simd_ ## ODDEVEN
+            const int16_t *const consts = rnd() & 1 ? (i ? CONST(8, odd)  : 
CONST(4, odd))
+                                                    : (i ? CONST(8, even) : 
CONST(4, even));
+
+            call_ref(inp, out_ref, consts);
+            call_new(inp, out_new, consts);
+
+            if (memcmp(out_ref, out_new, sizeof(out_new)))
+                fail();
+
+            bench_new(inp, out_new, consts);
+        }
+    }
+    report("sbc_analyze");
+}
+
+void checkasm_check_sbcdsp(void)
+{
+    SBCDSPContext sbcdsp;
+
+    ff_sbcdsp_init(&sbcdsp);
+
+    check_sbc_analyze(&sbcdsp);
+}
diff --git a/tests/fate/checkasm.mak b/tests/fate/checkasm.mak
index 8441bb3719..d75b885db1 100644
--- a/tests/fate/checkasm.mak
+++ b/tests/fate/checkasm.mak
@@ -53,6 +53,7 @@ FATE_CHECKASM = fate-checkasm-aacencdsp                       
          \
                 fate-checkasm-sbrdsp                                    \
                 fate-checkasm-rv34dsp                                   \
                 fate-checkasm-rv40dsp                                   \
+                fate-checkasm-sbcdsp                                    \
                 fate-checkasm-scene_sad                                 \
                 fate-checkasm-svq1enc                                   \
                 fate-checkasm-synth_filter                              \
-- 
2.52.0


>From 4835b3a900926e3078c3c2bd7fd2d2727f564d12 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Tue, 24 Mar 2026 15:55:45 +0100
Subject: [PATCH 10/12] avcodec/x86/sbcdsp: Port ff_sbc_analyze_[48]_mmx to
 SSE2

Halfs the amount of pmaddwd and improves performance a lot:
sbc_analyze_4_c:                                        55.7 ( 1.00x)
sbc_analyze_4_mmx:                                       7.0 ( 7.94x)
sbc_analyze_4_sse2:                                      4.3 (12.93x)
sbc_analyze_8_c:                                       131.1 ( 1.00x)
sbc_analyze_8_mmx:                                      22.4 ( 5.84x)
sbc_analyze_8_sse2:                                     10.7 (12.25x)

It also saves 224B of .text and allows to remove the emms_c()
from sbcenc.c (notice that ff_sbc_calc_scalefactors_mmx()
issues emms on its own, so it already abides by the ABI).

Hint: A pshufd could be avoided per function if the constants
were reordered.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/sbcenc.c          |   2 -
 libavcodec/x86/sbcdsp.asm    | 116 +++++++++++++++++++----------------
 libavcodec/x86/sbcdsp_init.c |  12 ++--
 tests/checkasm/sbcdsp.c      |   2 +-
 4 files changed, 70 insertions(+), 62 deletions(-)

diff --git a/libavcodec/sbcenc.c b/libavcodec/sbcenc.c
index bc2f844789..7e047cd5ab 100644
--- a/libavcodec/sbcenc.c
+++ b/libavcodec/sbcenc.c
@@ -31,7 +31,6 @@
  */
 
 #include "libavutil/channel_layout.h"
-#include "libavutil/emms.h"
 #include "libavutil/opt.h"
 #include "avcodec.h"
 #include "codec_internal.h"
@@ -322,7 +321,6 @@ static int sbc_encode_frame(AVCodecContext *avctx, AVPacket 
*avpkt,
                                        frame->blocks,
                                        frame->channels,
                                        frame->subbands);
-    emms_c();
     sbc_pack_frame(avpkt, frame, j, sbc->msbc);
 
     *got_packet_ptr = 1;
diff --git a/libavcodec/x86/sbcdsp.asm b/libavcodec/x86/sbcdsp.asm
index ddc1237d8f..3351e2aadf 100644
--- a/libavcodec/x86/sbcdsp.asm
+++ b/libavcodec/x86/sbcdsp.asm
@@ -38,43 +38,44 @@ SECTION .text
 %endif
 %endmacro
 
-%macro ANALYZE_MAC 9 ; out1, out2, in1, in2, tmp1, tmp2, add1, add2, offset
-    NIDN movq,    %5, %3
-    NIDN movq,    %6, %4
-    pmaddwd       %5, [constsq+%9]
-    pmaddwd       %6, [constsq+%9+8]
-    NIDN paddd,   %1, %7
-    NIDN paddd,   %2, %8
-%endmacro
-
-%macro ANALYZE_MAC_IN 7 ; out1, out2, tmp1, tmp2, add1, add2, offset
-    ANALYZE_MAC   %1, %2, [inq+%7], [inq+%7+8], %3, %4, %5, %6, %7
-%endmacro
-
-%macro ANALYZE_MAC_REG 7 ; out1, out2, in, tmp1, tmp2, offset, pack
-%ifidn %7, pack
-    psrad         %3, 16    ; SBC_PROTO_FIXED_SCALE
-    packssdw      %3, %3
+%macro ANALYZE_MAC 6 ; out1, out2, tmp1, tmp2, offset, aligned
+    mov%6             %3, [inq+%5]
+    mov%6             %4, [inq+%5+mmsize]
+%if %5 == 0
+    pcmpeqd           m0, m0
+    psrld             m0, 31
 %endif
-    ANALYZE_MAC   %1, %2, %3, %3, %4, %5, %4, %5, %6
+    pmaddwd           %3, [constsq+%5]
+    pmaddwd           %4, [constsq+%5+mmsize]
+%if %5 == 0
+    pslld             m0, 15         ; 1 << (SBC_PROTO_FIXED_SCALE - 1) as 
dword
+%endif
+    NIDN paddd,       %1, %3
+    NIDN paddd,       %2, %4
 %endmacro
 
 ;*******************************************************************
 ;void ff_sbc_analyze_4(const int16_t *in, int32_t *out, const int16_t *consts);
 ;*******************************************************************
-INIT_MMX mmx
-cglobal sbc_analyze_4, 3, 3, 4, in, out, consts
-    ANALYZE_MAC_IN   m0, m1, m0, m1, [scale_mask], [scale_mask], 0
-    ANALYZE_MAC_IN   m0, m1, m2, m3, m2, m3, 16
-    ANALYZE_MAC_IN   m0, m1, m2, m3, m2, m3, 32
-    ANALYZE_MAC_IN   m0, m1, m2, m3, m2, m3, 48
-    ANALYZE_MAC_IN   m0, m1, m2, m3, m2, m3, 64
+INIT_XMM sse2
+cglobal sbc_analyze_4, 3, 3, 5, in, out, consts
+    ANALYZE_MAC       m1, m2, m1, m2,  0, u
+    ANALYZE_MAC       m1, m2, m3, m4, 32, u
+    movu              m3, [inq+64]
+    paddd             m1, m0
+    pmaddwd           m3, [constsq+64]
+    paddd             m1, m2
+    paddd             m1, m3
 
-    ANALYZE_MAC_REG  m0, m2, m0, m0, m2, 80, pack
-    ANALYZE_MAC_REG  m0, m2, m1, m1, m3, 96, pack
+    psrad             m1, 16
+    packssdw          m1, m1
+    pshufd            m2, m1, q0000
+    pmaddwd           m2, [constsq+80]
+    pshufd            m1, m1, q1111
+    pmaddwd           m1, [constsq+96]
+    paddd             m1, m2
 
-    movq          [outq  ], m0
-    movq          [outq+8], m2
+    mova          [outq], m1
 
     RET
 
@@ -82,34 +83,41 @@ cglobal sbc_analyze_4, 3, 3, 4, in, out, consts
 ;*******************************************************************
 ;void ff_sbc_analyze_8(const int16_t *in, int32_t *out, const int16_t *consts);
 ;*******************************************************************
-INIT_MMX mmx
-cglobal sbc_analyze_8, 3, 3, 4, in, out, consts
-    ANALYZE_MAC_IN   m0, m1, m0, m1, [scale_mask], [scale_mask],  0
-    ANALYZE_MAC_IN   m2, m3, m2, m3, [scale_mask], [scale_mask], 16
-    ANALYZE_MAC_IN   m0, m1, m4, m5, m4, m5,  32
-    ANALYZE_MAC_IN   m2, m3, m6, m7, m6, m7,  48
-    ANALYZE_MAC_IN   m0, m1, m4, m5, m4, m5,  64
-    ANALYZE_MAC_IN   m2, m3, m6, m7, m6, m7,  80
-    ANALYZE_MAC_IN   m0, m1, m4, m5, m4, m5,  96
-    ANALYZE_MAC_IN   m2, m3, m6, m7, m6, m7, 112
-    ANALYZE_MAC_IN   m0, m1, m4, m5, m4, m5, 128
-    ANALYZE_MAC_IN   m2, m3, m6, m7, m6, m7, 144
+INIT_XMM sse2
+cglobal sbc_analyze_8, 3, 3, 6, in, out, consts
+    ANALYZE_MAC       m1, m2, m1, m2,   0, a
+    ANALYZE_MAC       m1, m2, m3, m4,  32, a
+    paddd             m1, m0
+    ANALYZE_MAC       m1, m2, m3, m4,  64, a
+    ANALYZE_MAC       m1, m2, m3, m4,  96, a
+    paddd             m2, m0
+    ANALYZE_MAC       m1, m2, m3, m4, 128, a
 
-    ANALYZE_MAC_REG  m4, m5, m0, m4, m5, 160, pack
-    ANALYZE_MAC_REG  m4, m5, m1, m6, m7, 192, pack
-    ANALYZE_MAC_REG  m4, m5, m2, m6, m7, 224, pack
-    ANALYZE_MAC_REG  m4, m5, m3, m6, m7, 256, pack
+    psrad             m1, 16
+    psrad             m2, 16
+    packssdw          m1, m2
 
-    movq          [outq  ], m4
-    movq          [outq+8], m5
+    pshufd            m2, m1, q0000
+    pmaddwd           m0, m2, [constsq+160]
+    pshufd            m3, m1, q1111
+    pmaddwd           m2, [constsq+176]
+    pmaddwd           m4, m3, [constsq+192]
+    pshufd            m5, m1, q2222
+    pmaddwd           m3, [constsq+208]
+    paddd             m0, m4
+    pmaddwd           m4, m5, [constsq+224]
+    pshufd            m1, m1, q3333
+    pmaddwd           m5, [constsq+240]
+    paddd             m2, m3
+    pmaddwd           m3, m1, [constsq+256]
+    paddd             m0, m4
+    pmaddwd           m1, [constsq+272]
+    paddd             m0, m3
+    paddd             m2, m5
 
-    ANALYZE_MAC_REG  m0, m5, m0, m0, m5, 176, no
-    ANALYZE_MAC_REG  m0, m5, m1, m1, m7, 208, no
-    ANALYZE_MAC_REG  m0, m5, m2, m2, m7, 240, no
-    ANALYZE_MAC_REG  m0, m5, m3, m3, m7, 272, no
-
-    movq          [outq+16], m0
-    movq          [outq+24], m5
+    mova          [outq], m0
+    paddd             m2, m1
+    mova       [outq+16], m2
 
     RET
 
diff --git a/libavcodec/x86/sbcdsp_init.c b/libavcodec/x86/sbcdsp_init.c
index d959f76f8c..acca0bbdc9 100644
--- a/libavcodec/x86/sbcdsp_init.c
+++ b/libavcodec/x86/sbcdsp_init.c
@@ -26,7 +26,7 @@
 
 /**
  * @file
- * SBC MMX optimization for some basic "building bricks"
+ * SBC DSP optimization for some basic "building bricks"
  */
 
 #include "libavutil/attributes.h"
@@ -34,8 +34,8 @@
 #include "libavutil/x86/cpu.h"
 #include "libavcodec/sbcdsp.h"
 
-void ff_sbc_analyze_4_mmx(const int16_t *in, int32_t *out, const int16_t 
*consts);
-void ff_sbc_analyze_8_mmx(const int16_t *in, int32_t *out, const int16_t 
*consts);
+void ff_sbc_analyze_4_sse2(const int16_t *in, int32_t *out, const int16_t 
*consts);
+void ff_sbc_analyze_8_sse2(const int16_t *in, int32_t *out, const int16_t 
*consts);
 void ff_sbc_calc_scalefactors_mmx(const int32_t sb_sample_f[16][2][8],
                                   uint32_t scale_factor[2][8],
                                   int blocks, int channels, int subbands);
@@ -45,8 +45,10 @@ av_cold void ff_sbcdsp_init_x86(SBCDSPContext *s)
     int cpu_flags = av_get_cpu_flags();
 
     if (EXTERNAL_MMX(cpu_flags)) {
-        s->sbc_analyze_4 = ff_sbc_analyze_4_mmx;
-        s->sbc_analyze_8 = ff_sbc_analyze_8_mmx;
         s->sbc_calc_scalefactors = ff_sbc_calc_scalefactors_mmx;
     }
+    if (EXTERNAL_SSE2(cpu_flags)) {
+        s->sbc_analyze_4 = ff_sbc_analyze_4_sse2;
+        s->sbc_analyze_8 = ff_sbc_analyze_8_sse2;
+    }
 }
diff --git a/tests/checkasm/sbcdsp.c b/tests/checkasm/sbcdsp.c
index aefe066fe2..3bef11a5e7 100644
--- a/tests/checkasm/sbcdsp.c
+++ b/tests/checkasm/sbcdsp.c
@@ -41,7 +41,7 @@ static void check_sbc_analyze(SBCDSPContext *sbcdsp)
     DECLARE_ALIGNED(SBC_ALIGN, int32_t, out_ref)[SBC_MAX_SUBBANDS];
     DECLARE_ALIGNED(SBC_ALIGN, int32_t, out_new)[SBC_MAX_SUBBANDS];
 
-    declare_func_emms(AV_CPU_FLAG_MMX, void, const int16_t *in, int32_t *out, 
const int16_t *consts);
+    declare_func(void, const int16_t *in, int32_t *out, const int16_t *consts);
 
     for (int i = 0; i < 2; ++i) {
         if (check_func(i ? sbcdsp->sbc_analyze_8 : sbcdsp->sbc_analyze_4, 
"sbc_analyze_%u", i ? 8 : 4)) {
-- 
2.52.0


>From 08476c00321a2650ee937e7748c68feb28909ec7 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Tue, 24 Mar 2026 17:33:35 +0100
Subject: [PATCH 11/12] tests/checkasm/sbcdsp: Add test for calc_scalefactors

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 tests/checkasm/sbcdsp.c | 42 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/tests/checkasm/sbcdsp.c b/tests/checkasm/sbcdsp.c
index 3bef11a5e7..802eb430ed 100644
--- a/tests/checkasm/sbcdsp.c
+++ b/tests/checkasm/sbcdsp.c
@@ -69,6 +69,45 @@ static void check_sbc_analyze(SBCDSPContext *sbcdsp)
     report("sbc_analyze");
 }
 
+static void check_sbc_calc_scalefactors(const SBCDSPContext *const sbcdsp)
+{
+    DECLARE_ALIGNED(SBC_ALIGN,  int32_t, sb_sample_f)[16][2][8];
+    DECLARE_ALIGNED(SBC_ALIGN, uint32_t, scale_factor_ref)[2][8];
+    DECLARE_ALIGNED(SBC_ALIGN, uint32_t, scale_factor_new)[2][8];
+
+    declare_func(void, const int32_t sb_sample_f[16][2][8],
+                       uint32_t scale_factor[2][8],
+                       int blocks, int channels, int subbands);
+
+    static int blocks = 0;
+    if (!blocks)
+        blocks = ((const int[]){4, 8, 12, 15, 16})[rnd() % 5];
+    int inited = 0;
+
+    for (int ch = 1; ch <= 2; ++ch) {
+        for (int subbands = 4; subbands <= 8; subbands += 4) {
+            if (!check_func(sbcdsp->sbc_calc_scalefactors, 
"calc_scalefactors_%dch_%dsubbands", ch, subbands))
+                return;
+
+            if (!inited) {
+                for (size_t i = 0; i < FF_ARRAY_ELEMS(sb_sample_f); ++i)
+                    for (size_t j = 0; j < FF_ARRAY_ELEMS(sb_sample_f[0]); ++j)
+                        for (size_t k = 0; k < 
FF_ARRAY_ELEMS(sb_sample_f[0][0]); ++k)
+                            sb_sample_f[i][j][k] = rnd();
+            }
+
+            call_ref(sb_sample_f, scale_factor_ref, blocks, ch, subbands);
+            call_new(sb_sample_f, scale_factor_new, blocks, ch, subbands);
+            for (int i = 0; i < ch; ++i)
+                for (int j = 0; j < subbands; ++j)
+                    if (scale_factor_ref[i][j] != scale_factor_new[i][j])
+                        fail();
+
+            bench_new(sb_sample_f, scale_factor_new, blocks, ch, subbands);
+        }
+    }
+}
+
 void checkasm_check_sbcdsp(void)
 {
     SBCDSPContext sbcdsp;
@@ -76,4 +115,7 @@ void checkasm_check_sbcdsp(void)
     ff_sbcdsp_init(&sbcdsp);
 
     check_sbc_analyze(&sbcdsp);
+
+    check_sbc_calc_scalefactors(&sbcdsp);
+    report("calc_scalefactors");
 }
-- 
2.52.0


>From 50b8ea90b083b97f361fbdd6aa4e56c10bbea9a1 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Tue, 24 Mar 2026 23:06:05 +0100
Subject: [PATCH 12/12] avcodec/x86/sbcdsp: Port MMX sbc_calc_scalefactors to
 SSE4

Besides giving a nice speedup over the MMX version,
it also avoids processing unnecessarily much input and
touching unnecessarily much output in the 2ch-4subbands case.

calc_scalefactors_1ch_4subbands_c:                     106.9 ( 1.00x)
calc_scalefactors_1ch_4subbands_mmx:                    46.7 ( 2.29x)
calc_scalefactors_1ch_4subbands_sse4:                   11.8 ( 9.05x)
calc_scalefactors_1ch_8subbands_c:                     220.5 ( 1.00x)
calc_scalefactors_1ch_8subbands_mmx:                    92.3 ( 2.39x)
calc_scalefactors_1ch_8subbands_sse4:                   23.8 ( 9.28x)
calc_scalefactors_2ch_4subbands_c:                     222.5 ( 1.00x)
calc_scalefactors_2ch_4subbands_mmx:                   139.3 ( 1.60x)
calc_scalefactors_2ch_4subbands_sse4:                   23.6 ( 9.41x)
calc_scalefactors_2ch_8subbands_c:                     440.3 ( 1.00x)
calc_scalefactors_2ch_8subbands_mmx:                   196.8 ( 2.24x)
calc_scalefactors_2ch_8subbands_sse4:                   46.5 ( 9.48x)

The MMX version has been removed.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavcodec/x86/sbcdsp.asm    | 75 ++++++++++++++++--------------------
 libavcodec/x86/sbcdsp_init.c | 12 +++---
 2 files changed, 39 insertions(+), 48 deletions(-)

diff --git a/libavcodec/x86/sbcdsp.asm b/libavcodec/x86/sbcdsp.asm
index 3351e2aadf..7742d6d316 100644
--- a/libavcodec/x86/sbcdsp.asm
+++ b/libavcodec/x86/sbcdsp.asm
@@ -26,10 +26,6 @@
 
 %include "libavutil/x86/x86util.asm"
 
-SECTION_RODATA
-
-scale_mask: times 2 dd 0x8000    ; 1 << (SBC_PROTO_FIXED_SCALE - 1)
-
 SECTION .text
 
 %macro NIDN 3
@@ -127,50 +123,45 @@ cglobal sbc_analyze_8, 3, 3, 6, in, out, consts
 ;                              uint32_t scale_factor[2][8],
 ;                              int blocks, int channels, int subbands)
 ;*******************************************************************
-INIT_MMX mmx
-cglobal sbc_calc_scalefactors, 5, 7, 4, sb_sample_f, scale_factor, blocks, 
channels, subbands, ptr, blk
-    ; subbands = 4 * subbands * channels
-    movq          m3, [scale_mask]
-    shl           subbandsd, 2
-    cmp           channelsd, 2
-    jl            .loop_1
-    add           subbandsd, 32
+INIT_XMM sse4
+cglobal sbc_calc_scalefactors, 5, 6, 5, sb_sample_f, scale_factor, blocks, 
channels, subbands, step
+    shl          blocksd, 6
+    pcmpeqd           m3, m3
+    shl        subbandsd, 2
+    mov            stepd, 48
+    add     sb_sample_fq, blocksq
+    psrld             m4, m3, 25      ; pd_127
+    neg          blocksq
+    shl        channelsd, 5
+    sub            stepd, subbandsd   ; step = subbands == 4 ? 32 : 16
+    pxor              m2, m2
 
 .loop_1:
-    sub           subbandsq, 8
-    lea           ptrq, [sb_sample_fq + subbandsq]
+    lea        subbandsq, [blocksq+64]
 
-    ; blk = (blocks - 1) * 64;
-    lea           blkq, [blocksq - 1]
-    shl           blkd, 6
-
-    movq          m0, m3
+    pabsd             m0, [sb_sample_fq+blocksq]
 .loop_2:
-    movq          m1, [ptrq+blkq]
-    pxor          m2, m2
-    pcmpgtd       m1, m2
-    paddd         m1, [ptrq+blkq]
-    pcmpgtd       m2, m1
-    pxor          m1, m2
+    pabsd             m1, [sb_sample_fq+subbandsq]
+    pmaxud            m0, m1
+    add        subbandsq, 64
+    js           .loop_2
 
-    por           m0, m1
+    paddd             m0, m3          ; max - 1, representable as signed value
+    pmaxsd            m0, m2
 
-    sub           blkq, 64
-    jns           .loop_2
+    ; We have to calculate log2(x|(1<<15))-15. This equals log2(x>>15) for x 
>= 2^15
+    ; and x>>15 is exactly representable as a float, so one can get the log2
+    ; by converting to float and subtracting 127 from the exponent.
+    ; For x < 2^15 the result is correct when using saturated subtraction.
+    psrld             m0, 15
+    cvtdq2ps          m0, m0
+    add     sb_sample_fq, stepq
+    psrld             m0, 23          ; exponent
+    psubusw           m0, m4          ; same as saturated dword subtraction
+    mova [scale_factorq], m0
 
-    movd          blkd, m0
-    psrlq         m0,   32
-    bsr           blkd, blkd
-    sub           blkd, 15    ; SCALE_OUT_BITS
-    mov           [scale_factorq + subbandsq], blkd
+    add    scale_factorq, stepq
+    sub        channelsd, stepd
+    jg           .loop_1
 
-    movd          blkd, m0
-    bsr           blkd, blkd
-    sub           blkd, 15    ; SCALE_OUT_BITS
-    mov           [scale_factorq + subbandsq + 4], blkd
-
-    cmp           subbandsq, 0
-    jg            .loop_1
-
-    emms
     RET
diff --git a/libavcodec/x86/sbcdsp_init.c b/libavcodec/x86/sbcdsp_init.c
index acca0bbdc9..b92f348942 100644
--- a/libavcodec/x86/sbcdsp_init.c
+++ b/libavcodec/x86/sbcdsp_init.c
@@ -36,19 +36,19 @@
 
 void ff_sbc_analyze_4_sse2(const int16_t *in, int32_t *out, const int16_t 
*consts);
 void ff_sbc_analyze_8_sse2(const int16_t *in, int32_t *out, const int16_t 
*consts);
-void ff_sbc_calc_scalefactors_mmx(const int32_t sb_sample_f[16][2][8],
-                                  uint32_t scale_factor[2][8],
-                                  int blocks, int channels, int subbands);
+void ff_sbc_calc_scalefactors_sse4(const int32_t sb_sample_f[16][2][8],
+                                   uint32_t scale_factor[2][8],
+                                   int blocks, int channels, int subbands);
 
 av_cold void ff_sbcdsp_init_x86(SBCDSPContext *s)
 {
     int cpu_flags = av_get_cpu_flags();
 
-    if (EXTERNAL_MMX(cpu_flags)) {
-        s->sbc_calc_scalefactors = ff_sbc_calc_scalefactors_mmx;
-    }
     if (EXTERNAL_SSE2(cpu_flags)) {
         s->sbc_analyze_4 = ff_sbc_analyze_4_sse2;
         s->sbc_analyze_8 = ff_sbc_analyze_8_sse2;
     }
+    if (EXTERNAL_SSE4(cpu_flags)) {
+        s->sbc_calc_scalefactors = ff_sbc_calc_scalefactors_sse4;
+    }
 }
-- 
2.52.0

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

Reply via email to