青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

大龍的博客

常用鏈接

統(tǒng)計

最新評論

流媒體相關(guān)知識介紹 及其 RTP 應(yīng)用 (轉(zhuǎn)) thanks

一、流媒體簡介

隨著Internet的日益普及,在網(wǎng)絡(luò)上傳輸?shù)臄?shù)據(jù)已經(jīng)不再局限于文字和圖形,而是逐漸向聲音和視頻等多媒體格式過渡。目前在網(wǎng)絡(luò)上傳輸音頻/視頻(Audio/Video,簡稱A/V)等多媒體文件時,基本上只有下載和流式傳輸兩種選擇。通常說來,A/V文件占據(jù)的存儲空間都比較大,在帶寬受限的網(wǎng)絡(luò)環(huán)境中下載可能要耗費數(shù)分鐘甚至數(shù)小時,所以這種處理方法的延遲很大。如果換用流式傳輸?shù)脑挘曇簟⒂跋瘛赢嫷榷嗝襟w文件將由專門的流媒體服務(wù)器負責向用戶連續(xù)、實時地發(fā)送,這樣用戶可以不必等到整個文件全部下載完畢,而只需要經(jīng)過幾秒鐘的啟動延時就可以了,當這些多媒體數(shù)據(jù)在客戶機上播放時,文件的剩余部分將繼續(xù)從流媒體服務(wù)器下載。

流(Streaming)是近年在Internet上出現(xiàn)的新概念,其定義非常廣泛,主要是指通過網(wǎng)絡(luò)傳輸多媒體數(shù)據(jù)的技術(shù)總稱。流媒體包含廣義和狹義兩種內(nèi)涵:廣義上的流媒體指的是使音頻和視頻形成穩(wěn)定和連續(xù)的傳輸流和回放流的一系列技術(shù)、方法和協(xié)議的總稱,即流媒體技術(shù);狹義上的流媒體是相對于傳統(tǒng)的下載-回放方式而言的,指的是一種從Internet上獲取音頻和視頻等多媒體數(shù)據(jù)的新方法,它能夠支持多媒體數(shù)據(jù)流的實時傳輸和實時播放。通過運用流媒體技術(shù),服務(wù)器能夠向客戶機發(fā)送穩(wěn)定和連續(xù)的多媒體數(shù)據(jù)流,客戶機在接收數(shù)據(jù)的同時以一個穩(wěn)定的速率回放,而不用等數(shù)據(jù)全部下載完之后再進行回放。

由于受網(wǎng)絡(luò)帶寬、計算機處理能力和協(xié)議規(guī)范等方面的限制,要想從Internet上下載大量的音頻和視頻數(shù)據(jù),無論從下載時間和存儲空間上來講都是不太現(xiàn)實的,而流媒體技術(shù)的出現(xiàn)則很好地解決了這一難題。目前實現(xiàn)流媒體傳輸主要有兩種方法:順序流(progressive streaming)傳輸和實時流(realtime streaming)傳輸,它們分別適合于不同的應(yīng)用場合。

順序流傳輸

順序流傳輸采用順序下載的方式進行傳輸,在下載的同時用戶可以在線回放多媒體數(shù)據(jù),但給定時刻只能觀看已經(jīng)下載的部分,不能跳到尚未下載的部分,也不能在傳輸期間根據(jù)網(wǎng)絡(luò)狀況對下載速度進行調(diào)整。由于標準的HTTP服務(wù)器就可以發(fā)送這種形式的流媒體,而不需要其他特殊協(xié)議的支持,因此也常常被稱作HTTP流式傳輸。順序流式傳輸比較適合于高質(zhì)量的多媒體片段,如片頭、片尾或者廣告等。

實時流傳輸

實時流式傳輸保證媒體信號帶寬能夠與當前網(wǎng)絡(luò)狀況相匹配,從而使得流媒體數(shù)據(jù)總是被實時地傳送,因此特別適合于現(xiàn)場事件。實時流傳輸支持隨機訪問,即用戶可以通過快進或者后退操作來觀看前面或者后面的內(nèi)容。從理論上講,實時流媒體一經(jīng)播放就不會停頓,但事實上仍有可能發(fā)生周期性的暫停現(xiàn)象,尤其是在網(wǎng)絡(luò)狀況惡化時更是如此。與順序流傳輸不同的是,實時流傳輸需要用到特定的流媒體服務(wù)器,而且還需要特定網(wǎng)絡(luò)協(xié)議的支持。





回頁首


二、流媒體協(xié)議

實時傳輸協(xié)議(Real-time Transport Protocol,PRT)是在Internet上處理多媒體數(shù)據(jù)流的一種網(wǎng)絡(luò)協(xié)議,利用它能夠在一對一(unicast,單播)或者一對多(multicast,多播)的網(wǎng)絡(luò)環(huán)境中實現(xiàn)傳流媒體數(shù)據(jù)的實時傳輸。RTP通常使用UDP來進行多媒體數(shù)據(jù)的傳輸,但如果需要的話可以使用TCP或者ATM等其它協(xié)議,整個RTP協(xié)議由兩個密切相關(guān)的部分組成:RTP數(shù)據(jù)協(xié)議和RTP控制協(xié)議。實時流協(xié)議(Real Time Streaming Protocol,RTSP)最早由Real Networks和Netscape公司共同提出,它位于RTP和RTCP之上,其目的是希望通過IP網(wǎng)絡(luò)有效地傳輸多媒體數(shù)據(jù)。

2.1 RTP數(shù)據(jù)協(xié)議

RTP數(shù)據(jù)協(xié)議負責對流媒體數(shù)據(jù)進行封包并實現(xiàn)媒體流的實時傳輸,每一個RTP數(shù)據(jù)報都由頭部(Header)和負載(Payload)兩個部分組成,其中頭部前12個字節(jié)的含義是固定的,而負載則可以是音頻或者視頻數(shù)據(jù)。RTP數(shù)據(jù)報的頭部格式如圖1所示:


圖1 RTP頭部格式

其中比較重要的幾個域及其意義如下:

  • CSRC記數(shù)(CC)  表示CSRC標識的數(shù)目。CSRC標識緊跟在RTP固定頭部之后,用來表示RTP數(shù)據(jù)報的來源,RTP協(xié)議允許在同一個會話中存在多個數(shù)據(jù)源,它們可以通過RTP混合器合并為一個數(shù)據(jù)源。例如,可以產(chǎn)生一個CSRC列表來表示一個電話會議,該會議通過一個RTP混合器將所有講話者的語音數(shù)據(jù)組合為一個RTP數(shù)據(jù)源。
  • 負載類型(PT)  標明RTP負載的格式,包括所采用的編碼算法、采樣頻率、承載通道等。例如,類型2表明該RTP數(shù)據(jù)包中承載的是用ITU G.721算法編碼的語音數(shù)據(jù),采樣頻率為8000Hz,并且采用單聲道。
  • 序列號  用來為接收方提供探測數(shù)據(jù)丟失的方法,但如何處理丟失的數(shù)據(jù)則是應(yīng)用程序自己的事情,RTP協(xié)議本身并不負責數(shù)據(jù)的重傳。
  • 時間戳  記錄了負載中第一個字節(jié)的采樣時間,接收方能夠時間戳能夠確定數(shù)據(jù)的到達是否受到了延遲抖動的影響,但具體如何來補償延遲抖動則是應(yīng)用程序自己的事情。

 

從RTP數(shù)據(jù)報的格式不難看出,它包含了傳輸媒體的類型、格式、序列號、時間戳以及是否有附加數(shù)據(jù)等信息,這些都為實時的流媒體傳輸提供了相應(yīng)的基礎(chǔ)。RTP協(xié)議的目的是提供實時數(shù)據(jù)(如交互式的音頻和視頻)的端到端傳輸服務(wù),因此在RTP中沒有連接的概念,它可以建立在底層的面向連接或面向非連接的傳輸協(xié)議之上;RTP也不依賴于特別的網(wǎng)絡(luò)地址格式,而僅僅只需要底層傳輸協(xié)議支持組幀(Framing)和分段(Segmentation)就足夠了;另外RTP本身還不提供任何可靠性機制,這些都要由傳輸協(xié)議或者應(yīng)用程序自己來保證。在典型的應(yīng)用場合下,RTP一般是在傳輸協(xié)議之上作為應(yīng)用程序的一部分加以實現(xiàn)的,如圖2所示:


