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

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

基于RTP的H264视频数据打包解包类的更多相关文章

  1. (转)基于RTP的H264视频数据打包解包类

    最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包.解包的文档和代码.功夫不负有心人,找到不少有价值的文档和代码.参考这些资料,写了H264 RTP打包类.解包类,实现 ...

  2. 【FFMPEG】基于RTP的H264视频数据打包解包类

    最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包.解包的文档和代码.功夫不负有心人,找到不少有价值的文档和代码.参考这些资料,写了H264 RTP打包类.解包类,实现 ...

  3. h264_rtp打包解包类及实现demo

    打包头文件: class CH2642Rtp { public: CH2642Rtp(uint32_t ssrc, uint8_t payloadType = 96, uint8_t fps = 25 ...

  4. Java之集合初探(二)Iterator(迭代器),collections,打包/解包(装箱拆箱),泛型(Generic),comparable接口

    Iterator(迭代器) 所有实现了Collection接口的容器都有一个iterator方法, 用来返回一个实现了Iterator接口的对象 Iterator对象称作迭代器, 用来方便的实现对容器 ...

  5. 07.进程管理+作业控制+文件查找与压缩+文件压缩与打包+tar打包解包+NFS

    进程管理 程序放在磁盘上叫文件,把它复制到内存,并在cpu运行,就叫进程, 进程多少也反映当前运行程序的多少 进程在系统中会为每个进程生成一个进程号,在所有的进程中有一个特殊进程即init进程, 它是 ...

  6. Mtk Android 打包解包*.img

    打包/解包 boot.img, system.img, userdata.img, or recovery.img [DESCRIPTION] MTK codebase编译出来的image必须使用MT ...

  7. 【Unity】AssetBundle的使用——打包/解包

    最近参考了各位大神的资源,初步学习了Unity的资源管理模式,包括在编辑器管理(使用AssetDatabase)和在运行时管理(使用Resources和AssetBundle).在此简单总结运行时用A ...

  8. xpack文件打包解包代码库

    Github ###概述 xpack是一个文件资源打包工具及类库,可以对多文件进行打包解包. 其使用文件名的hash作为索引,建立hash索引表以加速文件查找. ###特性 支持hashid自动解冲突 ...

  9. Ruby中星号打包解包操作

    Ruby中可以使用一个星号*和两个星号**完成一些打包.解包操作,它们称为splat操作符: 一个星号:以数组为依据进行打包解包(参考文章) 两个星号:以hash为依据进行打包解包(参考文章) 两个星 ...

随机推荐

  1. AnkhSVN 安装

    为 visual Studio 2013 添加 AnkhSVN 步骤 到 https://ankhsvn.open.collab.net/downloads 下载 2.6x或以上 安装 AnkhSvn ...

  2. 项目中libevent几个问题

    几个问题: .libevent到底用的是select还是iocp,然后是如何突破64限制的 typedef struct fd_set { u_int fd_count; /* how many ar ...

  3. EBP与ESP寄存器的使用

    push ebp mov esp,ebp esp是堆栈指针 ebp是基址指针 这两条指令的意思是将栈顶指向ebp的地址 ---------------------------------------- ...

  4. NS记录

    NS(Name Server)记录是域名服务器记录,用来指定该域名由哪个DNS服务器来进行解析. 1名词简介 您注册域名时,总有默认的DNS服务器,每个注册的域名都是由一个DNS域名服务器来进行解析的 ...

  5. LoadAssetAtPath 与 Load 的区别

    一.官方的文档 Resources.LoadAssetAtPath Returns a resource at an asset path (Editor Only). This function a ...

  6. android音乐播放器开发教程

    android音乐播放器开发教程 Android扫描sd卡和系统文件 Android 关于录音文件的编解码 实现米聊 微信一类的录音上传的功能 android操作sdcard中的多媒体文件——音乐列表 ...

  7. PhotoSwipe简介(PhotoSwipe是一个适合在触摸屏手机上使用的相册展示包)

    官方介绍PhotoSwipe 是专为移动触摸设备设计的相册/画廊.兼容所有iPhone.iPad.黑莓6+,以及桌面浏览器.底层实现基于HTML/CSS/JavaScript,是一款免费开源的相册产品 ...

  8. 小米2S 连接Ubuntu Android Studio

    1. 首先打开手机上的开发者选项,USB调试.拨号:*#*#717717#*#*  ,手机会以Toast形式出现“……enable”字样.再次拨号可disable. 2. Ubuntu安装mtpfs: ...

  9. floodlight make the VMs can not getDHCP IP address

    https://answers.launchpad.net/neutron/+question/242170 这个问题我也遇到了,但是没人回答. floodlight make the VMs can ...

  10. javaWEB邮件测试

    新建一个工具类: Mail.java 该类的主要关键点是:1.设置系统属性.也就是你是用什么协议来进行邮件发送的,邮件协议有很多在种,比如impt,smpt,prop等协议, 我现在测试用的是smpt ...