RTP/RTCP协议讲解


***【在线视频教程】***

好文章,来自【福优学苑@音视频+流媒体】

RTP 

RTP:(Real-time Transport Protocol)


是用于Internet上针对多媒体数据流的一种传输层协议.RTP 协议和 RTP 控制协议 RTCP 一起使用,而且它是建立在 UDP 协议上的.

RTP 不像http和ftp可完整的下载整个影视文件,它是以固定的数据率在网络上发送数据,客户端也是按照这种速度观看影视文件,当影视画面播放过后,就不可以再重复播放,除非重新向服务器端要求数据。


实时传输协议RTP(Real-Time Transport Protocol):

    RTP是针对Internet上多媒体数据流的一个传输协议, 由IETF(Internet工程任务组)作为RFC1889发布。RTP被定义为在一对一或一对多的传输情况下工作,其目的是提供时间信息和实现流同步。RTP的典型应用建立在UDP上,但也可以在TCP或ATM等其他协议之上工作。

    RTP本身只保证实时数据的传输,并不能为按顺序传送数据包提供可靠的传送机制,也不提供流量控制或拥塞控制,它依靠RTCP提供这些服务。



1.1流媒体概念

流媒体技术是网络技术和多媒体技术发展到一定阶段的产物。

术语流媒体既可以指在网上传输连续时基媒体的流式技术,也可以指使用流式技术的连续时基媒体本身。

在网上传输音频、视频等多媒体信息目前主要有两种方式:下载和流式传输

采用下载方式,用户需要先下载整个媒体文件,然后才能进行播放。由于网络带宽的限制,下载常常要花很长时间,所以这种处理方式延迟很大。

    而流媒体实现的关键技术是流式传输。传输之前首先对多媒体进行预处理(降低质量和高效压缩) ,然后使用缓存系统来保证数据连续正确地进行传输。使用流式传输方式,用户不必像采用下载方式那样要等到整个文件全部下载完毕,而是只需经过几秒到几十秒的启动延时即可在客户端进行播放和观看。此时媒体文件的剩余部分将在后台继续下载。

与单纯的下载方式相比,这种对多媒体文件边下载边播放的流式传输方式不仅使启动延时大幅度地缩短,而且对系统缓存容量的需求也大大降低。

使用流式传输的另一个好处是使传输那些事先不知道或无法知道大小的媒体数据(如网上直播、视频会议等) 成为可能。

到目前为止,Internet 上使用较多的流式视频格式主要有以下三种:RealNetworks 公司的RealMedia ,Apple 公司的QuickTime(hls) 以及Microsoft 公司的Advanced Streaming Format (ASF) 。

 

1.2支持流媒体的协议

    多媒体应用的一个显著特点是数据量大,并且许多应用对实时性要求比较高。

    传统的TCP 协议是一个面向连接的协议,它的重传机制和拥塞控制机制都是不适用于实时多媒体传输的。

    RTP 是一个应用型的传输层协议,它并不提供任何传输可靠性的保证和流量的拥塞控制机制。RTP 位于UDP(User Datagram Protocol) 之上。UDP 虽然没有TCP 那么可靠,并且无法保证实时业务的服务质量,需要RTCP 实时监控数据传输和服务质量。但是,由于UDP 的传输时延低于TCP ,能与音频和视频很好地配合。

    因此,在实际应用中,RTP/ RTCP/ UDP 用于音频/ 视频媒体,而TCP 用于数据和控制信令的传输。

    目前,支持流媒体传输的协议主要有实时传输协议RTP( Real-Time Transport Protocol) 、实时传输控制协议RTCP(Real-Time Transport Control Protocol) 和实时流协议RTSP(Real-Time Streaming Protocol) 等。下面分别对这三种协议作简要介绍。

流媒体协议栈如图1 所示。

image.png

 

1.3 RTP工作机制

    威胁多媒体数据传输的一个尖锐的问题就是不可预料数据到达时间。

但是流媒体的传输是需要数据的适时的到达用以播放和回放。

    rtp协议就是提供了时间标签,序列号以及其它的结构用于控制适时数据的流放。在流的概念中”时间标签”是最重要的信息。发送端依照即时的采样在数据包里隐蔽的设置了时间标签。在接受端收到数据包后,就依照时间标签按照正确的速率恢复成原始的适时的数据。不同的媒体格式调时属性是不一样的。

    但是rtp本身并不负责同步,rtp只是传输层协议,为了简化运输层处理,提高该层的效率。将部分运输层协议功能(比如流量控制)上移到应用层完成。同步就是属于应用层协议完成的。它没有运输层协议的完整功能,不提供任何机制来保证实时地传输数据,不支持资源预留,也不保证服务质量。rtp报文甚至不包括长度和报文边界的描述。同时rtp协议的数据报文和控制报文的使用相邻的不同端口,这样大大提高了协议的灵活性和处理的简单性。

