H264是一种针对视频的压缩编码方式。
一、压缩方法
H264主要基于以下几种方法,将数据进行压缩:
1.帧内预测压缩:解决空间域数据冗余的问题
2.帧间预测压缩:(运动估计与补偿)解决时间域数据冗余的问题
3.整数离散余弦变换(DCT):将空间上的相关性转换为频域上的无关性,然后量化
二、压缩后数据
压缩后,H264文件由I帧、B帧、P帧和GOP图像序列组成。
I帧:关键帧,由帧内压缩得到
B帧:双向预测帧,由帧间压缩得到,压缩时既考虑前面的帧,又考虑后边的帧
P帧:前向预测帧,由帧间压缩得到,压缩时只考虑前面处理的帧
GOP图像序列:由一个关键帧(I 帧)和后续的若干预测帧(P 帧和 B 帧)组成
三、H264组成
H264由网络提取层 + 视讯编码层这两层组成。
1.网络提取层(NAL):网络编码后产生的数据流。通过NAL的第一个字节可以判断帧的类型
2.视讯编码层(VCL):是一个过程的汇总,由数据通过压缩编码得到NAL的过程,称为VCL
四、码流结构
视频数据序列被压缩后形成VCL数据,VCL数据要封装在NAL单元中才可以传输。
SPS:序列参数集,作用于一系列连续的编码图像
PSS:图像参数集,作用于编码视频序列中一个或多个独立图像
上图中的NALU可以分为两种:VCL类型 和 非VCL类型
五、IDR帧
IDR帧,一种特殊的I帧。
一般由于B和P帧都需要参考前后帧进行压缩,因此缓冲区中总保存着前后帧的信息。当解码器接收到当前是IDR帧时,会清空当前缓冲区,找到第一个IDR帧,并重新解码。
每一个GOP的第一个帧就是IDR帧。(当图像差异过大时,会出现IDR帧)
六、封装成RTP包
6.1 H264二进制数据结构
H264由多个NALU组成,每个NALU之间使用00 00 00 01 或00 00 01分隔。
(00 00 00 01表示帧之间的分隔,00 00 01表示切片分隔)
每个NALU的第一个字节意义如下:
(以下数据结构为主机字节顺序:小端存储)
//NALU的第一个字节
uint8_t : 5; //第4-8位,NALU类型
uint8_t : 2; //第2-3位,NALU重要性
uint8_t : 1; //第1位,一般为0。为1表示有语法错误
(下表为网络字节顺序:大端存储)
位数 | 0 | 1 2 | 3 4 5 6 7 |
解释 | 必须为0 当为1时, 表示有语法错误 | 此NALU的重要性 越大越重要 | 此NALU的类型 常用NALU类型对应: SEI: 0x06(0 00 00110) type=6 SPS:0x67(0 11 00111) type=7 PPS:0x68(0 11 01000) type=8 IDR:0x66(0 11 00110) type=5 IDR:0x46(0 10 00110) type=5 IDR:0x16(0 01 00110) type=5 IDR:0x06(0 00 00110) type=5 I帧: 0x61(0 11 00001) type=1 P帧:0x41(0 10 00001) type=1 B帧:0x01(0 00 00001) type=1 |
(大端存储与小端存储只影响内存中的存储方式,解析时不影响,就是按照上述的数据结构方式)
6.2 三种打包形式
H264打包成RTP有三种常用的方式:
1. 单NALU打包
将一整个NSLU放入一个RTP包的有效荷载中
2. 聚合打包
对于较小的NALU,可以将多个NALU放入一个RTP包的有效荷载中
3. 分片打包
对于较大的NALU,可以分成多片,分别放入多个RTP包的有效荷载中。
为了告知此RTP包是上一个NALU的延续,用RTP包的有效荷载的前两个字节来标识:
第一个字节被称为FU Indicator,格式如下所示:
位数 | 0 | 1 2 | 3 4 5 6 7 |
解释 | 与NALU 第一字节相同 | 与NALU 第一字节相同 | 值为十进制28(是H.264规定死的) |
第二个字节被称为FU Header,格式如下所示:
位数 | 0 | 1 | 2 | 3 4 5 6 7 |
解释 | S位 标识是NALU的第一个包 | E位 标识是NALU的最后一个包 | R位 保留位 必须为0 | 与NALU第一字节相同 |