当前位置: 首页 > news >正文

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

http://www.dtcms.com/a/344898.html

相关文章:

  • vagrant怎么在宿主机操作虚拟机里面的系统管理和软件安装
  • xilinx的oddr原语是否可以直接使用verilog实现?
  • ingress和service区别
  • 20250822解决荣品RD-RK3588-MID核心板出现插USB开机-长按RESET开机的问题
  • 基于LangChain + Milvus 实现RAG
  • 升级 Docker Compose 到最新版本:从安装到验证全指南
  • SOLIDWORKS 2025智能工具优化设计流程
  • 数据结构: 2-3 树的删除操作 (Deletion)
  • Maven的概念与Maven项目的创建
  • 线程异步操作
  • LoRA内部原理代码解析(52)
  • 【笔记】动手学Ollama 第七章 应用案例 Agent应用
  • SpringBoot项目创建的五种方式
  • 线性回归:机器学习中的基石
  • Unreal Engine UE_LOG
  • BigData大数据应用开发学习笔记(04)离线处理--离线分析Spark SQL
  • 用 Go 从零实现一个简易负载均衡器
  • SSM从入门到实战: 2.7 MyBatis与Spring集成
  • 计算机内存中的整型存储奥秘、大小端字节序及其判断方法
  • Bluedroid vs NimBLE
  • 北京-测试-入职甲方金融-上班第三天
  • AR眼镜巡检系统在工业互联网的应用:AR+IoT
  • JAVA后端开发——API状态字段设计规范与实践
  • 目标检测数据集转换为图像分类数据集
  • Pandas中的SettingWithCopyWarning警告出现原因及解决方法
  • 共享内存详细解释
  • 前端在WebSocket中加入Token的方法
  • 12-Linux系统用户管理及基础权限
  • 塞尔达传说 王国之泪 PC/手机双端 免安装中文版
  • celery