VLC二--H264/AVC中CAVLC的FFmpeg实现

来源:互联网 发布:长沙学历网络教育报考 编辑:程序博客网 时间:2024/05/19 18:13

1.     算法描述

FFmpeg针对CAVLC做了大量的优化,主要体现在码表的构建和查找上。本章将从CAVLC码表的构建、查找和CAVLC残差解码三部分对CAVLC熵解码算法进行分析。

1.1.  CAVLC码表构建

1.1.1.    len和bits数组的构建

H264/AVC标准中表9-5、9-7~9-10是CAVLC的码表,针对每个码表FFmpeg定义了三个数组:xxx_len、xxx_bits和xxx_vlc,其中xxx_len存放的是对应二进制串的比特长度,xxx_bits存放的是对应二进制串的值,比如二进制串“0001 11”的len(长度)为6,bits(值)为7,xxx_vlc存放的是根据xxx_len和xxx_bits构建好的,供CAVLC最终使用的码表。

以表9-5中Nc==-1为例,表1表示的是YUV420P时的Chroma DC分量的coeff_token值。FFmpeg针对该coeff_token表构建了两个数组chroma_dc_coeff_token_len[4*5]和chroma_dc_coeff_token_bits[4*5],如图3所示。这两个数组的索引(key)是TotalCoeff和TrailingOnes的组合,等于((TotalCoeff<<2)| TrailingOnes)。联合图3和表1可以看出chroma_dc_coeff_token_len和chroma_dc_coeff_token_bits数组的0号位置存放的是coeff_token为“01”的二进制串的信息,数组的4号位置存放的是coeff_token为“000111”的二进制串的信息,其余依次类推,数组中多余的位置以0补充。

表1. Nc==-1时的coeff_token及其len和bits数组的构造原理

coeff_token

TrailingOnes

TotalCoeff

len

bits

key

01

0

0

2

1

0

0001 11

0

1

6

7

4

1

1

1

1

1

5

0001 00

0

2

6

4

8

0001 10

1

2

6

6

9

001

2

2

3

1

10

0000 11

0

3

6

3

12

0000 011

1

3

7

3

13

0000 010

2

3

7

2

14

0001 01

3

3

6

5

15

0000 10

0

4

6

2

16

0000 0011

1

4

8

3

17

0000 0010

2

4

8

2

18

0000 000

3

4

7

0

19


图3. 针对Chroma DC分量的coeff_token构造的len和bits数组

表9-5一共有六个表存在,需要对每个表都按照如上原理构造对应的len和bits数组(nC==-2是ChromaArrayType is equal to 2时对应的coeff_token表,目前只支持YUV420P,所以暂不考虑),表9-5中的coeff_token对应着TrailingOnes和TotalCoeff两个元素所以它的key值是由TrailingOnes和TotalCoeff组合而成,而9-7~9-10只存在一个值,所以其len和bits数组的构造略有差异。

如表2展示的是标准表9-9(a)的内容,表示的是ChromaDC 2x2 block的total_zeros的码表。联合表2和图4可以看出chroma_dc_total_zeros_len[0]对应于tzVlcIndex=1的一列,chroma_dc_total_zeros_len[1]对应于tzVlcIndex=2的一列等等,不存在的值补0。可以看出:其索引的顺序和标准表中的顺序是一样的。其他表对应的len和bits构造原理与此相同。由于level值是由level_prefix、一个比特的1和level_suffix组成,并没有固定的码表,所以针对level的解码没有相应的len和bits表,而是直接构造其对应的vlc表。

表2. Chroma DC 2x2 block的total_zeros的码表

total_zeros

tzVlcIndex

1

2

3

0

1

1

1

1

01

01

0

2

001

00

-

3

000

-

-


图4. Chroma DC 2x2 block的total_zeros的码表的len和bits数组

1.1.2.    vlc数组的构建和查找

1.1.2.1.     固定码表vlc数组的构建和查找

