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

Published: 2020-03-24

Tags: gb28181

本文总阅读量

概览

上文记录了如何模拟 SIP Server 和 SIP Client 基于 GB28181 从海康 IPC 摄像头获取 PS 流,本篇文章结合实例,用于记录分析推送过来的 PS 流的内容及结构。

上图为国标 GB28181 关于数据封装说明,能够接入 GB28181 平台的 IPC 符合上述标准。

先行准备

如果已经能够接收到海康的 RTP 流,那么用 wireshark 来看就行,或者下载我本次使用的二进制数据,它就是 wireshark 的 Payload 部分:hikvision-ps -stream.bin

这个是请求视频流后收到的第一条数据,使用二进制编辑器/查看器打开就可以了。

RTP 包

首条数据结构:RTP Header + PS Header + PS System Header + PSM + PESV(Header + Payload)

非首条数据结构:RTP Header + PS Header + PESV(Header + Payload)

关于 RTP Header,参考本文底部【参考1】网址查看。

接下来记录侧重于找到 H264 数据,所以会跳过一些暂时不关心的内容。

PS Header

RTP Payload 中承载的即为 PS 数据,起始的 00 00 01 ba 代表 PS 包的开始。

接下来跳过 9 个字节,暂时不关心它的内容,看第 10 个字节 fe,对应着二进制数据的 1111 1110

它的后三位为 110 为十进制的 6,即接下来的六个字节是扩展内容。

跳过 6 个字节后,遇到了 00 00 01 bb,这时来到了 PS System Header 部分。

PS System Header

System Header 当且仅当数据包为第一个数据包时才存在。

这四个字节代表 System Header 的开始,之后紧邻的 00 12 两个字节表示 System Header 的长度,换算为十进制,即为 18 个字节。

在 System Header 中,可以获取到 PS 中的码流种类(system_id)。

从标准文档截的图也很清晰如何获取 PS System header

PS 数据格式的标准文档可以参考这个 PDF:iso13818-1:2000.pdf

上图中,在 header_length 后共有 6 个字节的数据,之后就是 stream_id 字段。

system_id 值为 e0,跟首图 GB28181 图片中的内容对照可知本 PS 流为视频流。

它是 3 个字节一循环,下一个循环 system_id 字节值为 c0,为音频流,之后又出现了 bd

这个 bd 看一篇文章有提及:

遇到00 00 01 bd的,这个是海康私有流的标识,可以丢弃。丢弃之后就看不到原视频里移动侦测时闪烁的红框。

bf 在这篇文章中有提到,也是海康的私有数据。

PS System header 也可参考这个文档:http://stnsoft.com/DVD/sys_hdr.html

Program Stream Map(PSM)节目映射流

再之后开始解析,又碰到了 00 00 01,这三个字符连在一起可以作为数据端的分隔符。

现在还不知道这块数据是什么类型,读取下一个字节,也就是 bc,二进制的 1011 1100

对照 stream_id 表,第一行的就是本段数据的类型 program_stream_map,即 PSM。

看一下 PSM 的详细结构如下:

同理,再之后的两个字段为 header 的长度,00 5e 十进制的 94。

接下来的 94 个字节也是属于 PSM段的,从 PSM 中可以获取到视频流的具体编码类型。

结合上边的 PSM 结构,自 00 5e 后,跳过两个字段的固定内容,就到了两个字节的 program_stream_info_length,其值为 00 24,说明其后跟着的 descriptor 共占 36 字节。

跳过 36 字节后,接下来的值 00 30 为 element_stream_map_length(基本流映射长度),也就是 48 字节,它表示接下来的 48 字节都是用来描述原始流信息的。

接下来进入了原始流描述的第一次循环,第一个字节 stream_type 值为 1b

根据 GB28181 的定义可知为 H.264 编码,之后的 e0 表示其为视频流。

再之后的 00 1c 代表接下来描述占用 28 字节。

同理,接着循环下去,接下来的字段 90c0,代表着其为 G.711 编码的音频流。

循环两次后,他们占用的字节数已经等于 48,跟 element_stream_map_length 值相等。

所以循环停止,接下来的内容就是 CRC_32,四个字节。

PES 包(Header + Body)

PSM 之后跟着的就是 PES,它分为两个部分,一部分是 Header,一部分是 Payload,Header 用于存储一些描述信息,而 Body Payload 部分为其存储的原始数据,PES 可能有多个。

PES Header

数据开始以 00 00 01 进行分隔,接下来的一个字段决定着数据段的类型,其值为 e0 ,二进制的 1110 0000 ,由之前的表格可知,它是一个视频流。

