国标MPEG-PS实时流播放器开发(附例子)

  • Post author:
  • Post category:其他


公安部制定的GBT 28181标准广泛应用于安防领域,这个标准规定了传输的视音频数据要封装成PS流格式。PS格式(原名叫MPEG-PS)在很多领域已经应用了很长一段时间,特别是在安防、广播电视、影音制作等领域,我们熟知的DVD格式(vob)就是用PS封装的。这篇文章我打算给大家讲解怎么实现一个PS流的实时流播放器,通过这篇文章学习,大家就知道一个实时流播放器应该如何设计、如何对PS流做处理等。


一、基本概念


1)ES


ES–Elementary  Streams

是直接从编码器出来的数据流,可以是编码过的视频数据流(H.264,MJPEG等),音频数据流,或其他编码数据流的统称。ES流经过PES打包器之后,被转换成PES包。

ES是只包含一种内容的数据流,如只含视频或只含音频等,打包之后的PES也是只含一种性质的ES,如只含视频ES的PES,只含音频ES的PES等。


2)PES


PES–Packetized  Elementary Streams  (分组的ES),

ES形成的分组称为PES分组,是用来传递ES的一种数据结构。PES流是ES流经过PES打包器处理后形成的数据流,在这个过程中完成了将ES流分组、打包、加入包头信息等操作(对ES流的第一次打包)。PES流的基本单位是PES包。PES包由包头和payload组成。


3)PS


PS–Program Stream(节目流)

PS流由PS包组成,而一个PS包又由若干个PES包组成(到这里,ES经过了两层的封装)。PS包的包头中包含了同步信息与时钟恢复信息。


4)PTS、DTS


PTS–PresentationTime Stamp(显示时间标记)

表示显示单元出现在系统目标解码器(H.264、MPEG4等)的时间。


DTS–Decoding Time Stamp(解码时间标记)

表示将存取单元全部字节从解码缓存器移走的时间。

PTS/DTS是打在PES包的包头里面的,这两个参数是解决音视频同步显示,防止解码器输入缓存上溢或下溢的关键。每一个I(关键帧)、P(预测帧)、B(双向预测 帧)帧的包头都有一个PTS和DTS,但PTS与DTS对于B帧不一样。

PTS/DTS是相对SCR(系统参考)的时间戳,系统时钟频率为90Khz,是以90000为单位的,PTS/DTS到ms的转换公式是PTS/90,转换到秒为PTS/90000。如果没有B帧,PTS和DTS的顺序应该是一致的,如果有B帧,则需要先解码P帧,才能解出来B帧,所以需要PTS和DTS来控制解码时间和显示时间。

根据对前面概念的理解,我总结出以下几点:


1. PS流是一种复合流,可以包含视频流和音频流数据,也可以只包含一种流(视频、音频)的数据;


2. PES流是对原始ES流进行的第一层封装,PES流的基本单位是PES包,由包头和payload组成。


3. ES流即音视频裸流,是从编码器里面出来的原始视频音频流,ES流只包含一种内容,里面是视频或者音频;


4. ES首先需打包成PES包,然后PES加上PS包头,变成了标准的PS流进行存储或传输;


5. PES帧是变长的,每个帧的长度可能不一样;


6. 一般情况下是一帧数据放在一个PES包里面,但是一个PES包的最大长度为65535字节,因此一帧数据有可能被分为多个PES;


7 一个PS包包含若干个PES帧,是由PS头和一个或多个PES帧所组成




8. PS流解码时根据PS包里面的DTS和PTS时间戳确定帧的解码顺序和播放的时间。


9. 解封装PS流是一个封装的逆过程,需要先从原始的PS包里面去掉PS头,分解出PES包,然后去掉PES包头,得到ES裸流。


二、PS流码流结构

I Frame    PS_Header | PS_Map | PES |…….|PES

P Frame    PS_Header | PES | …….|PES

Audio Frame   PS_Header | (PS_Map) | PES  (音频一般封装在一个PES里面即可)

更详细的结构图如下:

这里要特别注意上面的PS System Map,简称PSM。关于PSM的介绍:


(以下这段内容摘录自:博客「SunkingYang」的文章《H264解码之PS流解析》,原文链接:https://blog.csdn.net/y601500359/article/details/97649112)

————————————————


PSM介绍

PSM提供了对PS流中的原始流和他们之间的相互关系的描述信息;PSM是作为一个PES分组出现,当stream_id == 0xBC时,说明此PES包是一个PSM;PSM是紧跟在系统头部后面的;PSM是作为PS包的payload存在的;

PSM由很多字段组成,其字节顺序如下所示:

其中,最关键的是这两个字段:


stream_type字段

:类型字段,占位8bit;表示原始流ES的类型;这个类型只能标志包含在PES包中的ES流类型;值0x05是被禁止的;常见取值类型有:

MPEG-4 视频流:0x10;H.264 视频流:0x1B;G.711 音频流:0x90;

因为PSM只有在关键帧打包的时候,才会存在,所以如果要判断PS打包的流编码类型,就根据这个字段来判断;


elementary_stream_id字段

:流ID字段,占位8bit;表示此ES流所在PES分组包头中的stream_id字段的值;其中0x(C0~DF)指音频,0x(E0~EF)为视频;


PSM只有在关键帧打包的时候,才会存在;IDR包含了SPS,PPS和I帧;每个IDR NALU前一般都会包含SPS、PPS等NALU,因此将SPS、PPS、IDR的NALU 封装为一个PS 包,包括PS头,PS system header,PSM,PES;所以一个IDR NALU PS 包由外到内顺序是:PS header| PS system header | PSM| PES。对于其它非关键帧的PS包,就简单多了,直接加上PS头和PES 头就可以了。顺序为:PS header | PES header | h264raw data。以上是对只有视频video 的情况,如果要把音频Audio也打包进PS 封装,只需将数据加上PES header 放到视频PES 后就可以了。顺序如下:PS 包=PS头|PES(video)|PES(audio);

————————————————


简而言之,播放器需要拿到PSM表的信息,从里面提取出各个Stream的elementary_stream_id,stream_type,这样就知道了哪个流对应哪种编码格式。

三、播放器的功能

1. 播放本地PS文件(这个功能不是这个例子的重点,但是为了便于测试,也加进来了,其实文件播放和实时流播放有些流程是一样的)。

2.  支持从网络接收MPEG-PS流,用UDP方式接收数据,支持接收UDP裸流或带RTP头的MPEG-PS流。

3. 对网络收到的PS流进行保存。

4. 支持从内存中读取MPEG-PS流,支持对流进行解封装(PS-》PES,PES-》ES),最终将流转化成ES流格式。

5. 将ES流送给FFmpeg解码,显示视频。

6. 能够获得PS流中视音频轨的相关信息(视频编码格式、视频宽高、音频编码格式)。

三、播放器设计

播放器的界面如下图:

整个播放器的处理流程图如下:



版权声明:本文为zhoubotong2012原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。