实时视频传输协议RTP
一、RTP(實時傳輸協(xié)議)
二、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 install2.初始化
首先應(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ā)送
在從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)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 3369 膜拜
- 下一篇: oracle 12C 创建用户失败 解决