最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包、解包的文档和代码。功夫不负有心人,找到不少有价值的文档 和代码。参考这些资料,写了H264 RTP打包类、解包类,实现了单个NAL单元包和FU_A分片单元包。对于丢包处理,采用简单的策略:丢弃随后的所有数据包,直到收到关键帧。测试效果还 不错,代码贴上来,若能为同道中人借鉴一二,足矣。两个类的使用说明如下(省略了错误处理过程):
RTP打包H264 NALU类使用范例代码:
- DWORD H264SSRC ;
- CH264_RTP_PACK pack ( H264SSRC ) ;
- BYTE *pVideoData ;
- DWORD Size, ts ;
- bool IsEndOfFrame ;
- WORD wLen ;
- pack.Set ( pVideoData, Size, ts, IsEndOfFrame ) ;
- BYTE *pPacket ;
- while ( pPacket = pack.Get ( &wLen ) )
- {
-
-
- }
RTP 承载H.264 Payload NALU 的打包类源码
// class CH264_RTP_PACK start
- class CH264_RTP_PACK
- {
- #define RTP_VERSION 2
-
- typedef struct NAL_msg_s
- {
- bool eoFrame ;
- unsigned char type;
- unsigned char *start;
- unsigned char *end;
- unsigned long size ;
- } NAL_MSG_t;
-
- typedef struct
- {
-
- unsigned short cc:4;
- unsigned short x:1;
- unsigned short p:1;
- unsigned short v:2;
- unsigned short pt:7;
- unsigned short m:1;
-
- unsigned short seq;
- unsigned long ts;
- unsigned long ssrc;
- } rtp_hdr_t;
-
- typedef struct tagRTP_INFO
- {
- NAL_MSG_t nal;
- rtp_hdr_t rtp_hdr;
- int hdr_len;
-
- unsigned char *pRTP;
- unsigned char *start;
- unsigned char *end;
-
- unsigned int s_bit;
- unsigned int e_bit;
- bool FU_flag;
- } RTP_INFO;
-
- public:
- CH264_RTP_PACK(unsigned long H264SSRC, unsigned char H264PAYLOADTYPE=96
- , unsigned short MAXRTPPACKSIZE=1472 )
- {
- m_MAXRTPPACKSIZE = MAXRTPPACKSIZE ;
- if ( m_MAXRTPPACKSIZE > 10000 )
- {
- m_MAXRTPPACKSIZE = 10000 ;
- }
- if ( m_MAXRTPPACKSIZE < 50 )
- {
- m_MAXRTPPACKSIZE = 50 ;
- }
-
- memset ( &m_RTP_Info, 0, sizeof(m_RTP_Info) ) ;
-
- m_RTP_Info.rtp_hdr.pt = H264PAYLOADTYPE ;
- m_RTP_Info.rtp_hdr.ssrc = H264SSRC ;
- m_RTP_Info.rtp_hdr.v = RTP_VERSION ;
-
- m_RTP_Info.rtp_hdr.seq = 0 ;
- }
-
- ~CH264_RTP_PACK(void)
- {
- }
-
-
-
-
- bool Set ( unsigned char *NAL_Buf, unsigned long NAL_Size
- , unsigned long Time_Stamp, bool End_Of_Frame )
- {
- unsigned long startcode = StartCode(NAL_Buf) ;
-
- if ( startcode != 0x01000000 )
- {
- return false ;
- }
-
- int type = NAL_Buf[4] & 0x1f ;
- if ( type < 1 || type > 12 )
- {
- return false ;
- }
-
- m_RTP_Info.nal.start = NAL_Buf ;
- m_RTP_Info.nal.size = NAL_Size ;
- m_RTP_Info.nal.eoFrame = End_Of_Frame ;
- m_RTP_Info.nal.type = m_RTP_Info.nal.start[4] ;
- m_RTP_Info.nal.end = m_RTP_Info.nal.start + m_RTP_Info.nal.size ;
-
- m_RTP_Info.rtp_hdr.ts = Time_Stamp ;
-
- m_RTP_Info.nal.start += 4 ;
-
- if ( (m_RTP_Info.nal.size + 7) > m_MAXRTPPACKSIZE )
- {
- m_RTP_Info.FU_flag = true ;
- m_RTP_Info.s_bit = 1 ;
- m_RTP_Info.e_bit = 0 ;
-
- m_RTP_Info.nal.start += 1 ;
- }
- else
- {
- m_RTP_Info.FU_flag = false ;
- m_RTP_Info.s_bit = m_RTP_Info.e_bit = 0 ;
- }
-
- m_RTP_Info.start = m_RTP_Info.end = m_RTP_Info.nal.start ;
- m_bBeginNAL = true ;
-
- return true ;
- }
-
-
- unsigned char* Get ( unsigned short *pPacketSize )
- {
- if ( m_RTP_Info.end == m_RTP_Info.nal.end )
- {
- *pPacketSize = 0 ;
- return NULL ;
- }
-
- if ( m_bBeginNAL )
- {
- m_bBeginNAL = false ;
- }
- else
- {
- m_RTP_Info.start = m_RTP_Info.end;
- }
-
- int bytesLeft = m_RTP_Info.nal.end - m_RTP_Info.start ;
- int maxSize = m_MAXRTPPACKSIZE - 12 ;
- if ( m_RTP_Info.FU_flag )
- maxSize -= 2 ;
-
- if ( bytesLeft > maxSize )
- {
- // limit RTP packetsize to 1472 bytes
- m_RTP_Info.end = m_RTP_Info.start + maxSize ;
- }
- else
- {
- m_RTP_Info.end = m_RTP_Info.start + bytesLeft ;
- }
-
- if ( m_RTP_Info.FU_flag )
- {
- if ( m_RTP_Info.end == m_RTP_Info.nal.end )
- {
- m_RTP_Info.e_bit = 1 ;
- }
- }
- // should be set at EofFrame
- m_RTP_Info.rtp_hdr.m = m_RTP_Info.nal.eoFrame ? 1 : 0 ;
- if ( m_RTP_Info.FU_flag && !m_RTP_Info.e_bit )
- {
- m_RTP_Info.rtp_hdr.m = 0 ;
- }
-
- m_RTP_Info.rtp_hdr.seq++ ;
-
- unsigned char *cp = m_RTP_Info.start ;
- cp -= ( m_RTP_Info.FU_flag ? 14 : 12 ) ;
- m_RTP_Info.pRTP = cp ;
-
- unsigned char *cp2 = (unsigned char *)&m_RTP_Info.rtp_hdr ;
- cp[0] = cp2[0] ;
- cp[1] = cp2[1] ;
-
- cp[2] = ( m_RTP_Info.rtp_hdr.seq >> 8 ) & 0xff ;
- cp[3] = m_RTP_Info.rtp_hdr.seq & 0xff ;
-
- cp[4] = ( m_RTP_Info.rtp_hdr.ts >> 24 ) & 0xff ;
- cp[5] = ( m_RTP_Info.rtp_hdr.ts >> 16 ) & 0xff ;
- cp[6] = ( m_RTP_Info.rtp_hdr.ts >> 8 ) & 0xff ;
- cp[7] = m_RTP_Info.rtp_hdr.ts & 0xff ;
-
- cp[8] = ( m_RTP_Info.rtp_hdr.ssrc >> 24 ) & 0xff ;
- cp[9] = ( m_RTP_Info.rtp_hdr.ssrc >> 16 ) & 0xff ;
- cp[10] = ( m_RTP_Info.rtp_hdr.ssrc >> 8 ) & 0xff ;
- cp[11] = m_RTP_Info.rtp_hdr.ssrc & 0xff ;
- m_RTP_Info.hdr_len = 12 ;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- if ( m_RTP_Info.FU_flag )
- {
-
- cp[12] = ( m_RTP_Info.nal.type & 0xe0 ) | 28 ;
-
- cp[13] = ( m_RTP_Info.s_bit << 7 )
- | ( m_RTP_Info.e_bit << 6 ) | ( m_RTP_Info.nal.type & 0x1f ) ;
-
-
- m_RTP_Info.s_bit = m_RTP_Info.e_bit= 0 ;
- m_RTP_Info.hdr_len = 14 ;
- }
- m_RTP_Info.start = &cp[m_RTP_Info.hdr_len] ;
-
- *pPacketSize = m_RTP_Info.hdr_len + ( m_RTP_Info.end - m_RTP_Info.start ) ;
- return m_RTP_Info.pRTP ;
- }
-
- private:
- unsigned int StartCode( unsigned char *cp )
- {
- unsigned int d32 ;
- d32 = cp[3] ;
- d32 <<= 8 ;
- d32 |= cp[2] ;
- d32 <<= 8 ;
- d32 |= cp[1] ;
- d32 <<= 8 ;
- d32 |= cp[0] ;
- return d32 ;
- }
-
- private:
- RTP_INFO m_RTP_Info ;
- bool m_bBeginNAL ;
- unsigned short m_MAXRTPPACKSIZE ;
- };
// class CH264_RTP_PACK end
(dengzikun)
|