一种RTP接收和解包的程序
Posted qianbo_insist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一种RTP接收和解包的程序相关的知识,希望对你有一定的参考价值。
jrtplib
除了自己写udp 接收程序,我们也可以使用jrtplib 的方式去接收数据包,比较简单,jrtplib可以解rtp 的头部,但不适宜解包,一般来说,解包都是要自己解的,我们使用jrtplib来收包,同时自己写解包代码,除此之外,rtf3984是H.264的baseline码流在RTP方式下传输的规范,我们传输实时码流,一般使用baseline。
jrtplib class
jrtplib可以在编译的时候使用thread,也就是编译出thread库,让其启动的时候启动多个线程。
class Service_RTP:public RTPSession
int status;
RTPUDPv4TransmissionParams m_transparams;
RTPSessionParams m_sessparams;
Service_RTP_Analyse m_rab;
protected:
void OnPollThreadStep()
BeginDataAccess();
if (GotoFirstSourceWithData())
do
RTPPacket *pack;
RTPSourceData * srcdat = GetCurrentSourceInfo();
const RTPIPv4Address *addr = (const RTPIPv4Address *)(srcdat->GetRTPDataAddress());
if (srcdat->RR_HasInfo()) //如果有收到rr包
std::cout << srcdat->RR_GetPacketsLost() << ":lost" << std::endl;//得到最近会话丢失的包数
while ((pack = GetNextPacket()) != NULL)
//这里要分发到不同的线程里面
m_rab.insert(addr->GetIP(), addr->GetPort(), pack);
//ProcessRTPPacket(addr->GetIP(), addr->GetPort(), *srcdat, pack);
DeletePacket(pack);
while (GotoNextSourceWithData());
EndDataAccess();
主函数启动RTP接收
int main()
#ifdef _WIN32
WSADATA dat;
WSAStartup(MAKEWORD(2, 2), &dat);
#endif
MyRTPSession sess;
std::string ipstr;
int status;
RTPUDPv4TransmissionParams transparams;
RTPSessionParams sessparams;
//6000 端口在InitContext里面配置
transparams.SetPortbase(PORT);
//设定RTP包的接收缓存
transparams.SetRTPReceiveBuffer(2 * 1024 * 1024);
sessparams.SetOwnTimestampUnit(1.0 / 90000.0);
sessparams.SetAcceptOwnPackets(true);
sessparams.SetUsePollThread(true);
//sess.SetCallBack(callback_1);
status = sess.Create(sessparams, &transparams);// &transparams);
checkerror(status);
//启动检查程序
for(;;)
//........
//Sleep(INFINITE);
return 0;
从jrtplib里面获取payload和长度都是有函数的。下面再说明一下常规解h264和AAC的程序片段:
h264 解包
#define H264 96
#define G711 8
#define AAC 97
#define RTP_HEADLEN 12
// 功能:解码RTP H.264视频
// 参数:1.RTP包缓冲地址 2.RTP包数据大小 3.H264输出地址 4.输出数据大小
// 返回:true:表示一帧结束 false:FU-A分片未结束或帧未结束
bool AnalyseRTPH264(void * bufIn, int len, void ** pBufOut, int * pOutLen)
*pOutLen = 0;
if (len < RTP_HEADLEN)
return false;
unsigned char * src = (unsigned char*)bufIn + RTP_HEADLEN;
unsigned char head1 = *src; // 获取第一个字节
unsigned char head2 = *(src + 1); // 获取第二个字节
unsigned char nal = head1 & 0x1f; // 获取FU indicator的类型域,
unsigned char flag = head2 & 0xe0; // 获取FU header的前三位,判断当前是分包的开始、中间或结束
unsigned char nal_fua = (head1 & 0xe0) | (head2 & 0x1f); // FU_A nal
bool bFinishFrame = false;
if (nal == 0x1c) // 判断NAL的类型为0x1c=28,说明是FU-A分片
// fu-a
if (flag == 0x80) // 开始
*pBufOut = src - 3;
*((int *)(*pBufOut)) = 0x01000000; // zyf:大模式会有问题
*((char *)(*pBufOut) + 4) = nal_fua;
*pOutLen = len - RTP_HEADLEN + 3;
else if (flag == 0x40) // 结束
*pBufOut = src + 2;
*pOutLen = len - RTP_HEADLEN - 2;
else // 中间
*pBufOut = src + 2;
*pOutLen = len - RTP_HEADLEN - 2;
else // 单包数据
*pBufOut = src - 4;
*((int *)(*pBufOut)) = 0x01000000; // 大模式会有问题
*pOutLen = len - RTP_HEADLEN + 4;
unsigned char * bufTmp = (unsigned char*)bufIn;
if (bufTmp[1] & 0x80)
bFinishFrame = true; // rtp mark
else
bFinishFrame = false;
return bFinishFrame;
AAC解包
AAC是高级音频编码,解RTP AAC音频包,声道和采样频率可以事先知道,否则就要多传输字节。
//参数:1.RTP包缓冲地址 2.RTP包数据大小 3.H264输出地址 4.输出数据大小
//返回:true:表示一帧结束 false:帧未结束 一般AAC音频包比较小,没有分片。
bool AnalyseRTPAAC(void * bufIn, int recvLen, void** pBufOut, int* pOutLen)
unsigned char* bufRecv = (unsigned char*)bufIn;
unsigned char ADTS[] = 0xFF, 0xF1, 0x00, 0x00, 0x00, 0x00, 0xFC ;
int audiosamprate = 44100;//音频采样率
int audioChannel = 2; //音频声道2,我们在采集端都重采样为双声道
int audioBit = 16; //16位 固定
switch (audioSamprate)
case 16000:
ADTS[2] = 0x60;
break;
case 32000:
ADTS[2] = 0x54;
break;
case 44100:
ADTS[2] = 0x50;
break;
case 48000:
ADTS[2] = 0x4C;
break;
case 96000:
ADTS[2] = 0x40;
break;
default:
break;
ADTS[3] = (audioChannel == 2) ? 0x80 : 0x40;
int len = recvLen - 16 + 7;
len <<= 5;//8bit * 2 - 11 = 5(headerSize 11bit)
len |= 0x1F;//5 bit 1
ADTS[4] = len >> 8;
ADTS[5] = len & 0xFF;
*pBufOut = (char*)bufIn + 16 - 7;
memcpy(*pBufOut, ADTS, sizeof(ADTS));
*pOutLen = recvLen - 16 + 7;
unsigned char* bufTmp = (unsigned char*)bufIn;
bool bFinishFrame = false;
if (bufTmp[1] & 0x80)
//DebugTrace::D("Marker");
bFinishFrame = true;
else
bFinishFrame = false;
return true;
#endif
以上是关于一种RTP接收和解包的程序的主要内容,如果未能解决你的问题,请参考以下文章