圖2 RTP與各種網(wǎng)絡(luò)協(xié)議的關(guān)系

2.2 RTCP控制協(xié)議

RTCP控制協(xié)議需要與RTP數(shù)據(jù)協(xié)議一起配合使用,當應(yīng)用程序啟動一個RTP會話時將同時占用兩個端口,分別供RTP和RTCP使用。RTP本身并不能為按序傳輸數(shù)據(jù)包提供可靠的保證,也不提供流量控制和擁塞控制,這些都由RTCP來負責完成。通常RTCP會采用與RTP相同的分發(fā)機制,向會話中的所有成員周期性地發(fā)送控制信息,應(yīng)用程序通過接收這些數(shù)據(jù),從中獲取會話參與者的相關(guān)資料,以及網(wǎng)絡(luò)狀況、分組丟失概率等反饋信息,從而能夠?qū)Ψ?wù)質(zhì)量進行控制或者對網(wǎng)絡(luò)狀況進行診斷。

RTCP協(xié)議的功能是通過不同的RTCP數(shù)據(jù)報來實現(xiàn)的,主要有如下幾種類型:

  • SR  發(fā)送端報告,所謂發(fā)送端是指發(fā)出RTP數(shù)據(jù)報的應(yīng)用程序或者終端,發(fā)送端同時也可以是接收端。
  • RR  接收端報告,所謂接收端是指僅接收但不發(fā)送RTP數(shù)據(jù)報的應(yīng)用程序或者終端。
  • SDES  源描述,主要功能是作為會話成員有關(guān)標識信息的載體,如用戶名、郵件地址、電話號碼等,此外還具有向會話成員傳達會話控制信息的功能。
  • BYE  通知離開,主要功能是指示某一個或者幾個源不再有效,即通知會話中的其他成員自己將退出會話。
  • APP  由應(yīng)用程序自己定義,解決了RTCP的擴展性問題,并且為協(xié)議的實現(xiàn)者提供了很大的靈活性。

 

RTCP數(shù)據(jù)報攜帶有服務(wù)質(zhì)量監(jiān)控的必要信息,能夠?qū)Ψ?wù)質(zhì)量進行動態(tài)的調(diào)整,并能夠?qū)W(wǎng)絡(luò)擁塞進行有效的控制。由于RTCP數(shù)據(jù)報采用的是多播方式,因此會話中的所有成員都可以通過RTCP數(shù)據(jù)報返回的控制信息,來了解其他參與者的當前情況。

在一個典型的應(yīng)用場合下,發(fā)送媒體流的應(yīng)用程序?qū)⒅芷谛缘禺a(chǎn)生發(fā)送端報告SR,該RTCP數(shù)據(jù)報含有不同媒體流間的同步信息,以及已經(jīng)發(fā)送的數(shù)據(jù)報和字節(jié)的計數(shù),接收端根據(jù)這些信息可以估計出實際的數(shù)據(jù)傳輸速率。另一方面,接收端會向所有已知的發(fā)送端發(fā)送接收端報告RR,該RTCP數(shù)據(jù)報含有已接收數(shù)據(jù)報的最大序列號、丟失的數(shù)據(jù)報數(shù)目、延時抖動和時間戳等重要信息,發(fā)送端應(yīng)用根據(jù)這些信息可以估計出往返時延,并且可以根據(jù)數(shù)據(jù)報丟失概率和時延抖動情況動態(tài)調(diào)整發(fā)送速率,以改善網(wǎng)絡(luò)擁塞狀況,或者根據(jù)網(wǎng)絡(luò)狀況平滑地調(diào)整應(yīng)用程序的服務(wù)質(zhì)量。

2.3 RTSP實時流協(xié)議

