Skip to content

LV010-PS封装简介

一、概述

1. PS 封装简介

PS 就是 Program Stream 的缩写,有时候也会见到这种名称:MPEG-2 PS(Program Stream),它好像更官方一点吧,都是一个概念。接下来就简答了解一下。

首先看一下 MPEG-2(Moving Picture Experts Group,运动图像专家组),它制定于 1994 年,设计目标是高级工业标准的图象质量以及更高的传输率。定义了一种多路复用数字音频,视频等的封装容器。MPEG-2 中定义了两种复合信息流:传送流(TS)和节目流(PS:Program Stream)。

MPEG2-PS PS 是 Program Stream(程序流或节目流)的简称,是主流的音视频数据封装方式之一,格式公开,可用于存储和网传。程序流将一个或多个分组但有共同的时间基准的基本数据流(PES)合并成一个整体流。它是为可靠稳定的储存媒介如光盘而设计的。广泛应用于 DVD 等多媒体文件的存储环节,PS 主要使用在 GB28181 中。

PS(Program Stream)封装的标准定义在 ISO/IEC 13818-1 标准中。该标准是 MPEG-2 系统层的一部分,详细描述了 MPEG-2 PS 的结构、数据流的组织方式、同步机制、错误检测方法等。

Tips:

ISO/IEC 13818-1 标准:信息技术 — 通用编码 — 第 1 部分:系统(Information technology — Generic coding of moving pictures and associated audio information — Part 1: Systems)

这里有一些文档可以参考,可以下载下来或者在线查看,网上还是比较多的。

道客巴巴上有两篇文档可以参考:

2. 常见术语

  • PS: Program Stream,mpeg2 第一部分定义的节目流。PS 流是一条将若干媒体数据 PES 加上一些辅助信息 PES 组成的无边界流。PS 流主要用于媒体存储或者无损传输,如 TCP。
  • TS: Transport Stream, mpeg2 第一部分定义的传输流。TS 流是将多个 PES 的组合重新切分成固定 188 个字节长度的包,由这些包组成的流。TS 流中也含有一些辅助信息的包。TS 流的设计目标是适应误码环境下的媒体传输。
  • ES:实体流。即编码后的比特流。
  • PES:Packetized Elementary Stream, 封装元素流,PS 数据的基本单位。一帧 ES 可以被打包成一或若干包 PES。PES 存在的目的是,提供一种编码层之上的,用于存储或传输的基本单位。所以 PES 打包需要提供流类别和时间戳等信息。
  • PSM:program stream map (PSM) 节目流映射提供了关于节目流中原始流以及它们之间相互关系的描述。作为一个 PES 分组出现。
  • RTP: Real-time Transport Protocol, 实时传输协议。
  • GOP: Group Of Picture, 图像组,一般指 I 帧及其后面依靠该 I 帧解码的其他帧。
  • NAL: Network Abstraction Layer, 网络适配层,H.264 定义的一个元素结构层次,包括编码数据和参数集信息等。
  • VCL: Video Coding Layer, 视频编码层,H.264 定义的一个元素结构层次,只包括编码数据。
  • IDR: Instantaneous Decoding Refresh,解码器立即重刷新。
  • IVS: Intelligence Video Surveillance,智能视频监控

二、PS 封装格式简介

1. PS 封装格式

PS 流的基本结构如下

image-20251209200306775

一个 PS 流或者文件可以视为多个 PS GOP,每个 GOP 是以 I 帧起始的多帧集合,各 GOP 之间的信息没有相互依赖性,可以进行剪切拼接。一个 PS GOP 由一个或多个 PS 包组成,一个 PS 包内包含一个 PSH(PS Header)和若干个 PES 包,每个 PS GOP 的第一个 PS 包应当在包头 PSH 后立即跟随一个 PSM 包。PSM 包是一种特殊的 PES 包,含有对其他 PES 负载数据类型的描述。PS 包内的其他 PES 的出现顺序和内容没有特殊约束,即一个 PS 包内可以包含交错出现的视频、音频和私有流等 PES 包,各 PES 包根据 PSM 的描述进行拆分。

