writeSyntaxElement_NumCoeffTrailingOnes里有lentab[3][4][17] codtab[3][4][17]
编码非零系数数目 (NumCoeff)和拖尾系数数目(TrailingOnes)
writeSyntaxElement_NumCoeffTrailingOnesChromaDC里有lentab[4][5] codtab[4][5]
与上面的函数功能一样, 只是这儿特别针对Chroma DC(色度直流系数)
writeSyntaxElement_TotalZeros里有lentab[TOTRUN_NUM(15)][16] codtab[TOTRUN_NUM][16]
编码最后一个非零系数前零的数目(TotalZeros)
writeSyntaxElement_TotalZerosChromaDC里有lentab[3][4] codtab[3][4]
特别针对色度直流系数ChromaDC
writeSyntaxElement_Run里有lentab[TOTRUN_NUM][16] codtab[TOTRUN_NUM][16]
编码非零系数前零的个数: write VLC for Run Before Next Coefficient, VLC0
writeSyntaxElement_Level_VLC1, writeSyntaxElement_Level_VLCN
编码除拖尾系数之外的非零系数的幅值
int writeSyntaxElement_TotalZeros(SyntaxElement *se, DataPartition *this_dataPart);
int writeSyntaxElement_TotalZerosChromaDC(SyntaxElement *se, DataPartition *this_dataPart);
int writeSyntaxElement_Run(SyntaxElement *se, DataPartition *this_dataPart);
int writeSyntaxElement_NumCoeffTrailingOnes(SyntaxElement *se, DataPartition *this_dataPart);
int writeSyntaxElement_NumCoeffTrailingOnesChromaDC(SyntaxElement *se, DataPartition *this_dataPart);
int writeSyntaxElement_Level_VLC1(SyntaxElement *se, DataPartition *this_dataPart);
int writeSyntaxElement_Level_VLCN(SyntaxElement *se, int vlc, DataPartition *this_dataPart);
基于内容的自适应变长编码[CAVLC]
基于内容自适应的变长编码方式用于编码zigzag顺序扫描的4x4和2x2残差变换系数块。
1、 编码系数个数和零序列(coeff_token):
coeff_token = <TotalCoeff, TrailingOnes>;
TotalCoeff = 编码非零系数总数; [0 , 16]
TrailingOnes = 特殊处理的+/-1个数; [0 , 3]
2、 编码每个TrailingOne的符号:
倒序,从高频开始向前编码TrailingOne符号,每个符号一位,0为正,1为负,最多为3个。
3、 编码余下非零系数的幅值:
编码顺序:倒序,从高频开始向前编码直到DC系数,每个幅值码字level[i]包含一个幅值前缀level_prefix和一个幅值后缀level_suffix。
level[i]: Level为实际系数的幅值。但有个例外:
当TrailingOnes<3时,那么被编码的第一个非T1 幅值肯定不是+/-1(否则将算作T1)。这个幅值如果为负就加1(如果为正就减1),例如+/-2 被映射成+/-1, +/-3映射成+/-2进行编码,这样可以用较短的变长码.
levelCode:
如果level[i]为正, levelCode = (Level[i] << 1) - 2;
如果 level[i]为负, levelCode = -(Level[i] << 1) - 1;
计算level_prefix:
编码时:
level_prefix = levelCode / (1 << suffixLength);
根据level_prefix查标准表9-6得到码字
解码时:
从比特流的当前位置开始读取,计算为0的leading bits数量。0的长度即为level_prefix值,对应关系可察看标准文档中表9-6。
计算suffixLength:
suffixLength为0-6 比特,其长度是自适应变换的。
suffixLength 增长过程:
1、 初始化suffixLength = 0 ; 如果有超过10个非零系数,并且少于3个TailingOnes,这时suffixLength = 1;
2、 编码最高频的非零系数;
3、 如果这个系数的幅值大于一定的阈值,则增长suffixLength
当前suffixLength | 增加suffixLength的系数阈值 |
0 | 0 |
1 | 3 |
2 | 6 |
3 | 12 |
4 | 24 |
5 | 48 |
6 | N/A |
更新suffixLength函数如下:
if(suffixLength == 0)
++suffixLength;
else if(level[i] > (3<<suffixLength-1) && suffixLength < 6)
++suffixLength;
计算levelSuffixSize: (后缀是长度为levelSuffixSize的无符号整数)
除了以下两种情况levelSuffixSize等于suffixLength:
1、 level_prefix == 14 && suffixLength == 0 时, levelSuffixSize = 4;
2、 level_prefix >= 15 时,levelSuffixSize = level_prefix – 3;
4、 编码最后一个非零系数前零的个数
使用VLC编码最高频非零系数前所有零的个数
total_zeros:既为最高非零系数前所有零的个数;编码表见标准表9-7;表9-8;表9-9
5、 编码每个零游程
zerosLeft: 当前系数之前所有的零的个数
run_before: 紧接当前系数前的零个数
CAVLC算法的具体过程(参考Sunrise的总结)
编码过程:
假设有一个4*4数据块
{
0, 3, -1, 0,
0, -1, 1, 0,
1, 0, 0, 0,
0, 0, 0, 0
}
数据重排列:0,3,0,1,-1,-1,0,1,0......
1) 初始值设定:
非零系数的数目(TotalCoeffs) = 5;
拖尾系数的数目(TrailingOnes)= 3;
最后一个非零系数前零的数目(Total_zeros) = 3;
变量NC=1;
(说明:NC值的确定:色度的直流系数NC=-1;其他系数类型NC值是根据当前块左边4*4块的非零系数数目(NA)当前块上面4*4块的非零系数数目(NB)求得的,见毕厚杰书P120表6.10)
suffixLength = 0;
i = TotalCoeffs = 5;
2) 编码coeff_token:
查标准(BS ISO/IEC 14496-10:2003)Table 9-5,可得:
If (TotalCoeffs == 5 && TrailingOnes == 3 && 0 <= NC < 2)
coeff_token = 0000 100;
Code = 0000 100;
3) 编码所有TrailingOnes的符号:
逆序编码,三个拖尾系数的符号依次是+(0),-(1),-(1);
即:
TrailingOne sign[i--] = 0;
TrailingOne sign[i--] = 1;
TrailingOne sign[i--] = 1;
Code = 0000 1000 11;
4) 编码除了拖尾系数以外非零系数幅值Levels:
过程如下:
(1)将有符号的Level[ i ]转换成无符号的levelCode;
如果Level[ i ]是正的,levelCode = (Level[ i ]<<1) – 2;
如果Level[ i ]是负的,levelCode = - (Level[ i ]<<1) – 1;
(2)计算level_prefix:level_prefix = levelCode / (1<<suffixLength);
查表9-6可得所对应的bit string;
(3)计算level_suffix:level_suffix = levelCode % (1<<suffixLength);
(4)根据suffixLength的值来确定后缀的长度;
(5)suffixLength updata:
If ( suffixLength == 0 )
suffixLength++;
else if ( levelCode > (3<<suffixLength-1) && suffixLength <6)
suffixLength++;
回到例子中,依然按照逆序,Level[i--] = 1;(此时i = 1)
levelCode = 0;level_prefix = 0;
查表9-6,可得level_prefix = 0时对应的bit string = 1;
因为suffixLength初始化为0,故该Level没有后缀;
因为suffixLength = 0,故suffixLength++;
Code = 0000 1000 111;
编码下一个Level:Level[0] = 3;
levelCode = 4;level_prefix = 2;查表得bit string = 001;
level_suffix = 0;suffixLength = 1;故码流为0010;
Code = 0000 1000 1110 010;
i = 0,编码Level结束。
5)编码最后一个非零系数前零的数目(TotalZeros):
查表9-7,当TotalCoeffs = 5,total_zero = 3时,bit string = 111;
Code = 0000 1000 1110 0101 11;
6) 对每个非零系数前零的个数(RunBefore)进行编码:
i = TotalCoeffs = 5;ZerosLeft = Total_zeros = 3;查表9-10:
依然按照逆序编码
ZerosLeft =3, run_before = 1 run_before[4]=10;
ZerosLeft =2, run_before = 0 run_before[3]=1;
ZerosLeft =2, run_before = 0 run_before[2]=1;
ZerosLeft =2, run_before = 1 run_before[1]=01;
ZerosLeft =1, run_before = 1 run_before[0]不需要码流来表示
Code = 0000 1000 1110 0101 1110 1101;
编码完毕。
CAVLC中的前缀和后缀——264小生
H264中的CAVLC在对TrailingOne之后的非零系数编码时,使用了前缀(prefix)和后缀(suffix)的概念,并且用suffixlength来表示后缀的长度。具体编码过程是这样的:
一,将suffixlength初始化为0(如果超过10个非零系数,而且少于3个TrailingOnes,suffixlength初始化为1)
二,将有符号的level(系数的值),转化为无符号数,有三种情况:
(1)如果Level是正的,levelCode = (Level<<1) – 2
(2)如果Level是负的,levelCode = -(Level<<1) – 1
(3)如果TrailingOnes小于3,那么第一个非TrailingOnes的非零系数必不为 +1、-1,为了节省编码比特,将其幅值减1。也就是如果level为正,level=level-1;否则,level=level+1。然后再按(1)
(2)将level转化为levelCode。T264中,此步骤是通过直接对levelcode减2完成的,levelcode=levelcode-2,这和通过对level幅值减1得到的levelcode是一样的。
三,得到level_prefix和level_suffix。
先说明一下,在解码端,levelcode是这样被解码的:
levelcode=(level_prefix<<suffixlength)+level_suffix
知道这一点很重要。从解码levelcode的公式中可以看出,编码端的level_prefix就是将levelcode右移suffixlength位得到的,而level_suffix直接就是levelcode的低suffixlength位。比如levelcode =13,也就是二进制'1101',而且如果此时的suffixlength=1,那么level_prefix=13>>1='110',level_suffix直接就是levelcode的最低位'1';再比如levelcode=13='1101', suffixlength=3,这时level_prefix =13>>3='1', level_suffix 就是 levelcode的低3位'101'。根据level_prefix 的值查表得到输出的码字。
这里还有三种特殊情况,在解码端:
(1)如果此时发现suffixlength=0,level_prefix=14,那么认为level_suffix是4位(而不是0位)。
(2)如果此时发现level_prefix=15,那么认为level_suffix是12位的。
(3)如果此时发现suffixlength=0,level_prefix=15,那么经过使用公式levelcode=
(level_prefix<<suffixlength)+level_suffix得到的levelcode还需要再加上15。