作為一個應(yīng)用層協(xié)議,RTSP提供了一個可供擴展的框架,它的意義在于使得實時流媒體數(shù)據(jù)的受控和點播變得可能。總的說來,RTSP是一個流媒體表示協(xié)議,主要用來控制具有實時特性的數(shù)據(jù)發(fā)送,但它本身并不傳輸數(shù)據(jù),而是必須依賴于下層傳輸協(xié)議所提供的某些服務(wù)。RTSP可以對流媒體提供諸如播放、暫停、快進等操作,它負責定義具體的控制消息、操作方法、狀態(tài)碼等,此外還描述了與RTP間的交互操作。

RTSP在制定時較多地參考了HTTP/1.1協(xié)議,甚至許多描述與HTTP/1.1完全相同。RTSP之所以特意使用與HTTP/1.1類似的語法和操作,在很大程度上是為了兼容現(xiàn)有的Web基礎(chǔ)結(jié)構(gòu),正因如此,HTTP/1.1的擴展機制大都可以直接引入到RTSP中。

由RTSP控制的媒體流集合可以用表示描述(Presentation Description)來定義,所謂表示是指流媒體服務(wù)器提供給客戶機的一個或者多個媒體流的集合,而表示描述則包含了一個表示中各個媒體流的相關(guān)信息,如數(shù)據(jù)編碼/解碼算法、網(wǎng)絡(luò)地址、媒體流的內(nèi)容等。

雖然RTSP服務(wù)器同樣也使用標識符來區(qū)別每一流連接會話(Session),但RTSP連接并沒有被綁定到傳輸層連接(如TCP等),也就是說在整個RTSP連接期間,RTSP用戶可打開或者關(guān)閉多個對RTSP服務(wù)器的可靠傳輸連接以發(fā)出RTSP 請求。此外,RTSP連接也可以基于面向無連接的傳輸協(xié)議(如UDP等)。

RTSP協(xié)議目前支持以下操作:

  • 檢索媒體  允許用戶通過HTTP或者其它方法向媒體服務(wù)器提交一個表示描述。如表示是組播的,則表示描述就包含用于該媒體流的組播地址和端口號;如果表示是單播的,為了安全在表示描述中應(yīng)該只提供目的地址。
  • 邀請加入  媒體服務(wù)器可以被邀請參加正在進行的會議,或者在表示中回放媒體,或者在表示中錄制全部媒體或其子集,非常適合于分布式教學(xué)。
  • 添加媒體  通知用戶新加入的可利用媒體流,這對現(xiàn)場講座來講顯得尤其有用。與HTTP/1.1類似,RTSP請求也可以交由代理、通道或者緩存來進行處理。

 





回頁首


三、流媒體編程

RTP是目前解決流媒體實時傳輸問題的最好辦法,如果需要在Linux平臺上進行實時流媒體編程,可以考慮使用一些開放源代碼的RTP庫,如LIBRTP、JRTPLIB等。JRTPLIB是一個面向?qū)ο蟮腞TP庫,它完全遵循RFC 1889設(shè)計,在很多場合下是一個非常不錯的選擇,下面就以JRTPLIB為例,講述如何在Linux平臺上運用RTP協(xié)議進行實時流媒體編程。

3.1 環(huán)境搭建

