全部博文(10)
分类: C/C++
2019-05-15 09:23:46
CAVLC 编码过程
0. CAVLC是h264的熵编码(entropy coding)一种,是一种无损编码.h264编码算法对任何(子)宏块无论采取帧内预测或是帧间运动估计,最终都会归结到对(子)宏块预测或估计的残差值矩阵进行DCT变换、量化、和熵编码.熵编码的结果才是最终的码流.
1. 现有经过DCT变换以及量化之后的4x4block,如下所示.
0 |
3 |
-1 |
0 |
0 |
-1 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
上述4x4block经过zig-zag顺序扫描之后,生成重排序列reorder-sequence: 0,3,0,1,-1,-1,0,1,0,0,0,0,0,0,0,0
2. 编码非零系数的数目(TotalCoeffs)以及拖尾系数的数目(TrailingOnes)
非零系数的数目(TotalCoeffs):就是reorder-sequence中非零系数的个数,这里TotalCoeffs=5.
拖尾系数的数目(TrailingOnes):逆向扫描reorder-sequence的非零系数,排在最前面的连续+1/-1串就是拖尾系数.拖尾系数数目TrailingOnes的范围是[0,3],也就是即便这个+1/-1串的个数大于3,也只有前3个被算入拖尾系数数目TrailingOnes.这里TrailingOnes=3, 因为+1/-1串的个数等于4,但是最大只能是3.
TotalCoeffs和TrailingOnes是作为一个整体一起编码的,码字是根据h264-2003.5.pdf的
Table 9-5 coeff_token mapping to TotalCoeff( coeff_token ) and TrailingOnes( coeff_token )表格得出的,此表格部分内容如下,
TrailingOnes |
TotalCoeff |
0 <= NC < 2 |
2 <= NC < 4 |
4 <= NC < 8 |
4 <= NC < 8 |
4 <= NC < 8 |
0 |
0 |
1 |
11 |
1111 |
0000 11 |
01 |
0 |
1 |
0001 01 |
0010 11 |
0011 11 |
0000 00 |
0001 11 |
…… |
…… |
…… |
…… |
…… |
…… |
…… |
3 |
5 |
0000 100 |
0011 0 |
1010 |
0100 11 |
- |
…… |
…… |
…… |
…… |
…… |
…… |
…… |
上表可以看出, TotalCoeffs和TrailingOnes的编码还得依据另一个变量NC的值来决定.
若当前块(4x4block)的左侧块(4x4block)的非零系数的数目TotalCoeffs是NA, 当前块(4x4block)的上侧块(4x4block)的非零系数的数目TotalCoeffs是NB,那么NC的值计算方法如下表.按照编码规范,上侧块、左侧块和当前块要属于同一个slice.
上侧块(NB) |
左侧块(NA) |
NC |
存在 |
存在 |
(NA+NB)/2 |
存在 |
不存在 |
NB |
不存在 |
存在 |
NA |
不存在 |
不存在 |
0 |
那么,假如当前块的上侧块和左侧块都不存在, reorder-sequence的TotalCoeffs和TrailingOnes的编码结果就是 0000 100
3. 编码拖尾系数的符号
按逆序编码, 正号用 0,负号用 1
那么, reorder-sequence的编码拖尾系数符号的编码结果就是0000 1000 11
4. 编码除了拖尾系数之外的每个非零系数
按逆序编码, 编码结果由两部分组成, 前缀 + 后缀, 前缀就是level_prefix的码字,后缀是suffixLength 个level_suffix(0或1)组成. 基本过程:
(1) 把非零系数记为level[i],这里level[i]是带符号的.
(2) 把level[i]转换为无符号的levelcode,
如果level[i] > 0, levelcode = (level[i] << 1) - 2;
如果level[i] < 0, levelcode = -(level[i] << 1) - 1;
(3) 计算level_prefix,
level_prefix = levelcode / ( 1 << suffixLength)
注意, suffixLength 初始化为0,但是当块中有多于10 个非零系数并且其中拖尾系数的数目少于3 个,suffixLength 初始化为1。
level_prefix的码字由h264-2003.5.pdf 的Table 9-6 – Codeword table for level_prefix得出
Table 9-6 – Codeword table for level_prefix
level_prefix |
bit string |
0 |
1 |
1 |
01 |
2 |
001 |
3 |
0001 |
4 |
0000 1 |
5 |
0000 01 |
6 |
0000 001 |
7 |
0000 0001 |
8 |
0000 0000 1 |
9 |
0000 0000 01 |
10 |
0000 0000 001 |
11 |
0000 0000 0001 |
12 |
0000 0000 0000 1 |
13 |
0000 0000 0000 01 |
14 |
0000 0000 0000 001 |
15 |
0000 0000 0000 0001 |
(4) 计算level_suffix,
level_suffix = levelcode % ( 1 << suffixLength)
(5) 此时的suffixLength决定后缀长度, level_suffix的奇偶性决定后缀是0还是1,奇数->1,偶数->0.
(6) 更新suffixLength,以便编码下一个系数
if (suffixLength == 0)
suffixLength++;
else if (levelcode >
(3<
suffixLength++;
当前suffixLength
Levelcode阈值
0
0
1
3
2
6
3
12
4
24
5
48
6
N/A
那么,
reorder-sequence需要编码的就是1,3两个非零系数.首先编码非零系数1,
levelcode = (1<<1)-2=0,level_prefix=0/(1<<0)=0,level_suffix=0%(1<<0)=0,suffixLength=0(初始值).所以非零系数1的编码结果就是1(前缀)(没有后缀,因为suffixLength=0).之后suffixLength++,然后编码非零系数3, levelcode =
(3<<1)-2=4,level_prefix=4/(1<<1)=2,level_suffix=4%(1<<1)=0,suffixLength=1, 所以非零系数3的编码结果就是001(前缀)0(后缀).
那么, reorder-sequence的非零系数的编码结果就是0000 1000 1110 010
5. 编码最后一个非零系数前零的数目(TotalZeros)
根据h264-2003.5.pdf 的Table 9-7, Table 9-8,最后一个非零系数前零的数目(TotalZeros)的码字由TotalCoeff决定. reorder-sequence的TotalCoeff=5, 最后一个非零系数前零的数目(TotalZeros)=3,查表可知,对应的码字是111.
那么, reorder-sequence最后一个非零系数前零的数目(TotalZeros)的编码结果就是0000 1000 1110 0101 11
6. 编码每个非零系数前零的个数(RunBefore)
逆序对每一个非零系数编码. ZerosLeft为系数前面0的个数, run_before为系数前面紧邻的连续0的个数.那么,对于reorder-sequence来说,通过查h264-2003.5.pdf 的Table 9-10 – Tables for run_before就有
系数1: ZerosLeft=3; run_before=1 码字10
系数-1: ZerosLeft=2;run_before=0 码字1
系数-1: ZerosLeft=2;run_before=0 码字1
系数1: ZerosLeft=2;run_before=1 码字01
系数3: ZerosLeft=1; run_before=1 最前面的系数不需要编码
那么, reorder-sequence每个非零系数前零的个数(RunBefore)的编码结果就是
0000 1000 1110 0101 1110 1101,这也就是这个4x4block最终的编码结果,直接输出为码流.