rtp协议和udp二者共同完成运输层协议功能。

    udp协议只是传输数据包,不管数据包传输的时间顺序。 

    rtp的协议数据单元是用udp分组来承载的。在承载rtp数据包的时候,有时候一帧数据被分割成几个包具有相同的时间标签,则可以知道时间标签并不是必须的。而udp的多路复用让rtp协议利用支持显式的多点投递,可以满足多媒体会话的需求。

rtp协议虽然是传输层协议但是它没有作为osi体系结构中单独的一层来实现。rtp协议通常根据一个具体的应用来提供服务,rtp只提供协议框架,开发者可以根据应用的具体要求对协议进行充分的扩展。

 

1.4 RTP协议的报文结构

RTP头格式如图2所示:

image.png


开始12个八进制出现在每个RTP包中,而CSRC标识列表仅出现在混合器插入时。各段含义如下:

①版本(V)

2位,标识RTP版本。

 

②填充标识(P)

1位,如设置填充位,在包尾将包含附加填充字,它不属于有效载荷。填充的最后一个八进制包含应该忽略的八进制计数。某些加密算法需要固定大小的填充字,或为在底层协议数据单元中携带几个RTP包。

 

③扩展(X)

1位,如设置扩展位,固定头后跟一个头扩展。

 

④CSRC计数(CC)

4位,CSRC计数包括紧接在固定头后CSRC标识符个数。

 

⑤标记(M)

1位,标记解释由设置定义,目的在于允许重要事件在包流中标记出来。设置可定义其他标示位,或通过改变位数量来指定没有标记位。

 

⑥载荷类型(PT)

7位,记录后面资料使用哪种 Codec , receiver 端找出相应的 decoder 解碼出來。

 


⑦系列号

16位,系列号随每个RTP数据包而增加1,由接收者用来探测包损失。系列号初值是随机的,使对加密的文本攻击更加困难。

 

⑧时标

32位,时标反映RTP数据包中第一个八进制数的采样时刻,采样时刻必须从单调、线性增加的时钟导出,以允许同步与抖动计算。时标可以让receiver端知道在正确的时间将资料播放出来。

 

由上图可知,如果只有系列号,并不能完整按照顺序的将data播放出来,因为如果data中间有一段是没有资料的,只有系列号的话会造成错误,需搭配上让它知道在哪个时间将data正确播放出来,如此我们才能播放出正确无误的信息。

 

⑨SSRC

32位,SSRC段标识同步源。此标识不是随机选择的,目的在于使同一RTP包连接中没有两个同步源有相同的SSRC标识。尽管多个源选择同一个标识的概率很低,所有RTP实现都必须探测并解决冲突。如源改变源传输地址,也必须选择一个新SSRC标识以避免插入成环行源。

 

⑩CSRC列表

0到15项,每项32位。CSRC列表表示包内的对载荷起作用的源。标识数量由CC段给出。如超出15个作用源,也仅标识15个。CSRC标识由混合器插入,采用作用源的SSRC标识。




   

RTCP

RTCP:Real-time Transport Control Protocol 或 RTP Control Protocol或简写 RTCP)


实时传输控制协议,是实时传输协议(RTP)的一个姐妹协议.


注:--:RTP 协议和 RTP控制协议(RTCP) 一起使用,而且它是建立在UDP协议上的(一般用于视频会议)

RTCP负责管理传输质量在当前应用进程之间交换控制信息。

在RTP会话期间,各参与者周期性地传送RTCP包,包中含有已发送的数据包的数量、丢失的数据包的数量等统计资料。因此,服务器可以利用这些信息动态地改变传输速率,甚至改变有效载荷类型。

RTP和RTCP配合使用,能以有效的反馈和最小的开销使传输效率最佳化,故特别适合传送网上的实时数据。

 

1.1 RTCP工作机制

当应用程序开始一个rtp会话时将使用两个端口:一个给rtp,一个给rtcp。

rtp本身并不能为按顺序传送数据包提供可靠的传送机制,也不提供流量控制或拥塞控制,它依靠rtcp提供这些服务。

在rtp的会话之间周期的发放一些rtcp包以用来传监听服务质量和交换会话用户信息等功能。rtcp包中含有已发送的数据包的数量、丢失的数据包的数量等统计资料。

因此,服务器可以利用这些信息动态地改变传输速率,甚至改变有效载荷类型。rtp和rtcp配合使用,它们能以有效的反馈和最小的开销使传输效率最佳化,因而特别适合传送网上的实时数据。根据用户间的数据传输反馈信息,可以制定流量控制的策略,而会话用户信息的交互,可以制定会话控制的策略。

 

