一、概述

MPEG-2是MPEG(Moving Picture Experts Group,运动图像专家组)组织制定的视频和音频有损压缩标准之一,它的正式名称为“基于数字存储媒体运动图像和语音的压缩标准”。MPEG-2标准是在1994年11月为数字电视而提出来的,目前分为9个部分,统称为ISO/IEC13818国际标准。其中第一部分ISO/IEC13818-1是系统(System)部分,该部分解决了将一个或多个基本视频流、音频流以及其他数据流合并成适合存储或传输的单个或多个流的问题。如下图为ISO/IEC13818-1标准中的原图,该系统(System)部分主要描述的是图中竖线右侧的相关内容,而图中左侧视频数据、音频数据的编码压缩分别遵循ISO/IEC 13818-2和ISO/IEC 13818-3中的规范,它们属于该标准的压缩层。

Figure 0-1 -- Simplified overview of ITU-T Rec. H.222.0 | ISO/IEC 13818-1 scope

在上图中左侧,经过量化、采样后的视频数据(如YUV或RGB)、音频数据(如PCM)经过编码压缩后输出音、视频基本流ES。ES是连续码流,为了方便存储与传输,需要将基本的码流ES根据需要分割成长度不等的数据包,并加上包头就形成了打包的基本数据流PES。然后为了适应不同的网络环境和应用场景,会将一路或多路节目的PES流复用、封装打包为单一的节目流PS或传输流TS。

        PS流与TS流的主要特性区别在于:

  • 长度:TS流的包结构是长度是固定的,而PS(Program Stream,节目流)流的包结构是可变长度的,且通常比较长;
  • 抗干扰:TS包由于长度固定,且携带同步信息,在信道环境较为恶劣、传输误码较高时,如果误码破坏了某一TS包的同步信息时,接收机可在固定的位置检测它后面包中的同步信息,从而恢复同步,避免了信息丢失。而PS包由于长度是变化的,一旦某一PS包的同步信息丢失,接收机无法确定下一包的同步位置, 就会造成失步,导致严重的信息丢失;
  • 用途:由于TS流的抗干扰性,使其可用于传输误码较高的网络传输,也可以用于存储,而PS流主要用于DVD;

