一种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接收和解包的程序的主要内容,如果未能解决你的问题,请参考以下文章

c++ h264RTP接收和发送程序

iOS RTP 实时音频接收

使用VLC接收RTP流并时时播放(RTP流是pcma包)

RTP包的学习记录

RTP包的学习记录

RTP包的学习记录