概述
关于RTP协议诊断,我们通常需要分析RTP头,扩展头,尤其是如SSRC, 时间戳,序号,mark标记从而进一步判定数据封包规范性,丢包及其网络抖动等问题,而wireshark 本是网络数据包分析利器,能根据SDP(RTSP/SIP交互)自动完成RTP协议解析,但针对TCP承载RTP只能自动解析RTSP隧道模式,针对GB28181使用的TCP承载RTP无法自动识别,
解决方式
有3种方式可以实现wireshark扩展支持该模式下的RTP协议自动解析(处理TCP粘包)
1. 基于LUA自实现wireshark插件
2. 基于c方式扩展wireshark插件
3. 通过wireshark+自定义工具组合方式解析
其中2方式难度较大,方式1可采用顶层插件解决TCP粘包识别,解析前2个字节长度,然后二次调用wireshark RTP解析器,需要有一定LUA脚本基础,方式3最为简单。
方式3: 可以通过wireshark跟踪原始tcp流以raw方式导出纯二进制文件,再简单文件处理即可导出纯RTP负载数据.
如GB28181中ps负载可导出mpg文件,vlc可以直接播放验证数据正确性,同时输出RTP相关字段值内容。
源码示例
#include <stdio.h>
#include <Winsock2.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
unsigned char* buffer = new unsigned char[10240];
FILE* readfile = fopen("gbdata", "rb");
if (NULL == readfile)
{
printf("open read file failed, check gbdata file!\n");
return -1;
}
FILE* logfile = fopen("RTP.log", "w");
if (NULL == readfile)
{
printf("open rtp file error!\n");
fclose(readfile);
return -1;
}
FILE* writefile = fopen("gb.mpg", "wb");
if (NULL == writefile)
{
printf("open video file error!\n");
fclose(readfile);
fclose(logfile);
return -1;
}
int len = 0;
int size = 0;
int last = 0;
while(!feof(readfile))
{
if (fread(&len, 2, 1, readfile) <= 0)
{
break;
}
size = ntohs(len);
if (fread(buffer, size, 1, readfile) <= 0)
{
break;
}
bool padding = false;
if (buffer[0] & 0x20)
padding = true;
unsigned int tm = 0;
unsigned int seq = 0;
unsigned int ssrc = 0;
if (last == 0) {
last = seq;
}
int mark = (buffer[1] & 0x80) >> 7;
seq = buffer[2] << 8 | buffer[3];
tm = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7];
ssrc = buffer[8] << 24 | buffer[9] << 16 | buffer[10] << 8 | buffer[11];;
unsigned char paddingLen = 0;
if (padding) {
paddingLen = buffer[size - 1];
}
if (paddingLen > 3) {
printf("Error: padding > 3 bytes!\n");
return 0;
}
char rtp[128] = {0};
sprintf(rtp, "size:% 10d | seq:% 10u | time:% 10u | ssrc:% 10u | padding:%d paddinglen:%d | mark:%d | byte2:%x\n", size-12, seq, tm, ssrc, padding, paddingLen, mark, buffer[1]);
fwrite(rtp, strlen(rtp), 1, logfile);
printf("======== seq:%u--timestamp:%u--ssrc:%u\n", seq, tm, ssrc);
fwrite(buffer+12, size-12 - paddingLen, 1, writefile);
}
printf("Parse Done!\n");
getchar();
fclose(readfile);
fclose(logfile);
fclose(writefile);
return 0;
}