织梦CMS - 轻松建站从此开始!

罗索

基于RTP的H264视频数据打包解包类

落鹤生 发布于 2011-01-14 16:17 点击:次 
最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包、解包的文档和代码。功夫不负有心人,找到不少有价值的文档和代码。参考这些资料,写了H264 RTP打包类、解包类,实现了单个NAL单元包和FU_A分片单元包。
TAG:

最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包、解包的文档和代码。功夫不负有心人,找到不少有价值的文档 和代码。参考这些资料,写了H264 RTP打包类、解包类,实现了单个NAL单元包和FU_A分片单元包。对于丢包处理,采用简单的策略:丢弃随后的所有数据包,直到收到关键帧。测试效果还 不错,代码贴上来,若能为同道中人借鉴一二,足矣。两个类的使用说明如下(省略了错误处理过程):
RTP打包H264 NALU类使用范例代码:

  1. DWORD H264SSRC ; 
  2. CH264_RTP_PACK pack ( H264SSRC ) ; 
  3. BYTE *pVideoData ; 
  4. DWORD Size, ts ; 
  5. bool IsEndOfFrame ; 
  6. WORD wLen ; 
  7. pack.Set ( pVideoData, Size, ts, IsEndOfFrame ) ; 
  8. BYTE *pPacket ; 
  9. while ( pPacket = pack.Get ( &wLen ) ) 
  10.  // rtp packet process 
  11.  // ... 

