h264-sps解析&Exp-golomb编解码

理论

熵编码

熵编码是一种无损编码,按照熵原理不丢失任何信息的编码。

常见的熵编码有:香浓(Shannon)编码、哈夫曼(Huffman)编码、算术(arithmetic)编码、指数哥伦布(exponential Golomb)编码、基于上下文的自适应变长编码(CAVLC:Context-based Adaptive Variable Length Coding )、基于上下文的自适应二进制算术编码(CABAC:Context-based Adaptive Binary Arithmetic Coding )。

在H264中,主要使用三种编码方式,exp-golomb、CAVLC、CABAC。

因为在项目中,需要解析sps,而sps RBSP语法元素主要用到了0阶exp-golomb,下面介绍0阶exp-golomb。

指数哥伦布编码

指数哥伦布码(Exponential-Golomb coding)是一种无损数据压缩方法。

Exp-golomb编码规则(文字描述版本)

说明:

codenum 表示 待编码的数 x;

codeword 表示 编码后的数;codeword的构成=[prefix][suffix]

prefix 也叫做 leadingzerobits; 二进制数

suffix 也是二进制数

编码步骤

  1. codenum+1 并将其值写成二进制形式,用suffix表示;
  2. 数suffix的位数,用M表示;
  3. prefix 由M-1个0组成;

以codenum=5为例,

  1. codenum+1=6,即suffix = 0b110;
  2. prefix = 0b00;
  3. codeword = 0b00110;

我们知道,在计算机中,以字节作为最小存储单位(字节对齐),而字节由8个bit组成。10进制数5在计算机中的存储为0b00000101,可以看出实际的有效位数只有3位,另外的5位没有用,但还是占用了5个bit的存储空间。所以为了更高效地利用物理存储空间,工程师们就想,有没有什么方式既能正确的表示数据又能更省存储空间呢?那就需要设计某种“规则”,使用这种“规则”重新表示数据。而这种“规则”用专业术语表达就叫做编码。
前面提到的指数哥伦布编码就是万千编码方式中的一种,通过exp-golomb coding,将0b00000101压缩成了0b00110,从8位压缩到了5位,节省了3位。

从上面讲解Exp-golomb编码规则中,并没有看到和指数相关的东西。那为什么这玩意叫指数哥伦布编码呢?

其实,上面讲解的编码规则是一种特殊情况(指数k=0)。k阶指数哥伦布编码的一般规则是

  1. x+ 2 k 2^k 2k-1 使用 0阶指数哥伦布编码;
  2. 数suffix的位数,用M表示;
  3. prefix 由M-1个0组成;

以codenum=5, k=1为例,

  1. 5 + 2 1 − 1 = 6 5+2^1-1=6 5+211=6,6的0阶指数哥伦布编码为00111;
  2. 删除 1 个前导 0;
  3. codeword 为 0b0111;
    k阶指数哥伦布表

Elias gamma coding

Elias γ code or Elias gamma code is a universal code encoding positive integers developed by Peter Elias.[1]:197, 199 It is used most commonly when coding integers whose upper-bound cannot be determined beforehand.

elias gamma coding 使用 2 ⌊ l o g 2 x ⌋ + 1 2\lfloor log_2^{x}\rfloor + 1 2log2x+1个bit来编码表示数值。例如,数字5 使用 5个bit来表示;数字10使用7个bit来表示。

在这里插入图片描述

编码规则

​ x 为 待编码数

  1. 找N,N为x的2的指数的最大幂次; N = f l o o r ( l o g 2 x ) N=floor(log_2^{x}) N=floor(log2x),即$2^N\le x < 2^{N+1} $;
  2. N个前导0 bits;
  3. 接着将x表示成2进制;
  4. 将#2和#3的二进制数组合 即为编码后的数;

以x=5为例:

  1. N = 2; x = 2 2 + 1 x = 2^2+1 x=22+1
  2. 2个前导0,00;
  3. x = 0b101
  4. codeword = 0b00101

实践

sps的数据语法格式如下
sps1

sps2

从sps的语法中可以看到,主要使用了4种描述子,u(1),u(n),ue(v),se(v)。

接下来,分别介绍这四种描述子及其代码实现。

在h264标准中,有一个读取比特流的语法函数,read_bits(n)

