1. 程式人生 > >視訊監控安防平臺--國標28181-2016版本TCP碼流沾包流程

視訊監控安防平臺--國標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