linux 下基于jrtplib库的实时传送实现
一、RTP 是进行实时流媒体传输的标准协议和关键技术
实时传输协议(Real-time Transport Protocol,PRT)是在 Internet 上处理多媒体数据流的一种网络协议,利用它能够在一对一(unicast,单播)或者一对多(multicast,多播)的网络环境中实现传流媒体数据的 实时传输。RTP 通常使用 UDP 来进行多媒体数据的传输,但如果需要的话可以使用 TCP 或者 ATM 等其它协议。

协议分析 :每一个RTP数据报都由头部(Header)和负载(Payload)两个部分组成,其中头部前 12 个字节的含义是固定的,而负载则可以是音频或者视频数据。

RTP 是目前解决流媒体实时传输问题的最好办法,要在 Linux 平台上进行实时传送编程,可以考虑使用一些开放源代码的 RTP 库,如 LIBRTP、JRTPLIB 等。JRTPLIB 是一个面向对象的 RTP 库,它完全遵循 RFC 1889 设计,在很多场合下是一个非常不错的选择。JRTPLIB 是一个用 C++ 语言实现的 RTP 库,这个库使用socket 机制实现网络通讯 因此可以运行在 Windows、Linux、FreeBSD、Solaris、Unix和VxWorks 等多种操作系统上。
二、JRTPLIB 库的使用方法及程序实现
(1)JRTPLIB  函数 的使用
a、在使用 JRTPLIB 进行实时流媒体数据传输之前,首先应该生成 RTPSession 类的一个实例来表示此次 RTP 会话,然后调用 Create() 方法来对其进行初始化操作。RTPSession 类的 Create() 方法只有一个参数,用来指明此次 RTP 会话所采用的端口号。
RTPSession sess;  sess.Create(5000);

b、设置恰当的时戳单元,是 RTP 会话初始化过程所要进行的另外一项重要工作,这是通过调用 RTPSession 类的 SetTimestampUnit() 方法来实现的,该方法同样也只有一个参数,表示的是以秒为单元的时戳单元。
sess.SetTimestampUnit(1.0/8000.0);

c、当 RTP 会话成功建立起来之后,接下去就可以开始进行流媒体数据的实时传输了。首先需要设置好数据发送的目标地址,RTP 协议允许同一会话存在多个目标地址,这可以通过调用 RTPSession 类的 AddDestination()、DeleteDestination() 和 ClearDestinations() 方法来完成。例如,下面的语句表示的是让 RTP 会话将数据发送到本地主机的 6000 端口:

unsigned long addr = ntohl(inet_addr("127.0.0.1"));
sess.AddDestination(addr, 6000);

d、目标地址全部指定之后,接着就可以调用 RTPSession 类的 SendPacket() 方法,向所有的目标地址发送流媒体数据。SendPacket() 是 RTPSession 类提供的一个重载函数
对于同一个 RTP 会话来讲,负载类型、标识和时戳增量通常来讲都是相同的,JRTPLIB 允许将它们设置为会话的默认参数,这是通过调用 RTPSession 类的 SetDefaultPayloadType()、SetDefaultMark() 和 SetDefaultTimeStampIncrement() 方法来完成的。为 RTP 会话设置这些默认参数的好处是可以简化数据的发送,例如,如果为 RTP 会话设置了默认参数:

sess.SetDefaultPayloadType(0);
 sess.SetDefaultMark(false);  
sess.SetDefaultTimeStampIncrement(10);

之后在进行数据发送时只需指明要发送 的数据及其长度就可以了:

sess.SendPacket(buffer, 5);

e、对于流媒体数据的接收端,首先需要调用 RTPSession 类的 PollData() 方法来接收发送过来的 RTP 或者 RTCP 数据报。由于同一个 RTP 会话中允许有多个参与者(源),你既可以通过调用 RTPSession 类的 GotoFirstSource() 和 GotoNextSource() 方法来遍历所有的源,也可以通过调用 RTPSession 类的 GotoFirstSourceWithData() 和 GotoNextSourceWithData() 方法来遍历那些携带有数据的源。在从 RTP 会话中检测出有效的数据源之后,接下去就可以调用 RTPSession 类的 GetNextPacket() 方法从中抽取 RTP 数据报,当接收到的 RTP 数据报处理完之后,一定要记得及时释放。