JRTPLIB是一個用C++語言實現(xiàn)的RTP庫,目前已經(jīng)可以運行在Windows、Linux、FreeBSD、Solaris、Unix和VxWorks等多種操作系統(tǒng)上。要為Linux 系統(tǒng)安裝JRTPLIB,首先從JRTPLIB的網(wǎng)站(http://lumumba.luc.ac.be/jori/jrtplib/jrtplib.html)下載最新的源碼包,此處使用的是jrtplib-2.7b.tar.bz2。假設(shè)下載后的源碼包保存在/usr/local/src目錄下,執(zhí)行下面的命令可以對其進行解壓縮:


            [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
            

最后再執(zhí)行如下命令就可以完成JRTPLIB的安裝:


            [root@linuxgam jrtplib-2.7b]# make install
            

3.2 初始化

在使用JRTPLIB進行實時流媒體數(shù)據(jù)傳輸之前,首先應(yīng)該生成RTPSession類的一個實例來表示此次RTP會話,然后調(diào)用Create()方法來對其進行初始化操作。RTPSession類的Create()方法只有一個參數(shù),用來指明此次RTP會話所采用的端口號。清單1給出了一個最簡單的初始化框架,它只是完成了RTP會話的初始化工作,還不具備任何實際的功能。


代碼清單1:initial.cpp

            #include "rtpsession.h"
            int main(void)
            {
            RTPSession sess;
            sess.Create(5000);
            return 0;
            }
            

如果RTP會話創(chuàng)建過程失敗,Create()方法將會返回一個負數(shù),通過它雖然可以很容易地判斷出函數(shù)調(diào)用究竟是成功的還是失敗的,但卻很難明白出錯的原因到底什么。JRTPLIB采用了統(tǒng)一的錯誤處理機制,它提供的所有函數(shù)如果返回負數(shù)就表明出現(xiàn)了某種形式的錯誤,而具體的出錯信息則可以通過調(diào)用RTPGetErrorString()函數(shù)得到。RTPGetErrorString()函數(shù)將錯誤代碼作為參數(shù)傳入,然后返回該錯誤代碼所對應(yīng)的錯誤信息。清單2給出了一個更加完整的初始化框架,它可以對RTP會話初始化過程中所產(chǎn)生的錯誤進行更好的處理:


代碼清單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;
            }
            

設(shè)置恰當?shù)臅r戳單元,是RTP會話初始化過程所要進行的另外一項重要工作,這是通過調(diào)用RTPSession類的SetTimestampUnit()方法來實現(xiàn)的,該方法同樣也只有一個參數(shù),表示的是以秒為單元的時戳單元。例如,當使用RTP會話傳輸8000Hz采樣的音頻數(shù)據(jù)時,由于時戳每秒鐘將遞增8000,所以時戳單元相應(yīng)地應(yīng)該被設(shè)置成1/8000:


            sess.SetTimestampUnit(1.0/8000.0);
            

3.3 數(shù)據(jù)發(fā)送

當RTP會話成功建立起來之后,接下去就可以開始進行流媒體數(shù)據(jù)的實時傳輸了。首先需要設(shè)置好數(shù)據(jù)發(fā)送的目標地址,RTP協(xié)議允許同一會話存在多個目標地址,這可以通過調(diào)用RTPSession類的AddDestination()、DeleteDestination()和ClearDestinations()方法來完成。例如,下面的語句表示的是讓RTP會話將數(shù)據(jù)發(fā)送到本地主機的6000端口:


            unsigned long addr = ntohl(inet_addr("127.0.0.1"));
            sess.AddDestination(addr, 6000);
            

目標地址全部指定之后,接著就可以調(diào)用RTPSession類的SendPacket()方法,向所有的目標地址發(fā)送流媒體數(shù)據(jù)。SendPacket()是RTPSession類提供的一個重載函數(shù),它具有下列多種形式:


            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()最典型的用法是類似于下面的語句,其中第一個參數(shù)是要被發(fā)送的數(shù)據(jù),而第二個參數(shù)則指明將要發(fā)送數(shù)據(jù)的長度,再往后依次是RTP負載類型、標識和時戳增量。


            sess.SendPacket(buffer, 5, 0, false, 10);
            

對于同一個RTP會話來講,負載類型、標識和時戳增量通常來講都是相同的,JRTPLIB允許將它們設(shè)置為會話的默認參數(shù),這是通過調(diào)用RTPSession類的SetDefaultPayloadType()、SetDefaultMark()和SetDefaultTimeStampIncrement()方法來完成的。為RTP會話設(shè)置這些默認參數(shù)的好處是可以簡化數(shù)據(jù)的發(fā)送,例如,如果為RTP會話設(shè)置了默認參數(shù):


            sess.SetDefaultPayloadType(0);
            sess.SetDefaultMark(false);
            sess.SetDefaultTimeStampIncrement(10);
            

之后在進行數(shù)據(jù)發(fā)送時只需指明要發(fā)送的數(shù)據(jù)及其長度就可以了:


            sess.SendPacket(buffer, 5);
            

3.4 數(shù)據(jù)接收

