[FFmpeg-cvslog] avfilter/x86/f_ebur128: add x86 AVX implementation

Niklas Haas git at videolan.org
Sat Jun 21 18:31:17 EEST 2025


ffmpeg | branch: master | Niklas Haas <git at haasn.dev> | Thu Jun 12 19:48:33 2025 +0200| [53e03ec8afa8cc68bb14993b75ffc48f146c6b62] | committer: Niklas Haas

avfilter/x86/f_ebur128: add x86 AVX implementation

Processes two channels in parallel, using 128-bit XMM registers.

In theory, we could go up to YMM registers to process 4 channels, but this is
not a gain except for relatively high channel counts (e.g. 7.1), and also
complicates the sample load/store operations considerably.

I decided to only add an AVX variant, since the C code is not substantially
slower enough to justify a separate function just for ancient CPUs.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=53e03ec8afa8cc68bb14993b75ffc48f146c6b62
---

 libavfilter/f_ebur128.c          |  15 ++--
 libavfilter/f_ebur128.h          |  16 +++++
 libavfilter/x86/Makefile         |   2 +
 libavfilter/x86/f_ebur128.asm    | 143 +++++++++++++++++++++++++++++++++++++++
 libavfilter/x86/f_ebur128_init.c |  35 ++++++++++
 5 files changed, 206 insertions(+), 5 deletions(-)

diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c
index b9e210c05a..2d94cefce7 100644
--- a/libavfilter/f_ebur128.c
+++ b/libavfilter/f_ebur128.c
@@ -579,6 +579,11 @@ static av_cold int init(AVFilterContext *ctx)
     /* summary */
     av_log(ctx, AV_LOG_VERBOSE, "EBU +%d scale\n", ebur128->meter);
 
+    ebur128->dsp.filter_channels = ff_ebur128_filter_channels_c;
+#if ARCH_X86
+    ff_ebur128_init_x86(&ebur128->dsp);
+#endif
+
     return 0;
 }
 
@@ -692,11 +697,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
         MOVE_TO_NEXT_CACHED_ENTRY(400);
         MOVE_TO_NEXT_CACHED_ENTRY(3000);
 
-        ff_ebur128_filter_channels_c(dsp, &samples[idx_insample * nb_channels],
-                                     &ebur128->i400.cache[bin_id_400 * nb_channels],
-                                     &ebur128->i3000.cache[bin_id_3000 * nb_channels],
-                                     ebur128->i400.sum, ebur128->i3000.sum,
-                                     nb_channels);
+        dsp->filter_channels(dsp, &samples[idx_insample * nb_channels],
+                             &ebur128->i400.cache[bin_id_400 * nb_channels],
+                             &ebur128->i3000.cache[bin_id_3000 * nb_channels],
+                             ebur128->i400.sum, ebur128->i3000.sum,
+                             nb_channels);
 
 #define FIND_PEAK(global, sp, ptype) do {                        \
     int ch;                                                      \
diff --git a/libavfilter/f_ebur128.h b/libavfilter/f_ebur128.h
index 7b8e876576..1889e28bdd 100644
--- a/libavfilter/f_ebur128.h
+++ b/libavfilter/f_ebur128.h
@@ -22,6 +22,9 @@
 #ifndef AVFILTER_F_EBUR128_H
 #define AVFILTER_F_EBUR128_H
 
