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

    Window 平台实时流媒体编程
压缩包可以从这里获得: http://www.bairuitech.com/upimg/soft/jrtplib-3.7.1.rar
下载 jrtplib-3.7.1.rar 后,首先将其解压到一个临时文件夹中,然后开始后续工作。
首先需要强调的是, jrtplib 是一个库而不是应用程序,编译后我们获得的是 .lib 文件。这个文件是用来实现 RTP 协议的,意义和我们在写 WIN32 程序时用到的 kernel.lib 一样。
解压后的文件夹中包含两个目录, jrtplib-3.7.1 jthread-1.2.1 ,打开这两个目录后我们可以看到下面又有两个同名的目录,为了后面能顺利编译,我们把同名目录下的文件全部考到上一级目录中,就是说把 f:\jrtplib-3.7.1\jrtplib-3.7.1\*.* 复制到 f:\jrtplib-3.7.1\ 。同理,把 f:\jthread-1.2.1\jthread-1.2.1\*.* 复制到 f:\jthread-1.2.1\
完成上述步骤后我们就可以开始编译库文件了。
Windows 平台下建议使用 Visual C++6.0
首先编译多线程库 jthread ,在 vc6 中直接打开工作区文件 jthread.dsw ,改变工程设置,选中 source file 下的文件,点右键选择 setting ,确保 code generation Use run-time library debug mulitithreaded DLL debug mulitithreaded
然后选 build 就可以了,和上面一样的方法完成 jrtpthread 的编译。这个底下的文件比 jthread 多一些。
默认产生的文件是 jthread.lib jrtplib.Lib, 这两个文件分别位于两个文件夹下的 debug 文件夹下,将它们复制到 VC6 lib 文件夹下。
完成上述工作后我们就可以开始尝试编译 jrtplib 附带的 examples
创建一个新的 Win32 Console 应用程序项目,添加 example 文件到 source files 文件夹中,然后添加 jrtplib 工程下的所有 .h 头文件,这里我们可以用 VC6 提供的一个功能偷懒:)将 jrtplib 项目添加到本工作区,然后将 Header Files 下的所有文件复制到我们创建的工程的 Header Files 文件夹里面。
修改 example.cpp 文件,在文件开始添加
#pragma comment(lib, "jrtplib.lib")
#pragma comment(lib, "jthread.lib")
#pragma comment(lib, "WS2_32.lib")
或者在 VC a) Project->Settings->Link Object/library modules: 添加 jthread.lib jrtplib.lib
b) Link
中添加 ws2_32.lib
检查 code generationdebug mulitithreaded DLL debug mulitithreaded ,方法同上文中检查库文件的方法。
最后就可以编译、连接、生成可执行文件了。
3、 具体流程图
 
 
 
 
一.    调试记录
(1). 输入端口, IP 后出错
ERROR: Can't retrieve login name
这是 rtpsession.cpp 中的 createCNAME 函数有问题
if (!gotlogin)
  {
  //     char *logname = getenv("LOGNAME");
         if (logname == 0)
                return ERR_RTP_SESSION_CANTGETLOGINNAME;
         strncpy((char *)buffer,logname,*bufferlength);
  }
logname 要求获得登陆名,而板子一般没有登陆名,将其强制改为 root 即可
if (!gotlogin)
  {
  //     char *logname = getenv("LOGNAME");
         char *logname = "root";
         if (logname == 0)
                return ERR_RTP_SESSION_CANTGETLOGINNAME;
         strncpy((char *)buffer,logname,*bufferlength);
  }
 
2 )板子和 PC 收发数据不能接收
PC 和板子上同时运行 jrtplib 例子程序 example1 (此程序可同时收发),在 PC 和板子之间收发数据,程序能够运行但双方都接收不到数据,结果如下:
查阅资料发现是字节序和位域的问题, x86 pc 机是用小端字节序 (little endian), 而嵌入式平台一般是大端字节序 (big endian), 可能是由于字节序的不同,导致了明明存在数据包,却认不出来的问题。
这是一个位域结构体, jrtplib 库使用哪种字节序完全取决于 RTP_BIG_ENDIAN 的定义,这样问题就简单化了。
      看了一下我编译 arm jrtplib 库的 rtpconfig_unix.h 这个文件,里面果然定义了一个 RTP_BIG_ENDIAN ,所以要和 pc 采用的小端字节序一样,先是直接在 rtpconfig_unix.h 中注释掉了
然后在重新编译库,执行
./configure �Chost=arm-linux �Cprefix=/usr/local/arm/2.95.3
make
make install
完了再次运行 example1 ,还是不行,查看 rtpconfig_unix.h 发现刚注释掉到内容又恢复了,
最后查找发现是此文件是由 ./configure 命令生成的,所以先执行 ./configure 命令,然后再注释上面的内容,最后
make
make install
编译完成再次运行 example1 ,能受到数据包,结果如下:
 
3 )自己写的接收程序写文件出错
接收端程序是在 example3 的基础上修改的,收到到数据包信息全部存在
RTPPacket *pack;
这个类指针当中,可以通过
uint8_t *data;
size_t *length;
data=pack->GetPayloadData();
length=pack->getPayloadLength();
提取出负载数据和负载长度。
收到数据以后以文件形式存下来。
if((write(outfile,data,length))<0)
  {
         perror("write outfile error;");
         return -1;
  }
最开始把打开文件放在开头,写入文件放在接收数据之后,但一直不能正确写文件,提示:
bad file descriptor
后来发现把打开文件放到写文件之前(即在接收数据到 while 循环之内)可以正确写数据,分析原因觉得可能是由于接收程序是一个多线程控制的而引起的。但是这样每次接收都要打开文件,会导致接收速度变慢,试着把打开文件放到循环外边发现也可以正确写数据,具体是什么原因导致这样暂时还不清楚。
 
4 )接收数据时有数据丢失现象,发送端发送数据时发现发送速度太快,所以数据瞬间发完,而不像例子程序一样一包一包的发送,最开始一直以为是设置时戳单元和时戳增量有问题,
sessparams.SetOwnTimestampUnit(1.0/1000.0);
sess.SetDefaultTimestampIncrement(10);
但改了几次还是没有变化,最后仔细对比例子程序,发现是
RTPTime ::Wait(RTPTime(0,0));
这个函数的位置放错了,此函数的作用就是发完一个包后等待一定时间(其中括号中第一个参数表示秒,第二个表示微秒),发送程序中将其放到了 while 循环之外,没有了这个等待时间而接收端还是以此间隔接收数据当然会丢失数据了,将其挪到循环之内就可以了。
 
二.    存在的问题和拟采取的解决方案
现在接收到的数据是以文件的形式存下来的,但是最后想要达到的目的是与 MPlayer 结合起来,使视频采集,压缩后的数据在接收端能够实时的播放出来,现在存在的问题就是如何把收到的数据流传到 MPlayer 中实时播放,下一阶段的工作首先是将 MPlayer 的源代码研究清楚,然后再想办法将接收数据实时传给 MPlayer

你可能感兴趣的:(文档,设计,数据传输,休闲,RTP)