[FFmpeg-devel] [PATCH] swresample/arm: add ff_resample_common_apply_filter_{x4, x8}_{float, s16}_neon

Matthieu Bouron matthieu.bouron at gmail.com
Wed May 11 18:39:20 CEST 2016


From: Matthieu Bouron <matthieu.bouron at stupeflix.com>

---

Hello,

Here are some benchmark on a rpi2 of the attached patch.

./ffmpeg -f lavfi -i sine=440,aformat=sample_fmts=fltp,asetnsamples=4096,abench=start,aresample=48000,abench=stop -t 1000 -f null -

With patch:    avg=0.001159 speed=44,1x
Without patch: avg=0.001297 speed=40,8x

./ffmpeg -f lavfi -i sine=440,aformat=sample_fmts=s16p,asetnsamples=4096,abench=start,aresample=48000,abench=stop -t 1000 -f null -

With patch:    avg=0.001374 speed=45,6x
Without patch: avg=0.000782 speed=64,6x

Matthieu

---
 libswresample/arm/Makefile        |   7 ++-
 libswresample/arm/resample.S      |  77 ++++++++++++++++++++++++
 libswresample/arm/resample_init.c | 120 ++++++++++++++++++++++++++++++++++++++
 libswresample/resample.h          |   1 +
 libswresample/resample_dsp.c      |   1 +
 5 files changed, 204 insertions(+), 2 deletions(-)
 create mode 100644 libswresample/arm/resample.S
 create mode 100644 libswresample/arm/resample_init.c

diff --git a/libswresample/arm/Makefile b/libswresample/arm/Makefile
index 60f3f6d..53ab462 100644
--- a/libswresample/arm/Makefile
+++ b/libswresample/arm/Makefile
@@ -1,5 +1,8 @@
-OBJS      += arm/audio_convert_init.o
+OBJS      += arm/audio_convert_init.o \
+             arm/resample_init.o
+
 
 OBJS-$(CONFIG_NEON_CLOBBER_TEST) += arm/neontest.o
 
