biari_encode_symbol函数分析
void biari_encode_symbol(EncodingEnvironmentPtr eep, signed short symbol, BiContextTypePtr bi_ct )
主要功能:通过使用相关上下文的概率估计对一个二进制符号进行算术编码。
输入:编码环境指针,待编码符号,上下文管理变量
从编码环境中读取当前区间的下限与范围(range = Erange, low = Elow)。
根据上下文管理变量中的概率状态与当前区间的范围,查表得到LPS的相关子区间范围(rLPS = rLPS_table_64x4[bi_ct->state][(range>>6) & 3])。
如果正在使用CABAC进行编码(cabac_encoding = 1),则上下文管理变量中的计数器加1(bi_ct->count++)。
把所有非零的待编码符号值为1。
计算新的区间范围(range -= rLPS)。
根据待编码符号判断出现的情况是MPS还是LPS。如果是LPS(symbol != bi_ct->MPS),更新区间的下限与范围(low += range,range = rLPS),此时如果概率状态为0,互换LPS与MPS。如果是MPS(symbol = bi_ct->MPS),不再改变已得到的区间。
无论是LPS还是MPS,最后都要更新概率状态(bi_ct->state = AC_next_state_LPS_64 [bi_ct->state],bi_ct->state = AC_next_state_MPS_64[bi_ct->state])。
在biariencode.h中可以查到相应的二维的LPS区间范围表格rLPS_table_64x4[64][4]与概率更新表格AC_next_state_MPS_64[64]与AC_next_state_LPS_64[64]。
如果要输出的区间范围小于28(range < QUARTER),则需作如下重整化处理。
如果下限大于等于29(low >= HALF),使用文件中的put_one_bit_plus_outstanding函数来输出1个或多个比特,然后更新下限(low -= HALF)。
如果下限小于28(low < QUARTER),使用文件中的put_one_bit_plus_outstanding函数来输出1个或多个比特。
如果下限处于28与29之间(QUARTER<=low< HALF),更新下限(low -= QUARTER)。
同时更新区间的下限与范围(low <<= 1, range <<= 1)。
再次检测区间范围,如果小于28,需不断进行重整化处理直至其值大于等于28。
biari_encode_symbol_eq_prob函数分析
void biari_encode_symbol_eq_prob(EncodingEnvironmentPtr eep, signed short symbol)
主要功能:对一个等概率的二进制符号(p(symbol) = 0.5)进行算术编码。
输入:编码环境指针,待编码符号。
初始化下限(low = (Elow<<1))。
如果编码符号为1(symbol != 0),更新下限(low += Erange)。
接着作重整化处理。
如果下限大于等于210(low >= ONE),使用biariencode.c文件中的put_one_bit_plus_ outstanding函数来输出1个或多个比特,然后更新下限(low -= ONE)。
如果下限小于29(low < HALF),使用biariencode.c文件中的put_one_bit_plus_ outstanding函数来输出1个或多个比特。
如果下限处于29与210之间(HALF<=low<ONE),更新下限(low -= HALF)。
biari_encode_symbol_final函数分析
void biari_encode_symbol_final(EncodingEnvironmentPtr eep, signed short symbol)
主要功能:终止前对最后一个符号进行算术编码。
输入:编码环境指针,待编码符号。
从编码环境中读取当前区间的下限与范围(range = Erange -2, low = Elow)。
如果待编码符号为1,更新当前区间的下限与范围(range = 2, low += range)。
接着作重整化处理。(与biari_encode_symbol函数中的重整化处理部分相同。)
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、 编码最高频的非零系数;
当前suffixLength
|
增加suffixLength的系数阈值
|
0
|
0
|
1
|
3
|
2
|
6
|
3
|
12
|
4
|
24
|
5
|
48
|
6
|
N/A
|
if(suffixLength == 0)更新suffixLength函数如下:
++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
CAVLC
编码过程:
假设有一个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;
编码完毕。
H.264中CAVLC解码过程详解
实例解析
{0 3 -1 0
0 -1 1 0
1 0 0 0
0 0 0 0} NC = 1
编码后得到输出码流为:0000 1000 1110 0101 1110 1101
解码详细过程如下:
1. 根据Coeff_token和NC查表(见标准表9-5),得到非零系数数目TotalCoeffs和拖尾系数数目TrailingOnes
NC = 1选择对应的表,Coeff_token为0000100,查表得到TotalCoeffs=5 TrailingOnes="3"
输出序列:无
2. 解析拖尾系数
由第一步得到拖尾系数有3个,输入拖尾系数符号编码码流011,得到两个拖尾系数由先到后是1,-1,-1
输出序列:1,-1,-1
3. 解析除拖尾系数外的非零系数的幅值(level)
(1) 确定后缀长度SuffixLength
(2) 根据码流查表9-6得到前缀LevelPrefix
(3) 根据前缀和后缀,得到LevelCode=(levelprefix<<suffixlength)+levelsuffix
(4) Levelcode为偶数 level=(level+2)/2
Levelcode为奇数 level=(-level-1)/2
(5) 根据设定的阈值确定是否update Suffixlegth
回到例子中,按照逆序
i=0,Sufixlegth=0,查表9-6,1对应的前缀levelprefix=0,levelcode=0,计算得到level=1,i++
i=1,sufixlegth=1,查表0010对应的前缀levelprefix=2,计算levelcode=4,level=3,i++
i=2>=TotalCoeffs-TrailingOnes,除拖尾系数外的非零系数解析完毕
输出序列:3,1,-1,-1,1
4. 解析每个非零系数前零的个数
根据TotalCoeffs=5和输入码流111查表9-7得到TotalZeros=3
初始i=TotalCoeffs-1=4,zeroleft=TotalZeros=3,5个非零系数前零的数目解析如下:
i=4,zeroleft=3,根据码流10查表9-10,runbefor=1,输出序列:3,1,-1,-1,0,1
i=3,zeroleft=3-1=2,根据码流1查表runbefore=0,输出序列:3,1,-1,-1,0,1
i=2,zeroleft=2-0=2,根据码流1查表runbefore=0,输出序列:3,1,-1,-1,0,1
i=1,zeroleft=2-0=2,根据码流01查表runbefore=1,输出序列:3,0,1,-1,-1,0,1
i=0,zeroleft=2-1=1,输出序列:0,3,0,1,-1,-1,0,1
5. 解码完毕,将剩下的元素用0补齐,反序排列就可以得到4*4矩阵。