网站建设战略合作方案,友情链接添加在网站中有什么用,WordPress高级版破解,中国建设招投标网一、CRC简介
CRC(Cyclic Redundancy Check)#xff0c;即循环冗余校验#xff0c;是一种根据网络数据包或电脑文件等数据产生简短固定位数校核码的快速算法#xff0c;主要用来检测或校核数据传输或者保存后可能出现的错误。CRC利用除法及余数的原理#xff0c;实现错误侦…一、CRC简介
CRC(Cyclic Redundancy Check)即循环冗余校验是一种根据网络数据包或电脑文件等数据产生简短固定位数校核码的快速算法主要用来检测或校核数据传输或者保存后可能出现的错误。CRC利用除法及余数的原理实现错误侦测的功能具有原理清晰、实现简单等优点。注意CRC校验只能对数据进行检错而不能对其纠错。因此在CAN总线上的每个节点一旦发现数据有错CAN控制器会根据总线仲裁原则和受损报文优先发送原则对已损坏的报文进行自动重传。具体可以参考《百度百科——CRC》。 二、CRC校验原理
可以参考《CRC校验原理及实现》、《什么是CRC循环冗余校验是如何对数据进行计算的》、《CRC码计算及校验原理的最通俗诠释》等文章。 三、CRC8/CRC16/CRC32
常见的CRC校验类型有CRC8/CRC16/CRC32。其中
CRC8一种较短的CRC校验类型其生成的校验码由8比特组成即一个字节。这意味着它能提供的唯一校验结果数量为2^8256种。
CRC16相较于CRC8CRC16提供了更强的错误检测能力其生成的校验码由16比特构成对应于2^16种不同的校验值。这种扩展提高了算法对单比特错误以及一定长度突发错误序列的检测概率。
CRC32位于CRC系列顶端的是CRC32它产生的校验码有32比特可形成2^32种不同组合。这种级别的CRC校验尤其适用于大数据传输、高可靠性要求的数据完整性保证场合如ISO 9660文件系统、ZIP压缩文件格式以及TCP/IP协议栈中的IP头校验等。
具体可以参考《CRC8/CRC16/CRC32全面对比详解》。 四、FFmpeg源码中计算CRC校验的实现
FFmpeg源码中通过av_crc函数计算CRC校验该函数定义在libavutil/crc.c中
/*** Calculate the CRC of a block.* param ctx initialized AVCRC array (see av_crc_init())* 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** see av_crc_init() le parameter*/
uint32_t av_crc(const AVCRC *ctx, uint32_t crc,const uint8_t *buffer, size_t length)
{const uint8_t *end buffer length;#if !CONFIG_SMALLif (!ctx[256]) {while (((intptr_t) buffer 3) buffer end)crc ctx[((uint8_t) crc) ^ *buffer] ^ (crc 8);while (buffer end - 3) {crc ^ av_le2ne32(*(const uint32_t *) buffer); buffer 4;crc ctx[3 * 256 ( crc 0xFF)] ^ctx[2 * 256 ((crc 8 ) 0xFF)] ^ctx[1 * 256 ((crc 16) 0xFF)] ^ctx[0 * 256 ((crc 24) )];}}
#endifwhile (buffer end)crc ctx[((uint8_t) crc) ^ *buffer] ^ (crc 8);return crc;
} 形参ctx输入型参数指向通过av_crc_get_table函数获取到的CRC table即初始化的AVCRC数组。
形参crc输入型参数先前块的CRC如果有的话或CRC的初始值。
形参buffer输入型参数指向缓冲区的指针该缓冲区存放要计算其CRC校验的数据。
形参length输入型参数形参buffer指向的缓冲区的长度单位为字节。
返回值计算出来的CRC校验。 五、av_crc函数的使用例子
一通过av_crc函数计算CRC校验
需要校验的数据如下以十六进制表示总共28个字节数据
02 B0 1D 00 01 C1 00 00 E1 00 F0 00 1B E1 00 F0 00 0F E1 01 F0 06 0A 04 75 6E 64 00 以参数模型为CRC-32/MPEG-2为例通过 CRC循环冗余校验在线计算 得出上面数据的CRC校验为0x080x7D0xE80x77 把FFmpeg中CRC相关的函数移植出来编写测试例子main.cpp
#include stdio.h
#include stdint.h
//#include stdint-uintn.h#ifdef __GNUC__
# define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ (x) || __GNUC__ (x) __GNUC_MINOR__ (y))
# define AV_GCC_VERSION_AT_MOST(x,y) (__GNUC__ (x) || __GNUC__ (x) __GNUC_MINOR__ (y))
#else
# define AV_GCC_VERSION_AT_LEAST(x,y) 0
# define AV_GCC_VERSION_AT_MOST(x,y) 0
#endif#if AV_GCC_VERSION_AT_LEAST(2,6) || defined(__clang__)
# define av_const __attribute__((const))
#else
# define av_const
#endif#ifndef av_always_inline
#if AV_GCC_VERSION_AT_LEAST(3,1)
# define av_always_inline __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
# define av_always_inline __forceinline
#else
# define av_always_inline inline
#endif
#endif#define AV_BSWAP16C(x) (((x) 8 0xff00) | ((x) 8 0x00ff))
#define AV_BSWAP32C(x) (AV_BSWAP16C(x) 16 | AV_BSWAP16C((x) 16))
#define AV_BSWAP64C(x) (AV_BSWAP32C(x) 32 | AV_BSWAP32C((x) 32))#define AVOnce char
#define AV_ONCE_INIT 0static inline int ff_thread_once(char *control, void (*routine)(void))
{if (!*control) {routine();*control 1;}return 0;
}#define EINVAL 22 /* Invalid argument */
#define AVERROR(e) (-(e)) /// Returns a negative error code from a POSIX error code, to return from library functions.#define CRC_TABLE_SIZE 1024#define av_le2ne32(x) (x)typedef uint32_t AVCRC;typedef enum {AV_CRC_8_ATM,AV_CRC_16_ANSI,AV_CRC_16_CCITT,AV_CRC_32_IEEE,AV_CRC_32_IEEE_LE, /* reversed bitorder version of AV_CRC_32_IEEE */AV_CRC_16_ANSI_LE, /* reversed bitorder version of AV_CRC_16_ANSI */AV_CRC_24_IEEE,AV_CRC_8_EBU,AV_CRC_MAX, /* Not part of public API! Do not use outside libavutil. */
}AVCRCId;static AVCRC av_crc_table[AV_CRC_MAX][CRC_TABLE_SIZE];#define DECLARE_CRC_INIT_TABLE_ONCE(id, le, bits, poly) \
static AVOnce id ## _once_control AV_ONCE_INIT; \
static void id ## _init_table_once(void) \
{ \av_crc_init(av_crc_table[id], le, bits, poly, sizeof(av_crc_table[id])); \
}#ifndef av_bswap32
static av_always_inline av_const uint32_t av_bswap32(uint32_t x)
{return AV_BSWAP32C(x);
}
#endif#define CRC_INIT_TABLE_ONCE(id) ff_thread_once(id ## _once_control, id ## _init_table_once)DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_8_ATM, 0, 8, 0x07)
DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_8_EBU, 0, 8, 0x1D)
DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI, 0, 16, 0x8005)
DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_16_CCITT, 0, 16, 0x1021)
DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_24_IEEE, 0, 24, 0x864CFB)
DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE, 0, 32, 0x04C11DB7)
DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE_LE, 1, 32, 0xEDB88320)
DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI_LE, 1, 16, 0xA001)int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size)
{unsigned i, j;uint32_t c;if (bits 8 || bits 32 || poly (1LL bits))return AVERROR(EINVAL);if (ctx_size ! sizeof(AVCRC) * 257 ctx_size ! sizeof(AVCRC) * 1024)return AVERROR(EINVAL);for (i 0; i 256; i) {if (le) {for (c i, j 0; j 8; j)c (c 1) ^ (poly (-(c 1)));ctx[i] c;} else {for (c i 24, j 0; j 8; j)c (c 1) ^ ((poly (32 - bits)) (((int32_t) c) 31));ctx[i] av_bswap32(c);}}ctx[256] 1;
#if !CONFIG_SMALLif (ctx_size sizeof(AVCRC) * 1024)for (i 0; i 256; i)for (j 0; j 3; j)ctx[256 * (j 1) i] (ctx[256 * j i] 8) ^ ctx[ctx[256 * j i] 0xFF];
#endifreturn 0;
}const AVCRC *av_crc_get_table(AVCRCId crc_id)
{
#if !CONFIG_HARDCODED_TABLESswitch (crc_id) {case AV_CRC_8_ATM: CRC_INIT_TABLE_ONCE(AV_CRC_8_ATM); break;case AV_CRC_8_EBU: CRC_INIT_TABLE_ONCE(AV_CRC_8_EBU); break;case AV_CRC_16_ANSI: CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI); break;case AV_CRC_16_CCITT: CRC_INIT_TABLE_ONCE(AV_CRC_16_CCITT); break;case AV_CRC_24_IEEE: CRC_INIT_TABLE_ONCE(AV_CRC_24_IEEE); break;case AV_CRC_32_IEEE: CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE); break;case AV_CRC_32_IEEE_LE: CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE_LE); break;case AV_CRC_16_ANSI_LE: CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI_LE); break;default: ;}
#endifreturn av_crc_table[crc_id];
}uint32_t av_crc(const AVCRC *ctx, uint32_t crc,const uint8_t *buffer, size_t length)
{const uint8_t *end buffer length;#if !CONFIG_SMALLif (!ctx[256]) {while (((intptr_t) buffer 3) buffer end)crc ctx[((uint8_t) crc) ^ *buffer] ^ (crc 8);while (buffer end - 3) {crc ^ av_le2ne32(*(const uint32_t *) buffer); buffer 4;crc ctx[3 * 256 ( crc 0xFF)] ^ctx[2 * 256 ((crc 8 ) 0xFF)] ^ctx[1 * 256 ((crc 16) 0xFF)] ^ctx[0 * 256 ((crc 24) )];}}
#endifwhile (buffer end)crc ctx[((uint8_t) crc) ^ *buffer] ^ (crc 8);return crc;
}int main()
{uint8_t cur_section_buf[28] {0x02, 0xB0, 0x1D, 0x00, 0x01, 0xC1, 0x00, 0x00, 0xE1, 0x00, 0xF0, 0x00, 0x1B, 0xE1, 0x00, 0xF0, 0x00, 0x0F, 0xE1, 0x01, 0xF0, 0x06, 0x0A, 0x04, 0x75, 0x6E, 0x64, 0x00};int crc av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1, cur_section_buf, sizeof(cur_section_buf));printf(crc:%d\n, crc);return 0;
} 在Linux系统上编译运行打印十进制的2011725064即0x770xE8, 0x7D0x08。可以看到跟上述“CRC在线计算”的计算结果是相符的只是高低位顺序不一样而已 二通过av_crc函数判断CRC校验是否正确
av_crc函数还有一个用途是用来判断一段包含CRC校验的数据中CRC校验是否正确。我们改写上面的man.cpp uint8_t cur_section_buf[32] {0x02, 0xB0, 0x1D, 0x00, 0x01, 0xC1, 0x00, 0x00, 0xE1, 0x00, 0xF0, 0x00, 0x1B, 0xE1, 0x00, 0xF0, 0x00, 0x0F, 0xE1, 0x01, 0xF0, 0x06, 0x0A, 0x04, 0x75, 0x6E, 0x64, 0x00, 0x08, 0x7D, 0xE8, 0x77}; int crc_valid !av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1, cur_section_buf, sizeof(cur_section_buf));printf(crc_valid:%d\n, crc_valid); 重新编译运行打印“1”表示CRC校验正确打印|“0”表示校验不正确