視訊監控安防平臺--國標28181-2016版本TCP碼流沾包流程
阿新 • • 發佈:2019-02-14
視訊安防監控平臺-國標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