上面所说的len和bits数组的存在是为了构建最终供CAVLC使用的vlc码表。vlc码表只需要保存len和key。针对coeff_token,解码得到key便可以通过(key>>2)和(key&0x03)得到对应的TotalCoeff和TrailingOnes;针对其他语法元素解码得到的key值便是最终所需的解码值;针对level值需要根据其vlc的构造原则做相应的改变。在vlc中保存len的目的是为了确定是否需要进行二次映射。

为了大致说明vlc表的构造流程,本节构造了表3所示的一个total_zeros表,需要注意的是该表不是标准中定义的表,标准中定义的表是表2所示的内容,表3的内容是为了说明vlc表的构建过程而创造出来的。图5显示了表3所对应的len和bits数组。

表3. 自己构造的的self_total_zeros的码表

key

tzVlcIndex

1

2

0

1

1

1

01

01010

2

001

0011111

3

000

0011101

设VLC_BITS表示vlc码表的索引位数,则索引表有2^VLC_BITS个条目项可以作为索引,针对表3的self_total_zeros码表,我们设VLC_BITS=4,则vlc可以有16个条目作为索引,如表5所示。从表3可以看出,当tzVlcIndex=1时vlc码表有足够的位数表示每一个key,但当tzVlcIndex=2时4位的vlc码表不足以表示最大位数为7(“0011111”和“0011101”都是7位)的码表。下面将分别讲述tzVlcIndex=1和tzVlcIndex=2时vlc码表的计算方法。

tzVlcIndex=1时,vlc表的构造原理是:从(bits<< (VLC_BITS-len))位置开始,连续(1<< (VLC_BITS-len))位置都保存len和key。为了形象的展示计算过程,我们首先创建一个如表4所示的表,将表4中的code、key和len条目都按照表3和图5填上对应的内容。然后开始计算。

其具体步骤如下:

1)       设TOTAL_BITS为计算中寄存器的最大位数,本节假设TOTAL_BITS=32,将所有code按照(code<<(TOTAL_BITS-len))的方法移位为32位的code32;

2)       计算某个code32在vlc码表的起始索引idx,idx=code32>>( TOTAL_BITS- VLC_BITS);

3)       计算某个code32在vlc码表中重复的次数cnt,cnt=1<<( VLC_BITS-len)。

对所有的元素使用如上三步即可计算出最终的vlc码表。我们以tzVlcIndex=1,key=2为例:code=001、len=3,code32=code<<(32-3)=0x20000000,idx=code32>>(32-4)=2,cnt=1<<(4-3)=2,其含义为:从idx=2开始将紧挨着的cnt=2个vlc表的key和len赋值为对应的值。最终我们可以计算出表5所示的self_total_zeros_vlc码表。

图5. 自己构造的的total_zeros的码表对应的len和bits数组

表4. self_total_zeros码表tzVlcIndex=1的vlc码表计算表格

code

key

len

code32

idx

cnt

1

0

1

0x80000000

8

8

01

1

2

0x40000000

4

4

001

2

3

0x20000000

2

2

000

3

3

0x1a000000

0

2

表5. self_total_zeros码表tzVlcIndex=1的vlc码表self_total_zeros_vlc

idx

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

key

3

3

2

2

1

1

1

1

0

0

0

0

0

0

0

0

len

3

3

3

3

2

2

2

2

1

1

1

1

1

1

1

1

当我们解码self_total_zeros码表中tzVlcIndex=1的二进制串时,我们读入4个比特的二进制串,假设我们读入的二进制串为“1011”,其十进制值为11,我们查找表5中idx=11的元素,可以知道self_total_zeros_vlc[11].key=0,self_total_zeros_vlc[11].len=1,由于self_total_zeros_vlc[11].len=1,但是当前读入了4个比特,所以剩余的三个比特“011”在下一次解析的时候继续要被读入,经过如此的变换即可将标准中的变成编码的解码方式变成定长编码的解析方式,可以提高效率。

 

上面tzVlcIndex=1的例子中VLC_BITS=4可以完全处理所对应的二进制串。当tzVlcIndex=2时,可以知道VLC_BITS=4时所建立的映射表已经不能完全索引每个key值了,所以需要建立二级映射表。

我们仍然假设TOTAL_BITS=32且VLC_BITS=4,此时需要经过如下步完成vlc码表的构建。