read_bits( n ) reads the next n bits from the bitstream and advances the bitstream pointer by n bit positions. When n is
equal to 0, read_bits( n ) is specified to return a value equal to 0 and to not advance the bitstream pointer

read_bits的作用就是 从当前比特流位置开始,读取n个比特,同时比特流指针向前移动n位。如果n为0,read_bits返回0,且比特流指针不移动。

Syntax elements coded as ue(v), me(v), or se(v) are Exp-Golomb-coded. Syntax elements coded as te(v) are truncated ExpGolomb-coded. The parsing process for these syntax elements begins with reading the bits starting at the current location in the bitstream up to and including the first non-zero bit, and counting the number of leading bits that are equal to 0.

This process is specified as follows:
leadingZeroBits = -1
for( b = 0; !b; leadingZeroBits++ )
b = read_bits( 1 )

在h264的语法元素中,ue(v),me(v),se(v)都是使用指数哥伦布编码;te(v)使用截断指数哥伦布编码。解码过程为 从当前比特流位置开始读,直到遇到第一个非0bit位,即1位,然后计算前导0的个数N(注意:比特流的指针移动到了第一个非0bit的下一位);接着再向后读取N个bit并得到这个N个bit对应的数值;再按照公式 c o d e N u m = 2 l e a d i n g Z e r o B i t s − 1 + r e a d _ b i t s ( l e a d i n g Z e r o B i t s ) codeNum=2^{leadingZeroBits}-1+read\_bits(leadingZeroBits) codeNum=2leadingZeroBits1+read_bits(leadingZeroBits)解出原数值。

例如,5的exp-golomb coded number是 00110,第一个比特值1的前面有2个前导0,即leadingZeroBits=2;接着,第一个比特值1后的两个比特值为10,也就是10进制的2;所以 c o d e N u m = 2 2 − 1 + 2 = 5 codeNum = 2^2-1+2=5 codeNum=221+2=5 ,这样就解出原数值5了。

从table9-1可以看出,"prefix"即是leadingZeroBits对应的前导0个数,"suffix"即是codeNum对应的比特值,由 x i x_i xi表示,i的范围是[0, leadingZeroBits-1], x i x_i xi可以是0也可以是1。

bit_string_prefix_suffix

u(1)

u(1)就相当于 read_bits(1)。它的值是0或1。

bcxt_read_u1

u(n)

unsigned integer using n bits. When n is “v” in the syntax table, the number of bits varies in a manner
dependent on the value of other syntax elements. The parsing process for this descriptor is specified by the return
value of the function read_bits( n ) interpreted as a binary representation of an unsigned integer with most
significant bit written first.

u(n) 就相当于 read_bits(n)。u(n)的返回值是n个bit对应的正整数。注意:most significant bit written first

bcxt_read_u

ue(v)

unsigned integer Exp-Golomb-coded syntax element with the left bit first. The parsing process for this
descriptor is specified in clause 9.1

ue(v)是使用0阶指数哥伦布编码的值,所以解析sps相应的语法元素时,要使用0阶指数哥伦布对应的解码规则进行解码。ue(v)的实现原理即是前面提到的 c o d e N u m = 2 l e a d i n g Z e r o B i t s − 1 + r e a d _ b i t s ( l e a d i n g Z e r o B i t s ) codeNum=2^{leadingZeroBits}-1+read\_bits(leadingZeroBits) codeNum=2leadingZeroBits1+read_bits(leadingZeroBits)。ue(v)的值即是codeNum。

在这里插入图片描述
在这里插入图片描述

se(v)

se(v)的值 就是 在ue(v)的值的基础上,按照 ( − 1 ) k + 1 C e i l ( k / 2 ) , k = u e ( v ) (-1)^{k+1}Ceil(k/2),k=ue(v) (1)k+1Ceil(k/2),k=ue(v)计算得到。

更直观点的描述就是,se(v)对应的语法元素的值 ,从1开始,每相邻的两个数为一对,低序号的值为正数,高序号的值为负数,依次升序排列,如下表所示。

se

bcxt_read_se

reference:

https://en.wikipedia.org/wiki/Exponential-Golomb_coding

ITU-T H.264 (V12) 2017-04-13

https://baike.baidu.com/item/%E7%86%B5%E7%BC%96%E7%A0%81/3303605

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sif_666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值