1、PS流封包格式

  • 视频关键帧的封装:    RTP|PS header|PS system header|PS system Map|PES header|H264 data
  • 视频非关键帧的封装:RTP|PS header|PES header|H264 data
  • 音频帧的封装:           RTP|PES header|G711

2、服务端PS流接收组包和解析

以海康DS-IPC-B12H2-I为例

(1)rtp over udp

80 60 00 00 00 00 00 00 00 00 04 00 00 00 01 ba
44 f0 4f 69 64 01 02 5f 03 fe ff ff 00 01 11 0c
00 00 01 bb 00 12 81 2f 81 04 e1 7f e0 e0 80 c0
c0 08 bd e0 80 bf e0 80 00 00 01 bc 00 5e f8 ff
00 24 40 0e 48 4b 01 00 14 14 40 16 6b bf 00 ff
ff ff 41 12 48 4b 00 01 02 03 04 05 06 07 08 09
0a 0b 0c 0d 0e 0f 00 30 1b e0 00 1c 42 0e 07 10
10 ea 05 00 02 d0 11 30 00 00 1c 21 2a 0a 7f ff
00 00 07 08 1f fe a0 5a 90 c0 00 0c 43 0a 01 40
fe 00 7d 03 03 e8 03 ff f6 53 94 03 00 00 01 e0
00 1e 8c 80 08 21 3c 13 da 59 ff ff fc 00 00 00
01 67 4d 00 1f 96 35 40 a0 0b 74 dc 04 04 04 08
00 00 01 e0 00 0e 8c 00 03 ff ff fc 00 00 00 01
68 ee 3c 80 00 00 01 e0 00 0e 8c 00 02 ff fc 00
00 00 01 06 e5 01 d5 80 00 00 01 e0 c2 06 8c 00
05 ff ff ff ff f8 00 00 00 01 65 b8 00 00 0a 77
80 00 00 4f e7 e5 34 0f f3 41 4b b9 58 a9 4e 4c
f4 ea 04 0e 32 a5 f9 51 df cc 4c b8 99 f2 cf 16
3e 32 19 ed 86 df 05 6b fc 21 5e 0f 87 90 20 c3
16 02 03 73 0f a3 d2 9b 52 1b b1 a7 7c b4 61 6d
d9 aa f4 5d 34 f6 49 d4 f6 72 af b6 c7 11 c0 ff
3d 1b fd e3 5d 41 db 32 3a c7 9f f4 f2 c0 99 e6 ...

数据解析,这是个I帧

rtp header:80 60 00 00 00 00 00 00 00 00 04 00

——12byte固定长度

ps header:00 00 01 ba ...

——00 00 01 ba 44 f0 4f 69 64 01 02 5f 03 fe ff ff 00 01 11 0c 前14byte是固定的,第14byte 0xfe & 0x07 = 0x0e 也就是后面拓展6byte

ps system header:00 00 01 bb ...

——随后的 00 12是长度,也就是ps system header长度=4+18 byte

ps system map:00 00 01 bc ...

——同样随后的 00 5e是长度,也就是ps system map的长度=4+94 byte

pes header:00 00 01 e0/c0 ...

——e0是视频,c0是音频,同样随后的00 1e是长度,也就是pes header的长度 4+30 byte,剩下的就是ps payload数据

ps payload SPS 00 00 00 01 67 ...

ps payload PPS 00 00 00 01 68 ...

ps payload I 00 00 00 01 65 ...

ps payload P 00 00 00 01 61/41 ...

海康的摄像头ps payload的起始标识是00 00 00 01 61,有些厂家的是00 00 00 01 41,通过第五字节 & 0x1F = 1,就是正确的ps payload起始标识

另外:

0x000001BD 私有数据,同0x000001E0 ,直接跳过,具体的PS格式可以参考网上的其他资料。

再者,如果数据中包含0x000001,按h264协议会进行转义,即变成0x00000301,涉及到3个转义 0x000001 -> 0x00000301   0x000002 -> 0x00000302  0x000003 -> 0x00000303

接收,解析流程 udp--->rtp--->ps--->h264

while ((pack = sess.GetNextPacket()) != NULL)
{    loaddata = pack->GetPayloadData();len      = pack->GetPayloadLength();/* payload type: ps */if(pack->GetPayloadType() == 96) {/*the last packet*/if(pack->HasMarker()) {if(pos + len < PS_BUFFER_SIZE){memcpy(&buff[pos],loaddata,len);                            printf("!!!  GetPayload len = %ld !!!! \n ",pos+len);size_t r = ps_demuxer_input(ps, buff, pos+len);pos = 0;lasttime = nowtime;}}else{if(pos + len < PS_BUFFER_SIZE){memcpy(&buff[pos],loaddata,len);pos = pos + len;}    }}else{printf("!!!  GetPayloadType = %d !!!! \n ",pack->GetPayloadType());}sess.DeletePacket(pack);
}

将解析出来的h264视频和g711音频填充到待处理的列队

video

/*
SPS frame   00 00 00 01 67
PPS frame   00 00 00 01 68
I   frame   00 00 00 01 65
P   slice   00 00 00 01 41/61
*/
if(FindStartCode(p))
{data_t d;if(rb_numitems(task->buffer) < DATA_ITEM_NMAX){if(task->pos < ITEM_BUFFER_SIZE) {               memcpy(d.buf,task->buf, task->pos);d.size = task->pos;d.type = H264;     rb_put(task->buffer, &d);                             fflush(stdout);}           }task->pos = 0;if((task->pos + bytes) < TASK_BUFFER_SIZE){memcpy(&(task->buf[task->pos]),p,bytes);    task->pos = task->pos + bytes;}
}
else
{if((task->pos + bytes) < TASK_BUFFER_SIZE){memcpy(&(task->buf[task->pos]),p,bytes);task->pos = task->pos + bytes;}
}

audio

data_t d;
if (rb_numitems(task->buffer) < DATA_ITEM_NMAX){if(bytes < ITEM_BUFFER_SIZE){                memcpy(d.buf, p, bytes);d.size = bytes;d.type = G711A;     rb_put(task->buffer, &d);                             fflush(stdout);}
}

h264 nalu数据帧解析可以参考live555的处理

H264VideoRTPSink.cpp

Boolean H264VideoRTPSource::processSpecialHeader(BufferedPacket* packet, unsigned& resultSpecialHeaderSize) {unsigned char* headerStart = packet->data();unsigned packetSize = packet->dataSize();unsigned numBytesToSkip;// Check the 'nal_unit_type' for special 'aggregation' or 'fragmentation' packets:if(packetSize < 1) return False;fCurPacketNALUnitType = (headerStart[0]&0x1F);switch (fCurPacketNALUnitType) {case 24: { // STAP-AnumBytesToSkip = 1; // discard the type bytebreak;}case 25: case 26: case 27: { // STAP-B, MTAP16, or MTAP24numBytesToSkip = 3; // discard the type byte, and the initial DONbreak;}case 28: case 29: { // // FU-A or FU-B// For these NALUs, the first two bytes are the FU indicator and the FU header.// If the start bit is set, we reconstruct the original NAL header into byte 1:if (packetSize < 2) return False;unsigned char startBit = headerStart[1]&0x80;unsigned char endBit = headerStart[1]&0x40;if (startBit) {fCurrentPacketBeginsFrame = True;headerStart[1] = (headerStart[0]&0xE0)|(headerStart[1]&0x1F);numBytesToSkip = 1;} else {// The start bit is not set, so we skip both the FU indicator and header:fCurrentPacketBeginsFrame = False;numBytesToSkip = 2;}fCurrentPacketCompletesFrame = (endBit != 0);break;}default: {// This packet contains one complete NAL unit:fCurrentPacketBeginsFrame = fCurrentPacketCompletesFrame = True;numBytesToSkip = 0;break;}}resultSpecialHeaderSize = numBytesToSkip;return True;
}

H264VideoRTPSink.cpp

