CABAC之手把手教你H.264编码

CABAC之手把手教你H.264编码输出PDF打印E-mail
  中华视频网   2006-09-25
    首先要说明的是 CABAC 的生命期是 SLICE, 因此本篇所讲的也是一个 SLICE 里 CABAC 的流程 , 其次对于我们来说场模式几乎用不到 , 所以本文的编码流程只使用帧模式 , 因此实际上用到的表只有 277 个 , 当然如果我写成 399, 不是说里面所有表都用到的 . 这里只是声明一下这个问题 , 如果大家实际操作的时候发现模型表序号始终不过 276 那是很正常的 . 本文参考了 T264 的代码 , 应此一帧里只有一个 SLICE. 而本文用的变量则采用标准里的变量 . 本文不会讲 CABAC 的原理 , 想要了解原理请参考 《 Context-based adaptive binary arithmetic coding in the H.264AVC video compression standard》

注意:我用的标准是BS的正式标准,可能里面的序号和大家的不一样,但是内容应该是一样.大家对照着就可以了

 

片级 : 即以下步骤在片期间只做 1 次

1,   在一帧的开始的时候 , 先看是否字节对齐 , 没有对齐则补 1, 直到字节对齐

2,   先根据 SliceQP 算出 399 个模型表里的 pStateIdx 和 valMPS , 构成一张初始表, 根据标准 9.3.1.1 里的公式 ,同时可以参考 T264_cabac_context_init 函数 . 这张表不要和模型表弄混 , 虽然都是 399 维的 , 但我们宏块级编码过程中实际用的只是这张表 , 而不是标准里的那张模型表 Table 9-23, 9-23 这张表是用来算由 pStateIdx 和valMPS 构成的初始表的.

3,   然后就是初始化 CABAC 的初值 , 下界指针 , 区间范围 (0x1FE) 等等 , 可参考 T264_cabac_encode_init 函数 .

 

宏块级 : 以下则是每个宏块都要做一次的 , 这一级中会处理很多的语法元素 , 这里我只用前 2 个语法元素做为例子 : mb_skip_flag, mb_type

4,   重整区间 , 确保在区间在 28 -29 内 . 这里的区间概念来自 BAC, 如果不明白先 google 算术编码 , 然后再看上面那个参考文献 .

5,   首先 mb_skip_flag 标志进行 CABAC 编码 , 由于这个元素本身就是 2 值的 , 所以直接就可以进行上下文模型选择了 :

1. 由标准 Table 9-24 知道 , P 帧 ( 这里要注意是 slice_type==P, 不是 mb_type) 的这个元素用 11 号表 , B帧用 24 号表 . 可以参考 T264 中的 T264_cabac_mb_skip 函数 .

2. 由于这个元素只有 1 个 bit, 因此只要算第一个 bit 的 ctxIdxInc 就可以了 , 参考标准 Table 9-29, 可以看到表中 11 和 24 号表确实只有第一个 bit 是可用的 , 根据 9.3.3.1.1 子条款可以知道这一位的 ctxIdxInc可能是 0, 1, 2 中的一个 , 在 T264 中简单的说就是看左边和上边宏块是否是 Skip 模式 , 有一个是 skip模式 ctxIdxInc 就加 1. 也就是全不是 skip 为 0, 有一个 skip 则 ctxIdxInc 就是 1, 全是 skip 则 ctxIdxInc就是 2.

3. 下来就是算术编码部分了 , 简单提一下基本原理 : 在 CABAC 中为了减少 RLPS = R*pLPS 这个区间变换公式的开销 , 用 128 个有限状态 ( 实际可用的为 126) 代替 pLPS , 用 rangeTab 这张表代替了 RLPS ,见标准 Table 9-33. 可以参考 T264 中的 T264_cabac_encode_decision 函数 , 看一下具体流程 :

Ø         获得当前bin 的pStateIdx 和 valMPS( 来自片级计算的那张初始表)

Ø         根据标准9.3.3.2.1 子条款, 求得qCodIRangeIdx 用来索引表 rangeTab, 即可以求得变换后的区间了.

Ø         修正区间codIRange = codIRange – codIRangeLPS

