日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

实时视频传输协议RTP

發(fā)布時間:2023/12/18 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 实时视频传输协议RTP 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、RTP(實時傳輸協(xié)議)

  • RTP全名是Real-time Transport Protocol(實時傳輸協(xié)議),RTP協(xié)議常用于流媒體系統(tǒng)(配合RTCP協(xié)議或者RTSP協(xié)議)。因為RTP自身具有Time stamp所以在ffmpeg 中被用做一種formate.
  • 每一個RTP數(shù)據(jù)報都由頭部(Header)和負載(Payload)兩個部分組成,其中頭部前12個字節(jié)的含義是固定的,而負載則可以是音頻或者視頻數(shù)據(jù)。
  • 二、RTP頭部格式

    • V:RTP協(xié)議的版本號,占2位,當(dāng)前協(xié)議版本號為2
    • P:填充標(biāo)志,占1位,如果P=1,則在該報文的尾部填充一個或多個額外的八位組,它們不是有效載荷的一部分。
    • X:擴展標(biāo)志,占1位,如果X=1,則在RTP報頭后跟有一個擴展報頭
    • CC:CSRC計數(shù)器,占4位,指示CSRC 標(biāo)識符的個數(shù)
    • M: 標(biāo)記,占1位,不同的有效載荷有不同的含義,對于視頻,標(biāo)記一幀的結(jié)束;對于音頻,標(biāo)記會話的開始。
    • PT: 有效荷載類型,占7位,用于說明RTP報文中有效載荷的類型,如GSM音頻、JPEM圖像等,在流媒體中大部分是用來區(qū)分音頻流和視頻流的,這樣便于客戶端進行解析
    • 序列號:占16位,用于標(biāo)識發(fā)送者所發(fā)送的RTP報文的序列號,每發(fā)送一個報文,序列號增1。這個字段當(dāng)下層的承載協(xié)議用UDP的時候,網(wǎng)絡(luò)狀況不好的時候可以用來檢查丟包。同時出現(xiàn)網(wǎng)絡(luò)抖動的情況可以用來對數(shù)據(jù)進行重新排序,序列號的初始值是隨機的,同時音頻包和視頻包的sequence是分別記數(shù)的。
    • 時戳(Timestamp):占32位,必須使用90 kHz 時鐘頻率。時戳反映了該RTP報文的第一個八位組的采樣時刻。接收者使用時戳來計算延遲和延遲抖動,并進行同步控制。
    • 同步信源(SSRC)標(biāo)識符:占32位,用于標(biāo)識同步信源。該標(biāo)識符是隨機選擇的,參加同一視頻會議的兩個同步信源不能有相同的SSRC。
    • 特約信源(CSRC)標(biāo)識符:每個CSRC標(biāo)識符占32位,可以有0~15個。每個CSRC標(biāo)識了包含在該RTP報文有效載荷中的所有特約信源。

    三、RTP負載H264碼流

    參考網(wǎng)頁: http://blog.csdn.net/chen495810242/article/details/39207305

    四、RTP編程(JRTPLIB)

    參考網(wǎng)頁: http://blog.csdn.net/pu1030/article/details/7619908

    JRTPLIB 是一個用C++語言實現(xiàn)的RTP庫,目前已經(jīng)可以運行在Windows、Linux、FreeBSD、 Solaris、Unix和VxWorks等多種操作系統(tǒng)上。

    1.linux(raspbian)安裝JRTPLIB

  • 首先從JRTPLIB的網(wǎng)站(http://research.edm.uhasselt.be/jori/page/Main/HomePage.html)下載最新的源碼包,我下載的是jrtplib-3.11.1.zip。再從Jthread網(wǎng)站(首先從JRTPLIB的網(wǎng)站(http://research.edm.uhasselt.be/jori/page/Main/HomePage.html)下載最新的源碼包,我下載的是jrtplib-3.11.1.zip。再從Jthread網(wǎng)站下載對應(yīng)的源碼包)下載對應(yīng)的源碼包jthread-1.3.3.zip。

  • 編譯說明:第一種是用jthread庫提供的線程自動在后臺執(zhí)行對數(shù)據(jù)的接收.第二種是用戶自己調(diào)用RTPSession中的Poll方法。如果采取第一種方法則要安裝jthread庫,而且 jthread-1.3.3必須先與jrtplib-3.11.1的安裝。因為在jrtplib-3.11.1的configure中,會查找系統(tǒng)是否有編譯了jthread庫,如果有,那么編譯的jrtp庫會開啟對jthread的支持。因此如果先編譯jrtp在編譯jthread,編譯出來的jrtp是沒有開啟對jthread的支持的。

  • 編譯jthread

    將下載的壓縮包解壓后進入jthread-1.3.3目錄中,修改該目錄下的CMakeLists.txt;

    添加:

    set( CMAKE_SYSTEM_NAME Linux) set( CMAKE_C_COMPILER arm-linux-gnueabihf-gcc ) set( CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++ ) set( CMAKE_INSTALL_PREFIX "/usr/local")

    編譯安裝:

    cmake CMakeLists.txtmakemake install

    編譯jrtplib

    同樣修改CMakeLists.txt

    set( CMAKE_SYSTEM_NAME Linux) set( CMAKE_C_COMPILER arm-linux-gnueabihf-gcc ) set( CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++ ) set( CMAKE_INSTALL_PREFIX "/usr/local")set(JRTPLIB_INTERNAL_INCLUDES "/usr/local/include") set(JRTPLIB_EXTERNAL_INCLUDES "/usr/local/include")

    編譯安裝:

    cmake CMakeLists.txtmakemake install

    2.初始化

  • 首先應(yīng)該生成RTPSession類的一個實例來表示此次RTP會話,然后調(diào)用Create()方法來對其進行初始化操作。RTPSession類的Create()方法只有一個參數(shù),用來指明此次RTP會話所采用的端口號。

  • RTPGetErrorString()函數(shù)將錯誤代碼作為參數(shù)傳入,然后返回該錯誤代碼所對應(yīng)的錯誤信息。JRTPLIB采用了統(tǒng)一的錯誤處理機制,它提供的所有函數(shù)如果返回負數(shù)就表明出現(xiàn)了某種形式的錯誤都可以調(diào)用此函數(shù)

  • SetTimestampUnit()方法來設(shè)置恰當(dāng)?shù)臅r戳單元,表示的是以秒為單元的時戳單元。例如,當(dāng)使用RTP會話傳輸8000Hz 采樣的音頻數(shù)據(jù)時,由于時戳每秒鐘將遞增8000,所以時戳單元相應(yīng)地應(yīng)該被設(shè)置成1.0/8000.0

    #include <stdio.h> #include "rtpsession.h"int main(void) {RTPSession sess;int status;char* msg;/* 創(chuàng)建一個端口號為6000的RTP實例 */sess.Create(6000);/* 如果創(chuàng)建失敗則輸出錯誤原因 */msg = RTPGetErrorString(status);printf("Error String: %s\\n", msg);/* 設(shè)置時間戳單元 */sess.SetTimestampUnit(1.0/8000.0);return 0; }
  • 3.發(fā)送數(shù)據(jù)

  • RTP協(xié)議允許同一會話存在多個目標(biāo)地址,這可以通過調(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);
  • SendPacket()方法向所有的目標(biāo)地址發(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負載類型、標(biāo)識和時戳增量。

    sess.SendPacket(buffer, 5, 0, false, 10);
  • 對于同一個RTP會話來講,負載類型、標(biāo)識和時戳增量通常來講都是相同的,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);

    4.數(shù)據(jù)發(fā)送

  • 調(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ù)報,當(dāng)接收到的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è)置。
  • 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.comxiaowp@linuxgam.com",19);

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

    6.實例

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

    #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ù)接收端的完整代碼,它負責(zé)從指定的端口不斷地讀取RTP數(shù)據(jù)包:

    #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; }

    總結(jié)

    以上是生活随笔為你收集整理的实时视频传输协议RTP的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。