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