gb28181发送码流选择PS流,PS流在封装H264的数据。本文详细描述如何通过ps流解析H264码流。

*************************PSM流解析**************************************************

先研究下PSM(节目流映射),PSM头定义如下:

这里找了一个标准的PS流里面的PSM数据进行研究分析:

packet_start_code_prefix—24bit :00 00 01

map_stream_id-8bit:BC

program_stream_map_length-16bit:00 5A  ----->90 此字段含义为紧随此字段还有90个字节,通过计算每行16*5+10=90,正确

current_next_indicator—1bit:--->1    置于1时指示发送的节目流映射为当前有效。置于0它指示发送的节目流映射尚未有效并且下一个节目流映射表将生效

reserved-2bit:---->11    预留位

program_stream_map_version-5bit:--00000    整个节目流映射的版本号,每当节目流映射的定义改变时,该版本号必须增

1模32,current_next_indicator置为1时,为当前有效的节目流映射的版本,当current_next_indicator置为0时,是下一个有效的节目流映射的版本。
reserved-7bit--->1111111
marker_bit-1bit--->1

program_stream_info_length-16bit--->0x00 0x24--->36   指示紧随此字段的描述符的总长为36个字节,

剩下的36个字节为:

for (i = 0; i < N; i++) {
descriptor()
}                

elementary_stream_map_length-16bit -->0x00 0x2C--->44  指示在此节目流映射中所有基本流信息的以字节为单位的总长度。

剩下44个字节为:

for (i = 0; i < N1; i++) {

stream_type

elementary_stream_id

elementary_stream_info_length

for (i = 0; i < N2; i++) {

descriptor()}

}

stream_type_8bit--->1B  含义如下:

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。

elementary_stream_id-8bit--->E0     指示存储此基本流的PES包的PES包头内stream_id 字段的赋值elementary_stream_info_length-16bit--->00  10--->16  指示紧随此字段的描述符长度为16个字节

这里一共花掉了1+1+2+16 =20个字节 而实际长度为44个字节 剩下的24个字节为什么呢?我们再分析剩下的24个字节。

stream_type_8bit--->90  说明音频为G711

elementary_stream_id-8bit--->C0 说明为音频

elementary_stream_info_length-16bit--->00  0c--->12  指示紧随此字段的描述符长度为12个字节

这里一共花掉了1+1+2+12 = 14个字节 而剩下的24-14=10个字节

剩下的这10个字节,表示无法理解。由于这段视频取的是海康的私有码流,说明这段码流加了私有信息。这里从新取了一段公安一所的测试的PS流进行分析,如下:

这段是符合上述标准的。

CRC_32--->0x00 00 00 00

**************************************************Pack_header流解析**************************************************

***************************我是分割线*********************************

下面主要讲解如何把PS流解析出裸H264数据

一个完整的ps流一般结构包括Pack_header +System_header+Program_stream_map+PES_pakcet(N个) 其中PES_pakcet可能有N个

可以通过头的标识来判断当前的类型:

        public static readonly byte[] Pack_start_code = { 0x00, 0x00, 0x01, 0xBA };public static readonly byte[] System_header_start_code = { 0x00, 0x00, 0x01, 0xBB };public static readonly byte[] Pakcet_start_code_prefix = { 0x00, 0x00, 0x01 };public static readonly byte Psm_map_stream_id = 0xBC;public static readonly byte Pes_map_stream_id_video = 0xE0;public static readonly byte Pes_map_stream_id_audio = 0xC0;

我的思路是先解析Pack_header 在逐个解析System_header/Program_stream_map/PES_pakcet  到了PES_pakcet时候,要注意下面一包可能是Pack_header 也可能是PES_pakcet 。代码如下:

static bool ParsingPs(){//find  Pack_headerif (m_Buf.Count<4){return false;}if(packState == PackState.PES_pakcet){//find Pack_headerif(m_Buf[0] == PsDefine.Pack_start_code[0] && m_Buf[0 + 1] == PsDefine.Pack_start_code[1] &&m_Buf[0 + 2] == PsDefine.Pack_start_code[2] && m_Buf[0 + 3] == PsDefine.Pack_start_code[3]){packState = PackState.Adding;}}if (packState == PackState.Adding){bool bFinePacketHead = false;for(int i =0;i<m_Buf.Count-4;i++){if(m_Buf[i] == PsDefine.Pack_start_code[0] && m_Buf[i+1] == PsDefine.Pack_start_code[1]&& m_Buf[i+2] == PsDefine.Pack_start_code[2] && m_Buf[i+3] == PsDefine.Pack_start_code[3]){bFinePacketHead = true;if (i>0){m_Buf.RemoveRange(0, i);}break;}}if(bFinePacketHead){Pack_header pack_Header = new Pack_header();if (!pack_Header.ParsingPackheader(m_Buf.ToArray())){return false;}if(m_Buf.Count> pack_Header.Pack_headerCount + pack_Header.Pack_stuffing_lenth_3){m_Buf.RemoveRange(0, pack_Header.Pack_headerCount + pack_Header.Pack_stuffing_lenth_3);packState = PackState.Pack_header;}else{return false;}}}if (packState == PackState.Pack_header){//find System_headerif (m_Buf.Count < 4){return false;}{if (m_Buf[0] == PsDefine.System_header_start_code[0] && m_Buf[0 + 1] == PsDefine.System_header_start_code[1] &&m_Buf[0 + 2] == PsDefine.System_header_start_code[2] && m_Buf[0 + 3] == PsDefine.System_header_start_code[3]){System_header system_Header = new System_header();if (!system_Header.ParsingSystem_header(m_Buf.ToArray())){return false;}if(m_Buf.Count> system_Header.Header_lenth+6){m_Buf.RemoveRange(0, system_Header.Header_lenth + 6);}else{return false;}}}//find Program_stream_mapif (m_Buf.Count < 4){return false;}{if(m_Buf[0] == PsDefine.Pakcet_start_code_prefix[0] &&m_Buf[0+1] == PsDefine.Pakcet_start_code_prefix[1] &&m_Buf[0+2] == PsDefine.Pakcet_start_code_prefix[2] &&m_Buf[0+3] == PsDefine.Psm_map_stream_id){Program_stream_map program_Stream_Map = new Program_stream_map();if(!program_Stream_Map.ParsingProgram_stream_map(m_Buf.ToArray())){return false;}if (m_Buf.Count > program_Stream_Map.Program_steam_map_lenth_16 + 6){m_Buf.RemoveRange(0, program_Stream_Map.Program_steam_map_lenth_16 + 6);}else{return false;}}}packState = PackState.PES_pakcet;}//find PES_pakcetif (m_Buf.Count < 4){return false;}if(m_Buf[0] == PsDefine.Pakcet_start_code_prefix[0] &&m_Buf[1]== PsDefine.Pakcet_start_code_prefix[1] &&m_Buf[2] == PsDefine.Pakcet_start_code_prefix[2]){PES_pakcet pES_Pakcet = new PES_pakcet();if(!pES_Pakcet.ParsingPES_pakcet(m_Buf.ToArray())){return false;}if(m_Buf.Count < pES_Pakcet.PES_pakcet_lenth_16+6){return false;}byte[] bPes = new byte[pES_Pakcet.PES_pakcet_lenth_16 + 6];m_Buf.CopyTo(0, bPes, 0, bPes.Length);m_Buf.RemoveRange(0,bPes.Length);if(bPes[3] == PsDefine.Pes_map_stream_id_video){if(pES_Pakcet.PES_pakcet_lenth_16>0){m_h264File.Write(bPes, 9 + bPes[8], bPes.Length - 9 - bPes[8]);m_h264File.Flush();}}else if(bPes[3] == PsDefine.Pes_map_stream_id_audio){}return true;}else{packState = PackState.Adding;return false;}}

为了便于大家学习和交流,用vs2017开发,C#语言实现的ps解析为H264资源如下,欢迎大家提问:

ps解析出H264

Gb28181之Ps流解析H264相关推荐

  1. java ps h264_从海康28181的PS流解析H264的补充

    前文 <简单解析海康PS流获取H264> 针对海康摄像头的PS流解析做了简单处理,基本逻辑是正确的,但最近几个摄像头出现了一些奇怪的问题,需要针对相关现象进行查询. RTP传输层 项目中为 ...

  2. GB28181学习之路——PS流解析H264

    磕磕绊绊的做了出来,也算为自己留个资料吧.先讲理论再上代码.挑些重点讲. 1. 首先就是获取到 rtp 包,rtp包的结构是:rtp包头+payload,payload就是我们要的ps包,rtp包头的 ...

  3. 使用ffmpeg来探测GB28181的ps流

    GB28181 GB28181 是我国内的标准,现在到2016修订后比较成熟,有很多可取之处,当然,依然是建立在sip协议之上,比起rtmp协议来说,他的优点是复用了rtp协议和sdp协议,这一点很优 ...

  4. 最简单的GB28181视频PS流播放器。

    一 从PS流中提取h264和aac. 移步:https://blog.csdn.net/qq_39805297/article/details/107083322 二 基于ffmpeg解码h264获取 ...

  5. 海康摄像头PS流格式解析(RTP/PS/H264)

    海康威视视频录像以PS格式打包,解析的过程按照PS包-->system header--->program stream map--->音视频PES包一路下来,海康在包中自定义了一些 ...

  6. RTP协议全解析(H264码流和PS流

    写在前面:RTP的解析,网上找了很多资料,但是都不全,所以我力图整理出一个比较全面的解析, 其中借鉴了很多文章,我都列在了文章最后,在此表示感谢. 互联网的发展离不开大家的无私奉献,我决定从我做起,希 ...

  7. RTP协议全解(H264码流和PS流)

    1 视频编码的原理 1.1 一个图像或者一个视频序列进行压缩,产生码流. 对图像的处理即是:帧内预测编码 其预测值P,是由已编码的图像做参考,经运动补偿得到的.预测图像P和当前帧Fn相减,得到两图像的 ...

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

    写在前面:RTP的解析,网上找了很多资料,但是都不全,所以我力图整理出一个比较全面的解析, 其中借鉴了很多文章,我都列在了文章最后,在此表示感谢. 互联网的发展离不开大家的无私奉献,我决定从我做起,希 ...

  9. RTP协议全解(H264码流和PS流)——看完这篇可以毕业

    http://blog.csdn.net/bytxl/article/details/50395427 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 1 视频编码的原理 1. ...

最新文章

  1. mysql执行ref_ref:mysql命令大全
  2. 网站长尾词布置需要注意什么事项?
  3. 系统集成项目管理工程师考试准备
  4. Linux下全局安装composer方法
  5. 命令注入_命令注入绕过方式总结
  6. 技术干货 | 源码解析 Github 上 14.1k Star 的 RocketMQ
  7. Python官方文档学习心得(第六篇)
  8. Mysql-5.5.3 主从同步不支持master-host问题的解决办法
  9. 现在农村有比较多老了的丝瓜,这些老了的丝瓜有什么作用吗?
  10. 安装CentOS的注意事项
  11. java泛型详解_Java泛型详解(透彻)
  12. 众智动力java_Java泛型简明教程
  13. 解决windows7“您可能没有权限使用网络资源”的方法
  14. 分析公司盈利能力的方法
  15. 少年中国说 梁启超
  16. 达梦DM单机部署以及日常运维管理
  17. 绝密计划:我在阿里打黑工
  18. Centos7,离线yum源下载,搭建
  19. 干货教程:数据结构与算法之美
  20. 树莓派:基于flask的远程视频监控

热门文章

  1. UiModeManager设置夜间模式和行车模式
  2. [转载]遗留系统中的RUBY中文解决方案
  3. nativefier - 把网页生成桌面应用程序
  4. htc服务器更新系统,HTC U11刷机教程_HTC U11卡刷官方ruu升级更新系统
  5. python TCP通信,主从服务设计(通过json进行数据通信)
  6. 运维安全加固规范_DBA如何巧用“三十六计”保障数据库安全?
  7. 平衡二叉树删除_自平衡二叉树实现及时间复杂度分析
  8. 果园机器人的写作思路_《果园机器人》三年级教学设计
  9. python怎么设置回文数_Python中的回文数
  10. Ipython Notebook ipynb文件转化为Python脚本