第一章 前言
第三章 有关 SPS 和 PPS 的一切
第四章 有关 Slice 的一切
第七章 帧间编码
第八章 残差的熵编码: CAVLC 和 CABAC
本小节,我们来介绍如何从 CAVLC 的码流里将 TotalCoeff 和 TrailingOnes 读出来。
我们先来观察一下 TotalCoeff 和 TrailingOnes 的码表。
这个码表描述了 TotalCoeff 和 TrailingOnes 的存放情况,可以看到,TotalCoeff 和 TrailingOnes 是放在一起存放的。
拿 0 <= nC < 2 的第二行来举例,如果我们读到一个长度为 6 bit,其值为 000101 的码流是,我们就可以解出来 TotalCoeff 等于 1,TrailingOnes 等于 0。
所以我们只需要从读取我们的码流里的数据,然后和码表中对应的数据进行比对,就可以找出其对应的 TotalCoeff 和 TrailingOnes。
但是,如果我们这样暴力得去找得话,这个码表有 62 行,要写的代码就太多了。
有没有什么聪明一点得办法能来读取这个码表呢?
要研究更聪明的读取方式,我们就先得研究一下 TotalCoeff 和 TrailingOnes。
我们前面已经介绍过,TotalCoeff 表示的是非零系数的总数,我们之前的内容曾经说过,残差数据的长度是 16 或者 15。这样 TotalCoeff 的取值范围就是 [0, 16] 共 17 种情况。
TrailingOnes 表示的是拖尾系数的个数,拖尾系数最大为 3,所以 TrailingOnes 的取值范围就是 [0, 3],共 4 种情况。
这样,TotalCoeff 和 TrailingOnes 通过排列组合,那就有 4 * 17 一共 68 种情况(对于一种 nC)。
但是这里面有一些特殊值要处理,由于 TotalCoeff 是一定要大于等于 TrailingOnes 的(自己琢磨为啥。。。)所以这 68 种情况要去掉几种 TotalCoeff 小于 TrailingOnes 的情况,最后有 62 种情况。
有了这些知识,我们再来观察一下码表。你就会发现,这个码表,也变得眉清目秀起来了。
依照这张码表的特性,我们可以将所有的码字装进一个 17 * 4 的表格里面去。
横坐标表示 TotalCoeff 一共 17 列。
纵坐标表示 TrailingOnes 一共 4 行。
当然,表格中的某一些是不存在的。我给他标记了出来。
所以,当我们要读取 TotalCoeff 和 TrailingOnes 的时候,只要循环遍历这个表格,找到码流中与之匹配的一项,然后取这项的行列坐标,分别就是 TotalCoeff 和 TrailingOnes。
例如,我们正好匹配到了下图中蓝色的这一项,那么 TotalCoeff 就是其横坐标 5,TrailingOnes 就是其纵坐标 1。
我们已经成功得将码表组织成了一个二维的表格,现在我们要从码流中读取数据,来匹配表格中的码字。
我们可以从头到尾,用一个双层循环来做这个操作。
int tableHeight = 4;
int tableWidth = 17;
for(int yIdx = 0; yIdx < tableHeight; yIdx++) {
for(int xIdx = 0; xIdx < tableWidth; xIdx++) {
// TODO
}
}
在循环中,我们需要读取码流中的数据,来和码表做比对。但是这里有一个比较麻烦的地方,就是码表中的码字是变长的。我们并不知道要读取多少个 bit 的数据。所以,我们就需要将码表中码字的长度储存起来。
例如,我们把 0 <= nC < 2 的码字长度存放到一个二位数组里面:
int CoeffTokenTableLength[4][17] =
{
{ 1, 6, 8, 9,10,11,13,13,13,14,14,15,15,16,16,16,16},
{ 0, 2, 6, 8, 9,10,11,13,13,14,14,15,15,15,16,16,16},
{ 0, 0, 3, 7, 8, 9,10,11,13,13,14,14,15,15,16,16,16},
{ 0, 0, 0, 5, 6, 7, 8, 9,10,11,13,14,14,15,15,16,16},
};
int tableHeight = 4;
int tableWidth = 17;
for(int yIdx = 0; yIdx < tableHeight; yIdx++) {
for(int xIdx = 0; xIdx < tableWidth; xIdx++) {
int codeLen = CoeffTokenTableLength[yIdx][xIdx];
// 从码流中读取 codeLen 个 bit 的数据
}
}
从码流中读取到数据后,就要和码表中的码字做一个比较了。当然,我们也把码字放到一个二位数组里面:
int CoeffTokenTableLength[4][17] =
{
{ 1, 6, 8, 9,10,11,13,13,13,14,14,15,15,16,16,16,16},
{ 0, 2, 6, 8, 9,10,11,13,13,14,14,15,15,15,16,16,16},
{ 0, 0, 3, 7, 8, 9,10,11,13,13,14,14,15,15,16,16,16},
{ 0, 0, 0, 5, 6, 7, 8, 9,10,11,13,14,14,15,15,16,16},
};
int CoeffTokenTableCode[4][17] =
{
{ 1, 5, 7, 7, 7, 7,15,11, 8,15,11,15,11,15,11, 7,4},
{ 0, 1, 4, 6, 6, 6, 6,14,10,14,10,14,10, 1,14,10,6},
{ 0, 0, 1, 5, 5, 5, 5, 5,13, 9,13, 9,13, 9,13, 9,5},
{ 0, 0, 0, 3, 3, 4, 4, 4, 4, 4,12,12, 8,12, 8,12,8},
};
int tableHeight = 4;
int tableWidth = 17;
for(int yIdx = 0; yIdx < tableHeight; yIdx++) {
for(int xIdx = 0; xIdx < tableWidth; xIdx++) {
int codeLen = CoeffTokenTableLength[yIdx][xIdx];
int code = ......; //从码流中读取 codeLen 个 bit 的数据
if(code == CoeffTokenTableCode[yIdx][xIdx]){
// 找到了
int TotalCoeff = xIdx;
int TrailingOnes = yIdx;
}
else{
// 没找到,继续循环
}
}
}
这样,我们就成功读取到了 TotalCoeff 和 TrailingOnes 。
0 <= nC < 2 码表的二维数组
Length:
{
{ 1, 6, 8, 9,10,11,13,13,13,14,14,15,15,16,16,16,16},
{ 0, 2, 6, 8, 9,10,11,13,13,14,14,15,15,15,16,16,16},
{ 0, 0, 3, 7, 8, 9,10,11,13,13,14,14,15,15,16,16,16},
{ 0, 0, 0, 5, 6, 7, 8, 9,10,11,13,14,14,15,15,16,16},
}
Code
{
{ 1, 5, 7, 7, 7, 7,15,11, 8,15,11,15,11,15,11, 7,4},
{ 0, 1, 4, 6, 6, 6, 6,14,10,14,10,14,10, 1,14,10,6},
{ 0, 0, 1, 5, 5, 5, 5, 5,13, 9,13, 9,13, 9,13, 9,5},
{ 0, 0, 0, 3, 3, 4, 4, 4, 4, 4,12,12, 8,12, 8,12,8},
}
2 <= nC < 4 码表的二维数组 Length:
{
{ 2, 6, 6, 7, 8, 8, 9,11,11,12,12,12,13,13,13,14,14},
{ 0, 2, 5, 6, 6, 7, 8, 9,11,11,12,12,13,13,14,14,14},
{ 0, 0, 3, 6, 6, 7, 8, 9,11,11,12,12,13,13,13,14,14},
{ 0, 0, 0, 4, 4, 5, 6, 6, 7, 9,11,11,12,13,13,13,14},
}
Code
{
{ 3,11, 7, 7, 7, 4, 7,15,11,15,11, 8,15,11, 7, 9,7},
{ 0, 2, 7,10, 6, 6, 6, 6,14,10,14,10,14,10,11, 8,6},
{ 0, 0, 3, 9, 5, 5, 5, 5,13, 9,13, 9,13, 9, 6,10,5},
{ 0, 0, 0, 5, 4, 6, 8, 4, 4, 4,12, 8,12,12, 8, 1,4},
}
4 <= nC < 8 码表的二维数组
Length:
{
{ 4, 6, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 9,10,10,10,10},
{ 0, 4, 5, 5, 5, 5, 6, 6, 7, 8, 8, 9, 9, 9,10,10,10},
{ 0, 0, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,10},
{ 0, 0, 0, 4, 4, 4, 4, 4, 5, 6, 7, 8, 8, 9,10,10,10},
}
Code
{
{15,15,11, 8,15,11, 9, 8,15,11,15,11, 8,13, 9, 5,1},
{ 0,14,15,12,10, 8,14,10,14,14,10,14,10, 7,12, 8,4},
{ 0, 0,13,14,11, 9,13, 9,13,10,13, 9,13, 9,11, 7,3},
{ 0, 0, 0,12,11,10, 9, 8,13,12,12,12, 8,12,10, 6,2},
}
695101696@qq.com
2024-01-18 16:06:46
2369398685@qq.com
2023-10-04 16:42:50