From: Zhao Zhili via ffmpeg-devel <ffmpeg-devel@ffmpeg.org> To: ffmpeg-devel@ffmpeg.org Cc: Zhao Zhili <code@ffmpeg.org> Subject: [FFmpeg-devel] [PATCH] avutil/crc: add arm64 crc32 asm (PR #20654) Date: Mon, 06 Oct 2025 13:30:37 -0000 Message-ID: <175975743841.65.5931684494133012869@bf249f23a2c8> (raw) PR #20654 opened by Zhao Zhili (quink) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20654 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20654.patch >From ab6fd7a273b88080e878c0c6dcf5e956cbff026e Mon Sep 17 00:00:00 2001 From: Zhao Zhili <zhilizhao@tencent.com> Date: Mon, 6 Oct 2025 13:41:16 +0800 Subject: [PATCH 1/3] avutil/cpu: add CPU feature flag for arm crc32 --- libavutil/aarch64/cpu.c | 5 +++++ libavutil/cpu.c | 1 + libavutil/cpu.h | 1 + libavutil/tests/cpu.c | 1 + 4 files changed, 8 insertions(+) diff --git a/libavutil/aarch64/cpu.c b/libavutil/aarch64/cpu.c index e82c0f19ab..de0d709062 100644 --- a/libavutil/aarch64/cpu.c +++ b/libavutil/aarch64/cpu.c @@ -24,6 +24,7 @@ #include <stdint.h> #include <sys/auxv.h> +#define HWCAP_AARCH64_CRC32 (1 << 7) #define HWCAP_AARCH64_ASIMDDP (1 << 20) #define HWCAP_AARCH64_SVE (1 << 22) #define HWCAP2_AARCH64_SVE2 (1 << 1) @@ -36,6 +37,8 @@ static int detect_flags(void) unsigned long hwcap = ff_getauxval(AT_HWCAP); unsigned long hwcap2 = ff_getauxval(AT_HWCAP2); + if (hwcap & HWCAP_AARCH64_CRC32) + flags |= AV_CPU_FLAG_CRC32; if (hwcap & HWCAP_AARCH64_ASIMDDP) flags |= AV_CPU_FLAG_DOTPROD; if (hwcap & HWCAP_AARCH64_SVE) @@ -67,6 +70,8 @@ static int detect_flags(void) flags |= AV_CPU_FLAG_DOTPROD; if (have_feature("hw.optional.arm.FEAT_I8MM")) flags |= AV_CPU_FLAG_I8MM; + if (have_feature("hw.optional.armv8_crc32")) + flags |= AV_CPU_FLAG_CRC32; return flags; } diff --git a/libavutil/cpu.c b/libavutil/cpu.c index 8f9b785ebc..d9753d58fa 100644 --- a/libavutil/cpu.c +++ b/libavutil/cpu.c @@ -186,6 +186,7 @@ int av_parse_cpu_caps(unsigned *flags, const char *s) { "i8mm", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_I8MM }, .unit = "flags" }, { "sve", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SVE }, .unit = "flags" }, { "sve2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SVE2 }, .unit = "flags" }, + { "crc32", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_CRC32 }, .unit = "flags" }, #elif ARCH_MIPS { "mmi", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMI }, .unit = "flags" }, { "msa", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MSA }, .unit = "flags" }, diff --git a/libavutil/cpu.h b/libavutil/cpu.h index 5ef5da58eb..11d7e13b99 100644 --- a/libavutil/cpu.h +++ b/libavutil/cpu.h @@ -74,6 +74,7 @@ #define AV_CPU_FLAG_I8MM (1 << 9) #define AV_CPU_FLAG_SVE (1 <<10) #define AV_CPU_FLAG_SVE2 (1 <<11) +#define AV_CPU_FLAG_CRC32 (1 <<12) #define AV_CPU_FLAG_SETEND (1 <<16) #define AV_CPU_FLAG_MMI (1 << 0) diff --git a/libavutil/tests/cpu.c b/libavutil/tests/cpu.c index fd2e32901d..a5058f891e 100644 --- a/libavutil/tests/cpu.c +++ b/libavutil/tests/cpu.c @@ -48,6 +48,7 @@ static const struct { { AV_CPU_FLAG_I8MM, "i8mm" }, { AV_CPU_FLAG_SVE, "sve" }, { AV_CPU_FLAG_SVE2, "sve2" }, + { AV_CPU_FLAG_CRC32, "crc32" }, #elif ARCH_ARM { AV_CPU_FLAG_ARMV5TE, "armv5te" }, { AV_CPU_FLAG_ARMV6, "armv6" }, -- 2.49.1 >From cbdcdff2b87a05f21e477aa686b79ff49ce64f23 Mon Sep 17 00:00:00 2001 From: Zhao Zhili <zhilizhao@tencent.com> Date: Mon, 6 Oct 2025 17:19:05 +0800 Subject: [PATCH 2/3] avutil/crc: use arm64 crc32 instruction On rpi5 A76 crc_32_ieee_le_c: 23410.8 ( 1.00x) crc_32_ieee_le_crc32: 1072.7 (21.82x) On RK3566 A55 crc_32_ieee_le_c: 28778.8 ( 1.00x) crc_32_ieee_le_crc32: 2625.8 (10.96x) --- doc/APIchanges | 3 ++ libavutil/aarch64/Makefile | 4 ++- libavutil/aarch64/crc.S | 43 ++++++++++++++++++++++++++ libavutil/aarch64/crc_init.c | 36 ++++++++++++++++++++++ libavutil/crc.c | 29 +++++++++++++++++- libavutil/crc.h | 25 ++++++++++++++++ libavutil/crc_internal.h | 28 +++++++++++++++++ libavutil/version.h | 2 +- tests/checkasm/Makefile | 1 + tests/checkasm/checkasm.c | 2 ++ tests/checkasm/checkasm.h | 1 + tests/checkasm/hash.c | 58 ++++++++++++++++++++++++++++++++++++ 12 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 libavutil/aarch64/crc.S create mode 100644 libavutil/aarch64/crc_init.c create mode 100644 libavutil/crc_internal.h create mode 100644 tests/checkasm/hash.c diff --git a/doc/APIchanges b/doc/APIchanges index 6e7f5d2037..38e8d3f403 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28 API changes, most recent first: +2025-10-xx - xxxxxxxxxx - lavu 60.14.100 - crc.h + Add av_crc_get and av_crc2 for ASM optimization. + 2025-08-xx - xxxxxxxxxx - lavf 62.6.100 - oggparsevorbis.h oggparseopus.h oggparseflac.h Drop header packets from secondary chained ogg/{flac, opus, vorbis} streams from demuxer output. diff --git a/libavutil/aarch64/Makefile b/libavutil/aarch64/Makefile index 992e95e4df..825836831d 100644 --- a/libavutil/aarch64/Makefile +++ b/libavutil/aarch64/Makefile @@ -1,8 +1,10 @@ OBJS += aarch64/cpu.o \ + aarch64/crc_init.o \ aarch64/float_dsp_init.o \ aarch64/tx_float_init.o \ -NEON-OBJS += aarch64/float_dsp_neon.o \ +NEON-OBJS += aarch64/crc.o \ + aarch64/float_dsp_neon.o \ aarch64/tx_float_neon.o \ SVE-OBJS += aarch64/cpu_sve.o \ diff --git a/libavutil/aarch64/crc.S b/libavutil/aarch64/crc.S new file mode 100644 index 0000000000..bca7a89c30 --- /dev/null +++ b/libavutil/aarch64/crc.S @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Zhao Zhili <quinkblack@foxmail.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 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 "asm.S" + +function ff_crc32_aarch64, export=1 + bic x5, x3, #15 + and x4, x3, #15 + mov w0, w1 + cbz x5, 2f +1: + ldp x6, x7, [x2], #16 + subs x5, x5, #16 + crc32x w0, w0, x6 + crc32x w0, w0, x7 + b.ne 1b +2: + cbz x4, 4f +3: + ldrb w5, [x2], #1 + subs x4, x4, #1 + crc32b w0, w0, w5 + b.ne 3b +4: + ret +endfunc diff --git a/libavutil/aarch64/crc_init.c b/libavutil/aarch64/crc_init.c new file mode 100644 index 0000000000..a5a79f67e8 --- /dev/null +++ b/libavutil/aarch64/crc_init.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Zhao Zhili <quinkblack@foxmail.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 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 "libavutil/aarch64/cpu.h" +#include "libavutil/attributes.h" +#include "libavutil/crc_internal.h" + +uint32_t ff_crc32_aarch64(const AVCRC *crctab, uint32_t crc, + const uint8_t *buffer, size_t length); + +av_cold void ff_crc_get_aarch64(AVCRCId crc_id, AVCRCCtx *ctx) +{ + if (crc_id != AV_CRC_32_IEEE_LE) + return; + + int cpu_flags = av_get_cpu_flags(); + if (cpu_flags & AV_CPU_FLAG_CRC32) + ctx->fn = ff_crc32_aarch64; +} diff --git a/libavutil/crc.c b/libavutil/crc.c index 703b56f4e0..2bc45c2a76 100644 --- a/libavutil/crc.c +++ b/libavutil/crc.c @@ -23,7 +23,7 @@ #include "thread.h" #include "avassert.h" #include "bswap.h" -#include "crc.h" +#include "crc_internal.h" #include "error.h" #if CONFIG_HARDCODED_TABLES @@ -413,3 +413,30 @@ uint32_t av_crc(const AVCRC *ctx, uint32_t crc, return crc; } + +int av_crc_get(AVCRCId crc_id, AVCRCCtx *ctx) +{ + if (!ctx) + return AVERROR(EINVAL); + + ctx->crctab = NULL; + ctx->fn = NULL; +#if ARCH_AARCH64 + ff_crc_get_aarch64(crc_id, ctx); +#endif + if (ctx->fn) + return 0; + + ctx->crctab = av_crc_get_table(crc_id); + if (!ctx->crctab) + return AVERROR_BUG; + ctx->fn = av_crc; + + return 0; +} + +uint32_t av_crc2(AVCRCCtx *ctx, uint32_t crc, + const uint8_t *buffer, size_t length) +{ + return ctx->fn(ctx->crctab, crc, buffer, length); +} diff --git a/libavutil/crc.h b/libavutil/crc.h index 7f59812a18..0c544b53bb 100644 --- a/libavutil/crc.h +++ b/libavutil/crc.h @@ -57,6 +57,12 @@ typedef enum { AV_CRC_MAX, /*< Not part of public API! Do not use outside libavutil. */ }AVCRCId; +typedef struct AVCRCCtx { + const AVCRC *crctab; + uint32_t (*fn)(const AVCRC *crctab, uint32_t crc, const uint8_t *buffer, + size_t length); +} AVCRCCtx; + /** * Initialize a CRC table. * @param ctx must be an array of size sizeof(AVCRC)*257 or sizeof(AVCRC)*1024 @@ -95,6 +101,25 @@ const AVCRC *av_crc_get_table(AVCRCId crc_id); uint32_t av_crc(const AVCRC *ctx, uint32_t crc, const uint8_t *buffer, size_t length) av_pure; +/** + * Get a AVCRCCtx depends on AVCRCId + * @param crc_id ID of a standard CRC + * @param ctx AVCRCCtx which will be set + * @return < 0 on failure + */ +int av_crc_get(AVCRCId crc_id, AVCRCCtx *ctx); + +/** + * Calculate the CRC of a block. + * @param ctx AVCRCCtx get from av_crc_get() + * @param crc CRC of previous blocks if any or initial value for CRC + * @param buffer buffer whose CRC to calculate + * @param length length of the buffer + * @return CRC updated with the data from the given block + */ +uint32_t av_crc2(AVCRCCtx *ctx, uint32_t crc, + const uint8_t *buffer, size_t length) av_pure; + /** * @} */ diff --git a/libavutil/crc_internal.h b/libavutil/crc_internal.h new file mode 100644 index 0000000000..4b0d020f28 --- /dev/null +++ b/libavutil/crc_internal.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Zhao Zhili <quinkblack@foxmail.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 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. + */ + +#ifndef AVUTIL_CRC_INTERNAL_H +#define AVUTIL_CRC_INTERNAL_H + +#include "libavutil/crc.h" + +void ff_crc_get_aarch64(AVCRCId crc_id, AVCRCCtx *ctx); + +#endif // AVUTIL_CRC_INTERNAL_H diff --git a/libavutil/version.h b/libavutil/version.h index 1099715076..176b99aef3 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -79,7 +79,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 60 -#define LIBAVUTIL_VERSION_MINOR 13 +#define LIBAVUTIL_VERSION_MINOR 14 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ diff --git a/tests/checkasm/Makefile b/tests/checkasm/Makefile index 1589a15e2f..a255c8e742 100644 --- a/tests/checkasm/Makefile +++ b/tests/checkasm/Makefile @@ -85,6 +85,7 @@ CHECKASMOBJS-$(CONFIG_SWSCALE) += $(SWSCALEOBJS) # libavutil tests AVUTILOBJS += aes.o AVUTILOBJS += av_tx.o +AVUTILOBJS += hash.o AVUTILOBJS += fixed_dsp.o AVUTILOBJS += float_dsp.o AVUTILOBJS += lls.o diff --git a/tests/checkasm/checkasm.c b/tests/checkasm/checkasm.c index e59d366f2b..b225259443 100644 --- a/tests/checkasm/checkasm.c +++ b/tests/checkasm/checkasm.c @@ -320,6 +320,7 @@ static const struct { #endif #if CONFIG_AVUTIL { "aes", checkasm_check_aes }, + { "hash", checkasm_check_hash }, { "fixed_dsp", checkasm_check_fixed_dsp }, { "float_dsp", checkasm_check_float_dsp }, { "lls", checkasm_check_lls }, @@ -341,6 +342,7 @@ static const struct { { "I8MM", "i8mm", AV_CPU_FLAG_I8MM }, { "SVE", "sve", AV_CPU_FLAG_SVE }, { "SVE2", "sve2", AV_CPU_FLAG_SVE2 }, + { "CRC32", "crc32", AV_CPU_FLAG_CRC32 }, #elif ARCH_ARM { "ARMV5TE", "armv5te", AV_CPU_FLAG_ARMV5TE }, { "ARMV6", "armv6", AV_CPU_FLAG_ARMV6 }, diff --git a/tests/checkasm/checkasm.h b/tests/checkasm/checkasm.h index eda806e870..6f24158bf4 100644 --- a/tests/checkasm/checkasm.h +++ b/tests/checkasm/checkasm.h @@ -105,6 +105,7 @@ void checkasm_check_h264chroma(void); void checkasm_check_h264dsp(void); void checkasm_check_h264pred(void); void checkasm_check_h264qpel(void); +void checkasm_check_hash(void); void checkasm_check_hevc_add_res(void); void checkasm_check_hevc_deblock(void); void checkasm_check_hevc_idct(void); diff --git a/tests/checkasm/hash.c b/tests/checkasm/hash.c new file mode 100644 index 0000000000..5169636ef1 --- /dev/null +++ b/tests/checkasm/hash.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025 Zhao Zhili <quinkblack@foxmail.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 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 "checkasm.h" +#include "libavutil/crc.h" + +#define BUF_SIZE (8192 + 11) + +static void check_crc(void) +{ + uint8_t buf[BUF_SIZE]; + + for (int i = 0; i < sizeof(buf); i++) + buf[i] = rnd(); + + AVCRCCtx ctx; + uint32_t crc0 = UINT32_MAX; + uint32_t crc1 = UINT32_MAX; + av_crc_get(AV_CRC_32_IEEE_LE, &ctx); + + declare_func(uint32_t, const AVCRC *crctab, uint32_t crc, + const uint8_t *buffer, size_t length); + /* Leave crctab as NULL is an optimization for real usecase, but doesn't + * work with call_ref. + */ + if (!ctx.crctab) + ctx.crctab = av_crc_get_table(AV_CRC_32_IEEE_LE); + if (check_func(ctx.fn, "crc_32_ieee_le")) { + crc0 = call_ref(ctx.crctab, crc0, buf, sizeof(buf)); + crc1 = call_new(ctx.crctab, crc1, buf, sizeof(buf)); + if (crc0 != crc1) + fail(); + bench_new(ctx.crctab, UINT32_MAX, buf, sizeof(buf)); + } +} + +void checkasm_check_hash(void) +{ + check_crc(); + report("crc"); +} -- 2.49.1 >From 13ba872d1039eecd0457c3e30e9d53f043ed85e9 Mon Sep 17 00:00:00 2001 From: Zhao Zhili <zhilizhao@tencent.com> Date: Mon, 6 Oct 2025 18:41:02 +0800 Subject: [PATCH 3/3] avutil/hash: Use new crc API --- libavutil/hash.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/libavutil/hash.c b/libavutil/hash.c index fbc24194de..b29de10551 100644 --- a/libavutil/hash.c +++ b/libavutil/hash.c @@ -66,7 +66,7 @@ enum hashtype { typedef struct AVHashContext { void *ctx; enum hashtype type; - const AVCRC *crctab; + AVCRCCtx crcctx; uint32_t crc; } AVHashContext; @@ -137,7 +137,14 @@ int av_hash_alloc(AVHashContext **ctx, const char *name) case SHA512_256: case SHA384: case SHA512: res->ctx = av_sha512_alloc(); break; - case CRC32: res->crctab = av_crc_get_table(AV_CRC_32_IEEE_LE); break; + case CRC32: { + int err = av_crc_get(AV_CRC_32_IEEE_LE, &res->crcctx); + if (err < 0) { + av_free(res); + return err; + } + } + break; case ADLER32: break; } if (i != ADLER32 && i != CRC32 && !res->ctx) { @@ -185,7 +192,7 @@ void av_hash_update(AVHashContext *ctx, const uint8_t *src, size_t len) case SHA512_256: case SHA384: case SHA512: av_sha512_update(ctx->ctx, src, len); break; - case CRC32: ctx->crc = av_crc(ctx->crctab, ctx->crc, src, len); break; + case CRC32: ctx->crc = av_crc2(&ctx->crcctx, ctx->crc, src, len); break; case ADLER32: ctx->crc = av_adler32_update(ctx->crc, src, len); break; } } -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
next reply other threads:[~2025-10-06 13:31 UTC|newest] Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top 2025-10-06 13:30 Zhao Zhili via ffmpeg-devel [this message] 2025-10-08 9:45 ` [FFmpeg-devel] " Kieran Kunhya via ffmpeg-devel
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=175975743841.65.5931684494133012869@bf249f23a2c8 \ --to=ffmpeg-devel@ffmpeg.org \ --cc=code@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror http://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ http://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git