1.H264码流格式——字节流格式
字节流格式是大多数编码器,默认的输出格式。它的基本数据单位为NAL单元,也即NALU。为了从字节流中提取出NALU,协议规定,在每个NALU的前面加上起始码:0x000001或0x00000001(0x代表十六进制) 。
字节流格式:
H264比特流 = Start_Code + NALU + Start_Code + NALU + …
只要我们从码流中,找到一个一个的起始码,那么位于起始码之间的数据,即为NALU。所以拿到码流,我们需要先从头开始,找到起始码0x000001或0x00000001,找到Start_Code_Prefix之后,从它之后的下一个字节开始,就是NALU的部分。
=========================
2.H264码流NALU头结构
H264码流在网络传输的是NALU,NALU的结构是:NAL头+RBSP,实际传输中的数据流
NALU Header由三个句法元素组成,分别为:
forbidden_zero_bit、nal_ref_idc和nal_unit_type,它们总共占据一个字节,也就是说,NALU Header,在整个NALU中,占据一个字节。forbidden_zero_bit的值对应1个bit,nal_ref_idc的值对应2个bit,nal_unit_type的值对应5个bit,加起来刚好一个字节。
-----------------------------------------------
forbidden_bit(1bit) + nal_reference_bit(2bit) + nal_unit_type(5bit)
1.forbidden_bit: 禁止位,初始为0,当网络发现NAL单元有比特错误时可设置该比特为1,以便接收方纠错或丢掉该单元。
2.nal_reference_bit: nal重要性指示,标志该NAL单元的重要性,值越大,越重要,解码器在解码处理不过来的时候,可以丢掉重要性为0的NALU。
取值0~3,代表当前这个NALU的重要性,取值越大,代表当前NALU越重要,就需要优先被保护。
尤其是当前NALU为图像参数集、序列参数集或IDR图像时,或者为参考图像条带(片/Slice),
或者为参考图像的条带数据分割时,nal_ref_idc值肯定不为0。
而当NALU 类型,nal_unit_type为6、9、10、11、或12时,nal_ref_idc都为0。
3.nal_unit_type
它表示NALU Header后面的RBSP的数据结构的类型。下图为nal_unit_type所有可能的取值
nal_unit_type | NAL 单元和 RBSP 语法结构的内容 |
0 | 未指定 |
1 | 一个非IDR图像的编码条带 slice_layer_without_partitioning_rbsp( ) |
2 | 编码条带数据分割块A slice_data_partition_a_layer_rbsp( ) |
3 | 编码条带数据分割块B slice_data_partition_b_layer_rbsp( ) |
4 | 编码条带数据分割块C slice_data_partition_c_layer_rbsp( ) |
5 | IDR图像的编码条带 slice_layer_without_partitioning_rbsp( ) |
6 | 辅助增强信息 (SEI) sei_rbsp( ) |
7 | 序列参数集 seq_parameter_set_rbsp( ) |
8 | 图像参数集 pic_parameter_set_rbsp( ) |
9 | 访问单元分隔符 access_unit_delimiter_rbsp( ) |
10 | 序列结尾 end_of_seq_rbsp( ) |
11 | 流结尾 end_of_stream_rbsp( ) |
12 | 填充数据 filler_data_rbsp( ) |
13 | 序列参数集扩展 seq_parameter_set_extension_rbsp( ) |
14...18 | 保留 |
19 | 未分割的辅助编码图像的编码条带 slice_layer_without_partitioning_rbsp( ) |
20...23 | 保留 |
24..31 | 未指定 |
可以看到,nal_unit_type的值为1-5时,表示RBSP里面包含的数据为条带(片/Slice)数据,所以值为1-5的NALU统称为VCL(视像编码层)单元,其他的NALU则称为非VCL NAL单元。
当nal_unit_type为7时,代表当前NALU为序列参数集,为8时为图像参数集。这也是我们打开.h264文件后,遇到的前两个NALU,它们位于码流的最前面。
而且当nal_unit_type为14-31时,我们可以不用理睬,目前几乎用不到。
===================================
3.H264码流NALU主体结构
NALU的主体涉及到三个重要的名词,分别为EBSP、RBSP和SODB。其中EBSP完全等价于NALU主体,而且它们三个的结构关系为:
EBSP包含RBSP,RBSP包含SODB,其中SODB就是最原始的编码数据。
其中的EBSP为扩展字节序列载荷(Encapsulated Byte Sequence Payload),而RBSP为原始字节序列载荷(Raw Byte Sequence Payload)。
EBSP相较于RBSP,多了防止竞争的一个字节:0x03。
我们知道,NALU的起始码为0x000001或0x00000001,同时H264规定,当检测到0x000000时,也可以表示当前NALU的结束。那这样就会产生一个问题,就是如果在NALU的内部,出现了0x000001或0x000000时该怎么办?
所以H264就提出了“防止竞争”这样一种机制,当编码器编码完一个NAL时,应该检测NALU内部,是否出现如下左侧的四个序列。当检测到它们存在时,编码器就在最后一个字节前,插入一个新的字节:0x03。