1)       设TOTAL_BITS为计算中寄存器的最大位数,本节假设TOTAL_BITS=32,将所有code按照(code<<(TOTAL_BITS-len))的方法移位为32位的code32;

2)       针对所有len> VLC_BITS的元素,计算其各自的code_prefix=code32>>( TOTAL_BITS- VLC_BITS);

3)       针对所有len> VLC_BITS的元素,计算其各自的code32_2=code32<< VLC_BITS;

4)       针对所有len> VLC_BITS的元素,计算其各自的sub_bits=len- VLC_BITS;

5)       针对所有len> VLC_BITS的元素,将code_prefix相同的元素分为一组,将各组的max_sub_bits设置为该组所有二进制串的sub_bits的最大值;

6)       针对所有len> VLC_BITS的元素,将其二进制串的code32_2赋值给各自的code32;

7)       针对所有len> VLC_BITS的元素,在code_prefix相同的组内,将max_sub_bit赋值给VLC_BITS,各组的max_sub_bit可能不同,因此VLC_BITS也就可能不同;

8)       针对所有len> VLC_BITS的元素,设置每个元素的len=len-VLC_BITS;

9)       针对所有len> VLC_BITS的元素,按照code_prefix组为单位,对code_prefix组内的所有元素调用第11)和12)的步骤,处理完成转第10)步;

10)   针对所有len> VLC_BITS的元素,code_prefix作为各组的一级索引idx,一级索引的len填为各组max_sub_bit的相反数,即-max_sub_bit,一级索引的key填为对应二级索引的地址;二级索引的idx和cnt为第11)和12)步中计算的idx和cnt,二级索引的key为各元素的code32_2的值,二级索引的len值为各元素第8)步计算后的len值,计算完成转13)步;

11)   计算某个code32在vlc码表的起始索引idx,idx=code32>>( TOTAL_BITS- VLC_BITS);

12)   计算某个code32在vlc码表中重复的次数cnt,cnt=1<<( VLC_BITS-len);

13)   针对所有len<= VLC_BITS的元素按照第11)和第12)的步骤执行。

14)   针对所有len<= VLC_BITS的元素,第11)和12)步中计算的idx和cnt作为一级索引,len和key填充对应各项的len和key;

15)   未填充项目的len设置为0,key设置为-1,结束。

根据以上算法表3中tzVlcIndex=2时,各二进制串的vlc码表的计算表格如表6所示,其建立的二级映射关系如图6所示。

表6. self_total_zeros码表tzVlcIndex=2的vlc码表计算表格

code

key

len

code32

code_prefix

code32_2

sub_bits

idx

cnt

1

0

1

0x80000000

-

8

8

01010

1

5

0x50000000

0x00000005

0x00000000

1

0

1

000111

2

6

0x1c000000

0x00000001

0xc0000000

2

6

2

0001101

3

7

0x1a000000

0x00000001

0xa0000000

3

5

1


图6. self_total_zeros码表tzVlcIndex=2的vlc二级映射码表

假设需要查找二进制串为“00011101”由于VLC_BITS=4,所以读入二进制串的前4比特“0001”,查找图6所示的一级索引表,可以知道一级索引表的idx=1的位置的len=-3,key指向二级索引。由于一级索引的len=-3,所以二级索引表需要继续读入3个比特“110”,所以二级索引的idx=110(二进制)=6,查找二级索引表idx=6的信息可以知道len=2,key=2。由于二级索引中idx=6的项的len=2,所以,最终查找的二进制串为“000111”,二进制串“00011101”的后两位下次需要继续读入。

需要注意的是上述建立vlc码表的过程中经常出现(code<<(TOTAL_BITS-len))和code_prefix=code32>>( TOTAL_BITS-VLC_BITS)等移位操作,而且移位都和TOTAL_BITS有关。假设TOTAL_BITS=32,如果在同一个码表中具有如下两个二进制串“01”和“001”,如果按照code32 = (code<<(TOTAL_BITS-len))的方式进行移位,那么二进制串“01”将被移位为“0x40000000”,而二进制串“001”将被移位为“0x20000000”,如此这样才符合码流的从左到右的读取顺序,如果是将二进制串“01”扩充为“0x00000001”,把二进制串“001”也扩充为“0x00000001”,如果对他们建立vlc码表,那么将可能导致码表重叠等无法区分每个二进制串的情况发生。

