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

简介: from:http://blog.csdn.net/dengzikun/article/details/5807694 最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包、解包的文档和代码。

from:http://blog.csdn.net/dengzikun/article/details/5807694

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

 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 packet process
  // ...
 }


 HRESULT hr ;
 CH264_RTP_UNPACK unpack ( hr ) ;
 BYTE *pRtpData ;
 WORD inSize;
 int outSize ;
 BYTE *pFrame = unpack.Parse_RTP_Packet ( pRtpData, inSize, &outSize ) ;
 if ( pFrame != NULL )
 {
  // frame process
  // ...
 }

 

 

 

[cpp]  view plain copy
 
  1. //////////////////////////////////////////////////////////////////////////////////////////  
  2. // class CH264_RTP_PACK start  
  3.   
  4. class CH264_RTP_PACK  
  5. {  
  6.     #define RTP_VERSION 2  
  7.   
  8.     typedef struct NAL_msg_s   
  9.     {  
  10.         bool eoFrame ;  
  11.         unsigned char type;     // NAL type  
  12.         unsigned char *start;   // pointer to first location in the send buffer  
  13.         unsigned char *end; // pointer to last location in send buffer  
  14.         unsigned long size ;  
  15.     } NAL_MSG_t;  
  16.   
  17.     typedef struct   
  18.     {  
  19.         //LITTLE_ENDIAN  
  20.         unsigned short   cc:4;      /* CSRC count                 */  
  21.         unsigned short   x:1;       /* header extension flag      */  
  22.         unsigned short   p:1;       /* padding flag               */  
  23.         unsigned short   v:2;       /* packet type                */  
  24.         unsigned short   pt:7;      /* payload type               */  
  25.         unsigned short   m:1;       /* marker bit                 */  
  26.   
  27.         unsigned short    seq;      /* sequence number            */  
  28.         unsigned long     ts;       /* timestamp                  */  
  29.         unsigned long     ssrc;     /* synchronization source     */  
  30.     } rtp_hdr_t;  
  31.   
  32.     typedef struct tagRTP_INFO  
  33.     {  
  34.         NAL_MSG_t   nal;        // NAL information  
  35.         rtp_hdr_t   rtp_hdr;    // RTP header is assembled here  
  36.         int hdr_len;            // length of RTP header  
  37.   
  38.         unsigned char *pRTP;    // pointer to where RTP packet has beem assembled  
  39.         unsigned char *start;   // pointer to start of payload  
  40.         unsigned char *end;     // pointer to end of payload  
  41.   
  42.         unsigned int s_bit;     // bit in the FU header  
  43.         unsigned int e_bit;     // bit in the FU header  
  44.         bool FU_flag;       // fragmented NAL Unit flag  
  45.     } RTP_INFO;  
  46.   
  47. public:  
  48.     CH264_RTP_PACK(unsigned long H264SSRC, unsigned char H264PAYLOADTYPE=96, unsigned short MAXRTPPACKSIZE=1472 )  
  49.     {  
  50.         m_MAXRTPPACKSIZE = MAXRTPPACKSIZE ;  
  51.         if ( m_MAXRTPPACKSIZE > 10000 )  
  52.         {  
  53.             m_MAXRTPPACKSIZE = 10000 ;  
  54.         }  
  55.         if ( m_MAXRTPPACKSIZE < 50 )  
  56.         {  
  57.             m_MAXRTPPACKSIZE = 50 ;  
  58.         }  
  59.           
  60.         memset ( &m_RTP_Info, 0, sizeof(m_RTP_Info) ) ;  
  61.   
  62.         m_RTP_Info.rtp_hdr.pt = H264PAYLOADTYPE ;  
  63.         m_RTP_Info.rtp_hdr.ssrc = H264SSRC ;  
  64.         m_RTP_Info.rtp_hdr.v = RTP_VERSION ;  
  65.   
  66.         m_RTP_Info.rtp_hdr.seq = 0 ;  
  67.     }  
  68.   
  69.     ~CH264_RTP_PACK(void)  
  70.     {  
  71.     }  
  72.   
  73.     //传入Set的数据必须是一个完整的NAL,起始码为0x00000001。  
  74.     //起始码之前至少预留10个字节,以避免内存COPY操作。  
  75.     //打包完成后,原缓冲区内的数据被破坏。  
  76.     bool Set ( unsigned char *NAL_Buf, unsigned long NAL_Size, unsigned long Time_Stamp, bool End_Of_Frame )  
  77.     {  
  78.         unsigned long startcode = StartCode(NAL_Buf) ;  
  79.           
  80.         if ( startcode != 0x01000000 )  
  81.         {  
  82.             return false ;  
  83.         }  
  84.   
  85.         int type = NAL_Buf[4] & 0x1f ;  
  86.         if ( type < 1 || type > 12 )  
  87.         {  
  88.             return false ;  
  89.         }  
  90.   
  91.         m_RTP_Info.nal.start = NAL_Buf ;  
  92.         m_RTP_Info.nal.size = NAL_Size ;  
  93.         m_RTP_Info.nal.eoFrame = End_Of_Frame ;  
  94.         m_RTP_Info.nal.type = m_RTP_Info.nal.start[4] ;  
  95.         m_RTP_Info.nal.end = m_RTP_Info.nal.start + m_RTP_Info.nal.size ;  
  96.   
  97.         m_RTP_Info.rtp_hdr.ts = Time_Stamp ;  
  98.   
  99.         m_RTP_Info.nal.start += 4 ; // skip the syncword  
  100.                                       
  101.         if ( (m_RTP_Info.nal.size + 7) > m_MAXRTPPACKSIZE )  
  102.         {  
  103.             m_RTP_Info.FU_flag = true ;  
  104.             m_RTP_Info.s_bit = 1 ;  
  105.             m_RTP_Info.e_bit = 0 ;  
  106.   
  107.             m_RTP_Info.nal.start += 1 ; // skip NAL header  
  108.         }  
  109.         else  
  110.         {  
  111.             m_RTP_Info.FU_flag = false ;  
  112.             m_RTP_Info.s_bit = m_RTP_Info.e_bit = 0 ;  
  113.         }  
  114.           
  115.         m_RTP_Info.start = m_RTP_Info.end = m_RTP_Info.nal.start ;  
  116.         m_bBeginNAL = true ;  
  117.   
  118.         return true ;  
  119.     }  
  120.   
  121.     //循环调用Get获取RTP包,直到返回值为NULL  
  122.     unsigned char* Get ( unsigned short *pPacketSize )  
  123.     {  
  124.         if ( m_RTP_Info.end == m_RTP_Info.nal.end )  
  125.         {  
  126.             *pPacketSize = 0 ;  
  127.             return NULL ;  
  128.         }  
  129.   
  130.         if ( m_bBeginNAL )  
  131.         {  
  132.             m_bBeginNAL = false ;  
  133.         }  
  134.         else  
  135.         {  
  136.             m_RTP_Info.start = m_RTP_Info.end;  // continue with the next RTP-FU packet  
  137.         }  
  138.   
  139.         int bytesLeft = m_RTP_Info.nal.end - m_RTP_Info.start ;  
  140.         int maxSize = m_MAXRTPPACKSIZE - 12 ;   // sizeof(basic rtp header) == 12 bytes  
  141.         if ( m_RTP_Info.FU_flag )  
  142.             maxSize -= 2 ;  
  143.   
  144.         if ( bytesLeft > maxSize )  
  145.         {  
  146.             m_RTP_Info.end = m_RTP_Info.start + maxSize ;   // limit RTP packetsize to 1472 bytes  
  147.         }  
  148.         else  
  149.         {  
  150.             m_RTP_Info.end = m_RTP_Info.start + bytesLeft ;  
  151.         }  
  152.   
  153.         if ( m_RTP_Info.FU_flag )  
  154.         {   // multiple packet NAL slice  
  155.             if ( m_RTP_Info.end == m_RTP_Info.nal.end )  
  156.             {  
  157.                 m_RTP_Info.e_bit = 1 ;  
  158.             }  
  159.         }  
  160.   
  161.         m_RTP_Info.rtp_hdr.m =  m_RTP_Info.nal.eoFrame ? 1 : 0 ; // should be set at EofFrame  
  162.         if ( m_RTP_Info.FU_flag && !m_RTP_Info.e_bit )  
  163.         {  
  164.             m_RTP_Info.rtp_hdr.m = 0 ;  
  165.         }  
  166.   
  167.         m_RTP_Info.rtp_hdr.seq++ ;  
  168.   
  169.         unsigned char *cp = m_RTP_Info.start ;  
  170.         cp -= ( m_RTP_Info.FU_flag ? 14 : 12 ) ;  
  171.         m_RTP_Info.pRTP = cp ;  
  172.           
  173.         unsigned char *cp2 = (unsigned char *)&m_RTP_Info.rtp_hdr ;  
  174.         cp[0] = cp2[0] ;  
  175.         cp[1] = cp2[1] ;  
  176.   
  177.         cp[2] = ( m_RTP_Info.rtp_hdr.seq >> 8 ) & 0xff ;  
  178.         cp[3] = m_RTP_Info.rtp_hdr.seq & 0xff ;  
  179.   
  180.         cp[4] = ( m_RTP_Info.rtp_hdr.ts >> 24 ) & 0xff ;  
  181.         cp[5] = ( m_RTP_Info.rtp_hdr.ts >> 16 ) & 0xff ;  
  182.         cp[6] = ( m_RTP_Info.rtp_hdr.ts >>  8 ) & 0xff ;  
  183.         cp[7] = m_RTP_Info.rtp_hdr.ts & 0xff ;  
  184.   
  185.         cp[8] =  ( m_RTP_Info.rtp_hdr.ssrc >> 24 ) & 0xff ;  
  186.         cp[9] =  ( m_RTP_Info.rtp_hdr.ssrc >> 16 ) & 0xff ;  
  187.         cp[10] = ( m_RTP_Info.rtp_hdr.ssrc >>  8 ) & 0xff ;  
  188.         cp[11] = m_RTP_Info.rtp_hdr.ssrc & 0xff ;  
  189.         m_RTP_Info.hdr_len = 12 ;  
  190.         /*! 
  191.         * /n The FU indicator octet has the following format: 
  192.         * /n 
  193.         * /n      +---------------+ 
  194.         * /n MSB  |0|1|2|3|4|5|6|7|  LSB 
  195.         * /n      +-+-+-+-+-+-+-+-+ 
  196.         * /n      |F|NRI|  Type   | 
  197.         * /n      +---------------+ 
  198.         * /n 
  199.         * /n The FU header has the following format: 
  200.         * /n 
  201.         * /n      +---------------+ 
  202.         * /n      |0|1|2|3|4|5|6|7| 
  203.         * /n      +-+-+-+-+-+-+-+-+ 
  204.         * /n      |S|E|R|  Type   | 
  205.         * /n      +---------------+ 
  206.         */  
  207.         if ( m_RTP_Info.FU_flag )  
  208.         {  
  209.             // FU indicator  F|NRI|Type  
  210.             cp[12] = ( m_RTP_Info.nal.type & 0xe0 ) | 28 ;  //Type is 28 for FU_A  
  211.             //FU header     S|E|R|Type  
  212.             cp[13] = ( m_RTP_Info.s_bit << 7 ) | ( m_RTP_Info.e_bit << 6 ) | ( m_RTP_Info.nal.type & 0x1f ) ; //R = 0, must be ignored by receiver  
  213.   
  214.             m_RTP_Info.s_bit = m_RTP_Info.e_bit= 0 ;  
  215.             m_RTP_Info.hdr_len = 14 ;  
  216.         }  
  217.         m_RTP_Info.start = &cp[m_RTP_Info.hdr_len] ;    // new start of payload  
  218.   
  219.         *pPacketSize = m_RTP_Info.hdr_len + ( m_RTP_Info.end - m_RTP_Info.start ) ;  
  220.         return m_RTP_Info.pRTP ;  
  221.     }  
  222.   
  223. private:  
  224.     unsigned int StartCode( unsigned char *cp )  
  225.     {  
  226.         unsigned int d32 ;  
  227.         d32 = cp[3] ;  
  228.         d32 <<= 8 ;  
  229.         d32 |= cp[2] ;  
  230.         d32 <<= 8 ;  
  231.         d32 |= cp[1] ;  
  232.         d32 <<= 8 ;  
  233.         d32 |= cp[0] ;  
  234.         return d32 ;  
  235.     }  
  236.   
  237. private:  
  238.     RTP_INFO m_RTP_Info ;  
  239.     bool m_bBeginNAL ;  
  240.     unsigned short m_MAXRTPPACKSIZE ;  
  241. };  
  242.   
  243. // class CH264_RTP_PACK end  
  244. //////////////////////////////////////////////////////////////////////////////////////////  
  245.   
  246.   
  247. //////////////////////////////////////////////////////////////////////////////////////////  
  248. // class CH264_RTP_UNPACK start  
  249.   
  250. class CH264_RTP_UNPACK  
  251. {  
  252.   
  253. #define RTP_VERSION 2  
  254. #define BUF_SIZE (1024 * 500)  
  255.   
  256.     typedef struct   
  257.     {  
  258.         //LITTLE_ENDIAN  
  259.         unsigned short   cc:4;      /* CSRC count                 */  
  260.         unsigned short   x:1;       /* header extension flag      */  
  261.         unsigned short   p:1;       /* padding flag               */  
  262.         unsigned short   v:2;       /* packet type                */  
  263.         unsigned short   pt:7;      /* payload type               */  
  264.         unsigned short   m:1;       /* marker bit                 */  
  265.   
  266.         unsigned short    seq;      /* sequence number            */  
  267.         unsigned long     ts;       /* timestamp                  */  
  268.         unsigned long     ssrc;     /* synchronization source     */  
  269.     } rtp_hdr_t;  
  270. public:  
  271.   
  272.     CH264_RTP_UNPACK ( HRESULT &hr, unsigned char H264PAYLOADTYPE = 96 )  
  273.         : m_bSPSFound(false)  
  274.         , m_bWaitKeyFrame(true)  
  275.         , m_bPrevFrameEnd(false)  
  276.         , m_bAssemblingFrame(false)  
  277.         , m_wSeq(1234)  
  278.         , m_ssrc(0)  
  279.     {  
  280.         m_pBuf = new BYTE[BUF_SIZE] ;  
  281.         if ( m_pBuf == NULL )  
  282.         {  
  283.             hr = E_OUTOFMEMORY ;  
  284.             return ;  
  285.         }  
  286.   
  287.         m_H264PAYLOADTYPE = H264PAYLOADTYPE ;  
  288.         m_pEnd = m_pBuf + BUF_SIZE ;  
  289.         m_pStart = m_pBuf ;  
  290.         m_dwSize = 0 ;  
  291.         hr = S_OK ;  
  292.     }  
  293.   
  294.     ~CH264_RTP_UNPACK(void)  
  295.     {  
  296.         delete [] m_pBuf ;  
  297.     }  
  298.   
  299.     //pBuf为H264 RTP视频数据包,nSize为RTP视频数据包字节长度,outSize为输出视频数据帧字节长度。  
  300.     //返回值为指向视频数据帧的指针。输入数据可能被破坏。  
  301.     BYTE* Parse_RTP_Packet ( BYTE *pBuf, unsigned short nSize, int *outSize )  
  302.     {  
  303.         if ( nSize <= 12 )  
  304.         {  
  305.             return NULL ;  
  306.         }  
  307.   
  308.         BYTE *cp = (BYTE*)&m_RTP_Header ;  
  309.         cp[0] = pBuf[0] ;  
  310.         cp[1] = pBuf[1] ;  
  311.   
  312.         m_RTP_Header.seq = pBuf[2] ;  
  313.         m_RTP_Header.seq <<= 8 ;  
  314.         m_RTP_Header.seq |= pBuf[3] ;  
  315.   
  316.         m_RTP_Header.ts = pBuf[4] ;  
  317.         m_RTP_Header.ts <<= 8 ;  
  318.         m_RTP_Header.ts |= pBuf[5] ;  
  319.         m_RTP_Header.ts <<= 8 ;  
  320.         m_RTP_Header.ts |= pBuf[6] ;  
  321.         m_RTP_Header.ts <<= 8 ;  
  322.         m_RTP_Header.ts |= pBuf[7] ;  
  323.   
  324.         m_RTP_Header.ssrc = pBuf[8] ;  
  325.         m_RTP_Header.ssrc <<= 8 ;  
  326.         m_RTP_Header.ssrc |= pBuf[9] ;  
  327.         m_RTP_Header.ssrc <<= 8 ;  
  328.         m_RTP_Header.ssrc |= pBuf[10] ;  
  329.         m_RTP_Header.ssrc <<= 8 ;  
  330.         m_RTP_Header.ssrc |= pBuf[11] ;  
  331.   
  332.         BYTE *pPayload = pBuf + 12 ;  
  333.         DWORD PayloadSize = nSize - 12 ;  
  334.   
  335.         // Check the RTP version number (it should be 2):  
  336.         if ( m_RTP_Header.v != RTP_VERSION )  
  337.         {  
  338.             return NULL ;  
  339.         }  
  340.   
  341.         /* 
  342.         // Skip over any CSRC identifiers in the header: 
  343.         if ( m_RTP_Header.cc ) 
  344.         { 
  345.             long cc = m_RTP_Header.cc * 4 ; 
  346.             if ( Size < cc ) 
  347.             { 
  348.                 return NULL ; 
  349.             } 
  350.  
  351.             Size -= cc ; 
  352.             p += cc ; 
  353.         } 
  354.  
  355.         // Check for (& ignore) any RTP header extension 
  356.         if ( m_RTP_Header.x ) 
  357.         { 
  358.             if ( Size < 4 ) 
  359.             { 
  360.                 return NULL ; 
  361.             } 
  362.  
  363.             Size -= 4 ; 
  364.             p += 2 ; 
  365.             long l = p[0] ; 
  366.             l <<= 8 ; 
  367.             l |= p[1] ; 
  368.             p += 2 ; 
  369.             l *= 4 ; 
  370.             if ( Size < l ) ; 
  371.             { 
  372.                 return NULL ; 
  373.             } 
  374.             Size -= l ; 
  375.             p += l ; 
  376.         } 
  377.          
  378.         // Discard any padding bytes: 
  379.         if ( m_RTP_Header.p ) 
  380.         { 
  381.             if ( Size == 0 ) 
  382.             { 
  383.                 return NULL ; 
  384.             } 
  385.             long Padding = p[Size-1] ; 
  386.             if ( Size < Padding ) 
  387.             { 
  388.                 return NULL ; 
  389.             } 
  390.             Size -= Padding ; 
  391.         }*/  
  392.   
  393.         // Check the Payload Type.  
  394.         if ( m_RTP_Header.pt != m_H264PAYLOADTYPE )  
  395.         {  
  396.             return NULL ;  
  397.         }  
  398.   
  399.         int PayloadType = pPayload[0] & 0x1f ;  
  400.         int NALType = PayloadType ;  
  401.         if ( NALType == 28 ) // FU_A  
  402.         {  
  403.             if ( PayloadSize < 2 )  
  404.             {  
  405.                 return NULL ;  
  406.             }  
  407.   
  408.             NALType = pPayload[1] & 0x1f ;  
  409.         }  
  410.   
  411.         if ( m_ssrc != m_RTP_Header.ssrc )  
  412.         {  
  413.             m_ssrc = m_RTP_Header.ssrc ;  
  414.             SetLostPacket () ;  
  415.         }  
  416.       
  417.         if ( NALType == 0x07 ) // SPS  
  418.         {  
  419.             m_bSPSFound = true ;  
  420.         }  
  421.   
  422.         if ( !m_bSPSFound )  
  423.         {  
  424.             return NULL ;  
  425.         }  
  426.   
  427.         if ( NALType == 0x07 || NALType == 0x08 ) // SPS PPS  
  428.         {  
  429.             m_wSeq = m_RTP_Header.seq ;  
  430.             m_bPrevFrameEnd = true ;  
  431.   
  432.             pPayload -= 4 ;  
  433.             *((DWORD*)(pPayload)) = 0x01000000 ;  
  434.             *outSize = PayloadSize + 4 ;  
  435.             return pPayload ;  
  436.         }  
  437.   
  438.         if ( m_bWaitKeyFrame )  
  439.         {  
  440.             if ( m_RTP_Header.m ) // frame end  
  441.             {  
  442.                 m_bPrevFrameEnd = true ;  
  443.                 if ( !m_bAssemblingFrame )  
  444.                 {  
  445.                     m_wSeq = m_RTP_Header.seq ;  
  446.                     return NULL ;  
  447.                 }  
  448.             }  
  449.   
  450.             if ( !m_bPrevFrameEnd )  
  451.             {  
  452.                 m_wSeq = m_RTP_Header.seq ;  
  453.                 return NULL ;  
  454.             }  
  455.             else  
  456.             {  
  457.                 if ( NALType != 0x05 ) // KEY FRAME  
  458.                 {  
  459.                     m_wSeq = m_RTP_Header.seq ;  
  460.                     m_bPrevFrameEnd = false ;  
  461.                     return NULL ;  
  462.                 }  
  463.             }  
  464.         }  
  465.   
  466.   
  467. ///////////////////////////////////////////////////////////////  
  468.               
  469.         if ( m_RTP_Header.seq != (WORD)( m_wSeq + 1 ) ) // lost packet  
  470.         {  
  471.             m_wSeq = m_RTP_Header.seq ;  
  472.             SetLostPacket () ;            
  473.             return NULL ;  
  474.         }  
  475.         else  
  476.         {  
  477.             // 码流正常  
  478.   
  479.             m_wSeq = m_RTP_Header.seq ;  
  480.             m_bAssemblingFrame = true ;  
  481.               
  482.             if ( PayloadType != 28 ) // whole NAL  
  483.             {  
  484.                 *((DWORD*)(m_pStart)) = 0x01000000 ;  
  485.                 m_pStart += 4 ;  
  486.                 m_dwSize += 4 ;  
  487.             }  
  488.             else // FU_A  
  489.             {  
  490.                 if ( pPayload[1] & 0x80 ) // FU_A start  
  491.                 {  
  492.                     *((DWORD*)(m_pStart)) = 0x01000000 ;  
  493.                     m_pStart += 4 ;  
  494.                     m_dwSize += 4 ;  
  495.   
  496.                     pPayload[1] = ( pPayload[0] & 0xE0 ) | NALType ;  
  497.                       
  498.                     pPayload += 1 ;  
  499.                     PayloadSize -= 1 ;  
  500.                 }  
  501.                 else  
  502.                 {  
  503.                     pPayload += 2 ;  
  504.                     PayloadSize -= 2 ;  
  505.                 }  
  506.             }  
  507.   
  508.             if ( m_pStart + PayloadSize < m_pEnd )  
  509.             {  
  510.                 CopyMemory ( m_pStart, pPayload, PayloadSize ) ;  
  511.                 m_dwSize += PayloadSize ;  
  512.                 m_pStart += PayloadSize ;  
  513.             }  
  514.             else // memory overflow  
  515.             {  
  516.                 SetLostPacket () ;  
  517.                 return NULL ;  
  518.             }  
  519.   
  520.             if ( m_RTP_Header.m ) // frame end  
  521.             {  
  522.                 *outSize = m_dwSize ;  
  523.   
  524.                 m_pStart = m_pBuf ;  
  525.                 m_dwSize = 0 ;  
  526.   
  527.                 if ( NALType == 0x05 ) // KEY FRAME  
  528.                 {  
  529.                     m_bWaitKeyFrame = false ;  
  530.                 }  
  531.                 return m_pBuf ;  
  532.             }  
  533.             else  
  534.             {  
  535.                 return NULL ;  
  536.             }  
  537.         }  
  538.     }  
  539.   
  540.     void SetLostPacket()  
  541.     {  
  542.         m_bSPSFound = false ;  
  543.         m_bWaitKeyFrame = true ;  
  544.         m_bPrevFrameEnd = false ;  
  545.         m_bAssemblingFrame = false ;  
  546.         m_pStart = m_pBuf ;  
  547.         m_dwSize = 0 ;  
  548.     }  
  549.   
  550. private:  
  551.     rtp_hdr_t m_RTP_Header ;  
  552.   
  553.     BYTE *m_pBuf ;  
  554.   
  555.     bool m_bSPSFound ;  
  556.     bool m_bWaitKeyFrame ;  
  557.     bool m_bAssemblingFrame ;  
  558.     bool m_bPrevFrameEnd ;  
  559.     BYTE *m_pStart ;  
  560.     BYTE *m_pEnd ;  
  561.     DWORD m_dwSize ;  
  562.   
  563.     WORD m_wSeq ;  
  564.   
  565.     BYTE m_H264PAYLOADTYPE ;  
  566.     DWORD m_ssrc ;  
  567. };  
  568.   
  569. // class CH264_RTP_UNPACK end  
  570. //////////////////////////////////////////////////////////////////////////////////////////  

 

 
主题推荐
视频 数据 h264 timestamp sizeof
猜你在找
查看评论
23楼  _beginthreadex 2014-11-07 16:31发表 [回复]
调用博主的代码成功实现了对RTP包的解析和帧重组,直接保存成文件可以用VLC播放。另,博主的解包类里面似乎没有对SEI进行处理,所以在转换某个摄像机的视频时,我得到的数据全都是SPS与PPS,后查看直接保存的二进制文件,发现因为SEI也是有序列号的,不加1的话,下一次比较定会出错。已手动修改。
22楼  对牛乱弹琴 2014-07-09 09:40发表 [回复]
你好,非常感谢你的代码,我调试可以正常解包的。
但是我现在有个问题,UDP传输,我本机发送本机接收,总是断断续续的丢包,
if ( m_RTP_Header.seq != (WORD)( m_wSeq + 1 ) )//lost packet 
会进入到这个判断里面?百思不得解,希望博主提示一下哈。
谢谢
Re:  dengzikun 2014-07-09 23:20发表 [回复]
回复chen495810242:本机收发丢包,可能是收发速率不匹配,可以增大 socket缓冲区试试。试试把接收数据后的处理逻辑去掉,只接收数据。
Re:  对牛乱弹琴 2014-07-10 08:53发表 [回复]
回复dengzikun:额,我必须表示感谢,增加接收缓冲区大小就可以了,⊙﹏⊙b汗。

在麻烦一下,你还有其他组包模式的解析方式吗?
FU-B,STAP-A,STAP-B等,还有你说的错误处理省略了,能否也加上,我觉得这个其实更重要,非常感谢
Re:  dengzikun 2014-07-11 14:26发表 [回复]
回复chen495810242:"省略错误处理"是指博文中的类使用示例代码。这两个类是可以放心使用的。H264 RTP包的其他解析方式你可以参考live555等开源库。
Re:  对牛乱弹琴 2014-07-16 11:12发表 [回复]
回复dengzikun:如果是大端模式怎么处理啊?谢谢
Re:  dengzikun 2014-07-16 11:32发表 [回复]
回复chen495810242:typedef struct {
#ifdef _BIG_ENDIAN
unsigned short v:2; /* packet type */
unsigned short p:1; /* padding flag */
unsigned short x:1; /* header extension flag */
unsigned short cc:4; /* CSRC count */
unsigned short m:1; /* marker bit */
unsigned short pt:7; /* payload type */
#else
unsigned short cc:4; /* CSRC count */
unsigned short x:1; /* header extension flag */
unsigned short p:1; /* padding flag */
unsigned short v:2; /* packet type */
unsigned short pt:7; /* payload type */
unsigned short m:1; /* marker bit */
#endif
uint16_t seq; /* sequence number */
uint32_t ts; /* timestamp */
uint32_t ssrc; /* synchronization source */
} rtp_hdr_t;
21楼  nanqingzhe 2014-06-09 17:33发表 [回复]
楼主,最近在做RTP包解析,发现用你这个解包不能成功啊。解包的时候,第一帧是I帧,SPS部分没有解析成功,然后每个包打包的多余字节没有去掉
Re:  dengzikun 2014-06-09 19:43发表 [回复]
回复nanqingzhe:代码片段只能解析单个NAL单元包和FU_A分片单元包,请确认你的H264 RTP打包格式。
Re:  nanqingzhe 2014-06-11 10:29发表 [回复]
回复dengzikun:打包解包均采用你给的代码。
一个完整的I帧塞进去打包,打包得到的数据交由解包的代码。
Re:  nanqingzhe 2014-06-11 10:27发表 [回复]
回复dengzikun:我用的就是你这个打包代码。将一个完整的I帧塞进去打包,打包后的数据交给你的这个解包代码。
Re:  dengzikun 2014-06-12 23:12发表 [回复]
回复nanqingzhe:你看一下Set 和Parse_RTP_Packet 的使用说明,应该是用法的问题。
20楼  恒月美剑 2012-11-26 15:57发表 [回复]
rtp_hdr_t结构体与标准的顺序不一样
Re:  dengzikun 2012-11-26 18:46发表 [回复]
回复huai_f:代码中注明了是little endian。
Re:  恒月美剑 2012-11-28 01:13发表 [回复]
回复dengzikun:嗯,我错了,我在jrtplib库中也看到过
19楼  chinapacs 2012-06-29 14:16发表 [回复]
非常感谢谢!!!基于时间戳这一块,困扰我大半个月。。目前圆满解决。我采用的方式跟你的类似,再次谢谢您。
memcpy(dst, nal[0].p_payload, i_frame_size);

if (count > 1) {
struct timeval now;
gettimeofday(&now, NULL);
double val = (now.tv_sec - firstTime.tv_sec) +
(now.tv_usec - firstTime.tv_usec) / 1000000.0;
ts_current= ts_current + val * 90000.0 + 0.5;
firstTime = now;
}
else {
ts_current= 0;
gettimeofday(&firstTime, NULL);
}
count ++;
18楼  chinapacs 2012-06-27 18:14发表 [回复] [引用] [举报]
有没有pseudo code?? demo 一下?这一块我一直没搞清楚在fps变化的情况下。
Re:  dengzikun 2012-06-29 09:12发表 [回复] [引用] [举报]
回复chinapacs:class RTP_Timestamp
{
public:

RTP_Timestamp(DWORD unit)
: m_dwUnit(unit)
{
QueryPerformanceFrequency ( (LARGE_INTEGER*)&m_Freq ) ;
}

~RTP_Timestamp(void)
{
}

DWORD GetTime ()
{
__int64 current ;
QueryPerformanceCounter ( (LARGE_INTEGER*)&current ) ;
DWORD ts = current * m_dwUnit / m_Freq ;
return ts ;
}

private:
DWORD m_dwUnit ;
__int64 m_Freq ;
};



RTP_Timestamp TS ( 90000 ) ;
每一帧调用TS.GetTime()获取时间戳。
目录
相关文章
|
3月前
RTP头部封装的实现
RTP头部封装的实现
26 0
|
7月前
|
编解码 监控 网络协议
GB/T28181-2016基于RTP的视音频数据封装和技术实现
首先我们先回顾下相关技术规范,看看基于RTP的音视频数据PS封装。
GB/T28181-2016基于RTP的视音频数据封装和技术实现
|
编解码
如何使用RTP封装H264视频数据
RTP的第一个字节是消息类型,如果是FU-A,第二个字节用来指示是否是I帧,是否I帧的开始或结束。
如何使用RTP封装H264视频数据
为什么发出去的2833 RTP流不能收号
为什么发出去的2833 RTP流不能收号
为什么发出去的2833 RTP流不能收号
|
安全 网络协议 算法
RTP、RTCP、RTSP 概念
<p style="line-height: 28px; margin-top: 0px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: rgb(51, 51, 51); font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helve
6650 0
|
编解码
RTP 包格式 详细解析
H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) NALU 头由一个字节组成, 它的语法如下:       +---------------+      |0|1|2|3|4|5|6|7|      +-+-+-+-+-+-+-+-+      |F|NRI|  Type   |      +---------------+ F: 1 个比特.
1223 0
|
数据采集 传感器 编解码
【Android RTMP】RTMPDump 封装 RTMPPacket 数据包 ( 关键帧数据格式 | 非关键帧数据格式 | x264 编码后的数据处理 | 封装 H.264 视频数据帧 )
【Android RTMP】RTMPDump 封装 RTMPPacket 数据包 ( 关键帧数据格式 | 非关键帧数据格式 | x264 编码后的数据处理 | 封装 H.264 视频数据帧 )
217 0