RTP、RTCP及媒体流同步
一、流媒体简介
流媒体是指在internet中使用流媒体技术的连续时基媒体,例如视频、音频或多媒体文件。流式传输方式是将音视频、动画等多媒体文件经过压缩后分成一个个小数据包,当用户端发出请求时,由服务器端向用户端实时、连续传送这些小数据包,动态变化的网络可能使各个包选择不同的路由,故到达用户端的时间延迟也就不同。在用户端用播放器播放时,需要为接收数据开辟缓存区,以弥补时延和时延抖动的影响和保证数据包传输顺序的正确,经解压缩后,只需要在缓冲区充满前等待几秒钟,就可以连续观看。而同时,后续数据包继续在后台从服务器端以稳定的速率向客户端发送,不影响前台播放。所以从理论上讲,播放前的延时主要是由于播放器接收、处理前几个数据包引起的,一旦播放就能够保证连续性和稳定性。流式传输的实现不仅需要高效的压缩算法和缓存,而且需要合适的传输协议。由于tcp需要较多的开销,不太适合传输实时数据。在流式传输的实现方案中,一般采用http/tcp来传输控制信息,而用RTP/UDP来传输实时视音频数据。实现流式传输一般都需要专用的媒体服务器和媒体播放器。
二、流媒体传输的网络协议:RTP与RTCP介绍
1.实时传输协议RTP( Real-time Transport Protocol)
RTP被定义在一对一或一对多传输下工作,其目的是提供时间信息和实现流同步。RTP封装了多媒体应用的数据块。RTP不建立连接,不保证交付,也不进行资源预留。RTP本身并不能为按顺序传送数据包提供可靠的传送机制,也不提供流量控制或拥塞控制,它依靠RTCP提供这些服务。RTP属于应用层协议,在应用发送端,开发者必须编写用RTP封装分组的程序代码。RTP由IETF定义在 RFC 3550和3551中。
2.实时传输控制协议RTCP(RTP Control Ptotocol)
RTCP的主要功能是:服务质量的监视与反馈、媒体间的同步,以及多播组中成员的标识。在RTP会话期间,各参与者周期性地传送RTCP包。RTCP包中含有已发送的数据包的数量、丢失的数据包的数量、数据包到达的平均时间间隔等统计信息,因此,各参与者可以利用这些信息动态地改变传输速率,甚至改变有效载荷类型。RTP和RTCP配合使用,它们能以有效的反馈和最小的开销使传输效率最佳化,因而特别适合传送网上的实时数据。
三、RTP与RTCP的协议层次及封装
RTP位于传输层(通常是UDP)之上,应用程序之下,实时语音、视频数据经过模数转换和压缩编码处理后,先送给RTP封装成为RTP数据单元,RTP数据单元被封装为UDP数据报,然后再向下递交给IP封装为IP数据包。
RTP分组只包含RTP数据,而控制是由另一个配套协议RTCP提供。RTP在端口号1024到65535之间选择一个未使用的偶数UDP端口号,而在同一次会话中的RTCP则使用下一个奇数UDP端口号。
RTP通常和RTCP一起工作,在RTP会话期间,各参与者周期的发送RTCP消息。RTCP消息也被封装为UDP数据报进行传输。
四、RTP协议头信息
1
2
3
4
5
6
7
8
9
10
11
12
|
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
version (V): 2 bits
标明RTP版本号。协议初始版本为0,RFC3550中规定的版本号为2。
padding (P): 1 bit
如果该位被设置,则在该packet末尾包含了额外的附加信息,附加信息的最后一个字节表示额外附加信息的长度(包含该字节本身)。该字段之所以存在是因为一些加密机制需要固定长度的数据块,或者为了在一个底层协议数据单元中传输多个RTP packets。
extension (X): 1 bit
如果该位被设置,则在固定的头部后存在一个扩展头部,格式定义在RFC3550 5.3.1节。
CSRC count (CC): 4 bits
在固定头部后存在多少个CSRC标记。
marker (M): 1 bit
该位的功能依赖于profile的定义。profile可以改变该位的长度,但是要保持marker和payload type总长度不变(一共是8 bit)。
payload type (PT): 7 bits
标记着RTP packet所携带信息的类型,标准类型列出在RFC3551中。如果接收方不能识别该类型,必须忽略该packet。负载类型主要用来告诉接收端(或者播放器)传输的是哪种类型的媒体(例如G.729,H.264,MPEG-4等),这样接收端(或者播放器)才知 道了数据流的格式,才会调用适当的编解码器去解码或者播放,这就是负载类型的主要作用。
sequence number: 16 bits
序列号,每个RTP packet发送后该序列号加1,接收方可以根据该序列号重新组合数据包顺序,判断包是否丢失等操作。注意:它只是表示了包的先后顺序,它不能表示时间上的任何其它信息。
timestamp: 32 bits
时间戳。反映RTP packet所携带信息包中第一个字节的采样时间(详见下文)。
SSRC: 32 bits
数据源标识。在一个RTP Session其间每个数据流都应该有一个不同的SSRC。
CSRC list: 0 to 15 items, 每个源标识32 bits
贡献数据源标识。只有存在Mixer的时候才有效。如一个将多声道的语音流合并成一个单声道的语音流,在这里就列出原来每个声道的SSRC。
补充:
CSRC记数(CC) 表示CSRC标识的数目。CSRC标识紧跟在RTP固定头部之后,用来表示RTP数据报的来源,RTP协议允许在同一个会话中存在多个数据源,它们可以 通过RTP混合器合并为一个数据源。例如,可以产生一个CSRC列表来表示一个电话会议,该会议通过一个 RTP混合器将所有讲话者的语音数据组合为一个RTP数据源。
负载类型(PT) 标明RTP负载的格式,包括所采用的编码算法、采样频率、承载通道等。例如,类型2表明该RTP数据包中承载的是用ITU G.721算法编码的语音数据,采样频率为8000Hz,并且采用单声道。
序列号 用来为接收方提供探测数据丢失的方法,但如何处理丢失的数据则是应用程序自己的事情,RTP协议本身并不负责数据的重传。
时间戳 记录了负载中第一个字节的采样时间,接收方根据时间戳能够确定数据的到达是否受到了延迟抖动的影响,但具体如何来补偿延迟抖动则是应用程序自己的事情。
关于RTP的时间戳(timestamp):
时间戳单位:时间戳计算的单位不是秒,而是采用采样频率的倒数,这样做的目的是为了使时间戳单位更为精准。比如说一个音频的采样频率为8000Hz,那么我们可以把时间戳单位设为1/8000s。
时间戳增量:相邻两个RTP包之间的时间差(以时间戳单位为基准)
采样频率: 每秒钟抽取样本的次数,例如音频的采样率一般为8000Hz,即每秒采样8000次,产生8000个样本
帧率: 每秒传输或者显示帧数,例如25f/s时间戳反映了RTP分组中的数据的第一个字节的采样时刻。在一次会话开始时的时间戳初值也是随机选择的。即使是没有信号发送时,时间戳的数值也要随时间不 断的增加。接收端使用时间戳可准确知道应当在什么时间还原哪一个数据块,从而消除传输中的抖动。时间戳还可用来使视频应用中声音和图像同步。
在RTP协议中并没有规定时间戳的粒度,这取决于有效载荷的类型。因此RTP的时间戳又称为媒体时间戳,以强调这种时间戳的粒度取决于信号的类型。例如,对于8kHz采样的音频信号,若每隔20ms构成一个数据块,则一个数据块中包含有160个样本(0.02×8000=160)。因此每发送一个RTP分 组,其时间戳的值就增加160。
如果采样频率为90000Hz,则时间戳单位为1/90000,我们就假设1s钟被划分了90000个时间块,那么,如果每秒发送25帧,那么,每一个帧的发送占多少个时间块呢?当然是 90000/25 = 3600。因此,我们根据定义“时间戳增量是发送第二个RTP包相距发送第一个RTP包时的时间间隔”,故时间戳增量应该为3600。时间戳可用来使视频应用中声音和图像同步,为什么呢?
首先,时间戳就是一个值,用来反映某个数据块的产生(采集)时间点的, 后采集的数据块的时间戳肯定是大于先采集的数据块的。有了这样一个时间戳,就可以标记数据块的先后顺序。
第二,在实时流传输中,数据采集后立刻传递到RTP 模块进行发送,那么,其实,数据块的采集时间戳就直接作为RTP包的时间戳。
第三,如果用RTP来传输固定的文件,则这个时间戳 就是读文件的时间点,依次递增。这个不再我们当前的讨论范围内,暂时不考虑。
五、RTCP协议
RTCP协议处理机定义了五种类型的报文,它们完成接收、分析、产生和发送控制报文的功能。
1.SR(sender report)发送者报告分组:用来使发送端周期的向所有接收端用多播方式进行报告。内容包括:
该RTP流的SSRC;该RTP流中最新产生的RTP分组的时间戳和绝对时钟时间(或称墙上时间:wall clock time);该RTP流包含的分组数;该RTP流包含的字节数。
绝对时钟时间是必要的。因为RTP要求每一种媒体使用一个流。有了绝对时钟时间就可以进行图形和声音的同步。
2.RR(receiver report)接收者报告分组:用来使接收端周期性的向所有的点用多播方式进行报告。内容包括所接收到的RTP流的SSRC;该RTP流的分组丢失率;在该RTP流中的最后一个RTP分组的序号;分组到达时间间隔的抖动等。
发送RR分组有两个目的。第一,可以使所有的接收端和发送端了解当前网络的状态。
第二,可以使所有发送RTCP分组的站点自适应的调整自己发送RTCP分组的速率,RTCP分组的通信量不超过网络中的数据分组的通信量的5%,而接收端分组报告分组的通信量又应小于所有RTCP分组的通信量的75%。
3.SDES(source description items)源描述分组:给出会话中参加者的描述,包括参加者的规范名(CNAME)
4.BYE(indicates end of participation)分组:关闭一个数据流。
5.APP(application specific functions)分组:应用程序能够定义新的分组类型。
在RTCP中,还有两个比较重要的东西,一个64位的绝对时间戳和一个32位的相对时间戳。64 位时间戳也叫NTP时间戳,它的前 32位是从1900 年1 月1 日0 时开始到现在的以秒为单位的整数部分,后32位是此时间的小数部,因此,它可以肯定的表示了数据发送出去的绝对时间。32位的时间戳和RTP中的时间戳是一样的,没有任何区别。
六、媒体流的同步:流内同步和流间同步
多媒体通信同步方法,主要有时间戳同步法、同步标记法、多路复用同步法三种。下面主要讨论时间戳同步法,特别是RTP时间戳同步。内容包括RTP媒 体间同步的实现,为什么需要RTCP的NTP时间来实现媒体间同步?没有RTCP,能实现RTP媒体间的同步吗?
序列号字段是否可以作为流内的同步标识?序列号只表示了包发出的先后顺序,它表示不了任何时间上的其它概念,所以严格的说,序列号并不能作为流内的同步标志。但是,由于一般来说,包的发送时间都会有严格限制,比如音频包是每秒种发送30个数据包,也就是说,每个包间隔1000/30MS,而这个时间就可以 作为一个同步时间来播放。也就是说,按照序列号,每1000/30MS间隔播放一个数据包,这样也能保证同步,但是这时候请考虑丢包问题。
根据RTP规范,不同的RTP媒体流是分开传输的,且使用各自独立的时间戳进行同步。假设在一次视频点播中,传输两路RTP媒体流,一路视频,一路音频。根据视频帧时间戳,可以实现视频流内同步,这很好理解,通过视频帧时间戳可以计算出相邻视频帧的时间间隔,也就是视频帧之间的相对时间关系很容易通过时间戳来确定,按照这个间隔去呈现视频,就可以获得较好的效果。同理,音频流也可以实现自身的同步。那么音频和视频这两路媒体间如何实现同步呢?我们只使用音视频的RTP时间戳,看能否实现媒体间的同步。音视频的RTP时间戳的增长速率一般是不同的,但没关系,知道了具体的单位后,两者是可以通过单位换算联系起来的。如下:
1
2
3
4
5
6
7
8
|
视频帧时间戳单位:90000Hz,帧率:25fps
音频帧时间戳单位:8000Hz,帧率:50fps
A:音频帧 V:视频帧 A/V:音频帧和视频帧
音频帧时间戳:0 160 320 480 640 ...... 音频时间轴
视频帧时间戳:0 3600 7200 ...... 视频时间轴
A/V A A/V A A/V
绝对时间轴: 0 20 40 60 80 ...... 单位:ms
|
现在来看,这种方法好像可以实现同步,因为音视频被映射到同一个时间轴上了,音频和视频帧间的相对关系很清楚。慢着,RTP规范要求时间戳的初 始值应该是一个随机值,那么假设音频帧时间戳的初始值是随机值1234,视频帧时间戳的初始值是随机值5678,看起来应该是下面这样:
1
2
3
4
5
|
音频帧时间戳:1234 1394 1554 1714 1874 ...... 音频时间轴
视频帧时间戳:5678 9278 12878 ...... 视频时间轴
A/V A A/V A A/V
绝对时间轴: 0 20 40 60 80 ...... 单位:ms
|
这么做合适吗?我们把音频帧时间戳1234和视频帧时间戳5678对应到绝对时间轴的0上,我们这么做的理由是什么?你可能会说,因为那是第一个音频帧和第一个视频帧,所以可以对应到同一个点上,在第一幅图中我们就是这么做的,把音频帧时间戳0和视频帧时间戳0对应到绝对时间轴的0上。但是RTP规范并没有规定第一个视频帧的时间戳和第一个音频帧的时间戳必须或者应该对应到绝对时间轴的同一个点上,从整个RTP规范中不能直接得出这样的结论,也推导不出这样的结论。
我们上面两幅图所做的转换是不正确的,为什么呢?因为在做转换时,隐含了一个假设,我们想当然地认为这个假设是成立的,实际上它并不总是成立。这个假设就是第一个视频帧和第一个音频帧的时间戳应该对应到同一个点上,即无论它们时间戳是多少,都应该在同一时间播放。
仅仅使用RTP时间戳是无法实现媒体间同步的,根本的原因是音频时间轴和视频时间轴是完全独立的,通过音频帧和视频帧的时间戳,无法确定一个视频帧和一个音频帧的相对时间关系,也就是无法把它们都准确定位在绝对时间轴上。
要实现RTP媒体间同步,需要借助于RTCP,在RTCP的SR包中,包含有<ntp时间,rtp时间戳>对,音频帧RTP时间戳和视频帧RTP时间戳通过<ntp时间,rtp时间戳>对,都可以准确定位到绝对时间轴NTP上,音频帧和视频帧的相对时间关系就可以确定下来 了。
上面提到,我们的那个隐含的假设并不总是成立,那就是说它有成立的时候。那是不是说当它成立时,我们就可以不用RTCP来做媒体间同步了?答案是,基本上可以这么认为。例如,对于RTP实时流,在发送端媒体间就同步的很好,在接收端只需做少许处理,不需要RTCP,就可以实现媒体间同步。当然,这只是少数例外。因为RTP规范并不包括这个假设,所以我们还是按照RTP规范来做吧。