RTP 协议解包为 H264裸流
一. 为什么使用 RTP 协议?
TCP 传输流媒体数据由于其可靠性,会造成很大的网络延时和卡顿。
UDP 传输由于其不可靠性,会导致丢帧,如果是关键帧,则会花屏一个序列的时长。
RTP 使用了 RTP 和 RTCP 两个子协议来完成。
RTP 使用 UDP 完成流媒体数据传输,保证其时效性。
RTCP 也是使用 UDP,但只传输控制信息,占带宽很小,此时上层根据 RTCP 的信息,按照其重要性决定是否对丢失的流媒体数据进行重传。
RTP 在 1025-65535 之间选择一个未使用的偶数端口号作为其端口,RTCP 则使用下一个奇数端口号作为其端口,进而组成一个 UDP 端口对,端口号 5004 和 5005 作为 RTP 和 RTCP 的默认端口号。
RTP-Header 的流媒体特性,提供 帧边界、编码格式、序列号、时间戳等字段。
RTP 支持网络多播,而 TCP 不支持。
二. H264 的封装
拆解:H264 --> 序列(SPS.PPS.IPBBP…) --> Frame(帧) --> slice(切片) --> 宏块 --> 子宏块。
序列:一段 H264 序列是指从一个 I 帧开始到下一个 I 帧前的所有帧的集合。
NALU:H264 被封装在一个个 NALU(Network Abstraction Layer Unit)中进行传输。
NALU 以 [00 00 00 01] 为开始码,之后是 NaluHeader,再之后是 NaluPayload。
eg: [00 00 00 01 67 2F A4 1E 23 59 1E 42 … ].
常见的帧头数据:
00 00 00 01 67(SPS)
00 00 00 01 68(PPS)
00 00 00 01 65(IDR 帧)
00 00 00 01 61(P帧)
三. RTP 解包概念解析
RTP 封包时会将 [00 00 00 01] 的开始码去除。(注:在收到 RTP 包时需要在每个 NALU 头的位置拼接此开始码)
eg:[RTP-Header] + [ 67 2F A4 1E 23 59 1E 42 … ].
NALU 封包策略
如果 NALU 长度比较小,则可以将其完整地装在一个 RTP 包中。
此时,RTP 的结构为 RtpHeader + RtpPayload(NaluHeader + NaluPayload).
如果 NALU 长度超过 MTU(最大传输单元) 时,则需要对 NALU 进行分片封包。
此时,RTP 的结构为 RtpHeader + RtpPayload(FuIndicator + FuHeader + NaluPayload).
会比完整包多一个字节的头信息,下文会详细解释其含义。
什么是 RtpHeader, NaluHeader, FuIndicator 和 FuHeader?
RtpHeader
结构体 /**</