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

ps流转发_(转)RTP协议全解(H264码流和PS流)
写在前⾯:RTP的解析,⽹上了很多资料,但是都不全,所以我⼒图整理出⼀个⽐较全⾯的解析,
其中借鉴了很多⽂章,我都列在了⽂章最后,在此表⽰感谢。
互联⽹的发展离不开⼤家的⽆私奉献,我决定从我做起,希望⼤家⽀持。
1、RTP Header解析
图1
1)        V:RTP协议的版本号,占2位,当前协议版本号为2
2)        P:填充标志,占1位,如果P=1,则在该报⽂的尾部填充⼀个或多个额外的⼋位组,它们不是有效载荷的⼀部分。
3)        X:扩展标志,占1位,如果X=1,则在RTP报头后跟有⼀个扩展报头
4)        CC:CSRC计数器,占4位,指⽰CSRC 标识符的个数
5)        M: 标记,占1位,不同的有效载荷有不同的含义,对于视频,标记⼀帧的结束;对于⾳频,标记会话的开始。
6)        PT: 有效荷载类型,占7位,⽤于说明RTP报⽂中有效载荷的类型,如GSM⾳频、JPEM图像等,在流媒体中⼤部分是⽤来区分⾳频流和视频流的,这样便于客户端进⾏解析。
7)        序列号:占16位,⽤于标识发送者所发送的RTP报⽂的序列号,每发送⼀个报⽂,序列号增1。这个字段当下层的承载协议⽤UDP 的时候,⽹络状况不好的时候可以⽤来检查丢包。同时出现⽹络抖动的情况可以⽤来对数据进⾏重新排序,序列号的初始值是随机的,同时⾳频包和视频包的sequence是分别记数的。
8)        时戳(Timestamp):占32位,必须使⽤90 kHz 时钟频率。时戳反映了该RTP报⽂的第⼀个⼋位组的采样时刻。接收者使⽤时戳来计算延迟和延迟抖动,并进⾏同步控制。
9)        同步信源(SSRC)标识符:占32位,⽤于标识同步信源。该标识符是随机选择的,参加同⼀视频会议的两个同步信源不能有相同的SSRC。
10)    特约信源(CSRC)标识符:每个CSRC标识符占32位,可以有0~15个。每个CSRC标识了包含在该RTP报⽂有效载荷中的所有特约信源。
注:基本的RTP说明并不定义任何头扩展本⾝,如果遇到X=1,需要特殊处理
取⼀段码流如下:
e1 0f 26 53 02 1a ff06 59 97 1d d2 2e 8c 50 01 ?.&Y?.?.?P.
cc 13 ec 52 77 4e e50e 7b fd 16 11 66 27 7c b4 ?.?RwN?.{?..f'|?
f6 e1 29 d5 d6 a4 ef3e 12 d8 fd 6c 97 51 e7 e9 ??)>.??l?Q??
cfc7 5e c8 a9 51 f6 82 65 d6 48 5a 86 b0 e0 8c ??^??Q??e?HZ
其中,
80              是V_P_X_CC
e0              是M_PT
00 1e          是SequenceNum
把前两字节换成⼆进制如下
1000 0000 1110 0000
按顺序解释如下:
三相全波整流10              是V;
0                是P;
0                是X;
0000          是CC;
1                是M;
110 0000    是PT;
排版不如word看的清晰,⼤家凑合着看吧。
2、RTP荷载H264码流
图2
辽宁石油化工大学学报
荷载格式定义三个不同的基本荷载结构,接收者可以通过RTP荷载的第⼀个字节后5位(如图2)识别荷载结构。
1)  单个NAL单元包:荷载中只包含⼀个NAL单元。NAL头类型域等于原始 NAL单元类型,即在范围1到23之间
2)  聚合包:本类型⽤于聚合多个NAL单元到单个RTP荷载中。本包有四种版本,单时间聚合包类型A (STAP-A),单时间聚合包类型B (STAP-B),多时间聚合包类型(MTAP)16位位移(MTAP16), 多时间聚合包类型(MTAP)24位位移(MTAP24)。赋予STAP-A, STAP-B, MTAP16, MTAP24的NAL单元类型号分别是 24,25, 26, 27
3)  分⽚单元:⽤于分⽚单个NAL单元到多个RTP包。现存两个版本FU-A,FU-B,⽤NAL单元类型 28,29标识
常⽤的打包时的分包规则是:如果⼩于MTU采⽤单个NAL单元包,如果⼤于MTU就采⽤FUs分⽚⽅式。
因为常⽤的打包⽅式就是单个NAL包和FU-A⽅式,所以我们只解析这两种。
2.1、单个NAL单元包
图3
定义在此的NAL单元包必须只包含⼀个。这意味聚合包和分⽚单元不可以⽤在单个NAL 单元包中。并且RTP序号必须符合NAL单元的解码顺序。NAL单元的第⼀字节和RTP荷载头第⼀个字节重合。如图3。
打包H264码流时,只需在帧前⾯加上12字节的RTP头即可。
2.2、分⽚单元(FU-A)
图4
分⽚只定义于单个NAL单元不⽤于任何聚合包。NAL单元的⼀个分⽚由整数个连续NAL单元字节组成。每个NAL单元字节必须正好是该NAL单元⼀个分⽚的⼀部分。相同NAL单元的分⽚必须使⽤递增的RTP序号连续顺序发送(第⼀和最后分⽚之间没有其他的RTP包)。相似,NAL单元必须按照RTP顺序号的顺序装配。
当⼀个NAL单元被分⽚运送在分⽚单元(FUs)中时,被引⽤为分⽚NAL单元。STAPs,MTAPs不可以被分⽚。 FUs不可以嵌套。 即, ⼀个FU 不可以包含另⼀个FU。运送FU的RTP时戳被设置成分⽚NAL单元的NALU时刻。
图 4 表⽰FU-A的RTP荷载格式。FU-A由1字节的分⽚单元指⽰(如图5),1字节的分⽚单元头(如图6),和分⽚单元荷载组成。
S: 1 bit 当设置成1,开始位指⽰分⽚NAL单元的开始。当跟随的FU荷载不是分⽚NAL单元荷载的开始,开始位设为0。
E: 1 bit 当设置成1, 结束位指⽰分⽚NAL单元的结束,即, 荷载的最后字节也是分⽚NAL单元的最后⼀个字节。当跟随的 FU荷载不是分⽚NAL单元的最后分⽚,结束位设置为0。
R: 1 bit 保留位必须设置为0,接收者必须忽略该位
打包时,原始的NAL头的前三位为FU indicator的前三位,原始的NAL头的后五位为FU header的后五位。
取⼀段码流分析如下:
00 0a 7f ca 94 05 3b7f 3e 7f fe 14 2b 27 26 f8 ...??.;.>.?.+'&?
89 88 dd 85 62 e1 6dfc 33 01 38 1a 10 35 f2 14 b?m?3.8..5?.
84 6e 21 24 8f 72 62f0 51 7e 10 5f 0d 42 71 12 ?n!$?rb?Q~._.Bq.
17 65 62 a1 f1 44 dc df 4b 4a 38 aa 96 b7 dd 24 .eb??D??KJ8$
前12字节是RTP Header
7c是FU indicator
85是FU Header
FU indicator(0x7C)和FU Header(0x85)换成⼆进制如下
0111 1100 1000 0101
按顺序解析如下:证券监督管理条例
0                            是F
11                          是NRI
11100                    是FU Type,这⾥是28,即FU-A
1                            是S,Start,说明是分⽚的第⼀包
填量词0                            是E,End,如果是分⽚的最后⼀包,设置为1,这⾥不是
0                            是R,Remain,保留位,总是0
00101                    是NAl Type,这⾥是5,说明是关键帧(不知道为什么是关键帧请⾃⾏⾕歌)
打包时,FUindicator的F、NRI是NAL Header中的F、NRI,Type是28;FU Header的S、E、R分别按照分⽚起始位置设置,Type是NAL Header中的Type。
解包时,取FU indicator的前三位和FU Header的后五位,即0110 0101(0x65)为NAL类型。
3、RTP荷载PS流
针对H264 做如下PS 封装:每个IDR NALU 前⼀般都会包含SPS、PPS 等NALU,因此将SPS、PPS、IDR 的NALU 封装为⼀个PS 包,包括ps 头,然后加上PS system header,PS system map,PES header+h264 raw data。所以⼀个IDR NALU PS 包由外到内顺序是:PSheader| PS system header | PS system Map | PES header | h264 raw data。对于其它⾮关键帧的PS 包,就简单多了,直接加上PS头和PES 头就可以了。顺序为:PS header | PES header | h264raw data。以上是对只有视频video 的情况,如果要把⾳频Audio也打包进PS 封装,也可以。当有⾳频数据时,将数据加上PES header 放到视频PES 后就可以了。顺序如下:PS 包=PS
头|PES(video)|PES(audio),再⽤RTP 封装发送就可以了。
GB28181 对RTP 传输的数据负载类型有规定(参考GB28181 附录B),负载类型中96-127
RFC2250 建议96 表⽰PS 封装,建议97 为MPEG-4,建议98 为H264
即我们接收到的RTP 包⾸先需要判断负载类型,若负载类型为96,则采⽤PS 解复⽤,将⾳视频分开解码。若负载类型为98,直接按照
H264 的解码类型解码。
注:此⽅法不⼀定准确,取决于打包格式是否标准
PS 包中的流类型(stream type)的取值如下:
1)        MPEG-4 视频流: 0x10;
2)        H.264 视频流: 0x1B;
3)        SVAC 视频流: 0x80;
4)        G.711 ⾳频流: 0x90;
5)        G.722.1 ⾳频流: 0x92;
6)        G.723.1 ⾳频流: 0x93;
7)        G.729 ⾳频流: 0x99;
8)      SVAC⾳频流: 0x9B。
3.1、PS包头
图7
1)        Pack start code:包起始码字段,值为0x000001BA的位串,⽤来标志⼀个包的开始。
2)        System clock reference base,system clock reference extenstion:系统时钟参考字段。
3)        Pack stuffing length :包填充长度字段,3 位整数,规定该字段后填充字节的个数
7e ff 3e fb 44 01 00 5f 6b f8 00 00 01 e0 14 53 ~.>?D.._k?...?.S
80 80 05 2f bf cf bed1 1c 42 56 7b 13 58 0a 1e €€./.BV{.X..
08 b1 4f 33 69 35 0453 6d 33 a8 04 15 58 d9 21 .?O3i5.Sm3?..X?!
9741 b9 f1 75 3d 94 2b 1f bc 0b b2 b4 97 bf 93 ?A??u=?+.?.
前12位是RTP Header,这⾥不再赘述;
000001ba是包头起始码;
接下来的9位包括了SCR,SCRE,MUXRate,具体看图7
最后⼀位是保留位(0xf8),定义了是否有扩展,⼆进制如下
1111 1000
前5位跳过,后3位指⽰了扩展长度,这⾥是0.
3.2、系统标题
图8
Systemheader当且仅当pack是第⼀个数据包时才存在,即PS包头之后就是系统标题。取值0x000001BB的位串,指出系统标题的开始,暂时不需要处理,读取Header Length直接跳过即可。
3.3、节⽬映射流
Systemheader当且仅当pack是第⼀个数据包时才存在,即系统标题之后就是节⽬流映射。取值0x000001BC的位串,指出节⽬流映射的开始,暂时不需要处理,读取Header Length直接跳过即可。前5字节的结构同系统标题,见图8。
取⼀段码流分析系统标题和节⽬映射流
01 bb 00 0c 80 cc f5 04 e1 7f e0 e0 e8 c0 c0 20  .?..€??.?.
2a 0a 7f ff 00 00 0708 1f fe a0 5a 90 c0 00 00  *........??Z??..
00 00 00 00 00 00 01 e0 7f e0 80 80 0521 6a 75  .......?.?€€.!ju
前14个字节是PS包头(注意,没有扩展);
接下来的00 00 01 bb是系统标题起始码;
接下来的00 0c说明了系统标题的长度(不包括起始码和长度字节本⾝);
接下来的12个字节是系统标题的具体内容,这⾥不做解析;
继续看到00 00 01 bc,这是节⽬映射流起始码;
紧接着的00 1e同样代表长度;
跳过e1 ff,基本没⽤;
接下来是00 18,代表基本流长度,说明了后⾯还有24个字节;
接下来的1b,意思是H264编码格式;
下⼀个字节e0,意思是视频流;
接下⾥00 0c,同样代表接下的长度12个字节;
跳过这12个字节,看到90,这是G.711⾳频格式;
下⼀个字节是c0,代表⾳频流;
追溯调整接下来的00 00同样代表长度,这⾥是0;
接下来4个字节是CRC,循环冗余校验。
到这⾥节⽬映射流解析完毕。(好累
)。
好戏还在后头呢。
3.4、PES分组头部
图9
别被这么长的图吓到,其实原理相同,但是,你必须处理其中的每⼀位。
1)        Packet start code prefix:值为0x000001的位串,它和后⾯的stream id 构成了标识分组开始的分组起始码,⽤来标志⼀个包的开始。
2)        Stream id:在节⽬流中,它规定了基本流的号码和类型。0x(C0~DF)指⾳频,0x(E0~EF)为视频
3)        PES packet length:16 位字段,指出了PES 分组中跟在该字段后的字节数⽬。值为0 表⽰PES 分组长度要么没有规定要么没有限制。这种情况只允许出现在有效负载包含来源于传输流分组中某个视频基本流的字节的PES 分组中。
4)        PTS_DTS:2 位字段。当值为'10'时,PTS 字段应出现在PES 分组标题中;当值为'11'时,PTS 字段和DTS 字段都应出现在PES 分组标题中;当值为'00'时,PTS 字段和DTS 字段都不出现在PES分组标题中。值'01'是不允许的。
5)        ESCR:1位。置'1'时表⽰ESCR 基础和扩展字段出现在PES 分组标题中;值为'0'表⽰没有ESCR 字段。
6)        ESrate:1 位。置'1'时表⽰ES rate 字段出现在PES 分组标题中;值为'0'表⽰没有ES rate 字段。
7)        DSMtrick mode:1 位。置'1'时表⽰有8 位特技⽅式字段;值为'0'表⽰没有该字段。
8)        Additionalinfo:1 位。附加版权信息标志字段。置'1'时表⽰有附加拷贝信息字段;值为'0'表⽰没有该字段。棱光实业
9)        CRC:1 位。置'1'时表⽰CRC 字段出现在PES 分组标题中;值为'0'表⽰没有该字段。
10)    Extensionflag:1 位标志。置'1'时表⽰PES 分组标题中有扩展字段;值为'0'表⽰没有该字段。
PES header data length: 8 位。PES 标题数据长度字段。指出包含在PES 分组标题中的可选字段和任何填充字节所占⽤的总字节数。该字段之前的字节指出了有⽆可选字段。
⽼规矩,上码流:

本文发布于:2024-09-21 15:52:56,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/461985.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:单元   字节   类型   分组   标题   开始
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议