RTP 承载H.264 Payload NALU 的打包类源码
// class CH264_RTP_PACK start

  1. class CH264_RTP_PACK 
  2.     #define RTP_VERSION 2 
  3.  
  4.     typedef struct NAL_msg_s 
  5.     { 
  6.         bool eoFrame ; 
  7.         unsigned char type;// NAL type 
  8.         unsigned char *start;// pointer to first location in the send buffer 
  9.         unsigned char *end;// pointer to last location in send buffer 
  10.         unsigned long size ; 
  11.     } NAL_MSG_t; 
  12.  
  13.     typedef struct 
  14.     { 
  15.         //LITTLE_ENDIAN 
  16.         unsigned short   cc:4; /* CSRC count                 */ 
  17.         unsigned short   x:1;  /* header extension flag      */ 
  18.         unsigned short   p:1;  /* padding flag               */ 
  19.         unsigned short   v:2;  /* packet type                */ 
  20.         unsigned short   pt:7; /* payload type               */ 
  21.         unsigned short   m:1;  /* marker bit                 */ 
  22.  
  23.         unsigned short    seq; /* sequence number            */ 
  24.         unsigned long     ts;  /* timestamp                  */ 
  25.         unsigned long     ssrc;/* synchronization source     */ 
  26.     } rtp_hdr_t; 
  27.  
  28.     typedef struct tagRTP_INFO 
  29.     { 
  30.         NAL_MSG_t    nal;    // NAL information 
  31.         rtp_hdr_t    rtp_hdr;// RTP header is assembled here 
  32.         int hdr_len;// length of RTP header 
  33.  
  34.         unsigned char *pRTP; // pointer to where RTP packet has beem assembled 
  35.         unsigned char *start;// pointer to start of payload 
  36.         unsigned char *end;  // pointer to end of payload 
  37.  
  38.         unsigned int s_bit;  // bit in the FU header 
  39.         unsigned int e_bit;  // bit in the FU header 
  40.         bool FU_flag;        // fragmented NAL Unit flag 
  41.     } RTP_INFO; 
  42.  
  43. public
  44.     CH264_RTP_PACK(unsigned long H264SSRC, unsigned char H264PAYLOADTYPE=96
  45. , unsigned short MAXRTPPACKSIZE=1472 ) 
  46.     { 
  47.         m_MAXRTPPACKSIZE = MAXRTPPACKSIZE ; 
  48.         if ( m_MAXRTPPACKSIZE > 10000 ) 
  49.         { 
  50.             m_MAXRTPPACKSIZE = 10000 ; 
  51.         } 
  52.         if ( m_MAXRTPPACKSIZE < 50 ) 
  53.         { 
  54.             m_MAXRTPPACKSIZE = 50 ; 
  55.         } 
  56.         
  57.         memset ( &m_RTP_Info, 0, sizeof(m_RTP_Info) ) ; 
  58.  
  59.         m_RTP_Info.rtp_hdr.pt = H264PAYLOADTYPE ; 
  60.         m_RTP_Info.rtp_hdr.ssrc = H264SSRC ; 
  61.         m_RTP_Info.rtp_hdr.v = RTP_VERSION ; 
  62.  
  63.         m_RTP_Info.rtp_hdr.seq = 0 ; 
  64.     } 
  65.  
  66.     ~CH264_RTP_PACK(void
  67.     { 
  68.     } 
  69.  
  70. //传入Set的数据必须是一个完整的NAL,起始码为0x00000001。 
  71. //起始码之前至少预留10个字节,以避免内存COPY操作。 
  72. //打包完成后,原缓冲区内的数据被破坏。 
  73.     bool Set ( unsigned char *NAL_Buf, unsigned long NAL_Size
  74. , unsigned long Time_Stamp, bool End_Of_Frame ) 
  75.     { 
  76.         unsigned long startcode = StartCode(NAL_Buf) ; 
  77.         
  78.         if ( startcode != 0x01000000 ) 
  79.         { 
  80.             return false ; 
  81.         } 
  82.  
  83.         int type = NAL_Buf[4] & 0x1f ; 
  84.         if ( type < 1 || type > 12 ) 
  85.         { 
  86.             return false ; 
  87.         } 
  88.  
  89.         m_RTP_Info.nal.start = NAL_Buf ; 
  90.         m_RTP_Info.nal.size = NAL_Size ; 
  91.         m_RTP_Info.nal.eoFrame = End_Of_Frame ; 
  92.         m_RTP_Info.nal.type = m_RTP_Info.nal.start[4] ; 
  93.         m_RTP_Info.nal.end = m_RTP_Info.nal.start + m_RTP_Info.nal.size ; 
  94.  
  95.         m_RTP_Info.rtp_hdr.ts = Time_Stamp ; 
  96.  
  97.         m_RTP_Info.nal.start += 4 ;    // skip the syncword 
  98.                                     
  99.         if ( (m_RTP_Info.nal.size + 7) > m_MAXRTPPACKSIZE ) 
  100.         { 
  101.             m_RTP_Info.FU_flag = true ; 
  102.             m_RTP_Info.s_bit = 1 ; 
  103.             m_RTP_Info.e_bit = 0 ; 
  104.  
  105.             m_RTP_Info.nal.start += 1 ;    // skip NAL header 
  106.         } 
  107.         else 
  108.         { 
  109.             m_RTP_Info.FU_flag = false ; 
  110.             m_RTP_Info.s_bit = m_RTP_Info.e_bit = 0 ; 
  111.         } 
  112.         
  113.         m_RTP_Info.start = m_RTP_Info.end = m_RTP_Info.nal.start ; 
  114.         m_bBeginNAL = true ; 
  115.  
  116.         return true ; 
  117.     } 
  118.  
  119.     //循环调用Get获取RTP包,直到返回值为NULL 
  120.     unsigned char* Get ( unsigned short *pPacketSize ) 
  121.     { 
  122.         if ( m_RTP_Info.end == m_RTP_Info.nal.end ) 
  123.         { 
  124.             *pPacketSize = 0 ; 
  125.             return NULL ; 
  126.         } 
  127.  
  128.         if ( m_bBeginNAL ) 
  129.         { 
  130.             m_bBeginNAL = false ; 
  131.         } 
  132.         else 
  133.         { 
  134. m_RTP_Info.start = m_RTP_Info.end;// continue with the next RTP-FU packet 
  135.         } 
  136.  
  137.         int bytesLeft = m_RTP_Info.nal.end - m_RTP_Info.start ; 
  138. int maxSize = m_MAXRTPPACKSIZE - 12 ; // sizeof(basic rtp header) == 12 bytes 
  139.         if ( m_RTP_Info.FU_flag ) 
  140.             maxSize -= 2 ; 
  141.  
  142.         if ( bytesLeft > maxSize ) 
  143.         {
  144. // limit RTP packetsize to 1472 bytes
  145.             m_RTP_Info.end = m_RTP_Info.start + maxSize ;
  146.         } 
  147.         else 
  148.         { 
  149.             m_RTP_Info.end = m_RTP_Info.start + bytesLeft ; 
  150.         } 
  151.  
  152.         if ( m_RTP_Info.FU_flag ) 
  153.         {    // multiple packet NAL slice 
  154.             if ( m_RTP_Info.end == m_RTP_Info.nal.end ) 
  155.             { 
  156.                 m_RTP_Info.e_bit = 1 ; 
  157.             } 
  158.         }
  159. // should be set at EofFrame
  160.         m_RTP_Info.rtp_hdr.m =    m_RTP_Info.nal.eoFrame ? 1 : 0 ;
  161.         if ( m_RTP_Info.FU_flag && !m_RTP_Info.e_bit )
  162.         { 
  163.             m_RTP_Info.rtp_hdr.m = 0 ; 
  164.         } 
  165.  
  166.         m_RTP_Info.rtp_hdr.seq++ ; 
  167.  
  168.         unsigned char *cp = m_RTP_Info.start ; 
  169.         cp -= ( m_RTP_Info.FU_flag ? 14 : 12 ) ; 
  170.         m_RTP_Info.pRTP = cp ; 
  171.         
  172.         unsigned char *cp2 = (unsigned char *)&m_RTP_Info.rtp_hdr ; 
  173.         cp[0] = cp2[0] ; 
  174.         cp[1] = cp2[1] ; 
  175.  
  176.         cp[2] = ( m_RTP_Info.rtp_hdr.seq >> 8 ) & 0xff ; 
  177.         cp[3] = m_RTP_Info.rtp_hdr.seq & 0xff ; 
  178.  
  179.         cp[4] = ( m_RTP_Info.rtp_hdr.ts >> 24 ) & 0xff ; 
  180.         cp[5] = ( m_RTP_Info.rtp_hdr.ts >> 16 ) & 0xff ; 
  181.         cp[6] = ( m_RTP_Info.rtp_hdr.ts >>  8 ) & 0xff ; 
  182.         cp[7] = m_RTP_Info.rtp_hdr.ts & 0xff ; 
  183.  
  184.         cp[8] =  ( m_RTP_Info.rtp_hdr.ssrc >> 24 ) & 0xff ; 
  185.         cp[9] =  ( m_RTP_Info.rtp_hdr.ssrc >> 16 ) & 0xff ; 
  186.         cp[10] = ( m_RTP_Info.rtp_hdr.ssrc >>  8 ) & 0xff ; 
  187.         cp[11] = m_RTP_Info.rtp_hdr.ssrc & 0xff ; 
  188.         m_RTP_Info.hdr_len = 12 ; 
  189. /*! 
  190. * \n The FU indicator octet has the following format: 
  191. * \n 
  192. * \n      +---------------+ 
  193. * \n MSB  |0|1|2|3|4|5|6|7|  LSB 
  194. * \n      +-+-+-+-+-+-+-+-+ 
  195. * \n      |F|NRI|  Type   | 
  196. * \n      +---------------+ 
  197. * \n 
  198. * \n The FU header has the following format: 
  199. * \n 
  200. * \n      +---------------+ 
  201. * \n      |0|1|2|3|4|5|6|7| 
  202. * \n      +-+-+-+-+-+-+-+-+ 
  203. * \n      |S|E|R|  Type   | 
  204. * \n      +---------------+ 
  205. */ 
  206.         if ( m_RTP_Info.FU_flag ) 
  207.         { 
  208.             // FU indicator  F|NRI|Type 
  209.             cp[12] = ( m_RTP_Info.nal.type & 0xe0 ) | 28 ;//Type is 28 for FU_A 
  210.             //FU header        S|E|R|Type 
  211.             cp[13] = ( m_RTP_Info.s_bit << 7 )
  212.  | ( m_RTP_Info.e_bit << 6 ) | ( m_RTP_Info.nal.type & 0x1f ) ;
  213. //R = 0, must be ignored by receiver 
  214.  
  215.             m_RTP_Info.s_bit = m_RTP_Info.e_bit= 0 ; 
  216.             m_RTP_Info.hdr_len = 14 ; 
  217.         } 
  218.         m_RTP_Info.start = &cp[m_RTP_Info.hdr_len] ;    // new start of payload 
  219.  
  220.         *pPacketSize = m_RTP_Info.hdr_len + ( m_RTP_Info.end - m_RTP_Info.start ) ; 
  221.         return m_RTP_Info.pRTP ; 
  222.     } 
  223.  
  224. private
  225.     unsigned int StartCode( unsigned char *cp ) 
  226.     { 
  227.         unsigned int d32 ; 
  228.         d32 = cp[3] ; 
  229.         d32 <<= 8 ; 
  230.         d32 |= cp[2] ; 
  231.         d32 <<= 8 ; 
  232.         d32 |= cp[1] ; 
  233.         d32 <<= 8 ; 
  234.         d32 |= cp[0] ; 
  235.         return d32 ; 
  236.     } 
  237.  
  238. private
  239.     RTP_INFO m_RTP_Info ; 
  240.     bool m_bBeginNAL ; 
  241.     unsigned short m_MAXRTPPACKSIZE ; 
  242. }; 


// class CH264_RTP_PACK end
(dengzikun)

本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201101/10763.html]
本文出处:CSDN博客 作者:dengzikun
顶一下
(7)
63.6%
踩一下
(4)
36.4%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容