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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 下基于jrtplib库的实时传送实现

發(fā)布時間:2025/3/21 linux 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 下基于jrtplib库的实时传送实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
linux 下基于jrtplib庫的實(shí)時傳送實(shí)現(xiàn)
一、RTP 是進(jìn)行實(shí)時流媒體傳輸?shù)臉?biāo)準(zhǔn)協(xié)議和關(guān)鍵技術(shù)
實(shí)時傳輸協(xié)議(Real-time Transport Protocol,PRT)是在 Internet 上處理多媒體數(shù)據(jù)流的一種網(wǎng)絡(luò)協(xié)議,利用它能夠在一對一(unicast,單播)或者一對多(multicast,多播)的網(wǎng)絡(luò)環(huán)境中實(shí)現(xiàn)傳流媒體數(shù)據(jù)的 實(shí)時傳輸。RTP 通常使用 UDP 來進(jìn)行多媒體數(shù)據(jù)的傳輸,但如果需要的話可以使用 TCP 或者 ATM 等其它協(xié)議。

協(xié)議分析 :每一個RTP數(shù)據(jù)報都由頭部(Header)和負(fù)載(Payload)兩個部分組成,其中頭部前 12 個字節(jié)的含義是固定的,而負(fù)載則可以是音頻或者視頻數(shù)據(jù)。

? ? ?RTP 是目前解決流媒體實(shí)時傳輸問題的最好辦法,要在 Linux 平臺上進(jìn)行實(shí)時傳送編程,可以考慮使用一些開放源代碼的 RTP 庫,如 LIBRTP、JRTPLIB 等。JRTPLIB 是一個面向?qū)ο蟮?RTP 庫,它完全遵循 RFC 1889 設(shè)計,在很多場合下是一個非常不錯的選擇。JRTPLIB 是一個用 C++ 語言實(shí)現(xiàn)的 RTP 庫,這個庫使用socket 機(jī)制實(shí)現(xiàn)網(wǎng)絡(luò)通訊 因此可以運(yùn)行在 Windows、Linux、FreeBSD、Solaris、Unix和VxWorks 等多種操作系統(tǒng)上。
二、JRTPLIB 庫的使用方法及程序?qū)崿F(xiàn)
(1)JRTPLIB ?函數(shù) 的使用
a、在使用 JRTPLIB 進(jìn)行實(shí)時流媒體數(shù)據(jù)傳輸之前,首先應(yīng)該生成 RTPSession 類的一個實(shí)例來表示此次 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() 方法來實(shí)現(xiàn)的,該方法同樣也只有一個參數(shù),表示的是以秒為單元的時戳單元。
sess.SetTimestampUnit(1.0/8000.0);

c、當(dāng) RTP 會話成功建立起來之后,接下去就可以開始進(jìn)行流媒體數(shù)據(jù)的實(shí)時傳輸了。首先需要設(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  接收模式后,運(yùn)行程序接收端不能接包。
?IP地址格式出了問題。iner_addr()與ntohl()函數(shù)要用對,否則參數(shù)傳不進(jìn)去,接受列表中無值,當(dāng)然接收不了數(shù)據(jù)包。
5、編譯通過,但測試時接收端不能接收到數(shù)據(jù)。
?可能是接收機(jī)防火墻未關(guān)閉。運(yùn)行:
?#iptables -F
?也可能是IP地址沒有設(shè)置好。運(yùn)行:
?#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)日志

    轉(zhuǎn)載于:https://blog.51cto.com/general/328224

    總結(jié)

    以上是生活随笔為你收集整理的linux 下基于jrtplib库的实时传送实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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