1、理论基础:
PSM(PS System map)提供了对PS流中的原始流和他们之间的相互关系的描述信息;PSM是作为一个PES分组出现,当stream_id == 0xBC时,说明此PES包是一个PSM;PSM是紧跟在系统头部后面的;PSM是作为PS包的payload存在的;
PS头( pack_header):0x000001BA
系统头部( system_header):0x000001BB我们一般只要先首先判断是否存在系统头,然后我们读取系统头的头部长度,即PS SYSTEM HEADER LENGTH部分,然后根据头部的长度,跳过PS系统头。进入下一个部分,即PS 节目流映射头
节目流映射( program_stream_map):0x000001BC的位串,指出节目流映射的开始,暂时不需要处理,读取Header Length直接跳过即可,如果需要解析流编码类型,必须详细解析这个字段。
GB28181 对RTP 传输的数据负载类型有规定(参考GB28181 附录B),负载类型中96-127,RFC2250 建议96 表示PS 封装,建议97 为MPEG-4,建议98 为H264
即我们接收到的RTP 包首先需要判断负载类型,若负载类型为96,则采用PS 解复用,将音视频分开解码。若负载类型为98,直接按照H264 的解码类型解码。注:此方法不一定准确,取决于打包格式是否标准。
PES视频流:0x000001E0
PES音频流:0x000001C0
针对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 封装发送就可以了。
PS码流文件分析:
mpeg-ps里面是没有音视频的编码信息的,如果是像pcm或pcma、pcmu这类音频,是不知道声道、采样率、采样位数的,所以就无法播放。实际上mpeg-ps中pcma、pcmu的声道、采样率、采样位数一般是1,8000,16,特别是28181协议中。
注:后面跟着就是自定义的描述内容(海康在这里放入了复合流的私有描述:两字节复合流描述字(40 0E)+内容(用于放置全局时间,编码设备型号等相关信息)+两字节复合流描述字(41 12)(可选)+内容(用于描述设备与通道号),所以长度就不是00 00)
接着我们来看看解析步骤:(来自MPEG-2标准文档)
表2-17 PES分组
语 法 | 位数 | 助记符 |
PES_packet(){ | ||
packet_start_code_prefix | 24 | bslbf |
stream_id | 8 | uimsbf |
PES_packet_length | 16 | uimsbf |
if(stream_id != program_stream_map | ||
&& stream_id !=padding_stream | ||
&& stream_id !=private_stream_2 | ||
&& stream_id !=ECM | ||
&& stream_id !=EMM | ||
&& stream_id !=program_stream_directory | ||
&& stream_id !=DSMCC_stream | ||
&& stream_id !=ITU-T Rec.H.222.1 type E stream){ | ||
'10' | 2 | bslbf |
PES_scrambling_control | 2 | bslbf |
PES_priority | 1 | bslbf |
data_alignment_indicator | 1 | bslbf |
copyright | 1 | bslbf |
original_or_copy | 1 | bslbf |
PTS_DTS_flags | 2 | bslbf |
ESCR_flag | 1 | bslbf |
ES_rate_flag | 1 | bslbf |
DSM_trick_mode_flag | 1 | bslbf |
additional_copy_info_flag | 1 | bslbf |
PES_CRC_flag | 1 | bslbf |
PES_extension_flag | 1 | bslbf |
PES_header_data_length | 8 | uimsbf |
if(PTS_DTS_flags =='10'){ | ||
'0010' | 4 | bslbf |
PTS[32..30] | 3 | bslbf |
marker_bit | 1 | bslbf |
PTS[29..15] | 15 | bslbf |
marker_bit | 1 | bslbf |
PTS[14..0] | 15 | bslbf |
marker_bit | 1 | bslbf |
} | ||
if(PTS_DTS_flags =='11'){ | ||
'0010' | 4 | bslbf |
PTS[32..30] | 3 | bslbf |
marker_bit | 1 | bslbf |
PTS[29..15] | 15 | bslbf |
marker_bit | 1 | bslbf |
PTS[14..0] | 15 | bslbf |
marker_bit | 1 | bslbf |
'0001' | 4 | bslbf |
DTS[32..30] | 3 | bslbf |
marker_bit | 1 | bslbf |
DTS[29..15] | 15 | bslbf |
marker_bit | 1 | bslbf |
DTS[14..0] | 15 | bslbf |
marker_bit | 1 | bslbf |
} | ||
if(ESCR_flag =='1'){ | ||
reserved | 2 | bslbf |
ESCR_base[32..30] | 3 | bslbf |
marker_bit | 1 | bslbf |
ESCR_base[29..15] | 15 | bslbf |
marker_bit | 1 | bslbf |
ESCR_base[14..0] | 15 | bslbf |
marker_bit | 1 | bslbf |
ESCR_extension | 9 | uimsbf |
marker_bit | 1 | bslbf |
} | ||
if(ES_rate_flag =='1'){ | ||
marker_bit | 1 | bslbf |
ES_rate | 22 | uimsbf |
marker_bit | 1 | bslbf |
} | ||
if (DSM_trick_mode_flag =='1'){ | ||
trick_mode_control | 3 | uimsbf |
if ( trick_mode_control = =fast_forward ) { | ||
field_id | 2 | bslbf |
intra_slice_refresh | 1 | bslbf |
frequency_truncation | 2 | bslbf |
} | ||
else if ( trick_mode_control = = slow_motion ) { | ||
rep_cntrl | 5 | uimsbf |
} | ||
else if ( trick_mode _control = = freeze_frame ) { | ||
field_id | 2 | uimsbf |
reserved | 3 | bslbf |
} | ||
else if ( trick_mode _control = = fast_reverse ) { | ||
field_id | 2 | bslbf |
intra_slice_refresh | 1 | bslbf |
frequency_truncation | 2 | bslbf |
else if ( trick_mode_control = = slow_reverse ) { | ||
rep_cntrl | 5 | uimsbf |
} | ||
else | ||
reserved | 5 | bslbf |
} | ||
if ( additional_copy_info_flag = ='1'){ | ||
marker_bit | 1 | bslbf |
additional_copy_info | 7 | bslbf |
} | ||
if (PES_CRC_flag==‘1’){ | ||
previous_PES_packet_CRC | 16 | bslbf |
} | ||
if ( PES_extension_flag =='1') { | ||
PES_private_data_flag | 1 | bslbf |
pack_header_field_flag | 1 | bslbf |
program_packet_sequence_counter_flag | 1 | bslbf |
P-STD_buffer_flag | 1 | bslbf |
reserved | 3 | bslbf |
PES_extension_flag_2 | 1 | bslbf |
if(PES_private_data_flag =='1'){ | ||
PES_private_data | 128 | bslbf |
} | ||
if (pack_header_field_flag == '1'){ | ||
pack_field_length | 8 | uimsbf |
pack_header() | ||
} | ||
if (program_packer_sequence_counter_flag == '1'){ | ||
marker_bit | 1 | bslbf |
program_packet_sequence_counter | 7 | uimsbf |
marker-bit | 1 | bslbf |
MPEG1_MPEG2_indentifier | 1 | bslbf |
original_stuff_length | 6 | uimsbf |
} | ||
if (P-STD_buffer_flag = = '1'({ | ||
'01' | 2 | bslbf |
P-STD_buffer_scale | 1 | bslbf |
P-STD_buffer_size | 13 | uimsbf |
} | ||
if (PES_extension_flag_2 == '1'{ | ||
marker_bit | 1 | bslbf |
PES_extension_field_length | 7 | uimsbf |
for(i=0;i<PES_extension_field_length;i++){ | ||
reserved | 8 | bslbf |
} | ||
} | ||
} | ||
for (i=0;i<N1;i++)} | ||
stuffing_byte | 8 | bslbf |
} | ||
for (i=0;i<N2;i++){ | ||
PES_packet_data_byte | 8 | bslbf |
} | ||
} | ||
else if (stream_id = = program_stream_map | ||
|| stream_id = = private_stream_2 | ||
|| stream_id = = ECM | ||
|| stream_id = = EMM | ||
|| stream_id = = program_stream_directory | ||
|| stream_id = = DSMCC_stream | ||
|| stream_id = = ITU-T Rec. H.222.1 type E stream ){ | ||
for (i=0;i<PES_packet_length;i++){ | ||
PES_packet_data_byte | 8 | bslbf |
} | ||
} | ||
else if (steam_id = = padding_stream){ | ||
for (i=0;i<PES_packet_length;i++){ | ||
padding_byte | 8 | bslbf |
} | ||
} | ||
} |
其中表2-18 Stream_id赋值
stream_id | 注 | 流 编 码 |
1011 1100 | 1 | program_stream_map(0xBC) |
1011 1101 | 2 | private_stream_1(0xBD) |
1011 1110 | padding_stream(0xBE) | |
1011 1111 | 3 | private_stream-2(0xBF) |
110x xxxx | GB/T XXXX.3或GB/T AAAA.3音频流编号xxxx(0xC0~0xDF) | |
1110 xxxx | GB/T XXXX.2或GB/T AAAA.2视频流编号xxxx(0xE0~0xEF) | |
1111 0000 | 3 | ECM_stream(0xF0) |
1111 0001 | 3 | EMM_stream(0xF1) |
1111 0010 | 5 | GB/T XXXX.1附录B或GB/T XXXX.6_DSMCC_stream(0xF2) |
1111 0011 | 2 | ISO/IEC_13522_stream(0xF3) |
1111 0100 | 6 | ITU-T Rec. H.222.1类型A |
1111 0101 | 6 | ITU-T Rec. H.222.1类型B |
1111 0110 | 6 | ITU-T Rec. H.222.1类型C |
1111 0111 | 6 | ITU-T Rec. H.222.1类型D |
1111 1000 | 6 | ITU-T Rec. H.222.1类型E |
1111 1001 | 7 | ancillary_stream(0xF9) |
1111 1010…1111 1110 | 保留数据流 | |
1111 1111 | 4 | program_stream_directory(0xFF) |
符号x表示值'0'或'1'均被允许且可产生相同的流类型。流号码由x的取值决定。 注 1 类型为program_stream_map的PES分组有唯一的语法,在2.5.4.1中作了规定。 2 类型为private_stream_1和ISO/IEC_13352_stream的PES分组与GB/T XXXX.2及GB/T XXXX.3音频流服从相同的PES分组语法。 3 类型为private_stream_2,ECM_stream和EMM_stream的PES分组与private_stream_1相似,除了在PES_packet_length字段后未规定语法。 4 类型为program_stream_directory的PES分组有唯一的语法,在2.5.5中作了规定。 5 类型为DSM_CC_stream的PES分组有唯一的语法,在GB/T XXXX.6中作了规定。 6 stream_id与表2-29中的stream_type 0x09相关联。 7 stream_id仅用于PES分组。PES分组在传输流中携带了来源于节目流或GB/T AAAA.1系统流的数据(参见2.4.3.7)。 |