PS流包格式之PS/SYS/PSM/PES头

PS流包格式
1,PS流的基本组成
PS流由很多个PS包组成.
每个PS包由如下组成:
PS header + SYS header(I帧)+PSM header(I帧) +PES header+ PES packet n
如:
不含音频非I帧顺序为:PS header | PES header | h264raw data
含音频顺序如下:PS 包=PS头|PES(video)|PES(audio)
PS包主要由固定包头,系统头,和PES包组成,其具体组成如下图所示:
PS流包格式之PS/SYS/PSM/PES头_第1张图片
PS流总是以0x000001BA开始,以0x000001B9结束,对于一个PS文件,有且只有一个结束码0x000001B9,不过对于网传的PS流,则应该是没有结束码的.

1.1 PS header:
PS流包格式之PS/SYS/PSM/PES头_第2张图片
PS头最小长度14个字节
pack_start_code字段:起始码,占位32bit,标识PS包的开始,固定为0x000001BA;

program_mux_rate字段:速率值字段,占位22bit,正整数,表示P-STD接收此字段所在包的PS流的速率;这个值以每秒50字节作为单位;禁止0值;
Marker_bit:标记字段,占位1bit,固定为’1’;
Marker_bit:标记字段,占位1bit,固定为’1’;
stuffing_byte:填充字段,固定为0xFF;长度由pack_stuffing_length确定;

1.2 system header
system header 只有关键帧的时候,才会存在
PS流包格式之PS/SYS/PSM/PES头_第3张图片
 system_header_start_code字段:系统头部起始码,占位32bit,值固定为0x000001BB,标志系统首部的开始;
 header_length字段:头部长度字段,占位16bit,表示此字段之后的系统首部字节长度;
SYS头长度18个字节,则header_length=18-4-2=18-6=12
 Marker_bit字段:占位1bit,固定值为1;
 rate_bound字段:整数值,占位22bit,为一个大于或等于PS流所有PS包中的最大program_mux_rate值的整数;可以被解码器用来判断是否可以对整个流进行解码;
 Marker_bit字段:占位1bit,固定值为1;
 audio_bound字段:占位6bit;取值范围0到32间整数;大于或等于同时进行解码处理的PS流中的音频流的最大数目;
 fixed_flag字段:标志位,占位1bit;置位1表示固定比特率操作,置位0则为可变比特率操作;
 CSPS_flag字段:CSPS标志位,占位1bit;置位1表示此PS流满足标准的限制;
 system_audio_lock_flag字段:标志位,占位1bit,表示音频采样率和STD的system_clock_frequency之间有一特定常数比例关系;
 system_video_lock_flag字段:标志位,占位1bit,表示在系统目标解码器system_clock_frequency和视频帧速率之间存在一特定常数比例关系;
 Marker_bit字段:占位1bit,固定值为1;
 video_bound字段:整数,占位5bit,取值范围0到16;大于或等于同时进行解码处理的PS流中的视频流的最大数目;
 packet_rate_restriction_flag字段:分组速率限制标志字段,占位1bit,若CSPS_flag == 1,则此字段表示哪种限制适用于分组速率;若CSPS_flag == 0,则此字段无意义;
 reserved_bits字段:保留字段,占位7bit,固定为’1111111’;

若stream_id ==’1011 1000’,则其后的P-STD_buffer_bound_scale和P-STD_buffer_size_bound字段对应PS流中的所有音频流;若stream_id ==’1011 1001’,则其后的P-STD_buffer_bound_scale和P-STD_buffer_size_bound字段对应PS流中的所有视频流;若取其他值,则应大于’1011 1100’,且按照标准对应Stream id(详见附录1)
 P-STD_buffer_bound_scale字段:占位1bit,表示用来解释后面P-STD_buffer_size_bound字段的比例因子;如果之前的stream_id表示音频流,则此值应为0,若之前的stream_id表示视频流,则此值应为1,对于其他stream类型,此值可以0或1;
 P-STD_buffer_size_bound字段:占位13bit,无符号整数;大于或等于所有PS流分组的P-STD输入缓冲区大小BSn的最大值;若P-STD_buffer_bound_scale == 0,则P-STD_buffer_size_bound以128字节为单位;若P-STD_buffer_bound_scale == 1,则P-STD_buffer_size_bound以1024字节为单位;
