对PES进行了封装,PES对ES又进行了封装,所以有了两层的封装

PS system map(I帧才会有)

格式描述

开始码 4字节 0x000001BC
PSM长度 2字节
PSM当前可用(1)+PSM版本号(5) 1字节
保留字节 1字节
描述子总长度N 2字节
描述子 N字节
PS所有原始流信息的总字节数 2字节
原始流类型+PES_id+描述子长度+描述子 1+1+2+N2
CRC_32 4个字节

总长度为 :4+PSM长度
注意点:1)PSM长度<1024;2)描述子长度<PSM长度;3)原始流信息
总字节数<PSM长度

​​PS封装H264/H265码流分析_​​PS封装H264/H265码流分析

视频编码格式

0x1b H264

0x24 H265

华为NVR800国标推送PS流分析

​​PS封装H264/H265码流分析_​​PS封装H264/H265码流分析_02

原始码流

00 00 01 bc 00 12 e0 ff 00 00

(00 12代表后面长度是18)(e0 ff是版本号)(00 00说明基本流长度是0)

00 08 24 e0 00 00 90 c0 00 00 00 00 00 00 00 00

(00 08说明程序流映射的所有流信息长度为8)(24代表是H265码流,e0视频)

 01 e0 f0 08 88 80 05 21 00 01 1c 21 00 00 00 01 

40 01 0c 01 ff ff 01 60 00 00 03 00 b0 00 00 03

PSM分析代码

m = *reinterpret_cast<UINT32*>(p);
    if (m == 0xBC010000)
    {
      skip = 4 + 2 + (p[4] << 8) + p[5];
      if (n < skip) return false;
      if (n < (4 + 2 + 6)) return false;

      int nCurBaseCurrenceLen = (p[4+2+2] << 8) + p[4+2+2+1];
      //4(startcode)+2(长度)+2(版本号)+2(基本流长度)+nCurBaseCurrenceLen(跳过基本流长度)+2)
      if (0x1b == p[4 + 2 + 2 + 2 + nCurBaseCurrenceLen + 2])
      {
        printf("H264\n");
      }

      if (0x24 == p[4 + 2 + 2 + 2 + nCurBaseCurrenceLen + 2])
      {
        printf("H265\n");
      }

如下是基本流不为零的情况

​​PS封装H264/H265码流分析_​​PS封装H264/H265码流分析_03

音频数据

封包

RTP + PES header + G711(这个格式按照现场会有改动)

​​PS封装H264/H265码流分析_​​PS封装H264/H265码流分析_04

说明音频包是没有PS头信息的

​​PS封装H264/H265码流分析_​​PS封装H264/H265码流分析_05


视频数据

00 00 01 e0 开头的第九个字节,指定了PES的扩展长度

e0,意思是视频流(e0到ef表示视频);

c0,代表音频流( c0到df表示音频)



wireshark抓包海康PS流

GB28181的PS流完全分析(封装 / 分包发送 / 接收组包 / 解析) - dong1 - 博客园 (cnblogs.com)

PS封装H264码流分析 - 简书 (jianshu.com)

PS流详解(载荷H264)_Spark!的博客-CSDN博客_ps流

https://blog.csdn.net/caixing_java/article/details/79154819