對于流媒體數(shù)據(jù)的接收端,首先需要調(diào)用RTPSession類的PollData()方法來接收發(fā)送過來的RTP或者RTCP數(shù)據(jù)報。由于同一個RTP會話中允許有多個參與者(源),你既可以通過調(diào)用RTPSession類的GotoFirstSource()和GotoNextSource()方法來遍歷所有的源,也可以通過調(diào)用RTPSession類的GotoFirstSourceWithData()和GotoNextSourceWithData()方法來遍歷那些攜帶有數(shù)據(jù)的源。在從RTP會話中檢測出有效的數(shù)據(jù)源之后,接下去就可以調(diào)用RTPSession類的GetNextPacket()方法從中抽取RTP數(shù)據(jù)報,當接收到的RTP數(shù)據(jù)報處理完之后,一定要記得及時釋放。下面的代碼示范了該如何對接收到的RTP數(shù)據(jù)報進行處理:


            if (sess.GotoFirstSourceWithData()) {
            do {
            RTPPacket *pack;
            pack = sess.GetNextPacket();
            // 處理接收到的數(shù)據(jù)
            delete pack;
            } while (sess.GotoNextSourceWithData());
            }
            

JRTPLIB為RTP數(shù)據(jù)報定義了三種接收模式,其中每種接收模式都具體規(guī)定了哪些到達的RTP數(shù)據(jù)報將會被接受,而哪些到達的RTP數(shù)據(jù)報將會被拒絕。通過調(diào)用RTPSession類的SetReceiveMode()方法可以設(shè)置下列這些接收模式:

  • RECEIVEMODE_ALL  缺省的接收模式,所有到達的RTP數(shù)據(jù)報都將被接受;
  • RECEIVEMODE_IGNORESOME  除了某些特定的發(fā)送者之外,所有到達的RTP數(shù)據(jù)報都將被接受,而被拒絕的發(fā)送者列表可以通過調(diào)用AddToIgnoreList()、DeleteFromIgnoreList()和ClearIgnoreList()方法來進行設(shè)置;
  • RECEIVEMODE_ACCEPTSOME  除了某些特定的發(fā)送者之外,所有到達的RTP數(shù)據(jù)報都將被拒絕,而被接受的發(fā)送者列表可以通過調(diào)用AddToAcceptList ()、DeleteFromAcceptList和ClearAcceptList ()方法來進行設(shè)置。

3.5 控制信息

JRTPLIB是一個高度封裝后的RTP庫,程序員在使用它時很多時候并不用關(guān)心RTCP數(shù)據(jù)報是如何被發(fā)送和接收的,因為這些都可以由JRTPLIB自己來完成。只要PollData()或者SendPacket()方法被成功調(diào)用,JRTPLIB就能夠自動對到達的RTCP數(shù)據(jù)報進行處理,并且還會在需要的時候發(fā)送RTCP數(shù)據(jù)報,從而能夠確保整個RTP會話過程的正確性。

而另一方面,通過調(diào)用RTPSession類提供的SetLocalName()、SetLocalEMail()、SetLocalLocation()、SetLocalPhone()、SetLocalTool()和SetLocalNote()方法,JRTPLIB又允許程序員對RTP會話的控制信息進行設(shè)置。所有這些方法在調(diào)用時都帶有兩個參數(shù),其中第一個參數(shù)是一個char型的指針,指向?qū)⒁辉O(shè)置的數(shù)據(jù);而第二個參數(shù)則是一個int型的數(shù)值,表明該數(shù)據(jù)中的前面多少個字符將會被使用。例如下面的語句可以被用來設(shè)置控制信息中的電子郵件地址:


            sess.SetLocalEMail("xiaowp@linuxgam.com",19);
            

在RTP會話過程中,不是所有的控制信息都需要被發(fā)送,通過調(diào)用RTPSession類提供的EnableSendName()、EnableSendEMail()、EnableSendLocation()、EnableSendPhone()、EnableSendTool()和EnableSendNote()方法,可以為當前RTP會話選擇將被發(fā)送的控制信息。

3.6 實際應(yīng)用

最后通過一個簡單的流媒體發(fā)送-接收實例,介紹如何利用JRTPLIB來進行實時流媒體的編程。清單3給出了數(shù)據(jù)發(fā)送端的完整代碼,它負責向用戶指定的IP地址和端口,不斷地發(fā)送RTP數(shù)據(jù)包:


代碼清單3:sender.cpp

            #include <stdio.h>
            #include <string.h>
            #include "rtpsession.h"
            // 錯誤處理函數(shù)
            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]);
            // 創(chuàng)建RTP會話
            status = sess.Create(portbase);
            checkerror(status);
            // 指定RTP數(shù)據(jù)接收端
            status = sess.AddDestination(destip, destport);
            checkerror(status);
            // 設(shè)置RTP會話默認參數(shù)
            sess.SetDefaultPayloadType(0);
            sess.SetDefaultMark(false);
            sess.SetDefaultTimeStampIncrement(10);
            // 發(fā)送流媒體數(shù)據(jù)
            index = 1;
            do {
            sprintf(buffer, "%d: RTP packet", index ++);
            sess.SendPacket(buffer, strlen(buffer));
            printf("Send packet !\\n");
            } while(1);
            return 0;
            }
            

清單4則給出了數(shù)據(jù)接收端的完整代碼,它負責從指定的端口不斷地讀取RTP數(shù)據(jù)包:


代碼清單4:receiver.cpp

            #include <stdio.h>
            #include "rtpsession.h"
            #include "rtppacket.h"
            // 錯誤處理函數(shù)
            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]);
            // 創(chuàng)建RTP會話
            status = sess.Create(localport);
            checkerror(status);
            do {
            // 接受RTP數(shù)據(jù)
            status = sess.PollData();
            // 檢索RTP數(shù)據(jù)源
            if (sess.GotoFirstSourceWithData()) {
            do {
            RTPPacket* packet;
            // 獲取RTP數(shù)據(jù)報
            while ((packet = sess.GetNextPacket()) != NULL) {
            printf("Got packet !\\n");
            // 刪除RTP數(shù)據(jù)報
            delete packet;
            }
            } while (sess.GotoNextSourceWithData());
            }
            } while(1);
            return 0;
            }
            

本文源碼 下載