在恒定比特率的操作期间,system_clock_reference字段值应遵从下面的线性公式:
SCR_base(i)=((c1×i+c2) DIV 300) % 233
SCR_ext(i)=((c1×i+c2) DIV 300) % 300
其中:c1 对所有i均有效的实型常数;c2 对所有i均有效的实型常数;
i 在GB/T XXXX.1复合流中包含任何system_clock_reference字段的最后一位的字节索引。
system_video_lock_flag =1 时 SCFR=system_clock_frequency / frame_rate_in_the_P-STD
在这里插入图片描述
system_audio_lock_flag =1时
SCASR=(system_clock_frequency) / audio_sample_rate_in_the_P-STD
PS流包格式之PS/SYS/PSM/PES头_第4张图片

1.3 PSM header
目前的系统头部好像是没有用到的,所以对于系统头部的解析,我们一般只要先首先判断是否存在系统头(根据系统头的起始码0x000001BB),然后我们读取系统头的头部长度,即header_length部分,然后根据系统头部的长度,跳过PS系统头,进入下一个部分,即PS的payload,PES包;在固定包头和系统头之后,就是PS包的payload,即PES包;若PSM存在,则第一个PES包即为PSM。
PSM只有关键帧的时候,才会存在。PSM用来提供es流的描述信息,以及各es流之间的关系。
IDR包含了SPS,PPS和I帧;每个IDR NALU前一般都会包含SPS、PPS等NALU,因此将SPS、PPS、IDR的NALU 封装为一个PS 包,包括PS头,PS system header,PSM,PES;所以一个IDR NALU PS 包由外到内顺序是:PS header| PS system header | PSM| PES。对于其它非关键帧的PS包,就简单多了,直接加上PS头和PES 头就可以了。顺序为:PS header | PES header | h264raw data。以上是对只有视频video 的情况,如果要把音频Audio也打包进PS 封装,只需将数据加上PES header 放到视频PES 后就可以了。顺序如下:PS 包=PS头|PES(video)|PES(audio);
PS流包格式之PS/SYS/PSM/PES头_第5张图片
 Packet start code prefix字段:包头起始码,固定为0x000001,占位24bit;与后面的字段map_stream_id一起组成分组开始码,标志着分组的开始;
 map_stream_id字段:类型字段,标志此分组是什么类型,占位8bit;如果此值为0xBC,则说明此PES包为PSM;
 program_stream_map_length字段:长度字段,占位16bit;表示此字段之后PSM的总长度,最大值为1018(0x3FA);
 current_next_indicator字段:标识符,占位1bit;置位1表示当前PSM是可用的,置位0则表示当前PSM不可以,下一个可用;
 program_stream_map_version字段:版本字段,占位5bit;表示PSM的版本号,取值范围1到32,随着PSM定义的改变循环累加;若current_next_indicator == 1,表示当前PSM的版本号,若current_next_indicator == 0,表示下一个PSM的版本号;
 elementary_stream_map_length字段:长度字段,占位16bit;表示在这个PSM中所有ES流信息的总长度;包括stream_type, elementary_stream_id, elementary_stream_info_length的长度,即N*32bit;是不包括具体ES流描述信息descriptor的长度的;
 stream_type字段:类型字段,占位8bit;表示原始流ES的类型;这个类型只能标志包含在PES包中的ES流类型;值0x05是被禁止的;常见取值类型有MPEG-4 视频流:0x10;H.264 视频流:0x1B;G.711 音频流:0x90;因为PSM只有在关键帧打包的时候,才会存在,所以如果要判断PS打包的流编码类型,就根据这个字段来判断;

 elementary_stream_id字段:流ID字段,占位8bit;表示此ES流所在PES分组包头中的stream_id字段的值;其中0x(C0DF)指音频,0x(E0EF)为视频;

