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

来源:互联网 发布:js 文本编辑器 编辑:程序博客网 时间:2024/05/22 12:18
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 packet process 
 // ... 

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;// NAL type 
        unsigned char *start;// pointer to first location in the send buffer 
        unsigned char *end;// pointer to last location in send buffer 
        unsigned long size ; 
    } NAL_MSG_t; 
 
    typedef struct 
    { 
        //LITTLE_ENDIAN 
        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                 */ 
 
        unsigned short    seq; /* sequence number            */ 
        unsigned long     ts;  /* timestamp                  */ 
        unsigned long     ssrc;/* synchronization source     */ 
    } rtp_hdr_t; 
 
    typedef struct tagRTP_INFO 
    { 
        NAL_MSG_t    nal;    // NAL information 
        rtp_hdr_t    rtp_hdr;// RTP header is assembled here 
        int hdr_len;// length of RTP header 
 
        unsigned char *pRTP; // pointer to where RTP packet has beem assembled 
        unsigned char *start;// pointer to start of payload 
        unsigned char *end;  // pointer to end of payload 
 
        unsigned int s_bit;  // bit in the FU header 
        unsigned int e_bit;  // bit in the FU header 
        bool FU_flag;        // fragmented NAL Unit 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) 
    { 
    } 
 
//传入Set的数据必须是一个完整的NAL,起始码为0x00000001。 
//起始码之前至少预留10个字节,以避免内存COPY操作。 
//打包完成后,原缓冲区内的数据被破坏。 
    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 ;    // skip the syncword 
                                    
        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 ;    // skip NAL header 
        } 
        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 ; 
    } 
 
    //循环调用Get获取RTP包,直到返回值为NULL 
    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;// continue with the next RTP-FU packet 
        } 
 
        int bytesLeft = m_RTP_Info.nal.end - m_RTP_Info.start ; 
