关于h264视频的sps和pps解析和哥伦布编码

时间:2022-12-26 11:26:41

        今天闲来无聊,根据2011年5月的《T-REC-H.264-201106-S!!PDF-E》文档,写了个h264视频的sps和pps解析。

        下载地址在http://download.csdn.net/detail/gyley2/5008185。有需要的朋友可以去download。希望能帮助需要的朋友。

         顺带说一下哥伦布编码:

       

用来表示非负整数的k阶指数哥伦布码可用如下步骤生成:

  1. 将数字以二进制形式写出,去掉最低的k个比特位,之后加1
  2. 计算留下的比特数,将此数减一,即是需要增加的前导零个数
  3. 将第一步中去掉的最低k个比特位补回比特串尾部

k=0阶指数哥伦布码如下所示:

 0 => 1 => 1  1 => 10 => 010  2 => 11 => 011  3 => 100 => 00100  4 => 101 => 00101  5 => 110 => 00110  6 => 111 => 00111  7 => 1000 => 0001000  8 => 1001 => 0001001
解码:

      解析k阶指数哥伦布码时,首先从比特流的当前位置开始寻找第一个非零比特,并将找到的零比特个数记为leadingZeroBits,然后根据leadingZeroBits计算CodeNum。用伪代码描述如下:

    

关于h264视频的sps和pps解析和哥伦布编码

下表给出了0阶、1阶、2阶和3阶指数哥伦布码的结构。指数哥伦布码的比特串分为“前缀”和“后缀”两部分。前缀由leadingZeroBits 个连续的0和一个1构成,后缀由leadingZeroBits+k个比特构成,即表中的xi串,i的范围为0~(leadingZeroBits+k- 1),每个xi的值为0或1。

关于h264视频的sps和pps解析和哥伦布编码

(1)ue(v):无符号直接映射,code_num = v 。应用在宏块类型、参考帧索引等参数上。(2)se(v):符号映射,应用于运动矢量差值,量化参数差值等,映射规则如下:code_num=2lvl    (v<0)code_num=2lvl-1 (v>0)(3)me(v):标记映射,参数 根据标准中定义的一张表格映射到code_num。这种映射方式用于coded_block_pattern参数。每一种映射方式(ue,se,me)都被尽量设计成对出现频率高的值使用较短的码字而对出现频率低的值使用较长的码字。例如,宏块模式Pred L0 16x16被映射到code_num 0,因为这种预测方式出现频率高,而Pred_8x8被映射为code num3,因其出现频率较低。

  H.264的一个重要特色就是采用UVLC(Universal Variable Length coding, 统一可变长编码)编码,提高了编码效率。

          UVLC编码中有一种编码方式就是指数哥伦布编码。程序实现该编码时需要计算编码长度len及其value,下面分别对无符号和有符号两种指数哥伦布编码进行分析。

          设编码值为code_val。

    static const int i_size0_255[256] =
    {
        1,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
        8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
        8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
        8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
        8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
    };

    void bs_write( bs_t *s, int bit_len, int value); 

1. ue(v)

        1) value = code_val+1        2)len = 2*i_size0_255[value]+1编程实现如下:void ue_v( bs_t *s, unsigned int code_val )
{
    int i_size = 0;
    if( val == 0 )
    {
        bs_write( s, 1, 1); 
    }
    else
    {
        unsigned int tmp = ++code_val;
        if( tmp >= 0x00010000 )
        {
            i_size += 16;
            tmp >>= 16;
        }
        if( tmp >= 0x100 )
        {
            i_size += 8;
            tmp >>= 8;
        }
        i_size += i_size0_255[tmp];
        bs_write( s, 2 * i_size - 1, code_val);
    }
}

2. se(v)

        1) 若code_val>0:    value = 2*code_val-1            若code_val>0:     value = -2*val       2)len = 2*i_size0_255[value]+1编程实现如下:static void se_v( bs_t *s, int code_val )
{
    ue_v( s, code_val <= 0 ? -code_val  * 2 : code_val * 2 - 1);
}