linux 下基于jrtplib库的实时传送实现
生活随笔
收集整理的這篇文章主要介紹了
linux 下基于jrtplib库的实时传送实现
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
linux 下基于jrtplib庫的實時傳送實現(xiàn)
一、RTP 是進(jìn)行實時流媒體傳輸?shù)臉?biāo)準(zhǔn)協(xié)議和關(guān)鍵技術(shù)
實時傳輸協(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 來進(jìn)行多媒體數(shù)據(jù)的傳輸,但如果需要的話可以使用 TCP 或者 ATM 等其它協(xié)議。
協(xié)議分析 :每一個RTP數(shù)據(jù)報都由頭部(Header)和負(fù)載(Payload)兩個部分組成,其中頭部前 12 個字節(jié)的含義是固定的,而負(fù)載則可以是音頻或者視頻數(shù)據(jù)。
? ? ?RTP 是目前解決流媒體實時傳輸問題的最好辦法,要在 Linux 平臺上進(jìn)行實時傳送編程,可以考慮使用一些開放源代碼的 RTP 庫,如 LIBRTP、JRTPLIB 等。JRTPLIB 是一個面向?qū)ο蟮?RTP 庫,它完全遵循 RFC 1889 設(shè)計,在很多場合下是一個非常不錯的選擇。JRTPLIB 是一個用 C++ 語言實現(xiàn)的 RTP 庫,這個庫使用socket 機(jī)制實現(xiàn)網(wǎng)絡(luò)通訊 因此可以運行在 Windows、Linux、FreeBSD、Solaris、Unix和VxWorks 等多種操作系統(tǒng)上。
二、JRTPLIB 庫的使用方法及程序?qū)崿F(xiàn)
(1)JRTPLIB ?函數(shù) 的使用
a、在使用 JRTPLIB 進(jìn)行實時流媒體數(shù)據(jù)傳輸之前,首先應(yīng)該生成 RTPSession 類的一個實例來表示此次 RTP 會話,然后調(diào)用 Create() 方法來對其進(jìn)行初始化操作。RTPSession 類的 Create() 方法只有一個參數(shù),用來指明此次 RTP 會話所采用的端口號。
RTPSession sess; ?sess.Create(5000);
b、設(shè)置恰當(dāng)?shù)臅r戳單元,是 RTP 會話初始化過程所要進(jìn)行的另外一項重要工作,這是通過調(diào)用 RTPSession 類的 SetTimestampUnit() 方法來實現(xiàn)的,該方法同樣也只有一個參數(shù),表示的是以秒為單元的時戳單元。
sess.SetTimestampUnit(1.0/8000.0);
c、當(dāng) RTP 會話成功建立起來之后,接下去就可以開始進(jìn)行流媒體數(shù)據(jù)的實時傳輸了。首先需要設(shè)置好數(shù)據(jù)發(fā)送的目標(biāo)地址,RTP 協(xié)議允許同一會話存在多個目標(biāo)地址,這可以通過調(diào)用 RTPSession 類的 AddDestination()、DeleteDestination() 和 ClearDestinations() 方法來完成。例如,下面的語句表示的是讓 RTP 會話將數(shù)據(jù)發(fā)送到本地主機(jī)的 6000 端口:
unsigned long addr = ntohl(inet_addr("127.0.0.1"));
sess.AddDestination(addr, 6000);
d、目標(biāo)地址全部指定之后,接著就可以調(diào)用 RTPSession 類的 SendPacket() 方法,向所有的目標(biāo)地址發(fā)送流媒體數(shù)據(jù)。SendPacket() 是 RTPSession 類提供的一個重載函數(shù)
對于同一個 RTP 會話來講,負(fù)載類型、標(biāo)識和時戳增量通常來講都是相同的,JRTPLIB 允許將它們設(shè)置為會話的默認(rèn)參數(shù),這是通過調(diào)用 RTPSession 類的 SetDefaultPayloadType()、SetDefaultMark() 和 SetDefaultTimeStampIncrement() 方法來完成的。為 RTP 會話設(shè)置這些默認(rèn)參數(shù)的好處是可以簡化數(shù)據(jù)的發(fā)送,例如,如果為 RTP 會話設(shè)置了默認(rèn)參數(shù):
sess.SetDefaultPayloadType(0);
?sess.SetDefaultMark(false); ?
sess.SetDefaultTimeStampIncrement(10);
之后在進(jìn)行數(shù)據(jù)發(fā)送時只需指明要發(fā)送 的數(shù)據(jù)及其長度就可以了:
sess.SendPacket(buffer, 5);
e、對于流媒體數(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ù)報,當(dāng)接收到的 RTP 數(shù)據(jù)報處理完之后,一定要記得及時釋放。
JRTPLIB 為 RTP 數(shù)據(jù)報定義了三種接收模式,其中每種接收模式都具體規(guī)定了哪些到達(dá)的 RTP 數(shù)據(jù)報將會被接受,而哪些到達(dá)的 RTP 數(shù)據(jù)報將會被拒絕。通過調(diào)用 RTPSession 類的 SetReceiveMode() 方法可以設(shè)置下列這些接收模式:
? RECEIVEMODE_ALL 缺省的接收模式,所有到達(dá)的 RTP 數(shù)據(jù)報都將被接受;
? RECEIVEMODE_IGNORESOME 除了某些特定的發(fā)送者之外,所有到達(dá)的 RTP 數(shù)據(jù)報都將被接受,而被拒絕的發(fā)送者列表可以通過調(diào)用 AddToIgnoreList()、DeleteFromIgnoreList() 和 ClearIgnoreList() 方法來進(jìn)行設(shè)置;
? RECEIVEMODE_ACCEPTSOME 除了某些特定的發(fā)送者之外,所有到達(dá)的 RTP 數(shù)據(jù)報都將被拒絕,而被接受的發(fā)送者列表可以通過調(diào)用 AddToAcceptList ()、DeleteFromAcceptList 和 ClearAcceptList () 方法來進(jìn)行設(shè)置。 下面是采用第三種接收模式的程序示例。
if (sess.GotoFirstSourceWithData()) { ?
?do { ?
? sess.AddToAcceptList(remoteIP, allports,portbase);
? ? ? ? ?sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);
? ?RTPPacket *pack; ? ? ? ?
? ?pack = sess.GetNextPacket(); ? ? ? ? ? ?// 處理接收到的數(shù)據(jù) ? ?
? ?delete pack; ? }
?while (sess.GotoNextSourceWithData());
?}
?(2)程序流程圖
發(fā)送:獲得接 收端的 IP 地址和端口號 ? ? ? ?創(chuàng)建 RTP 會話 ? ? ? ?指定 RTP 數(shù)據(jù)接收端 設(shè)置 RTP 會話默認(rèn)參數(shù) ? 發(fā)送流媒體數(shù)據(jù)
接收:獲得用戶指定的端口號 ?創(chuàng)建RTP會話 ?設(shè)置接收模式 ?接受RTP數(shù)據(jù) ?檢索RTP數(shù)據(jù)源 ?獲取RTP數(shù)據(jù)報 ?刪除RTP數(shù)據(jù)報
三、環(huán)境搭建及編譯方法
引用(1)Toolchain的安裝
首先找到xscale-arm-toolchain.tgz文件,假設(shè)該文件包放在/tmp/下
#cd /
#tar -zxvf /tmp/xscale-arm-toolchain.tgz
再設(shè)置環(huán)境變量
#export PATH=/usr/local/arm-linux/bin:$PATH
最后檢查一下交叉編譯工具是否安裝成功
#arm-linux-g++ --version
看是否顯示arm-linux-g++的版本,如有則安裝成功。
(2)JRTPLIB 庫的交叉編譯及安裝
首先從 JRTPLIB 的網(wǎng)站(http://lumumba.luc.ac.be/jori/jrtplib/jrtplib.htmll) 下載最新的源碼包,此處使用的是jrtplib-2.8.tar,假設(shè)下載后的源碼包放在/tmp下,執(zhí) 行下面的命令對其解壓縮:
#cd /tmp
#tar -zxvf jrtplib-2.8.tar
然后要對jrtplib進(jìn)行配置和編譯
#cd jrtplib-2.8
#./configure CC=arm-linux-g++ cross-compile=yes
修改Makefile文件
將鏈接命令ld 和ar改為arm-linux-ld和 arm-linux-ar
#make
最后再執(zhí)行如下命令就可以完成 JRTPLIB 的安裝:
#make install
(3)程序編譯
a、配置編譯環(huán)境
可以用export來配置,也可以用編寫Makefile的方法。這里采用Makefile。
編寫Makefile&:
INCL = -I/usr/local/include
CFLAGS = -pipe -O2 -fno-strength-reduce
LFLAGS = /usr/local/lib/libjrtp.a -L/usr/X11R6/lib
LIBS = -LX11 -LXext /usr/local/lib/libjrtp.a
CC = arm-linux-g++
main:main.o
$(CC) $(LFLAGS) $(INCL) -o main main.o $(LIBS)
main.o:main.cpp
clean:
rm -f main
rm -f *.o
.SUFFIXES:.cpp
.cpp.o:
$(CC) -c $(CFLAGS) $(INCL) -o $@ $< ? ? ? ? /* ?$@表示目標(biāo)的完整名字 ? ? ?*/
? ? ? ? ?/* $<表示第一個依賴文件的名字 */
b、編譯
假設(shè)發(fā)送和接收程序分別放在/tmp/send和/tmp/receive目錄下
#cd /tmp/send
#make
#cd /tmp/receive
#make
四、易出錯誤及注意問題
引用1、找不到一些標(biāo)準(zhǔn)的最 基本的一些頭文件。
?主要是因為Toolchain路徑?jīng)]安裝對,要 嚴(yán)格按照步驟安裝。
2、找不到使用的jrtplib庫中的一些頭文件。
?在 jrtplib的安裝目錄下,include路徑下不能再有別的目錄。
3、recieve函數(shù)接收數(shù)據(jù)包不能正確提出所要數(shù)據(jù)。
?由于每一個RTP數(shù)據(jù)報都由頭部(Header)和負(fù)載(Payload)兩個部分組成,若使用getrawdata()是返回整個數(shù)據(jù)包的數(shù)據(jù),包含 傳輸媒體的類型、格式、序列號、時間戳以及是否有附加數(shù)據(jù)等信息。getpayload()函數(shù)是返回所發(fā)送的數(shù)據(jù)。兩者一定要分清。
4、設(shè)置RECEIVEMODE_ACCEPTSOME 接收模式后,運行程序接收端不能接包。
?IP地址格式出了問題。iner_addr()與ntohl()函數(shù)要用對,否則參數(shù)傳不進(jìn)去,接受列表中無值,當(dāng)然接收不了數(shù)據(jù)包。
5、編譯通過,但測試時接收端不能接收到數(shù)據(jù)。
?可能是接收機(jī)防火墻未關(guān)閉。運行:
?#iptables -F
?也可能是IP地址沒有設(shè)置好。運行:
?#ifocnfig eth0 ?*.*.*.* ?netmask *.*.*.*
6、使用jrtolib庫時,在程序中include 后最好加上庫所在的路徑。五、程序
send:
view plainprint?#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會話默認(rèn)參數(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;?? }?? #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會話默認(rèn)參數(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; }
receive:
view plainprint?#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,portbase;?? ??int?status;?? ??unsigned?long?remoteIP;?? ??if?(argc?!=?4)?{?? ????printf("Usage:?./sender?localport\\n");?? ????return?-1;?? ??}?? ?? ???//?獲得用戶指定的端口號?? ????? ??remoteIP?=?inet_addr(argv[1]);?? ??localport?=?atoi(argv[2]);?? ??portbase?=?atoi(argv[3]);?? ??//?創(chuàng)建RTP會話?? ??status?=?sess.Create(localport);?? ??checkerror(status);?? ???? ??//RTPHeader?*rtphdr;?? ??unsigned?long?timestamp1;?? ??unsigned?char?*?RawData;?? ??unsigned?char?temp[30];?? ??int?lengh?,i;?? ??bool?allports?=?1;?? ???? ??sess.AddToAcceptList(remoteIP,?allports,portbase);?? ???? ?????do?{?? ?//設(shè)置接收模式?? ????????sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);?? ???sess.AddToAcceptList(remoteIP,?allports,portbase);?? ?? ????//?接受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");?? ?? ???timestamp1?=?packet->GetTimeStamp();?? ???lengh=packet->GetPayloadLength();?? ???RawData=packet->GetPayload();?? ????? ???for(i=0;i<lengh;i++){?? ??????temp[i]=RawData[i];?? ??printf("%c",temp[i]);?? ???}?? ???temp[i]='\0';?? ???printf("??timestamp:?%d?lengh=%d?data:%s\n",timestamp1,lengh,&temp);?? ??????????//?刪除RTP數(shù)據(jù)報?? ????? ??????????delete?packet;?? ????????}?? ??????}?while?(sess.GotoNextSourceWithData());?? ????}?? ??}?while(1);?? ?? ??return?0;?? }?? #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,portbase; ?int status; ?unsigned long remoteIP; ?if (argc != 4) { ? ?printf("Usage: ./sender localport\\n"); ? ?return -1; ?} ? // 獲得用戶指定的端口號 ? ?remoteIP = inet_addr(argv[1]); ?localport = atoi(argv[2]); ?portbase = atoi(argv[3]); ?// 創(chuàng)建RTP會話 ?status = sess.Create(localport); ?checkerror(status); ? ?//RTPHeader *rtphdr; ?unsigned long timestamp1; ?unsigned char * RawData; ?unsigned char temp[30]; ?int lengh ,i; ?bool allports = 1; ? ?sess.AddToAcceptList(remoteIP, allports,portbase); ? ? ? do { //設(shè)置接收模式 ? ? ? ?sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME); ? sess.AddToAcceptList(remoteIP, allports,portbase); ? ?// 接受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"); ? timestamp1 = packet->GetTimeStamp(); ? lengh=packet->GetPayloadLength(); ? RawData=packet->GetPayload(); ? ? for(i=0;i<lengh;i++){ ? ? ?temp[i]=RawData[i]; ?printf("%c",temp[i]); ? } ? temp[i]='\0'; ? printf(" ?timestamp: %d lengh=%d data:%s\n",timestamp1,lengh,&temp); ? ? ? ? ?// 刪除RTP數(shù)據(jù)報 ? ? ? ? ? ?delete packet; ? ? ? ?} ? ? ?} while (sess.GotoNextSourceWithData()); ? ?} ?} while(1); ?return 0; } 相關(guān)日志
一、RTP 是進(jìn)行實時流媒體傳輸?shù)臉?biāo)準(zhǔn)協(xié)議和關(guān)鍵技術(shù)
實時傳輸協(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 來進(jìn)行多媒體數(shù)據(jù)的傳輸,但如果需要的話可以使用 TCP 或者 ATM 等其它協(xié)議。
協(xié)議分析 :每一個RTP數(shù)據(jù)報都由頭部(Header)和負(fù)載(Payload)兩個部分組成,其中頭部前 12 個字節(jié)的含義是固定的,而負(fù)載則可以是音頻或者視頻數(shù)據(jù)。
? ? ?RTP 是目前解決流媒體實時傳輸問題的最好辦法,要在 Linux 平臺上進(jìn)行實時傳送編程,可以考慮使用一些開放源代碼的 RTP 庫,如 LIBRTP、JRTPLIB 等。JRTPLIB 是一個面向?qū)ο蟮?RTP 庫,它完全遵循 RFC 1889 設(shè)計,在很多場合下是一個非常不錯的選擇。JRTPLIB 是一個用 C++ 語言實現(xiàn)的 RTP 庫,這個庫使用socket 機(jī)制實現(xiàn)網(wǎng)絡(luò)通訊 因此可以運行在 Windows、Linux、FreeBSD、Solaris、Unix和VxWorks 等多種操作系統(tǒng)上。
二、JRTPLIB 庫的使用方法及程序?qū)崿F(xiàn)
(1)JRTPLIB ?函數(shù) 的使用
a、在使用 JRTPLIB 進(jìn)行實時流媒體數(shù)據(jù)傳輸之前,首先應(yīng)該生成 RTPSession 類的一個實例來表示此次 RTP 會話,然后調(diào)用 Create() 方法來對其進(jìn)行初始化操作。RTPSession 類的 Create() 方法只有一個參數(shù),用來指明此次 RTP 會話所采用的端口號。
RTPSession sess; ?sess.Create(5000);
b、設(shè)置恰當(dāng)?shù)臅r戳單元,是 RTP 會話初始化過程所要進(jìn)行的另外一項重要工作,這是通過調(diào)用 RTPSession 類的 SetTimestampUnit() 方法來實現(xiàn)的,該方法同樣也只有一個參數(shù),表示的是以秒為單元的時戳單元。
sess.SetTimestampUnit(1.0/8000.0);
c、當(dāng) RTP 會話成功建立起來之后,接下去就可以開始進(jìn)行流媒體數(shù)據(jù)的實時傳輸了。首先需要設(shè)置好數(shù)據(jù)發(fā)送的目標(biāo)地址,RTP 協(xié)議允許同一會話存在多個目標(biāo)地址,這可以通過調(diào)用 RTPSession 類的 AddDestination()、DeleteDestination() 和 ClearDestinations() 方法來完成。例如,下面的語句表示的是讓 RTP 會話將數(shù)據(jù)發(fā)送到本地主機(jī)的 6000 端口:
unsigned long addr = ntohl(inet_addr("127.0.0.1"));
sess.AddDestination(addr, 6000);
d、目標(biāo)地址全部指定之后,接著就可以調(diào)用 RTPSession 類的 SendPacket() 方法,向所有的目標(biāo)地址發(fā)送流媒體數(shù)據(jù)。SendPacket() 是 RTPSession 類提供的一個重載函數(shù)
對于同一個 RTP 會話來講,負(fù)載類型、標(biāo)識和時戳增量通常來講都是相同的,JRTPLIB 允許將它們設(shè)置為會話的默認(rèn)參數(shù),這是通過調(diào)用 RTPSession 類的 SetDefaultPayloadType()、SetDefaultMark() 和 SetDefaultTimeStampIncrement() 方法來完成的。為 RTP 會話設(shè)置這些默認(rèn)參數(shù)的好處是可以簡化數(shù)據(jù)的發(fā)送,例如,如果為 RTP 會話設(shè)置了默認(rèn)參數(shù):
sess.SetDefaultPayloadType(0);
?sess.SetDefaultMark(false); ?
sess.SetDefaultTimeStampIncrement(10);
之后在進(jìn)行數(shù)據(jù)發(fā)送時只需指明要發(fā)送 的數(shù)據(jù)及其長度就可以了:
sess.SendPacket(buffer, 5);
e、對于流媒體數(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ù)報,當(dāng)接收到的 RTP 數(shù)據(jù)報處理完之后,一定要記得及時釋放。
JRTPLIB 為 RTP 數(shù)據(jù)報定義了三種接收模式,其中每種接收模式都具體規(guī)定了哪些到達(dá)的 RTP 數(shù)據(jù)報將會被接受,而哪些到達(dá)的 RTP 數(shù)據(jù)報將會被拒絕。通過調(diào)用 RTPSession 類的 SetReceiveMode() 方法可以設(shè)置下列這些接收模式:
? RECEIVEMODE_ALL 缺省的接收模式,所有到達(dá)的 RTP 數(shù)據(jù)報都將被接受;
? RECEIVEMODE_IGNORESOME 除了某些特定的發(fā)送者之外,所有到達(dá)的 RTP 數(shù)據(jù)報都將被接受,而被拒絕的發(fā)送者列表可以通過調(diào)用 AddToIgnoreList()、DeleteFromIgnoreList() 和 ClearIgnoreList() 方法來進(jìn)行設(shè)置;
? RECEIVEMODE_ACCEPTSOME 除了某些特定的發(fā)送者之外,所有到達(dá)的 RTP 數(shù)據(jù)報都將被拒絕,而被接受的發(fā)送者列表可以通過調(diào)用 AddToAcceptList ()、DeleteFromAcceptList 和 ClearAcceptList () 方法來進(jìn)行設(shè)置。 下面是采用第三種接收模式的程序示例。
if (sess.GotoFirstSourceWithData()) { ?
?do { ?
? sess.AddToAcceptList(remoteIP, allports,portbase);
? ? ? ? ?sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);
? ?RTPPacket *pack; ? ? ? ?
? ?pack = sess.GetNextPacket(); ? ? ? ? ? ?// 處理接收到的數(shù)據(jù) ? ?
? ?delete pack; ? }
?while (sess.GotoNextSourceWithData());
?}
?(2)程序流程圖
發(fā)送:獲得接 收端的 IP 地址和端口號 ? ? ? ?創(chuàng)建 RTP 會話 ? ? ? ?指定 RTP 數(shù)據(jù)接收端 設(shè)置 RTP 會話默認(rèn)參數(shù) ? 發(fā)送流媒體數(shù)據(jù)
接收:獲得用戶指定的端口號 ?創(chuàng)建RTP會話 ?設(shè)置接收模式 ?接受RTP數(shù)據(jù) ?檢索RTP數(shù)據(jù)源 ?獲取RTP數(shù)據(jù)報 ?刪除RTP數(shù)據(jù)報
三、環(huán)境搭建及編譯方法
引用(1)Toolchain的安裝
首先找到xscale-arm-toolchain.tgz文件,假設(shè)該文件包放在/tmp/下
#cd /
#tar -zxvf /tmp/xscale-arm-toolchain.tgz
再設(shè)置環(huán)境變量
#export PATH=/usr/local/arm-linux/bin:$PATH
最后檢查一下交叉編譯工具是否安裝成功
#arm-linux-g++ --version
看是否顯示arm-linux-g++的版本,如有則安裝成功。
(2)JRTPLIB 庫的交叉編譯及安裝
首先從 JRTPLIB 的網(wǎng)站(http://lumumba.luc.ac.be/jori/jrtplib/jrtplib.htmll) 下載最新的源碼包,此處使用的是jrtplib-2.8.tar,假設(shè)下載后的源碼包放在/tmp下,執(zhí) 行下面的命令對其解壓縮:
#cd /tmp
#tar -zxvf jrtplib-2.8.tar
然后要對jrtplib進(jìn)行配置和編譯
#cd jrtplib-2.8
#./configure CC=arm-linux-g++ cross-compile=yes
修改Makefile文件
將鏈接命令ld 和ar改為arm-linux-ld和 arm-linux-ar
#make
最后再執(zhí)行如下命令就可以完成 JRTPLIB 的安裝:
#make install
(3)程序編譯
a、配置編譯環(huán)境
可以用export來配置,也可以用編寫Makefile的方法。這里采用Makefile。
編寫Makefile&:
INCL = -I/usr/local/include
CFLAGS = -pipe -O2 -fno-strength-reduce
LFLAGS = /usr/local/lib/libjrtp.a -L/usr/X11R6/lib
LIBS = -LX11 -LXext /usr/local/lib/libjrtp.a
CC = arm-linux-g++
main:main.o
$(CC) $(LFLAGS) $(INCL) -o main main.o $(LIBS)
main.o:main.cpp
clean:
rm -f main
rm -f *.o
.SUFFIXES:.cpp
.cpp.o:
$(CC) -c $(CFLAGS) $(INCL) -o $@ $< ? ? ? ? /* ?$@表示目標(biāo)的完整名字 ? ? ?*/
? ? ? ? ?/* $<表示第一個依賴文件的名字 */
b、編譯
假設(shè)發(fā)送和接收程序分別放在/tmp/send和/tmp/receive目錄下
#cd /tmp/send
#make
#cd /tmp/receive
#make
四、易出錯誤及注意問題
引用1、找不到一些標(biāo)準(zhǔn)的最 基本的一些頭文件。
?主要是因為Toolchain路徑?jīng)]安裝對,要 嚴(yán)格按照步驟安裝。
2、找不到使用的jrtplib庫中的一些頭文件。
?在 jrtplib的安裝目錄下,include路徑下不能再有別的目錄。
3、recieve函數(shù)接收數(shù)據(jù)包不能正確提出所要數(shù)據(jù)。
?由于每一個RTP數(shù)據(jù)報都由頭部(Header)和負(fù)載(Payload)兩個部分組成,若使用getrawdata()是返回整個數(shù)據(jù)包的數(shù)據(jù),包含 傳輸媒體的類型、格式、序列號、時間戳以及是否有附加數(shù)據(jù)等信息。getpayload()函數(shù)是返回所發(fā)送的數(shù)據(jù)。兩者一定要分清。
4、設(shè)置RECEIVEMODE_ACCEPTSOME 接收模式后,運行程序接收端不能接包。
?IP地址格式出了問題。iner_addr()與ntohl()函數(shù)要用對,否則參數(shù)傳不進(jìn)去,接受列表中無值,當(dāng)然接收不了數(shù)據(jù)包。
5、編譯通過,但測試時接收端不能接收到數(shù)據(jù)。
?可能是接收機(jī)防火墻未關(guān)閉。運行:
?#iptables -F
?也可能是IP地址沒有設(shè)置好。運行:
?#ifocnfig eth0 ?*.*.*.* ?netmask *.*.*.*
6、使用jrtolib庫時,在程序中include 后最好加上庫所在的路徑。五、程序
send:
view plainprint?
receive:
view plainprint?
轉(zhuǎn)載于:https://blog.51cto.com/general/328224
總結(jié)
以上是生活随笔為你收集整理的linux 下基于jrtplib库的实时传送实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何使用grup制作U盘多重启动盘
- 下一篇: oracle PL/SQL