实时传输协议RTP(一)
实时传输协议:Real-time Transport Protocol(RTP )。
实时传输控制协议:Real-time Transport Control Protocol(RTCP)。
RFC文档为RFC3550(RFC1889为其过期版本)详细介绍了RTP/RTCP相关协议。
RTP对音频、视频、图像等多种种需要实时传输的多媒体数据提供端到端的实时传输服务。RTP为Internet上端到端的实时传输提供时间信息和流同步,但并不保证服务质量,服务质量由RTCP来提供。
本章对RTP进行简介和实例说明,RTCP在后面章节详细解释。RTP协议详解
RTP 初始设计是用来满足参与者媒体会议的需要,它没有限定于专门的应用。但随着在单播或多播网络需求中应用实时数据传输的推广。RTP现在广泛的应用在流媒体直播、会议、可视电话等多个领域中。
简单的多播音频会议。语音通信通过一个多播地址和一对端口来实现。一个用于音频数据(RTP),另一个用于控制包(RTCP)。
音频和视频会议。如果在一次会议中同时使用了音频和视频会议,这两种媒体将分别在不同的RTP会话中传送,每一个会话使用不同的传输地址(IP地址 端口)。如果一个用户同时使用了两个会话,则每个会话对应的RTCP包都使用规范化名字CNAME(Canonical Name)。与会者可以根据RTCP包中的CNAME来获取相关联的音频和视频,然后根据RTCP包中的计时信息(Network time protocol)来实现音频和视频的同步。
基于UDP实现的,RTP用来为端到端的实时传输提供时间信息和流同步,但并不保证服务质量。服务质量由RTCP来提供。
整体协议字段如图所示:
图1-rtp协议
1.RTP协议之Header固定头结构解析
图2-Header固定头
Header固定头有12个固定字节,各字段按比特计算,代表含义如下所示:
(1)版本(V):2 比特,此定义了 RTP 的版本。此协议定义的版本是 2。
(2)填充(P):1 比特,若填料比特被设置,则此包包含一到多个附加在末端的填充比特,填充比特不算作负载的一部分。填充的最后一个字节指明可以忽略多少个填充比特。填充可能用于某些具有固定长度的加密算法,或者用于在底层数据单元中传输多个 RTP 包。
(3)扩展(X):1 比特,设置扩展比特标识。0代表无扩展头,1代表有扩展头。
(4)CSRC 计数(CC):4 比特,CSRC 计数包含了跟在固定头后面 CSRC 识别符的数目。
(5)标志(M):1 比特,标志的解释由具体协议规定。它用来允许在比特流中标记重要的事件,如帧边界。
(6)负载类型(PT):7 比特,此定义了负载的格式,由具体应用决定其解释,协议可以规定负载类型码和负载格式之间一个默认的匹配。其他的负载类型码可以通过非 RTP 方法动态定义。RTP发送端在任意给定时间发出一个单独的 RTP 负载类型;此不用来复用不同的媒体流。
(7)序列号(sequence number):16 比特,每发送一个 RTP 数据包,序列号加 1,接收端可以据此检测丢包和重建包序列。序列号的初始值是随机的(不可预测),以使即便在源本身不加密时(有时包要通过翻译器,它会这样做),对加密算法泛知的普通文本攻击也会更加困难。
(8)时间戳(timestamp) :32 比特,时间戳反映了 RTP 数据包中第一个字节的采样时间。时钟频率依赖于负载数据格式,并在描述文件(profile)中进行描述。也可以通过 RTP 方法对负载格式动态描述。
(9)SSRC:32 比特,用以识别同步源。标识符被随机生成,以使在同一个 RTP 会话期中没有任何两个同步源有相同的 SSRC 识别符。尽管多个源选择同一个 SSRC 识别符的概率很低,所有 RTP 实现工具都必须准备检测和解决冲突。若一个源改变本身的源传输地址,必须选择新的SSRC 识别符,以避免被当作一个环路源。
(10)CSRC 列表:0 到 15 项,每项 32 比特,CSRC 列表识别在此包中负载的所有贡献源。识别符的数目在 CC 域中给定。若有贡献源多于 15 个,仅识别 15 个。CSRC 识别符由混合器插入,并列出所有贡献源的 SSRC 识别符。
2.RTP协议之Header扩展头结构解析
RTP-Header固定长度12字节,在一些情况下无法满足需要,需要扩展。在固定头中标识了是否有扩展字段相关信息。
如果 RTP 标准头部扩展(X) 位为1,就表示CSRC后面还有一些额外的 RTP 扩展头,rfc5285 对 header extension 做了拓展,支持两种类型的拓展头 One-byte Header 和 Two-byte Header
图3-扩展头
扩展头(ExtensionsHeader)所有信息都包含在CC中,可以得知扩展头长度:如CC=4,ExtensionsHeader_size =4*4(字节)=4*32(bit)。
前4个字节来区分用何种类型扩展头defined by profile(占2个字节):[One-byte Header 标识0xBEDE/Two-byte Header 标识0x1000],length表示除去 defined by profile和length字段之外的ExtensionsHeader 长度说明( 占2个字节);
图4-One-byte Header
如上图4所示第一个 16 为固定为 0XBEDE 标志,意味着这是一个 one-byte 扩展,length = 3 说明 header extension 的总长度为 3 * 32bit = 96bit = 12byte。
每个扩展头首先以一个 byte 开始, ID为标识,占4bit, 后4bit是L 的长度代表后面紧跟数据长度(此时 数据长度为L+1) ,比如 L=0 时,紧跟后面有1个 byte 的 data,同理第二个扩展头的 L=1 说明后面还有 2 个 byte 的 data,但是注意,其后没有紧跟第三个扩展头,而是添加了 2 个byte大小的全 0 的 data,这是为了作填充对齐,因为扩展头是以为 32bit 作填充对齐的
图5-Two-byte Header
如上图5所示第一个 16 为固定为 0X1000 标志,意味着这是一个 two-byte 扩展,length = 3 说明 header extension 的总长度为 3 * 32bit = 96bit = 12byte。
每个扩展头首先以一个 byte 开始, ID为标识,占8bit, 后8bit是L 的长度代表后面紧跟数据长度(此时 数据长度为L,表示真实的长度 ) ,比如 L=0 时,紧跟没有data,同理第二个扩展头的 L=1 说明后面还有 1个 byte 的 data,但是注意,其后没有紧跟第三个扩展头,而是添加了 1 个byte大小的全 0 的 data,这是为了作填充对齐,因为扩展头是以为 32bit 作填充对齐的
3.RTP协议之Playload/Padding解析
注释: buffer为RtpPacket数据,size为RtpPacket数据长度,payload_offset为RtpPacket数据真正载荷的偏移量,cc为固定头中字段CSRC 计数(CC)。
一段RtpPacket数据包由RtpHeader + RtpBody组成;
RtpHeader由FixHeader + ExtensionsHeader 组成;
RtpBody由Playload + Padding组成;
在FixHeader中标识了是否有填充数据字段填充(P);若为1,则有填充字段;如何计算填充数据长度?在RtpPacket包最后一位标记了填充数据长度。注意填充数据长度也包含RtpPacket包最后一位。
if (P)
padding_size = buffer[size - 1];
else
padding_size =0;
Playload是RtpPacket数据所承载的真实数据,长度为:
payload_offset = FixedHeaderSize + cc* 4;
payload_size = size - payload_offset - padding_size;
4.RTP实例演示
图6-wirshark-RtpPacket
如上图6所示,抓取wirshark获取的rtp包,从中可以看到rtp 固定头信息和扩展头信息。截取一段RTP包的buffer数据分析如下:
90 60 02 7c 00 13 51 50 00 03 11 a6 be de 00 01 51 02 7c 00 7c 85 b8 00 00 08 10 63
90 是V_P_X_CC ,把90换成二进制1000 0000
V是10;P是0;X是1;CC是0000 (这个地方有误);
60 是M_PT,把60换成二进制0110 0000
M是0;PT是1100000;
02 7e 是SequenceNum;
00 13 51 50 是Timestamp;
00 03 11 a6 是SSRC;
be de 是扩展头defined by profile (One-byte Header 标识);
00 01 是length字段,说明有一个扩展字段;
51 是扩展字段标识和长度,把51换成二进制0101 0001;
标识是5;
长度是1,其 真实长度是1+1=2 ;
02 7c 是扩展字段内容;
00 是填充字段,要保证4的倍数;
5.RTP代码解析
此段代码是对RtpPacket的解析,代码中进行了相关注释!!!
请继续关注本人系列作品!欢迎讨论!!!