<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    基于RTP的H264視頻數據打包解包類

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    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 plaincopy  
    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. //////////////////////////////////////////////////////////////////////////////////////////  

     

     
    主題推薦
    視頻數據h264timestampsizeof
    猜你在找
    分享一段H264視頻和AAC音頻的RTP封包代碼rtsp流媒體服務器的搭建RTSP服務器實例live555源代碼分析ubuntu下編譯ffmpeg公開的幾個 rtsp流媒體測試地址SDP協議分析RTP學習三linux下RTP編程使用 JRTPLIB 受益匪淺Windows下編譯FFmpeg詳解VLC架構及流程分析通過FFmpeg將多媒體文件解碼后保存成Bmp圖像YUV420 RGB32 【精品課程】Spark+Scala套餐值不值,看你敢不敢學!【精品課程】高安定PMP認證網絡套餐5折優惠【精品課程】C語言及程序設計學習套餐【精品課程】學項目管理系列視頻教程之基礎篇(上)【精品課程】Java Web高級技術
    準備好了么? 更多職位盡在 
    數據工程師(外包) 工銀瑞信基金管理有限公司 9-18K/月 我要跳槽
    Android視頻工程師 國廣星空視頻科技(北京)有限公司 15-20K/月 我要跳槽
    H5高級攻城獅 五彩世界(北京)文化傳媒有限公司 10-15K/月 我要跳槽
    H5前端開發工程師 獵聘網 10-15K/月 我要跳槽
    查看評論
    23樓 _beginthreadex 2014-11-07 16:31發表 [回復]
    RFID設備管理軟件
    調用博主的代碼成功實現了對RTP包的解析和幀重組,直接保存成文件可以用VLC播放。另,博主的解包類里面似乎沒有對SEI進行處理,所以在轉換某個攝像機的視頻時,我得到的數據全都是SPS與PPS,后查看直接保存的二進制文件,發現因為SEI也是有序列號的,不加1的話,下一次比較定會出錯。已手動修改。
    22樓 對牛亂彈琴 2014-07-09 09:40發表 [回復]
    RFID設備管理軟件
    你好,非常感謝你的代碼,我調試可以正常解包的。
    但是我現在有個問題,UDP傳輸,我本機發送本機接收,總是斷斷續續的丟包,
    if ( m_RTP_Header.seq != (WORD)( m_wSeq + 1 ) )//lost packet 
    會進入到這個判斷里面?百思不得解,希望博主提示一下哈。
    謝謝
    Re: dengzikun 2014-07-09 23:20發表 [回復]
    RFID設備管理軟件
    回復chen495810242:本機收發丟包,可能是收發速率不匹配,可以增大 socket緩沖區試試。試試把接收數據后的處理邏輯去掉,只接收數據。
    Re: 對牛亂彈琴 2014-07-10 08:53發表 [回復]
    RFID設備管理軟件
    回復dengzikun:額,我必須表示感謝,增加接收緩沖區大小就可以了,⊙╊⊙b汗。

    在麻煩一下,你還有其他組包模式的解析方式嗎?
    FU-B,STAP-A,STAP-B等,還有你說的錯誤處理省略了,能否也加上,我覺得這個其實更重要,非常感謝
    Re: dengzikun 2014-07-11 14:26發表 [回復]
    RFID設備管理軟件
    回復chen495810242:"省略錯誤處理"是指博文中的類使用示例代碼。這兩個類是可以放心使用的。H264 RTP包的其他解析方式你可以參考live555等開源庫。
    Re: 對牛亂彈琴 2014-07-16 11:12發表 [回復]
    RFID設備管理軟件
    回復dengzikun:如果是大端模式怎么處理啊?謝謝
    Re: dengzikun 2014-07-16 11:32發表 [回復]
    RFID設備管理軟件
    回復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發表 [回復]
    RFID設備管理軟件
    樓主,最近在做RTP包解析,發現用你這個解包不能成功啊。解包的時候,第一幀是I幀,SPS部分沒有解析成功,然后每個包打包的多余字節沒有去掉
    Re: dengzikun 2014-06-09 19:43發表 [回復]
    RFID設備管理軟件
    回復nanqingzhe:代碼片段只能解析單個NAL單元包和FU_A分片單元包,請確認你的H264 RTP打包格式。
    Re: nanqingzhe 2014-06-11 10:29發表 [回復]
    RFID設備管理軟件
    回復dengzikun:打包解包均采用你給的代碼。
    一個完整的I幀塞進去打包,打包得到的數據交由解包的代碼。
    Re: nanqingzhe 2014-06-11 10:27發表 [回復]
    RFID設備管理軟件
    回復dengzikun:我用的就是你這個打包代碼。將一個完整的I幀塞進去打包,打包后的數據交給你的這個解包代碼。
    Re: dengzikun 2014-06-12 23:12發表 [回復]
    RFID設備管理軟件
    回復nanqingzhe:你看一下Set 和Parse_RTP_Packet 的使用說明,應該是用法的問題。
    20樓 恒月美劍 2012-11-26 15:57發表 [回復]
    RFID設備管理軟件
    rtp_hdr_t結構體與標準的順序不一樣
    Re: dengzikun 2012-11-26 18:46發表 [回復]
    RFID設備管理軟件
    回復huai_f:代碼中注明了是little endian。
    Re: 恒月美劍 2012-11-28 01:13發表 [回復]
    RFID設備管理軟件
    回復dengzikun:嗯,我錯了,我在jrtplib庫中也看到過
    19樓 chinapacs 2012-06-29 14:16發表 [回復]
    RFID設備管理軟件
    非常感謝謝!!!基于時間戳這一塊,困擾我大半個月。。目前圓滿解決。我采用的方式跟你的類似,再次謝謝您。
    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發表 [回復] [引用] [舉報]
    RFID設備管理軟件
    有沒有pseudo code?? demo 一下?這一塊我一直沒搞清楚在fps變化的情況下。
    Re: dengzikun 2012-06-29 09:12發表 [回復] [引用] [舉報]
    RFID設備管理軟件
    回復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()獲取時間戳。
    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全