posted on 2009-01-24 15:01 大龍 閱讀(487) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲欧美精品在线| 小嫩嫩精品导航| 欧美激情亚洲精品| 亚洲精品国产系列| 亚洲韩日在线| 欧美日韩精品欧美日韩精品| 一区二区三区日韩在线观看| aa级大片欧美三级| 国产精品自在欧美一区| 久久五月激情| 免费在线国产精品| 亚洲一区二区在线免费观看视频| 一区二区三区欧美激情| 国产亚洲欧美日韩一区二区| 美女尤物久久精品| 欧美日韩国产一区二区三区地区 | 久久精品人人做人人爽| 在线观看欧美激情| 日韩视频在线免费| 国产午夜精品在线| 亚洲国产精品久久人人爱蜜臀| 欧美午夜不卡在线观看免费| 久久九九电影| 欧美激情一二区| 欧美一区二区视频网站| 蜜桃av一区| 欧美在线视频导航| 欧美黄色网络| 六月婷婷一区| 国产精品久久福利| 亚洲国产精品高清久久久| 国产精品视频一区二区三区| 欧美激情按摩| 国产一级精品aaaaa看| 亚洲精品在线二区| 国内成人自拍视频| 亚洲性夜色噜噜噜7777| 亚洲欧洲三级电影| 欧美亚洲网站| 亚洲欧美在线一区二区| 欧美顶级少妇做爰| 玖玖精品视频| 国产日韩一区二区三区在线| 一本久道久久综合中文字幕| 亚洲国产日韩欧美| 欧美在线在线| 欧美一区二区在线| 国产精品theporn88| 亚洲国产色一区| 在线观看国产一区二区| 欧美一区亚洲二区| 午夜国产不卡在线观看视频| 欧美二区在线播放| 欧美成人一二三| 在线观看日韩国产| 欧美在线三级| 久久精品视频免费观看| 国产精品永久在线| 亚洲午夜精品一区二区三区他趣| 一区二区欧美在线| 欧美人成网站| 日韩网站在线| 亚洲手机成人高清视频| 欧美日韩视频专区在线播放 | 欧美jizzhd精品欧美巨大免费| 国产视频精品va久久久久久| 亚洲欧美日韩视频二区| 午夜精品福利视频| 国产精品入口福利| 亚洲天堂网在线观看| 亚洲一区欧美激情| 国产精品99一区二区| 亚洲午夜在线| 久久久国产精品一区二区中文| 国产视频一区三区| 久久精品国产999大香线蕉| 久久综合中文字幕| 在线免费观看日本欧美| 美女尤物久久精品| 欧美激情在线有限公司| 亚洲精品三级| 国产精品爱啪在线线免费观看| 亚洲无限乱码一二三四麻| 欧美在线视频日韩| 国产在线播精品第三| 久久综合色88| 亚洲精品偷拍| 欧美一级播放| 伊人久久综合97精品| 欧美顶级大胆免费视频| 亚洲深夜影院| 麻豆成人在线观看| 在线视频欧美日韩精品| 国产情人综合久久777777| 久久久噜噜噜久久狠狠50岁| 亚洲日本一区二区三区| 欧美一区二区高清| 亚洲国产欧美日韩精品| 欧美色123| 久久久久久久综合狠狠综合| 亚洲免费播放| 久久先锋影音av| 亚洲一区黄色| 亚洲高清久久| 国产精品制服诱惑| 欧美成人一区二免费视频软件| 亚洲在线播放电影| 欧美激情精品久久久久久大尺度 | 亚洲在线观看视频网站| 精品9999| 国产精品一区二区三区久久久| 免费观看成人鲁鲁鲁鲁鲁视频| 亚洲视频一二三| 欧美激情区在线播放| 久久国产乱子精品免费女| av成人黄色| 影音先锋日韩资源| 国产精品自在在线| 欧美日韩精品在线播放| 久久久久久久97| 亚洲一区精品视频| 亚洲免费成人| 欧美国产91| 久久一区国产| 久久精品亚洲精品| 亚洲一区欧美一区| 99精品热视频| 亚洲欧洲在线一区| 伊人成综合网伊人222| 国产精品免费小视频| 欧美日韩高清在线播放| 欧美91大片| 久久亚洲精品一区二区| 久久久精品2019中文字幕神马| 亚洲在线观看免费| 一区二区日韩伦理片| 亚洲巨乳在线| 欧美激情精品久久久久久黑人| 蜜桃精品久久久久久久免费影院| 久久久久国产精品一区| 久久aⅴ国产欧美74aaa| 久久99伊人| 久久精品视频在线免费观看| 欧美一区观看| 久久精品国语| 久久久亚洲欧洲日产国码αv | 久久久久久亚洲精品杨幂换脸| 午夜天堂精品久久久久| 欧美亚洲综合网| 久久国产精品电影| 久久青草欧美一区二区三区| 久久综合伊人77777麻豆| 久久精品免费观看| 久久午夜电影| 欧美激情亚洲激情| 最新成人av网站| 一区二区三区视频免费在线观看| 妖精成人www高清在线观看| 中日韩午夜理伦电影免费| 亚洲一区欧美激情| 欧美一区日本一区韩国一区| 久久久久一区二区三区| 裸体歌舞表演一区二区| 欧美日韩国产成人在线观看| 国产精品白丝av嫩草影院| 国产精品一二三视频| 好看的日韩av电影| 亚洲人成艺术| 亚洲欧美一区二区激情| 六月丁香综合| 亚洲精品久久久久久久久久久| 在线一区观看| 久久久精品久久久久| 欧美激情精品久久久久久| 国产精品久久国产精品99gif| 国产视频一区免费看| 亚洲精品免费在线观看| 欧美一区2区三区4区公司二百| 久久夜色撩人精品| 亚洲麻豆一区| 久久精品一本| 欧美日韩中文在线| 伊人久久成人| 亚洲欧美日韩成人高清在线一区| 久久全球大尺度高清视频| 亚洲欧洲一区二区三区久久| 亚洲欧美日韩视频二区| 欧美国产日本韩| 国产亚洲日本欧美韩国| 在线一区二区日韩| 玖玖综合伊人| 亚洲欧美日韩成人| 欧美美女视频| 伊人成人在线视频| 欧美怡红院视频一区二区三区| 亚洲精品婷婷| 麻豆精品网站| 国内精品写真在线观看| 午夜欧美视频| 一二三区精品|