怎么自己建設(shè)網(wǎng)站品牌推廣的步驟和技巧
一、CRC簡(jiǎn)介
CRC(Cyclic Redundancy Check),即循環(huán)冗余校驗(yàn),是一種根據(jù)網(wǎng)絡(luò)數(shù)據(jù)包或電腦文件等數(shù)據(jù)產(chǎn)生簡(jiǎn)短固定位數(shù)校核碼的快速算法,主要用來(lái)檢測(cè)或校核數(shù)據(jù)傳輸或者保存后可能出現(xiàn)的錯(cuò)誤。CRC利用除法及余數(shù)的原理,實(shí)現(xiàn)錯(cuò)誤偵測(cè)的功能,具有原理清晰、實(shí)現(xiàn)簡(jiǎn)單等優(yōu)點(diǎn)。注意,CRC校驗(yàn)只能對(duì)數(shù)據(jù)進(jìn)行檢錯(cuò),而不能對(duì)其糾錯(cuò)。因此,在CAN總線上的每個(gè)節(jié)點(diǎn)一旦發(fā)現(xiàn)數(shù)據(jù)有錯(cuò),CAN控制器會(huì)根據(jù)總線仲裁原則和受損報(bào)文優(yōu)先發(fā)送原則對(duì)已損壞的報(bào)文進(jìn)行自動(dòng)重傳。具體可以參考:《百度百科——CRC》。
二、CRC校驗(yàn)原理
可以參考:《CRC校驗(yàn)原理及實(shí)現(xiàn)》、《什么是CRC循環(huán)冗余校驗(yàn),是如何對(duì)數(shù)據(jù)進(jìn)行計(jì)算的?》、《CRC碼計(jì)算及校驗(yàn)原理的最通俗詮釋》等文章。
三、CRC8/CRC16/CRC32
常見(jiàn)的CRC校驗(yàn)類(lèi)型有CRC8/CRC16/CRC32。其中:
CRC8:一種較短的CRC校驗(yàn)類(lèi)型,其生成的校驗(yàn)碼由8比特組成,即一個(gè)字節(jié)。這意味著它能提供的唯一校驗(yàn)結(jié)果數(shù)量為2^8=256種。
CRC16:相較于CRC8,CRC16提供了更強(qiáng)的錯(cuò)誤檢測(cè)能力,其生成的校驗(yàn)碼由16比特構(gòu)成,對(duì)應(yīng)于2^16種不同的校驗(yàn)值。這種擴(kuò)展提高了算法對(duì)單比特錯(cuò)誤以及一定長(zhǎng)度突發(fā)錯(cuò)誤序列的檢測(cè)概率。
CRC32:位于CRC系列頂端的是CRC32,它產(chǎn)生的校驗(yàn)碼有32比特,可形成2^32種不同組合。這種級(jí)別的CRC校驗(yàn)尤其適用于大數(shù)據(jù)傳輸、高可靠性要求的數(shù)據(jù)完整性保證場(chǎng)合,如ISO 9660文件系統(tǒng)、ZIP壓縮文件格式,以及TCP/IP協(xié)議棧中的IP頭校驗(yàn)等。
具體可以參考:《CRC8/CRC16/CRC32全面對(duì)比詳解》。
四、FFmpeg源碼中,計(jì)算CRC校驗(yàn)的實(shí)現(xiàn)
FFmpeg源碼中通過(guò)av_crc函數(shù)計(jì)算CRC校驗(yàn),該函數(shù)定義在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:輸入型參數(shù),指向通過(guò)av_crc_get_table函數(shù)獲取到的CRC table,即初始化的AVCRC數(shù)組。
形參crc:輸入型參數(shù),先前塊的CRC(如果有的話)或CRC的初始值。
形參buffer:輸入型參數(shù),指向緩沖區(qū)的指針,該緩沖區(qū)存放要計(jì)算其CRC校驗(yàn)的數(shù)據(jù)。
形參length:輸入型參數(shù),形參buffer指向的緩沖區(qū)的長(zhǎng)度,單位為字節(jié)。
返回值:計(jì)算出來(lái)的CRC校驗(yàn)。
五、av_crc函數(shù)的使用例子
(一)通過(guò)av_crc函數(shù)計(jì)算CRC校驗(yàn)
需要校驗(yàn)的數(shù)據(jù)如下(以十六進(jìn)制表示),總共28個(gè)字節(jié)數(shù)據(jù):
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
以參數(shù)模型為CRC-32/MPEG-2為例,通過(guò)?CRC(循環(huán)冗余校驗(yàn))在線計(jì)算? 得出上面數(shù)據(jù)的CRC校驗(yàn)為0x08,0x7D,0xE8,0x77:
把FFmpeg中CRC相關(guān)的函數(shù)移植出來(lái),編寫(xiě)測(cè)試?yán)觤ain.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系統(tǒng)上編譯,運(yùn)行,打印十進(jìn)制的2011725064,即0x77,0xE8, 0x7D,0x08??梢钥吹礁鲜觥癈RC在線計(jì)算”的計(jì)算結(jié)果是相符的,只是高低位順序不一樣而已:
(二)通過(guò)av_crc函數(shù)判斷CRC校驗(yàn)是否正確
av_crc函數(shù)還有一個(gè)用途是用來(lái)判斷一段包含CRC校驗(yàn)的數(shù)據(jù)中,CRC校驗(yàn)是否正確。我們改寫(xiě)上面的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);
重新編譯,運(yùn)行,打印“1”表示CRC校驗(yàn)正確,打印|“0”表示校驗(yàn)不正確: