一. GB28181要求的RTP流格式
本文来自于互联网的好几个博客总结
首先,我们来看看I帧的PS流格式,这里需要注意的是SPS、PPS之前要加上PES头部。如下图所示,其中绿色部分就是我们拿到的H.264裸流数据,须将它拆分成三段并在前面加上PES头部。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RGHRtyob-1604307620259)(C:\Users\HiYoung\Downloads\20190826212138335.png)]
一般情况下IDR帧很大,超过了RTP的负载长度限制(1400字节),所以上面这一个I帧要拆分成若干包RTP分多次发送。第一包的结构如上图所示,第二包以后RTP的结构就简单多了,它是这样的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yEldCY1s-1604307620275)(C:\Users\HiYoung\Downloads\20190826212933415.png)]
上面提到的是I帧的情况,相比它,P/B帧的帧格式真是太简单了,因为它既没有SYS、PSM,也没有SPS、PPS:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1oUDuNXz-1604307620295)(C:\Users\HiYoung\Downloads\20190826213252367.png)]
P/B帧大小一般不超过1400字节,如果超过1400字节,也需分成多包RTP数据进行传输,超出1400部分的第二包RTP结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BJn40rSh-1604307620309)(C:\Users\HiYoung\Downloads\20190826213439774.png)]
二. 字段解释
2.1 RTP包头
首先是RTP包头信息,它一般长度为12个字节。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D3RA3d8i-1604307620314)(C:\Users\HiYoung\Downloads\20140912153130104.png)]
1)V:RTP协议的版本号,占2位,当前协议版本号为2。/* 2位 rtp version版本号固定为2*/
2) P:填充标志,占1位,如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分/* rtp padding 1位*/
-
X:扩展标志,占1位,如果X=1,则在RTP报头后跟有一个扩展报头 /* 1位 rtp extension */
-
CC:CSRC计数器,占4位,指示CSRC 标识符的个数 /* 4位 rtp CSRC count */
-
M: 标记,占1位,不同的有效载荷有不同的含义,对于视频,标记一帧的结束;对于音频,标记会话的开始。/* rtp marker 结束标志位,一帧图像的最后一包RTP置1,标志音频的开始*/
-
PT: 有效荷载类型,占7位,用于说明RTP报文中有效载荷的类型,如GSM音频、JPEM图像等,在流媒体中大部分是用来区分音频流和视频流的,这样便于客户端进行解析。/* rtp payload type,96代表PS*/
-
序列号:占16位,用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1。这个字段当下层的承载协议用UDP的时候,网络状况不好的时候可以用来检查丢包。同时出现网络抖动的情况可以用来对数据进行重新排序,序列号的初始值是随机的,同时音频包和视频包的sequence是分别记数的。 /* rtp sequence */
-
时戳(Timestamp):占32位,必须使用90 kHz 时钟频率。时戳反映了该RTP报文的第一个八位组的采样时刻。接收者使用时戳来计算延迟和延迟抖动,并进行同步控制。 /* rtp timestamp */
-
同步信源(SSRC)标识符:占32位,用于标识同步信源。该标识符是随机选择的,参加同一视频会议的两个同步信源不能有相同的SSRC。 /* rtp SSRC */
-
特约信源(CSRC)标识符:每个CSRC标识符占32位,可以有0~15个。每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源。
基本的RTP说明并不定义任何头扩展本身,如果遇到X=1,需要特殊处理,开头一般为80 e0 00 1e
2.2 PSHead头部
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 封装发送就可以了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VBkhp9Iq-1604307620324)(C:\Users\HiYoung\Downloads\20190826212138335.png)]
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;
- 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。
PSH头部,它占了14个字节
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZuIJ3eVD-1604307620328)(C:\Users\HiYoung\Downloads\20140912161343125.png)]
- Pack start code:包起始码字段,值为0x000001BA的位串,用来标志一个包的开始。/start codes 起始码/
2)后面01固定。/*marker bits ‘01b’ */
- System clock reference base,system clock reference extenstion:系统时钟参考字段。/*System clock [32…30] /
4)always set /*marker bit */
5) /*System clock [29…15] */ 15位 , 2+8+5
6) /*marker bit */ always set 1
7)/System clock [14…0]/ 15位
8)/*marker bit */ always set 1
9)/*SCR extension */ 9位
10)/*marker bit */ always set 1
11)/*bit rate(n units of 50 bytes per second.) */ 22位 ,10字节到12字节部分。一个22位整数,规定P-STD在包含该字段的包期间接收节目流的速率。其值以50字节/秒为单位。不允许取0值。
12) /* marker bits ‘11’*/ always set 2位
13)/* reserved(reserved for future use)*/ 保留5位
14)/*stuffing length */包填充长度字段,3 位整数,规定该字段后填充字节的个数
15)stuffing byte为填充得字节数 //8位字段,取值恒为’1111 1111’
2.3 PS系统头
PS system header
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HhzVQRu2-1604307620336)(C:\Users\HiYoung\Downloads\20140912162121737.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BN6wAD6o-1604307620344)(C:\Users\HiYoung\Downloads\20190530220948278.jpg)]
- system_header_start_code 系统标题起始码字段,32 位字段,取值’0000 0000 0000 0000 0000 0001 1011 1011’ (0x000001BB)的位串,指出系统标题的开始。
- header_length 标题长度字段,16位字段。指出该字段后的系统标题的字节长度。在本规范将来的扩充中可能扩展该字段。
- marker_bit 占位1bit, 固定值为 1
- rate_bound 速率界限字段。22位字段,取值不小于编码在节目流的任何包中的program_mux_rate字段的最大值。该字段可被解码器用于估计是否有能力对整个流解码
- marker_bit 占位1bit, 固定值为 1
- audio_bound 音频界限字段,6位字段,取值是在从0到32的闭区间中的整数,且不小于节目流中解码过程同时活动的GB/T XXXX.3和GB/T AAAA.3音频流的最大数目
- fixed_flag 固定标志字段,1位标志位。置’1’时表示比特率恒定的操作;置’0’时,表示操作的比特率可变
- CSPS_flag CSPS标志字段,1位字段。置’1’时,节目流符合标准
- system_audio_lock_flag 系统音频锁定标志字段,1位字段。表示在系统目标解码器的音频采样率和system_clock_frequency之间存在规定的比率。
- system_video_lock_flag 系统视频锁定标志字段1位字段。表示在系统目标解码器的视频帧速率和system_clock_frequency之间存在规定的比率
- marker_bit 占位1bit, 固定值为 1
- vedio_bound 视频界限字段,5位字段,取值是在从0到16的闭区间中的整数且不小于节目流中解码过程同时活动的GB/T XXXX.2和GB/T AAAA.2流的最大数目
- packet_rate_restriction_flag 分组速率限制标志字段,1位标志位。若CSPS标识为’1’,则该字段表示2.7.9中规定的哪个限制适用于分组速率。若CSPS标识为’0’,则该字段的含义未定义。
- reserved_bits 保留位字段,7位字段。固定值应为’111 1111’定。
- stream_id 流标识字段,8位字段。指示其后的P-STD_buffer_bound_scale和P-STD_buffer_size_bound字段所涉及的流的编码和基本流号码。若取值’1011 1000’,则其后的P-STD_buffer_bound_scale和P-STD_buffer_size_bound字段指节目流中所有的音频流;若取值’1011 1001’,则其后的P-STD_buffer_bound_scale和P-STD_buffer_size_bound字段指节目流中所有的视频流。
- marker_bit 占位2bit, 固定值为 11
- P-STD_buffer_bound_scale P-STD缓冲区界限比例字段,1位字段。表示用于解释后续P-STD_buffer_size_bound字段的比例系数。若前面的stream_id表示一个音频流,则该字段值为’0’。若表示一个视频流,则该字段值为’1’。对于所有其它的流类型,该字段值可以为’0’也可以为’1’。
- P-STD_buffer_size_bound P-STD缓冲区大小界限字段,13位无符号整数,取值不小于节目流中流n的所有分组的P-STD缓冲区大小BSn的最大值。若P-STD_buffer_bound_scale的值为’0’,则该字段以128字节为单位来度量缓冲区大小的边界。
Systemheader当且仅当pack是第一个数据包时才存在,也就是IDR NALU , 即PS包头之后就是系统标题。取值0x000001BB的位串,指出系统标题的开始,暂时不需要处理,读取Header Length直接跳过即可。SYS
2.4 PSMap头
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CVxll6Jz-1604307620349)(C:\Users\HiYoung\Downloads\20190530222915772.png)]
1)packet_start_code_prefix 分组起始码前缀字段24位码。它和跟随其后的map_stream_id共同组成一个分组起始码以标志分组的开始。该字段是值为’0000 0000 0000 0000 0000 0001’ (0x000001)的位串。
2)map_stream_id 映射流标识字段8位字段,值为0xBC
3)program_stream_map_length 节目流映射长度字段16位字段。指示紧跟在该字段后得program_stream_map中的字节数。
4)current_next_indicator 当前下一个指示符字段1位字段。置’1’时表示传送的节目流映射当前是可用的。置’0’时表示传送的节目流映射还不可用,但它将是下一个生效的表。
5)reserved 保留字段 2位
6)program_stream_map_version 节目流映射版本字段5位字段,表示整个节目流映射版本号。一旦节目流映射的定义发生变化,该字段将递增1,并对32取模。在current_next_indicator为’1’时,该字段应该是当前适用的节目流映射的版本号;在current_next_indicator为’0’时,该字段应该是下一个适用的节目流映射的版本号。
7)reserved 保留字段 7位
8)marker_bit 标志位 , 1位字段,取值为’1’。
9)program_stream_info_length 节目流信息长度字段16位字段,指出紧跟在该字段后的描述符的总长度。
10)elementary_stream_map_length 基本流映射长度字段16位字段,指出在该节目流映射中的所有基本流信息的字节长度。它只包括stream_type、elementary_stream_id和elementary_stream_info_length字段。
11)stream_type 流类型字段,MPEG-4 视频流: 0x10;H.264 视频流: 0x1B;SVAC 视频流: 0x80;
G.711 音频流: 0x90;G.722.1 音频流: 0x92;G.723.1 音频流: 0x93;G.729 音频流: 0x99;
SVAC音频流: 0x9B。
12)elementary_stream_id 基本流标识字段,8位字段,指出该基本流所在PES分组的PES分组标题中stream_id字段的值。(这个字段的定义,其中0x(C0DF)指音频,0x(E0EF)为视频)
13)elementary_stream_info_length 基本流信息长度字段,16位字段,指出紧跟在该字段后的描述符的字节长度。(即这个类型的流描述长度。这个后面的字段后面的指定长度不在elementary_stream_map_length指定的范围类。)
14)CRC_32 32位字段,它包含CRC值以在处理完整个节目流映射后在附录A中定义的解码器寄存器产生0输出值。
2.5 PES Header
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oHr7COLm-1604307620354)(C:\Users\HiYoung\Downloads\20190530224252306.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZOUAMUfJ-1604307620358)(C:\Users\HiYoung\Downloads\20190530224258177.jpg)]
-
packet_start_code_prefix 分组起始码前缀字段,24位代码,它和后面的stream_id构成了标识分组开始的分组起始码。它是一个值为’0000 0000 0000 0000 0000 0001’ (0x000001)的位串。
-
stream_id 流标识字段,在节目流中,它规定了基本流的号码和类型。具体见下表, Stream id:在节目流中,它规定了基本流的号码和类型。0x(C0DF)指音频,0x(E0EF)为视频
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u3UjKQfU-1604307620371)(C:\Users\HiYoung\Downloads\20190530224851337.png)]
-
PES_packet_length PES分组长度字段,16位字段,指出了PES分组中跟在该字段后的字节数目。
-
PES_scrambling_control PES加扰控制字段,2位字段,表示PES分组有效负载的加扰方式。当加扰发生在PES层,PES分组标题,如果有可选字段的话也包括在内,不应被加扰(参见2-19)。
-
PES_priority PES优先级字段, 1位字段,指示PES分组中有效负载的优先级,'1’表示PES分组中有效负载的优先级高于该字段为’0’的PES分组有效负载。
-
data_alignment_indicator 数据对齐指示符字段,1位标志。置’1’时表示PES分组标题后紧跟着在2.6.10中的data_alignment_indicator所指出的视频起始码或音频同步字,如果有data_alignment_indicator描述符的话。若其值为’1’且无该描述符,则需要在表2-47和2-48中alignment_type '01’所表示的对齐。当值为’0’时,没有定义是否有任何此种的对齐。
-
copyright 版权字段,1位字段。置’1’时表示相关PES分组有效负载的材料受到版权保护。当值为’0’时,没有定义该材料是否受到版权保护。2.6.24中,描述的版权描述符与包含PES分组的基本流相关。若描述符作用于包含PES分组的材料,则版权标志被置为’1’。
-
original_or_copy 原始或拷贝字段,1位字段。置’1’时表示相关PES分组有效负载的内容是原始的;值为’0’表示相关PES分组有效负载的内容是一份拷贝。
-
PTS_DTS_flags PTS DTS标志字段,2位字段。当值为’10’时,PTS字段应出现在PES分组标题中;当值为’11’时,PTS字段和DTS字段都应出现在PES分组标题中;当值为’00’时,PTS字段和DTS字段都不出现在PES分组标题中。值’01’是不允许的
-
ESCR_flag ESCR标志字段,1位标志。置’1’时表示ESCR基础和扩展字段出现在PES分组标题中;值为’0’表示没有ESCR字段。
-
ES_rate_flag,ES速率标志字段,1位标志。置’1’时表示ES_rate字段出现在PES分组标题中;值为’0’表示没有ES_rate字段。
-
DSM_trick_mode_flag DSM特技方式标志字段,1位标志。置’1’时表示有8位特技方式字段;值为’0’表示没有该字段。
-
additional_copy_info_flag 附加版权信息标志字段.1位标志。置’1’时表示有附加拷贝信息字段;值为’0’表示没有该字段。
14)PES_CRC_flag PES CRC标志字段。1位标志。置’1’时表示CRC字段出现在PES分组标题中;值为’0’表示没有该字段
15) PES_extension_flag PES扩展标志字段。1位标志。置’1’时表示PES分组标题中有扩展字段;值为’0’表示没有该字段。
16) PES_header_data_length PES标题数据长度字段。8位字段。指出包含在PES分组标题中的可选字段和任何填充字节所占用的总字节数。该字段之前的字节指出了有无可选字段。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ud4ZKcTP-1604307620376)(C:\Users\HiYoung\Downloads\20200316225535799.jpg)]
三. RTP负载H.264
h264裸流文件中,主要由NAL单元构成,每个单元被0x00 00 01或0x00 00 00 01分割。NAL单元分为1个字节的头部和负载组成。NAL单元头部定义如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RAE2XOIP-1604307620385)(C:\Users\HiYoung\Downloads\20200425170610701.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nIdrvfBf-1604307620390)(C:\Users\HiYoung\Downloads\20200425173734719.png)]
NALU简单介绍
F:禁止位,0表示正常,1表示错误,正常H264数据为0。
NRI:重要级别,表示当前NAL单元的重要性。
TYPE:表示该NAL的类型是什么。
I帧封装顺序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PGeD4Q9r-1604307620403)(C:\Users\HiYoung\Downloads\20171226215951622.png)]
E2XOIP-1604307620385)]
[外链图片转存中…(img-nIdrvfBf-1604307620390)]
NALU简单介绍
F:禁止位,0表示正常,1表示错误,正常H264数据为0。
NRI:重要级别,表示当前NAL单元的重要性。
TYPE:表示该NAL的类型是什么。
I帧封装顺序
[外链图片转存中…(img-PGeD4Q9r-1604307620403)]