ffmpeg 0阶哥伦布算法的详细注释及简单测试程序

$ cat main.c

/* ffmpeg 0阶哥伦布算法的详细注释及简单测试程序

* author: hjjdebug

* date: 2023年 07月 14日 星期五 15:18:11 CST

* 博客即是代码,copy 编译通过即可运行

*/

#pragma GCC diagnostic ignored "-Wunused-parameter"

#pragma GCC diagnostic ignored "-Wsign-compare"

#define SUINT unsigned

#include <libavcodec/get_bits.h>

#include <libavcodec/golomb.h>

/*

* 0价哥伦布码表

* 1 代表0

* 0 1 x 代表1,2

* 0 0 1 x x 代表3,4,5,6

* 0 0 0 1 x x x 代表7,8,9,10,11,12,13,14

* 0 0 0 0 1 x x x x 代表15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30

* ................... 忽略后面码子

* 总之,代表的实际数字是0b1x..x-1, x的个数是前导0的个数

*这个编码是哥伦布发明的,所以叫哥伦布编码表

在FFmpeg中采用了查表和计算相结合的方法来解码. 为的是加快速度

对码长不超过9比特的码字制作了ff_golomb_vlc_len和ff_ue_golomb_vlc_code直接获取码长和码字,

对码长超过9bits的码字要计算,看后面代码.

表格解释: 以读到的9bits 数据为索引, 数值也在这9bits之间(当索引大于16时)

  1. 索引1nnnnnnnn 范围[256,511],码长为1,code为0 因为后面的n我们是don't care的,长度只有1

  2. 索引01xnnnnnn 范围[128,255],码长为3,code为0b1x-1

  3. 索引001xxnnnn 范围[64,127], 码长为5,code为0b1xx-1

  4. 索引0001xxxnn 范围[32,64], 码长为7,code为0b1xxx-1

  5. 索引00001xxxx 范围[16,31], 码长为9,code为0b1xxxx-1 9bits码长,解码数值在15-30之间

  6. 索引000001xxx 范围[8,15], 码长为11,code值较大,本9bits不能容纳,给最大值32代替

  7. 索引0000001xx 范围[4,7], 码长为13,code值较大,本9bits不能容纳,给最大值32代替

  8. 索引00000001x 范围[2,3], 码长为15,code值较大,本9bits不能容纳,给最大值32代替

  9. 索引000000001 范围[1], 码长为17,code值较大,本9bits不能容纳,给最大值32代替

10.索引000000000 范围[0], 码长不确定,至少大于19位,code值较大,本9bits不能容纳,给最大值32代替

*/

const uint8_t ff_golomb_vlc_len[512]={

19,17,15,15,13,13,13,13,11,11,11,11,11,11,11,11,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,

7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,

5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,

5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,

3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,

3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,

3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,

3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,

1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,

1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,

1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,

1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,

1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,

1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,

1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,

1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

};

const uint8_t ff_ue_golomb_vlc_code[512]={

32,32,32,32,32,32,32,32,31,32,32,32,32,32,32,32,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,

7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,14,

3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,

5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,

1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,

2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

};

// 照搬ffmpeg 中的写法, 有宏,不容易搞清运算关系,不过理解了也就无所谓了.

int my_get_ue_golomb(GetBitContext *gb)

{

unsigned int buf;

OPEN_READER(re, gb); //准备

UPDATE_CACHE(re, gb); //

buf = GET_CACHE(re, gb); //端序调整,获取反转后的值(小端需要翻转,大端不用)

if (buf >= (1 << 27)) { //当前5bits 不全为0时

buf >>= 32 - 9; //取前9bits

LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); //更新gb中的re_index

CLOSE_READER(re, gb); //关闭

return ff_ue_golomb_vlc_code[buf]; //返回解码数值.

} else {

int log = 2 * av_log2(buf) - 31; //得到不属于哥伦布编码的位长,参考注1证明

LAST_SKIP_BITS(re, gb, 32 - log); //更新gb中的re_index, 32-log为码长

CLOSE_READER(re, gb); //关闭

if (log < 7)

return AVERROR_INVALIDDATA; //返回非法数据错误

buf >>= log; //移除不属于哥伦布编码的位

buf--; //-1得到原值

return buf;

}

}

