1. 引言
在根据起始码找到NALU的位置和获取到NALU的种类之后,接下来我们需要进行的就是对每个NALU的内容进行解析。根据h264的白皮书协议,按照规定的的方法从码流中把协议里的每个参数解析出来,解出来之后再按照参数的含义的作用进行图像的复原,得到YUV图。
所以,这一节的关键点就在于,怎么进行白皮书中参数的解析。
(以T-REC-H.264-201003-I!!PDF-E.pdf为例,最新的协议请到ITU官网下载)
2. 描述子
上一节中我们得到了NALU,并知道NALU有多种类型,那我们打开白皮书,先看一下其中很重要的SPS,sequence parameter set,来看一看这些NALU的内部究竟是些什么。
翻到 43面 7.3.2.1.1 Sequence parameter set data syntax。

可以看到,表格一共分三列:
- 第一列就是我们要解析的参数,也就是我们需要的结果,profile类别,level类别等等
- 第二列 C是 category种类,指明了一些参数的包含关系。
- 第三列 就是最重要的一列:描述子,这一列说明了,我们究竟要用什么办法去解析这个bit流,怎么样的去读取这些0,1的数据,来得到我们需要的参数。
可能看到这里大家会有些疑惑,就这么个简单的表达式,就足够描述所有h264中的编码方式了吗?
别急,让我们先把这些第三列的描述子浏览一遍,看一下有没有什么规律。
简单的过了一遍从42面开始的一些常用NAL的 Syntax in tabular form,我们应该很快就能发现,其实第三列的Descriptor描述子,有很多是一样的,比如u(2), u(5), 我们都可以把他们归为u(n)一类。
总体看下来,一共只有固定几类: f(n), u(n), b(n), ue(v), se(v)……
这些描述子代表了什么?
怎么去解析?
别急,白皮书里同样给了所用到的描述子的所有介绍:

可以看出,一共分了 10类,对应着不同的解码方式。
- ae(v):基于上下文自适应的二进制算术熵编码
- b(8):读进连续的 8 个比特
- ce(v):基于上下文自适应的可变长熵编码
- f(n):读进连续的 n 个比特
- i(n):读进连续的若干比特,并把它们解释为有符号整数
- me(v):映射指数 Golomb 熵编码
- se(v):有符号指数 Golomb 熵编码
- te(v):截断指数 Golomb 熵编码
- u(n):读进连续的若干比特,并将它们解释为无符号整数
- ue(v):无符号指数 Golomb 熵编码
其实在我看来,按照大的解码方式来分,我们可以把所有的描述子分为4大类:
| 方式 | 描述子 |
|---|---|
| 二进制读取 | b(8),f(n),i(n),u(n) |
| 熵编码- 指数哥伦布 | me(v),se(v),te(v),ue(v) |
| 熵编码- CAVLC | ce(v) |
| 熵编码- CABAC | ae(v) |
2.1 二进制读取
这一类是最简单的解析,从左往右读取n位二进制数,把它解析成一个有符号数或者无符号数即可。
其中,n可能是一个固定值,也可能是根据前面解析过的参数计算出来的值。
比如 下图中的 frame_num,描述子是u(v), 即连续读取v个二进制bit,解析成为无符号数。
具体v的值,就是根据之前解析SPS的时候,得到的log2_max_frame_num_minu4 的 值来确定的。

2.2 指数哥伦布
这一类包含: me(v),se(v),te(v),ue(v)。
读取的长度是不固定的,但是解析方法是一样的,解出来的值也是确定的。
其中,ue(v)和 se(v)用的较多,me(v)和te(v)使用较少。
具体的解析会在后面文章介绍。
2.3 CAVLC
CAVLC是baseline的内容,是一定会有的,我们后面会重点学习一下熵编码 CAVLC的编解码方法
2.3 CABAC
CABAC是扩展方法,效率更高但是编解码流程更复杂。这个之后也会学习。

1073

被折叠的 条评论
为什么被折叠?



