[toc]

1_基础知识

前言

学习梳理源自B站视频

https://www.bilibili.com/video/BV1b3411X7eE/?spm_id_from=333.999.0.0&vd_source=c385e6592167e9e48e3dd8f1b317ef7e

感谢大佬的教学

H.264 / AVC

H.264和AVC本质上是同一套视频编码标准,只是不同组织对其命名不同

Nalu

Network Abstraction Layer Unit 网络抽象层单元

Nalu是组成H.264码流的最基本单元,一个H.264码流由无数Nalu组成。

H.264码流中没有音频,没有时间戳,只有图片本身的信息,把H.264码流和音频、时间戳等信息结合起来的叫封装器如MP4

CleanShot 2023-01-23 at 14.09.41@2x

两个特殊的NALU

H.264中有两个比较特殊的NALU,分别是SPS和PPS,其存放了解码一路H.264所必须的参数信息

1. SPS

2. PPS

Nalu的两种封装格式

H.264码流的Nalu单元常见有两种封装格式

1. Annex-B

由于这种写法位于ITU-T的H.264标准文档的附录B中,所以得名Annex-B

CleanShot 2023-01-23 at 14.17.28@2x

即在Nalu头部固定0001或001来标识一个Nalu单元,(每个数字一个字节,即一共32位或24位)

为了防止竞争(字节流中本来就存在001),在为NALU添加起始码之前,会对码流进行一次遍历,查找其内本身就存在的000,001,002,003的字节,对其进行如下修改:

  • 0 0 0 => 0 0 3 0
  • 0 0 1 => 0 0 3 1
  • 0 0 2 => 0 0 3 2
  • 0 0 3 => 0 0 3 3

2. avcC(avc1)

avcC主要使用于MP4容器中,在mp4中,会使用box来存放信息,而表示box类型的box type是4个字节,所以通常会把3个字节的类型补充上一个奇怪的字节变成4个字节,所以avc格式补完4个字节就成了avcC或avc1之类的奇怪字符

Annex-B是通过在每个NALU前面添加一个特殊的起始码来作为NALU的分隔符,而avcC则采用另一种形式,就是在每个NALU前面写上几个字节,这几个字节组成一个整数(大端字节序),这个整数表示了整个NALU的长度,在读取时,先把这个长度读出来,然后按照长度读取整个NALU即可。

在Annex-B中,SPSPPS被当作普通NALU来处理,而在avcC中,SPSPPS信息被当作了特殊的信息进行了处理。在一路采用 avcC 打包的 H.264 流之中,我们首先看到的将是一段被称之为 extradata 的数据,这段数据定义了这个 H.264 流的基本属性数据,当然,也包含了 SPS 和 PPS 数据。

extradata 数据格式如下:

长度 bits 名称 备注
8 version always 0x01
8 avc profile sps[0][1] (第一个sps的第一个字节)
8 avc compatibility sps[0][2]
8 avc level sps[0][3]
6 reserved 保留字段
2 NALULengthSizeMinusOne NALU Body Length数据的长度减一
3 reserved 保留字段
5 number of SPS NALUs 有几个SPS,一般情况这里是1
– repeated once per SPS –
16 SPS size SPS的长度
变长 SPS NALU data SPS NALU的数据
– repeated end –
8 number of PPS NALUs 有几个PPS,一般情况这里是1
– repeated once per PPS –
16 PPS size PPS的长度
变长 PPS NALU data PPS NALU的数据
– repeated end –
NALULengthSizeMinusOne

NALULengthSizeMinusOne只有两个bit,表示0-3,所以NALU Body Length的长度就是1-4个字节。这个NALU Body Length的长度表明了NALU中前几个字节表示NALU Body Length。如NALULengthSizeMinusOne=3,则NALU Body Length的长度为4个字节,所有后面每个NALU都需要先读区前4个字节,解析出NALU长度。

CleanShot 2023-01-24 at 20.11.16@2x

3. 两种封装格式的对比

avcC的好处就是比较容易定位,不用像Annex-B一样要遍历所有数据然后做查找和替换,处理avcC的时候性能损耗会更低。

avcC数据由于分为了两部分,有一个extradata数据,无形中增加了解析的成本。

平台硬解码的时候,比如IOS video toolbox只接受avcC;Android平台的media又支持Annex-B,不同平台最好经过转换区分平台便于硬解码

直播流的时候可能会有分辨率转换,对于Android无影响,使用Annex-B,不区分NALU,直接塞进去就行了,但是对于IOS的avcC,由于SPS和PPS分开了,所有需要监控SPS和PPS的变化,发生改变时去重置相关信息完成切换。