ffmpeg 中 crc32 源码分析及调试
author: hjjdebug
date: 2025年 08月 22日 星期五 13:18:50 CST
descrip: ffmpeg 中 crc32 源码分析及调试
文章目录
- 1. 前言
- 2. 代码:
- 3. 测试代码执行结果.
1. 前言
看一看ffmpeg 中crc32 到底是怎样实现的.
其代码在libavformat/crc.c 中,
单纯阅读库代码不能深刻理解其含义, 而且其中又包含一些宏,不易理解.
所以我去掉了它的宏, 抽取了其结构定义部分. 形成一个独立的,最简单的代码形式,
同时也保留了原来的架构. 这样我们就能调试了.
代码实现了最常用的crc32 计算,
同时也极易实现其它多项式构成的crc. 限于篇幅这部分就不列了.
2. 代码:
$ cat main.c
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// #include <libavutil/crc.h> //外部头文件,库文件都可以去掉了,这是一个完整的代码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,AV_CRC_16_ANSI_LE,AV_CRC_24_IEEE,AV_CRC_8_EBU,AV_CRC_MAX,
} AVCRCId;static AVCRC av_crc_table[AV_CRC_MAX][1024]; //保留了这个大的table 表,对实验而言,留一个就够了
static pthread_once_t AV_CRC_32_IEEE_once_control = 0;static inline uint32_t av_bswap32(uint32_t x) //颠倒32bits 数据位置
{return ((((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) << 16 | ((((x) >> 16) << 8 & 0xff00) | (((x) >> 16) >> 8 & 0x00ff)));
}// 初始化table 过程, AVCRC 是uint32_t
// 输入参数: le,为假
// bits:32
// poly:0x04c11db7
// ctx_size:1024*4
//输出参数: ctx. table 指针 , 这个表格也可以用数组直接定义,就不用计算了.
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)) // bits <8 或 >32 是非法的.return (-(22));if (ctx_size != sizeof(AVCRC) * 257 && ctx_size != sizeof(AVCRC) * 1024) // ctx_size 就是1024*4return (-(22));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{ //建表过程, 256项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; //第257项if (ctx_size >= (int)sizeof(AVCRC) * 1024) // 大表,还要初始化另外3个部分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];return 0; //返回0为成功
}static void AV_CRC_32_IEEE_init_table_once(void)
{do{if (!(av_crc_init(av_crc_table[AV_CRC_32_IEEE], 0, 32, 0x04C11DB7, sizeof(av_crc_table[AV_CRC_32_IEEE])) >= 0)){printf("failed\n");}} while (0);
}
// 向table 中填充数据
// 保留了原来的架构, 为了保证 AV_CRC_8_EBU_init_table_once只会被执行一次
const AVCRC* av_crc_get_table(AVCRCId crc_id)
{switch (crc_id){ //把注释留在这, 其它的crc 元素将来也可以扩充使用// case AV_CRC_8_ATM: pthread_once(&AV_CRC_8_ATM_once_control, AV_CRC_8_ATM_init_table_once); break;// case AV_CRC_8_EBU: pthread_once(&AV_CRC_8_EBU_once_control, AV_CRC_8_EBU_init_table_once); break;// case AV_CRC_16_ANSI: pthread_once(&AV_CRC_16_ANSI_once_control, AV_CRC_16_ANSI_init_table_once); break;// case AV_CRC_16_CCITT: pthread_once(&AV_CRC_16_CCITT_once_control, AV_CRC_16_CCITT_init_table_once); break;// case AV_CRC_24_IEEE: pthread_once(&AV_CRC_24_IEEE_once_control, AV_CRC_24_IEEE_init_table_once); break;case AV_CRC_32_IEEE:pthread_once(&AV_CRC_32_IEEE_once_control, AV_CRC_32_IEEE_init_table_once);break;// case AV_CRC_32_IEEE_LE: pthread_once(&AV_CRC_32_IEEE_LE_once_control, AV_CRC_32_IEEE_LE_init_table_once); break;// case AV_CRC_16_ANSI_LE: pthread_once(&AV_CRC_16_ANSI_LE_once_control, AV_CRC_16_ANSI_LE_init_table_once); break;default:printf("not handle it for simple\n");exit(0);}return 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 (!ctx[256]){while (((intptr_t)buffer & 3) && buffer < end) //buffer 指针一般是4字节对齐的crc = ctx[((uint8_t)crc) ^ *buffer++] ^ (crc >> 8);while (buffer < end - 3){crc ^= (*(const uint32_t*)buffer); //crc 与数据异或buffer += 4; //指针加4//crc 与表格中的4个项异或生成新的crccrc = ctx[3 * 256 + (crc & 0xFF)]^ ctx[2 * 256 + ((crc >> 8) & 0xFF)]^ ctx[1 * 256 + ((crc >> 16) & 0xFF)]^ ctx[0 * 256 + ((crc >> 24))];}}//单字节运算最后几个byte//crc 与数据异或,从表格中取到数据,再与crc>>8异或来更新crcwhile (buffer < end)crc = ctx[((uint8_t)crc) ^ *buffer++] ^ (crc >> 8);return crc;
}
static unsigned crc32(const uint8_t* data, unsigned size)
{return av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, data, size);
}
const unsigned char* str = (unsigned char*)"hello world";
int main()
{int len = strlen((char*)str);unsigned int crc = crc32(str, len);printf("crc32:%04x\n", crc);return 0;
}
3. 测试代码执行结果.
$ ./tt
crc32:aef27a73