RTP中H264封装NALU格式详细解析

名词解释:NAL
NAL的英文全称为Network Abstract Layer,即网络抽象层,在H264/AVC视频编解码标准中,整个系统框架分为两个层面,视频编解码层面(VCL)和网络抽象层面(NAL)。VCL负责有效表示视频数据内容,NAL负责格式化数据并加上相应的头信息,以保证数据适合各种信道和存储介质上的传输。NAL单元NALU是NAL的基本语法结构,它包含一个字节的头信息和一系列来自VCL的原始字节载序列载荷(RBSP)的字节流。

一、H.264 NAL单元(NALU)的组成:

NALU有多种类型,分为VCL和no-VCL。
VCL(Video Coding Layer):是图像编码数据
NO-VCL:非视频信息,配置信息。 (其中sps、pps等NALU单元都是非VCL NAL单元)
关于VCL和非VCL的分类: 其中NALU单元nal_unit_type 值等于 1 到 5(包括 1 和 5)的 NAL 单元是VCL NAL单元,其他的 NAL 单元都称作非 VCL NAL 单元。

NAL单元组成由起始码、NAL头、NAL Payload三部分组成
RTP中H264封装NALU格式详细解析_第1张图片

下面详解解析NAL单元三个组成部分
1、起始码:分为3或者4字节的0x000001和0x00000001两种的开始码
2、NAL头: 长度为1字节
RTP中H264封装NALU格式详细解析_第2张图片
RTP中H264封装NALU格式详细解析_第3张图片
3、NAL Payload:具体的NAL内容payload

一个简单的例子:
NALU头为0x67,转换为二进制0110 0111
禁止位为0
NAL重要性为11,即3,表示最重要
NALU类型为[00111],即7,类型为7表示该NALU是SPS

二、RTP报文的封包格式

一共有三种模式:
1、单一NALU模式
2、组合封包模式
3、分片封包模式

1、单一NALU模式

RTP中H264封装NALU格式详细解析_第4张图片
如下面是一个SPS帧的例子:
下面是SPS帧的格式如下:SPS的NALU头中的Type值为7,表示SPS(Sequence parameter set),SPS还包含一些图像编码的一些重要配置信息,比如profile_id,level_id,图像的宽高信息等,具体如下图
RTP中H264封装NALU格式详细解析_第5张图片
RTP中H264封装NALU格式详细解析_第6张图片
上图中图像的宽高为:1920*1088

2、组合封包模式

RTP中H264封装NALU格式详细解析_第7张图片
开头1个字节表示NAL单元类型,接着1个或多个聚合单元,后面是可选的RTP填充,组合包模式有以下四种类型:
RTP中H264封装NALU格式详细解析_第8张图片
组合包模式是当H264 NALU单元的长度较小时,将几个NALU单元封装在一个RTP数据包中,以STAP-A为例进行详细介绍。

   单时刻聚合包(STAP-A)应该用于当聚合在一起的NAL单元共享相同的NALU时间。STAP-A荷载不包括DON(Decoding Order Number),并且至少包含一个单时刻聚合单元,如下图所示

RTP中H264封装NALU格式详细解析_第9张图片
single-time aggregation unit的格式如下图所示:
RTP中H264封装NALU格式详细解析_第10张图片
一个RTP包含一个STAP-A组合包,一个STAP-A包含两个单时间聚合单元的示例如下图所示:
RTP中H264封装NALU格式详细解析_第11张图片
具体数据示例:
【00 00 00 01 67 42 C0 1F 8C 8D 40 48 14 B2 F0 0F 08 84 6A】
【00 00 00 01 68 CE 3C 80】
将以上SPS、PPS两个H264 NAL单元封装成STAP-A形式如下所示:
【RTP Header】【78 00 0F 67 42 C0 1F 8C 8D 40 48 14 B2 F0 0F 08 84 6A 00 04 68 CE 3C 80 】
78:第一位表示F为,值为0;第二三位表示NRI重要程度;后五位Type,值为24,表示STAP-A类型。
00 0F:NALU 1 size
67:NALU 1 HDR
42 C0 1F 8C 8D 40 48 14 B2 F0 0F 08 84 6A:NALU 1 data
00 04:NALU 2 size
68:NALU 2 HDR
CE 3C 80:NALU 2 data

3.分片封包模式

当H264 NALU 的长度超过 MTU 时, 就必须对 NALU 单元进行分片封包. 也称为 Fragmentation Units ,主要包含FU-A和FU-B两种形式,FU-A分包格式如下图所示:
RTP中H264封装NALU格式详细解析_第12张图片
FU indicator的格式如下图所示:
RTP中H264封装NALU格式详细解析_第13张图片
F:禁止位,与NALU Header的F位一致
NRI:重要程度,与NALU Header的NRI一致
Type:分包类型,28表示FU-A类型,29表示FU-B类型

FU header的格式如下图所示:
RTP中H264封装NALU格式详细解析_第14张图片
S:占1bit,值为1,表示NAL分包的开始,其余情况值为0。
E:占1bit,值为1,表示NAL分包的结束,其余情况为0。
R:占1bit,值为0,表示保留位。
Type:占5bit,值为H264 NALU Header中的Type。

        具体数据示例:
【00 00 00 01 65 b8 00 01 4d 00 00 ff bc 5d…】
将H264 I帧进行分包,具体的分包多少由I帧的数据长度和设置分包大小决定,示例如下所示:
【RTP Header】【7c 85】【H264 Payload Data】
【RTP Header】【7c 05】【H264 Payload Data】
【RTP Header】【7c 45】【H264 Payload Data】
7c 85:表示分包开始包。
7c 05:表示分包中间包。
7c 45:表示分包结束包。

 通过wiereshark抓包分析协议格式:

RTP中H264封装NALU格式详细解析_第15张图片
RTP中H264封装NALU格式详细解析_第16张图片
RTP中H264封装NALU格式详细解析_第17张图片

三、H264封装示例
读取一个H264文件,封装为RTP协议格式进行传输,具体实现如下所示:
RTP中H264封装NALU格式详细解析_第18张图片

1、SPS、PPS采用单包模式发送。
2、I帧、P帧采用FU-A分包模式发送。
3、注意RTP Header中Mark标记位的设置和相对时间戳的设置。 MARK标记的是首包

知识点:
AUD:
一般文档没有对AUD进行描叙,其实这是一个帧开始的标志,字节顺序为:00 00 00 01 09 f1,从结构上看,有start code, 所以确实是一个NALU,类型09在H264定义里就是AUD(分割器)。大部分播放器可以在没有AUD的情况下正常播放。紧随AUD,一般是SPS/PPS/SEI/IDR的组合或者简单就是一个SLICE,也就是一个帧的开始。像Flash这样的播放器,每次需要一个完整的帧数据,那么把2个AUD之间的数据按照格式打包给播放器就可以了。

H.264编码时,在每个NAL前添加起始码 0x000001,解码器在码流中检测到起始码,当前NAL结束。为了防止NAL内部出现0x000001的数据,h.264又提出’防止竞争 emulation prevention"机制,在编码完一个NAL时,如果检测出有连续两个0x00字节,就在后面插入一个0x03。当解码器在NAL内部检测到0x000003的数据,就把0x03抛弃,恢复原始数据。
0x000000 -----------> 0x00000300
0x000001 -----------> 0x00000301
0x000002 -----------> 0x00000302
0x000003 -----------> 0x00000303

总的来说,H264的码流的打包方式有两种,一种为annex-b byte stream format 的格式,这个是绝大部分编码器的默认输出格式,就是每个帧的开头的3~4个字节是H264的start_code,0x00000001或者0x000001;另一种是原始的NAL打包格式,就是开始的若干字节(1,2,4字节)是NAL的长度,而不是start_code,此时必须借助某个全局的数据来获得编 码器的profile,level,PPS,SPS等信息才可以解码。

H.264的NALU单元组织格式

这里需要了解下H264打包方式,所谓打包方式就是如何组织一连串的NALU单元为完整的H264码流,目前有两种主流格式:
Annex-B 和 AVCC

一、Annex-B: :
通过起始码startCode(0x00000001或0x000001)来分割NALU,打包方式如下:
[start Code]–[NALU]–[start code]–[NALU]…

二、AVCC:
([extradata]) | ([length] NALU) | ([length] NALU) | …
这种模式也叫AVC1格式,和上述Annex-b相比没有起始码。 其中AVCC这种格式下NALU一般没有sps、pps等参数信息,这些信息属于额外数据extradata存放在其他地方。 extradata后面就是nalu数据,在每帧前面几个字节(通常是4字节)是帧长度。

1字节:version (通常0x01)2字节:avc profile (值同第1个sps的第2字节)3字节:avc compatibility (值同第1个sps的第3字节)4字节:avc level (值同第1个sps的第3字节)5字节前6位:保留全15字节后2位:NALU Length 字段大小减1,通常这个值为3,即NAL码流中使用3+1=4字节表示NALU的长度
第6字节前3位:保留,全16字节后5位:SPS NALU的个数,通常为17字节开始后接1个或者多个SPS数据
	SPS结构 [16位 SPS长度][SPS NALU data]

SPS数据后
第1字节:PPS的个数,通常为12字节开始接1个或多个PPS数据
	PPS结构 [16位 PPS长度][SPS NALU data]

上述内容参考 https://titanwolf.org/Network/Articles/Article?AID=7efa4423-1e7d-46e0-ba19-6f5c6eec84a7

关于Annex-B和AVCC两种格式总结
1、两种格式都有防止竞争字节
2、使用场景如下:

Annex B格式通常用于实时的流格式,比如说传输流,通过无线传输的广播、DVD等。在这些格式中通常会周期性的重复SPS和PPS包,经常是在每一个关键帧之前,因此据此建立解码器可以一个随机访问的点,这样就可以加入一个正在进行的流,及播放一个已经在传输的流。

AVCC格式的一个优点是在开始配置解码器的时候可以跳到流的中间播放,这种格式通常用于可以被随机访问的多媒体数据,如存储在硬盘的文件。
也因为这个特性,MP4、MKV通常用AVCC格式来存储。

你可能感兴趣的:(音视频,音频编码解码)