JRTPLIB 为 RTP 数据报定义了三种接收模式,其中每种接收模式都具体规定了哪些到达的 RTP 数据报将会被接受,而哪些到达的 RTP 数据报将会被拒绝。通过调用 RTPSession 类的 SetReceiveMode() 方法可以设置下列这些接收模式:
? RECEIVEMODE_ALL  缺省的接收模式,所有到达的 RTP 数据报都将被接受;
? RECEIVEMODE_IGNORESOME  除了某些特定的发送者之外,所有到达的 RTP 数据报都将被接受,而被拒绝的发送者列表可以通过调用 AddToIgnoreList()、DeleteFromIgnoreList() 和 ClearIgnoreList() 方法来进行设置;
? RECEIVEMODE_ACCEPTSOME  除了某些特定的发送者之外,所有到达的 RTP 数据报都将被拒绝,而被接受的发送者列表可以通过调用 AddToAcceptList ()、DeleteFromAcceptList 和 ClearAcceptList () 方法来进行设置。 下面是采用第三种接收模式的程序示例。
if (sess.GotoFirstSourceWithData()) {  
 do {  
  sess.AddToAcceptList(remoteIP, allports,portbase);
         sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);

RTPPacket *pack;        
   pack = sess.GetNextPacket();            // 处理接收到的数据    
   delete pack;   }
 while (sess.GotoNextSourceWithData());
 }

(2)程序流程图
发送:获得接 收端的 IP 地址和端口号        创建 RTP 会话        指定 RTP 数据接收端 设置 RTP 会话默认参数   发送流媒体数据
接收:获得用户指定的端口号  创建RTP会话  设置接收模式  接受RTP数据  检索RTP数据源  获取RTP数据报  删除RTP数据报

三、环境搭建及编译方法

