H.264历史
NALU 的两种格式
Network Abstract Layer Unit
Annex-B
H.264 标准文档附录B 中记录
码流开头startcode : 0001 或者 001
防竞争字节序
NALU 起始码错误分割,判断好多次001, 造成错误怎么办
就是在 NALU 添加起始码之前,先对码流进行一次遍历,查找码流里面存在的 000、001、002、003 的字节
| 000 | 001 | 002 | 003 |
|---|---|---|---|
| 0030 | 0031 | 0032 | 0033 |
使用防竞争字节序
原始 H.264 码流中, 按照规则假如 003 的字节
avcC
avcC 主要使用 mp4 容器中,在 mp4 中会使用一个box 来存放信息,而表示 box 类型的box byte 是 4 个字节,所以通常会把 3 个字节的类型补充上一个奇怪的字节,变成 4 个字节; box 开始表示长度,之后的字节表示类型;
avc -> avcc
avc -> avc1
AnnexB NALU 分割
AnnexB 的原理是在每一个 NALU 前面写上一个特殊的起始码, 通过这个起始码来当做 NALU 的分隔符,从而分割每个 NALU 。
avcC NALU 分割
而 avcC 则采用了另外一种方式。
那就是在 NALU 前面写上几个字节, 这几个字节组成一个整数 (大端字节序) 这个整数表示整个 NALU 的长度, 在读取的时候,先把整个整数读出来, 拿到这个NALU 的长度,然后按照长度读取整个 NALU ,我们不妨把这几个字节叫做 NALU Body Length
SPS 和 PPS
SPS全称是"序列参数集" (Sequence Parameter Set)
PPS全称是"图像参数集"(Picture Parameter Set)
EBSP 拓展字节序列载荷
解析 SPS 和 PPS
首先要说明的是,H.264 标准中其实并没有这个概念,这个概念是出现在 JM 项目里面。 在 JM 中,将带有 startcode 的 NALU 的去掉 001 的 startcode 的后的数据叫做 EBSP ,在这里,我们不妨沿用这个概念,也用 EBSP 来代指去掉 startcode 的 NALU 数据。
RBSP 原始字节序列载荷
- RBSP 是 H.264 标准中的概念,防止竞争字节
- H.264 在编码的时候,会加还是那个 0x03 的字节来防止和 startcode 产生冲突, 而在读取都 NALU 之后,我们就要把编码时候加上的 防竞争字节去掉,
- NALU 去掉 startcode ,接着又去掉防竞争字节之后的数据,就叫做 RBSP。
SODB 数据比特串
两种特殊的 NALU ,这个两个 NALU 就是 SPS 和 PPS , SPS 和 PPS 存放了解码一路 H.264 码流的必要的参数信息,也就是说,你想要解码一路 H.264 ,就必须先要获取 SPS 和 PPS
-
在 AnnexB 中, SPS PPS 被当做了普通的 NALU 进行处理,
-
而在avcC 中, SPS 和 PPS 信息被当做了特殊的信息进行处理
avcC 头数据
avcC NALULengthSizeMinusOne
两种格式的区别
- avcC 一个 header 和 body,
IOS video2box 使用 avcC 的格式
- AnnexB 都是 NALU ,处理起来简单一些,
Android MediaCodec 支持 AnnexB
分辨率发生变化时, Android 是不需要做特殊的处理, 自动在 NALU 改变分辨率的 SPS 和 PPS 信息;