Ø         判断当前的bin 是否为最有可能的值, 如果不是(binVal!= valMPS), 则更新区间下边界codILow = codILow + codIRange, 同时修正区间codIRange = codIRangeLPS; 然后判断当前状态, 如果已经达到状态0, 是则把valMPS的值取反( 即0,1 互换), 如果还有没达到0, 则进行LPS 的状态迁移, 具体参看标准Table 9-34 的状态迁移表中的transIdxLPS

Ø         如果当前的binVal 值等于valMPS, 就比较简单了, 直接进行状态迁移, MPS 的状态迁移也很简单, 直接数据+1 就可以了( 最大63), 具体参考标准Table 9-34 的状态迁移表中的transIdxMPS, 状态的转移其实就是修改了399 个模型的初始表.

Ø         区间重整, 如果区间过小则输出一些bit, 这样可以不用把数据全部编码完再输出, 可以编一部分输出一些.

Ø         已编码的2 进制值bin 总数+1, 即SymCnt+1, 这个值用于字节填充, 可以参考标准9.3.4.6, 其中的BinCountsInNALunits 就是指这个值, 至此算术编码部分就结束了.

6, 下面就是开始编码第二个语法元素了: mb_type

1)     不同于上一个语法元素 mb_skip_flag, mb_type 这个语法元素本身并不是二值化的 , 因此编码的第一步是进行二值化 , 查阅标准 Table 9-24 可知 mb_type 的二值化方法需要参考 9.3.2.5 子条款 , 由该条款可知 mb_type 的二值化相对简单 , 可以直接参考表得到 , 例如 I 片中某宏块 mb_type 为I_16x16 时则二值化后 bin0=1, 且非 I_PCM 则 bin1=0, 亮度 AC 无非 0 系数则 bin2=0, 色度有非 0系数则 bin3=1, 色度 DC,AC 都无非 0 系数时 ,bin4=0, 帧内预测模式为 0 时则 bin5=0, bin6=0, 因此我们就得到了标准中 I_16x16_0_1_0 的二值化串为 1001000

2)     下来是上下文模型选择, 由Table 9-24 可知 I 的mb_type 元素起始表是3 号表, 然后参考标准表Table 9-29, 计算bin 串中每个bin 的ctxIdxInc 值, 由表可知bin0 要参考9.3.3.1.1.3 才能确定 ctxIdxInc 值 , 简单的说就是如果上边和左边的块模式有一个不是 I_4x4 则 ctxIdxInc++, 这样就有0,1,2 这 3 种可能的结果了 ; bin1 的 ctxIdx 固定是 276, 直接就调用了 encoder_terminal 模块 , 即标准 Figure 9-11 的右分支 ;bin2 的 ctxIdxInc 是 3;bin3 的 ctxIdxInc 是 4,; bin4 和 bin5 要参考9.3.3.1.2 子条款 , 由该条款可知如果 bin3 是 1 则 bin4 的 ctxIdxInc=5,bin5 的 ctxIdxInc=6, 如果bin3=0 则 bin4 的 ctxIdxInc =6,bin5 的 ctxIdxInc =7, 由于 I_16x16_0_1_0 的二值化串为 1001000,其中 bin3=1, 由此可知此时 bin4 的 ctxIdxInc =5, bin5 的 ctxIdxInc =6; 最后由表 9-29 中 bin6 的ctxIdxInc 为 7. 至此二进制串所有位的表号可以用 3+ 的 ctxIdxInc 来得到了 .

3)     下来就是算术编码部分 , 这个部分于 mb_skip_flag 的算术编码部分步骤一样 . 这里要提的是 , 第一步获得当前 bin 的 pStateIdx 和 valMPS 的模型表已经被更新了 ( 是表被更新 , 但不一定是当前表 ),还记得么 ? 是在上一个语法元素的状态转移的时候更新的 .

7, 下面的语法元素就是按照标准7.3.5 的语法一一编码的, 其过程和上面2 个语法元素的编码过程大同小异,就不一一细述了.

 

…… 如此做完所有的宏块里的语法元素

又回到片级:

8, 写入end_of_slice_flag 的标志, 即完成标准 Figure 9-11 的左分支 , 然后调用 T264_cabac_encode_flush函数 , 输出 bit

9, 进行byte stuffing, 参考标准9.3.4.6 Byte stuffing process 里的公式可以求得k, 在码流中填充k 次的0x000003

10, 最后是模型更新, 更换模型表( 更改PB 帧所用的模型表, 而I 帧所用的不变)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值