通过C/C++结构体解析RTP/RTCP的包头的方法

RTP包的头构成为:

 0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |V=2|P|X|  CC   |M|     PT      |       sequence number         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                           timestamp                           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           synchronization source (SSRC) identifier            |
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   |            contributing source (CSRC) identifiers             |
   |                             ....                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

通过wireshark解析的形式:

在C/C++中,对包的头信息解析的方法为,定义一个结构体:

struct RTP_Header
{
	unsigned __int16 csrc_count:4;
	unsigned __int16 extension:1;
	unsigned __int16 padding:1;
	unsigned __int16 version:2;
	unsigned __int16 payloadtype:7;	
	unsigned __int16 marker:1;	

	unsigned __int16 seq;
	unsigned __int32 timestamp;
	unsigned __int32 ssrc;
};

结构体中,冒号后面数字为实际占的位数,注意8位字节的内部,网络序与本地序是相反的,csrc_count在第1字节的后4位,而在结构体声明中,csrc_count需要在前4位,应用的方法,以序列号的获取为例:

int RTPProcessor::getSequenceNumber(PacketBuffer* packet)
{
	RTP_Header* pHeader =  (RTP_Header*)packet->data;
	return ntohs(pHeader->seq);
}
其中packet->data为recv的udp的原始包,通过RTP_Header的强制类型转换,即可直接通过pHeader->seq获取,这里需要网络序转换成字节序,调用ntohs的函数,同理,对序列号的修改如下:

void RTPProcessor::setSequenceNumber(PacketBuffer* packet)
{
	RTP_Header* pHeader =  (RTP_Header*)packet->data;
	pHeader->seq=  htons(m_sequenceNumer); 
}
-----------------------------------------------------------------------------------------------------××××××-----------------------------------------------------------------------------------------------------------------------------------
对于RTCP,方法与RTP相似,RTCP的包的头信息为:

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |V=2|P|   CC    |      PT       |           length              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           synchronization source (SSRC) identifier            |
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   |                    source or chunk                            |
   |                             ....                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

RTCP的包的头信息与RTP有点不同,wireshark的解析为:


在C/C++中,对包的头信息解析的方法为,定义一个结构体:

struct RTCP_Header
{
	unsigned __int16 csrc_count:5;
	unsigned __int16 padding:1;
	unsigned __int16 version:2; //1 char
	unsigned __int16 payloadtype:8; //2 char
	unsigned __int16 length; //3,4 char

	unsigned __int32 ssrc; //5,6,7,8 char
};

应用的方法,也是获取原始数据包的首地址,再通过RTCP_Header进行强制类型转换。

注意,RTCP的包比较小,通常会将多个RTCP包,通过1个UDP包进行发送,那么就需要对多个RTCP包进行拆解,拆解的方法是通过length,获取不同包的首地址。

多个包的组成为:

C/C++解析的方法为:

bool RTPProcessor::checkRtcp(PacketBuffer* packet)
{
	bool ret =false;
	const int rtcpCount=5;
	int i=0;
	RTCP_Header* pHeader[rtcpCount];
	int length[rtcpCount]={0};
	int ssrc[rtcpCount]={0};
	int offset=0;
	for (i=0;i<rtcpCount;i++)
	{
		if (i > 0)
		{
			offset+=4*(length[i-1]+1);
		}
		if (offset >= packet->dataSize)
		{
			break;
		}
		pHeader[i] =  (RTCP_Header*)(packet->data+offset);
		length[i] = ntohs(pHeader[i]->length);
		ssrc[i] = ntohl(pHeader[i]->ssrc);

	}
	return ret;
}

其中offset为每个包的偏移地址,rtcpCount=5为每个UDP包,预计不超过5个RTCP包。

发布了159 篇原创文章 · 获赞 42 · 访问量 19万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览