当前位置:文档之家› CABAC流程

CABAC流程

算术编码流程:CABAC编码首先要说明的是CABAC的生命期是SLICE,因此本篇所讲的也是一个SLICE里CABAC的流程,其次对于我们来说场模式几乎用不到,所以本文的编码流程只使用帧模式,因此实际上用到的表只有277个, 当然如果我写成460, 不是说里面所有表都用到的. 这里只是声明一下这个问题, 如果大家实际操作的时候发现模型表序号始终不过276那是很正常的. 本文参考了T264的代码, 应此一帧里只有一个SLICE. 而本文用的变量则采用标准里的变量.本文不会讲CABAC的原理, 想要了解原理请参考FTP上的<<Context-based adaptive binary arithmetic coding in the H.264AVC video compression standard>>片级:即以下步骤在片期间只做1次1.初始化上下文模型先根据SliceQP算出460个模型表里的pStateIdx和valMPS, 构成一张初始表,根据标准9.3.1.1里的公式, 同时可以参考T264_cabac_context_init函数. 这张表不要和模型表弄混,虽然都是399维的, 但我们宏块级编码过程中实际用的只是这张表, 而不是标准里的那张模型表Table 9-23, 9-23这张表是用来算由pStateIdx和valMPS构成的初始表的.2.初始化概率的下限和区间然后就是初始化CABAC的初值, 下界指针,区间范围,可参考T264_cabac_encode_init函数.解:下界指针codILow为0,区间范围codIRange为(0x1FE)510宏块级:以下则是每个宏块都要做一次的, 这一级中会处理很多的语法元素, 这里我只用前2个语法元素做为例子:假设:mb_skip_flag = 1mb_type = 33.语法元素二值化H.264 通过二进制化把多维算术编码转化为二进制算术编码,提高了运算速度。

语法元素二进制化就是把非二进制的符号映射成若干位的二进制串。

CABAC 引入了二进制化预处理过程来减小要编码的语法元素符号集的大小, 对于给定的语法元素用一个惟一的二进制串代替。

CABAC 二进制化方案由基本方案,串接方案(参考标准子条款9.3.2.3,9.3.2.6)以及特别的手工选择方案(参考标准子条款9.3.2.5)组成。

基本方案有一元码、截断一元码、K 阶指数哥伦布码和定长码4 种;串接方案由基本方案串接而成;手工选择方案有5 种,专门针对mb_type 和sub_mb_type 这两种语法元素。

对语法元素的二进制化方案参考标准表9‐25。

经二进制化编码输出的是MPS 概率极高的比特流,这样可以达到极高的压缩效果。

4. CABAC编码处理流程首先mb_skip_flag标志进行CABAC编码, 由于这个元素本身就是2值的,所以直接就可以进行上下文模型选择了:1.求ctxIdx上下文模型索引值1)由标准Table 9-11知道, P帧(这里要注意是slice_type==P, 不是mb_type)的这个元素用9-13号表, B帧用9-14号表.解:假设P帧得到ctxIdxOffset=112)由于这个元素只有1个bit, 因此只要算第一个bit的ctxIdxInc 就可以了, 参考标准Table 9-30,根据9.3.3.1.1子条款可以知道这一位的ctxIdxInc可能是0, 1, 2中的一个, 变量condTermFlagN (N 为A 或 B)的值推导如下:—如果mbAddrN不可用或宏块mbAddrN 的mb_skip_flag等于1,则condTermFlagN被置为0;—否则condTermflagN置为1。

