jrtplib:linux下基于jrtplib库的实时传送实现来源: 发布时间:星期四, 2008年12月11日 浏览:7次 评论:0
linux 下基于jrtplib库实时传送实现
gcGfbaiducukSwh、RTP 是进行实时流媒体传输标准协议和关键技术 gcGfbaiducukSwh 实时传输协议(Real-time Transport ProtocolPRT)是在 Internet 上处理多媒体数据流种网络协议利用它能够在对(unicast单播)或者对多(multicast多播)网络环境中实现传流媒体数据实时传输RTP 通常使用 UDP 来进行多媒体数据传输但如果需要话可以使用 TCP 或者 ATM 等其它协议 gcGfbaiducukSwh 协议分析 :每个RTP数据报都由头部(Header)和负载(Payload)两个部分组成其中头部前 12 个字节含义是固定而负载则可以是音频或者视频数据 gcGfbaiducukSwh gcGfbaiducukSwh RTP 是目前解决流媒体实时传输问题最好办法要在 Linux 平台上进行实时传送编程可以考虑使用些开放源代码 RTP 库如 LIBRTP、JRTPLIB 等JRTPLIB 是个面向对象 RTP 库它完全遵循 RFC 1889 设计在很多场合下是个非常不错选择JRTPLIB 是个用 C 语言实现 RTP 库这个库使用 机制实现网络通讯 因此可以运行在 Windows、Linux、FreeBSD、Solaris、Unix和VxWorks 等多种操作系统上 gcGfbaiducukSwh二、JRTPLIB 库使用方法及实现 gcGfbaiducukSwh (1)JRTPLIB 使用 gcGfbaiducukSwh a、在使用 JRTPLIB 进行实时流媒体数据传输之前首先应该生成 RTPSession 类个实例来表示此次 RTP 会话然后 Create 方法来对其进行化操作RTPSession 类 Create 方法只有个参数用来指明此次 RTP 会话所采用端口号 gcGfbaiducukSwh RTPSession sess; sess.Create(5000); gcGfbaiducukSwh gcGfbaiducukSwh b、设置恰当时戳单元是 RTP 会话化过程所要进行另外项重要工作这是通过 RTPSession 类 SetTimestampUnit 方法来实现该方法同样也只有个参数表示是以秒为单元时戳单元 gcGfbaiducukSwh sess.SetTimestampUnit(1.0/8000.0); gcGfbaiducukSwh gcGfbaiducukSwh c、当 RTP 会话成功建立起来之后接下去就可以开始进行流媒体数据实时传输了首先需要设置好数据发送目标地址RTP 协议允许同会话存在多个目标地址这可以通过 RTPSession 类 AddDestination、DeleteDestination 和 ClearDestinations 方法来完成例如下面语句表示是让 RTP 会话将数据发送到本地主机 6000 端口: gcGfbaiducukSwh gcGfbaiducukSwh unsigned long addr = ntohl(inet_addr("127.0.0.1")); gcGfbaiducukSwh sess.AddDestination(addr, 6000); gcGfbaiducukSwh gcGfbaiducukSwh d、目标地址全部指定之后接着就可以 RTPSession 类 SendPacket 方法向所有目标地址发送流媒体数据SendPacket 是 RTPSession 类提供个重载 gcGfbaiducukSwh对于同个 RTP 会话来讲负载类型、标识和时戳增量通常来讲都是相同JRTPLIB 允许将它们设置为会话默认参数这是通过 RTPSession 类 SetDefaultPayloadType、SetDefaultMark 和 SetDefaultTimeStampIncrement 方法来完成为 RTP 会话设置这些默认参数好处是可以简化数据发送例如如果为 RTP 会话设置了默认参数: gcGfbaiducukSwh gcGfbaiducukSwh sess.SetDefaultPayloadType(0); gcGfbaiducukSwh sess.SetDefaultMark(false); gcGfbaiducukSwh sess.SetDefaultTimeStampIncrement(10); gcGfbaiducukSwh gcGfbaiducukSwh gcGfbaiducukSwh gcGfbaiducukSwh之后在进行数据发送时只需指明要发送数据及其长度就可以了: gcGfbaiducukSwh gcGfbaiducukSwh sess.SendPacket(buffer, 5); gcGfbaiducukSwh gcGfbaiducukSwh gcGfbaiducukSwh e、对于流媒体数据接收端首先需要 RTPSession 类 PollData 方法来接收发送过来 RTP 或者 RTCP 数据报由于同个 RTP 会话中允许有多个参与者(源)你既可以通过 RTPSession 类 GotoFirstSource 和 GotoNextSource 方法来遍历所有源也可以通过 RTPSession 类 GotoFirstSourceWithData 和 GotoNextSourceWithData 方法来遍历那些携带有数据源在从 RTP 会话中检测出有效数据源之后接下去就可以 RTPSession 类 GetNextPacket 方法从中抽取 RTP 数据报当接收到 RTP 数据报处理完之后定要记得及时释放 gcGfbaiducukSwh gcGfbaiducukSwhJRTPLIB 为 RTP 数据报定义了三种接收模式其中每种接收模式都具体规定了哪些到达 RTP 数据报将会被接受而哪些到达 RTP 数据报将会被拒绝通过 RTPSession 类 SetReceiveMode 方法可以设置下列这些接收模式: gcGfbaiducukSwh? RECEIVEMODE_ALL 缺省接收模式所有到达 RTP 数据报都将被接受; gcGfbaiducukSwh? RECEIVEMODE_IGNORESOME 除了某些特定发送者之外所有到达 RTP 数据报都将被接受而被拒绝发送者列表可以通过 AddToIgnoreList、DeleteFromIgnoreList 和 ClearIgnoreList 方法来进行设置; gcGfbaiducukSwh? RECEIVEMODE_ACCEPTSOME 除了某些特定发送者之外所有到达 RTP 数据报都将被拒绝而被接受发送者列表可以通过 AddToAcceptList 、DeleteFromAcceptList 和 ClearAcceptList 方法来进行设置 下面是采用第三种接收模式示例 gcGfbaiducukSwh (sess.GotoFirstSourceWithData) { gcGfbaiducukSwh do { gcGfbaiducukSwh sess.AddToAcceptList(remoteIP, allports,portbase); gcGfbaiducukSwh sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME); gcGfbaiducukSwh gcGfbaiducukSwh RTPPacket *pack; gcGfbaiducukSwh pack = sess.GetNextPacket; // 处理接收到数据 gcGfbaiducukSwh delete pack; } gcGfbaiducukSwh while (sess.GotoNextSourceWithData); gcGfbaiducukSwh } gcGfbaiducukSwh gcGfbaiducukSwh gcGfbaiducukSwh (2)流程图 gcGfbaiducukSwh发送:获得接收端 IP 地址和端口号 创建 RTP 会话 指定 RTP 数据接收端 设置 RTP 会话默认参数 发送流媒体数据 gcGfbaiducukSwh接收:获得用户指定端口号 创建RTP会话 设置接收模式 接受RTP数据 检索RTP数据源 获取RTP数据报 删除RTP数据报 gcGfbaiducukSwh gcGfbaiducukSwh gcGfbaiducukSwh三、环境搭建及编译方法 gcGfbaiducukSwh(1)Toolchain安装 gcGfbaiducukSwh 首先找到xscale-arm-toolchain.tgz文件假设该文件包放在/tmp/下 gcGfbaiducukSwh #cd / gcGfbaiducukSwh #tar -zxvf /tmp/xscale-arm-toolchain.tgz gcGfbaiducukSwh 再设置环境变量 gcGfbaiducukSwh #export PATH=/usr/local/arm-linux/bin:$PATH gcGfbaiducukSwh 最后检查下交叉编译工具是否安装成功 gcGfbaiducukSwh #arm-linux-g --version gcGfbaiducukSwh 看是否显示arm-linux-g版本如有则安装成功 gcGfbaiducukSwh(2)JRTPLIB 库交叉编译及安装 gcGfbaiducukSwh 首先从 JRTPLIB 网站(http://lumumba.luc.ac.be/jori/jrtplib/jrtplib.htmll) 下载最新源码包此处使用是jrtplib-2.8.tar假设下载后源码包放在/tmp下执 行下面命令对其解压缩: gcGfbaiducukSwh #cd /tmp gcGfbaiducukSwh #tar -zxvf jrtplib-2.8.tar gcGfbaiducukSwh 然后要对jrtplib进行配置和编译 gcGfbaiducukSwh #cd jrtplib-2.8 gcGfbaiducukSwh #./configure CC=arm-linux-g cross-compile=yes gcGfbaiducukSwh 修改Makefile文件 gcGfbaiducukSwh 将链接命令ld 和ar改为arm-linux-ld和 arm-linux-ar gcGfbaiducukSwh #make gcGfbaiducukSwh 最后再执行如下命令就可以完成 JRTPLIB 安装: gcGfbaiducukSwh #make gcGfbaiducukSwh(3)编译 gcGfbaiducukSwh a、配置编译环境 gcGfbaiducukSwh 可以用export来配置也可以用编写Makefile方法这里采用Makefile gcGfbaiducukSwh 编写Makefile&: gcGfbaiducukSwhINCL = -I/usr/local/ gcGfbaiducukSwhCFLAGS = -pipe -O2 -fno-strength-reduce gcGfbaiducukSwhLFLAGS = /usr/local/lib/libjrtp.a -L/usr/X11R6/lib gcGfbaiducukSwhLIBS = -LX11 -LXext /usr/local/lib/libjrtp.a gcGfbaiducukSwhCC = arm-linux-g gcGfbaiducukSwh gcGfbaiducukSwh:.o gcGfbaiducukSwh $(CC) $(LFLAGS) $(INCL) -o .o $(LIBS) gcGfbaiducukSwh.o:.cpp gcGfbaiducukSwh gcGfbaiducukSwhclean: gcGfbaiducukSwh rm -f gcGfbaiducukSwh rm -f *.o gcGfbaiducukSwh gcGfbaiducukSwh.SUFFIXES:.cpp gcGfbaiducukSwh.cpp.o: gcGfbaiducukSwh $(CC) -c $(CFLAGS) $(INCL) -o $@ $< /* $@表示目标完整名字 */ gcGfbaiducukSwh /* $<表示第个依赖文件名字 */ gcGfbaiducukSwh b、编译 gcGfbaiducukSwh 假设发送和接收分别放在/tmp/send和/tmp/receive目录下 gcGfbaiducukSwh #cd /tmp/send gcGfbaiducukSwh #make gcGfbaiducukSwh #cd /tmp/receive gcGfbaiducukSwh #make gcGfbaiducukSwh gcGfbaiducukSwh四、易出及注意问题 gcGfbaiducukSwh 1、找不到些标准最 基本些头文件 gcGfbaiducukSwh 主要是Toolchain路径没安装对要 严格按照步骤安装 gcGfbaiducukSwh 2、找不到使用jrtplib库中些头文件 gcGfbaiducukSwh 在 jrtplib安装目录下路径下不能再有别目录 gcGfbaiducukSwh 3、recieve接收数据包不能正确提出所要数据 gcGfbaiducukSwh 由于每个RTP数据报都由头部(Header)和负载(Payload)两个部分组成若使用getrawdata是返回整个数据包数据包含传输媒体类型、格式、序列号、时间戳以及是否有附加数据等信息getpayload是返回所发送数据两者定要分清 gcGfbaiducukSwh 4、设置RECEIVEMODE_ACCEPTSOME 接收模式后运行接收端不能接包 gcGfbaiducukSwh IP地址格式出了问题iner_addr与ntohl要用对否则参数传不进去接受列表中无值当然接收不了数据包 gcGfbaiducukSwh 5、编译通过但测试时接收端不能接收到数据 gcGfbaiducukSwh 可能是接收机防火墙未关闭运行: gcGfbaiducukSwh #iptables -F gcGfbaiducukSwh 也可能是IP地址没有设置好运行: gcGfbaiducukSwh #ocnfig eth0 *.*.*.* netmask *.*.*.* gcGfbaiducukSwh 6、使用jrtolib库时在中 后最好加上库所在路径 gcGfbaiducukSwh五、 gcGfbaiducukSwh gcGfbaiducukSwhsend: gcGfbaiducukSwh gcGfbaiducukSwh# <stdio.h> gcGfbaiducukSwh# <.h> gcGfbaiducukSwh# "rtpsession.h" gcGfbaiducukSwh gcGfbaiducukSwh// 处理 gcGfbaiducukSwhvoid checkerror( err) gcGfbaiducukSwh{ gcGfbaiducukSwh (err < 0) { gcGfbaiducukSwh char* errstr = RTPGetErrorString(err); gcGfbaiducukSwh prf("Error:%s\\n", errstr); gcGfbaiducukSwh exit(-1); gcGfbaiducukSwh } gcGfbaiducukSwh} gcGfbaiducukSwh gcGfbaiducukSwh ( argc, char** argv) gcGfbaiducukSwh{ gcGfbaiducukSwh RTPSession sess; gcGfbaiducukSwh unsigned long destip; gcGfbaiducukSwh destport; gcGfbaiducukSwh portbase = 6000; gcGfbaiducukSwh status, index; gcGfbaiducukSwh char buffer[128]; gcGfbaiducukSwh gcGfbaiducukSwh (argc != 3) { gcGfbaiducukSwh prf("Usage: ./sender destip destport\\n"); gcGfbaiducukSwh -1; gcGfbaiducukSwh } gcGfbaiducukSwh gcGfbaiducukSwh // 获得接收端IP地址和端口号 gcGfbaiducukSwh destip = inet_addr(argv[1]); gcGfbaiducukSwh (destip INADDR_NONE) { gcGfbaiducukSwh prf("Bad IP address specied.\\n"); gcGfbaiducukSwh -1; gcGfbaiducukSwh } gcGfbaiducukSwh destip = ntohl(destip); gcGfbaiducukSwh destport = atoi(argv[2]); gcGfbaiducukSwh gcGfbaiducukSwh // 创建RTP会话 gcGfbaiducukSwh status = sess.Create(portbase); gcGfbaiducukSwh checkerror(status); gcGfbaiducukSwh gcGfbaiducukSwh // 指定RTP数据接收端 gcGfbaiducukSwh status = sess.AddDestination(destip, destport); gcGfbaiducukSwh checkerror(status); gcGfbaiducukSwh gcGfbaiducukSwh // 设置RTP会话默认参数 gcGfbaiducukSwh sess.SetDefaultPayloadType(0); gcGfbaiducukSwh sess.SetDefaultMark(false); gcGfbaiducukSwh sess.SetDefaultTimeStampIncrement(10); gcGfbaiducukSwh gcGfbaiducukSwh // 发送流媒体数据 gcGfbaiducukSwh index = 1; gcGfbaiducukSwh do { gcGfbaiducukSwh sprf(buffer, "%d: RTP packet", index ); gcGfbaiducukSwh sess.SendPacket(buffer, strlen(buffer)); gcGfbaiducukSwh prf("Send packet !\\n"); gcGfbaiducukSwh } while(1); gcGfbaiducukSwh gcGfbaiducukSwh 0; gcGfbaiducukSwh} gcGfbaiducukSwh gcGfbaiducukSwh gcGfbaiducukSwh gcGfbaiducukSwh gcGfbaiducukSwh gcGfbaiducukSwh gcGfbaiducukSwhreceive: gcGfbaiducukSwh gcGfbaiducukSwh# <stdio.h> gcGfbaiducukSwh# "rtpsession.h" gcGfbaiducukSwh# "rtppacket.h" gcGfbaiducukSwh gcGfbaiducukSwh// 处理 gcGfbaiducukSwhvoid checkerror( err) gcGfbaiducukSwh{ gcGfbaiducukSwh (err < 0) { gcGfbaiducukSwh char* errstr = RTPGetErrorString(err); gcGfbaiducukSwh prf("Error:%s\\n", errstr); gcGfbaiducukSwh exit(-1); gcGfbaiducukSwh } gcGfbaiducukSwh} gcGfbaiducukSwh gcGfbaiducukSwh ( argc, char** argv) gcGfbaiducukSwh{ gcGfbaiducukSwh RTPSession sess; gcGfbaiducukSwh localport,portbase; gcGfbaiducukSwh status; gcGfbaiducukSwh unsigned long remoteIP; gcGfbaiducukSwh (argc != 4) { gcGfbaiducukSwh prf("Usage: ./sender localport\\n"); gcGfbaiducukSwh -1; gcGfbaiducukSwh } gcGfbaiducukSwh gcGfbaiducukSwh // 获得用户指定端口号 gcGfbaiducukSwh gcGfbaiducukSwh remoteIP = inet_addr(argv[1]); gcGfbaiducukSwh localport = atoi(argv[2]); gcGfbaiducukSwh portbase = atoi(argv[3]); gcGfbaiducukSwh // 创建RTP会话 gcGfbaiducukSwh status = sess.Create(localport); gcGfbaiducukSwh checkerror(status); gcGfbaiducukSwh gcGfbaiducukSwh //RTPHeader *rtphdr; gcGfbaiducukSwh unsigned long timestamp1; gcGfbaiducukSwh unsigned char * RawData; gcGfbaiducukSwh unsigned char temp[30]; gcGfbaiducukSwh lengh ,i; gcGfbaiducukSwh bool allports = 1; gcGfbaiducukSwh gcGfbaiducukSwh sess.AddToAcceptList(remoteIP, allports,portbase); gcGfbaiducukSwh gcGfbaiducukSwh do { gcGfbaiducukSwh //设置接收模式 gcGfbaiducukSwh sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME); gcGfbaiducukSwh sess.AddToAcceptList(remoteIP, allports,portbase); gcGfbaiducukSwh gcGfbaiducukSwh // 接受RTP数据 gcGfbaiducukSwh status = sess.PollData; gcGfbaiducukSwh gcGfbaiducukSwh gcGfbaiducukSwh // 检索RTP数据源 gcGfbaiducukSwh (sess.GotoFirstSourceWithData) { gcGfbaiducukSwh do { gcGfbaiducukSwh gcGfbaiducukSwh RTPPacket* packet; gcGfbaiducukSwh // 获取RTP数据报 gcGfbaiducukSwh while ((packet = sess.GetNextPacket) != NULL) { gcGfbaiducukSwh prf("Got packet !\n"); gcGfbaiducukSwh gcGfbaiducukSwh timestamp1 = packet->GetTimeStamp; gcGfbaiducukSwh lengh=packet->GetPayloadLength; gcGfbaiducukSwh RawData=packet->GetPayload; gcGfbaiducukSwh gcGfbaiducukSwh for(i=0;i<lengh;i){ gcGfbaiducukSwh temp[i]=RawData[i]; gcGfbaiducukSwh prf("%c",temp[i]); gcGfbaiducukSwh } gcGfbaiducukSwh temp[i]='\0'; gcGfbaiducukSwh prf(" timestamp: %d lengh=%d data:%s\n",timestamp1,lengh,&temp); gcGfbaiducukSwh // 删除RTP数据报 gcGfbaiducukSwh gcGfbaiducukSwh delete packet; gcGfbaiducukSwh } gcGfbaiducukSwh } while (sess.GotoNextSourceWithData); gcGfbaiducukSwh } gcGfbaiducukSwh } while(1); gcGfbaiducukSwh gcGfbaiducukSwh 0; gcGfbaiducukSwh 0
相关文章
读者评论
发表评论 |