RTPSessionParams sessParams;
RTPUDPv4TransmissionParams transParams;
sessParams.SetAcceptOwnPackets(true);
sessParams.SetOwnTimestampUnit(ddparm); //25 video frames per second
sessParams.SetUsePollThread(false);
sessParams.SetMaximumPacketSize(nMaxPackSize);
transParams.SetPortbase(nBasePort);
transParams.SetBindIP(ntohl(inet_addr(strBaseIP.c_str())));
nRet = m_VedioRTPSession.Create(sessParams, &transParams);
if (nRet>0)
{
RTPIPv4Address dest(ntohl(inet_addr(strBaseIP.c_str())), nBasePort, true);
m_VedioRTPSession.AddToAcceptList(dest);
}
LOGI("取流模式为: udp ,本地ip:" << strBaseIP << "本地接收端口:" << nBasePort);
这段代码是一个使用RTP(Real-time Transport Protocol)的C++代码片段,用于创建一个RTP会话和传输参数,并将目标地址添加到接受列表中。RTP是一种常用于音频和视频传输的协议。
让我们逐行解析这段代码:
1. `RTPSessionParams sessParams;`
- 创建一个`RTPSessionParams`对象,用于设置RTP会话的参数。
2. `RTPUDPv4TransmissionParams transParams;`
- 创建一个`RTPUDPv4TransmissionParams`对象,用于设置RTP传输的参数。
3. `sessParams.SetAcceptOwnPackets(1);`
- 设置接受本地发送的RTP数据包。这个参数被设置为1,表示允许接收本地发出的RTP数据包。
4. `sessParams.SetOwnTimestampUnit(ddparm);`
- 设置自己的时间戳单位。时间戳单位定义为一段时间内的采样数除以这段时间(以秒为单位)。例如:对于80000Hz的音频数据,时间戳单位就是1.0/8000.0.因为这个值初始设置为一个非法的值,所以使用者必须设置为一个允许的值才可以创建一个会话。
5. `sessParams.SetUsePollThread(false);`
- 如果设为了true则会话将使用一个线程池自动的处理收到的数据以及在需要的时候发送RTCP数据包。
6. `sessParams.SetMaximumPacketSize(nMaxPackSize);`
- 设置RTP数据包的最大大小。
7. `transParams.SetPortbase(nBasePort);`
- 设置RTP传输的端口号基数。
8. `transParams.SetBindIP(ntohl(inet_addr(strBaseIP.c_str())));`
- 设置绑定的IP地址。`strBaseIP`是一个字符串,应该包含有效的IP地址。`inet_addr`函数用于将IP地址字符串转换为网络字节序的32位整数。`ntohl`函数用于将32位整数从网络字节序转换为主机字节序。这样,`SetBindIP`将网络字节序的IP地址设置为RTP传输参数。
9. `nRet = m_VedioRTPSession.Create(sessParams, &transParams);`
- 创建RTP会话。`m_VedioRTPSession`是一个RTP会话对象,`Create`函数用于使用之前设置的`sessParams`和`transParams`创建RTP会话。`nRet`将接收函数的返回值。
10. `RTPIPv4Address dest(ntohl(inet_addr(strBaseIP.c_str())), nBasePort, true);`
- 创建一个`RTPIPv4Address`对象,用于表示目标地址。与之前一样,`inet_addr`函数用于将字符串格式的IP地址转换为32位整数,并使用`ntohl`转换为主机字节序。
11. `m_VedioRTPSession.AddToAcceptList(dest);`
- 将目标地址添加到RTP会话的接受列表中。这将允许从指定地址接收RTP数据包。
一.初始化
1.在使用 JRTPLIB 进行实时流媒体数据传输之前,首先应该生成 RTPSession 类的一个实例来表示此次 RTP会话,然后调用 Create() 方法来对其进行初始化操作。
RTPUDPv4TransmissionParams transparams;
RTPSessionParams sessparams;
sessparams.SetAcceptOwnPackets(true);
sessParams.SetOwnTimestampUnit(ddparm); //25 video frames per second
sessParams.SetUsePollThread(false);
sessParams.SetMaximumPacketSize(nMaxPackSize);
transParams.SetPortbase(nBasePort);/*本地通讯端口*/
transParams.SetBindIP(ntohl(inet_addr(strBaseIP.c_str())));
nRet = m_VedioRTPSession.Create(sessParams, &transParams);
二.数据发送
1.当 RTP 会话成功建立起来之后,接下去就可以开始进行流媒体数据的实时传输了。首先需要设置好数据发送的目标地址,RTP 协议允许同一会话存在多个目标地址,这可以通过调用 RTPSession 类的AddDestination()、DeleteDestination() 和 ClearDestinations() 方法来完成。例如,下面的语句表示的是让 RTP 会话将数据发送到本地主机的 6000 端口:
// 创建 RTP 会话。
RTPIPv4Address dest(ntohl(inet_addr(strRemoteIP.c_str())), nRemotePort, true);
//将目标地址 dest 加入到 RTP 会话的接收列表,表示接收从该地址发送的 RTP 数据包。
m_VedioRTPSession.AddToAcceptList(dest);
//将目标地址 dest 加入到 RTP 会话的目标地址列表,表示将 RTP 数据包发送给该地址。
m_VedioRTPSession.AddDestination(dest);
2.目标地址全部指定之后,接着就可以调用 RTPSession 类的 SendPacket() 方法,向所有的目标地址发送流媒体数据。SendPacket() 是 RTPSession 类提供的一个重载函数对于同一个 RTP 会话来讲,负载类型、标识和时戳增量通常来讲都是相同的,JRTPLIB 允许将它们设置为会话的默认参数,这是通过调用 RTPSession 类的 SetDefaultPayloadType()、SetDefaultMark() 和SetDefaultTimeStampIncrement() 方法来完成的。为 RTP 会话设置这些默认参数的好处是可以简化数据的发送,例如,如果为 RTP 会话设置了默认参数:
//设置默认负载类型(Payload Type)
nRet = m_VedioRTPSession.SetDefaultPayloadType(nPlayLoadType);
if (nRet < 0)
{
rtpErrorString = RTPGetErrorString(nRet);
LOG_E("SetDefaultPayloadType - JRTP ERROR : %s", rtpErrorString.c_str());
return nRet;
}
//设置RTP数据包的默认标记位,标记位用于标识某些特殊意义的数据包。
nRet = m_VedioRTPSession.SetDefaultMark(bMark);
if (nRet < 0)
{
rtpErrorString = RTPGetErrorString(nRet);
LOG_E("SetDefaultMark - JRTP ERROR : %s", rtpErrorString.c_str());
return nRet;
}
//设置RTP数据包的默认时间戳增量,用于控制数据包之间的时间间隔。
nRet = m_VedioRTPSession.SetDefaultTimestampIncrement(timestampinc);
if (nRet < 0)
{
rtpErrorString = RTPGetErrorString(nRet);
LOG_E("SetDefaultTimestampIncrement - JRTP ERROR : %s", rtpErrorString.c_str());
return nRet;
}
//设置RTP接收模式为AcceptAll,该模式允许接收所有传入的RTP数据包。
nRet = m_VedioRTPSession.SetReceiveMode(RTPTransmitter::AcceptAll);
if (nRet < 0)
{
rtpErrorString = RTPGetErrorString(nRet);
LOG_E("SetReceiveMode - JRTP ERROR : %s", rtpErrorString.c_str());
return nRet;
}
3.之后在进行数据发送时只需指明要发送的数据及其长度
if(bsipsrc)
//SendRawData函数用于直接发送原始的RTP数据,不对数据进行封包。
//pData是数据缓冲区指针,nLen是数据长度,true表示发送数据后会释放缓冲区。
iRet = m_VedioRTPSession.SendRawData(pData, nLen, true);
else
{
//如果m_timeStamp为零,说明是第一次发送数据,使用SendPacket函数发送RTP数据包,但不指定时间戳。
if (0 == m_timeStamp)
iRet = m_VedioRTPSession.SendPacket(pData, nLen);
else
//使用SendPacket函数发送RTP数据包,并指定时间戳和其他参数。pt是负载类型,bHasMarker是标记位,timestamp - m_timeStamp计算出时间戳增量,用于控制数据包之间的时间间隔。
iRet = m_VedioRTPSession.SendPacket(pData, nLen, pt, bHasMarker, timestamp - m_timeStamp);
m_timeStamp = timestamp;
}
SendRawData
和SendPacket
是JRTP库中用于发送RTP数据包的两种不同方法,它们的区别在于数据的处理方式和发送方式:
-
SendRawData
:SendRawData
方法用于直接发送原始的RTP数据,不对数据进行封包处理。这意味着用户必须自行确保传入的数据符合RTP格式,包括正确设置RTP头信息、负载类型、时间戳等。JRTP库不会对数据进行任何修改或封装,而是直接将原始数据发送出去。这种方法适用于那些已经对RTP格式非常熟悉且需要精细控制数据内容的开发者。使用SendRawData
时,开发者需要负责所有RTP协议相关的细节。 -
SendPacket
:SendPacket
方法用于发送经过JRTP库封装的RTP数据包。这意味着JRTP库会自动处理RTP头信息、负载类型、时间戳等,并将数据封装成符合RTP格式的数据包,然后再发送出去。这种方法更适用于那些希望简化RTP数据包发送过程、不需要深入了解RTP协议细节的开发者。JRTP库会自动处理RTP数据包的格式,让开发者能够更专注于业务逻辑。
总结:
SendRawData
方法适合高级用户,需要对RTP协议和数据包格式非常了解,并且需要自己处理原始RTP数据。SendPacket
方法适合普通用户,JRTP库会自动处理数据包格式,使得发送RTP数据包更加简便。开发者只需要提供数据和一些简单的参数,如负载类型和时间戳等,就能发送RTP数据包。
三.数据接收
对于流媒体数据的接收端,首先需要调用 RTPSession 类的 PollData() 方法来接收发送过来的 RTP 或者RTCP 数据报。
JRTPLIB-3.11中修改PollData()方法为Poll(),使用都一样由于同一个 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 () 方法来进行设置。
1.与数据发送只有一点不同
//是一个用于发送RTCP APP包的方法。RTCP(Real-time Transport Control Protocol)是用于RTP会话控制和反馈的协议,而RTCP APP包是RTCP中的一种特殊类型的包,用于承载应用程序特定的控制信息
m_VedioRTPSession.SendRTCPAPPPacket(1, (const uint8_t*)"RR", "1", 1);
2.接收数据
//初始化为25毫秒
RTPTime delay(0,25*1000);
//等待RTP数据包的到来。该函数将阻塞当前线程,直到接收到数据包或达到超时时间
m_VedioRTPSession.WaitForIncomingData(delay, &is_data_available);
if (is_data_available)
{
//开始访问RTP数据。在接收RTP数据之前,必须调用这个函数。
m_VedioRTPSession.BeginDataAccess();
//将迭代器定位到第一个有数据的RTP源。
if (m_VedioRTPSession.GotoFirstSourceWithData())
{
//循环遍历所有有数据的RTP源,并处理接收到的RTP数据包。
do
{
//GetNextPacket获取下一个RTP数据包,并通过OnRTPPacket函数进行处理。
RTPPacket * pkt = NULL;
while (m_startrecv && (pkt = m_VedioRTPSession.GetNextPacket()) != NULL)
{
m_VedioRTPSession.OnRTPPacket(pkt);
//处理完后,通过DeletePacket函数删除已处理的数据包,确保内存不被泄漏。
m_VedioRTPSession.DeletePacket(pkt);
}
} while (m_startrecv && m_VedioRTPSession.GotoNextSourceWithData());
}
//结束对RTP数据的访问
m_VedioRTPSession.EndDataAccess();
}
//用于轮询并处理RTP传输的网络事件。
int statu = m_VedioRTPSession.Poll();