在上一节中通过一个小程序,可以提取NAL Unit所包含的的字节数据。H.264码流中的每一个NAL Unit的作用并不是相同的,而是根据不同的类型起不同的作用。下面将对NAL Unit中的数据进行解析。
一、NAL Unit结构
一个NAL Unit都是由一个NAL Header和一个NAL Body组成。对于基本版本的H.264标准(不考虑SVC和MVC扩展),一个NAL Header的长度固定为1,即8bit。这8bit的含义分别为:
- forbidden_zero_bit:每一个NAL Header的第一个bit,规定必须为0;
- nal_ref_idc:第2和3位,主要表示NAL的优先级。当该值为正时,表示当前NAL Unit中包含了SPS、PPS和作为参考帧的Slice等重要数据。
- nal_unit_type:表示NAL Unit的类型,包括VCL层和非VCL层的多种数据类型。常见的nal_unit_type取值有:7表示SPS,8表示PPS,5表示IDR帧,1表示非IDR帧等。
查询H.264文档7.3节,可以看到NAL Unit语法结构:
7.4节介绍了每一个语法结构的内容和作用
二、NAL Unit的有效负载数据及其封装
在NAL Header之后,NAL Unit的其余部分,即NAL Body包含了有效负载数据的封装。从NAL Body到实际的语法元素的码流共3层封装:
第一层:EBSP——扩展字节序列载荷
EBSP全称为Extended Byte String Payload,等同于NAL Body的数据本身。在EBSP中包含了一个特殊的字节0x03,表示防止竞争校验字节:
emulation_prevention_three_byte:设置该值的目的是为了防止NAL Body内部出现于NAL Unit起始码0x 00 00 01或0x 00 00 00 01冲突。
当内部的连续4字节数据出现了下列情况时:
0x 00 00 00
0x 00 00 01
0x 00 00 02
0x 00 00 03
在两个0字节之后会插入值为3的一个字节,形成下列情况:
0x 00 00 03 00
0x 00 00 03 01
0x 00 00 03 02
0x 00 00 03 03
在进行解析时需要将附加的03字节去掉,得到RBSP数据。
第二层:RBSP——原始字节序列载荷
RBSP全称为Raw Byte Sequence Payload,相当于NAL Body去掉emulation_prevention_three_byte之后的数据,是对原始的语法元素码流进一步处理后产生的数据。
作用:字节对齐。
每一个NAL Unit都是紧密排列的,如果出现一个UAL unit字节没对齐,后面的就都对不齐,那就需要时刻进行数据位的对齐操作, 会对接收端和解码端造成极大的负担。
在语法元素编码后,并不一定占满了所有的比特,最后可能会空出几位来。为了补全一位数据,在RBSP在末尾添加了rbsp_trailing_bits()部分,其主要目的是字节对齐。
每个rbsp_trailing_bits()包括一个1bit和若干个0bit,0bit的个数不定,以实现字节的对齐。
例如:一个字节中前三位编码了语法元素1 0 1,后面还剩5位,需要补上1 0 0 0 0,凑成一个字节。
完整的一个字节为 1 0 1 1 0 0 0 0。
第三层:SODB——数据字节流
SODB全称为String Of Data Bits,表示H.264的语法元素编码完成后的实际的原始二进制码流。SODB通常不能保证字节对其。