1.4 PES header
PS流包格式之PS/SYS/PSM/PES头_第6张图片
PS流包格式之PS/SYS/PSM/PES头_第7张图片
PS流包格式之PS/SYS/PSM/PES头_第8张图片
PES包的起始码是(0x000001), 起始码之后是stream_id(1个字节), 在之后的两个字节是PES包的长度,再往后的两个字节不用理,再往后的一个字节说明了PES header的长度,PES header 之后就是 PES的负载了,即ES流。
 PES分组长度字段 PES_packet_length
16位字段,指出了PES分组中跟在该字段后的字节数目,通常是静荷长度+13(该字段后本身头结构的长度)。
 PTS DTS标志字段 PTS_DTS_flags
2位字段。当值为’10’时,PTS字段应出现在PES分组标题中;当值为’11’时,PTS字段和DTS字段都应出现在PES分组标题中;当值为’00’时,PTS字段和DTS字段都不出现在PES分组标题中。值’01’是不允许的。
 PES标题数据长度字段 PES_header_data_length
8位字段。指出包含在PES分组标题中的可选字段和任何填充字节所占用的总字节数。该字段之前的字节指出了有无可选字段。
 展现时间戳字段 PTS , 解码时间戳字段 DTS
PTS/DTS的值以系统时钟频率的1/300(即90 kHz)为单位。 system_clock_frequency =300*90000=27M
对编码展现时间戳频率的约束:
PTS(k)=((system_clock_frequency×tpn(k)) DIV 300) % 233
其中,tpn(k)是展现单元Pn(k)的展现时间,即每帧的时间戳(ms).
DTS(j)=((system_clock_frequency×tdn(j)) DIV 300) % 233
其中,tdn(j)是存取单元An(j)的解码时间。
其中PTS和DTS使用的是90KHZ时钟单位,即1PTS表示1/90000秒,PTS和DTS虽然是33位,但占用了5个字节.
如: tp(n)= 1547524052, (2019/1/15 11:47:32)
PTS(n)= tp(n)27M/300=154752405290000
如果是以微妙为单位,即tp(k)= tp(n)*1000000us,
PTS(n)= tp(n)*27M/300=(tp(k)/1000000)271000000/300=tp(k)*9/100;
 特技方式控制字段 trick_mode_control
PS流包格式之PS/SYS/PSM/PES头_第9张图片
 片内参考字段 intra_slice_refresh
1位标志。置’1’时表示PES分组的视频数据编码片中可能有丢失的宏块;置’0’时,表示上述情况可能不出现。更多的信息可参见GB/T XXXX.2。解码器可以用前一个解码画面中同一个位置的宏块来代替丢失的宏块。
 填充字节字段 stuffing_byte
8位字段,其值恒定为’1111 1111’。可以由编码器插入以满足通道的需求等。解码器丢弃该字段。一个PES分组标题中只能出现32个填充字节。
 PES分组数据字节字段 PES_packet_data_byte
该字段应该是来自于由分组的stream_id或PID所指定的基本流的连续数据字节。当基本流数据符合GB/T XXXX.2或GB/T XXXX.3时,该字段应该是与本标准的字节相对齐的字节。基本流的字节序应得到保持。该字段的字节数N由PES_packet_length字段规定。N应等于PES_packet_length减去在PES_packet_length字段的最后一个字节与第一个 PES_packet_data_byte间的字节数。

 结构图
PS流包格式之PS/SYS/PSM/PES头_第10张图片
再来看另一图:
PS流包格式之PS/SYS/PSM/PES头_第11张图片

PS流包格式之PS/SYS/PSM/PES头_第12张图片

你可能感兴趣的:(视频)