视频监控系统的构建(2)———jrtplib库的使用教程(RTP数据的发送与接收)

可以对照jrtplib样例12看以下内容。

一、创建一个RTP对话的步骤:

1.使用RTPSession类创建一个会话对象sess/session

2.通过RTP会话的参数类RTPSessionParams创建一个参数设置的对象sessparams/sessionparams。具体设置的属性有:时间戳单元(SetOwnTimestampUnit),是否允许接受自己的数据(SetAcceptOwnPackets)

3.传递参数类(RTPTransmissionParams)下面的有基于UDPIPV4的传递参数的派生类(RTPUDPv4TransmissionParams),除此之外,还有基于UDPIPV6的派生类,一般就使用头第一个了。用于设置本机的数据传递参数,主要是RTP数据包中的首部参数,本机要使用的端口号(偶数)。

4.通过会话对象sess/sessionCreate方法调用34中的两个类完成对话的创建。

5.IPV4目标地址类(RTPIPv4Address)创建的时候,完成目标端口号和目标ip地址。

6.通过会话对象sess/session的方法AddDestination()将创建的目标地址对象添加到发送到队列中,这里可以添加多个目标地址。

7.以上就是使用jrtplib包进行TCP通信的通用步骤。

说明:

1.端口号选择偶数是因为在jrtplib中偶数位用于RTP通信,然后自动将下一数字(奇数)用于RTCP通信。

2.创建RTP会话依靠RTPSession类的方法,其他的三个类RTPSessionParamsRTPTransmissionParamsRTPIPv4Address作为RTPSession的参数分别为其提供RTP会话所需要的时间戳单元、本机的传递参数设置、以及目标主机的IP地址和端口号,样例中一般先创建前两个类,完成RTP对话创建,最后使用第三个类添加目标主机的地址,也可以添加多个目标主机,就是发往不同的主机上。


二、实现RTP数据的发送与接受

发送数据:

数据的发送由一个重载函数完成

1. intjrtplib::RTPSession::SendPacket(const void* data,size_t len)

2. intjrtplib::RTPSession::SendPacket(const void* data,size_t len,uint8_tpt,bool mark,uint32_t timetampinc)

第二个函数相对于第一个函数多了ptp填充),M标志位,以及时间戳,这几个参数都是RTP首部包中需要的部分。下图是RTP包的首部格式,不太明白的可以看看相关RTP包的介绍,红色标注对应这三个参数,其他的暂时不用关心。

如果需要使用第一个函数发送数据,需要设置先将这三个参数设置成默认值。具体设置通过RTP会话对象的三个属性完成。

session.SetDefaultPayloadType(96);

session.SetDefaultMark(false);

session.SetDefaultTimestampIncrement(160);

重要说明:

    在创建一个TCP对话和发送数据中两次用到了与时间戳相关的参数(蓝色处),这里解释一下这两处分别代表什么意思,该如何设置。

    第一处是RTP会话的参数类RTPSessionParams,这里需要设置基本的时钟单元,例如,一个8000hz的声音信号,接受端每接收一个采样信号的时间就是要增加1/8000s。这个就是传递这个信号最基本的时钟单元。sessionparams.SetOwnTimestampUnit(1.0/8000.0);再例如:一个20帧的图像,每传送一幅图像过去,时钟信号需要增加1/20s.

    第二处是RTP会话对象的默认时间戳属性(蓝色标记处),假设我们一个每一个RTP包中包含一个20ms的声音信号(对于声音而言,每一个字节就是一个采样信号),则这一个包传送过去,时间需要增加多久呢?0.02s/(1/8000s)=160。得到的160就是以第一处设置的基本时钟单元为单位的传送这20ms的声音信号所需要的时间。

    最后,我们再看第一处设置的一定要是(1.0/8000.0)吗?答案应该是否定的,第一处增加或者减少几倍,对应的第二处增加或者减少几倍,只要能够保证第二处的时钟单元传送所需的时间正确就可以(猜测,还未证实,应该是这样的)。