1.1 PSH

1.1.1 字段说明

PSH (Program Stream pack Header)是 PS 包的包头,主要描述系统参考时钟、码流信息,STUFF 信息等。常用的 PSH 的语法定义如下:

c
pack header() {                                 // No. of bits  Mnemonic unsigned char *buf
	pack start code;                            //     32        bslbf         buf [3:0].8
	'01';                                       //      2        bslbf         buf [4].2
	system_clock_reference_base [32...30];      //      3        bslbf         buf [4].3
	marker_bit;                                 //      1        bslbf         buf [4].1
	system_clock_reference_base [29...15];      //     15        bslbf         buf [4].2+buf [5].8+buf [6].5
	marker_bit;                                 //      1        bslbf         buf [6].1
	system_clock_reference_base [14...0];       //     15        bslbf         buf [6].2+buf [7].8+buf [8].5
	marker_bit;                                 //      1        bslbf         buf [8].1
	system_clock_reference_extension;           //      9        bslbf         buf [8].2+buf [9].7
	marker_bit;                                 //      1        bslbf         buf [9].1
	program_mux_rate;                           //     22        bslbf         buf [11:10].8+buf [12].6
	marker_bit;                                 //      1        bslbf         buf [12].1
	marker_bit;                                 //      1        bslbf         buf [12].1
	reserved;                                   //      5        bslbf         buf [13].5
	pack_stuffing_length;                       //      3        bslbf         buf [13].3
	for (i = 0; i < pack_stuffing_length; i++) {
		stuffing_byte;                          //      8        bslbf         buf [pack_stuffing_length: 14].8
	}
	if (nextbits() == system_header_start_code) {
		system_header ();
	}
}

PSH 中字段的语义定义:

字段 bit 说明
marker_bit 1 其值为‘ 1’ 。
system_clock_reference_base
system_clock_reference_extension
33
9
系统时钟参考( SCR)为分成两部分编码的 42 比特字段。第一部分,system_clock_reference_base 为 33 比特字段,其值由公式 5-1 中给出的 SCR_base (i)给出。第二部分,system_clock_reference_extension,为 9 比特字段,其值由公式 5-2 中给出的 SCR_ext (i)给出。 SCR 指示在节目目标解码器的输入端包含 system_clock_reference_base 最后比特的字节到达的预期时间。
SCR_base(i) = ((system_clock_frequency * t(i))DIV300)%2^33 (5-1)
SCR_ext(i) = ((system_clock_frequency * t(i))DIV300)%300 (5-2)
我们精度要求没有这么高,system_clock_reference_extension 设置为 0 即可。
pack_start_code 32 为 0x000001BA,标识包的起始。
program_mux_rate 22 指示包期间 P-STD 接收节目流的速率,其中该节目流包含在包中。 program_mux_rate 值以 50 字节/秒为度量单位。0 值禁用。
pack_stuffing_length 3 指示跟随此字段的填充字节数。
stuffing_byte 8 此为等于 0xFF 的固定 8 比特值(这里并不是一定要是 0xff,具体含义可以定义,例如可以吧帧号,编码日期等放在这里),可以由编码器插入,例如满足信道的要求。它由解码器丢弃。在每个包头中,应存在不多于 7 个的填充字节。

需要注意的是,PSH 主要包含了系统同步时间,MPEG2 part 1 并没有定义 PSH 与其后数据之间的必然关系。虽然 PSH 是一个 PS 包的包头,但 PSH 本身并不包含 PS 包负载数据的内容和长度信息,这些信息存在于作为 PS 包负载的 PES 包内,一个 PS 包内包含的 PES 包个数、类型和长度没有限制。也就是说,一个 PS 流文件只需要有头上一个 PSH,后面的视频、音频和私有数据 PES 包可以交错排列。但是作为系统同步的需要,PSH 应当以一定的频率在流中出现,I 帧前必须有 PSH,P/B 帧前要有 PSH。

1.1.2 实例

img

1.1.3 解析 PSH
  • 搜索 PSH
c
int PSDEMUX_search_PSH(unsigned char *buf, int len)
{
    int pos = 0;

    for (pos = 0; pos < len - 4; pos++)
    {
        if (buf[pos] == 0x00 && buf[pos + 1] == 0x00 && buf[pos + 2] == 0x01)
        {
            if (buf[pos + 3] == 0xba)
            {
                return pos;
            }
        }
    }

    return NEED_MORE_DATA;
}

1.2 system Header 系统头

PS System Header,节目流系统标题,一般属于 PSH 头部后携带的扩展。

1.2.1 字段说明
c
system_header () {               // No. of bits  Mnemonic 
    system_header_start_code     //     32        bslbf 
    header_length                //     16        uimsbf 
    marker_bit                   //      1        bslbf 
    rate_bound                   //     22        uimsbf 
    marker_bit                   //      1        bslbf 
    audio_bound                  //      6        uimsbf 
    fixed_flag                   //      1        bslbf 
    CSPS_flag                    //      1        bslbf 
    system_audio_lock_flag       //      1        bslbf 
    system_video_lock_flag       //      1        bslbf 
    marker_bit                   //      1        bslbf 
    video_bound                  //      5        uimsbf 
    packet_rate_restriction_flag //      1        bslbf 
    reserved_bits                //      7        bslbf 
    while (nextbits () == '1') {    
        stream_id                //      8        uimsbf 
        if (stream id == '1011 0111') {
            '11'                 //      2        bslbf 
            '0000000'            //      7        bslbf 
            stream id extension  //      7        uimsbf 
            '10110110'           //      8        bslbf 
            '11'                 //      2        bslbf 
            P-STD_buffer_bound_scale //  1        bslbf 
            P-STD_buffer_size_bound  // 13        uimsbf 
        } 
        else { 
            '11'                     //  2        bslbf 
            P-STD_buffer_bound_scale //  1        bslbf 
            P-STD_buffer_size_bound  //  13       uimsbf 
        }  
    } 
}

各个字段说明如下:

字段 bit 说明
system_header_start_code 32 为 0x000001BB,标识系统头的起始。
header_length 16 指示跟随 header_length 字段后的系统头的长度,以字节为单位。
rate_bound 22 rate_bound 为大于或等于在任意节目流包中编码的 program_mux_rate 字段的最大值的整数值。它可供解码器使用来评估它是否有能力解码该完整流。
audio_bound 6 audio_bound 为 0 到 32 闭区间内的一个整数,在解码过程同时被激活的节目流中,它被设置为大于或等于 ISO/IEC 13818-3 和 ISO/IEC 11172-3 音频流最大数的整数值。出于本子节的目的, 规定只要 STD 缓冲器非空或者只要显示单元正在 P-STD 模型中显示, ISO/IEC 13818-3 或 ISO/IEC11172-3 音频流的解码处理就被激活。
fixed_flag 1 置于‘ 1’时指示固定的比特速率操作。置于‘ 0’时指示可变比特速率操作。固定的比特速率操作期间,在该多路复用的 ITU-T H.222.0 建议书 ISO/IEC 13818-1 流中,所有 system_clock_reference 字段中的编码值应依从以下线性方程:
SCR_base(i) = ((c1 × i + c2) DIV 300) % 2^33 (5-3)
SCR_ext(i) = ((c1 × i + c2) DIV 300) % 300 (5-4)
其中: c1 为对所有 i 有效的实值常量, c2 为对所有 i 有效的实值常量, i 为该流中包含任意 system_clock_reference 字段最后比特的字节在 ITU-T H.222.0 建议书 ISO/IEC 13818-1 多路复用流中的索引号。
CSPS_flag 1 其值置于‘ 1’ ,则节目流满足 2.7.9 中规定的限制。
system_audio_lock_flag 1 指示音频采样速率和系统目标解码器的 system_clock_frequency 之间存在特定的常量比率关系。 system_clock_frequency 在子节 2.5.2.1 中定义,音频采样速率在 ISO/IEC 13818-3 中指定。 system_audio_lock_flag 可以设置为‘ 1’ ,仅当对于节目流的所有音频基本流的所有显示单元而言, system_clock_frequency 与实际音频采样速率的比例 SCASR,为常量并等于下表中音频流所指示的标准采样速率所规定的值。

system_video_lock_flag 1 指示视频时间基和系统目标解码器的系统时钟频率之间存在特定的常量比率关系。 system_video_lock_flag 可以设置为‘ 1’ ,仅当对于 ITU-TH.222.0 建议书 ISO/IEC 13818-1 节目的所有视频基本流的所有显示单元而言, system_clock_frequency 与实际视频时间基的比例为常量值。
对于 ISO/IEC 11172-2 和 ITU-T H.262 建议书 ISO/IEC 13818-2 视频流,如果 system_video_lock_flag 设置为 '1', system_clock_frequency 与实际视频帧速率的比例 SCFR,为常量并等于下表中对视频流所指示的标准帧速率所规定的值。
对于 ISO/IEC 14496-2 视频流,如果 system_video_lock_flag 设置为 '1', ISO/IEC 14496-2 视频流的时间基, 由 vop_time_increment_resolution 规定, 锁定为 STC 并精确地等于 N 倍的 system_clock_frequency 除以 K,其中整数 N 和 K 在每个可视目标序列中有固定的值, K 大于或等于 N。
对于 ITU-T H.264 建议书 ISO/IEC 14496-10 视频流, AVC 时间基的频率由 AVC 参数 time_scale 规定。如果对于 AVC 视频流, system_video_lock_flag 设置为 '1' ,则 AVC 时间基的频率锁定为 STC 并精确地等于 N 倍的 system_clock_frequency 除以 K,其中整数 N 和 K 在每个可视目标序列中有固定的值, K 大于或等于 N。


该比例 SCFR 的值是精确的。在标准速率为每秒 23.976、 29.97、 59.94 帧的情况中,实际帧速率与标准速率略有差别。
video_bound 5 在 0 到 16 的闭区间内取值,在解码过程同时被激活的节目流中,它被设置为大于或等于视流的最大数的整数值。对于本小节来说,规定只要 P-STD 模型中的一个缓冲器非空,或者只要显示单元正在 P-STD 模型中显示,视频流的解码处理就被激活。
packet_rate_restriction_flag 1 若 CSPS 标志设置为‘ 1’ ,则 packet_rate_restriction_flag 指示适用于该包速率的那些限制。若 CSPS 标志置于‘ 0’值,则 packet_rate_restriction_flag 的含义未确定。
reserved_bits 7 此 7 比特字段由 ISO/IEC 保留供未来使用。除非由 ITU-T
stream_id 8 指示以下 P-STD_buffer_bound_scale 和 P-STDP-STD_buffer_size_bound 字段所涉及的流的编码与基本流编号。
若 stream_id 等 于 ‘ 1011 1000 ’, 则 跟 随 stream_id 的 P-STD_buffer_bound_scale 和 P-STD_buffer_size_bound 字段涉及节目流中的所有音频流。
若 stream_id 等 于 ‘ 1011 1001 ’, 则 跟 随 stream_id 的 P-STD_buffer_bound_scale 和 P-STD_buffer_size_bound 字段涉及节目流中的所有视频流。
若 stream_id 取任何其他值,则它将是大于或等于‘ 1011 1100’的字节值并将解释为涉及依照表 2-22 的流编码和基本流编号。
节目流中存在的每个基本流应有其 P-STD_buffer_bound_scale 和 P-STD_buffer_size_bound, 在每个系统头中通过此机制确切地一次指定。
P-STD_buffer_bound_scale 1 指 示 用 于 解 释 后 续 P-STD_buffer_size_bound 字段的标度因子。若前导 stream_id 指示音频流,则 P-STD_buffer_bound_scale 必有‘ 0’值。若前导 stream_id 指示视频流,则 P-STD_buffer_bound_scale 必有‘ 1’值。对所有其他流类型,P-STD_buffer_bound_scale 的值可以为‘ 1’或为‘ 0’ 。
P-STD_buffer_size_bound 13 P-STD_buffer_size_bound 为 13 比特无符号整数,规定该值大于或等于节目流中流 n 的所有包上的最大 P-STD 输入缓冲器尺寸 BSn。若 P-STD_buffer_bound_scale 有‘0’值,那么 P-STD_buffer_size_bound 以 128 字节为单位度量该缓冲器尺寸限制。 若 P-STD_buffer_bound_scale 有‘ 1’值,那么 P-STD_buffer_size_bound 以 1024 字节为单位度量该缓冲器尺寸限制。
1.2.2 实例

img

1.3 PSM

节目流映射 PSM(Program stream map) 提供节目流中基本流的描述及其相互关系。作为一个 PES 分组出现。

1.3.1 字段说明
c
program_stream_map() {                // No. of bits  Mnemonic 
    packet_start_code_prefix          //       24      bslbf 
    map_stream_id                     //        8      uimsbf 
    program_stream_map_length         //       16      uimsbf 
    current_next_indicator            //        1      bslbf 
    single_extension_stream_flag      //        1      bslbf 
    reserved                          //        1      bslbf 
    program_stream_map_version        //        5      uimsbf 
    reserved                          //        7      bslbf 
    marker_bit                        //        1      bslbf 
    program_stream_info_length        //       16      uimsbf 
    for (i = 0; i < N; i++) {         
        descriptor()         
    }         
    elementary_stream_map_length      //       16      uimsbf 
    for (i = 0; i < N1; i++) {         
        stream_type                   //        8      uimsbf 
        elementary_stream_id          //        8      uimsbf 
        elementary_stream_info_length //       16      uimsbf 
        if ( elementary_stream_id ==0xFD &&
            single_extension_stream_flag == 0) {
            pseudo_descriptor_tag     //        8      uimsbf
            pseudo_descriptor_length  //        8      uimsbf
            marker_bit                //        1      bslbf
            elementary_stream_id_extension //   7      uimsbf
            for (i =3; i < N2; i++) {
                descriptor()
            }
        }
        else
        {
            for (i = 0; i < N2; i++) {         
                descriptor()         
            }    
        }    
    }          
    CRC_32                            //       32      rpchof 
}

各个字段说明如下:

字段 bit 说明
packet_start_code_prefix 24 同跟随它的 map_stream_id 一起组成包起始码标识包的始端。 packet_start_code_prefix 为 0x000001。
map_stream_id 8 值为 0xBC。
program_stream_map_length 16 指示紧随此字段的 program_stream_map 中的字节总数。此字段的最大值为 1018( 0x3FA)。
current_next_indicator 1 置‘ 1’时指示发送的节目流映射为当前有效。该比特置‘ 0’时,它指示发送的节目流映射尚未有效并且下一个节目流映射表将生效。建议设置为'1'。
single_extension_stream_flag 1 单个扩展流标志,这是一个 1 位字段,当设置为“1”时,表示程序流最多包含一个流 id 等于 0xFD 的基本流。
program_stream_map_version 5 整个节目流映射的版本号。每当节目流映射的定义改变时,该版本号必须增 1 模 32。 current_next_indicator 置为‘ 1’时, program_stream_map_version 应是当前有效的节目流映射的版本。 current_next_indicator 设置为‘ 0’时, program_stream_map_version 应是下一个有效的节目流映射的版本。
program_stream_info_length 16 指示紧随此字段的描述符的总长。
marker_bit 1 1
elementary_stream_map_length 16 指示在此节目流映射中所有基本流信息的以字节为单位的总长度。它包括 stream_type、 elementary_stream_id 以及 elementary_stream_info_length 字段。
stream_type 8 指示依照下表的流类型。 stream_type 字段仅标识 PES 包中包含的基本流。 0x05 赋值被禁用。
elementary_stream_id 8 指示存储此基本流的 PES 包的 PES 包头内的 stream_id 字段的赋值。
elementary_stream_info_length 16 指示紧随此字段的描述符长度,以字节为单位。
CRC_32 32 包含整个节目流映射处理后附件 A 定义的解码器中给出寄存器零输出的 CRC 值。
1.3.2 流类型列表

ISO IEC 13818-1 中介绍 PSM 的 stream_type 的时候,有说明流类型,它在一个表格中,同样在文档内,具体可以看文档。文档中定义了很多,其中 0x80-0xFF 是 User Private,这部分用户可以自定义类型,封装和解封装的时候对应就可以了。这里可以定义音频类型、视频类型以及私有帧类型等,具体看需求。

一般来说标准 H265 定义为 0x24,H264 定义为 0x1B,AAC 音频为 0x0F,私有类型一般多用 0xBD、0xBF。

1.3.3 实例

img

1.4 PES

PES, Packetised Elementray Stream, 原始流分组。Elementary Stream, 原始流,指的是视频或音频压缩编码后产生的比特数据,而视频或音频原始流分别打包生成视频 PES 和音频 PES。一个 PES 分组只包含一个原始流的编码数据。

1.4.1 字段说明

这个有点长,可以直接看文档中的内容,这里只记录一下部分字段的含义:

字段 bit 说明
packet_start_code_prefix 24 同跟随它的 stream_id 一起组成包起始码标识包的始端。 packet_start_code_prefix 为比 0x000001 。
stream_id 8 用来区分 PES 分组负载,例如,0xE0~0xEF 表示负载为视频 PES。stream_id 定义如下(bit 表示):
1110 xxxx(0xE0~0xEF) 视频 PES(我们使用 0xE0)
110x xxxx(0xC0~0xDF) 音频 PES(我们使用 0xC0)
1011 1110(0xBE) 填充 PES(填充数据为 0xff)
1011 1111(0xBF)不含时标数据的私有 PES,不需要与其他流同步时使用 1011 1101(0xBD) 一般表示私有包
PES_packet_length 16 此字段后 PES 分组的字节数,不包含前面的 6(3+1+2)个字节。‘0’表明对 PES 分组长度既没有说明也没有限制,这种情况只有在 PES 分组的有效负载是 TS 流分组中的视频原始流时才允许。
PES_scrambling_control 2 表示 PES 分组有效负载的加密模式,不加密时建议置 0,否则置 01,10 和 11 保留。
PES_priority 1 指示 PES 分组负载的优先级。1 高优先级,0 低优先级。非参考帧(包括 B 帧和,E 帧,P 帧)应置 0,其余帧置 1。
data_alignment_indicator 1 置'1'表明此 PES 分组头部之后是 data_stream_alignment_descriptor 所定义的访问单元数据类型。若为‘0’,则没有定义是否对准。建议当是输入单元的第一个包时置 1,其余置 0。
copyright 1 置'1',表明相应 PES 分组的有效负载中的数据是有版权的,建议置 0。
original_or_copy 1 建议置 1。
PTS_DTS_flag 2 标志 PES 首部含有 PTS, DTS 的状态。‘1x’表明 PES 首部含有 PTS, 若为‘x1’, 则首部含有 DTS。PTS, presentation_time_stamp, DTS, decoding_time_stamp, 建议置‘10’或‘00’。
ESCR_flag 1 置'1'表示 ESCR 的 base 和 extension 字段都在 PES 分组首部出现;建议置 0。
ES_rate_flag 1 置'1'表示 PES 首部有 ES_rate 字段;建议置 0。
DSM_trick_mode_flag 1 置'1'表示 PES 首部有 8bit 的 trick_mode_field;建议置 0。
additional_copy_info_flag 1 置'1'表示有 additional_copy_info 字段;建议置 0。
PES_CRC_flag 1 置'1'表示在 PES 首部分组中有 CRC 字段;建议置 0。
PES_extension_flag 1 置'1'可选字段出现,当需要在每帧添加私有数据时建议置 1,其余情况置 0
PES_header_data_length 8 表示 PES 分组首部中可选字段和填充字节的总字节数。
marker_bit 1 1
PTS 33 Presentation Time Stamp,表示该 PES 所包含的元素流单元的显示时刻。
PES_private_data_flag 1 置'1'表示 PES 分组首部中含有私有数据;当需要在每帧添加私有数据时建议置 1,其余情况置 0
pack_header_field_flag 1 置'1'表示一个 ISO/IEC 11172 组首部或程序流组首部存储在此 PES 分组首部,建议置 0。
program_packet_sequence_counter_flag 1 置'1'表示 PES 分组中有 program_packet_sequence_counter 和 original_stuff_length 字段。建议置 0。
P-STD_buffer_flag 1 置'1'表示 PES 分组首部中有 P-STD_buffer_scale 和 P-STD_buffer_size 字段;建议置 0。
PES_private_data 128 128bit 用户私有数据,见可用扩展字段说明。
PES_extension_flag2 1 置'1'表示出现 PES_extension_field; 建议置 0。
stuffing_byte 8 填充字节,根据标准编码其应当在此填入 0xff,解码器端应当将这些字节抛弃。

PES 头信息中,用两个字节标识当前 PES 包长度,最大可以表示 64K,超出这个大小无法表示。PES 头信息中还会描述当前帧的时间戳(其中音频帧通常不加时间戳)。

需要注意的是,当对原始流进行 PES 分组,尤其是需要将一帧信息断开分成多个 PES 分组时,从第二个分组开始不需要 PTS,PES_header_data_length 和它前面的一个字节又都为 0x00,很可能与后面断开的数据组合形成 0x00 00 01 等类似的伪起始码或关键字,令解码端在收到流不完整时产生误判,因此填充字节 stuffing_byte 至少必须加入 1 byte 以确保这种误判不会发生。

Tips:PES Header 长度由于是可变长度,可以简单用以下方法确认:PES Header 长度 = 基本长度(9 字节)+扩展长度(uface PS 封装带 PTS 是 7 字节,不带 PTS 是 3 个字节);基本长度(8 字节的长度+1 字节的 PES 扩展头字节数),扩展长度填充规则是,至少 2 字节,PES Header 长度保持 4 字节对齐,PES 分包后,只有首包含 PTS。

1.4.2 实例

暂无。

2. H264 流的 PS 封装

(1)一个网络抽象单元(NALU)视为一个处理单元,编码器一帧编码后输出可能是多个处理单元;

(2)除 B 帧外的帧输出的多个单元封装时应当在第一个单元头部添加 PSH;

(3)当一个 NALU 单元长度超过系统 PES 包长限制时,可以将该 NALU 分割成多个 PES 包,但每个 PES 包内不应当包含多于 1 个 NALU 的数据;

(4)每个帧的第一个处理单元所封装成的第一个 PES 包包头应当带有 PTS;

(5)每个 I 帧封装时应当在 PSH 之后添加 PSM;

(6)当元素流的基本特性(编码格式,帧率,分辨率,场编码等)发生变化时,变化后的第一帧封装时必须在 PSH 之后添加 PSM;

2.1 典型的 H.264 I 帧 PS 包

image-20251209200608466

2.2 典型的 H.264 P/B 帧 PS 包

image-20251209200623429

3. 音频元素流封装规则

(1)在音视频同步时序条件允许的情况下,连续的一个或多个音频帧可以合并,每帧视为一个处理单元;

(2)当音频帧长度不大于 PES 包负载或网络传输单元所能承受的最大长度时,建议将每个音频帧封装成一个单独的 PES 包;

(3)每次处理的第一个音频帧所形成的第一个 PES 包头应当带有 PTS,其余音频帧所形成的第一个 PES 包头建议带有 PTS;

(4)当系统不包含视频流时,PSH 在流中出现的间隔应当小于 1 秒,PSM 的出现间隔应当小于 4 秒;当音频参数(码率,采样率,声道数等)发生变化时,必须在变化后立即出现 PSH 和 PSM。

image-20251209200632861

参考资料

海康视频录像文件打包格式解析 - 黑车司机 - 博客园

GB/T28181 数据流分析学习笔记 1:PS 数据格式解析_yjkhtddx ps-CSDN 博客

PS 流包格式之 PS/SYS/PSM/PES 头 - 简书

PS 流及其封装 - shunxiang - 博客园

H264 码流中 SPS PPS 详解_h264 sps pps-CSDN 博客

海康威视 PS 封装的码流用 ffmpeg 读取视频流(HEVC/H265) - 溪溯 P - 博客园