引用
(1)Toolchain的安装
首先找到xscale-arm-toolchain.tgz文件,假设该文件包放在/tmp/下
#cd /
#tar -zxvf /tmp/xscale-arm-toolchain.tgz
再设置环境变量
#export PATH=/usr/local/arm-linux/bin:$PATH
最后检查一下交叉编译工具是否安装成功
#arm-linux-g++ --version
看是否显示arm-linux-g++的版本,如有则安装成功。
(2)JRTPLIB 库的交叉编译及安装
首先从 JRTPLIB 的网站(http://lumumba.luc.ac.be/jori/jrtplib/jrtplib.htmll) 下载最新的源码包,此处使用的是jrtplib-2.8.tar,假设下载后的源码包放在/tmp下,执 行下面的命令对其解压缩:
#cd /tmp
#tar -zxvf jrtplib-2.8.tar
然后要对jrtplib进行配置和编译
#cd jrtplib-2.8
#./configure CC=arm-linux-g++ cross-compile=yes
修改Makefile文件
将链接命令ld 和ar改为arm-linux-ld和 arm-linux-ar
#make
最后再执行如下命令就可以完成 JRTPLIB 的安装:
#make install
(3)程序编译
a、配置编译环境
可以用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 $@ $<         /*  $@表示目标的完整名字      */
         /* $<表示第一个依赖文件的名字 */
b、编译
假设发送和接收程序分别放在/tmp/send和/tmp/receive目录下
#cd /tmp/send
#make
#cd /tmp/receive
#make

四、易出错误及注意问题

引用
1、找不到一些标准的最 基本的一些头文件。
 主要是因为Toolchain路径没安装对,要 严格按照步骤安装。
2、找不到使用的jrtplib库中的一些头文件。
 在 jrtplib的安装目录下,include路径下不能再有别的目录。
3、recieve函数接收数据包不能正确提出所要数据。
 由于每一个RTP数据报都由头部(Header)和负载(Payload)两个部分组成,若使用getrawdata()是返回整个数据包的数据,包含 传输媒体的类型、格式、序列号、时间戳以及是否有附加数据等信息。getpayload()函数是返回所发送的数据。两者一定要分清。
4、设置RECEIVEMODE_ACCEPTSOME  接收模式后,运行程序接收端不能接包。
 IP地址格式出了问题。iner_addr()与ntohl()函数要用对,否则参数传不进去,接受列表中无值,当然接收不了数据包。
5、编译通过,但测试时接收端不能接收到数据。
 可能是接收机防火墙未关闭。运行:
 #iptables -F
 也可能是IP地址没有设置好。运行:
 #ifocnfig eth0  *.*.*.*  netmask *.*.*.*
6、使用jrtolib库时,在程序中include 后最好加上库所在的路径。

五、程序

send:

view plainprint?
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "rtpsession.h"
  4. // 错误处理函数
  5. void checkerror(int err)
  6. {
  7. if (err < 0) {
  8. char* errstr = RTPGetErrorString(err);
  9. printf("Error:%s\\n", errstr);
  10. exit(-1);
  11. }
  12. }
  13. int main(int argc, char** argv)
  14. {
  15. RTPSession sess;
  16. unsigned long destip;
  17. int destport;
  18. int portbase = 6000;
  19. int status, index;
  20. char buffer[128];
  21. if (argc != 3) {
  22. printf("Usage: ./sender destip destport\\n");
  23. return -1;
  24. }
  25. // 获得接收端的IP地址和端口号
  26. destip = inet_addr(argv[1]);
  27. if (destip == INADDR_NONE) {
  28. printf("Bad IP address specified.\\n");
  29. return -1;
  30. }
  31. destip = ntohl(destip);
  32. destport = atoi(argv[2]);
  33. // 创建RTP会话
  34. status = sess.Create(portbase);
  35. checkerror(status);
  36. // 指定RTP数据接收端
  37. status = sess.AddDestination(destip, destport);
  38. checkerror(status);
  39. // 设置RTP会话默认参数
  40. sess.SetDefaultPayloadType(0);
  41. sess.SetDefaultMark(false);
  42. sess.SetDefaultTimeStampIncrement(10);
  43. // 发送流媒体数据
  44. index = 1;
  45. do {
  46. sprintf(buffer, "%d: RTP packet", index ++);
  47. sess.SendPacket(buffer, strlen(buffer));
  48. printf("Send packet !\\n");
  49. } while(1);
  50. return 0;
  51. }

#include <stdio.h> #include <string.h> #include "rtpsession.h" // 错误处理函数 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]);  // 创建RTP会话  status = sess.Create(portbase);  checkerror(status);  // 指定RTP数据接收端  status = sess.AddDestination(destip, destport);  checkerror(status);  // 设置RTP会话默认参数  sess.SetDefaultPayloadType(0);  sess.SetDefaultMark(false);  sess.SetDefaultTimeStampIncrement(10);  // 发送流媒体数据  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?
  1. #include <stdio.h>
  2. #include "rtpsession.h"
  3. #include "rtppacket.h"
  4. // 错误处理函数
  5. void checkerror(int err)
  6. {
  7. if (err < 0) {
  8. char* errstr = RTPGetErrorString(err);
  9. printf("Error:%s\\n", errstr);
  10. exit(-1);
  11. }
  12. }
  13. int main(int argc, char** argv)
  14. {
  15. RTPSession sess;
  16. int localport,portbase;
  17. int status;
  18. unsigned long remoteIP;
  19. if (argc != 4) {
  20. printf("Usage: ./sender localport\\n");
  21. return -1;
  22. }
  23. // 获得用户指定的端口号
  24. remoteIP = inet_addr(argv[1]);
  25. localport = atoi(argv[2]);
  26. portbase = atoi(argv[3]);
  27. // 创建RTP会话
  28. status = sess.Create(localport);
  29. checkerror(status);
  30. //RTPHeader *rtphdr;
  31. unsigned long timestamp1;
  32. unsigned char * RawData;
  33. unsigned char temp[30];
  34. int lengh ,i;
  35. bool allports = 1;
  36. sess.AddToAcceptList(remoteIP, allports,portbase);
  37. do {
  38. //设置接收模式
  39. sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);
  40. sess.AddToAcceptList(remoteIP, allports,portbase);
  41. // 接受RTP数据
  42. status = sess.PollData();
  43. // 检索RTP数据源
  44. if (sess.GotoFirstSourceWithData()) {
  45. do {
  46. RTPPacket* packet;
  47. // 获取RTP数据报
  48. while ((packet = sess.GetNextPacket()) != NULL) {
  49. printf("Got packet !\n");
  50. timestamp1 = packet->GetTimeStamp();
  51. lengh=packet->GetPayloadLength();
  52. RawData=packet->GetPayload();
  53. for(i=0;i<lengh;i++){
  54. temp[i]=RawData[i];
  55. printf("%c",temp[i]);
  56. }
  57. temp[i]='\0';
  58. printf("  timestamp: %d lengh=%d data:%s\n",timestamp1,lengh,&temp);
  59. // 删除RTP数据报
  60. delete packet;
  61. }
  62. } while (sess.GotoNextSourceWithData());
  63. }
  64. } while(1);
  65. return 0;
  66. }

#include <stdio.h> #include "rtpsession.h" #include "rtppacket.h" // 错误处理函数 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]);  // 创建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 { //设置接收模式        sess.SetReceiveMode(RECEIVEMODE_ACCEPTSOME);   sess.AddToAcceptList(remoteIP, allports,portbase);    // 接受RTP数据    status = sess.PollData();     // 检索RTP数据源    if (sess.GotoFirstSourceWithData()) {      do {                RTPPacket* packet;        // 获取RTP数据报        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数据报            delete packet;        }      } while (sess.GotoNextSourceWithData());    }  } while(1);  return 0; } 相关日志