1.2 RTCP数据报

在RTCP通信控制中,RTCP协议的功能是通过不同的RTCP数据报来实现的,主要有如下几种类型:

①SR:发送端报告,所谓发送端是指发出RTP数据报的应用程序或者终端,发送端同时也可以是接收端。

②RR:接收端报告,所谓接收端是指仅接收但不发送RTP数据报的应用程序或者终端。

③SDES:源描述,主要功能是作为会话成员有关标识信息的载体,如用户名、邮件地址、电话号码等,此外还具有向会话成员传达会话控制信息的功能。

④BYE:通知离开,主要功能是指示某一个或者几个源不再有效,即通知会话中的其他成员自己将退出会话。

⑤APP:由应用程序自己定义,解决了RTCP的扩展性问题,并且为协议的实现者提供了很大的灵活性。



RTSP 和 RTP 的关系


    RTP不象http和ftp可完整的下载整个影视文件,它是以固定的数据率在网络上发送数据,客户端也是按照这种速度观看影视文件,当影视画面播放过后,就不可以再重复播放,除非重新向服务器端要求数据。


    RTSP与RTP最大的区别在于:RTSP是一种双向实时数据传输协议,它允许客户端向服务器端发送请求,如回放、快进、倒退等操作。当然,RTSP可基于RTP来传送数据,还可以选择TCP、UDP、组播UDP等通道来发送数据,具有很好的扩展性。它是一种类似于http协议的网络应用层协议。


我们来看看下图所示的例子:服务器端实时采集、编码并发送两路视频,客户端接收并显示两路视频。由于客户端不必对视频数据做任何回放、倒退等操作,可直接采用UDP+RTP+组播实现。


image.png

--->:RTSP 与 RTP 最大的区别在于:RTSP 是一种双向实时数据传输协议,它允许客户端向服务器端发送请求,如回放、快进、倒退等操作。当然,RTSP 可基于 RTP 来传送数据,还可以选择 TCP、UDP、组播 UDP 等通道来发送数据,具有很好的扩展性。它是一种类似与http协议的网络应用层协议.


RTP是实时传输协议,一般不作为单独应用层协议处理;rtsp是实时流传输协议,它是与http等级的应用层网络协议,它是由realmedia开发,用来传输流媒体影像文件。   

   rtsp可基于rtp之上,比如常见的视频流传输过程:视频压缩文件->rtp打包->基于udp的rtsp网络传输;也可以不做成rtp包,直接基于udp传送,如视频压缩文件->基于udp的rtsp网络传输。


 


具体协议内容可参看以下标准文档:

RTP/RTCP-------------------------RFC3550/RFC3551

RTSP        --------------------------RFC2326



--->:RTSP、RTCP、RTP区别

1:RTSP实时流协议

作为一个应用层协议,RTSP提供了一个可供扩展的框架,它的意义在于使得实时流媒体数据的受控和点播变得可能。总的说来,RTSP是一个流媒体表示协议,主要用来控制具有实时特性的数据发送,但它本身并不传输数据,而是必须依赖于下层传输协议所提供的某些服务。RTSP可以对流媒体提供诸如播放、暂停、快进等操作,它负责定义具体的控制消息、操作方法、状态码等,此外还描述了与RTP间的交互操作(RFC2326)。


2:RTCP控制协议

RTCP控制协议需要与RTP数据协议一起配合使用,当应用程序启动一个RTP会话时将同时占用两个端口,分别供RTP和RTCP使用。RTP本身并不能为按序传输数据包提供可靠的保证,也不提供流量控制和拥塞控制,这些都由RTCP来负责完成。通常RTCP会采用与RTP相同的分发机制,向会话中的所有成员周期性地发送控制信息,应用程序通过接收这些数据,从中获取会话参与者的相关资料,以及网络状况、分组丢失概率等反馈信息,从而能够对服务质量进行控制或者对网络状况进行诊断。


RTCP协议的功能是通过不同的RTCP数据报来实现的,主要有如下几种类型:

SR:发送端报告,所谓发送端是指发出RTP数据报的应用程序或者终端,发送端同时也可以是接收端。(SERVER定时间发送给CLIENT)。

RR:接收端报告,所谓接收端是指仅接收但不发送RTP数据报的应用程序或者终端。(SERVER接收CLIENT端发送过来的响应)。

SDES:源描述,主要功能是作为会话成员有关标识信息的载体,如用户名、邮件地址、电话号码等,此外还具有向会话成员传达会话控制信息的功能。

BYE:通知离开,主要功能是指示某一个或者几个源不再有效,即通知会话中的其他成员自己将退出会话。

APP:由应用程序自己定义,解决了RTCP的扩展性问题,并且为协议的实现者提供了很大的灵活性。


3:RTP数据协议

RTP数据协议负责对流媒体数据进行封包并实现媒体流的实时传输,每一个RTP数据报都由头部(Header)和负载(Payload)两个部分组成,其中头部前12个字节的含义是固定的,而负载则可以是音频或者视频数据。


RTP用到的地方就是 PLAY ,服务器往客户端传输数据用UDP协议,RTP是在传输数据的前面加了个12字节的头(描述信息)。


RTP载荷封装设计本文的网络传输是基于IP协议,所以最大传输单元(MTU)最大为1500字节,在使用IP/UDP/RTP的协议层次结构的时候,这其中包括至少20字节的IP头,8字节的UDP头,以及12字节的RTP头。这样,头信息至少要占用40个字节,那么RTP载荷的最大尺寸为1460字节。以H264 为例,如果一帧数据大于1460,则需要分片打包,然后到接收端再拆包,组合成一帧数据,进行解码播放。



1.RTP over UDP和RTP over RTSP有什么区别?

不一样,

RTP over UDP 是RTP下层使用udp传输,

RTP over RTSP 是指的用rtsp协议建立会话,然后使用RTP协议传输数据;


2.RTP over RTSP是不是就是RTP over TCP?

不是:RTP over RTSP 是指的用用rtsp协议建立会话,然后使用RTP协议传输数据;

至于下面用udp 还是tcp是不确定的


3.RTP over TCP 打包视频是不是要加4个字节的头,是怎么加的?

需要看rfc3984


4.有PS流的封装格式吗?

PS,TS,ES都有


rtp和rtsp协议是应用层的,tcp和udp是传输层的,所以只能说rtp over tcp/udp。

而且一般情况下一个点播需要rtsp+rtp+rtcp三个协议共同来实现。


RTP,RTCP数据和RTSP数据共享TCP数据通道,所以必须有一个标识来区别三种数据。

RTP和RTCP数据会以$符号+1个字节的通道编号+4个字节的数据长度,共6个字节的前缀开始,

RTSP数据是没有前缀数据的。


RTP数据和RTCP数据的区别在于第二个字节的通道编号,据观察RTP通道编号是偶数,RTCP通道编号是奇数。



Rtp over tcp:需要4字节的头部

RTP,RTCP数据和RTSP数据共享TCP数据通道

RTP,RTCP数据和RTSP数据共享TCP数据通道,所以必须有一个标识来区别三种数据。

RTP和RTCP数据会以【$符号+1个字节的通道编号+2个字节的数据长度】,共4个字节的前缀开始,

RTSP数据是没有前缀数据的。


RTP数据和RTCP数据的区别在于第二个字节的通道编号,据观察RTP通道编号是偶数,RTCP通道编号是奇数。

两种发送方式的RTP包的打包方式和内容都是一样的,不同的地方主要是rtsp会话交互发送的信息还有通过TCP方式发送的RTP包前面再加四个字节的头,加四个字节头以及数据发送的代码如下:

static int send_rtp_packet(rtpclientparam_info* pinfo, unsigned char *buf,int len)

{

    int sfd = 0;

    int sendtonum;

    struct sockaddr_in s;

 

    if(!pinfo || !buf)

        return 1;

 

    if(pinfo->rtpovertcp)// rtp over tcp:需要另外添加4字节的头部

    {

        unsigned char tcp_pkt[len + 4];//tcp包:缓冲区

        uint16 *intlvd_ch = (uint16 *)&tcp_pkt[2];//缓冲区长度

 

        tcp_pkt[0] = '$';

        tcp_pkt[1] = (unsigned char)(pinfo->dst_videoport);//在这里目标端口号就是Channel id

         

        printf("tcp_pkt[1]=%d,port=%d\n",tcp_pkt[1],pinfo->dst_videoport);

        *intlvd_ch = htons((uint16)len);//两个字节的缓冲区长度

        memcpy(tcp_pkt + 4, buf, len);

         

        sendtonum = send(pinfo->tcpfd, tcp_pkt, len+4, MSG_NOSIGNAL);

         

    }

    else

    {

        s.sin_family = AF_INET;

            s.sin_addr.s_addr = pinfo->dstip;

         

        sfd = video_sockethandle;

        s.sin_port = htons(pinfo->dst_videoport);

         

        sendtonum = sendto(sfd, buf, len, 0, (struct sockaddr *)&s, sizeof(s));

         

    }   

     

    if(sendtonum != len)

        return 2;

 

    return 0;

}





好文章,来自【福优学苑@音视频+流媒体】
***【在线视频教程】***