cabac是一种特数的二进制算数编码,假设我们有由“0”和“1”组成的字符串需要编码,且“0”和“1”的出现的概率概率分别为0.4和0.6,那么我们分配如下初始概率区间:
0 | 1 |
---|---|
[0, 0.4) | [0.4, 1] |
这种编码方式需要知道原始数据的长度和编码后的区间
,不然会一直判断下去;我们以上的编码是按照,0出现的概率为0.4,1出现的概率为0.6来进行编码的,但实际应用中,我们怎么得到这个真实的概率呢?
CABAC中我们根据如下几个条件对其进行分类,有一张大的查找表look_up确定每个分类的“0”和“1”的概率:
举个例子,假设一个4bit的语法元素,syn;
首先我们判断上方宏块的情况condA(上方宏块可访问则condA为1,否则为0), 和左面宏块的编码情况condB(上方宏块可访问则condB为1,否则为0), syn语法元素的基准值为Ctxoffset(查表确定,这里假设为0),偏差Ctxinc = f(condA, condB, bin), 这里的bin代表当前编码是第几个比特,f(condA, condB, bin)的表达式每个语法元素都不一样,需要翻书确认(详见参考资料【4】)本文假定Ctxinc = f(condA, condB, bin) = condA + condB + bin,总的查表地址如下所示
C t x i d x = C t x o f f s e t + C t x i n c = C t x o f f s e t + f ( c o n d A , c o n d B , b i n ) Ctxidx=Ctxoffset+Ctxinc=Ctxoffset + f(condA, condB, bin) Ctxidx=Ctxoffset+Ctxinc=Ctxoffset+f(condA,condB,bin)
假设syn为1100,且上方和左方的宏块都不可获取(比如最左上角的宏块),
也就是说, CABAC会在编码过程中不断的更新该情况下“0”“1”出现的概率,以求编码时用到的概率趋近于真实的概率;
至于概率和编码的关系,就需要参考香农定理了,网上有很多,这里就不多做解释了;
2.1 cabac里面1,和0出现的概率是不断变换的:
cabac编码为每个语法元素的每个bit都分配了一个概率模型;每个语法元素的概率模型的基地址为Ctxoffset,根据上方和左边LCU的情况,计算出每个比特的偏移地址ctxinc,从而得到ctxIdk = ctxoffset + ctxinc;
在一个slice开始时,为每个模型分配一个初始概率值,每编码1bit,对该bit的概率模型进行更新;
2.2 cabac输出编码区间的溢出情况:
普通二元算术编码的编码区间越来越小,最终输出一个很小的区间;
cabac则是设定区间大小为【0,510】,当区间小于256时,就扩大区间,并输出0/1的方式,记录扩大区间的情况(书中称为“归一化”)。
解码时,初始区间为【0,510】,根据编码端扩大区间时输出的码流(书中记为OFFSET,也就是“区间归一化”过程输出的码流),来还原区间变化过程,从而达到解码的作用;
这个归一化的过程有点复杂,可以简单理解为当编码区间变为(0.6,1)时,那么无论后面怎么编码,最终的编码出的值都肯定大于0.5,我们就现输出一个0.5,即小数位的第一个比特是1,当编码区间变为(0.6,0.75)时,无论后面怎么编码,肯定都小于0.75,因此小数位第二位肯定是0,此时就可以先输出个“0”,虽然不准确,但大概就是这么个意思;
5.1 怎么判断一个语法元素结束了呢?
这个和二值化的方式有关,比如FL二值化,有cmax;U则是0为一个语法元素的最后1bit;
5.2 怎么判断当前编码或解码的元素是什么?
编码时,语法元素有严格的编码条件和编码顺序,比如h264的编码,若为p帧,第一个一定是编码mb_skip_flag,若mb_skip_flag为0,下一个必定编码mb_type,若mb_type为pcm,则必定编码残差系数;
解码端同理,若为p帧,第一个一定解码mb_skip_flag,若解码出的mb_skip_flag为0,下一个语法元素一定是mb_type,否则是end_of_slice_flag,知道下一个编码的语法元素,自然就知道其对应的ctxoffset,二值化方式等信息了;
本文只是对博主学习CABAC期间一些疑问的点的总结,完整的学习cabac编码建议阅读官方标准协议(参考文献【3】);个人认为,学习好cabac,必须得去读官方协议文档,不然很难弄明白;