注:HM代码版本为HM-16.2+SCM-3.0rc1/。
对应TDecSbac::parseCoeffNxN()函数解析。暂时先忽略掉几个模式:pcCU->getCUTransquantBypass(uiAbsPartIdx)、pcCU->getSlice()->getPPS()->getUseTransformSkip()、pcCU->isRDPCMEnabled(uiAbsPartIdx),这些判断假定全部为假。
忽略掉以上几个模式之后,程序流程图如下:
图8 逆扫描流程图
关于流程图说明以下几个问题。
1. 获取的编码参数
获取的编码参数如下表所示。
表2 获取的编码参数
参数 |
备注 |
像素点扫描表 |
若块尺寸为8x8,那么g_scanOrder中尺寸为:log2BlockWidth=3,log2BlockHeight=3 |
CG扫描表 |
若块尺寸为8x8,那么g_scanOrder中尺寸为:log2WidthInGroups=1,log2HeightInGroups=1 |
扫描方式 |
扫描方式是按照与编码端相同的方式推断出来的 |
CG尺寸 |
包括宽度和高度,意为当前TU包含几个CG |
firstSignificanceMapContext |
与熵解码相关,这里暂不作讨论 |
2. 获取最后一个非零系数的位置
获取最后一个非零系数的位置是熵解码的过程,是编码端写进码流里的,这里暂不做讨论。
3. 为什么要通过像素点扫描表找到最后一个非零系数的位置?
通过熵解码得到的最后一个非零系数的位置是编码端传过来的,在编码端它表征的是在扫描之前最后一个非零量化系数的位置,这个位置我猜测是与扫描顺序相反的顺序找到的,具体查找过程推测如下。
首先,这个位置的查找过程是跟扫描方式相关的,而且是以4x4为单位进行查找的。以对角扫描方式、查找16x16亮度块为例,CG的光栅扫描顺序如下图。
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
图9 CG的光栅扫描顺序
CG的对角扫描顺序如下图所示。
0 |
4 |
1 |
8 |
5 |
2 |
12 |
9 |
6 |
3 |
13 |
10 |
7 |
14 |
11 |
15 |
图10 CG的对角扫描顺序
那么最后一个非零系数的查找过程是按照与对角扫描顺序相反的过程进行查找的:首先查找位置为15的CG的4x4=16个系数是否全为0,如果全为0,那么继续按照11->14->7->…->1->4->0的顺序依次进行查找。如果找到某一个CG发现该CG内包含非零系数,那么再在此CG内同样按照与对角扫描顺序相反的顺序进行查找。
编码端通过以上方式找到的位置是光栅扫描位置,所以对应到解码端需要将该位置映射到对应的扫描方式的位置。
以8x8亮度块为例,如下图所示,绿色系数值表示系数为0,红色表示最后一个非零系数值,黑色系数表示系数是否为0未知。首先在右下角的4x4像素点内发现全部为0,那么继续在右上角的4x4内查找发现包含非零系数值;实际上在该4x4内查找时也是按照与扫描顺序相反的顺序进行查找的,发现该4x4内绿色部分系数全为0,最后一个非零位置为5,因此将该位置发送到解码端。所以,实际上该4x4内只包含三个非零系数。
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
图11 最后一个非零系数位置示例
解码端收到最后一个非零系数的位置为5之后,在像素点扫描表中找到该位置对应的索引值为34,如下图所示。
0 |
8 |
1 |
16 |
9 |
2 |
24 |
17 |
10 |
3 |
25 |
18 |
11 |
26 |
19 |
27 |
32 |
40 |
33 |
48 |
41 |
34 |
56 |
49 |
42 |
35 |
57 |
50 |
43 |
58 |
51 |
59 |
4 |
12 |
5 |
20 |
13 |
6 |
28 |
21 |
14 |
7 |
29 |
22 |
15 |
30 |
23 |
31 |
36 |
44 |
37 |
52 |
45 |
38 |
60 |
53 |
46 |
39 |
61 |
54 |
47 |
62 |
55 |
63 |
图12 像素点扫描表中最后一个非零系数示例
4. 如何通过以上位置推断出有效CG的最大索引?
有了最后一个非零系数在像素点扫描表中的映射位置,将该位置的一维索引值除以16即可得到。
5. 有效CG之间的逆扫描顺序是怎样的?
有效CG之间的逆扫描顺序也是按照与扫描顺序相反的顺序进行解码的。
以8x8亮度块、对角扫描方式为例,假如编码端传过来的最后一个非零系数的位置为5,那么通过像素点扫描表的映射找到的位置为34,那么有效CG的最大索引为34/16=2,按照下图所示的CG扫描表,解码器按照1->2->0的顺序对三个4x4块进行解码。
0 |
2 |
1 |
3 |
图13 8x8 CG扫描表
6. CG内部的逆扫描过程
且听下文分解。