音视频入门基础:RTP专题(12)——RTP中的NAL Unit Type简介
一、引言
RTP封装H.264时,RTP对NALU Header的nal_unit_type附加了扩展含义。
由《音视频入门基础:H.264专题(4)——NALU Header:forbidden_zero_bit、nal_ref_idc、nal_unit_type简介》可以知道,nal_unit_type表示NALU的类型,在H.264官方文档《T-REC-H.264-202108-I!!PDF-E.pdf》第65页定义为:
二、NAL Unit Type
在RTP封包中,nal_unit_type被附加了扩展含义。根据《RFC 6184》第13页:
可以看到值为1 - 23的nal_unit_type为原H.264中规定的类型,24 - 31为RTP扩展的类型。扩展的类型包括STAP-A、STAP-B、MTAP16、MTAP24、FU-A、FU-B。
三、Decoding Order Number (DON)
根据《RFC 6184》第17页,在 interleaved packetization mode(交错分组模式)中,允许NAL单元的传输顺序与NAL单元的解码顺序不同。Decoding Order Number (解码顺序号 ,DON)是有效载荷结构或派生变量中的一个字段,表示 NAL 单元的解码顺序。传输和解码顺序的耦合由 可选的sprop-interleaving-depth 媒体类型参数控制,具体如下。当可选的sprop-interleaving-depth媒体类型参数的值等于 0(显式或默认值)时,NAL单元的传输顺序必须与 NAL 单元的解码顺序一致。当可选的sprop-interleaving-depth媒体类型参数的值大于 0时,NAL 单元的传输顺序必须与 NAL 单元的解码顺序一致。
MTAP16和MTAP24中NAL单元的顺序不需要是 NAL单元解码顺序,并且在两个连续数据包中通过去包STAP-B、MTAP和FU生成的NAL单元的顺序不需要是 NAL 单元解码顺序:
四、STAP
STAP是Single-time aggregation packet(单时聚合数据包)的意思。根据《RFC 6184》第22页,当 NAL单元聚合在一起且共享相同的NALU时间时,应使用单时聚合数据包。
(一)STAP-A
STAP-A(STAP type A)的有效载荷不包括DON,至少由一个single-time aggregation units(单时聚合单元)组成。如下图所示:
single-time aggregation units(单时聚合单元)由 16 位无符号大小信息(按网络字节顺序排列)组成,以字节为单位表示后面NAL单元的大小(不包括这两个八位位组,但包括 NAL单元的NAL 单元类型八位位组),后面是NAL单元本身,包括其 NAL 单元类型字节。单时聚合单元在 RTP 有效载荷内按字节对齐,但不一定按 32 位字边界对齐。下图显示了单时聚合单元的结构:
下图展示了一个包含 STAP-A 的 RTP 数据包示例。STAP 包含两个单时聚合单元,在图中分别标为1和2:
(二)STAP-B
STAP-B的有效载荷包括一个16位无符号解码顺序号 (DON)(按网络字节顺序排列)和至少一个single-time aggregation units(单时聚合单元):
DON 字段按传输顺序指定 STAP-B 中第一个 NAL 单元的DON值。对于 STAP-B 中按出现顺序连续出现的每个 NAL 单元,DON 值 =(STAP-B中前一个NAL单元的DON 值 + 1)% 65536,其中“%”表示模乘运算。
下图展示了一个包含 STAP-B 的 RTP 数据包示例。STAP 包含两个单时聚合单元,在图中分别标为 1 和 2:
五、MTAP
MTAP是Multi-Time Aggregation Packet(多时聚合包)的意思。MTAP 的NA 单元有效载荷包括一个 16 位无符号解码顺序号基 (DONB)(按网络字节顺序排列)和一个或多个多时间聚合单元,如下图所示。DONB必须包含MTAP NAL单元解码顺序中第一个NAL单元的DON值。说明:NAL 单元解码顺序中的第一个 NAL 单元不一定是 MTAP 中 NAL 单元封装顺序中的第一个 NAL 单元:
《RFC 6184》定义了两种不同的多时间聚合单元。它们都由以下 NAL 单元的 16 位无符号大小信息(按网络字节顺序)、8 位无符号解码顺序号差值(DOND)和该 NAL 单元的 n 位时间戳偏移(TS 偏移)(按网络字节顺序)组成,其中 n 可以是 16 位或 24 位。不同 MTAP 类型(MTAP16 和 MTAP24)之间的选择取决于应用:时间戳偏移越大,MTAP 的灵活性越高,但开销也越大。
MTAP16的多时间聚合单元结构如下图所示:
MTAP24的多时间聚合单元结构如下图所示:
数据包内聚合单元的起始或终止位置不要求在 32 位字边界上。多时间聚合单元中包含的 NAL 单元的 DON 等于 (DONB + DOND) % 65536,其中 % 表示取模运算。本备忘录未说明 MTAP 中的 NAL 单元如何排序,但在大多数情况下,应使用 NAL 单元解码顺序。
时间戳偏移字段必须设置为等于以下公式的值:如果 NALU 时间大于或等于数据包的 RTP 时间戳,则时间戳偏移 = (NAL 单元的 NALU 时间 - 数据包的 RTP 时间戳)。
如果 NALU 时间小于数据包的 RTP 时间戳,则时间戳偏移等于 NALU 时间 + (2^32 - 数据包的 RTP 时间戳)。
对于 MTAP 中的 “最早 ”多时间聚合单元,时间戳偏移必须为零。因此,MTAP 本身的 RTP 时间戳与最早的 NALU 时间相同。
参考说明:“最早 ”的多时间聚合单元是指如果聚合单元中包含的 NAL 单元封装在单个 NAL 单元数据包中,在 MTAP 的所有聚合单元中具有最小扩展 RTP 时间戳的单元。扩展时间戳是一种时间戳,它的位数超过 32 位,并能计算时间戳字段的缠绕,因此能确定时间戳缠绕时的最小值。这种 “最早 ”的聚合单元可能不是 MTAP 中聚合单元封装顺序中的第一个。最早 "的 NAL 单元也不必与 NAL 单元解码顺序中的第一个 NAL 单元相同。
下图展示了一个包含 MTAP16 类型的多时间聚合数据包的 RTP 数据包示例,该数据包包含两个多时间聚合单元,在图中标注为 1 和 2:
下图展示了一个包含 MTAP24 类型的多时间聚合数据包的 RTP 数据包示例,该数据包包含两个多时间聚合单元,在图中标注为 1 和 2:
六、Fragmentation Units (FUs)
根据《RFC 6184》第29页,这种有效载荷类型允许将一个 NAL 单元分割成多个 RTP 数据包。在应用层而不是依靠低层分片(如 IP)这样做有以下优点:
该有效载荷格式能够在 IPv4 网络上传输大于 64 kbytes 的 NAL 单元,而这些 NAL 单元可能存在于预先录制的视频中,尤其是高清格式中(每幅图像的切片数有限制,这导致每幅图像的 NAL 单元数有限制,从而可能产生较大的 NAL 单元)。
分片机制允许对单个 NAL 单元进行分片,并前向纠错。
片段只针对单个 NAL 单元,而不针对任何聚合数据包。一个 NAL 单元的片段由该 NAL 单元的整数个连续八位位组组成。NAL 单元的每个八位字节必须恰好是该 NAL 单元的一个片段的一部分。
同一 NAL 单元的片段必须以升序 RTP 序列号连续发送(在第一个片段和最后一个片段之间不发送同一 RTP 数据包流中的其他 RTP 数据包)。同样,一个 NAL 单元必须按 RTP 序列号顺序重新组装。
当一个 NAL 单元被分片并在分片单元 (FUs) 内传送时,它被称为分片 NAL 单元。STAP 和 MTAP 不得分片。FU 不得嵌套;也就是说,一个 FU 不得包含另一个 FU。
携带 FU 的 RTP 数据包的 RTP 时间戳被设置为分片 NAL 单元的 NALU 时间。
下图显示了 FU-A 的 RTP 有效载荷格式。FU-A 由一个八位位组的碎片单元指示符、一个八位位组的碎片单元报头和一个碎片单元有效载荷组成:
下图显示了 FU-B 的 RTP 有效载荷格式。FU-B 由一个八位位组的片段单元指示符、一个八位位组的片段单元头、一个解码顺序号(DON)(按网络字节顺序)和一个片段单元有效载荷组成。换句话说,FU-B 的结构与 FU-A 的结构相同,只是多了一个 DON 字段:
在interleaved packetization mode(交错分组模式)中,NAL 单元类型 FU-B 必须用于分片 NAL 单元的第一个分片单元。在任何其他情况下都不得使用 NAL 单元类型 FU-B。换句话说,在交错分组模式下,每个被分片的 NALU 的第一个分片都是 FU-B,然后是一个或多个 FU-A 分片。
FU 指示符八位位组的格式如下:
FU 指示符八位位组类型字段 28 和 29 的值分别标识 FU-A 和 FU-B。NRI 字段的值必须根据分片 NAL 单元中 NRI 字段的值设置。
FU 头的格式如下:
其中:
S:占1位。当设置为 1 时,起始位表示分片 NAL 单元的起始位置。当下面的 FU 有效载荷不是片段 NAL 单元有效载荷的开始时,开始位设为 0。
E:占1位。当设置为 1 时,End 位表示分片 NAL 单元的结束,即有效载荷的最后一个字节也是分片 NAL 单元的最后一个字节。当后续 FU 有效载荷不是片段 NAL 单元的最后一个片段时,End 位被置 0。
R:占1位。保留位必须等于 0,且必须被接收器忽略。
Type:占5位。下图中定义的 NAL 单元有效载荷类型:
说明:FU-Bs 中的 DON 字段允许网关将 NAL 单元分片到 FU-Bs,而无需按照 NAL 单元解码顺序组织传入的 NAL 单元。
片段 NAL 单元不得在一个 FU 中传输;也就是说,在同一个 FU 标头中,开始位和结束位不得同时置 1。
FU 有效载荷由片段 NAL 单元有效载荷的片段组成,这样,如果连续 FU 的片段单元有效载荷按顺序连接起来,就可以重建片段 NAL 单元的有效载荷。碎片 NAL 单元的 NAL 单元类型八位位组不包含在碎片单元有效载荷中,而是在碎片单元 FU 指示符八位位组的 F 和 NRI 字段以及 FU 标头的类型字段中传达碎片 NAL 单元的 NAL 单元类型八位位组信息。FU 有效载荷可以有任意数量的八位位组,也可以是空的。
说明:空 FU 允许在几乎无损的环境中减少某类发送方的延迟。这些发送方的特点是,他们在 NALU 完全生成之前,也就是在知道 NALU 大小之前,就将 NALU 片段打包。如果不允许使用零长度的 NALU 片段,发送者就必须在发送当前片段之前生成至少一个比特的下一个片段数据。由于 H.264 的特点,有时几个宏块占用的比特为零,这种情况并不可取,而且会增加延迟。不过,在使用零长度 NALU 片段(可能)时,应仔细权衡因传输时使用额外数据包而增加的至少部分 NALU 丢失风险。
如果一个分片单元丢失,接收方应按照传输顺序丢弃与同一分片 NAL 单元相对应的所有后续分片单元。端点或 MANE 中的接收方可将 NAL 单元的前 n 1 个片段聚合为一个(不完整的)NAL 单元,即使未收到该 NAL 单元的 n 个片段。在这种情况下,NAL 单元的 forbidden_zero_bit 必须设为 1,以表示语法违规。