PR #21108 opened by Lynne URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21108 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21108.patch
This commit adds a new function pointer based API for CRC. The CRC code is some of the oldest in the entire codebase. Despite CRC instructions existing on most CPUs back when it was written, it did not implement support for them, nor even 64-bit CRCs. Our TTA decoder even NIHs its own 64-bit CRC just because the API is simply not capable of it! Attempts to use architecture-specific CRCs remain blocked on this. The new API is much simpler, implementation-wise. It was copied verbatim from the lavu/tx API. There will be no support for hardcoded tables: users are already expected to keep state (the function pointer), and they'll have to init a context. We'll make the old code a wrapper for the new if this is accepted, and we'll get rid of hardcoded tables to save space. Ref: #20751 >From 5dfa403995e97f1aba251b19d1d39cca6bf0a6f4 Mon Sep 17 00:00:00 2001 From: Lynne <[email protected]> Date: Fri, 5 Dec 2025 10:07:59 +0100 Subject: [PATCH] lavu/crc: add a function pointer based API This commit adds a new function pointer based API for CRC. The CRC code is some of the oldest in the entire codebase. Despite CRC instructions existing on most CPUs back when it was written, it did not implement support for them, nor even 64-bit CRCs. Our TTA decoder even NIHs its own 64-bit CRC just because the API is simply not capable of it! Attempts to use architecture-specific CRCs remain blocked on this. The new API is much simpler, implementation-wise. It was copied verbatim from the lavu/tx API. There will be no support for hardcoded tables: users are already expected to keep state (the function pointer), and they'll have to init a context. We'll make the old code a wrapper for the new if this is accepted, and we'll get rid of hardcoded tables to save space. --- libavutil/crc.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ libavutil/crc.h | 60 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 131 insertions(+), 1 deletion(-) diff --git a/libavutil/crc.c b/libavutil/crc.c index 703b56f4e0..ac1186795b 100644 --- a/libavutil/crc.c +++ b/libavutil/crc.c @@ -25,6 +25,7 @@ #include "bswap.h" #include "crc.h" #include "error.h" +#include "mem.h" #if CONFIG_HARDCODED_TABLES static const AVCRC av_crc_table[AV_CRC_MAX][257] = { @@ -413,3 +414,74 @@ uint32_t av_crc(const AVCRC *ctx, uint32_t crc, return crc; } + +struct CRCPreset { + uint64_t poly; + int bits; + int le; +} crc_presets[AV_CRC_MAX] = { + [AV_CRC_8_ATM] = { 0x07, 8, 0 }, + [AV_CRC_8_EBU] = { 0x1D, 8, 0 }, + [AV_CRC_16_ANSI] = { 0x8005, 16, 0 }, + [AV_CRC_16_ANSI_LE] = { 0xA001, 16, 1 }, + [AV_CRC_16_CCITT] = { 0x1021, 16, 0 }, + [AV_CRC_24_IEEE] = { 0x864CFB, 24, 0 }, + [AV_CRC_32_IEEE] = { 0x04C11DB7, 32, 0 }, + [AV_CRC_32_IEEE_LE] = { 0xEDB88320, 32, 1 }, +}; + +void av_crc_preset(AVCRCId crc, uint64_t *poly, int *bits, int *le) +{ + if (crc >= AV_CRC_MAX) { + *poly = *bits = *le = 0; + return; + } + + *poly = crc_presets[crc].poly; + *bits = crc_presets[crc].bits; + *le = crc_presets[crc].le; +} + +static uint64_t av_crc_wrapper(const uint8_t *ctx, uint64_t crc, + const uint8_t *buffer, size_t length) +{ + return av_crc((const AVCRC *)ctx, crc, buffer, length); +} + +int av_crc2_init(uint8_t **ctx, av_crc_fn *fn, + uint64_t poly, int bits, enum AVCRCFlags flags) +{ + *ctx = av_malloc(4096); + if (!(*ctx)) + return AVERROR(ENOMEM); + + int err = av_crc_init((uint32_t *)(*ctx), flags & AV_CRC_FLAG_LE, + bits, poly, 4096); + if (err < 0) { + av_freep(ctx); + return err; + } + + *fn = av_crc_wrapper; + + return 0; +} + +uint64_t av_crc_calc(AVCRCId crc_id, uint64_t crc, + uint8_t *buffer, size_t length) +{ + uint64_t poly; + int bits, le; + av_crc_preset(crc_id, &poly, &bits, &le); + if (!poly) + return 0; + + uint8_t *ctx; + av_crc_fn fn; + av_crc2_init(&ctx, &fn, poly, bits, + AV_CRC_FLAG_UNALIGNED | (le ? AV_CRC_FLAG_LE : 0)); + + crc = fn(ctx, crc, buffer, length); + av_free(&ctx); + return crc; +} diff --git a/libavutil/crc.h b/libavutil/crc.h index 7f59812a18..c8a51c0c9b 100644 --- a/libavutil/crc.h +++ b/libavutil/crc.h @@ -90,11 +90,69 @@ const AVCRC *av_crc_get_table(AVCRCId crc_id); * @param length length of the buffer * @return CRC updated with the data from the given block * - * @see av_crc_init() "le" parameter +x * @see av_crc_init() "le" parameter */ uint32_t av_crc(const AVCRC *ctx, uint32_t crc, const uint8_t *buffer, size_t length) av_pure; +/** + * Function pointer to a function to perform a round of CRC calculations on a buffer. + * + * @note Using a different context than the one allocated during av_crc2_init() + * is not allowed. + * + * @param ctx the transform context + * @param crc the current CRC state + * @param buffer the buffer on which to perform CRC + * @param length the length of the buffer + * + * The buffer array must be aligned to the maximum required by the CPU + * architecture unless the AV_CRC_UNALIGNED flag was set in av_crc2_init(). + */ +typedef uint64_t (*av_crc_fn)(const uint8_t *ctx, uint64_t crc, + const uint8_t *buffer, size_t length); + +/** + * Get the parameters of a common CRC algorithm. + */ +void av_crc_preset(AVCRCId crc, uint64_t *poly, int *bits, int *le); + +enum AVCRCFlags { + /** + * Specifies that the pointer to perform the CRC on is not guaranteed to be aligned. + */ + AV_CRC_FLAG_UNALIGNED = 1 << 0, + + /** + * The lowest bit represents the coefficient for the highest + * exponent of the corresponding polynomial (both for poly and actual CRC). + * If set, you must bitswap the CRC parameter and the result of av_crc_fn + * if you need the standard representation (can be simplified in + * most cases to e.g. bswap16): + * av_bswap32(crc << (32-bits)) + */ + AV_CRC_FLAG_LE = 1 << 1, +}; + +/** + * Initialize a context and a function pointer for a CRC algorithm. + * + * @param ctx a pointer to where a CRC context will be set + * NOTE: must be freed using av_free() + * @param fn a function pointer where the function to perform a CRC will be set + * @param bits the length of the polynomial + * @param poly the polynomial for the CRC + * @param flags the set of flags to use + */ +int av_crc2_init(uint8_t **ctx, av_crc_fn *fn, + uint64_t poly, int bits, enum AVCRCFlags flags); + +/** + * Convenience wrapper function to perform a well-known CRC algorithm on a function. + * Guaranteed to not require new allocations. + */ +uint64_t av_crc_calc(AVCRCId crc_id, uint64_t crc, uint8_t *buffer, size_t length); + /** * @} */ -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