变量ctxIdxInc 为: ctxIdxInc = condTermFlagA + condTermFlagB. 解:如果全是skip模式得到ctxIdx=132. 规则算术编码过程下来就是算术编码部分了, 简单提一下基本原理: 在CABAC中为了减少R LPS= R*p LPS这个区间变换公式的开销, 用128个有限状态(实际可用的为126)代替p LPS , 用rangeTab这张表代替了R LPS, 见标准Table 9-35. 可以参考T264中的T264_cabac_encode_decision函数, 看一下具体流程:1)查表得pStateIdx和valMPS▲获得当前bin的pStateIdx和valMPS(来自片级计算的那张初始表) 假设cabac_init_idc=0查表获得:m=21,n=0假设SliceQP Y=26preCtxState = Clip3( 1, 126, ( ( 21 * Clip3( 0, 51, 26 ) ) >> 4 ) + 0 )preCtxState=34if( preCtxState <= 63 ) {pStateIdx = 63 - preCtxStatevalMPS = 0} else {pStateIdx = preCtxState - 64valMPS = 1}解:pStateIdx=29,valMPS=0;2)求得变换后的区间▲根据标准9.3.3.2.1子条款, 求得qCodIRangeIdx用来索引表rangeTab, 即可以求得变换后的区间了.解:qCodIRangeIdx = (codIRange>>6)&3qCodIRangeIdx = (510>>6)&3 = 2.查表9-35,codIRangeLPS =46▲修正区间codIRange = codIRange – codIRangeLPS解:codIRange =510-46=4643)更新下边界,区间,概率状态索引值▲判断当前的bin是否为最有可能的值, 如果不是(binVal!= valMPS),则更新区间下边界codILow = codILow + codIRange, 同时修正区间codIRange = codIRangeLPS;然后判断当前状态, 如果已经达到状态0, 是则把valMPS的值取反(即0,1互换), 如果还有没达到0, 则进行LPS 的状态迁移,具体参看标准Table 9-36的状态迁移表中的transIdxLPS解:codILow = codILow + codIRange=0+464=464codIRange= codIRangeLPS =46查表9-36,pStateIdx=transIdxLPS[29]=22▲如果当前的binVal值等于valMPS, 就比较简单了, 直接进行状态迁移, MPS的状态迁移也很简单, 直接数据+1就可以了(最大63),具体参考标准Table 9-36的状态迁移表中的transIdxMPS, 状态的转移其实就是修改了460个模型的初始表.解:pStateIdx=min(29+1,62)=304)编码归一化▲区间重整, 如果区间过小则输出一些bit, 这样可以不用把数据全部编码完再输出, 可以编一部分输出一些.编码归一化算法如下:While(R<0x100){if(L<0x100){Put_Bits_Outstanding(0,binsOutStanding);}Else{If(L<0x200){L=L-0x100;bitsOutSanding=bitsOutStanding+1;}Else{L=L-0x200;Put_Bits_Outstanding(1,binsOutStanding);}}R=R<<1;L=L<<1;}算法中,Put_Bits_Outstanding是根据下溢的状态进行输出的。

Put_Bits_Outstanding(bitVal,binsOutStanding){putbit(bitVal);While(bitsOutstanding>0){Putbit(~bitVal);binsOutStanding= binsOutStanding-1;}}解:(1)codILow = codILow-0x100=464-256=208binsOutStanding = binsOutStanding+1=0+1=1 codIRange= codIRange<<1=46*2=92codILow= codILow <<1=208*2=416(2)codILow = codILow-0x100=416-256=160 binsOutStanding = binsOutStanding+1=1+1=2 codIRange= codIRange<<1=92*2=184codILow= codILow <<1=160*2=320(3)codILow = codILow-0x100=320-256=64 binsOutStanding = binsOutStanding+1=2+1=3 codIRange= codIRange<<1=184*2=368 codILow= codILow <<1=64*2=1283旁路编码过程对于概率近似0.5 的符号(在标准表9‐30 中标为na 的符号)则通过旁路编码器进行编码,旁路编码器不需要概率更新以提高计算速度。

在旁路编码器中把区间更新和归一化集成在一起,如图4 所示:4算术编码器的判定编码过程算术编码器的终止流程如图5 所示。

在ctxIdx 等于276 时,语法元素end_of_slice_flag 和语法元素mb_type 指示I_PCM 的二进制码的编码都需使用该流程。

如图5 所示:当要编码的 binVal 值等于 1 时,结束 CABAC 编码,应用图 9-12 所示的流程。

在该流程中,由 WriteBits( B, N )写入的最后一个比特等于1。

当解码end_of_slice_flag 时,最后一个比特为rbsp_stop_one_bit 。

5.下一个语法元素编码下面就是开始编码第二个语法元素了: mb_type1) 不同于上一个语法元素mb_skip_flag, mb_type这个语法元素本身并不是二值化的, 因此编码的第一步是进行二值化, 查阅标准Table 9-25可知mb_type的二值化方法需要参考9.3.2.5子条款, 由该条款可知mb_type的二值化相对简单, 可以直接参考表得到, 例如P片中某宏块mb_type为3, 因此我们就得到了标准中P_8*8的二值化串为001 2) 下来是上下文模型选择, 由Table 9-11可知P的mb_type元素起始表是Table 9-13号表, 然后参考标准表Table 9-30, 计算bin串中每个bin的ctxIdxInc值,由表可知bin0固定是0, bin1固定是1, bin2参考9.3.3.1.2如果bin1=0, ctxIdxInc=2 ,否则bin1=1,ctxIdxInc=3,因为bin1=1所以bin2=3.至此二进制串所有位的表号可以用14+的ctxIdxInc来得到了ctxIdx.3) 下来就是算术编码部分,这个部分于mb_skip_flag的算术编码部分步骤一样.这里要提的是, 第一步获得当前bin的pStateIdx和valMPS 的模型表已经被更新了(是表被更新,但不一定是当前表), 还记得么? 是在上一个语法元素的状态转移的时候更新的.下面的语法元素就是按照标准7.3.5的语法一一编码的, 其过程和上面2个语法元素的编码过程大同小异,就不一一细述了.……如此做完所有的宏块里的语法元素6. 字节填充的过程要处理的图像最后一个条带的最后一个宏块的编码完成并且封装后,还有一个字节填充的过程。

相关主题