-NEON-OBJS += arm/audio_convert_neon.o
+NEON-OBJS += arm/audio_convert_neon.o \
+             arm/resample.o
diff --git a/libswresample/arm/resample.S b/libswresample/arm/resample.S
new file mode 100644
index 0000000..13462e3
--- /dev/null
+++ b/libswresample/arm/resample.S
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
+ *
+ * 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/arm/asm.S"
+
+function ff_resample_common_apply_filter_x4_float_neon, export=1
+    vmov.f32            q0, #0.0                                       @ accumulator
+1:  vld1.32             {q1}, [r1]!                                    @ src
+    vld1.32             {q2}, [r2]!                                    @ filter
+    vmla.f32            q0, q1, q2                                     @ src + {0..3} * filter + {0..3}
+    subs                r3, #4                                         @ filter_length -= 4
+    bgt                 1b                                             @ loop until filter_length
+    vpadd.f32           d0, d0, d1                                     @ pair adding of the 4x32-bit accumulated values
+    vpadd.f32           d0, d0, d0                                     @ pair adding of the 4x32-bit accumulator values
+    vst1.32             {d0[0]}, [r0]                                  @ write accumulator
+    mov pc, lr
+endfunc
+
+function ff_resample_common_apply_filter_x8_float_neon, export=1
+    vmov.f32            q0, #0.0                                       @ accumulator
+1:  vld1.32             {q1}, [r1]!                                    @ src1
+    vld1.32             {q2}, [r2]!                                    @ filter1
+    vld1.32             {q8}, [r1]!                                    @ src2
+    vld1.32             {q9}, [r2]!                                    @ filter2
+    vmla.f32            q0, q1, q2                                     @ src1 + {0..3} * filter1 + {0..3}
+    vmla.f32            q0, q8, q9                                     @ src2 + {0..3} * filter2 + {0..3}
+    subs                r3, #8                                         @ filter_length -= 4
+    bgt                 1b                                             @ loop until filter_length
+    vpadd.f32           d0, d0, d1                                     @ pair adding of the 4x32-bit accumulated values
+    vpadd.f32           d0, d0, d0                                     @ pair adding of the 4x32-bit accumulator values
+    vst1.32             {d0[0]}, [r0]                                  @ write accumulator
+    mov pc, lr
+endfunc
+
+function ff_resample_common_apply_filter_x4_s16_neon, export=1
+    vmov.s32            q0, #0                                         @ accumulator
+1:  vld1.16             {d2}, [r1]!                                    @ src
+    vld1.16             {d4}, [r2]!                                    @ filter
+    vmlal.s16           q0, d2, d4                                     @ src + {0..3} * filter + {0..3}
+    subs                r3, #4                                         @ filter_length -= 4
+    bgt                 1b                                             @ loop until filter_length
+    vpadd.s32           d0, d0, d1                                     @ pair adding of the 4x32-bit accumulated values
+    vpadd.s32           d0, d0, d0                                     @ pair adding of the 4x32-bit accumulator values
+    vst1.32             {d0[0]}, [r0]                                  @ write accumulator
+    mov pc, lr
+endfunc
+
+function ff_resample_common_apply_filter_x8_s16_neon, export=1
+    vmov.s32            q0, #0                                         @ accumulator
+1:  vld1.16             {q1}, [r1]!                                    @ src
+    vld1.16             {q2}, [r2]!                                    @ filter
+    vmlal.s16           q0, d2, d4                                     @ src + {0..3} * filter + {0..3}
+    vmlal.s16           q0, d3, d5                                     @ src + {4..7} * filter + {4..7}
+    subs                r3, #8                                         @ filter_length -= 8
+    bgt                 1b                                             @ loop until filter_length
+    vpadd.s32           d0, d0, d1                                     @ pair adding of the 4x32-bit accumulated values
+    vpadd.s32           d0, d0, d0                                     @ pair adding of the 4x32-bit accumulator values
+    vst1.32             {d0[0]}, [r0]                                  @ write accumulator
+    mov pc, lr
+endfunc
diff --git a/libswresample/arm/resample_init.c b/libswresample/arm/resample_init.c
new file mode 100644
index 0000000..c817d03
--- /dev/null
+++ b/libswresample/arm/resample_init.c
@@ -0,0 +1,120 @@
+/*
+ * audio resampling
+ * Copyright (c) 2004-2012 Michael Niedermayer <michaelni at gmx.at>
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * audio resampling
+ * @author Matthieu Bouron <matthieu.bouron stupeflix.com>
+ */
+
+#include "config.h"
+
+#include "libavutil/cpu.h"
+#include "libavutil/avassert.h"
+
+#include "libavutil/arm/cpu.h"
+#include "libswresample/resample.h"
+
+#define DECLARE_RESAMPLE_COMMON_TEMPLATE(TYPE, DELEM, FELEM, FELEM2, OUT)                         \
+                                                                                                  \
+void ff_resample_common_apply_filter_x4_##TYPE##_neon(FELEM2 *acc, const DELEM *src,              \
+                                                      const FELEM *filter, int length);           \
+                                                                                                  \
+void ff_resample_common_apply_filter_x8_##TYPE##_neon(FELEM2 *acc, const DELEM *src,              \
+                                                      const FELEM *filter, int length);           \
+                                                                                                  \
+static int ff_resample_common_##TYPE##_neon(ResampleContext *c, void *dest, const void *source,   \
+                                            int n, int update_ctx)                                \
+{                                                                                                 \
+    DELEM *dst = dest;                                                                            \
+    const DELEM *src = source;                                                                    \
+    int dst_index;                                                                                \
+    int index= c->index;                                                                          \
+    int frac= c->frac;                                                                            \
+    int sample_index = index >> c->phase_shift;                                                   \
+    int x4_aligned_filter_length = c->filter_length & ~3;                                         \
+    int x8_aligned_filter_length = c->filter_length & ~7;                                         \
+                                                                                                  \
+    index &= c->phase_mask;                                                                       \
+    for (dst_index = 0; dst_index < n; dst_index++) {                                             \
+        FELEM *filter = ((FELEM *) c->filter_bank) + c->filter_alloc * index;                     \
+                                                                                                  \
+        FELEM2 val=0;                                                                             \
+        int i = 0;                                                                                \
+        if (x8_aligned_filter_length >= 8) {                                                      \
+            ff_resample_common_apply_filter_x8_##TYPE##_neon(&val, &src[sample_index],            \
+                                                             filter, x8_aligned_filter_length);   \
+            i += x8_aligned_filter_length;                                                        \
+                                                                                                  \
+        } else if (x4_aligned_filter_length >= 4) {                                               \
+            ff_resample_common_apply_filter_x4_##TYPE##_neon(&val, &src[sample_index],            \
+                                                             filter, x4_aligned_filter_length);   \
+            i += x4_aligned_filter_length;                                                        \
+        }                                                                                         \
+        for (; i < c->filter_length; i++) {                                                       \
+            val += src[sample_index + i] * (FELEM2)filter[i];                                     \
+        }                                                                                         \
+        OUT(dst[dst_index], val);                                                                 \
+                                                                                                  \
+        frac  += c->dst_incr_mod;                                                                 \
+        index += c->dst_incr_div;                                                                 \
+        if (frac >= c->src_incr) {                                                                \
+            frac -= c->src_incr;                                                                  \
+            index++;                                                                              \
+        }                                                                                         \
+        sample_index += index >> c->phase_shift;                                                  \
+        index &= c->phase_mask;                                                                   \
+    }                                                                                             \
+                                                                                                  \
+    if(update_ctx){                                                                               \
+        c->frac= frac;                                                                            \
+        c->index= index;                                                                          \
+    }                                                                                             \
+                                                                                                  \
+    return sample_index;                                                                          \
+}                                                                                                 \
+
+#define OUT(d, v) d = v
+DECLARE_RESAMPLE_COMMON_TEMPLATE(float, float, float, float, OUT)
+#undef OUT
+
+#define OUT(d, v) (v) = ((v) + (1<<(14)))>>15; (d) = av_clip_int16(v)
+DECLARE_RESAMPLE_COMMON_TEMPLATE(s16, int16_t, int16_t, int32_t, OUT)
+#undef OUT
+
+av_cold void swri_resample_dsp_arm_init(ResampleContext *c)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    if (!have_neon(cpu_flags))
+        return;
+
+    switch(c->format) {
+    case AV_SAMPLE_FMT_FLTP:
+        if (!c->linear)
+            c->dsp.resample = ff_resample_common_float_neon;
+        break;
+    case AV_SAMPLE_FMT_S16P:
+        if (!c->linear)
+            c->dsp.resample = ff_resample_common_s16_neon;
+        break;
+    }
+}
diff --git a/libswresample/resample.h b/libswresample/resample.h
index a126b11..ca0cf2b 100644
--- a/libswresample/resample.h
+++ b/libswresample/resample.h
@@ -60,5 +60,6 @@ typedef struct ResampleContext {
 
 void swri_resample_dsp_init(ResampleContext *c);
 void swri_resample_dsp_x86_init(ResampleContext *c);
+void swri_resample_dsp_arm_init(ResampleContext *c);
 
 #endif /* SWRESAMPLE_RESAMPLE_H */
diff --git a/libswresample/resample_dsp.c b/libswresample/resample_dsp.c
index a811b8b..41369f3 100644
--- a/libswresample/resample_dsp.c
+++ b/libswresample/resample_dsp.c
@@ -65,4 +65,5 @@ void swri_resample_dsp_init(ResampleContext *c)
     }
 
     if (ARCH_X86) swri_resample_dsp_x86_init(c);
+    else if (ARCH_ARM) swri_resample_dsp_arm_init(c);
 }
-- 
2.8.2



More information about the ffmpeg-devel mailing list