1.1.2.2.     level的vlc数组的构建和查找

level系数由level_prefix、“1”和level_suffix三部分组成,并没有像H264/AVC标准中表9-5、9-7~9-10一样的固定码表可以用于构建vlc码表,且level_prefix和level_suffix的长度prefix_length和suffix_length不固定,所以其构建的码表分为了三种情况。

第一种情况是prefix_length+1+suffix_length<=LEVEL_TAB_BITS,在解码的时候一次读入8比特的二进制串,如图7(a)所示,可知8比特的数据长度由4部分长度组成:level_prefix的长度prefix_length、比特1、level_suffix的长度suffix_length和m个无效比特位。假设该8比特的二进制串对应的十进制为val,则可以知道suffix_length和m个无效比特位的长度为log2(val),则m个无效比特位的长度为m=log2(val)-suffix_length,则将m个无效位右移后由比特“1”和suffix_length两部分组成,如图7(b),其值为val>>m=val>>(log2(val)-suffix_length),因此suffix_length部分的level_suffix=(val>>m)-(1<<suffix_length)=val>>(log2(val)-suffix_length)-(1<<suffix_length),因此该8比特的数字代码的值level=level_prefix+level_suffix=(prefix<<1)+val>>(log2(val)-suffix_length)-(1<<suffix_length)。

图7. 第一种情况的比特组成

第二种情况是prefix_length+1<=LEVEL_TAB_BITS,第三种情况是prefix_length==LEVEL_TAB_BITS。

其存储结构仍然和前面vlc码表的存储方式一样,需要保存len和key。针对第一种情况len保存prefix_length+1+suffix_length之和,key保存为最终的level值,即(level_prefix<<suffix_length)+level_suffix且进行了正负号映射之后的值;针对第二种情况len保存prefix_length+1之和,key保存为level_prefix+100;针对第三种情况len保存为LEVEL_TAB_BITS,key保存为LEVEL_TAB_BITS+100;这里的100可以是其他不会造成冲突的值,其中第二种情况保存的level_prefix+100肯定小于第三种情况保存的LEVEL_TAB_BITS+100,因为第二种情况下prefix_length+1 <=LEVEL_TAB_BITS,即level_prefix<= LEVEL_TAB_BITS-1(因为level的前缀采用一元码的编码方式,所以level_prefix就等于prefix_length)。

根据以上的算法分析,可以生成图8所示的level值的vlc码表,这里由于显示空间的原因,这里只显示了每个suffix_length的前16个元素。由于存储空间的原因,level值的存储也是LEVEL_TAB_BITS =8比特作为一级索引的大小。在解码时,首先读入8比特的一个值val,同时根据当前的suffix_length的值,查找key=level_vlc[suffix_length][val][0]和len=level_vlc[suffix_length][val][1];当key<100时,key表示最终解码需要的真实的key值,len表示该key值需要的比特长度,比如val=10,suffix_length=1,则key=level_vlc[1][10][0]=5和len=level_vlc[1][10][1]=6,说明当前的key值只需要6比特表示,剩余的2比特下次解码时仍然需要读入;当val=108时,表示prefix_length= LEVEL_TAB_BITS=8,需要继续解码前缀和后缀,否则100<val<108时表示prefix=val-100,后缀为suffix_length,然后根据标准即可计算最终的level值。

                                          图8. level值的vlc码表level_vlc

1.2.  CAVLC残差解码

上一小节所有建立的vlc查找表都是为了在残差解码时使用的。残差解码的过程主要分为:解码coeff_token(非零系数个数TotalCoeffs和拖尾系数TrailingOnes)、解析拖尾系数符号、解析除拖尾系数外的非零系数的值、解析最后一个非零系数前零的个数TotalZeros和解析每个非零系数前零的个数RunBefore五步。

