Android 音视频第二篇 NALU两种格式及 SPS、PPS

108 阅读3分钟

H.264历史

image.png

NALU 的两种格式

Network Abstract Layer Unit

Annex-B

H.264 标准文档附录B 中记录

image.png

码流开头startcode : 0001 或者 001

防竞争字节序

NALU 起始码错误分割,判断好多次001, 造成错误怎么办

就是在 NALU 添加起始码之前,先对码流进行一次遍历,查找码流里面存在的 000、001、002、003 的字节

000001002003
0030003100320033

使用防竞争字节序

原始 H.264 码流中, 按照规则假如 003 的字节

image.png

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 数据。

image.png

RBSP 原始字节序列载荷

  • RBSP 是 H.264 标准中的概念,防止竞争字节
  • H.264 在编码的时候,会加还是那个 0x03 的字节来防止和 startcode 产生冲突, 而在读取都 NALU 之后,我们就要把编码时候加上的 防竞争字节去掉,
  • NALU 去掉 startcode ,接着又去掉防竞争字节之后的数据,就叫做 RBSP。

image.png

SODB 数据比特串

image.png

两种特殊的 NALU ,这个两个 NALU 就是 SPS 和 PPS , SPS 和 PPS 存放了解码一路 H.264 码流的必要的参数信息,也就是说,你想要解码一路 H.264 ,就必须先要获取 SPS 和 PPS

  • 在 AnnexB 中, SPS PPS 被当做了普通的 NALU 进行处理,

  • 而在avcC 中, SPS 和 PPS 信息被当做了特殊的信息进行处理

avcC 头数据

image.png

avcC NALULengthSizeMinusOne

image.png

两种格式的区别

  • avcC 一个 header 和 body,

IOS video2box 使用 avcC 的格式

  • AnnexB 都是 NALU ,处理起来简单一些,

Android MediaCodec 支持 AnnexB

分辨率发生变化时, Android 是不需要做特殊的处理, 自动在 NALU 改变分辨率的 SPS 和 PPS 信息;