int maxSize = m_MAXRTPPACKSIZE - 12 ; // sizeof(basic rtp header) == 12 bytes 
        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 ) 
        {    // multiple packet NAL slice 
            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 ; 
/*! 
* \n The FU indicator octet has the following format: 
* \n 
* \n      +---------------+ 
* \n MSB  |0|1|2|3|4|5|6|7|  LSB 
* \n      +-+-+-+-+-+-+-+-+ 
* \n      |F|NRI|  Type   | 
* \n      +---------------+ 
* \n 
* \n The FU header has the following format: 
* \n 
* \n      +---------------+ 
* \n      |0|1|2|3|4|5|6|7| 
* \n      +-+-+-+-+-+-+-+-+ 
* \n      |S|E|R|  Type   | 
* \n      +---------------+ 
*/ 
        if ( m_RTP_Info.FU_flag ) 
        { 
            // FU indicator  F|NRI|Type 
            cp[12] = ( m_RTP_Info.nal.type & 0xe0 ) | 28 ;//Type is 28 for FU_A 
            //FU header        S|E|R|Type 
            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 
 
            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] ;    // new start of payload 
 
        *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



RTP 承载H.264 Payload的解包类源码

// class CH264_RTP_UNPACK start

  1. class CH264_RTP_UNPACK 
  2.  
  3. #define RTP_VERSION 2 
  4. #define BUF_SIZE (1024 * 500) 
  5.  
  6.     typedef struct 
  7.     { 
  8.         //LITTLE_ENDIAN 
  9.         unsigned short   cc:4;/* CSRC count                 */ 
  10.         unsigned short   x:1; /* header extension flag      */ 
  11.         unsigned short   p:1; /* padding flag               */ 
  12.         unsigned short   v:2; /* packet type                */ 
  13.         unsigned short   pt:7;/* payload type               */ 
  14.         unsigned short   m:1; /* marker bit                 */ 
  15.  
  16.         unsigned short    seq;/* sequence number            */ 
  17.         unsigned long     ts; /* timestamp                  */ 
  18.         unsigned long     ssrc;/*synchronization source     */ 
  19.     } rtp_hdr_t; 
  20. public
  21.  
  22.     CH264_RTP_UNPACK ( HRESULT &hr, unsigned char H264PAYLOADTYPE = 96 ) 
  23.         : m_bSPSFound(false
  24.         , m_bWaitKeyFrame(true
  25.         , m_bPrevFrameEnd(false
  26.         , m_bAssemblingFrame(false
  27.         , m_wSeq(1234) 
  28.         , m_ssrc(0) 
  29.     { 
  30.         m_pBuf = new BYTE[BUF_SIZE] ; 
  31.         if ( m_pBuf == NULL ) 
  32.         { 
  33.             hr = E_OUTOFMEMORY ; 
  34.             return ; 
  35.         } 
  36.  
  37.         m_H264PAYLOADTYPE = H264PAYLOADTYPE ; 
  38.         m_pEnd = m_pBuf + BUF_SIZE ; 
  39.         m_pStart = m_pBuf ; 
  40.         m_dwSize = 0 ; 
  41.         hr = S_OK ; 
  42.     } 
  43.  
  44.     ~CH264_RTP_UNPACK(void
  45.     { 
  46.         delete [] m_pBuf ; 
  47.     } 
  48.  
  49. //pBuf为H264 RTP视频数据包,nSize为RTP视频数据包字节长度,outSize为输出视频数据帧字节长度。 
  50. //返回值为指向视频数据帧的指针。输入数据可能被破坏。 
  51.     BYTE* Parse_RTP_Packet ( BYTE *pBuf, unsigned short nSize, int *outSize ) 
  52.     { 
  53.         if ( nSize <= 12 ) 
  54.         { 
  55.             return NULL ; 
  56.         } 
  57.  
  58.         BYTE *cp = (BYTE*)&m_RTP_Header ; 
  59.         cp[0] = pBuf[0] ; 
  60.         cp[1] = pBuf[1] ; 
  61.  
  62.         m_RTP_Header.seq = pBuf[2] ; 
  63.         m_RTP_Header.seq <<= 8 ; 
  64.         m_RTP_Header.seq |= pBuf[3] ; 
  65.  
  66.         m_RTP_Header.ts = pBuf[4] ; 
  67.         m_RTP_Header.ts <<= 8 ; 
  68.         m_RTP_Header.ts |= pBuf[5] ; 
  69.         m_RTP_Header.ts <<= 8 ; 
  70.         m_RTP_Header.ts |= pBuf[6] ; 
  71.         m_RTP_Header.ts <<= 8 ; 
  72.         m_RTP_Header.ts |= pBuf[7] ; 
  73.  
  74.         m_RTP_Header.ssrc = pBuf[8] ; 
  75.         m_RTP_Header.ssrc <<= 8 ; 
  76.         m_RTP_Header.ssrc |= pBuf[9] ; 
  77.         m_RTP_Header.ssrc <<= 8 ; 
  78.         m_RTP_Header.ssrc |= pBuf[10] ; 
  79.         m_RTP_Header.ssrc <<= 8 ; 
  80.         m_RTP_Header.ssrc |= pBuf[11] ; 
  81.  
  82.         BYTE *pPayload = pBuf + 12 ; 
  83.         DWORD PayloadSize = nSize - 12 ; 
  84.  
  85.         // Check the RTP version number (it should be 2): 
  86.         if ( m_RTP_Header.v != RTP_VERSION ) 
  87.         { 
  88.             return NULL ; 
  89.         } 
  90.  
  91.         /* 
  92.         // Skip over any CSRC identifiers in the header: 
  93.         if ( m_RTP_Header.cc ) 
  94.         { 
  95.             long cc = m_RTP_Header.cc * 4 ; 
  96.             if ( Size < cc ) 
  97.             { 
  98.                 return NULL ; 
  99.             } 
  100.  
  101.             Size -= cc ; 
  102.             p += cc ; 
  103.         }
  104.  
  105.         // Check for (& ignore) any RTP header extension 
  106.         if ( m_RTP_Header.x ) 
  107.         { 
  108.             if ( Size < 4 ) 
  109.             { 
  110.                 return NULL ; 
  111.             } 
  112.  
  113.             Size -= 4 ; 
  114.             p += 2 ; 
  115.             long l = p[0] ; 
  116.             l <<= 8 ; 
  117.             l |= p[1] ; 
  118.             p += 2 ; 
  119.             l *= 4 ; 
  120.             if ( Size < l ) ; 
  121.             { 
  122.                 return NULL ; 
  123.             } 
  124.             Size -= l ; 
  125.             p += l ; 
  126.         } 
  127.         
  128.         // Discard any padding bytes: 
  129.         if ( m_RTP_Header.p ) 
  130.         { 
  131.             if ( Size == 0 ) 
  132.             { 
  133.                 return NULL ; 
  134.             } 
  135.             long Padding = p[Size-1] ; 
  136.             if ( Size < Padding ) 
  137.             { 
  138.                 return NULL ; 
  139.             } 
  140.             Size -= Padding ; 
  141.         }*/ 
  142.  
  143.         // Check the Payload Type. 
  144.         if ( m_RTP_Header.pt != m_H264PAYLOADTYPE ) 
  145.         { 
  146.             return NULL ; 
  147.         } 
  148.  
  149.         int PayloadType = pPayload[0] & 0x1f ; 
  150.         int NALType = PayloadType ; 
  151.         if ( NALType == 28 ) // FU_A 
  152.         { 
  153.             if ( PayloadSize < 2 ) 
  154.             { 
  155.                 return NULL ; 
  156.             } 
  157.  
  158.             NALType = pPayload[1] & 0x1f ; 
  159.         } 
  160.  
  161.         if ( m_ssrc != m_RTP_Header.ssrc ) 
  162.         { 
  163.             m_ssrc = m_RTP_Header.ssrc ; 
  164.             SetLostPacket () ; 
  165.         } 
  166.     
  167.         if ( NALType == 0x07 ) // SPS 
  168.         { 
  169.             m_bSPSFound = true ; 
  170.         } 
  171.  
  172.         if ( !m_bSPSFound ) 
  173.         { 
  174.             return NULL ; 
  175.         } 
  176.  
  177.         if ( NALType == 0x07 || NALType == 0x08 ) // SPS PPS 
  178.         { 
  179.             m_wSeq = m_RTP_Header.seq ; 
  180.             m_bPrevFrameEnd = true ; 
  181.  
  182.             pPayload -= 4 ; 
  183.             *((DWORD*)(pPayload)) = 0x01000000 ; 
  184.             *outSize = PayloadSize + 4 ; 
  185.             return pPayload ; 
  186.         } 
  187.  
  188.         if ( m_bWaitKeyFrame ) 
  189.         { 
  190.             if ( m_RTP_Header.m ) // frame end 
  191.             { 
  192.                 m_bPrevFrameEnd = true ; 
  193.                 if ( !m_bAssemblingFrame ) 
  194.                 { 
  195.                     m_wSeq = m_RTP_Header.seq ; 
  196.                     return NULL ; 
  197.                 } 
  198.             } 
  199.  
  200.             if ( !m_bPrevFrameEnd ) 
  201.             { 
  202.                 m_wSeq = m_RTP_Header.seq ; 
  203.                 return NULL ; 
  204.             } 
  205.             else 
  206.             { 
  207.                 if ( NALType != 0x05 ) // KEY FRAME 
  208.                 { 
  209.                     m_wSeq = m_RTP_Header.seq ; 
  210.                     m_bPrevFrameEnd = false ; 
  211.                     return NULL ; 
  212.                 } 
  213.             }
  214.         }
  215.         if ( m_RTP_Header.seq != (WORD)( m_wSeq + 1 ) )//lost packet 
  216.         { 
  217.             m_wSeq = m_RTP_Header.seq ; 
  218.             SetLostPacket () ;            
  219.             return NULL ; 
  220.         } 
  221.         else 
  222.         { 
  223.             // 码流正常 
  224.  
  225.             m_wSeq = m_RTP_Header.seq ; 
  226.             m_bAssemblingFrame = true ; 
  227.             
  228.             if ( PayloadType != 28 ) // whole NAL 
  229.             { 
  230.                 *((DWORD*)(m_pStart)) = 0x01000000 ; 
  231.                 m_pStart += 4 ; 
  232.                 m_dwSize += 4 ; 
  233.             } 
  234.             else // FU_A 
  235.             { 
  236.                 if ( pPayload[1] & 0x80 ) // FU_A start 
  237.                 { 
  238.                     *((DWORD*)(m_pStart)) = 0x01000000 ; 
  239.                     m_pStart += 4 ; 
  240.                     m_dwSize += 4 ; 
  241.  
  242.                     pPayload[1] = ( pPayload[0] & 0xE0 ) | NALType ; 
  243.                     
  244.                     pPayload += 1 ; 
  245.                     PayloadSize -= 1 ; 
  246.                 } 
  247.                 else 
  248.                 { 
  249.                     pPayload += 2 ; 
  250.                     PayloadSize -= 2 ; 
  251.                 } 
  252.             } 
  253.  
  254.             if ( m_pStart + PayloadSize < m_pEnd ) 
  255.             { 
  256.                 CopyMemory ( m_pStart, pPayload, PayloadSize ) ; 
  257.                 m_dwSize += PayloadSize ; 
  258.                 m_pStart += PayloadSize ; 
  259.             } 
  260.             else // memory overflow 
  261.             { 
  262.                 SetLostPacket () ; 
  263.                 return NULL ; 
  264.             } 
  265.  
  266.             if ( m_RTP_Header.m ) // frame end 
  267.             { 
  268.                 *outSize = m_dwSize ; 
  269.  
  270.                 m_pStart = m_pBuf ; 
  271.                 m_dwSize = 0 ; 
  272.  
  273.                 if ( NALType == 0x05 ) // KEY FRAME 
  274.                 { 
  275.                     m_bWaitKeyFrame = false ; 
  276.                 } 
  277.                 return m_pBuf ; 
  278.             } 
  279.             else 
  280.             { 
  281.                 return NULL ; 
  282.             } 
  283.         } 
  284.     } 
  285.  
  286.     void SetLostPacket() 
  287.     { 
  288.         m_bSPSFound = false ; 
  289.         m_bWaitKeyFrame = true ; 
  290.         m_bPrevFrameEnd = false ; 
  291.         m_bAssemblingFrame = false ; 
  292.         m_pStart = m_pBuf ; 
  293.         m_dwSize = 0 ; 
  294.     } 
  295.  
  296. private
  297.     rtp_hdr_t m_RTP_Header ; 
  298.  
  299.     BYTE *m_pBuf ; 
  300.  
  301.     bool m_bSPSFound ; 
  302.     bool m_bWaitKeyFrame ; 
  303.     bool m_bAssemblingFrame ; 
  304.     bool m_bPrevFrameEnd ; 
  305.     BYTE *m_pStart ; 
  306.     BYTE *m_pEnd ; 
  307.     DWORD m_dwSize ; 
  308.  
  309.     WORD m_wSeq ; 
  310.  
  311.     BYTE m_H264PAYLOADTYPE ; 
  312.     DWORD m_ssrc ; 
  313. }; 
  314.  
  315. // class CH264_RTP_UNPACK end 

使用范例:

  1. HRESULT hr ; 
  2. CH264_RTP_UNPACK unpack ( hr ) ; 
  3. BYTE *pRtpData ; 
  4. WORD inSize; 
  5. int outSize ; 
  6. BYTE *pFrame = unpack.Parse_RTP_Packet ( pRtpData, inSize, &outSize ) ; 
  7. if ( pFrame != NULL ) 
  8. // frame process 
  9. // ... 
文章转载自:罗索实验室 [http://www.rosoo.net/a/201101/10763.html]

原创粉丝点击