signed

QiShunwang

“诚信为本、客户至上”

rtp包解析出负载数据过滤包头附加数据

2021/5/14 21:55:46   来源:

rtp包格式并不复杂,自定义个rtp头结构体,指针强制转换即可解析。但某些厂家设备一旦发来带有rtp扩展数据的包,就容易被当成负载内容从而解析失败。抓包一看wireshark解析得好好的,对方是按标准添加的数据,只能自己修改适配。

以下get_rtp_data()函数简单几行即可将rtp附加数据一口气撸了去,非常方便,具体看代码注释。

struct RtpHead
{
	unsigned char	csrclen : 4;	//特约信源数,每个4字节,紧接ssrc
	unsigned char	extension : 1;	//扩展数据,在特约信源后面,先是两个字节标识内容,再两字节标识长度,需乘4
	unsigned char	padding : 1;	//填充,包的最后一个字节表示填充字节数
	unsigned char	version : 2;	//版本,当前是2
	unsigned char	payload : 7;	//负载类型
	unsigned char	marker : 1;		//标识位
	unsigned short	seqno;			//包序号,用来重组,统计丢包乱序
	unsigned int	timestamp;		//时间戳
	unsigned int	ssrc;			//信源,用来区分rtp包
};

int get_rtp_data(unsigned char* rtp_pkg, int rtp_len, unsigned char*& data, int& data_len)
{
	if (!rtp_pkg || rtp_len < sizeof(RtpHead) || !data) {
		return -1;
	}

	RtpHead* head = (RtpHead*)rtp_pkg;
	int head_len = sizeof(RtpHead) + head->csrclen * 4; //包头长位固定长度 + 特约信源占用
	if (head->extension == 1) {
		// 再加附加数据(2字节内容摘要,2字节具体内容长度 + 具体数据)
		head_len += (rtp_pkg[head_len + 2] + rtp_pkg[head_len + 3]) * 4 + 4;
	}

	data = rtp_pkg + head_len;
	data_len = rtp_len - head_len;
	if (head->padding == 1) {
		//末尾填充位,数据长度要减去
		data_len -= rtp_pkg[data_len - 1];
	}
	if (data_len < 0) {
		return -1;
	}
	return 0;
}