一、 相关术语
NALU:H264编码数据存储或传输的基本单元,一般H264码流最开始的两个NALU是SPS和PPS,第三个NALU是IDR。SPS、PPS、SEI这三种NALU不属于帧的范畴。
SPS(Sequence Parameter Sets):序列参数集,作用于一系列连续的编码图像。
PPS(Picture Parameter Set):图像参数集,作用于编码视频序列中一个或多个独立的图像。
SEI(Supplemental enhancement information):附加增强信息,包含了视频画面定时等信息,一般放在主编码图像数据之前,在某些应用中,它可以被省略掉。
IDR(Instantaneous Decoding Refresh):即时解码刷新。
HRD(Hypothetical Reference Decoder):假想码流调度器。
二、 H.264 NALU语法结构
在H.264/AVC视频编码标准中,整个系统框架被分为了两个层面:视频编码层面(VCL)和网络抽象层面(NAL)。其中,前者负责有效表示视频数据的内容,而后者则负责格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。
因此我们平时的每帧数据就是一个NAL单元(SPS与PPS除外)。在实际的H264数据帧中,往往帧前面带有00 00 00 01 或 00 00 01分隔符,一般来说编码器编出的首帧数据为PPS与SPS,接着为I帧……在H264码流中,都是以"0x00 0x00 0x01"或者"0x00 0x00 0x00 0x01"为开始码的,找到开始码之后,使用开始码之后的第一个字节的低 5 位判断是否为 7(sps)或者 8(pps), 及 data[4] & 0x1f == 7 || data[4] & 0x1f == 8。然后对获取的 nal 去掉开始码之后进行 base64 编码,得到的信息就可以用于 sdp。 sps和pps需要用逗号分隔开来。
上图中,00 00 00 01是一个nalu的起始标志。后面的第一个字节,0x67,是nalu的类型,type &0x1f==0x7表示这个nalu是sps,type &0x1f==0x8表示是pps。
三、 NALU语法结构:
H264基本码流由一些列的NALU组成。原始的NALU单元组成:
[start code] + [NALU header] + [NALU payload];H.264码流在网络中传输时实际是以NALU的形式进行传输的.
每个NALU
由一个字节的Header
和RBSP
组成.
NAL Header 的组成为:
forbidden_zero_bit(1bit) + nal_ref_idc(2bit) + nal_unit_type(5bit)
1、forbidden_zero_bit:
禁止位,初始为0,当网络发现NAL单元有比特错误时可设置该比特为1,以便接收方纠错或丢掉该单元。
2、nal_ref_idc:
nal重要性指示,标志该NAL单元的重要性,值越大,越重要,解码器在解码处理不过来的时候,可以丢掉重要性为0的NALU。
3、nal_unit_type:NALU类型取值如下表所示:
不过上面这张图,我实在没有找到出处啊。但是我在 x264 里看到了这个。
其中需要关注的是 SEI、SPS、PPS。我在 LIVE555 里又看到这个。
这不就是上面我们讲到的,nalu的类型 type &0x1f==0x7表示这个nalu是sps,type &0x1f==0x8表示是pps。
四、 RBSP
这里提一下 SODB 和 RBSP 关系:
SODB(String Of Data Bits):最原始的编码数据RBSP, 长度不一定是8的倍数,此时需要对齐.
**RBSP: **在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit“1”)若干比特“0”,以便字节对齐。
我们知道码流是由一个个的NAL Unit组成的,NALU是由NALU头和RBSP数据组成,而RBSP可能是SPS,PPS,Slice或SEI,目前我们这里SEI不会出现,而且SPS位于第一个NALU,PPS位于第二个NALU,其他就是Slice(严谨点区分的话可以把IDR等等再分出来)了。
我们先看第一个NALU(SPS)的 RBSP (10个字节)
67 4D 40 33 92 54 0C 04 B4 20
转换成二进制:
0110 0111
0100 1101
0100 0000
0011 0011
1001 0010
0101 0100
0000 1100
0000 0100
1011 0100
0010 0000
先看NALU头,解析结果如下:
forbidden_zero_bit = 0 // 0 u(1)
nal_ref_idc = 3 // 11 u(2)
nal_unit_type = 7 // 00111 u(5)
这就对了,看看 NAL_SPS = 7;