H264VideoRTPSink* H264VideoRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs,         unsigned char rtpPayloadFormat,char const* sPropParameterSetsStr)
{u_int8_t* sps = NULL; unsigned spsSize = 0;u_int8_t* pps = NULL; unsigned ppsSize = 0;unsigned numSPropRecords;SPropRecord* sPropRecords = parseSPropParameterSets(sPropParameterSetsStr,numSPropRecords);for(unsigned i = 0; i < numSPropRecords; ++i) {if(sPropRecords[i].sPropLength == 0) continue; // bad datau_int8_t nal_unit_type = (sPropRecords[i].sPropBytes[0])&0x1F;if (nal_unit_type == 7/*SPS*/) {sps = sPropRecords[i].sPropBytes;spsSize = sPropRecords[i].sPropLength;} else if (nal_unit_type == 8/*PPS*/) {pps = sPropRecords[i].sPropBytes;ppsSize = sPropRecords[i].sPropLength;}}H264VideoRTPSink* result = new H264VideoRTPSink(env, RTPgs, rtpPayloadFormat, sps, spsSize, pps, ppsSize);delete[] sPropRecords;return result;
}

帧属性分离

SPS:  0x67    header & 0x1F = 7

PPS:  0x68    header & 0x1F = 8

SEI:  0x66     header & 0x1F = 6

I Frame: 0x65    header & 0x1F = 5

P Frame: 0x41   header & 0x1F = 1

H264 nalu的解析参考(https://blog.csdn.net/qq_15559817/article/details/106135451)

(2)rtp over tcp

(len)05 84 (rtp header)80 60 6d ee 00 b5 62 60 00 00 a5 f6 (ps header)00 00
01 ba 44 76 55 85 74 01 02 5f 03 fe ff ff 00 00
86 24 (pes header)00 00 01 e0 21 ba 8c 80 0a 21 1d 95 61 5d
ff ff ff ff f8 (ps payload P)00 00 00 01 61 e0 40 00 59 13 ff
01 23 44 a1 02 38 33 0f 99 df 89 95 01 9e 6d 31
00 2a 8f 05 a5 fb 96 67 38 b8 7f c5 73 bb 25 b6
96 3d 0c 15 0e a4 ed 95 30 6b 43 35 51 9a 04 a1
89 26 6a 6a fc 64 c6 44 37 2a 32 6d 16 12 41 83
53 42 d7 66 e3 51 6b 8e bc 8f 40 73 2a 22 9d a0
d7 b9 c1 ed f8 a5 14 91 2d 8e 90 07 0e b4 2e 4a
0e cb 03 4b 73 f4 1a 49 0a d3 1f bb 72 c5 28 13
b7 9b 35 a0 18 3a c0 91 73 99 1d 4c dd 3b fd eb
ce 8e 73 79 34 8a 05 6d 98 d6 a9 20 d3 43 44 d9
b3 cd be 5b f6 74 86 f4 67 26 2f a1 be fb 5c 2c
aa 81 4d 51 85 06 c7 65 82 52 47 05 5b ae 76 93

数据解析,这是个P帧

len:05 84

rtp header:80 60 6d ee 00 b5 62 60 00 00 a5 f6

ps header:00 00 01 ba ...

pes header:00 00 01 e0 ...

ps payload P:00 00 00 01 61/41 ...

RTP over TCP模式比RTP over UDP模式多了长度字段,但是通过长度信息组包,组成完整的TCP包,完整的TCP包去掉长度信息就是RTP包。然后由于tcp底层会作拆包和粘包的优化处理,所以应用层需要特殊处理,最好用jrtplib的tcp模式,jrtplib库已经处理好了拆包和粘包。

接收,解析流程:tcp ---> rtp ---> ps ---> h264

提供一个示例代码(RTP over TCP/UDP example in jrtplib)

https://github.com/j0r1/JRTPLIB/blob/master/examples/example8.cpp

3、设备端PS流封装和发送

既然从设备接收到的数据已经分析得比较彻底,那么如何反过来封包,分片,发送呢?

ps流封装与解析可以用libmpeg库
https://github.com/ireader/media-server/tree/master/libmpeg
熟悉ffmpeg,也可以定制ffmpeg-4.1/doc/examples/muxing.c

封好的ps buf,按FU-A的格式,每隔1400 byte切一片,每片往前添加个12 byte的rtp header,最后一个切片置位Marker,往外发就行。

rtp over tcp模式下,rtp heade前还得加2 byte长度,所以rtp over tcp头是14 byte,rtp over udp头是12byte.

各种分片细节看rfc3984 https://datatracker.ietf.org/doc/rfc3984/

参考链接:https://www.cnblogs.com/dong1/p/11051708.html
感谢作者提供的分享,受益匪浅,摘录到CSDN和大家一起分享下,如有侵权,请联系删除!

RTP载荷PS流全面分析相关推荐

  1. RTP 发送PS流工具(已经开源)

    RTP接收和发送程序 实时传输协议一直在构建之中,此次听雨堂RTP程序增加了一个PS流发送,以便于GB28181 程序作为测试.     对RTP协议的理解越深,越想自己建立一个实时传输协议. 程序界 ...

  2. RTP协议全解(H264码流和PS流)

    1 视频编码的原理 1.1 一个图像或者一个视频序列进行压缩,产生码流. 对图像的处理即是:帧内预测编码 其预测值P,是由已编码的图像做参考,经运动补偿得到的.预测图像P和当前帧Fn相减,得到两图像的 ...

  3. RTP协议全解(H264码流和PS流)——看完这篇可以毕业

    http://blog.csdn.net/bytxl/article/details/50395427 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 1 视频编码的原理 1. ...

  4. RTP协议全解析(H264码流和PS流

    写在前面:RTP的解析,网上找了很多资料,但是都不全,所以我力图整理出一个比较全面的解析, 其中借鉴了很多文章,我都列在了文章最后,在此表示感谢. 互联网的发展离不开大家的无私奉献,我决定从我做起,希 ...

  5. ps流 转发_(转)RTP协议全解(H264码流和PS流)

    写在前面:RTP的解析,网上找了很多资料,但是都不全,所以我力图整理出一个比较全面的解析, 其中借鉴了很多文章,我都列在了文章最后,在此表示感谢. 互联网的发展离不开大家的无私奉献,我决定从我做起,希 ...

  6. Gb28181之Ps流解析H264

    gb28181发送码流选择PS流,PS流在封装H264的数据.本文详细描述如何通过ps流解析H264码流. *************************PSM流解析*************** ...

  7. PS流(ISO13818和GB28181)分析

    1.理论基础: PSM(PS System map)提供了对PS流中的原始流和他们之间的相互关系的描述信息:PSM是作为一个PES分组出现,当stream_id == 0xBC时,说明此PES包是一个 ...

  8. 海康摄像头PS流格式解析(RTP/PS/H264)

    海康威视视频录像以PS格式打包,解析的过程按照PS包-->system header--->program stream map--->音视频PES包一路下来,海康在包中自定义了一些 ...

  9. RTP协议全解析(H264码流和PS流)(转)

    源: RTP协议全解析(H264码流和PS流) 转载于:https://www.cnblogs.com/LittleTiger/p/10489247.html

最新文章

  1. 前端面经笔记 2021.8.28
  2. SSAS使用时间智能解决本年累计、同比、环比【转载】
  3. matlab读int16读文件_matlab文件读写.doc.doc
  4. si24r1程序_简要分析SI24R1替代兼容NRF24L01P
  5. 结合现有分布式系统的数据一致性思考
  6. android关机分区卸载,Android关机重启流程(二)
  7. 顶级Javaer,常用的 14 个类库
  8. 《架构之美》学习随笔:设计第一步
  9. python装饰器记录每一个函数的执行时间
  10. Matlab中值滤波去噪
  11. 2021-08-27-亚马逊 MWS 坑 handling time(handing time)
  12. matlab画全球参数分布图 绘制世界地图
  13. Unity3d网络总结NetWork组件使用(总结篇)
  14. Linux学习笔记(3)- 网络编程以及范例程序
  15. A/Btest小项目实操
  16. JDBC四个核心对象及其常用方法
  17. 超分辨率——综述文章
  18. 使用迅搜制作站内搜索引擎-安装篇
  19. [Python]输入星座名查询对应Unicode编码图案
  20. Python矩阵计算类:计算矩阵加和、矩阵乘积、矩阵转置、矩阵行列式值、伴随矩阵和逆矩阵

热门文章

  1. 如何修复NullPointerException异常
  2. 弗莱纳公式(Frenet–Serret formulas)
  3. 浙江省引进人才居住证和浙江省居住证有什么不同?
  4. js进阶--JSON,克隆,解构赋值,class类与箭头函数 06
  5. A网站引用B服务器虚拟目录文件导致:网站部署到IIS7上出现HTTP 错误 500.19(由于权限不足而无法读取配置文件)的问题
  6. 业务系统接入单点登录服务
  7. Java方法怎么写怎么用
  8. Altium Desinger 20概述-安装及卸载
  9. AMAX服务器安装双系统(win10,Ubuntu)记要
  10. Package com.** signatures do not match previously installed version; ignoring