专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »嵌入式开发 » jrtplib:linux下基于jrtplib库的实时传送实现 »正文

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条 分0页

发表评论

  • 昵称:
  • 内容: