zoukankan      html  css  js  c++  java
  • 音视频处理之PS封装的介绍与使用20180928


    1.PS封装介绍
    MPEG2-PS是一种多路复用数字音频,视频等的封装容器。PS是Program Stream(程序流或节目流)的简称。程序流
    将一个或多个分组但有共同的时间基准的基本数据流(PES)合并成一个整体流。它是为可靠稳定的储存媒介如光盘
    而设计的。
    一般来说,采用MPEG2-HD格式的高清数码摄像机一般以"MPEG2-PS"来保存文件;而采用AVCHD格式的高清摄像机则
    通常以".M2TS"或".MTS"保存文件。

    此处介绍的PS封装方式需要支持MPEG2/MPEG4/H.264等视频和MPEG系列音频,可以被大部分支持ps和相应元素流解码
    的播放器正常播放,支持在多个层次加入私有数据,方便解码,拖动和减少延时。
    具体可参考《ISO.IEC-13818-1》
    1).名词解释
    PES:Packetized Elementary Stream,封装元素流,PS数据的基本单位。
    GOP:Group Of Picture,图像组,一般指I帧及其后面依靠该I帧编码的其他帧。
    PSH:Program Stream pack Header ,是PS包的包头,主要包含系统时间信息。
    //PSM:program stream map,节目流映射提供了关于节目流中原始流以及它们之间相互关系的描述。作为一个PES分组出现。

    2).PS流的基本结构:
    PS GOP|PS GOP|PS GOP
    其中PS GOP包含:
    Video I Frame|Audio Frames|Private Data|...|Video P/B Frame|...
    其中Video I Frame包含:
    PSH|PSM|Video PES|Video PES|...
    其中Video P/B Frame包含:
    PSH|Video PES|Video PES|...
    其中Video PES包含:
    PES Header|PES Payload
    其中Audio Frames包含:
    Audio PES|Audio PES|...

    3).PS 封装
    PS 封装按照ISO.IEC-13818-1标准
    针对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 封装发送就可以了。

    GB28181 对RTP 传输的数据负载类型有规定(参考GB28181 附录B),负载类型中96-127,RFC2250 建议96 表示PS 封装,建议97 为MPEG-4,建议98 为H264
    即我们接收到的RTP 包首先需要判断负载类型,若负载类型为96,则采用PS 解复用,将音视频分开解码。若负载类型为98,直接按照H264 的解码类型解码。
    注:此方法不一定准确,取决于打包格式是否标准

    PS 包中的流类型(stream type)的取值如下:
    a、 MPEG-4 视频流: 0x10;
    b、 H.264 视频流: 0x1B;
    c、 SVAC 视频流: 0x80;
    d、 G.711 音频流: 0x90;
    e、 G.722.1 音频流: 0x92;
    f、 G.723.1 音频流: 0x93;
    g、 G.729 音频流: 0x99;
    h、 SVAC音频流: 0x9B。

    2.PS 封装各个部分详细介绍
    1).PSH PSheader
    PSheader是一个PS包的包头,主要包含系统同步时间。
    I、 Pack start code:包起始码字段,值为0x000001BA的位串,用来标志一个包的开始。
    II、 System clock reference base,system clock reference extenstion:系统时钟参考字段。
    III、 Pack stuffing length :包填充长度字段,3 位整数,规定该字段后填充字节的个数
    如下图1:

    80 60 53 1f 00 94 89 00 00 0000 00 00 00 01 ba €`S..??........?
    7e ff 3e fb 44 01 00 5f 6b f8 00 00 01 e0 14 53 ~.>?D.._k?...?.S
    80 80 05 2f bf cf bed1 1c 42 56 7b 13 58 0a 1e €€./????.BV{.X..
    08 b1 4f 33 69 35 0453 6d 33 a8 04 15 58 d9 21 .?O3i5.Sm3?..X?!
    9741 b9 f1 75 3d 94 2b 1f bc 0b b2 b4 97 bf 93 ?A??u=?+.?.?????

    前12位是RTP Header,这里不再赘述;
    000001ba是包头起始码;
    接下来的9位包括了SCR,SCRE,MUXRate,具体看上图
    最后一位是保留位(0xf8),定义了是否有扩展,二进制如下
    1111 1000
    前5位跳过,后3位指示了扩展长度,这里是0.

    海康定义的PS流子集中,stuffing_byte为6字节,其后4字节存放当前帧的帧号。
    00 00 01 BA 46 9B 4E 47 C4 01 01 47 B3 FE FF FF
    00 03 23 EA(帧的帧号)

    2).PS system header 系统标题
    如下图2:

    Systemheader当且仅当pack是第一个数据包时才存在,即PS包头之后就是系统标题。取值0x000001BB的位串,指出系统标题的开始,暂时不需要处理,读取Header Length直接跳过即可。

    3).PS system Map 节目映射流(PSM)
    Systemheader当且仅当pack是第一个数据包时才存在,即系统标题之后就是节目流映射。取值0x000001BC的位串,指出节目流映射的开始,暂时不需要处理,读取Header Length直接跳过即可。前5字节的结构同系统标题,见上图。

    取一段码流分析系统标题和节目映射流
    00 00 01 ba 45 a9 d4 5c 34 0100 5f 6b f8 00 00 ...?E??4.._k?..
    01 bb 00 0c 80 cc f5 04 e1 7f e0 e0 e8 c0 c0 20 .?..€??.?.?????
    00 00 01 bc 00 1e e1 ff00 00 00 18 1b e0 00 0c ...?..?......?..
    2a 0a 7f ff 00 00 0708 1f fe a0 5a 90 c0 00 00 *........??Z??..
    00 00 00 00 00 00 01 e0 7f e0 80 80 0521 6a 75 .......?.?€€.!ju

    前14个字节是PS包头(注意,没有扩展);
    接下来的00 00 01 bb是系统标题起始码;
    接下来的00 0c说明了系统标题的长度(不包括起始码和长度字节本身);
    接下来的12个字节是系统标题的具体内容,这里不做解析;
    继续看到00 00 01 bc,这是节目映射流起始码;
    紧接着的00 1e同样代表长度;
    跳过e1 ff,基本没用;
    接下来是00 00,自定义的复合流描述的长度,为0表示后面没有否则
    后面跟着就是自定义的描述内容(海康在这里放入了复合流的私有描述:
    两字节复合流描述字(40 0E)+内容(用于放置全局时间,编码设备型号等相关信息)+
    两字节复合流描述字(41 12)(可选)+内容(用于描述设备与通道号),
    所以长度就不是00 00)

    接下来是00 18,代表基本流长度,说明了后面还有24个字节
    接下来的1b,stream type 意思是H264编码格式;
    下一个字节e0,意思是视频流(stream id e0到ef表示视频);
    接下里00 0c,同样代表接下的长度12个字节,表示的是元素流的自定义描述的长度,接下来
    是对应长度的描述内容,这里一般是视频流的描述,以海康的为例,这里是;
    两字节长度(00 10)+两字节视频描述字(42 0E)+内容(用于描述视频编码分辨率、帧率、是否场编码,B帧个数等信息)

    跳过这12个字节,看到90,stream type 这是G.711音频格式;
    下一个字节是c0,代表音频流(stream id c0到df表示音频);
    接下来的00 00同样代表长度,这里是0,表示元素流的自定义(私有)描述长度,如果不为0后面跟着一般是音频流描述,;
    不为0的情况以海康的为例:
    两字节长度(00 0c)+两字节音频描述字(43 0A)+内容(用于描述音频编码的采样率,码率,帧长度,声道数等信息)

    接下来4个字节是CRC,循环冗余校验。
    到这里节目映射流解析完毕。


    PSM节目流映射提供了关于节目流中原始流以及它们之间相互关系的描述:
    I、复合流级私有描述(HIK PS私有),用于放置全局时间,编码设备型号等相关信息
    II、元素流级私有描述(HIK PS私有,一般包含视频描述和音频描述两种),用于视频编码的分辨率、帧率、
    是否场编码、B帧个数,帧间间隔、以及
    音频编码的采样率、码率、帧长度、声道数等相关信息。


    4).PES header PES分组头部
    PES
    Packetised Elementary Stream ,原始流分组。Elementary Stream,原始流,指的是视频或音频压缩编码后产生的比特数据,
    而视频或音频原始流分别打包生成视频PES和音频PES。一个PES分组只包含一种原始流的编码数据。
    如下图3:

    别被这么长的图吓到,其实原理相同,但是,你必须处理其中的每一位。
    1)Packet start code prefix:值为0x000001的位串,它和后面的stream id 构成了标识分组开始的分组起始码,用来标志一个包的开始。
    2)Stream id:在节目流中,它规定了基本流的号码和类型。0x(C0~DF)指音频,0x(E0~EF)为视频,bf 私有,be 填充
    3)PES packet length:16 位字段,指出了PES 分组中跟在该字段后的字节数目。值为0 表示PES 分组长度要么没有规定要么没有限制。这种情况只允许出现在有效负载包含来源于传输流分组中某个视频基本流的字节的PES 分组中。
    4)PTS_DTS:2 位字段。当值为'10'时,PTS 字段应出现在PES 分组标题中;当值为'11'时,PTS 字段和DTS 字段都应出现在PES 分组标题中;当值为'00'时,PTS 字段和DTS 字段都不出现在PES分组标题中。值'01'是不允许的。
    5)ESCR:1位。置'1'时表示ESCR 基础和扩展字段出现在PES 分组标题中;值为'0'表示没有ESCR 字段。
    6)ESrate:1 位。置'1'时表示ES rate 字段出现在PES 分组标题中;值为'0'表示没有ES rate 字段。
    7)DSMtrick mode:1 位。置'1'时表示有8 位特技方式字段;值为'0'表示没有该字段。
    8)Additionalinfo:1 位。附加版权信息标志字段。置'1'时表示有附加拷贝信息字段;值为'0'表示没有该字段。
    9)CRC:1 位。置'1'时表示CRC 字段出现在PES 分组标题中;值为'0'表示没有该字段。
    10)Extensionflag:1 位标志。置'1'时表示PES 分组标题中有扩展字段;值为'0'表示没有该字段。
    PES header data length: 8 位。PES 标题数据长度字段。指出包含在PES 分组标题中的可选字段和任何填充字节所占用的总字节数。该字段之前的字节指出了有无可选字段。

    老规矩,上码流:
    00 00 01 e0 21 33 80 80 05 2b 5f df 5c 95 71 84 ...?!3€€.+_??q?
    aa e4 e9 e9 ec 40 cc17 e0 68 7b 23 f6 89 df 90 ?????@?.?h{#????
    a9d4 be 74 b9 67 ad 34 6d f0 92 0d 5a 48 dd 13 ???t?g?4m??.ZH?.

    00 00 01是起始码;
    e0是视频流;
    21 33 是帧长度;
    接下来的两个80 80见下面的二进制解析;
    下一个字节05指出了可选字段的长度,前一字节指出了有无可选字段;
    接下来的5字节是PTS;
    第7、8字节的二进制如下:
    1000 0000 1000 0000

    按顺序解析:
    第7个字节:
    10 是标志位,必须是10;
    00 是加扰控制字段,‘00’表示没有加密,剩下的01,10,11由用户自定义;
    0 是优先级,1为高,0为低;
    0 是数据对齐指示字段;
    0 是版权字段;
    0 是原始或拷贝字段。置'1'时表示相关PES分组有效负载的内容是原始的;'0'表示内容是一份拷贝;
    第8个字节:
    10 是PTS_DTS字段,这里是10,表示有PTS,没有DTS;
    0 是ESCR标志字段,这里为0,表示没有该段;
    0 是ES速率标志字段,,这里为0,表示没有该段;
    0 是DSM特技方式标志字段,,这里为0,表示没有该段;
    0 是附加版权信息标志字段,,这里为0,表示没有该段;
    0 是PESCRC标志字段,,这里为0,表示没有该段;
    0 是PES扩展标志字段,,这里为0,表示没有该段;

    3.私有信息扩展-IVS举例
    PES Header|Private Data Header|Private data
    其中,
    Private Data Header包括:Private Data Type|Private Data Length
    Private data以IVS Info举例:IVS Info Header|IVS Data

    Private data type的定义如下:
    0x0000 Reserved
    0x0001 Basic Stream Info
    0x0002 Codec Info
    0x0003 IVS Info

    IVS Info Header长度8byte,定义如下:
    0x0000 Reserved
    0x0001 MetaData
    0x0002 EventData
    0x0003 RuleData
    0x0100 Face Identification
    0x0101 Face Identification ATM

  • 相关阅读:
    使用Hugo框架搭建博客的过程
    使用Hugo框架搭建博客的过程
    使用Hugo框架搭建博客的过程
    Windows软件包管理工具:Scoop
    Centos8 安装ifconfig(net-tools.x86_64)
    Centos8 重启网卡方法
    使用Visual Studio 2019--调试汇编32位代码的详细步骤
    linux 三剑客之awk总结
    linux 三剑客之sed常用总结
    mysql数据库的笔记
  • 原文地址:https://www.cnblogs.com/yuweifeng/p/9717354.html
Copyright © 2011-2022 走看看