实现一个H.264解码器——1_基础知识
[toc]
1_基础知识
前言
学习梳理源自B站视频
感谢大佬的教学
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](https://alfred-img.oss-cn-chengdu.aliyuncs.com/img/CleanShot%202023-01-23%20at%2014.09.41@2x.png)
两个特殊的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](https://alfred-img.oss-cn-chengdu.aliyuncs.com/img/CleanShot%202023-01-23%20at%2014.17.28@2x.png)
即在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中,SPS
和PPS
被当作普通NALU来处理,而在avcC中,SPS
和PPS
信息被当作了特殊的信息进行了处理。在一路采用 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](https://alfred-img.oss-cn-chengdu.aliyuncs.com/img/CleanShot%202023-01-24%20at%2020.11.16@2x.png)
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的变化,发生改变时去重置相关信息完成切换。