+#include <assert.h>
+#include <stddef.h>
+
 typedef struct EBUR128Biquad {
     double b0, b1, b2;
     double a1, a2;
@@ -35,8 +38,21 @@ typedef struct EBUR128DSPContext {
     /* Cache of 3 samples for each channel */
     double *y; /* after pre-filter */
     double *z; /* after RLB-filter */
+
+    /* DSP functions */
+    void (*filter_channels)(const struct EBUR128DSPContext *dsp,
+                            const double *samples,
+                            double *cache_400, double *cache_3000,
+                            double *sum_400, double *sum_3000,
+                            int nb_channels);
 } EBUR128DSPContext;
 
+static_assert(offsetof(EBUR128DSPContext, pre) == 0,                   "struct layout mismatch");
+static_assert(offsetof(EBUR128DSPContext, rlb) == 5  * sizeof(double), "struct layout mismatch");
+static_assert(offsetof(EBUR128DSPContext, y)   == 10 * sizeof(double), "struct layout mismatch");
+
+void ff_ebur128_init_x86(EBUR128DSPContext *dsp);
+
 void ff_ebur128_filter_channels_c(const EBUR128DSPContext *, const double *,
                                   double *, double *, double *, double *, int);
 
diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile
index 0d9a28a935..0efe3f8d2c 100644
--- a/libavfilter/x86/Makefile
+++ b/libavfilter/x86/Makefile
@@ -7,6 +7,7 @@ OBJS-$(CONFIG_BLEND_FILTER)                  += x86/vf_blend_init.o
 OBJS-$(CONFIG_BWDIF_FILTER)                  += x86/vf_bwdif_init.o
 OBJS-$(CONFIG_COLORSPACE_FILTER)             += x86/colorspacedsp_init.o
 OBJS-$(CONFIG_CONVOLUTION_FILTER)            += x86/vf_convolution_init.o
+OBJS-$(CONFIG_EBUR128_FILTER)                += x86/f_ebur128_init.o
 OBJS-$(CONFIG_EQ_FILTER)                     += x86/vf_eq_init.o
 OBJS-$(CONFIG_FSPP_FILTER)                   += x86/vf_fspp_init.o
 OBJS-$(CONFIG_GBLUR_FILTER)                  += x86/vf_gblur_init.o
@@ -52,6 +53,7 @@ X86ASM-OBJS-$(CONFIG_BLEND_FILTER)           += x86/vf_blend.o
 X86ASM-OBJS-$(CONFIG_BWDIF_FILTER)           += x86/vf_bwdif.o
 X86ASM-OBJS-$(CONFIG_COLORSPACE_FILTER)      += x86/colorspacedsp.o
 X86ASM-OBJS-$(CONFIG_CONVOLUTION_FILTER)     += x86/vf_convolution.o
+X86ASM-OBJS-$(CONFIG_EBUR128_FILTER)         += x86/f_ebur128.o
 X86ASM-OBJS-$(CONFIG_EQ_FILTER)              += x86/vf_eq.o
 X86ASM-OBJS-$(CONFIG_FRAMERATE_FILTER)       += x86/vf_framerate.o
 X86ASM-OBJS-$(CONFIG_FSPP_FILTER)            += x86/vf_fspp.o
diff --git a/libavfilter/x86/f_ebur128.asm b/libavfilter/x86/f_ebur128.asm
new file mode 100644
index 0000000000..f8515d811d
--- /dev/null
+++ b/libavfilter/x86/f_ebur128.asm
@@ -0,0 +1,143 @@
+;*****************************************************************************
+;* x86-optimized functions for ebur128 filter
+;*
+;* Copyright (C) 2025 Niklas Haas
+;*
+;* 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/x86/x86util.asm"
+
+struc Biquad
+    .b0 resq 1
+    .b1 resq 1
+    .b2 resq 1
+    .a1 resq 1
+    .a2 resq 1
+endstruc
+
+struc DSP
+    .pre resq 5
+    .rlb resq 5
+    .y resq 1
+    .z resq 1
+endstruc
+
+SECTION .text
+
+%macro MOVNQ 3 ; num, dst, src
+%if %1 == 1
+    movsd %2, %3
+%else
+    movupd %2, %3
+%endif
+%endmacro
+
+%macro FILTER 11 ; y0, y1, y2, x, b0, b1, b2, a1, a2, samples, num_channels
+    ; Y[0] := b0 * X + Y1
+    ; Y[1] := b1 * X + Y2 - a1 * Y[0]
+    ; Y[2] := b2 * X - a2 * Y[0]
+    movsd %1, [%10 +  8]
+    movsd %3, [%10 + 16]
+%if %11 > 1
+    movhpd %1, [%10 + 32]
+    movhpd %3, [%10 + 40]
+%endif
+
+    mulpd %2, %5, %4
+    addpd %1, %2
+
+    mulpd %2, %8, %1
+    subpd %3, %2
+    mulpd %2, %6, %4
+    addpd %2, %3
+
+    mulpd %3, %7, %4
+    mulpd %4, %9, %1
+    subpd %3, %4
+
+    movsd [%10 +  0], %1
+    movsd [%10 +  8], %2
+    movsd [%10 + 16], %3
+%if %11 > 1
+    movhpd [%10 + 24], %1
+    movhpd [%10 + 32], %2
+    movhpd [%10 + 40], %3
+%endif
+    add %10, 24 * %11
+%endmacro
+
+%macro filter_channels 1 ; num_channels
+    MOVNQ %1, m3, [samplesq]
+    add samplesq, 8 * %1
+
+    FILTER m0, m1, m2, m3, m4,  m5,  m6,  m7,  m8, r7q, %1
+    FILTER m3, m1, m2, m0, m9, m10, m11, m12, m13, r8q, %1
+
+    ; update sum and cache
+    mulpd m3, m3
+    subpd m0, m3, [cache400q]
+    subpd m1, m3, [cache3000q]
+    MOVNQ %1, [cache400q],  m3
+    MOVNQ %1, [cache3000q], m3
+    add cache400q,  8 * %1
+    add cache3000q, 8 * %1
+    addpd m0, [sum400q]
+    addpd m1, [sum3000q]
+    MOVNQ %1, [sum400q],  m0
+    MOVNQ %1, [sum3000q], m1
+    add sum400q,  8 * %1
+    add sum3000q, 8 * %1
+%endmacro
+
+%if ARCH_X86_64
+
+INIT_XMM avx
+cglobal ebur128_filter_channels, 7, 9, 14, dsp, samples, cache400, cache3000, sum400, sum3000, channels
+    movddup m4,  [dspq + DSP.pre + Biquad.b0]
+    movddup m5,  [dspq + DSP.pre + Biquad.b1]
+    movddup m6,  [dspq + DSP.pre + Biquad.b2]
+    movddup m7,  [dspq + DSP.pre + Biquad.a1]
+    movddup m8,  [dspq + DSP.pre + Biquad.a2]
+
+    movddup m9,  [dspq + DSP.rlb + Biquad.b0]
+    movddup m10, [dspq + DSP.rlb + Biquad.b1]
+    movddup m11, [dspq + DSP.rlb + Biquad.b2]
+    movddup m12, [dspq + DSP.rlb + Biquad.a1]
+    movddup m13, [dspq + DSP.rlb + Biquad.a2]
+
+    mov r7q, [dspq + DSP.y]
+    mov r8q, [dspq + DSP.z]
+
+    ; handle odd channel count
+    test channelsd, 1
+    jnz .tail
+
+.loop:
+    filter_channels 2
+    sub channelsd, 2
+    jg .loop
+    RET
+
+.tail:
+    filter_channels 1
+    dec channelsd
+    test channelsd, channelsd
+    jnz .loop
+    RET
+
+%endif ; ARCH_X86_64
diff --git a/libavfilter/x86/f_ebur128_init.c b/libavfilter/x86/f_ebur128_init.c
new file mode 100644
index 0000000000..8f38aee967
--- /dev/null
+++ b/libavfilter/x86/f_ebur128_init.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018 Paul B Mahol
+ *
+ * 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/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/x86/cpu.h"
+#include "libavfilter/f_ebur128.h"
+
+void ff_ebur128_filter_channels_avx(const EBUR128DSPContext *, const double *,
+                                    double *, double *, double *, double *, int);
+
+av_cold void ff_ebur128_init_x86(EBUR128DSPContext *dsp)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    if (ARCH_X86_64 && EXTERNAL_AVX(cpu_flags))
+        dsp->filter_channels = ff_ebur128_filter_channels_avx;
+}



More information about the ffmpeg-cvslog mailing list