发布日期:2024-09-27 22:19 点击次数:153
一、流媒体简介西西人軆艺术网
跟着Internet的日益晋升,在集中上传输的数据已经不再局限于翰墨和图形,而是逐渐向声息和视频等多媒身景色过渡。当今在集中上传输音频/视频(Audio/Video,简称A/V)等多媒体文献时,基本上只须下载和流式传输两种弃取。通常说来,A/V文献占据的存储空间都相比大,在带宽受限的集中环境中下载可能要耗尽数分钟致使数小时,是以这种处理要领的延伸很大。如果换用流式传输的话,声息、影像、动画等多媒体文献将由专门的流媒体做事器庄重向用户连气儿、实时地发送,这么用户可以不必比及通盘文献全部属载完了,而只需要经过几秒钟的启动延时就可以了,当这些多媒体数据在客户机上播放时,文献的剩余部分将不时从流媒体做事器下载。
流(Streaming)是频年在Internet上出现的新成见,其界说超越等闲,主若是指通过集中传输多媒体数据的本事总称。流媒体包含广义和狭义两种内涵:广义上的流媒体指的是使音频和视频酿成褂讪和连气儿的传输流和回放流的一系列本事、要领和合同的总称,即流媒体本事;狭义上的流媒体是相关于传统的下载-回放神色而言的,指的是一种从Internet上获取音频和视频等多媒体数据的新要领,它粗略赈济多媒体数据流的实时传输和实时播放。通过时骗流媒体本事,做事器粗略向客户机发送褂讪和连气儿的多媒体数据流,客户机在摄取数据的同期以一个褂讪的速率回放,而毋庸等数据全部属载完之后再进行回放。
由于受集中带宽、缠绵机处理能力和合同表率等方面的限定,要念念从Internet高下载宽广的音频和视频数据,不管从下载时辰和存储空间上来讲都是不太本质的,而流媒体本事的出现则很好地惩处了这一壅塞。当今终了流媒体传输主要有两种要领:限定流(progressive streaming)传输和实时流(realtime streaming)传输,它们离别适合于不同的应用所在。
限定流传输
限定流传输选拔限定下载的神色进行传输,鄙人载的同期用户可以在线回放多媒体数据,但给定时刻只可不雅看已经下载的部分,弗成跳到尚未下载的部分,也弗成在传输时期字据集中气象对下载速率进行调理。由于圭表的HTTP做事器就可以发送这种景色的流媒体,而不需要其他特殊合同的赈济,因此也通常被称作HTTP流式传输。限定流式传输相比适合于高质地的多媒体片断,如片头、片尾或者告白等。
实时流传输
实时流式传输保证媒体信号带宽粗略与刻下集中气象相匹配,从而使得流媒体数据老是被实时地传送,因此超越适合于现场事件。实时流传输赈济立时打听,即用户可以通过快进或者后退操作来不雅看前边或者背面的内容。从表面上讲,实时流媒体如故播放就不会停顿,但事实上仍有可能发生周期性的暂停阵势,尤其是在集中气象恶化时更是如斯。与限定流传输不同的是,实时流传输需要用到特定的流媒体做事器,而且还需要特定集中合同的赈济。
回页首
二、流媒体合同
实时传输合同(Real-time Transport Protocol,PRT)是在Internet上处理多媒体数据流的一种集中合同,利用它粗略在一双一(unicast,单播)或者一双多(multicast,多播)的集中环境中终了传流媒体数据的实时传输。RTP通常使用UDP来进行多媒体数据的传输,但如果需要的话可以使用TCP或者ATM等其它合同,通盘RTP合同由两个密切关联的部分构成:RTP数据合同和RTP适度合同。实时流合同(Real Time Streaming Protocol,RTSP)最早由Real Networks和Netscape公司共同淡薄,它位于RTP和RTCP之上,其办法是但愿通过IP集中有用地传输多媒体数据。
2.1 RTP数据合同
RTP数据合同庄重对流媒体数据进行封包并终了媒体流的实时传输,每一个RTP数据报都由头部(Header)和负载(Payload)两个部分构成,其中头部前12个字节的含义是固定的,而负载则可以是音频或者视频数据。RTP数据报的头部景色如图1所示:
图1 RTP头部景色
其中相比遑急的几个域过甚兴味如下:
CSRC记数(CC) 暗意CSRC标记的数量。CSRC标记紧跟在RTP固定头部之后,用来暗意RTP数据报的起首,RTP合同允许在归拢个会话中存在多个数据源,它们可以通过RTP羼杂器合并为一个数据源。举例,可以产生一个CSRC列表来暗意一个电话会议,该会议通过一个RTP羼杂器将统共讲话者的语音数据组合为一个RTP数据源。 负载类型(PT) 表明RTP负载的景色,包括所选拔的编码算法、采样频率、承载通说念等。举例,类型2表明该RTP数据包中承载的是用ITU G.721算法编码的语音数据,采样频率为8000Hz,而且选拔单声说念。 序列号 用来为摄取方提供探伤数据丢失的要领,但怎样处理丢失的数据则是应用设施我方的事情,RTP合同本人并不庄重数据的重传。 时辰戳 纪录了负载中第一个字节的采样时辰,摄取方粗略时辰戳粗略细目数据的到达是否受到了延伸抖动的影响,但具体怎样来赔偿延伸抖动则是应用设施我方的事情。
从RTP数据报的景色不丢丑出,它包含了传输媒体的类型、景色、序列号、时辰戳以及是否有附加数据等信息,这些都为实时的流媒体传输提供了相应的基础。RTP合同的办法是提供实时数据(如交互式的音频和视频)的端到端传输做事,因此在RTP中莫得畅通的成见,它可以成立在底层的面向畅通或面向非畅通的传输合同之上;RTP也不依赖于超越的集中地址景色,而只是只需要底层传输合同赈济组帧(Framing)和分段(Segmentation)就饱和了;另外RTP本人还不提供任何可靠性机制,这些都要由传输合同或者应用设施我方来保证。在典型的应用所在下,RTP一般是在传输合同之上手脚应用设施的一部分加以终了的,如图2所示:
图2 RTP与多样集中合同的关系
2.2 RTCP适度合同
RTCP适度合同需要与RTP数据合同一皆合营使用,当应用设施启动一个RTP会话时将同期占用两个端口,离别供RTP和RTCP使用。RTP本人并弗成为按序传输数据包提供可靠的保证,也不提供流量适度和拥塞适度,这些都由RTCP来庄重完成。通常RTCP会选拔与RTP疏导的分发机制,向会话中的统共成员周期性地发送适度信息,应用设施通过摄取这些数据,从中获取会话参与者的关联府上,以及集中气象、分组丢失概率等响应信息,从而粗略对做事质地进行适度或者对集中气象进行会诊。
RTCP合同的功能是通过不同的RTCP数据报来终了的,主要有如下几种类型:
SR 发送端回报,所谓发送端是指发出RTP数据报的应用设施或者结尾,发送端同期也可以是摄取端。 RR 摄取端回报,所谓摄取端是指仅摄取但不发送RTP数据报的应用设施或者结尾。 SDES 源神情,主邀功能是手脚会话成员联系标记信息的载体,如用户名、邮件地址、电话号码等,此外还具有向会话成员传达会话适度信息的功能。 BYE 告知离开,主邀功能是结合某一个或者几个源不再有用,即告知会话中的其他成员我方将退出会话。 APP 由应用设施我方界说,惩处了RTCP的膨胀性问题,而且为合同的终了者提供了很大的天真性。
RTCP数据报佩带有做事质地监控的必要信息,粗略对做事质地进行为态的调理,并粗略对集中拥塞进行有用的适度。由于RTCP数据报选拔的是多播神色,因此会话中的统共成员都可以通过RTCP数据攻击返的适度信息,来了解其他参与者确刻下情况。
在一个典型的应用所在下,发送媒体流的应用设施将周期性地产生发送端回报SR,该RTCP数据报含有不同媒体流间的同步信息,以及已经发送的数据报和字节的计数,摄取端字据这些信息可以揣测出实质的数据传输速率。另一方面,摄取端会向统共已知的发送端发送摄取端回报RR,该RTCP数据报含有已摄取数据报的最大序列号、丢失的数据报数量、延时抖动和时辰戳等遑急信息,发送端应用字据这些信息可以揣测出往来时延,而且可以字据数据报丢失概率和时延抖动情况动态调剃头送速率,以改善集中拥塞气象,或者字据集中气象平滑地调理当用设施的做事质地。
2.3 RTSP实时流合同
手脚一个应用层合同,RTSP提供了一个可供膨胀的框架,它的兴味在于使得实时流媒体数据的受控和点播变得可能。总的说来,RTSP是一个流媒体暗意合同,主要用来适度具有实时特质的数据发送,但它本人并不传输数据,而是必须依赖于基层传输合同所提供的某些做事。RTSP可以对流媒体提供诸如播放、暂停、快进等操作,它庄重界说具体的适度音问、操作要领、状态码等,此外还神情了与RTP间的交互操作。
RTSP在制定时较多地参考了HTTP/1.1合同,致使许多神情与HTTP/1.1实足疏导。RTSP之是以成心使用与HTTP/1.1访佛的语法和操作,在很猛进程上是为了兼容现存的Web基础结构,正因如斯,HTTP/1.1的膨胀机制大都可以顺利引入到RTSP中。
由RTSP适度的媒体流搭伙可以用暗意神情(Presentation Description)来界说,所谓暗意是指流媒体做事器提供给客户机的一个或者多个媒体流的搭伙,而暗意神情则包含了一个暗意中各个媒体流的关联信息,如数据编码/解码算法、集中地址、媒体流的内容等。
诚然RTSP做事器相似也使用标记符来区别每一流畅通会话(Session),但RTSP畅通并莫得被绑定到传输层畅通(如TCP等),也便是说在通盘RTSP畅通时期,RTSP用户可绽开或者关闭多个对RTSP做事器的可靠传输畅通以发出RTSP 央求。此外,RTSP畅通也可以基于面向无畅通的传输合同(如UDP等)。
RTSP合同当今赈济以下操作:
检索媒体 允许用户通过HTTP或者其它要领向媒体做事器提交一个暗意神情。如暗意是组播的,则暗意神情就包含用于该媒体流的组播地址和端标语;如果暗意是单播的,为了安全在暗意神情中应该只提供办法地址。 邀请加入 媒体做事器可以被邀请插足正在进行的会议,或者在暗意中回放媒体,或者在暗意中录制全部媒体或其子集,超越适合于分散式教悔。 添加媒体 告知用户新加入的可利用媒体流,这对现场讲座来讲显得尤其有用。与HTTP/1.1访佛,RTSP央求也可以交由代理、通说念或者缓存来进行处理。
回页首
三、流媒体编程
RTP是当今惩处流媒体实时传输问题的最佳办法,如果需要在Linux平台上进行实时流媒体编程,可以商酌使用一些开放源代码的RTP库,如LIBRTP、JRTPLIB等。JRTPLIB是一个面向对象的RTP库,它实足衔命RFC 1889遐想,在许多所在下是一个超越可以的弃取,底下就以JRTPLIB为例,诠释如安在Linux平台上期骗RTP合同进行实时流媒体编程。
3.1 环境搭建
JRTPLIB是一个用C++讲话终了的RTP库,当今已经可以运行在Windows、Linux、FreeBSD、Solaris、Unix和VxWorks等多种操作系统上。要为Linux 系统装配JRTPLIB,当先从JRTPLIB的网站()下载最新的源码包,此处使用的是jrtplib-2.7b.tar.bz2。假定下载后的源码包保存在/usr/local/src目次下,实施底下的敕令可以对其进行解压缩:
[root@linuxgam src]# bzip2 -dc jrtplib-2.7b.tar.bz2 | tar xvf -
接下去需要对JRTPLIB进行建树和编译:
[root@linuxgam src]# cd jrtplib-2.7 [root@linuxgam jrtplib-2.7b]# ./configure [root@linuxgam jrtplib-2.7b]# make
终末再实施如下敕令就可以完成JRTPLIB的装配:
[root@linuxgam jrtplib-2.7b]# make install
3.2 运升沉
在使用JRTPLIB进行实时流媒体数据传输之前,当先应该生成RTPSession类的一个实例来暗意这次RTP会话,然后调用Create()要领来对其进走时升沉操作。RTPSession类的Create()要领只须一个参数,用来指明这次RTP会话所选拔的端标语。清单1给出了一个最毛糙的运升沉框架,它只是完成了RTP会话的运升沉使命,还不具备任何实质的功能。
代码清单1:initial.cpp
#include "rtpsession.h" int main(void) { RTPSession sess; sess.Create(5000); return 0; }
如果RTP会话创建流程失败,Create()要领将会复返一个负数,通过它诚然可以很容易地判断出函数调用究竟是成功的照旧失败的,但却很难赫然出错的原因到底什么。JRTPLIB选拔了搭伙的特殊处理机制,它提供的统共函数如果复返负数就表明出现了某种景色的特殊,而具体的出错信息则可以通过调用RTPGetErrorString()函数得到。RTPGetErrorString()函数将特殊代码手脚参数传入,然后复返该特殊代码所对应的特殊信息。清单2给出了一个愈加完好意思的运升沉框架,它可以对RTP会话运升沉流程中所产生的特殊进行更好的处理:
代码清单2:framework.cpp
#include <stdio.h> #include "rtpsession.h" int main(void) { RTPSession sess; int status; char* msg; sess.Create(6000); msg = RTPGetErrorString(status); printf("Error String: %s\\n", msg); return 0; }
树立适应的时戳单位,是RTP会话运升沉流程所要进行的另外一项遑急使命,这是通过调用RTPSession类的SetTimestampUnit()要领来终了的,该要领相似也只须一个参数,暗意的是以秒为单位的时戳单位。举例,当使用RTP会话传输8000Hz采样的音频数据时,由于时戳每秒钟将递加8000,是以时戳单位相应地应该被树立成1/8000:
sess.SetTimestampUnit(1.0/8000.0);
3.3 数据发送
当RTP会话成功成立起来之后,接下去就可以脱手进行流媒体数据的实时传输了。当先需要树立好数据发送的方针地址,RTP合同允许归拢会话存在多个方针地址,这可以通过调用RTPSession类的AddDestination()、DeleteDestination()和ClearDestinations()要领来完成。举例,底下的语句暗意的是让RTP会话将数据发送到土产货主机的6000端口:
濑亚美莉喷奶番号unsigned long addr = ntohl(inet_addr("127.0.0.1")); sess.AddDestination(addr, 6000);
方针地址全部指定之后,接着就可以调用RTPSession类的SendPacket()要领,向统共的方针地址发送流媒体数据。SendPacket()是RTPSession类提供的一个重载函数,它具有下列多种景色:
int SendPacket(void *data,int len) int SendPacket(void *data,int len,unsigned char pt,bool mark,unsigned long timestampinc) int SendPacket(void *data,int len,unsigned short hdrextID,void *hdrextdata,int numhdrextwords) int SendPacket(void *data,int len,unsigned char pt,bool mark,unsigned long timestampinc, unsigned short hdrextID,void *hdrextdata,int numhdrextwords)
SendPacket()最典型的用法是访佛于底下的语句,其中第一个参数是要被发送的数据,而第二个参数则指明将要发送数据的长度,再往后规律是RTP负载类型、标记和时戳增量。
sess.SendPacket(buffer, 5, 0, false, 10);
关于归拢个RTP会话来讲,负载类型、标记和时戳增量通常来讲都是疏导的,JRTPLIB允许将它们树立为会话的默许参数,这是通过调用RTPSession类的SetDefaultPayloadType()、SetDefaultMark()和SetDefaultTimeStampIncrement()要领来完成的。为RTP会话树立这些默许参数的平正是可以简化数据的发送,举例,如果为RTP会话树立了默许参数:
sess.SetDefaultPayloadType(0); sess.SetDefaultMark(false); sess.SetDefaultTimeStampIncrement(10);
之后在进行数据发送时只需指明要发送的数据过甚长度就可以了:
sess.SendPacket(buffer, 5);
3.4 数据摄取
关于流媒体数据的摄取端,当先需要调用RTPSession类的PollData()要领来摄取发送过来的RTP或者RTCP数据报。由于归拢个RTP会话中允许有多个参与者(源),你既可以通过调用RTPSession类的GotoFirstSource()和GotoNextSource()要领来遍历统共的源,也可以通过调用RTPSession类的GotoFirstSourceWithData()和GotoNextSourceWithData()要领来遍历那些佩带特地据的源。在从RTP会话中检测出有用的数据源之后,接下去就可以调用RTPSession类的GetNextPacket()要领从中抽取RTP数据报,当摄取到的RTP数据报处理完之后,一定要牢记实时开释。底下的代码示范了该怎样对摄取到的RTP数据报进行处理:
if (sess.GotoFirstSourceWithData()) { do { RTPPacket *pack; pack = sess.GetNextPacket(); // 处理摄取到的数据 delete pack; } while (sess.GotoNextSourceWithData()); }
JRTPLIB为RTP数据报界说了三种摄取模式,其中每种摄取模式都具体法令了哪些到达的RTP数据报将会被经受,而哪些到达的RTP数据报将会被拒却。通过调用RTPSession类的SetReceiveMode()要领可以树立下列这些摄取模式:
RECEIVEMODE_ALL 缺省的摄取模式,统共到达的RTP数据报都将被经受; RECEIVEMODE_IGNORESOME 除了某些特定的发送者以外,统共到达的RTP数据报都将被经受,而被拒却的发送者列表可以通过调用AddToIgnoreList()、DeleteFromIgnoreList()和ClearIgnoreList()要领来进行树立; RECEIVEMODE_ACCEPTSOME 除了某些特定的发送者以外,统共到达的RTP数据报都将被拒却,而被经受的发送者列表可以通过调用AddToAcceptList ()、DeleteFromAcceptList和ClearAcceptList ()要领来进行树立。3.5 适度信息
JRTPLIB是一个高度封装后的RTP库,设施员在使用它时许多时候并毋庸祥和RTCP数据报是怎样被发送和摄取的,因为这些都可以由JRTPLIB我方来完成。只须PollData()或者SendPacket()要领被成功调用,JRTPLIB就粗略自动对到达的RTCP数据报进行处理,而且还会在需要的时候发送RTCP数据报,从而粗略确保通盘RTP会话流程的正确性。
而另一方面,通过调用RTPSession类提供的SetLocalName()、SetLocalEMail()、SetLocalLocation()、SetLocalPhone()、SetLocalTool()和SetLocalNote()要领,JRTPLIB又允许设施员对RTP会话的适度信息进行树立。统共这些要领在调用时都带有两个参数,其中第一个参数是一个char型的指针,指向将要被树立的数据;而第二个参数则是一个int型的数值,表明该数据中的前边若干个字符将会被使用。举例底下的语句可以被用来树立适度信息中的电子邮件地址:
sess.SetLocalEMail("xiaowp@linuxgam.com",19);
在RTP会话流程中,不是统共的适度信息都需要被发送,通过调用RTPSession类提供的EnableSendName()、EnableSendEMail()、EnableSendLocation()、EnableSendPhone()、EnableSendTool()和EnableSendNote()要领,可合计刻下RTP会话弃取将被发送的适度信息。
3.6 实质应用
终末通过一个毛糙的流媒体发送-摄取实例,先容怎样利用JRTPLIB来进行实时流媒体的编程。清单3给出了数据发送端的完好意思代码,它庄重向用户指定的IP地址和端口,不停地发送RTP数据包:
代码清单3:sender.cpp
#include <stdio.h> #include <string.h> #include "rtpsession.h" // 特殊处理函数 void checkerror(int err) { if (err < 0) { char* errstr = RTPGetErrorString(err); printf("Error:%s\\n", errstr); exit(-1); } } int main(int argc, char** argv) { RTPSession sess; unsigned long destip; int destport; int portbase = 6000; int status, index; char buffer[128]; if (argc != 3) { printf("Usage: ./sender destip destport\\n"); return -1; } // 取得摄取端的IP地址和端标语 destip = inet_addr(argv[1]); if (destip == INADDR_NONE) { printf("Bad IP address specified.\\n"); return -1; } destip = ntohl(destip); destport = atoi(argv[2]); // 创建RTP会话 status = sess.Create(portbase); checkerror(status); // 指定RTP数据摄取端 status = sess.AddDestination(destip, destport); checkerror(status); // 树立RTP会话默许参数 sess.SetDefaultPayloadType(0); sess.SetDefaultMark(false); sess.SetDefaultTimeStampIncrement(10); // 发送流媒体数据 index = 1; do { sprintf(buffer, "%d: RTP packet", index ++); sess.SendPacket(buffer, strlen(buffer)); printf("Send packet !\\n"); } while(1); return 0; }
清单4则给出了数据摄取端的完好意思代码,它庄重从指定的端口不停地读取RTP数据包:
代码清单4:receiver.cpp
#include <stdio.h> #include "rtpsession.h" #include "rtppacket.h" // 特殊处理函数 void checkerror(int err) { if (err < 0) { char* errstr = RTPGetErrorString(err); printf("Error:%s\\n", errstr); exit(-1); } } int main(int argc, char** argv) { RTPSession sess; int localport; int status; if (argc != 2) { printf("Usage: ./sender localport\\n"); return -1; } // 取得用户指定的端标语 localport = atoi(argv[1]); // 创建RTP会话 status = sess.Create(localport); checkerror(status); do { // 经受RTP数据 status = sess.PollData(); // 检索RTP数据源 if (sess.GotoFirstSourceWithData()) { do { RTPPacket* packet; // 获取RTP数据报 while ((packet = sess.GetNextPacket()) != NULL) { printf("Got packet !\\n"); // 删除RTP数据报 delete packet; } } while (sess.GotoNextSourceWithData()); } } while(1); return 0; }
本文源码 下载
回页首
四、小结
跟着多媒体数据在Internet上所承担的作用变得越来越遑急,需要实时传输音频和视频等多媒体数据的所在也将变得越来越多,如IP电话、视频点播、在线会议等。RTP是用来在Internet上进行实时流媒体传输的一种合同,当今已经被等闲地应用在多样所在,JRTPLIB是一个面向对象的RTP封装库,利用它可以很粗略地完成Linux平台上的实时流媒体编程。
回页首
参考府上 西西人軆艺术网
1. 在JRTPLIB的网站上,可以下载到JRTPLIB最新的源码包,而且还能找到一些与RTP关联的资源。 2. 顾淑珍等编订,宽带升值做事斥地实例,北京:机械工业出书社,2002 3. 黄永峰等编订,IP集中多媒体通讯本事,北京:东说念主民邮电出书社,2003