再之后的 00 2a 表示长度,即其后的 42 字节为数据内容长度。

之后参考 PES packet 结构来解析数据。

由文档可知,当 PES 包的 stream_id 不是几种类型的情况,那么进行解析。

开始时一个固定的两位二进制数 10,跟图片上的 8c(二进制:1000 1100),加上之后的几个数据位,共 8 位一个字节,跳过后,来到了 80(二进制:1000 000),也就是 PTS_DTS_flags = 10

当值为'10'时,PTS 字段应出现在PES 分组标题中;当值为'11'时,PTS 字段和DTS 字段都应出现在PES 分组标题中;当值为'00'时,PTS 字段和 DTS 字段都不出现在 PES 分组标题中。值'01'是不允许的。

也就是 PES Header 中含有 PTS 段,不含有 DTS 段,PES 头主要是通过 PTS 和 DTS 来提供音视频同步的信息。

PES:打包的 ES(Packetized Elementary Streams),是用来传递ES的一种数据结构。是ES流经过 PES打包形成的数据流,即将ES流分组、打包、加入包头信息,是对ES流的第一次打包。

PTS - 显示时间戳(Presentation Time Stamp),用来表示显示单元出现在系统目标解码器的时间。

DTS - 解码时间戳(Decoding Time Stamp),用来表示将存取单元全部字节从解码缓存取走的时间。

PTS/DTS 这两个参数是解决音视频同步显示,防止解码器输入缓存上溢或下溢的关键。每一个 I帧 | P帧 | B帧 的包头都有一个PTS和DTS。

下边是 PES packet 结构的下边部分。

另外注意的一个字段是 PES_header_data_length:它的位置是PES 包长度跳过两个字节后的位置。

它的值为 09,也就是其后字节的长度,通过这个可以分割PES头部内容和数据段,其它字段暂不关心。

上边3个截图,它们都是以 00 00 01 e0 起始的 PES 包,PES 是可以存在多个的,有点不同的是最后一个截图,它的包很大,ff c6 有 65478 个字节,根据长度位置后边的第二个字节 00 (二进制:0000 0000)判断可知,这个 PES 包的 PTS_DTS_flags 值为 0,这个 PES 包不包含 PTS 和 DTS 信息。

再之后的字节 05 为 PES_header_data_length,代表它的 Header 头部数据长度为 5。

PES Body(H264 Payload)

PES Header 其后就是 Payload 数据,00 00 00 01 表示着数据段的开始。

翻看上边 PES 截图,本例中共有四个 PES 包,查看一下它们的数据部分。

00 00 00 01 其后分别跟着 67680665

根据 H264 封装规则,67 代表这一帧为 SPS,68 为 PPS,06 为 SEI Message,65 为 I 帧。

我从海康收到的第一个PS包,到最后解析到 I 帧的时候,至数据末尾肯定不到 1400 个字节,而最后一个 PES 包的长度字段标志为 65478 字节,可以确定的是因为 I 帧过大,进行了分包。

00 好的包即为刚刚分析的包,PS Payload 我这里查看最大是 1400 字节一个包。

pack 00:1400 - 245 = 1155

00 00 00 01 开始到本包的结尾共有 1155 字节

65478 - 8 = 65470 - 1155 = 64315

ff c6 先减去 8 字节的 Header,是 00 00 00 01 开始的 H264 开始的视频字节数,减去 1155 为后续包字节数

因为后续的包有不少包都是这个 I 帧的延续,它们是没有 Header 等信息的,所以一个包 1400 字节都是 H264 数据。

64315 / 1400 = 45.939...

计算可得编号 Seq: 46 的包有本 I 帧的结束。

到 46 号包查看,结尾处找到了下一个视频帧的起始 00 00 01 e0 ~

总结

以上,通过对海康网络摄像头输出的 PS 流结构进行查看,已经清晰的知道了它的结构,虽未详尽了解各个参数,但包含主要的节点,能为后续解码提供先行知识,正如 GB28181 文档所写的,RTP 返回的数据承载着 PS 包,PS 包有 PS Header,系统头,PSM,还有N个 PES(国标中用 PESV 表示视频,PESA 表示音频),知道了 PS 包的结构,就可以用处理程序解析数据,从而把原始流ES(H264)从 PES 包中解析出来。

参考

  1. RTP协议全解析(H264码流和PS流)
  2. ps流格式解析和总结(改了一下排版)
  3. MPEG-PS封装格式
  4. Gb28181之Ps流解析H264
  5. 海康视频录像文件打包格式解析