视频监控安防平台--国标28181-2016版本TCP码流沾包流程

视频安防监控平台-国标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


你可能感兴趣的:(视频监控系统平台)