简介
jrtplib是用C++开发的rtp/rtcp库,非常方便嵌入到C++工程中,可用于rtsp server或rtsp client的开发之中,或者其他以rtp/rtcp格式的推流与收流。
初始化
示例代码:
RTPSession rtp_session;
unsigned short rtp_port = 6666;
unsigned int payload_type = 96; //以H264为例
const std::string dst_ip = "224.124.1.101";
unsigned short dst_port = 8856;
int status = 0;
RTPUDPv4TransmissionParams transparams;
RTPSessionParams sessparams;
sessparams.SetOwnTimestampUnit(1.0/25.0);//必须设置
transparams.SetPortbase(rtp_port);//rtp_port必须是偶数
base_type::SetDefaultPayloadType(payload_type);
// 创建,成功返回0
status = rtp_session.Create(sessparams, &transparams);
// 添加目标地址与端口,成功返回0
status = rtp_session.AddDestination( RTPIPv4Address(ntohl(inet_addr(dst_ip.c_str()),dst_port) );
发送
示例代码:
unsigned char* packetData;
unsigned int packetDataSize;
unsigned int payload_type = 96; //以H264为例
unsigned int timestamp; //时间戳
bool end_mark = true; //结束标志,当分片发送时,最后一篇true,其他的false,当单发送nal时为true
int status = 0;
status = rtp_session.SendPacket(PacketData,packetDataSize,payload_type,end_mark,timestamp);
接收
示例代码:
//num循环的次数
for (i = 1 ; i <= num ; i++)
{
rtp_session.BeginDataAccess();
if (rtp_session.GotoFirstSourceWithData())
{
do
{
RTPPacket *pack;
while ((pack = rtp_session.GetNextPacket()) != NULL)
{
/* 收到的数据在pack中 */
//释放pack
rtp_session.DeletePacket(pack);
}
} while (rtp_session.GotoNextSourceWithData());
}
rtp_session.EndDataAccess();
//等待
RTPTime::Wait(RTPTime(1,0));
}
移除目标地址和端口
示例代码:
status = rtp_session.DeleteDestination( RTPIPv4Address(ntohl(inet_addr(dst_ip.c_str()),dst_port) );
释放
示例代码:
//void BYEDestroy(const RTPTime &maxwaittime,const void *reason,size_t reasonlength);
rtp_session.BYEDestroy(RTPTime(10,0),0,0);
为更方便的使用,新建了RTPSessionUtils.cpp和RTPSessionUtils.h,把jrtp接口再封装一遍。
RTPSessionUtils.h
#include "rtpsession.h"
#include "rtppacket.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtpsessionparams.h"
#include "rtperrors.h"
#ifndef WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <winsock2.h>
#endif // WIN32
#include "rtpsourcedata.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
//jrtplib应用需链接的lib
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib, "jrtplib_d.lib")
#pragma comment(lib,"jthread_d.lib")
namespace jrtplib
{
class RTPSessionUtils : public RTPSession
{
typedef RTPSession base_type;
public:
RTPSessionUtils();
~RTPSessionUtils();
int AddDestination(const std::string& ip, uint16_t port);
int DeleteDestination(const std::string& ip, uint16_t port);
int CreateDefault(uint16_t port);
protected:
void OnNewSource(RTPSourceData *dat);
void OnBYEPacket(RTPSourceData *dat);
void OnRemoveSource(RTPSourceData *dat);
void OnRTPPacket(RTPPacket *pack,const RTPTime &receivetime,
const RTPAddress *senderaddress);
void OnRTCPCompoundPacket(RTCPCompoundPacket *pack,const RTPTime &receivetime,
const RTPAddress *senderaddress);
void OnPollThreadStep();
private:
int GetAddrFromSource(RTPSourceData *dat, uint32_t& ip, uint16_t& port);
};
}
//整形的ip转成字符串ip
static std::string IPToString(const unsigned int iIP)
{
struct in_addr inaddr;
inaddr.s_addr = htonl(iIP);
return std::string(inet_ntoa(inaddr));
}
//字符串ip转成整形ip
static unsigned int IPToInt(const std::string& sIP)
{
return inet_addr(sIP.c_str());
}
RTPSessionUtils.cpp
#include "RTPSessionUtils.h"
namespace jrtplib{
RTPSessionUtils::RTPSessionUtils()
{
#ifdef WIN32
WSADATA dat;
WSAStartup(MAKEWORD(2,2),&dat);
#endif // WIN32
}
RTPSessionUtils::~RTPSessionUtils()
{
#ifdef WIN32
WSACleanup();
#endif // WIN32
}
int RTPSessionUtils::CreateDefault(uint16_t port)
{
RTPUDPv4TransmissionParams transparams;
RTPSessionParams sessparams;
//sessparams.SetAcceptOwnPackets(true);
sessparams.SetOwnTimestampUnit(1.0/25.0);//必须设置
transparams.SetPortbase(port);//port必须是偶数
base_type::SetDefaultPayloadType(96);
return base_type::Create(sessparams, &transparams);
base_type::SetDefaultPayloadType(96);
base_type::SetDefaultTimestampIncrement(0);
base_type::SetDefaultMark(false);
}
int RTPSessionUtils::AddDestination(const std::string& ip, uint16_t port)
{
return base_type::AddDestination(RTPIPv4Address(ntohl(inet_addr(ip.c_str())), port));
}
int RTPSessionUtils::DeleteDestination(const std::string& ip, uint16_t port)
{
return base_type::DeleteDestination(RTPIPv4Address(ntohl(inet_addr(ip.c_str())), port));
}
int RTPSessionUtils::GetAddrFromSource(RTPSourceData *dat, uint32_t& ip, uint16_t& port)
{
if (dat->IsOwnSSRC())
return -1;
if (dat->GetRTPDataAddress() != 0)
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTPDataAddress());
ip = addr->GetIP();
port = addr->GetPort();
}
else if (dat->GetRTCPDataAddress() != 0)
{
const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat->GetRTCPDataAddress());
ip = addr->GetIP();
port = addr->GetPort()-1;
}
return 0;
}
void RTPSessionUtils::OnNewSource(RTPSourceData *dat)
{
uint32_t ip;
uint16_t port;
if (GetAddrFromSource(dat, ip, port))
return;
RTPIPv4Address dest(ip,port);
base_type::AddDestination(dest);
std::cout << "OnNewSource Adding destination " << IPToString(ip) << ":" << port << std::endl;
}
void RTPSessionUtils::OnRemoveSource(RTPSourceData *dat)
{
if (dat->ReceivedBYE())
return;
uint32_t ip;
uint16_t port;
if (GetAddrFromSource(dat, ip, port))
return;
RTPIPv4Address dest(ip,port);
base_type::DeleteDestination(dest);
std::cout << "OnRemoveSource Deleting destination " << IPToString(ip) << ":" << port << std::endl;
}
void RTPSessionUtils::OnBYEPacket(RTPSourceData *dat)
{
uint32_t ip;
uint16_t port;
if (GetAddrFromSource(dat, ip, port))
return;
RTPIPv4Address dest(ip,port);
base_type::DeleteDestination(dest);
std::cout << "OnBYEPacket Deleting destination " << IPToString(ip) << ":" << port << std::endl;
}
//只要有rtp包就会触发
void RTPSessionUtils::OnRTPPacket(RTPPacket *pack,const RTPTime &receivetime,
const RTPAddress *senderaddress)
{
std::cout << "OnRTPPacket: data:" << pack->GetPayloadData() << std::endl;
}
//收到rtcp包触发
void RTPSessionUtils::OnRTCPCompoundPacket(RTCPCompoundPacket *pack,const RTPTime &receivetime,
const RTPAddress *senderaddress)
{
std::cout << "OnRTCPCompoundPacket: data:" << pack->GetCompoundPacketData() << std::endl;
}
//隔段时间就会触发,也可以用于收包回调函数
//void RTPSessionUtils::OnPollThreadStep()
//{
// BeginDataAccess();
// // check incoming packets
// if (GotoFirstSourceWithData())
// {
// do
// {
// RTPPacket *pack;
// RTPSourceData *srcdat;
// srcdat = GetCurrentSourceInfo();
// while ((pack = GetNextPacket()) != NULL)
// {
// std::cout << "Got packet " << pack->GetExtendedSequenceNumber() << " from SSRC " << srcdat->GetSSRC() << std::endl;
// DeletePacket(pack);
// }
// } while (GotoNextSourceWithData());
// }
// EndDataAccess();
//}
}