ZigZag Sin
登 陆
后面没有了 上一篇:CAVLC 的介绍

读取 TotalCoeff 和 TrailingOnes

乔红
2021-5-7 15:23 阅读 285

本小节由 逆水行舟 赞助支持~~~

引言

本小节,我们来介绍如何从 CAVLC 的码流里将 TotalCoeffTrailingOnes 读出来。

码表

我们先来观察一下 TotalCoeffTrailingOnes 的码表。

cavlc1

这个码表描述了 TotalCoeffTrailingOnes 的存放情况,可以看到,TotalCoeffTrailingOnes 是放在一起存放的。

0 <= nC < 2 的第二行来举例,如果我们读到一个长度为 6 bit,其值为 000101 的码流是,我们就可以解出来 TotalCoeff 等于 1,TrailingOnes 等于 0。

所以我们只需要从读取我们的码流里的数据,然后和码表中对应的数据进行比对,就可以找出其对应的 TotalCoeffTrailingOnes

但是,如果我们这样暴力得去找得话,这个码表有 62 行,要写的代码就太多了。

有没有什么聪明一点得办法能来读取这个码表呢?

TotalCoeffTrailingOnes 的取值范围

要研究更聪明的读取方式,我们就先得研究一下 TotalCoeffTrailingOnes

我们前面已经介绍过,TotalCoeff 表示的是非零系数的总数,我们之前的内容曾经说过,残差数据的长度是 16 或者 15。这样 TotalCoeff 的取值范围就是 [0, 16] 共 17 种情况。

TrailingOnes 表示的是拖尾系数的个数,拖尾系数最大为 3,所以 TrailingOnes 的取值范围就是 [0, 3],共 4 种情况。

这样,TotalCoeffTrailingOnes 通过排列组合,那就有 4 * 17 一共 68 种情况(对于一种 nC)。

但是这里面有一些特殊值要处理,由于 TotalCoeff 是一定要大于等于 TrailingOnes 的(自己琢磨为啥。。。)所以这 68 种情况要去掉几种 TotalCoeff 小于 TrailingOnes 的情况,最后有 62 种情况。

有了这些知识,我们再来观察一下码表。你就会发现,这个码表,也变得眉清目秀起来了。

cavlc2_tag

创建表格

依照这张码表的特性,我们可以将所有的码字装进一个 17 * 4 的表格里面去。

横坐标表示 TotalCoeff 一共 17 列。

纵坐标表示 TrailingOnes 一共 4 行。

cavlc_table

当然,表格中的某一些是不存在的。我给他标记了出来。

所以,当我们要读取 TotalCoeffTrailingOnes 的时候,只要循环遍历这个表格,找到码流中与之匹配的一项,然后取这项的行列坐标,分别就是 TotalCoeffTrailingOnes

例如,我们正好匹配到了下图中蓝色的这一项,那么 TotalCoeff 就是其横坐标 5,TrailingOnes 就是其纵坐标 1。

cavlc_table_example

如何匹配码表

我们已经成功得将码表组织成了一个二维的表格,现在我们要从码流中读取数据,来匹配表格中的码字。

我们可以从头到尾,用一个双层循环来做这个操作。

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{
            // 没找到,继续循环
        }
    }
}

这样,我们就成功读取到了 TotalCoeffTrailingOnes

附录-码表的二位数组(0 <= nC < 8)

  • 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},
    }
    
后面没有了 上一篇:CAVLC 的介绍
给我买个键盘吧。。。求打赏。。。
欢迎加群,一起交流~~~