视频安防监控平台-国标28181-2016版本TCP码流沾包流程 (如需交流可联系QQ:123011785)
由于28181规定tcp码流要使用RFC4571,通俗点就是每个包的格式为 长度(2个字节)+RTP头(12个字节)+数据模式,然后自己在根据这个格式进行沾包处理。
1、首先明确GB28181的TCP码流遵循的是RFC4571(RTP OVER TCP),具体类型
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 --------------------------------------------------------------- | LENGTH | RTP or RTCP packet ... | --------------------------------------------------------------- Figure 1: The bit field definition of the framing method
2、详细协议文档可以参考《rfc4571.Framing-Real-time-Transport-Protocol-(RTP)-and-RTP-Control-Protocol-(RTCP)-Packets-over-Conn.pdf》文档
3、下面我把沾包的代码基本流程放上来, 目前已经在很多项目上面用,实用情况比较好
void StreamThread::StickyTcpStramPacket(UINT8 *pData, int TcpRecvLen) //接收每个tcp的数据和长度
{
if (pData == NULL || TcpRecvLen <= 0)
{
printf("%s :Tcp Recv Data Error!!", __FUNCTION__);
return;
}
UINT8* pBuff = pData;
do
{
if (0 == m_sizeOfTcpRecvBufTmp)
{
//长度的字段分开,需要保留最好一个字节, 确保每一个包都完整的接收
if (TcpRecvLen < TCP_STRAM_HEADER_LEN)
{
printf("TcpRecvLen(%d) < TCP_STRAM_HEADER_LEN(2) !!!!!!!!!!pBuff[0]:0x%02x", TcpRecvLen, pBuff[0]);
if ((TcpRecvLen > 0) && (m_HeadTmplen <= 0))
{
memcpy(m_pHeadTmpBuff, pBuff, TcpRecvLen);
m_HeadTmplen = TcpRecvLen;
}
break;
}
if ((m_HeadTmplen > 0) && (m_pHeadTmpBuff != NULL))
{
memcpy(m_pHeadTmpBuff+m_HeadTmplen, pData, TcpRecvLen);
//针对buff重新赋值;
pBuff = m_pHeadTmpBuff;
TcpRecvLen += m_HeadTmplen;
m_HeadTmplen = 0;
}
m_sizeOfTcpRecvPacketBuf = htons(*( (UINT16 *)&pBuff[0] ));
pBuff += TCP_STRAM_HEADER_LEN;
TcpRecvLen -= TCP_STRAM_HEADER_LEN;
m_sizeOfTcpRecvBufTmp = m_sizeOfTcpRecvPacketBuf;
m_pTcpRecvPacketBuf = (UINT8 *)malloc(m_sizeOfTcpRecvPacketBuf*2);
m_pTcpRecvBufTmp = m_pTcpRecvPacketBuf;
}
if (TcpRecvLen <= 0)
{
break;
}
//已接收的包数据长度 < 包数据长度 = 一个不完整的包
if (TcpRecvLen < m_sizeOfTcpRecvBufTmp)
{
memcpy(m_pTcpRecvBufTmp, pBuff, TcpRecvLen);
m_pTcpRecvBufTmp += TcpRecvLen;
m_sizeOfTcpRecvBufTmp -= TcpRecvLen;
pBuff += TcpRecvLen;
TcpRecvLen -= TcpRecvLen;
}
else
{
//已接收的包数据长度 == 包数据长度 = 一个完整的包
//已接收的包数据长度 > 包数据长度 = 至少有一个完整的包 + 至少一个数据片段
memcpy(m_pTcpRecvBufTmp, pBuff, m_sizeOfTcpRecvBufTmp);
pBuff += m_sizeOfTcpRecvBufTmp;
TcpRecvLen -= m_sizeOfTcpRecvBufTmp;
UINT32 SSrc = ntohl( *( (UINT32 *)&m_pTcpRecvPacketBuf[8]) );
if (m_tcprecvssrc <= 0)
{
m_tcprecvssrc = SSrc;
}
//如果ssrc不一致, 表示解析失败
if (m_tcprecvssrc != SSrc)
{
printf("vvvvvvv%d recvpacklen:%d\n", TcpRecvLen, m_sizeOfTcpRecvPacketBuf);
//free
if (m_pTcpRecvPacketBuf != NULL)
{
free(m_pTcpRecvPacketBuf);
m_pTcpRecvPacketBuf = NULL;
}
m_sizeOfTcpRecvBufTmp = 0;
break;
}
TcpStreamPacket tcppacket;
tcppacket.nLength = m_sizeOfTcpRecvPacketBuf;
tcppacket.pData = (UINT8*)new char[m_sizeOfTcpRecvPacketBuf+1];
memcpy(tcppacket.pData, m_pTcpRecvPacketBuf, tcppacket.nLength);
if (tcppacket.nLength > 0)
{
tcppacket.pData[tcppacket.nLength] = '\0';
}
m_listTcpStreamPacket.push_back(tcppacket);
#if 1
//free
if (m_pTcpRecvPacketBuf != NULL)
{
free(m_pTcpRecvPacketBuf);
m_pTcpRecvPacketBuf = NULL;
}
m_sizeOfTcpRecvBufTmp = 0;
#else
//memset(m_pTcpRecvBufTmp, 0, sizeof(m_pTcpRecvBufTmp));
m_pTcpRecvBufTmp = NULL;
m_sizeOfTcpRecvBufTmp = 0;
#endif
}
}while(TcpRecvLen > 0);
}
协议文档《rfc4571.Framing-Real-time-Transport-Protocol-(RTP)-and-RTP-Control-Protocol-(RTCP)-Packets-over-Conn.pdf》下载地址:
http://download.csdn.net/download/songxiao1988918/10148885