//注1: av_log2(buf)=log2(buf)=w-1, 位宽w最大32, av_log2(buf)是x等于w-1

//因为位宽1为2^0,位宽1为2^1,位宽32为2^31,故32bits数最大为2^31,log2(max32)=31

//前导0+1bit+信息长+无用=32,

//前导0=32-w

//故 (32-w)+1+(32-w)+n=32 =>

//32-(w-1)-(w-1)-1+n=0 =>

//n = 2(w-1) - 31 =>

//n = 2*av_log2(buf)-31

//去掉宏的函数,帮助搞清运算关系

int my_get_ue_golomb2(GetBitContext *gb)

{

unsigned int buf;

unsigned int re_index = (gb)->index;

unsigned int re_size_plus8 = (gb)->size_in_bits_plus8;

unsigned int re_cache = av_bswap32((((const union unaligned_32 *) ((gb)->buffer + (re_index >> 3)))->l)) << (re_index & 7);

buf = ((uint32_t) re_cache);

if (buf >= (1 << 27)) {

buf >>= 32 - 9;

re_index = ((re_size_plus8) > (re_index + (ff_golomb_vlc_len[buf])) ? (re_index + (ff_golomb_vlc_len[buf])) : (re_size_plus8));

(gb)->index = re_index;

return ff_ue_golomb_vlc_code[buf];

} else {

int log = 2 * av_log2(buf) - 31;

re_index = ((re_size_plus8) > (re_index + (32 - log)) ? (re_index + (32 - log)) : (re_size_plus8));

(gb)->index = re_index;

if (log < 7)

return (-(int)(('I') | (('N') << 8) | (('D') << 16) | ((unsigned)('A') << 24)));

buf >>= log;

buf--;

return buf;

}

}

int main()

{

//一个PPS 数据集

unsigned char data[]={

0x68,

0xeb,

0xec,

0xb2,

0x2c

};

GetBitContext gb;

int ret = init_get_bits8(&gb, data, sizeof(data));

if(ret!=0) return 1;

get_bits1(&gb);

int ref_idc = get_bits(&gb, 2); //获取idc值为3

int type = get_bits(&gb, 5); //获取type 为8

printf("%x %x\n",ref_idc,type);

unsigned int pps_id = my_get_ue_golomb(&gb);

printf("id:%d\n",pps_id);

return 0;

}

相关推荐
嘟嘟实验室19 小时前
微信小程序xr-frame透明视频实现
微信小程序·ffmpeg·音视频·xr
泰勒朗斯1 天前
如何编译Opencv +ffmpeg linux 明明安装了ffmpeg但是opencv就是找不到
linux·opencv·ffmpeg
-Mr_X-1 天前
windows下srs流媒体服务器使用ffmpeg推流
ffmpeg
dvlinker1 天前
C++开源项目 VLC 源代码的交叉编译以及库的裁剪方法详解
ffmpeg·mingw-w64·msys2·cygwin·开源vlc·vlc编译·vlc裁剪
因我你好久不见2 天前
springboot java ffmpeg 视频压缩、提取视频帧图片、获取视频分辨率
java·spring boot·ffmpeg
cuijiecheng20182 天前
音视频入门基础:MPEG2-TS专题(21)——FFmpeg源码中,获取TS流的视频信息的实现
ffmpeg·音视频
cuijiecheng20182 天前
音视频入门基础:AAC专题(13)——FFmpeg源码中,获取ADTS格式的AAC裸流音频信息的实现
ffmpeg·音视频·aac
流氓也是种气质 _Cookie3 天前
uniapp blob格式转换为video .mp4文件使用ffmpeg工具
ffmpeg·uni-app
网络安全queen3 天前
网络安全-企业环境渗透2-wordpress任意文件读&&FFmpeg任意文件读
安全·web安全·ffmpeg
yerennuo3 天前
FFmpeg库之ffmpeg
qt·ffmpeg