static int decode_residual(const H264Context *h, H264SliceContext *sl,GetBitContext *gb, int16_t *block, int n,const uint8_t *scantable, const uint32_t *qmul,int max_coeff){static const int coeff_token_table_index[17] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3 };int level[16];int zeros_left, coeff_token, total_coeff, i, trailing_ones, run_before;if (max_coeff <= 8){if (max_coeff == 4)coeff_token = get_vlc2(gb, chroma_dc_coeff_token_vlc.table, 8, 1);elsecoeff_token = get_vlc2(gb, chroma422_dc_coeff_token_vlc.table, 13, 1);total_coeff = coeff_token >> 2;}else{if (n >= LUMA_DC_BLOCK_INDEX){total_coeff = pred_non_zero_count(h, sl, (n - LUMA_DC_BLOCK_INDEX) * 16);coeff_token = get_vlc2(gb, coeff_token_vlc[coeff_token_table_index[total_coeff]].table, 8, 2);total_coeff = coeff_token >> 2;}else{total_coeff = pred_non_zero_count(h, sl, n);coeff_token = get_vlc2(gb, coeff_token_vlc[coeff_token_table_index[total_coeff]].table, 8, 2);total_coeff = coeff_token >> 2;}}sl->non_zero_count_cache[scan8[n]] = total_coeff;if (total_coeff == 0)return 0;if (total_coeff > (unsigned)max_coeff) {av_log(h->avctx, AV_LOG_ERROR, "corrupted macroblock %d %d (total_coeff=%d)\n", sl->mb_x, sl->mb_y, total_coeff);return -1;}trailing_ones = coeff_token & 3;ff_tlog(h->avctx, "trailing:%d, total:%d\n", trailing_ones, total_coeff);av_assert2(total_coeff <= 16);i = show_bits(gb, 3);skip_bits(gb, trailing_ones);level[0] = 1 - ((i & 4) >> 1);level[1] = 1 - ((i & 2));level[2] = 1 - ((i & 1) << 1);if (trailing_ones<total_coeff) {int mask, prefix;int suffix_length = total_coeff > 10 & trailing_ones < 3;int bitsi = show_bits(gb, 8);int level_code = cavlc_level_tab[suffix_length][bitsi][0];skip_bits(gb, cavlc_level_tab[suffix_length][bitsi][1]);if (level_code >= 100){prefix = level_code - 100;if (prefix == 8)prefix += get_level_prefix(gb);if (prefix<14){if (suffix_length)level_code = (prefix << 1) + get_bits1(gb);elselevel_code = prefix;}else if (prefix == 14){if (suffix_length)level_code = (prefix << 1) + get_bits1(gb);elselevel_code = prefix + get_bits(gb, 4);}else{level_code = 30;if (prefix >= 16){if (prefix > 25 + 3){av_log(h->avctx, AV_LOG_ERROR, "Invalid level prefix\n");return -1;}level_code += (1 << (prefix - 3)) - 4096;}level_code += get_bits(gb, prefix - 3);}if (trailing_ones < 3) level_code += 2;suffix_length = 2;mask = -(level_code & 1);level[trailing_ones] = (((2 + level_code) >> 1) ^ mask) - mask;}else{level_code += ((level_code >> 31) | 1) & -(trailing_ones < 3);suffix_length = 1 + (level_code + 3U > 6U);level[trailing_ones] = level_code;}for (i = trailing_ones + 1; i<total_coeff; i++) {static const unsigned int suffix_limit[7] = { 0, 3, 6, 12, 24, 48, INT_MAX };int bitsi = show_bits(gb, 8);level_code = cavlc_level_tab[suffix_length][bitsi][0];skip_bits(gb, cavlc_level_tab[suffix_length][bitsi][1]);if (level_code >= 100){prefix = level_code - 100;if (prefix == 8){prefix += get_level_prefix(gb);}if (prefix<15){level_code = (prefix << suffix_length) + get_bits(gb, suffix_length);}else{level_code = 15 << suffix_length;if (prefix >= 16) {if (prefix > 25 + 3){av_log(h->avctx, AV_LOG_ERROR, "Invalid level prefix\n");return AVERROR_INVALIDDATA;}level_code += (1 << (prefix - 3)) - 4096;}level_code += get_bits(gb, prefix - 3);}mask = -(level_code & 1);level_code = (((2 + level_code) >> 1) ^ mask) - mask;}level[i] = level_code;suffix_length += suffix_limit[suffix_length] + level_code > 2U * suffix_limit[suffix_length];}}if (total_coeff == max_coeff)zeros_left = 0;else{if (max_coeff <= 8) {if (max_coeff == 4)zeros_left = get_vlc2(gb, (chroma_dc_total_zeros_vlc - 1)[total_coeff].table,3, 1);elsezeros_left = get_vlc2(gb, (chroma422_dc_total_zeros_vlc - 1)[total_coeff].table,5, 1);}else {zeros_left = get_vlc2(gb, (total_zeros_vlc - 1)[total_coeff].table, 9, 1);}}if (h->pixel_shift) {//}else {scantable += zeros_left + total_coeff - 1;if (n >= LUMA_DC_BLOCK_INDEX){((int16_t*)block)[*scantable] = level[0];for (i = 1; i<total_coeff && zeros_left > 0; i++){if (zeros_left < 7)run_before = get_vlc2(gb, (run_vlc - 1)[zeros_left].table, 3, 1);elserun_before = get_vlc2(gb, run7_vlc.table, 6, 2);zeros_left -= run_before;scantable -= 1 + run_before;((int16_t*)block)[*scantable] = level[i];}for (; i<total_coeff; i++){scantable--;((int16_t*)block)[*scantable] = level[i];}}else{((int16_t*)block)[*scantable] = ((int)(level[0] * qmul[*scantable] + 32)) >> 6;for (i = 1; i<total_coeff && zeros_left > 0; i++){if (zeros_left < 7)run_before = get_vlc2(gb, (run_vlc - 1)[zeros_left].table, 3, 1);elserun_before = get_vlc2(gb, run7_vlc.table, 6, 2);zeros_left -= run_before;scantable -= 1 + run_before;((int16_t*)block)[*scantable] = ((int)(level[i] * qmul[*scantable] + 32)) >> 6;}for (; i<total_coeff; i++){scantable--;((int16_t*)block)[*scantable] = ((int)(level[i] * qmul[*scantable] + 32)) >> 6;}}}if (zeros_left<0){av_log(h->avctx, AV_LOG_ERROR, "negative number of zero coeffs at %d %d\n", sl->mb_x, sl->mb_y);return -1;}return 0;}


上面所示的代码进行了一些调整:为了简单起见删除了部分代码。代码中第9~35行是属于解码coeff_token部分,38~42行是解析拖尾系数符号,43~116行解析除拖尾系数外的非零系数的值,117~131行解析最后一个非零系数前零的个数TotalZeros,132~175解析每个非零系数前零的个数RunBefore并将最终的level值保存到数组中。

代码中第9~35行是属于解码coeff_token部分,其中第9~15行是对Chroma的DC分量的coeff_token进行解码,第16~27行是对其他情况下的coeff_token进行解码,第35行是对TrailingOnes进行解码。在这部分最重要的就是get_vlc2函数,该函数的解码规则对应着前面已经详细讲解了的编码规则。由于coeff_token的低两比特表示拖尾系数的个数TrailingOnes,其他比特表示非零系数个数TotalCoeffs。

38~42行是解析拖尾系数符号,拖尾系数的个数取值范围是0~3,一个比特表示一个符号位,比特0表示拖尾系数为+1,比特1表示拖尾系数为-1。为了防止判断,此处直接解析三个值,然后再跟进实际的拖尾系数的个数跳过trailing_ones个比特。((i& 4) >> 1)的值为000或者010,((i& 2))的值为000或者010,((i& 1)<< 1)的值也是000或者010,然后用数值1减去他们的值即可得到最终的拖尾系数值。

43~116行解析除拖尾系数外的非零系数的值。其中49~85解析第一个非零系数的值,86~115解析剩下的非零系数值,之所以如此是因为第一个非零系数的值的处理情况有点儿特殊,为了减少分支判断等,所以特别单独处理。第45行(total_coeff> 10) & (trailing_ones < 3)暗示非零幅值系数有可能比较稠密、比较大,所以将suffix_length赋值为1,相当于对非零系数值直接除以2而非1,然后进行编解码。第49行表示prefix_length>=7,第51~52行表示prefix_length>=8,需要继续读取余下的二进制串才能确定前缀长度。根据CAVLC标准可知,只有第一个非零系数值的suffix_length才有可能为0,所以第54行和60行需要判断suffix_length是否为0,然后根据不同情况读取指定位数的后缀;第63行是针对对第一个非零系数幅值的level>=14 且小于等于29(14 + (4bit所能表示的最大值15))的值进行编码的方法。第66行level_code=30是根据标准中的第4条:The variable levelCode is setequal to ( Min( 15, level_prefix ) << suffixLength ) + level_suffix和第5条:When level_prefix is greater than or equal to 15 and suffixLength isequal to 0, levelCode is incremented by 15两天标准可以推导而得,现在正在解码第一个非零系数值,所以suffixLength只可能为0或者为1,当suffixLength=0时第四条可以得到Min( 15, level_prefix ),第5条可以得到( 15, level_prefix )+15=30,当suffixLength为1时,第4条可以得到Min( 15, level_prefix )<<1=30,综上可以得到第66行的level_code=30。标准中第7条:When the index i is equal to TrailingOnes( coeff_token ) andTrailingOnes( coeff_token ) is less than 3, levelCode is incremented by 2,而76行只判断了trailing_ones < 3,是因为第一次计算level_code时,一定是i==trailing_ones的那个level,因为,前面已经解析了trailing_ones个拖尾系数。标准中第9条:When suffixLength is equal to 0,suffixLength is set equal to 1,第10条:When theabsolute value of levelVal[i] is greater than (3 <<(suffixLength-1))andsuffixLength is less than 6, suffixLength is incremented by 1,根据条件9和10可知:第一,suffix_length为0时,suffix_length设为1,第二,阈值threshold= 3<<(suffix_length-1)=3<<0=3,第三,判断suffix_length是否要增加suffix_length+=((level[i]>threshold)|| (level[i]<-threshold))&&(suffix_length< 6),进入到77行所在的分支一定有prefix>=8,所以level一定大于其对应的阈值3,综上可以得出suffix_length=2。第78和79行mask==0时,level_code=(2+level_code)>>1,mask==1时,level_code=(((2 + level_code)>> 1) ^ mask) - mask=(((2 + level_code) >> 1) ^ 0xffffffff) -0xffffffff=(((2 + level_code) >> 1) ^ 0xffffffff) + 1 =-((2 + level_code)>> 1),即为其相反数,简单的运算即完成了奇偶数判断并根据奇数和偶数的不同情况取了正数或者负数。前面在分析level的vlc码表构建的时候已经知道当属于第一种情况时,vlc码表中存储的是最终的level值,所以第82行不再需要进行奇偶判断和除2等操作,但是在前面计算的时候没有将trailing_ones <3的情况计算在内,故在这里需要将这一情况补上,当level_code为奇数时,需要在level_code的基础上减去1,当level_code为偶数时需要将level_code加1,当level_code为奇数时((level_code >> 31) | 1)为0xffffffff,当level_code为偶数时((level_code >> 31) | 1)为0x00000001,当trailing_ones < 3时(-(trailing_ones < 3))为-1,0xffffffff&-1=-1,0x00000001&-1=1。第114行中suffix_limit[7]={0,3,6,12,24,48,INT_MAX}是根据公式(3<<(suffixLength-1))计算出来的阈值,当level_code>suffix_limit[suffix_length]时,suffix_limit[suffix_length] +level_code>((suffix_limit[suffix_length]) << 1),相当于suffix_length+=1;当level_code<=suffix_limit[suffix_length]时,suffix_limit[suffix_length] +level_code<=((suffix_limit[suffix_length]) << 1),相当于suffix_length+=0,当suffix_length=6时,suffix_limit[6]=HKA_MAX_S32=2147483647,suffix_limit[6]+level_code一定小于2*HKA_MAX_S32=4294967294,所以当suffix_length==6时,suffix_length将不再发生变化。

其余部分代码逻辑相对简单,在此不再赘述。

1 0
原创粉丝点击