PS流(ISO13818和GB28181)分析
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)。 |
PS流(ISO13818和GB28181)分析相关推荐
- Gb28181之Ps流解析H264
gb28181发送码流选择PS流,PS流在封装H264的数据.本文详细描述如何通过ps流解析H264码流. *************************PSM流解析*************** ...
- 使用ffmpeg来探测GB28181的ps流
GB28181 GB28181 是我国内的标准,现在到2016修订后比较成熟,有很多可取之处,当然,依然是建立在sip协议之上,比起rtmp协议来说,他的优点是复用了rtp协议和sdp协议,这一点很优 ...
- GB28181 PS流传输格式详解
1.PS流传输格式预览 1.视频关键帧的封装 RTP + PS header + PS system header + PS system Map + PES header +h264 data 2. ...
- ps流 转发_VAG.Node: GB28181 信令服务服务,支持PS流到RTMP流的转码和转发功能
VAG.Node GB28181 VAG(Video Agent Gateway) ,主要应用将 GB28181协议 摄像机/硬盘录像机 的PS流(H264/H265)打包推送到RTMP服务器发布. ...
- javaCV简单解析gb28181的rtp ps流,并推流到rtmp服务
本文转自javacv社区三群管理员"赶在时间前面":过去的过去了的博客,感谢大佬倾情贡献,支持javacv社区发展和壮大. 国标gb28181全系列都可以参考过去的过去了的博客,再 ...
- RTP载荷PS流全面分析
1.PS流封包格式 视频关键帧的封装: RTP|PS header|PS system header|PS system Map|PES header|H264 data 视频非关键帧的封装:R ...
- gb28181 ps流文件解析
基础 假定是udp上接收包,端口 5060 ,如果是tcp是要加一些额外得代码, 可以使用jrtplib,或者自己写udpserver 放出udp socket 接收包,当然使用jrtplib等稍微简 ...
- 最简单的h264/h265/svac和g711封装成ps流符合gb28181过检码流要求
最近做国标级联,鼓捣了个简单的ps流封装,做分享做笔记. #include <stdint.h> #include <string> #include <memory.h ...
- gb28181简单解包rtp ps流,推出rtmp(java版基于springboot):六、解包rtp ps流,推出rtmp
解析流程参考 https://blog.csdn.net/chen495810242/article/details/39207305 代码基于github上的修改 https://github.co ...
最新文章
- 51js 的json编辑器
- 用Javascript为DropDownList添加一个Item至定义索引位置
- mysql 查看某个表缓存情况_MySQL 查询缓存 QUERY_CACHE
- 电脑常用音频剪辑软件_如何使用音频剪辑软件,快速剪辑任意格式音频!
- git项目比对_Argo 项目入驻 CNCF,一文解析 Kubernetes 原生工作流
- android 蓝牙通知,android – 蓝牙低能耗通知
- iis8使用url2.0模块实现http跳转到https
- Centos启用rz/sz命令
- 俄罗斯网络间谍被指攻击斯洛伐克政府长达数月
- python气象数据处理与绘图(9)_《利用Python进行数据分析·第2版》第9章 绘图和可视化...
- Red Hat Linux 启动流程图
- Docker零基础入门指南(一):Docker介绍
- 数学建模灵敏度分析是什么?为什么获奖论文基本都有!【科研交流】
- Word文件怎么在方框里面打对勾
- 达梦数据库如何把EXCEL的数据导入到表中?
- java获取汉字拼音_Java获取汉字对应的拼音(全拼或首字母)
- Flutter 全能型选手GetX —— 依赖管理
- 《大明王朝》雪崩前,精英们的狂欢
- 刘韧:和人物共同创作人物故事
- 一键实现前程无忧(51job)简历不停刷新(selenium)