H.264熵解码详细过程

1、三种熵编码形式

熵编码是无损压缩编码方法,它生成的码流可以经熵解码无失真地恢复出数据。
对应熵编码方案,在H.264标准中也有3种熵解码方案: 指数哥伦布解码,CAVLC解码和CABAC解码。在标准中通过描述子(Descriptor)的形式来说明一个语法元素熵解码的方法。对于片层以上的语法元素有定长解码和变长解码方案;对于片层以下的语法元素,当entropy_coding_mode_flag为0时使用指数哥伦布和CAVLC解码,为1时使用CABAC解码。

2、CAVLC解析过程

//coeffLevel存放着解析后的系数
residual_block_cavlc(int coeffLevel, int maxNumCoeff ) 
{
    for( i = 0; i < maxNumCoeff; i++ )
        coeffLevel[ i ] = 0;

    int coeff_token = ce(v);    //根据(标准表9-5)计算出非零系数数目(TotalCoeff)、拖尾系数数目(TrailingOnes)

    if( TotalCoeff( coeff_token ) > 0 )     //非零系数的数目 > 0 
    {
        int suffixLength;               //后缀长度
        if( TotalCoeff( coeff_token ) > 10 && TrailingOnes( coeff_token ) < 3 )
            suffixLength = 1;   
        else
            suffixLength = 0;

        for( i = 0; i < TotalCoeff( coeff_token ); i++ )
        {
            if( i < TrailingOnes( coeff_token ) )   //解码拖尾系数的符号
            {
                int trailing_ones_sign_flag = u(1);
                level[ i ] = 12 * trailing_ones_sign_flag;
            }
            else                                                    //解码拖尾系数之外的非零系数的幅值(Levels)
            {
                int level_prefix = ce(v);       //从当前位置不断读取0,直至读到1为止,则0的个数就是level_prefix的值(标准表9-6)
                int levelCode = ( Min( 15,level_prefix ) << suffixLength );

                if( suffixLength > 0 || level_prefix >= 14 ) 
                {
                    int level_suffix = u(v);    //读入v位并解释成无符号整数
                    levelCode += level_suffix;
                }

                if( level_prefix >= 15 && suffixLength == 0 )
                    levelCode += 15;
                if( level_prefix > = 16 )
                    levelCode += ( 1 << ( level_prefix – 3 ) ) – 4096;

                if( i == TrailingOnes( coeff_token ) && TrailingOnes( coeff_token ) < 3 )
                    levelCode += 2;

                //将无符号的levelCode转换成有符号的level
                if( levelCode % 2 == 0 )
                    level[ i ] = ( levelCode + 2 ) >> 1;
                else
                    level[ i ] = ( -1*levelCode – 1 ) >> 1;

                //更新suffixLength,隐含了上下文自适应过程 
                if( suffixLength == 0 )
                    suffixLength = 1;
                if( Abs( level[ i ] ) > ( 3 << ( suffixLength – 1 ) ) && suffixLength < 6 )
                    suffixLength++;
            }

            int zerosLeft;
            if( TotalCoeff( coeff_token ) < maxNumCoeff ) 
            {
                int total_zeros = ce(v);    //系数中0的总个数(标准表9-7,9-8,9-9)
                zerosLeft = total_zeros;
            } 
            else
                zerosLeft = 0;

            for( i = 0; i < TotalCoeff( coeff_token ) – 1; i++ ) 
            {
                if( zerosLeft > 0 ) 
                {
                    int run_before = ce(v); //解码非零系数前零的个数(标准表9-10)
                    run[ i ] = run_before;
                } else
                    run[ i ] = 0;

                zerosLeft = zerosLeft – run[ i ];
            }           
            run[ TotalCoeff( coeff_token ) – 1 ] = zerosLeft;   //run[i]记录了第i个非零系数前0的个数

            int coeffNum = -1;
            for( i = TotalCoeff( coeff_token ) – 1; i >= 0; i--) 
            {
                coeffNum += run[ i ] + 1
                coeffLevel[ coeffNum ] = level[ i ];
            }
        }
    }
}

K阶指数哥伦布编码

在H.264中,使用CABAC需要进行二值化处理,而指数哥伦布编码就是CABAC的一种二值化处理的方法。k阶指数哥伦布编解码具体过程如下:

A、编码过程:假设待编码数字为CodeNum(必须非负整数)

指数哥伦布编码后的形式为[MZeors][1][Info],MZero表示M个0。

  1、将CodeNum以二进制形式表示(若不足k位,前面补0),去掉后面k位(若刚好是k位,去掉k位后得0),将结果(数值)加1,得到二进制数T1;

  2、M为二进制数T1的二进制位数减一;

  3、然后将第一步中舍去的k位接到T1结尾,就得到[1][Info]。

设[Info]的二进制位数为I,编码过程也可以如下描述:

  [1 Info] 是CodeNum+2^k的二进制表示,MZeros中0的个数M = I - k。

  于是就有总的编码长度CodeLen = M + 1 + I =2M+k+1。

B、解码过程:

  1、读入连续0,连续0的个数就是M;

  2、计算CodeLen = 2M+k+1,得到[1 Info]的位数是 I=CodeLen - M =M+K+1;

  3、读入I位二进制码字,转换成10进制,假设为W。由W = CodeNum + 2^k,得CodeNum = W-2^K。

C、示例:

  对于 k =0时:CodeNum=3。
  编码如下:

    二进制表示为11,去掉k=0位后加1得100;

    所以M=2;

    所以编码后结果为[MZeros][1][Info] = [MZeros][1 Info] = 00100

  解码如下:

    读入连续2个0,所以M=2;CodeLen=2M+1+k=5;所以需要再读入3个码流100,[1 Info]就是100,转成十进制结果W为4,所以CodeNum = W-2^K=4-1=3;

  同样对于k=0,CodeNum=6时,编码为:00111;

  同样对于k=3,CodeNum=3时,编码为:1011;

  同样对于k=3,CodeNum=6时,编码为:1110;

  同样对于k=3,CodeNum=10时,编码为:010010;
H.264熵解码详细过程_第1张图片

你可能感兴趣的:(h.264)