基于RTP的H264视频数据打包解包类 Dear 丶 2022-06-11 23:40 281阅读 0赞 http://blog.csdn.net/dengzikun/article/details/5807694 版权声明:本文为博主原创文章,未经博主允许不得转载。 最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包、解包的文档和代码。功夫不负有心人,找到不少有价值的文档和代码。参考这些资料,写了H264 RTP打包类、解包类,实现了单个NAL单元包和FU\_A分片单元包。对于丢包处理,采用简单的策略:丢弃随后的所有数据包,直到收到关键帧。[测试][Link 1]效果还不错,代码贴上来,若能为同道中人借鉴一二,足矣。两个类的使用说明如下(省略了错误处理过程): 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 plain][] [copy][view plain] 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. // 顶 0 踩 0 * 下一篇[使用D3D渲染YUV视频数据][D3D_YUV] #### #### 相关文章推荐 * • [RTP协议全解(H264码流和PS流)][RTP_H264_PS] * • [关于H264通过RTP传输的打包方式][H264_RTP] * • [基于RTP的H264视频数据打包解包类][RTP_H264] * • [分析一段H264视频数据][H264] * • [基于RTP协议的IP电话QoS监测及提高策略][RTP_IP_QoS] * • [H264 RTP解包][H264 RTP] * • [RTP/RTCP工程实践与问题解决方案(合集)][RTP_RTCP] * • [H264 RTP打包类、解包类][H264 RTP 1] * • [数字媒体技术揭秘][Link 2] * • [H264 RTP头分析][H264 RTP 2] 猜你在找 [机器学习之概率与统计推断][Link 3] [机器学习之数学基础][Link 4] [机器学习之凸优化][Link 5] [机器学习之矩阵][Link 6] [响应式布局全新探索][Link 7] [探究Linux的总线、设备、驱动模型][Linux] [深度学习基础与TensorFlow实践][TensorFlow] [深度学习之神经网络原理与实战技巧][Link 8] [前端开发在线峰会][Link 9] [TensorFlow实战进阶:手把手教你做图像识别应用][TensorFlow 1] 查看评论 25楼 [feb\_li][feb_li] 2017-04-11 17:47发表 [\[回复\]][Link 10] [![3_feb_li.jpg][]][feb_li] 为什么我打包后,rtp的头 只有8个字节 不是12个字节呢 24楼 [灿哥哥][Link 11] 2016-11-02 13:42发表 [\[回复\]][Link 10] [![3_caoshangpa.jpg][]][Link 11] 学习了 23楼 [\_beginthreadex][beginthreadex] 2014-11-07 16:31发表 [\[回复\]][Link 10] [![3_mickeylyy.jpg][]][beginthreadex] 调用博主的代码成功实现了对RTP包的解析和帧重组,直接保存成文件可以用VLC播放。另,博主的解包类里面似乎没有对SEI进行处理,所以在转换某个摄像机的视频时,我得到的数据全都是SPS与PPS,后查看直接保存的二进制文件,发现因为SEI也是有序列号的,不加1的话,下一次比较定会出错。已手动修改。 22楼 [对牛乱弹琴][Link 12] 2014-07-09 09:40发表 [\[回复\]][Link 10] [![3_chen495810242.jpg][]][Link 12] 你好,非常感谢你的代码,我调试可以正常解包的。 但是我现在有个问题,UDP传输,我本机发送本机接收,总是断断续续的丢包, if ( m\_RTP\_Header.seq != (WORD)( m\_wSeq + 1 ) )//lost packet 会进入到这个判断里面?百思不得解,希望博主提示一下哈。 谢谢 Re: [dengzikun][] 2014-07-09 23:20发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复对牛乱弹琴:本机收发丢包,可能是收发速率不匹配,可以增大 socket缓冲区试试。试试把接收数据后的处理逻辑去掉,只接收数据。 Re: [对牛乱弹琴][Link 12] 2014-07-10 08:53发表 [\[回复\]][Link 10] [![3_chen495810242.jpg][]][Link 12] 回复dengzikun:额,我必须表示感谢,增加接收缓冲区大小就可以了,⊙﹏⊙b汗。 在麻烦一下,你还有其他组包模式的解析方式吗? FU-B,STAP-A,STAP-B等,还有你说的错误处理省略了,能否也加上,我觉得这个其实更重要,非常感谢 Re: [dengzikun][] 2014-07-11 14:26发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复对牛乱弹琴:"省略错误处理"是指博文中的类使用示例代码。这两个类是可以放心使用的。H264 RTP包的其他解析方式你可以参考live555等开源库。 Re: [对牛乱弹琴][Link 12] 2014-07-16 11:12发表 [\[回复\]][Link 10] [![3_chen495810242.jpg][]][Link 12] 回复dengzikun:如果是大端模式怎么处理啊?谢谢 Re: [dengzikun][] 2014-07-16 11:32发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复对牛乱弹琴: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发表 [\[回复\]][Link 10] [![3_nanqingzhe.jpg][]][nanqingzhe] 楼主,最近在做RTP包解析,发现用你这个解包不能成功啊。解包的时候,第一帧是I帧,SPS部分没有解析成功,然后每个包打包的多余字节没有去掉 Re: [dengzikun][] 2014-06-09 19:43发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复nanqingzhe:代码片段只能解析单个NAL单元包和FU\_A分片单元包,请确认你的H264 RTP打包格式。 Re: [nanqingzhe][] 2014-06-11 10:29发表 [\[回复\]][Link 10] [![3_nanqingzhe.jpg][]][nanqingzhe] 回复dengzikun:打包解包均采用你给的代码。 一个完整的I帧塞进去打包,打包得到的数据交由解包的代码。 Re: [nanqingzhe][] 2014-06-11 10:27发表 [\[回复\]][Link 10] [![3_nanqingzhe.jpg][]][nanqingzhe] 回复dengzikun:我用的就是你这个打包代码。将一个完整的I帧塞进去打包,打包后的数据交给你的这个解包代码。 Re: [dengzikun][] 2014-06-12 23:12发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复nanqingzhe:你看一下Set 和Parse\_RTP\_Packet 的使用说明,应该是用法的问题。 20楼 [恒月美剑][Link 13] 2012-11-26 15:57发表 [\[回复\]][Link 10] [![3_huai_f.jpg][]][Link 13] rtp\_hdr\_t结构体与标准的顺序不一样 Re: [dengzikun][] 2012-11-26 18:46发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复恒月美剑:代码中注明了是little endian。 Re: [恒月美剑][Link 13] 2012-11-28 01:13发表 [\[回复\]][Link 10] [![3_huai_f.jpg][]][Link 13] 回复dengzikun:嗯,我错了,我在jrtplib库中也看到过 19楼 [chinapacs][] 2012-06-29 14:16发表 [\[回复\]][Link 10] [![3_chinapacs.jpg][]][chinapacs] 非常感谢谢!!!基于时间戳这一块,困扰我大半个月。。目前圆满解决。我采用的方式跟你的类似,再次谢谢您。 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发表 [\[回复\]][Link 10] [![3_chinapacs.jpg][]][chinapacs] 有没有pseudo code?? demo 一下?这一块我一直没搞清楚在fps变化的情况下。 Re: [dengzikun][] 2012-06-29 09:12发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复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\*)¤t ) ; DWORD ts = current \* m\_dwUnit / m\_Freq ; return ts ; \} private: DWORD m\_dwUnit ; \_\_int64 m\_Freq ; \}; RTP\_Timestamp TS ( 90000 ) ; 每一帧调用TS.GetTime()获取时间戳。 17楼 [chinapacs][] 2012-06-27 11:48发表 [\[回复\]][Link 10] [![3_chinapacs.jpg][]][chinapacs] 那请教一下H264 RTP的 timestamp 是如何计算的??应该不是简单的900000/fps吧? Re: [dengzikun][] 2012-06-27 16:18发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复chinapacs:如果你的FPS是固定的,时间戳可以按900000/fps递增。 另一种处理方法可以这么做,发送数据包时获取系统计时器 时间(当然,精度要高一些,windows下可以用QueryPerformanceCounter),然后转换为RTP时间戳。 Re: [dengzikun][] 2012-06-27 17:04发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复dengzikun:纠正一下,应该是 90000/fps 。 16楼 [chinapacs][] 2012-06-12 15:36发表 [\[回复\]][Link 10] [![3_chinapacs.jpg][]][chinapacs] 时间戳非常关键,这里没有体现出来 Re: [dengzikun][] 2012-06-13 15:25发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复chinapacs:准确的地说是正确的使用时间戳,很关键。 时间戳的正确使用牵涉到不同的编码媒体类型、网络状况, 应用需求等,特别是接收端对时间戳的使用。 这里只是简单地讲了H.264的打包解包。 15楼 [qibo15193][] 2012-03-17 22:24发表 [\[回复\]][Link 10] [![3_qibo15193.jpg][]][qibo15193] 有没有C语言的代码,解码部分从if ( m\_bWaitKeyFrame ) 开始,看不懂什么意思?m\_p一组数据不懂什么意思? 14楼 [请叫我小清新][Link 14] 2012-01-04 14:59发表 [\[回复\]][Link 10] [![3_aaadddzxc.jpg][]][Link 14] 引用“aaadddzxc”的评论:老大 你的解包代码有问题吧,用于都是在 if ( m\_RTP\_Header.v != RTP\_... 而且我看了下你的解码包,你和标准的RTP包处理过程不一致 标准RTP包 类型定义顺序错了! 13楼 [请叫我小清新][Link 14] 2012-01-04 14:55发表 [\[回复\]][Link 10] [![3_aaadddzxc.jpg][]][Link 14] 老大 你的解包代码有问题吧,用于都是在 if ( m\_RTP\_Header.v != RTP\_VERSION ) \{ return NULL ; \} 这一行过不去,你有没有能够正常的RTP解包代码呢? BYTE \*cp = (BYTE\*)&m\_RTP\_Header ; cp\[0\] = pBuf\[0\] ; cp\[1\] = pBuf\[1\] ; 这几行的作用又是什么呢? Re: [dengzikun][] 2012-01-05 09:26发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复请叫我小清新:BYTE \*cp = (BYTE\*)&m\_RTP\_Header ;cp\[0\] = pBuf\[0\] ;cp\[1\] = pBuf\[1\] ;从字节流中抽取RTP头。这些代码一直在用,没发现有什么大问题。 12楼 [SnowWolf\_zhijun][SnowWolf_zhijun] 2011-10-23 18:46发表 [\[回复\]][Link 10] [![3_snowwolf_zhijun.jpg][]][SnowWolf_zhijun] 你好,我现在在看一个网络摄像机的程序,它里面用live555来实现的音视频流传输,请问下,live555代码包里是不是,既可以以RTSP的方式接收音视频流,也可以以RTP的方式来接收音视频流?请问是这样吗,如果是的话,我在PC端用什么来接收呢,我想用VC++来编写一个播放器,接收live555传过来的音视频流,谢谢!!!! Re: [dengzikun][] 2011-10-23 20:01发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复SnowWolf\_zhijun:RTP是用来传输媒体流(音视频等)的, RTSP是用来传输控制信令的. LIVE555我没用过,但它确实是用RTP传输媒体流的. 控制信令的传输,LIVE555应该用的是RTSP吧. 11楼 [xulx999][] 2011-10-08 16:29发表 [\[回复\]][Link 10] [![3_xulx999.jpg][]][xulx999] 不知道方便可以加你的QQ,然后交流下嘛? Re: [dengzikun][] 2011-10-18 14:03发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复xulx999:不好意思啊,我确实没有即时通信工具。 Re: [dengzikun][] 2011-10-08 20:11发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 回复xulx999:没做过wince开发,可能没法帮你. 另,我不使用即时通信工具. Re: [xulx999][] 2011-10-09 11:15发表 [\[回复\]][Link 10] [![3_xulx999.jpg][]][xulx999] 回复dengzikun:哦,是这样哈,那还是多谢你肯回复我了,我再看看! 10楼 [xulx999][] 2011-10-08 16:26发表 [\[回复\]][Link 10] [![3_xulx999.jpg][]][xulx999] 我知道,可是就是现在我用这个库函数来编写基于SDK的程序,总是会报写链接错误,我不知道该怎么解决,不知道是不是网上的库函数用于wince中需要修改,我在网上查了很多,网上也就说把jrtplib库函数稍微修改下,就可应用到wince编程,始终没有找到讲该如何做的,所以想问问你! 9楼 [dengzikun][] 2011-09-30 20:17发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] RTP协议并不是很复杂,你可以根据实际的音视频应用,到网上找相关的资料. 8楼 [xulx999][] 2011-09-29 12:40发表 [\[回复\]][Link 10] [![3_xulx999.jpg][]][xulx999] 我的QQ:123399481! 7楼 [xulx999][] 2011-09-29 12:39发表 [\[回复\]][Link 10] [![3_xulx999.jpg][]][xulx999] 想问下楼主,我想在wince上使用RTP协议,但是网上下的开源的jrtplib不能用在我的EVC中来编写程序,请问能给些许指导,自己刚开始入门,很多东西无从下手的感觉,谢谢! 6楼 [dishuai][] 2011-07-05 09:29发表 [\[回复\]][Link 10] [![3_dishuai.jpg][]][dishuai] 楼主,可以交流一下吗? 5楼 [dengzikun][] 2010-12-30 09:44发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 完整的接收、解包代码可以参考live555。 4楼 [pike0002][] 2010-12-30 00:36发表 [\[回复\]][Link 10] [![3_pike0002.jpg][]][pike0002] 请问有接收RTP包并解码RTP包的代码吗?谢谢,我现在正在做一个与此有关的项目。希望能从你这里得到些许帮助。 3楼 [yidaoba\_2010][yidaoba_2010] 2010-08-30 11:32发表 [\[回复\]][Link 10] [![3_yidaoba_2010.jpg][]][yidaoba_2010] \[e01\] 好人啊,写得很详细,学习学习 2楼 [dengzikun][] 2010-08-20 18:51发表 [\[回复\]][Link 10] [![3_dengzikun.jpg][]][dengzikun] 关键帧就是可以独立解码的帧。 1楼 [zxydsdk][] 2010-08-20 15:59发表 [\[回复\]][Link 10] [\[引用\]][Link 15] [\[举报\]][Link 16] [![3_zxydsdk.jpg][]][zxydsdk] 问个问题?什么是关键帧? 发表评论 [Link 1]: http://lib.csdn.net/base/softwaretest [view plain]: http://blog.csdn.net/dengzikun/article/details/5807694# [D3D_YUV]: http://blog.csdn.net/dengzikun/article/details/5824874 [RTP_H264_PS]: http://blog.csdn.net/u012519333/article/details/53207859 [H264_RTP]: http://weiyinchao88.iteye.com/blog/1414463 [RTP_H264]: http://blog.csdn.net/gokartscomeon/article/details/44408295 [H264]: http://xpp02.iteye.com/blog/1785319 [RTP_IP_QoS]: http://blog.csdn.net/ASKLW/article/details/73498629 [H264 RTP]: http://blog.csdn.net/key123zhangxing/article/details/7876047 [RTP_RTCP]: http://blog.csdn.net/arau_sh/article/details/3064478 [H264 RTP 1]: http://blog.csdn.net/embzheng/article/details/7729988 [Link 2]: http://blog.csdn.net/czc1009/article/details/13022349 [H264 RTP 2]: http://xpp02.iteye.com/blog/1785131 [Link 3]: http://edu.csdn.net/huiyiCourse/series_detail/46 [Link 4]: http://edu.csdn.net/huiyiCourse/series_detail/49 [Link 5]: http://edu.csdn.net/huiyiCourse/series_detail/48 [Link 6]: http://edu.csdn.net/huiyiCourse/series_detail/47 [Link 7]: http://edu.csdn.net/huiyiCourse/detail/421 [Linux]: http://edu.csdn.net/huiyiCourse/detail/426 [TensorFlow]: http://edu.csdn.net/huiyiCourse/detail/422 [Link 8]: http://edu.csdn.net/huiyiCourse/series_detail/45 [Link 9]: http://edu.csdn.net/huiyiCourse/series_detail/43 [TensorFlow 1]: http://edu.csdn.net/huiyiCourse/series_detail/44 [feb_li]: http://blog.csdn.net/feb_li [Link 10]: http://blog.csdn.net/dengzikun/article/details/5807694#reply [3_feb_li.jpg]: /images/20220612/b0de52d7efff46edb280f4868f51fee6.png [Link 11]: http://blog.csdn.net/caoshangpa [3_caoshangpa.jpg]: /images/20220612/ce278d99c3f24128b90e8624d138b59b.png [beginthreadex]: http://blog.csdn.net/MickeyLyy [3_mickeylyy.jpg]: /images/20220612/916820e8b97f4baaa838b888e47b2131.png [Link 12]: http://blog.csdn.net/chen495810242 [3_chen495810242.jpg]: /images/20220612/e806ee3550e14fdb83d3b416e4d165af.png [dengzikun]: http://blog.csdn.net/dengzikun [3_dengzikun.jpg]: /images/20220612/eff237868460409e9ad3e516b91a3036.png [nanqingzhe]: http://blog.csdn.net/nanqingzhe [3_nanqingzhe.jpg]: /images/20220612/2a31ec2820404b1c94cdbfa9e64973c8.png [Link 13]: http://blog.csdn.net/huai_f [3_huai_f.jpg]: /images/20220612/838063ad61a8450fb90c4b21e7d2e629.png [chinapacs]: http://blog.csdn.net/chinapacs [3_chinapacs.jpg]: /images/20220612/153cbaa02e7943fabec01c2d62d6337e.png [qibo15193]: http://blog.csdn.net/qibo15193 [3_qibo15193.jpg]: /images/20220612/422fe3303a5343deb5aec1d9da1fca2a.png [Link 14]: http://blog.csdn.net/aaadddzxc [3_aaadddzxc.jpg]: /images/20220612/bb1896b9a37a4ee4ace23567d0caad07.png [SnowWolf_zhijun]: http://blog.csdn.net/SnowWolf_zhijun [3_snowwolf_zhijun.jpg]: /images/20220612/464bf873a1e54e6e973aa8920630a928.png [xulx999]: http://blog.csdn.net/xulx999 [3_xulx999.jpg]: /images/20220612/96455351bd6c420b9d23b4e7e7216d57.png [dishuai]: http://blog.csdn.net/dishuai [3_dishuai.jpg]: /images/20220612/8fd7fe7d8c514e1285ddc47465d95c14.png [pike0002]: http://blog.csdn.net/pike0002 [3_pike0002.jpg]: /images/20220612/bc0d2fd5af414ef39f83af69a8d62ed0.png [yidaoba_2010]: http://blog.csdn.net/yidaoba_2010 [3_yidaoba_2010.jpg]: /images/20220612/221ec9cc76764ef69893307caf198d67.png [zxydsdk]: http://blog.csdn.net/zxydsdk [Link 15]: http://blog.csdn.net/dengzikun/article/details/5807694#quote [Link 16]: http://blog.csdn.net/dengzikun/article/details/5807694#report [3_zxydsdk.jpg]: /images/20220612/5694aac6450b4e6986dcb80dd8171d4f.png
还没有评论,来说两句吧...