接收数据:

    接收端首选要使用RTPSession的成员函数poll接受来自不同会话参与者的数据(不同的IP地址发来的数据,这里称之为会话参与者)。

    在数据接受端,关于RTP会话参与者以及数据包检索等信息,可以在对RTPSession类的成员函数RTPSession::BegainDataAccessRTPSession::EndDataAceess的调用之间完成。这种方式是为了保证你所使用的数据不会被其他隐藏线程所调用。使用RTPSession::GotoFirstSourceRTPSession::GotoNextSource两个成员函数的迭代找出你所需要的会话参与者,当前被选中的会话参与者的数据包可以通过RTPSession::GetNextPacket函数获取,该函数返回一个RTPPacket类的对象。这是本文中提到来的第五个类(三个与参数RTP会话的参数设置有关,一个是贯穿始终的RTP会话类(RTPSession)。这个是用于数据接收的类RTPPacket)这个包文件中所有数据(包括RTP首部的各种信息、以及负载数据)都可以通过该类的成员函数得到。

例子:

status=session.Poll();
check(status);
 
status=session.BeginDataAccess();
if (session.GotoFirstSource())
{
    do
    {
        RTPPacket *packet;
        while ((packet = session.GetNextPacket()) != 0)
        {
            std::cout << "Got packet with extended sequence number " 
                      << packet->GetExtendedSequenceNumber() 
                      << " from SSRC " << packet->GetSSRC() 
                      << std::endl;
            session.DeletePacket(packet);
        }
    } while (session.GotoNextSource());
}
session.EndDataAccess();

再次说明

1.RTPSession::GetNextPacket函数是获取当前参与者的数据包,而不是下一个

2.packet->GetPayloadData()用来获取负载数据

3.除此之外,如果想要获取发送报告,接受报告,SDES等数据可以通过RTPSsion类的成员函数GetCurrentSourceInfo函数来获取。这个函数返回的是一个RTPSourceData类。

4.文中所说的会话参与者意思是:数据接受端接受不止一个IP主机发送过来的数据,不同的参与者指的就是不同IP主机。

三、与时间相关的几个函数的解释

与时间相关的类是RTPTime类。其功能如下

1、构造函数

jrtplib::RTPTime::RTPTime(double t)//s为单位

jrtplib::RTPTime::RTPTime(int64_t seconds, uint32_t microseconds )//以(sms)为单位。

通过RTPTime构造一个延时类

例如:RTPTimedelay(0.02)。这个时候并没有延时,只是构造了一个需要延时0.02sdealy对象。

2、成员函数

(1) RTPTime jrtplib::RTPTime::CurrentTime() 获取当前的时间,这个时间是以s为单位,从世界标准时间的19701100:00:00开始算起为第0s

例如:RTPTimestarttime =RTPTime::CurrentTime();构造一个RTPTime的对象,并且对其进行类的成员函数进行操作,等同于

RTPTime starttime

starttime.CurrentTime();

(2)void jrtplib::RTPTime::Wait ( constRTPTime & delay) 等待延时,传入的是“1、构造函数”中的对象。

RTPTime::Wait(delay);

四、资源释放

当程序结束的时候,需要发送一个再见包,用来释放RTP会话资源。

delay= RTPTime(10.0);

session.BYEDestroy(delay,"Time'sup",9);


五、RTP发送与接受的样例


样例下载地址:

https://git.coding.net/DavidZh666/Video_TCP_h264.git


该样例通过jrtplib中的example2.cpp修改后完成。

Ubuntu中,使用如下命令编译完成

g++ jrtp_send.cpp -ojrtp_send -ljrtp

g++ jrtp_receive.cpp-o jrtp_receive -ljrtp

运行

./jrtp_receive.cpp

./jrtp_send.cpp





        

猜你喜欢

转载自blog.csdn.net/weixin_40100431/article/details/80386404