压缩包可以从这里获得: 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
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 –host=arm-linux –prefix=/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
。
对于本博客有任何问题的朋友可加Q:992139738