ES(Elemental Stream,基本流是编码视频数据流或音频数据流,每个ES都由若干个AU(Access Unit,访问单元)组成,每个视频AU或音频AU都是由头部和编码数据两部分组成,1个AU相当于编码的1幅视频图像或1个音频帧。也可以说,每个AU实际上是编码数据流的显示单元,即相当于解码的1幅视频图像或1个音频帧的取样。

二、PES结构与字段分析

PES(Packet Elemental Stream,打包的基本数据流只是担任ES分割、打包、封装为PS/TS中间桥梁的角色,是MPEG-2数据流互换的逻辑结构。在PES层,比较关键的是在PES包头信息中加入PTS(显示时间标签)和DTS(解码时间标签)用于视频、音频同步。

Figure F-2 -- PES packet syntax diagram

如上图是标准文档中PES包结构原图,其中一些字段分行进行说明如下:

图Figure F-2第一行字段信息
字段 大小/Bit         说明
packet_start_code_prefix 24         PES包头起始串,固定为'0000 0000 0000 0000 0000 0001' (0x000001);
stream_id 8

用于指定基本(ES)流的类型和编号,见stream_id取值表;

PES_packet_length 16         指定一个PES包中该字段之后的字节数。取0时代表不指定和限制PES包的大小,但只出现在TS包中的PES包的荷载是视频基本流时;
PES_packet_data_byte 8         由stream_id或PID指定的基本数据流的连续数据的字节数,该字节数N=PES_packet_length - (PES_packet_data_byte字段的第一个字节到PES_packet_length字段最后一个字节之间的字节数),可以理解为图中Optional PES HEADER所占的字节数,遵循字节对齐模式;
Stream_id取值表
stream_id 流编码(注:符号x意味着值'0'或'1'都是允许的,并指向相同的流类型)
1011 1100 program_stream_map
1011 1101 private_stream_1
1011 1110 padding_stream
1011 1111 private_stream_2
110x xxxx ISO/IEC 13818-3 or ISO/IEC 11172-3 audio stream number x xxxx
1110 xxxx ITU-T Rec. H.262 | ISO/IEC 13818-2 or ISO/IEC 11172-2 video stream number xxxx
1111 0000 ECM_stream
1111 0001 EMM_stream
1111 0010 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A or ISO/IEC 13818-6_DSMCC_stream
1111 0011 ISO/IEC_13522_stream
1111 0100 ITU-T Rec. H.222.1 type A
1111 0101 ITU-T Rec. H.222.1 type B
1111 0110 ITU-T Rec. H.222.1 type C
1111 0111 ITU-T Rec. H.222.1 type D
1111 1000 ITU-T Rec. H.222.1 type E
1111 1001 ancillary_stream
1111 1010 … 1111 1110 reserved data stream
1111 1111 program_stream_directory
图Figure F-2第二行字段信息
字段 大小/Bit         说明
PES_scrambling_control 2         PES加扰控制,'00'代表不加扰,'01'、'10'、'11'由用户定义,加扰(可以理解为加密)时,不会对PES包头数据加扰;
PES_priority 1         PES报文中负载的优先级,取值为'1'时的优先级高于'0'。多路复用器可以使用PES_priority位对基本流中的数据进行优先级排序,这个字段不应被运输机制改变;
data_alignment_indicator 1         数据对齐指示器,置为1时根据数据流对齐描述符进行对齐;
copyright 1         版权保护标识,置为1时,使用版权保护标识符对PES包中的基本数据流提供版权保护;
original_or_copy 1         置为1时,代表PES保重的荷载数据时原始数据,否则是copy的内容;

PTS_DTS_flags、

ESCR_flag、

ES_rate_flag、

DSM_trick_mode_flag、

additional_copy_info_flag、

PES_CRC_flag、

PES_extension_flag

8

指示图Figure F-2第三行中各个字段是否会出现的标识,除了PTS_DTS_flags外,其余6个flag都是只占用1bit,取值为1时,代表对应字段会出现,否则不会。

        PTS_DTS_flags占用2bit,‘10’代表仅使用PTS,'11'代表PTS和DTS都使用,'00'代表两个都不使用。'01'标识禁止使用,即不允许只出现DTS;

PES_header_data_length 8         指定PES包头中可选字段(optional fields)和任何填充字节(stuffing bytes)所占用的总字节数;
stuffing_byte m*8         填充字节,用一组或几组固定值('1111 1111')来填充,最多填充32位(即4组)。编码时插入,用于对齐,解码时会被丢弃;
图Figure F-2第三行字段信息
字段 大小/Bit 说明
PTS 33

        显示时间戳(Presentation Time Stamp)表示基本流n的一个显示单元k在系统目标解码器中显示的时间tpn(k),PTS的值以系统时钟频率除以300(即90khz)的周期为单位指定;

DTS 33         解码时间戳(Decoding Time Stamp)表示基本流n的一个访问单元j在系统目标解码器的解码时间tdn(j),DTS的值以系统时钟频率的周期除以300(即90 kHz)为单位指定;
ESCR 42

基本流时钟参考(Elementary Stream Clock Reference)由33bit的ESCR_base和9bit的ESCR_extension两部分构成;

ES_rate 22         ES_rate指定在PES流的情况下,系统目标解码器接收PES包字节的速率,ES_rate在包含它的PES报文中有效,在同一个PES流的后续PES报文中也有效,直到遇到新的ES_rate字段为止;
trick_mode_control 8

前三个bit位指定视频流的trick模式,如果是除视频流以外的其他流,这三个bit位和后面的5个bit位的数值将无意义。如果前三个bit位定义了相关的trick模式,那么紧跟其后的五个bit位则附带对应trick模式的描述信息;

前三个字段的取值意义:

'000':        快进(fast forward);

'001':        慢放(slow motion);

'010':        冻帧(freeze frame);

'011':        快退(fast reverse);

'100':        慢退(slow reverse);

'101'-'111':reserved(预留字段);

additional_copy_info 7         版权信息相关的私有数据;
previous_PES_packet_CRC 16         前一个PES包的CRC值,该值用于网络维护,因为PES包头数据在传输过程中可以被修改,所以该值只对基本流数据字节计算,基本流解码时不会用到该值;

PES_private_data_flag、

pack_header_field_flag、

program_packet_sequence_counter_flag、

P-STD_buffer_flag、

PES_extension_flag_2

5         指定图Figure F-2最后一行各个字段是否会出现的标识,每个flag占用1个bit,取值为1时表示会出现,否则不会;
图Figure F-2最后一行字段信息
字段 大小/Bit         说明
PES_private_data 128         存储PES 16字节的私有数据,16byte * 8 = 128 bit;
pack_header_field 8         用pack_field_length表示pack_header_field()的字节长度;
program_packet_seq_cntr 7         自增的7bit的节目包序列计数器(program packet sequence counter),上溢后从0重新开始循环;
MPEG1_MPEG2_identifier 1         取1时表示该PES包携带MPEG-1系统信息,取0时表示携带PS流信息;
original_stuff_length 6         表示PES包头中填充的字节数;
P-STD_buffer_scale 1         该字段只有在PES包被包含在PS流中时才会定义,用于解释紧跟其后P-STD_buffer_size字段的缩放因子。如果图Figure F-2第一行中的stream_id表示音频流时,该值取0;如果是视频流时,该值取1;其他流取0或1都可以;
P-STD_buffer_size 13

该字段只有在PES包被包含在PS流中时才会定义,其表示P-STD中输入缓冲区BSn的大小,如果P-STD_buffer_scale的值为'0',BSn = P-STD_buffer_scale * 128;如果P-STD_buffer_scale的值为'1',BSn = P-STD_buffer_scale * 1024;

PES_extension_field_length 7         指定该字段后面的数据以及任何保留字节的长度(以字节为单位)  ;
PES_extension_field_data PES_extension_field_length         保留空间

以下是原文档中PES包结构的代码逻辑,读者可以参考上边的字段说明信息和PES包结构图来参考阅读、理解:

/**  数据类型:
*    bslbf:"Bit string, left bit first",位串,左位优先
*    uimsbf:"Unsigned integer",无符号整型
*/
PES_packet() {packet_start_code_prefix                               24 uimsbfstream_id                                               8 uimsbfPES_packet_length                                      16 uimsbfif( stream_id != program_stream_map&& stream_id != padding_stream&& stream_id != private_stream_2&& stream_id != ECM&& stream_id != EMM&& stream_id != program_stream_directory&& stream_id != DSMCC_stream&& stream_id != ITU-T Rec. H.222.1 type E_stream) {'10'                                                2 bslbfPES_scrambling_control                              2 bslbfPES_priority                                        1 bslbfdata_alignment_indicator                            1 bslbfcopyright                                           1 bslbforiginal_or_copy                                    1 bslbfPTS_DTS_flags                                       2 bslbfESCR_flag                                           1 bslbfES_rate_flag                                        1 bslbfDSM_trick_mode_flag                                 1 bslbfadditional_copy_info_flag                           1 bslbfPES_CRC_flag                                        1 bslbfPES_extension_flag                                  1 bslbfPES_header_data_length                              8 uimsbfif (PTS_DTS_flags =='10' ) {'0010'                                          4 bslbfPTS [32..30]                                    3 bslbfmarker_bit                                      1 bslbfPTS [29..15]                                   15 bslbfmarker_bit                                      1 bslbfPTS [14..0]                                    15 bslbfmarker_bit                                      1 bslbf}if (PTS_DTS_flags ==‘11’ ) {'0011'                                          4 bslbfPTS [32..30]                                    3 bslbfmarker_bit                                      1 bslbfPTS [29..15]                                   15 bslbfmarker_bit                                      1 bslbfPTS [14..0]                                    15 bslbfmarker_bit                                      1 bslbf'0001'                                          4 bslbfDTS [32..30]                                    3 bslbfmarker_bit                                      1 bslbfDTS [29..15]                                   15 bslbfmarker_bit                                      1 bslbfDTS [14..0]                                    15 bslbfmarker_bit                                      1 bslbf}if (ESCR_flag=='1') {reserved                                        2 bslbfESCR_base[32..30]                               3 bslbfmarker_bit                                      1 bslbfESCR_base[29..15]                              15 bslbfmarker_bit                                      1 bslbfESCR_base[14..0]                               15 bslbfmarker_bit                                      1 bslbfESCR_extension                                  9 uimsbfmarker_bit                                      1 bslbf}if (ES_rate_flag == '1') {marker_bit                                      1 bslbfES_rate                                        22 uimsbfmarker_bit                                      1 bslbf}if (DSM_trick_mode_flag == '1') {trick_mode_control                              3 uimsbfif ( trick_mode_control == fast_forward ) {field_id                                    2 bslbfintra_slice_refresh                         1 bslbffrequency_truncation                        2 bslbf} else if ( trick_mode_control == slow_motion ) {rep_cntrl                                   5 uimsbf} else if ( trick_mode_control == freeze_frame ) {field_id                                    2 uimsbfreserved                                    3 bslbf} else if ( trick_mode_control == fast_reverse ) {field_id                                    2 bslbfintra_slice_refresh                         1 bslbffrequency_truncation                        2 bslbf} else if ( trick_mode_control == slow_reverse ) {rep_cntrl                                   5 uimsbf} else {reserved                                    5 bslbf}}if ( additional_copy_info_flag == '1' ) {marker_bit                                      1 bslbfadditional_copy_info                            7 bslbf}if ( PES_CRC_flag == '1' ) {previous_PES_packet_CRC                        16 bslbf}if ( PES_extension_flag == '1' ) {PES_private_data_flag                           1 bslbfpack_header_field_flag                          1 bslbfprogram_packet_sequence_counter_flag            1 bslbfP-STD_buffer_flag                               1 bslbfreserved                                        3 bslbfPES_extension_flag_2                            1 bslbfif ( PES_private_data_flag == '1' ) {PES_private_data                          128 bslbf}if (pack_header_field_flag == '1' ) {pack_field_length                           8 uimsbfpack_header()}if(program_packet_sequence_counter_flag== '1'){marker_bit                                  1 bslbfprogram_packet_sequence_counter             7 uimsbfmarker_bit                                  1 bslbfMPEG1_MPEG2_identifier                      1 bslbforiginal_stuff_length                       6 uimsbf}if ( P-STD_buffer_flag == '1' ) {'01'                                        2 bslbfP-STD_buffer_scale                          1 bslbfP-STD_buffer_size                          13 uimsbf}if ( PES_extension_flag_2 == '1'){marker_bit                                  1 bslbfPES_extension_field_length                  7 uimsbffor(i=0;i<PES_extension_field_length;i++) {reserved                                8 bslbf}}}for (i=0;i<N1;i++) {stuffing_byte                                   8 bslbf}for (i=0;i<N2;i++) {PES_packet_data_byte                            8 bslbf}} else if ( stream_id == program_stream_map|| stream_id == private_stream_2|| stream_id == ECM|| stream_id == EMM|| stream_id == program_stream_directory|| stream_id == DSMCC_stream)|| stream_id == ITU-T Rec. H.222.1 type E stream {for ( i=0;i<PES_packet_length;i++) {PES_packet_data_byte                            8 bslbf}} else if ( stream_id == padding_stream) {for ( i=0;i<PES_packet_length;i++) {padding_byte                                    8 bslbf}}
}

三、TS结构与字段分析

Figure F-1 -- Transport Stream syntax diagram

如上图所示是标准文档中的TS(Transport Stream,传输流)包结构原图,从图中第一行可以看到传输流TS中的每个TS包固定大小188字节。一个TS包主要由头部(header)和有效荷载(payload)两部分组成,其中payload承载的数据主体是PES,而头部除了包含前4个固有字节外还可能包含自适应字段(adaptation field)。自适应字段是一个可变长的字段,它可以没有,也可以扩展到整个TS包,其存在与否由adaptation_field_control来控制。那么下面我们依然是分层看一下TS数据包头部的各个字段。第一层的代码逻辑和字段解释按顺序展示如下:

// TS包头部第一行字段代码
transport_packet(){sync_byte                          8 bslbftransport_error_indicator          1 bslbfpayload_unit_start_indicator       1 bslbftransport_priority                 1 bslbfPID                               13 uimsbftransport_scrambling_control       2 bslbfadaptation_field_control           2 bslbfcontinuity_counter                 4 uimsbfif(adaptation_field_control=='10' || adaptation_field_control=='11'){adaptation_field()}if(adaptation_field_control=='01' || adaptation_field_control=='11') {for (i=0;i<N;i++){data_byte                  8 bslbf}}
}
TS包结构Header第一层(即前四个字节)字段信息
字段 大小/Bit         说明
sync_byte 8         固定的8bit数值'0100 0111' (0x47);
transport_error_indicator 1         传输错误指示器,取值为1时代表该TS包中至少存在一处无法纠正的bit error,并且取值为1时,不能重置为0,除非错误bit位的值已被修正;
payload_unit_start_indicator 1

有效荷载单元起始指示器:

如果TS包包含PES包数据的有效荷载部分,那么该字段取1时代表这个TS包的有效负载将从(有且只有)一个PES包的第一个字节开始,取0时将不会有PES包在该TS包中开始;

如果TS包包含PSI数据,那么该字段取1时代表该TS包携带了一个包含PSI section的第一个字节,取0时则代表未携带;

空包时,该字段取0;

transport_priority 1         传输优先级,该字段取“1”时表示该数据包的优先级高于其他PID相同但没有设置为“1”的数据包,传输机制可以使用它来对基本流ES中的数据进行优先级排序。
PID 13

指示数据包荷载中存储的数据类型:

0x0000:                        PAT(Program Association Table,节目关联表);

0x0001:                        CAT(Conditional Access Table,条件访问表);

0x0002-0x000F:           预留(reserved);

0x1FFF:                        空包(Null packet);

0x00010-0x1FFE:        可能被分配为network_PID,Program_map_PID,                                                                  elementary_PID,或其他目的;

transport_scrambling_control 2

传输加扰控制,TS包头和适应字段(adaptation field)不应该加扰,空包时该字段应该取'00'。‘00’代表不加扰,'01'、'10'、'11'意义由用户自定义;

adaptation_field_control 2

指示该TS包头后面是否跟有一个adaptation_field或payload:

'00':                预留(reserved for future use by ISO/IEC);

'01':                没有adaptation_field,只有payload;

'10':                只有adaptation_field,没有payload;

'11':                adaptation_field之后跟随payload;

解码器应该丢弃该字段为'00'的TS数据包,空数据包该值应该取'01';

continuity_counter 4

连续计数器,跟随每个具有相同PID的TS包递增,上溢时从0重新循环,当adaptation_field_control取'00'或'10'时,该字段不递增,空包时,该字段是未定义的;

在TS流中,重复的包可以作为有且只有两个PID相同的连续TS报文发送,重复的这两个包里该字段值应该一样,重复的包里PCR字段除外的其他字段都应该重复;

后续三层自适应字段(adaptation_field)的代码结构和字段解释按顺序展示如下:

/**
*    tcimsbf:'two's complement integer, msb (sign) bit first', 有符号整数
*/
adaptation_field() {adaptation_field_length                                8 uimsbfif(adaptation_field_length >0) {discontinuity_indicator                            1 bslbfrandom_access_indicator                            1 bslbfelementary_stream_priority_indicator               1 bslbfPCR_flag                                           1 bslbfOPCR_flag                                          1 bslbfsplicing_point_flag                                1 bslbftransport_private_data_flag                        1 bslbfadaptation_field_extension_flag                    1 bslbfif(PCR_flag == '1') {program_clock_reference_base                  33 uimsbfreserved                                       6 bslbfprogram_clock_reference_extension              9 uimsbf}if(OPCR_flag == '1') {original_program_clock_reference_base         33 uimsbfreserved                                       6 bslbforiginal_program_clock_reference_extension     9 uimsbf}if (splicing_point_flag == '1') {splice_countdown                               8 tcimsbf}if(transport_private_data_flag == '1') {transport_private_data_length                  8 uimsbffor (i=0; i<transport_private_data_length;i++){private_data_byte                          8 bslbf}}if (adaptation_field_extension_flag == '1' ) {adaptation_field_extension_length              8 uimsbfltw_flag                                       1 bslbfpiecewise_rate_flag                            1 bslbfseamless_splice_flag                           1 bslbfreserved                                       5 bslbfif (ltw_flag == '1') {ltw_valid_flag                             1 bslbfltw_offset                                15 uimsbf}if (piecewise_rate_flag == '1') {reserved                                   2 bslbfpiecewise_rate                            22 uimsbf}if (seamless_splice_flag == '1'){splice_type                                4 bslbfDTS_next_AU[32..30]                        3 bslbfmarker_bit                                 1 bslbfDTS_next_AU[29..15]                       15 bslbfmarker_bit                                 1 bslbfDTS_next_AU[14..0]                        15 bslbfmarker_bit                                 1 bslbf}for ( i=0;i<N;i++) {reserved                                   8 bslbf}}for (i=0;i<N;i++){stuffing_byte                                  8 bslbf}}
}
TS包结构Header第二层字段信息
字段 大小/Bit         说明
adaptation_field_length 8

指定该字段后面adaptation_field中的字节数,该值取0时代表该TS包中插入单个填充字节;

当adaptation_field_control值为'11'时,该字段取值范围是0~182;

当adaptation_field_control值为'10'时,该字段取值183;

discontinuity_indicator 1         不连续指示器,指示当前TS数据包的不连续状态,该字段取1时代表不连续状态为真,否则为假;这个不连续包含系统基本时间的不连续(节目切换时出现)和连续计数器continuity_counter的不连续(trick模式会出现)两种;
random_access_indicator 1         随机访问指示器,置为1时,当前PID的TS包有效荷载中开始的下一个PES包,应当包含一个视频(或音频)序列头的第一个字节;
elementary_stream_priority_indicator 1         基本流优先级指示器,该字段取1时指示在相同PID情况下、当前TS包的有效荷载中基本流数据的优先级高于其他TS包;

PCR_flag、

OPCR_flag、

splicing_point_flag、

transport_private_data_flag、

adaptation_field_extension_flag

5         下一层相关字段是否会出现的标识符,每个flag占1bit,取1时对应字段会出现,取0则不会出现;
TS包结构Header第三层字段信息
字段 大小/Bit         说明
PCR      42         节目时钟参考(Program Clock Reference)由33bit的PCR_Base和9bit的PCR_Extension共同组成,指示包含PCR_Base最后一位的字节到达系统目标解码器输入处的预期时间,用于时钟同步;
OPCR 42

原始节目时钟参考(Original Program Clock Reference)只出现在包含PCR字段的TS包中,用于从另一个TS流重建单个节目TS流,主要目的还是为了纠错PCR。原始节目TS流中设定OPCR的值等于PCR,这样完全重构TS流时,直接将OPCR字段值复制到PCR;

splice_countdown 8

拼接倒计时,一个可正可负的有符号整数,指示相同PID的TS包剩余数量;

该字段值倒数到0时,缓冲区TBn传输后立即进行拼接,当前TS包的有效荷载最后一个字节应该是编码音频或图像的最后一个字节;

如果是视频,结束单元sequence_end_code要么出现在拼接点前的TS包末尾,要么出现在下一个TS包中PES有效荷载的第一个字节;

相同PID情况下,为了拼接点前后尽量与包边缘对齐,拼接点前包末尾可通过填充对齐,拼接点后下一个TS包中PES有效荷载的第一个字节应该是视频或音频流的第一个字节;

该字段取负值-n时,表示要拼接的包是拼接点之后的第n个数据包;

transport_private_data_length 8         指示其后的private_data字节数,private_data不应该超出adaptation_field范围;
transport_private_data transport_private_data_length         private_data
adaptation_field_extension_length 8         表示adaptation_field扩展字段数据在该字段结束后的字节数,如果存在则包括保留字节;

ltw_flag、

piecewise_rate_flag、

seamless_splice_flag

3         标识flag,按顺序分别指示下一层ltw_offset、piecewise_rate、splice_type和DTS_next_AU字段是否会出现;
TS包结构Header第四层字段信息
字段 大小/Bit         说明
ltw_valid_flag 1         该字段取1时,其后面的ltw_offset值才有效,取0时ltw_offset未定义;
ltw_offset 15

合法的时间窗口偏移量 (legal time window_offset)单位是(300/fs)秒,其中fs是该PID所属节目的系统时钟频率;

满足 t1(i) - t(i) = offset;其中i等于当前TS包第一个字节索引,offset是当前字段编码的值,t(i)是T-STD中字节i到达的时间,t1(i)是与此TS流数据包相关联的合法时间窗口时间段内的时间上限;

在合法的时间窗口结束时,同一节目的所有其他TS流数据包都在它们的合法时间窗口结束时传输完毕;

piecewise_rate 22         该字段仅在ltw_flag和ltw_valid_flag都被设置为' 1 '时才定义,其指定一个假设的比特率R,用于定义与此报文后面的PID相同但不包含ltw_offsett字段的传输流的合法时间窗口的结束时间;
splice_type 4

拼接类型,从这个字段第一次出现开始,它将在它所在的PID相同的所有后续TS流数据包中具有相同的值,直到splice_countdown为0的数据包(包括这个数据包);

PID中携带的基本流是音频流,该字段的值应为0000;

如果PID中携带的基本流是视频流,则该字段表示该基本流为拼接目的应遵守的条件,具体条件见标准splice_type字段详细解释;

DTS_next_AU 33

表示在当前拼接点上未进行拼接(或无缝拼接)的情况下,在拼接点之后第一个访问单元AU的解码时间;

从这个字段第一次出现开始,它将在它所在的PID相同的所有后续TS流数据包中具有相同的值,直到splice_countdown为0的数据包(包括这个数据包);

四、PSI

TS流中是多路节目复用的,即多个节目的多个基本流复用后在同一个TS流上传输,那么怎么知道各个节目在传输流中的位置,并区分哪个流属于哪个节目呢?所以就还需要一些附加信息,这就是PSI(Program Specific Information,节目专用信息)。标准中规定了4个PSI,分别是节目关联表PAT、节目映射表PMT、条件访问表CAT、网络信息表NIT。这些表都由一个或多个子表组成,而子表又进一步由一个或多个section组成,在从PSI表到TS包的转换过程中,section起到了中介的作用。不同的表之间可以通过表标识(table_id)进行区分,属于同一个table_id的不同子表一般通过表的扩展标识(table_id_extension)、版本号(version_number)进行区分,对于子表还要加上其它的字段信息条件。其在这些表中的结构如下图:        

PSI包含了进行多路解调和显示节目的必要的和足够的信息,每个PSI表填充一个单独的TS包,并周期性间隔插入到TS流中,它们的PID值是特定的。因为TS包中需要PSI的存在,TS流中的TS包结构可能存在以下可能:

TS流中可能存在的TS包结构
Header PSI(PAT、PMT、CAT、NIT) Stuffing Bytes
Header Adaptation Field
Header Adaptation Field PES_1
Header (PES_2) ~ (PES_N-1)
Header Adaptation Field PES_N
Header Null Package

当TS包中传输的是PSI时,该TS包中Header和PSI表之间会有一个8bit的字段:pointer_field,该字段的取值表示其后面直到TS包中PSI表第一个section的第一个字节的字节数。如果当前TS包中至少有一个PSI表的中的一个section,那么TS包头部的payload_unit_start_indicator字段值应该设置为1,payload部分的第一个字节应该是这个pointer_field字段,以指示PSI表第一个section的起始位置。如果当前TS包中未传输PSI,则TS头部的payload_unit_start_indicator字段值应该设置为0,payload部分就不会有这个pointer_field字段。

4.1、PAT

PAT(Program Association Table,节目关联表)的PID值固定为'0x0000', 每个TS流中可能包含一个或多个PAT,所有的这些PAT共同组成了这个TS流中包含的节目列表。PAT列出了TS流中存在哪些节目流,指定了TS流中每个节目对应PMT所在TS包的PID。PAT的第一条数据指定了NIT所在TS包的PID,其他数据指定了PMT所在TS包的PID,一个TS流含多少个节目就含有多少PMT。节目关联表PAT的结构图、结构代码、字段信息按顺序展示如下:

Figure F-3 -- Program association section diagram
/**
*    rpchof: 'remainder polynomial coefficients, highest order first',剩余的多项式系数,最高位优先
*/
program_association_section() {table_id                     8 uimsbfsection_syntax_indicator     1 bslbf'0'                          1 bslbfreserved                     2 bslbfsection_length              12 uimsbftransport_stream_id         16 uimsbfreserved                     2 bslbfversion_number               5 uimsbfcurrent_next_indicator       1 bslbfsection_number               8 uimsbflast_section_number          8 uimsbffor (i=0; i<N;i++) {program_number          16 uimsbfreserved                 3 bslbfif(program_number == '0') {network_PID         13 uimsbf} else {program_map_PID     13 uimsbf}}CRC_32                      32 rpchof
}
PAT字段信息
字段 大小/Bit         说明
table_id 8

PAT中该字段固定为'0x00',该字段所有取值如下:

'0x00':                节目关联section

'0x01':                条件访问section

'0x02':                节目映射section

'0x03-0x3F':       预留

'0x40-0xFE':       用户私有

'0xFF':                禁用

section_syntax_indicator 1         取值为1
section_length 12         前两个bit取'00',该字段指示当前字段之后(包括CRC)的section字节数,上限不能超过1021;
transport_stream_id 16         作为一个标签来识别该TS流与网络中其他复用,取值由用户自定义;
version_number 5

当前PAT表的版本号,当PAT表中内容发生变化时,版本号+1,在0~31之间循环;

字段current_next_indicator取1时,该字段是当前PAT表的版本号;

字段current_next_indicator取0时,该字段是下一个PAT表的版本号;

current_next_indicator 1

取1时,表示发送的PAT表当前适用;

取0时,表示发送的PAT表不再适用,下一个PAT表才有效;

section_number 8         PAT表中的section编号,第一个出现的应该取'0x00',之后每增加一个,该字段+1;
last_section_number 8         指示PAT表中最后一个section的编号;
program_number 16

节目编号,指定program_map_PID可应用的节目,在一个PAT版本中,该字段不能多次取任何单个值;

该字段取'0x0000'时,之后的PID引用应该是网络PID,否则应该是用户自定义的节目编号;

network_PID 13         该字段可选,指定TS流中网络信息表NIT的PID,取值范围是'0x00010~0x1FFE';
program_map_PID 13

TS流中当前program_number指定了一个节目,该字段指定该节目的节目映射表PMT在TS流中的PID;

该字段取值由用户自定义,取值范围是'0x00010~0x1FFE';

4.2、PMT

解析TS流的时候首先要从PID为0的包里找到节目关联表PAT,因为在PAT中指定了PMT(Program Map Table,节目映射表)所在包的PID。由于PMT中指定了一路节目中各个基本流(视频、音频等)的映射关系,即该节目视频或音频所在TS包的PID,根据指定的PID就可以找到对应的音视频流。总结来说,PMT是用来区分单个节目中的各个基本流,PAT则是区分多路复用中的各个节目。节目映射表的结构图、代码结构、字段解释按顺序解释如下:

Figure F-5 -- TS program map section diagram
TS_program_map_section() {table_id 8 uimsbfsection_syntax_indicator     1 bslbf'0'                          1 bslbfreserved                     2 bslbfsection_length              12 uimsbfprogram_number              16 uimsbfreserved                     2 bslbfversion_number               5 uimsbfcurrent_next_indicator       1 bslbfsection_number               8 uimsbflast_section_number          8 uimsbfreserved                     3 bslbfPCR_PID                     13 uimsbfreserved                     4 bslbfprogram_info_length         12 uimsbffor (i=0; i<N; i++) {descriptor()}for (i=0;i<N1;i++) {stream_type                  8 uimsbfreserved                     3 bslbfelementary_PID              13 uimsnfreserved                     4 bslbfES_info_length              12 uimsbffor (i=0; i<N2; i++) {descriptor()}}CRC_32                      32 rpchof
}

4.3、CAT

CAT(Conditional Access Table,条件访问表)所在TS包的PID值为'0x0001',CAT中列出了条件控制信息(ECM)和条件管理信息(EMM)所在分组的PID,用于节目的加密与解密。CAT的结构图、代码结构按顺序展示如下(相关字段在上面的PAT和PMT中已经出现过了,不需要再解释,参考上面即可):

CA_section() {table_id                     8 uimsbfsection_syntax_indicator     1 bslbf'0'                          1 bslbfreserved                     2 bslbfsection_length              12 uimsbfreserved                    18 bslbfversion_number               5 uimsbfcurrent_next_indicator       1 bslbfsection_number               8 uimsbflast_section_number          8 uimsbffor (i=0; i<N;i++) {descriptor()}CRC_32                      32 rpchof
}

4.4、NIT

NIT(Network Information Table,网络信息表)的PID由PAT中的network_PID字段指定,但NIT的内容是私有的、由用户指定的。它提供TS流的传输信息以及网络自身特性信息,比如网络名称、频道频率、调制特征等信息。

五、同步与时钟恢复

Mpeg-2用于音视频同步以及系统时钟恢复的时间标签分别在ES、PES和TS这3个层次中。在ES层,与同步有关的主要是视频缓冲验证VBV,用于防止解码器的缓冲器出现上溢或者下溢;在PES层,主要是在PES头信息里出现的显示时间标签PTS和解码时间标签DTS;在TS层中,TS头信息包含了节目时钟参考PCR,用于恢复出与编码端一致的系统时序时钟STC。

5.1、ES层

通常的视频压缩算法都采用了可变长编码,编码生成的视频码流是可变码率的。为了能够在实际的固定码率信道或者可变码率信道上传输,需要引入缓冲区缓存视频码流数据。因此,视频编码算法必须提供一个有效的缓冲区管理策略,确保缓冲区不会发生上溢和下溢。编码器通过码率控制算法,调整生成的视频码流满足既定的缓冲区管理策略;同时在码率控制算法中使用自适应量化方法,确保压缩视频的质量。缓冲区管理策略通常都是建立在一个假想的解码器模型上,该解码器模型直接和编码器的输出相连接,缓冲区管理策略通过控制编码视频数据流移入和移出解码器缓冲区的时间以保证解码器模型的数据缓冲区不上溢也不下溢。在Mpeg-2标准中,该解码器模型称为VBV(Video Buffer Verifier,视频缓冲验证),VBV在ES层中定义。

5.2、PES层

在PES层打包的时候,在包的头部插入了DTS(Decoding Time Stamp,解码时间戳)PTS(Presentation Time Stamp,显示时间戳两个标签。对于视频来说,由于B帧PTS和DTS相等,所以无须在B帧多插入 DTS,而对于I帧和P帧,由于经过复用后数据包的顺序会发生变化,显示前一定要存储在视频解码器的重新排序缓存器中,经过重新排序后再显示,所以一定要同时插入PTS和DTS作为重新排序的依据。而对于音频流来说,音频没有双向预测,它的解码时间就是显示时间,即DTS和PTS是相同的,因此只用一个即可,又因为标准中规定不能单单只出现DTS而没有PTS(见上面的表格《图Figure F-2第二行字段信息》),所以音频只采用PTS即可。

DTS和PTS为系统目标解码器分别指定了基本流的预期解码时间和显示时间,它们都是对系统时钟的300分频的时钟计数值,且应该和PCR有相同的起点。本机PCR起到的是连续计数的功能,而DTS和PTS则是指定的一个时间点,可以起到时间定时的作用,相当于闹钟。在PCR值连续的情况下,DTS和PTS等待自身指定的时间点的到来,当PCR的值等于DTS或PTS时,代表着解码器的解码序列或显示序列已经准备好了,可以开始按照指定的时间进行解码或显示动作了。

如上所示的两个公式分别是DTS、PTS值的计算公式,其中分别表示基本流n的显示单元k在系统目标解码器的解码时间和显示时间,DTS和PTS的值是以系统时钟频率除以300(即90khz)的周期为单位。其中的系统时钟频率(SystemClockFrequency)单位是赫兹(Hz),其应该满足如下约束(原始数据编码和实际应用程序中该约束会有更高的精度,高精度的约束会通过系统时钟描述符descriptor传递给解码器):

SystemClockFrequency随时间变化的速率 

5.3、TS层

在Mpeg-2编码器中有一个共同的系统时钟,此时钟用来产生指示音频和视频的正确解码和显示时序的时间标签(DTS、PTS),同时可用来产生在抽样瞬间系统时序时钟的瞬时值(PCR)。标准中规定的系统时钟频率为27MHz,传输流中的PCR,PTS/DTS等均为对该共同系统时钟的采样值。解码端捕获PCR,恢复出本地的STC(System Time Clock,系统时序时钟),将其作为音视频同步控制的基准,并依据PTS和DTS时间标签来安排解码和显示时间表,使音视频分别同步于STC,以实现音视频之间的同步。

PCR(Program Clock Reference,节目时钟参考)由33bit的PCR_base和9bit的PCR_ext共同组成,表示包含PCR_base最后一位的字节到达T-STD(Transport Stream System Target Decoder,系统目标解码器)输入处的预期时间。PCR的取值是对编码器系统时钟脉冲触发的计数器状态抽样而来,其插入到TS包头的自适应区(Adaptation Field)中进行传输,用于解码端的时钟同步。标准规定在原始音频和视频流中,PTS的间隔不能超过0.7s(700ms),而出现在TS包头的PCR间隔不能超过0.1s(100ms)。

PCR_base是由27MHz脉冲经300分频后的90kHz脉冲触发计数器,再对计数器状态进行取样得到的,其作用是在解码器切换节目时,提供对解码器PCR计数器的初始值,让该PCR值与PTS、DTS最大可能地达到相同的时间起点;而PCR_ext是由27MHz脉冲直接触发计数器,再对计数器状态进行取样得到的,其作用是通过解码器端的锁相环电路修正解码器的系统时钟,使其达到和编码器一致的27MHz。如下面所示的三行算式是PCR的计算公式,其中i表示PCR_base字段的最后一个字节,t(i)表示该字节到达系统目标解码器输入处的时间:

由于存在编码端PCR值的不精确或PCR在再复用过程中的修改引起PCR值的不确定性,标准中对于这种不确定性提出了一个PCR值的忍受范围:,该容忍范围不包含网络抖动、传输损伤或其他原因所造成的误差。

5.4、时钟恢复

Figure D-2 -- STC recovery using PLL

当新节目的PCR到达解码器时,需要更新时间基准,此时解码端系统时钟STC被置位。通常第一个从解复用器中解出的PCR被直接装入到如上图所示的左侧作为输入,然后进入右侧的PLL(phase-locked loop,锁相环闭环操作部分。每当一个新节目的PCR到达解码器时,此值被认为是锁相环的参考频率,用来与STC的当前值比较,减法器(Subtractor)产生的差值e经过脉宽调制后被输入低通滤波器并经放大,输出控制信号f,用做电压控制振荡器(VCO)的瞬时频率,VCO输出的频率是在27MHz左右振荡的信号,作为解码器的系统时钟。27MHz时钟经过波形整理后输入到计数器(Counter)中,产生当前的STC值,其33bits的90kHz部分用于和PTS/DTS比较,产生解码和显示的同步信号。

MPEG-2 TS流结构浅析相关推荐

  1. MPEG2 -TS流结构详细浅析

    一.概述 MPEG-2是MPEG(Moving Picture Experts Group,运动图像专家组)组织制定的视频和音频有损压缩标准之一,它的正式名称为"基于数字存储媒体运动图像和语 ...

  2. 对TS流的一些理解TS流的结构

     TS流的结构 TS流由很多个TS包组成,而每个TS包的结构包括:4B的包头,可变长的调整字段,有效净荷(payload).现在分别说一下这三部分的结构和作用. 包头 包头最小为4字节,这四字节分 ...

  3. MPEG TS流简介

    TS简介 MPEG-TS(Transport stream)即Mpeg传输流定义于ITU-T Rec. H.222.0和ISO 13818-1标准中,属于MPEG2的系统层.MPEG2-TS面向的传输 ...

  4. 【mpeg】mpeg1、mpeg2与mpeg4码流结构区别分析

    Date: 2018.10.25 1.参考 http://www.cnblogs.com/CoderTian/p/9246225.html 2.前言     最近在学习和研究MPEG-2标准的过程中, ...

  5. VLC视频播放器原理详细分析含TS流格式分析

    vlc是一个功能强大的玩意,能做很多有意思的事情. 最简单的,从界面打开一个文件播放,也可以在命令行下使用,如 C:\Program Files\VideoLAN\VLC>vlc.exe tes ...

  6. 网络流媒体(四)———TS流

    1. 数字视频压缩MPEG-2标准 MPEG-2是MPEG(Moving Picture Experts Group,运动图像专家组)组织制定的视频和音频有损压缩标准之一,它的正式名称为"基 ...

  7. ffmpeg基础三:H264,从MP4文件获取(av_bsf_get_by_name(“h264_mp4toannexb“))和从TS流获取保存H264

    参考:零声学院 1.流媒体编解码流程 2.编码原理 在⾳视频传输过程中,视频⽂件的传输是⼀个极⼤的问题:⼀段分辨率为19201080,每个像 素点为RGB占⽤3个字节,帧率是25的视频,对于传输带宽的 ...

  8. DVB中TS流数据解析

    引  言 数字生活方式是现代文明的一个重要标志.在与人们工作生活密切相关的电脑.手机和电视三大信息平台中,电脑和手机已实现了数字化和网络化,为人们带来了多姿多彩的资讯和娱乐服务,也为相关企业带来了巨额 ...

  9. TS流解析【PCR】自己的总结

    http://www.cnblogs.com/ztteng/articles/3166025.html http://blog.csdn.net/liuhongxiangm/article/detai ...

  10. TS流概述(ES流-基本流,PES流-打包基本码流,PS流-节目流,TS流-传输流)

    一.TS流概述 ES流(Elementary Stream,基本流):数字电视各组成部分编码后所形成的直接表示基本元素内容的流,包含视频.音频或数据的连续码流. PES流(Paketized Elem ...

最新文章

  1. DBA很忙—MySQL的性能优化及自动化运维实践
  2. Interview:算法岗位面试—2019秋招校园招聘—算法工程师【机器学习、深度学习(偏图像)】秋招感悟:初期阶段的傲娇→中期阶段的紧张→后期阶段的蜕变
  3. php 图片上传 水印,PHP - 图片上传并添加水印
  4. github删除错误的commit并保留之前的提交
  5. 德国留学语言c1,德国留学申请,关于语言
  6. 【解决问题】IDEA配置Tomcat添加Deployment时没有Artifact
  7. Dev-C++ 常用快捷键大全
  8. Java原生序列化、Avro、RPC与Log4j
  9. 机器视觉:自动织物检测系统
  10. 最简单的视音频播放示例8:DirectSound播放PCM
  11. 学习使用Ansj分词工具(一)
  12. HDU1846 Brave Game
  13. 马尔科夫区制转换matlab,马尔科夫区制转移混频向量自回归(MS-MF-VAR)模型及其Gauss实现...
  14. 最新kali之arping
  15. 【STM32训练—SIM900A模块】第二篇、STM32驱动SIM900A发送中文和英文短信
  16. 人脸识别算法DeepFace论文解读
  17. PaddlePaddle深度学习--线性回归
  18. 【Unity3D开发小游戏】《太空射击游戏》Unity开发教程
  19. 大数据006——Zookeeper
  20. mysql中日期相减_非凡教育教你excel怎么计算两个日期天数差和时间差

热门文章

  1. 像中文的罗马音字体复制_罗马音字体大全可复制
  2. 十折交叉验证和混淆矩阵
  3. 罗马音平假名中文可复制_怎么记也记不住? 轻松打好日文50音基础的4个方法...
  4. VBS基础教程(收藏)
  5. 【动手学深度学习】01 Windows下安装环境
  6. 解决Intellij IDEA中找不到汉化包问题
  7. Unity-UI-实现文本框内容自动滚动
  8. 数字图像空间域 频域
  9. 软件测试 | 手把手教你如何使用 ABD调试工具,学不会算我的!
  10. 开源遥感软件(未完待续)