转载于:https://blog.51cto.com/general/328224

linux 下基于jrtplib库的实时传送实现相关推荐

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

    linux 下基于jrtplib库的实时传送实现 一.RTP 是进行实时流媒体传输的标准协议和关键技术  实时传输协议(Real-time Transport Protocol,PRT)是在 Inte ...

  2. Linux下基于Libmad库的MP3音乐播放器编写

    linux下基于Libmad库的MP3音乐播放器编写 libmad是一个开源mp3解码库,其对mp3解码算法做了很多优化,性能较好,很多播放器如mplayer.xmms等都是使用这个开源库进行解码的: ...

  3. Linux下基于SDL库贪吃蛇游戏

    Linux下基于SDL库贪吃蛇游戏   SDL(Simple DirectMediaLayer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成.SDL提供了数种控制图像.声音.输出入的函数,让开 ...

  4. Linux下使用JRTPLIB进行实时流媒体编程

    收藏于 2013-04-22 迁移自本人的百度空间 -------------------------------- 转载自 http://blog.csdn.net/dongliqiang2006/ ...

  5. 基于JRTPLIB库的RTP数据传输设计文档(1)

    关键词:JRTPLIB  RTP  ARM  交叉编译 BCNG  项 目 组 技 术 文 档                            基于JRTPLIB库的RTP数据传输设计文档   ...

  6. 基于JRTPLIB库的RTP数据传输设计文档

    http://xiyong8260.blog.163.com/blog/static/665146212008824112748499/  版权所有,若转载,请注明出处,谢谢合作.  关键词:JRTP ...

  7. Linux下curses函数库的详细介绍

    Linux下curses函数库的详细介绍 curses库介绍 安装 curses库函数介绍 初始化和重置函数 管理屏幕的函数 输出到屏幕 从屏幕读取 清除屏幕 移动光标 字符属性 管理键盘的函数 键盘 ...

  8. Linux下Rsync+sersync实现数据实时同步

    一.为什么要用Rsync+sersync架构? 1.sersync是基于Inotify开发的,类似于Inotify-tools的工具 2.sersync可以记录下被监听目录中发生变化的(包括增加.删除 ...

  9. Linux下基于ffmpeg音视频解码

    Linux下基于ffmpeg音视频解码 1.ffmpeg简介   FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序.采用LGPL或GPL许可证.它提供了录制.转换以 ...

最新文章

  1. 美国运通使用AI技术检测欺诈行为 增强安全性
  2. SAP Commerce Extension的Web应用启动问题
  3. 怎么样实现对一个对象的深拷贝
  4. ASP.NET常用代码
  5. 计算机图形学(一) 视频显示设备_3_随机扫描显示器
  6. Luogu2481 SDOI2010 代码拍卖会 DP、组合
  7. CSS五种定位(相对定位、绝对定位、固定定位、static定位、sticky 定位)模式学习笔记
  8. go1.5源代码安装
  9. 使用nmake编译Gdal源代码(Win10, VS2022)
  10. matlab仿真超声波测距,超声波测距仪制作-Arduino中文社区 - Powered by Discuz!
  11. 几款好用证件照制作工具推荐
  12. 因为文件共享不安全,所以你不能连接到文件共享。此共享需要过时的SMB1协议
  13. 【IDEA】IDEA常用配置
  14. 《我的世界》游戏攻略:如何一建生成房屋指令?
  15. Cadence Orcad Capture新建原理图Symbol及新建和添加元件库到工程的方法图文教程及视频演示
  16. tomcat如何调优
  17. 201621123031 《Java程序设计》第7周学习总结
  18. DLL入口点函数DllMain .
  19. 汽车库存进出管理系统
  20. LRU(Least Recently Used)算法简单介绍

热门文章

  1. python集合运算_python-集合及其运算
  2. 微信小程序电商实战-商品列表流式布局
  3. python OpenCV 绘图函数
  4. 计算机病毒按破坏性分为哪两类,计算机导论复习要点.doc
  5. aov建立Java模拟,数据结构之---C语言实现拓扑排序AOV图
  6. CString比较相等不得不说的故事
  7. Java 面试知识点解析(五)——网络协议篇
  8. Dubbo 源码分析 - SPI 机制
  9. Java HashMap工作原理深入探讨
  10. 有史以来最简单的三层实例(C#)