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

最近考虑使用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
  // ...
 }

 

 
view plaincopy to clipboardprint?
01.//  
02.// class CH264_RTP_PACK start  
03. 
04.class CH264_RTP_PACK  
05.{  
06.    #define RTP_VERSION 2  
07. 
08.    typedef struct NAL_msg_s   
09.    {  
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.// 

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/dengzikun/archive/2010/08/12/5807694.aspx

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RTP H.264 数据需要进行以下步骤: 1. 从 RTP 报文中提取出 H.264 数据。 2. 析 H.264 数据,提取出 NAL 单元。 3. 将 NAL 单元按照 H.264 规范进行拼接,形成完整的 H.264 帧。 4. 对 H.264 帧进行码,获取视频帧。 下面是一个基于 C++ 和 FFmpeg 库的简单示例代码: ```cpp #include <stdio.h> #include <stdlib.h> #include <string.h> extern "C" { #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> } #define MAX_RTP_PKT_LENGTH 1360 int main(int argc, char* argv[]) { AVFormatContext* fmt_ctx = NULL; AVCodecContext* codec_ctx = NULL; AVCodec* codec = NULL; AVPacket pkt; AVFrame* frame = NULL; uint8_t* frame_buf = NULL; int frame_size = 0; int got_frame = 0; int ret = 0; int i; av_register_all(); // 打开 RTP 输入文件 if (avformat_open_input(&fmt_ctx, "rtp://127.0.0.1:1234", NULL, NULL) != 0) { printf("Could not open input file.\n"); return -1; } // 查找视频流 if (avformat_find_stream_info(fmt_ctx, NULL) < 0) { printf("Could not find stream information.\n"); return -1; } int video_stream_index = -1; AVStream* video_stream = NULL; for (i = 0; i < fmt_ctx->nb_streams; i++) { if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_index = i; video_stream = fmt_ctx->streams[i]; break; } } if (video_stream_index == -1) { printf("Could not find video stream.\n"); return -1; } // 查找视频码器 codec = avcodec_find_decoder(video_stream->codecpar->codec_id); if (codec == NULL) { printf("Could not find codec.\n"); return -1; } // 初始化视频码器上下文 codec_ctx = avcodec_alloc_context3(codec); if (codec_ctx == NULL) { printf("Could not allocate codec context.\n"); return -1; } if (avcodec_parameters_to_context(codec_ctx, video_stream->codecpar) < 0) { printf("Could not copy codec parameters.\n"); return -1; } if (avcodec_open2(codec_ctx, codec, NULL) < 0) { printf("Could not open codec.\n"); return -1; } // RTP 数据 av_init_packet(&pkt); pkt.data = (uint8_t*)malloc(MAX_RTP_PKT_LENGTH); while (1) { // 从 RTP 文件中读取数据 ret = av_read_frame(fmt_ctx, &pkt); if (ret < 0) { break; } // 跳过 RTP 头 uint8_t* rtp_data = pkt.data + 12; // 提取 H.264 NAL 单元 while (pkt.size > 0) { int nal_start = 0, nal_end = 0; for (i = 0; i < pkt.size - 4; i++) { if (rtp_data[i] == 0x00 && rtp_data[i + 1] == 0x00 && rtp_data[i + 2] == 0x00 && rtp_data[i + 3] == 0x01) { if (nal_start != 0) { nal_end = i - 1; break; } else { nal_start = i + 4; } } } if (nal_end == 0) { nal_end = pkt.size - 1; } // 拼接 NAL 单元 int nal_size = nal_end - nal_start + 1; if (frame_buf == NULL) { frame_buf = (uint8_t*)malloc(nal_size); } else { frame_buf = (uint8_t*)realloc(frame_buf, frame_size + nal_size); } memcpy(frame_buf + frame_size, rtp_data + nal_start, nal_size); frame_size += nal_size; // 码 H.264 帧 while (frame_size > 0) { ret = avcodec_decode_video2(codec_ctx, frame, &got_frame, &pkt); if (ret < 0) { printf("Error decoding frame.\n"); break; } if (got_frame) { // 处理码后的视频帧 printf("Decoded frame: %dx%d\n", codec_ctx->width, codec_ctx->height); } // 移动指针 int consumed = av_parser_parse2(codec_ctx->parser, codec_ctx, &pkt.data, &pkt.size, rtp_data + nal_end + 1, pkt.size - nal_size - (rtp_data + nal_end + 1 - pkt.data), pkt.pts, pkt.dts, pkt.pos); frame_size -= nal_size + consumed; rtp_data += nal_size + consumed; } // 移动指针 pkt.size -= nal_size; } av_packet_unref(&pkt); } // 释放资源 if (codec_ctx != NULL) { avcodec_close(codec_ctx); avcodec_free_context(&codec_ctx); } if (fmt_ctx != NULL) { avformat_close_input(&fmt_ctx); } if (frame_buf != NULL) { free(frame_buf); } return 0; } ``` 这里使用了 FFmpeg 库中的函数进行 RTP 数据析和 H.264 数据码,具体流程请参考代码注释。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值