RTP协议解析及H264/H265 音视频RTP打包分析

一 概述

实时传输协议(Real-time Transport Protocol或简写RTP)是一个网络传输协议,它是由IETF的多媒体传输工作小组1996年在RFC 1889中公布的。
RTP协议详细说明了在互联网上传递音频和视频的标准数据包格式。它一开始被设计为一个多播协议,但后来被用在很多单播应用中。RTP协议常用于流媒体系统(配合RTSP协议),视频会议和一键通(Push to Talk)系统(配合H.323或SIP),使它成为IP电话产业的技术基础。RTP协议和RTP控制协议RTCP一起使用,而且它是创建在UDP协议上的。
当RTSP会话建立成功,并开始传输时,音视频数据以RTP协议打包发送给客户端;

二 RTP报头解析

RTP协议解析及H264/H265 音视频RTP打包分析
V:RTP协议的版本号,占2位,当前协议版本号为2
P:填充标标志,占1位,如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分。
X:扩展标志,占1位,如果X=1,则在RTP报头后跟有一个扩展报头
CC:CSRC计数器,占4位,指示CSRC 标识符的个数
M:标记,占1位,不同的有效载荷有不同的含义,对于视频,标记一帧的结束;对于音频,标记会话的开始
PT:有效载荷类型,占7位,用于说明RTP报文中有效载荷的类型,如GSM音频、JPEM图像等
sequence number:***,占16位,用于标识发送者所发送的RTP报文的***,每发送一个报文,***增1。接收者通过***来检测报文丢失情况,重新排序报文,恢复数据
timestamp:时间戳,占32位,时戳反映了该RTP报文的第一个八位组的采样时刻。接收者使用时戳来计算延迟和延迟抖动,并进行同步控制
SSRC:同步信源标识符,占32位,用于标识同步信源。该标识符是随机选择的,对弈同一个视频源,每个会话都有自己独立的同步信源
CSRC:特约信源标识符,每个CSRC信源占32位,可以有0-15个,具体数量由CC决定,每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源

三 H264/H265 RTP打包分析1.RTP包头的封装

打包时,每帧数据包均需要添加二中所述RTP包头,对于每路视频流,RTP包头除***外,基本保持不变;另一个要注意的时,由于包头需要按位填充,当填充/发送数据时,应注意发送端数据的大小端限制。2.数据流的包头
此处以h264,h265,aac,g711来举例说明
g711数据在发送时,不需要额外的头部信息,其他三种数据流,在rtp包头后,应按格式封装自己的数据头
其中h264为一个字节,h265为两个字节,aac数据为四个字节
1.h264打包
视频包时需要考虑到MTU的大小,每包数据不能超过MTU的大小,通常情况下,设备是不知道当前网络的MTU大小的。
因此都会在代码中指定一个大小,开发时,可以参考ffmpeg中给定该值的大小
H264数据打包格式如下:
RTP头+h264字节头+视频数据帧
h264字节头为两个字节,格式如下
第一个字节
RTP协议解析及H264/H265 音视频RTP打包分析
根据ffmpeg代码,F为0,此处type为28,
nri = buff[0] & 0x60;
buff[0] 为视频帧的第一个数据
第二个字节
RTP协议解析及H264/H265 音视频RTP打包分析
此处type = buff[0] & 0x1f;
其中S E R的解释如下,
RTP协议解析及H264/H265 音视频RTP打包分析
注意当数据包被分成多包数据后,处S E R三位,其他均与第一包保持一致,不得改变
2.h265打包
打包和h264过程类似,区别就是H265的数据头为三个字节,
h265的三个字节,结构如下:
第一第二个字节
RTP协议解析及H264/H265 音视频RTP打包分析
参考ffmpeg代码 此处F为0,Type为49,LayerId为0,TID为1
第三个字节
RTP协议解析及H264/H265 音视频RTP打包分析

其中FuType = (buf[0] >> 1) & 0x3F;
S E的用法和h264中相同,此处不再叙述3.aac打包
aac在打包为RTP数据包时,每帧数据前还应该由四个字节头,即格式如下
RTP包头+AAC字节头+AAC数据
当AAC数据前由ADTS头时, 打包时应该跳过7字节的ADTS头
AAC字节头定义如下
字节1:0x00
字节2:0x01
字节3:(data_len & 0x1fe0) >> 5
字节4:(data_len &0x1f) << 3

四 参考代码

ffmpeg代码 rtpenc_h264_hevc.c文件
void ff_rtp_send_h264_hevc(AVFormatContext *s1, const uint8_t *buf1, int size);
此处注意,该函数将h264和h265的nalu打包放在了同一个函数中,注意根据判断语句来区分。