MPEG-2 TS流结构浅析

一、概述        

        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_prefix24        PES包头起始串,固定为'0000 0000 0000 0000 0000 0001' (0x000001);
stream_id8

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

PES_packet_length16        指定一个PES包中该字段之后的字节数。取0时代表不指定和限制PES包的大小,但只出现在TS包中的PES包的荷载是视频基本流时;
PES_packet_data_byte8        由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 1100program_stream_map
1011 1101private_stream_1
1011 1110padding_stream
1011 1111private_stream_2
110x xxxxISO/IEC 13818-3 or ISO/IEC 11172-3 audio stream number x xxxx
1110 xxxxITU-T Rec. H.262 | ISO/IEC 13818-2 or ISO/IEC 11172-2 video stream number xxxx
1111 0000ECM_stream
1111 0001EMM_stream
1111 0010ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A or ISO/IEC 13818-6_DSMCC_stream
1111 0011ISO/IEC_13522_stream
1111 0100ITU-T Rec. H.222.1 type A
1111 0101ITU-T Rec. H.222.1 type B
1111 0110ITU-T Rec. H.222.1 type C
1111 0111ITU-T Rec. H.222.1 type D
1111 1000ITU-T Rec. H.222.1 type E
1111 1001ancillary_stream
1111 1010 … 1111 1110reserved data stream
1111 1111program_stream_directory
图Figure F-2第二行字段信息
字段大小/Bit        说明
PES_scrambling_control2        PES加扰控制,'00'代表不加扰,'01'、'10'、'11'由用户定义,加扰(可以理解为加密)时,不会对PES包头数据加扰;
PES_priority1        PES报文中负载的优先级,取值为'1'时的优先级高于'0'。多路复用器可以使用PES_priority位对基本流中的数据进行优先级排序,这个字段不应被运输机制改变;
data_alignment_indicator1        数据对齐指示器,置为1时根据数据流对齐描述符进行对齐;
copyright1        版权保护标识,置为1时,使用版权保护标识符对PES包中的基本数据流提供版权保护;
original_or_copy1        置为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_length8        指定PES包头中可选字段(optional fields)和任何填充字节(stuffing bytes)所占用的总字节数;
stuffing_bytem*8        填充字节,用一组或几组固定值('1111 1111')来填充,最多填充32位(即4组)。编码时插入,用于对齐,解码时会被丢弃;
图Figure F-2第三行字段信息
字段大小/Bit说明
PTS33

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

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

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

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

        前三个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_info7        版权信息相关的私有数据;
previous_PES_packet_CRC16        前一个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_data128        存储PES 16字节的私有数据,16byte * 8 = 128 bit;
pack_header_field8        用pack_field_length表示pack_header_field()的字节长度;
program_packet_seq_cntr7        自增的7bit的节目包序列计数器(program packet sequence counter),上溢后从0重新开始循环;
MPEG1_MPEG2_identifier1        取1时表示该PES包携带MPEG-1系统信息,取0时表示携带PS流信息;
original_stuff_length6        表示PES包头中填充的字节数;
P-STD_buffer_scale1        该字段只有在PES包被包含在PS流中时才会定义,用于解释紧跟其后P-STD_buffer_size字段的缩放因子。如果图Figure F-2第一行中的stream_id表示音频流时,该值取0;如果是视频流时,该值取1;其他流取0或1都可以;
P-STD_buffer_size13

        该字段只有在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_length7        指定该字段后面的数据以及任何保留字节的长度(以字节为单位)  ;
PES_extension_field_dataPES_extension_field_length        保留空间

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

/**  数据类型:
*    bslbf:"Bit string, left bit first",位串,左位优先
*    uimsbf:"Unsigned integer",无符号整型
*/
PES_packet() {
	packet_start_code_prefix                               24 uimsbf
	stream_id                                               8 uimsbf
	PES_packet_length                                      16 uimsbf
	if( 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 bslbf
		PES_scrambling_control                              2 bslbf
		PES_priority                                        1 bslbf
		data_alignment_indicator                            1 bslbf
		copyright                                           1 bslbf
		original_or_copy                                    1 bslbf
		PTS_DTS_flags                                       2 bslbf
		ESCR_flag                                           1 bslbf
		ES_rate_flag                                        1 bslbf
		DSM_trick_mode_flag                                 1 bslbf
		additional_copy_info_flag                           1 bslbf
		PES_CRC_flag                                        1 bslbf
		PES_extension_flag                                  1 bslbf
		PES_header_data_length                              8 uimsbf
		if (PTS_DTS_flags =='10' ) {
			'0010'                                          4 bslbf
			PTS [32..30]                                    3 bslbf
			marker_bit                                      1 bslbf
			PTS [29..15]                                   15 bslbf
			marker_bit                                      1 bslbf
			PTS [14..0]                                    15 bslbf
			marker_bit                                      1 bslbf
		}
		if (PTS_DTS_flags ==‘11’ ) {
			'0011'                                          4 bslbf
			PTS [32..30]                                    3 bslbf
			marker_bit                                      1 bslbf
			PTS [29..15]                                   15 bslbf
			marker_bit                                      1 bslbf
			PTS [14..0]                                    15 bslbf
			marker_bit                                      1 bslbf
			'0001'                                          4 bslbf
			DTS [32..30]                                    3 bslbf
			marker_bit                                      1 bslbf
			DTS [29..15]                                   15 bslbf
			marker_bit                                      1 bslbf
			DTS [14..0]                                    15 bslbf
			marker_bit                                      1 bslbf
		}
		if (ESCR_flag=='1') {
			reserved                                        2 bslbf
			ESCR_base[32..30]                               3 bslbf
			marker_bit                                      1 bslbf
			ESCR_base[29..15]                              15 bslbf
			marker_bit                                      1 bslbf
			ESCR_base[14..0]                               15 bslbf
			marker_bit                                      1 bslbf
			ESCR_extension                                  9 uimsbf
			marker_bit                                      1 bslbf
		}
		if (ES_rate_flag == '1') {
			marker_bit                                      1 bslbf
			ES_rate                                        22 uimsbf
			marker_bit                                      1 bslbf
		}
		if (DSM_trick_mode_flag == '1') {
			trick_mode_control                              3 uimsbf
			if ( trick_mode_control == fast_forward ) {
				field_id                                    2 bslbf
				intra_slice_refresh                         1 bslbf
				frequency_truncation                        2 bslbf
			} else if ( trick_mode_control == slow_motion ) {
				rep_cntrl                                   5 uimsbf
			} else if ( trick_mode_control == freeze_frame ) {
				field_id                                    2 uimsbf
				reserved                                    3 bslbf
			} else if ( trick_mode_control == fast_reverse ) {
				field_id                                    2 bslbf
				intra_slice_refresh                         1 bslbf
				frequency_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 bslbf
			additional_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 bslbf
			pack_header_field_flag                          1 bslbf
			program_packet_sequence_counter_flag            1 bslbf
			P-STD_buffer_flag                               1 bslbf
			reserved                                        3 bslbf
			PES_extension_flag_2                            1 bslbf
			if ( PES_private_data_flag == '1' ) {
				PES_private_data                          128 bslbf
			}
			if (pack_header_field_flag == '1' ) {
				pack_field_length                           8 uimsbf
				pack_header()
			}
			if(program_packet_sequence_counter_flag== '1'){
				marker_bit                                  1 bslbf
				program_packet_sequence_counter             7 uimsbf
				marker_bit                                  1 bslbf
				MPEG1_MPEG2_identifier                      1 bslbf
				original_stuff_length                       6 uimsbf
			}
			if ( P-STD_buffer_flag == '1' ) {
				'01'                                        2 bslbf
				P-STD_buffer_scale                          1 bslbf
				P-STD_buffer_size                          13 uimsbf
			}
			if ( PES_extension_flag_2 == '1'){
				marker_bit                                  1 bslbf
				PES_extension_field_length                  7 uimsbf
				for(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 bslbf
    transport_error_indicator          1 bslbf
    payload_unit_start_indicator       1 bslbf
    transport_priority                 1 bslbf
    PID                               13 uimsbf
    transport_scrambling_control       2 bslbf
    adaptation_field_control           2 bslbf
    continuity_counter                 4 uimsbf
    if(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_byte8        固定的8bit数值'0100 0111' (0x47);
transport_error_indicator1        传输错误指示器,取值为1时代表该TS包中至少存在一处无法纠正的bit error,并且取值为1时,不能重置为0,除非错误bit位的值已被修正;
payload_unit_start_indicator1

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

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

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

        空包时,该字段取0;

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

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

        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_control2

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

adaptation_field_control2

        指示该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_counter4

        连续计数器,跟随每个具有相同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 uimsbf
	if(adaptation_field_length >0) {
		discontinuity_indicator                            1 bslbf
		random_access_indicator                            1 bslbf
		elementary_stream_priority_indicator               1 bslbf
		PCR_flag                                           1 bslbf
		OPCR_flag                                          1 bslbf
		splicing_point_flag                                1 bslbf
		transport_private_data_flag                        1 bslbf
		adaptation_field_extension_flag                    1 bslbf
		if(PCR_flag == '1') {
			program_clock_reference_base                  33 uimsbf
			reserved                                       6 bslbf
			program_clock_reference_extension              9 uimsbf
		}
		if(OPCR_flag == '1') {
			original_program_clock_reference_base         33 uimsbf
			reserved                                       6 bslbf
			original_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 uimsbf
			for (i=0; i<transport_private_data_length;i++){
				private_data_byte                          8 bslbf
			}
		}
		if (adaptation_field_extension_flag == '1' ) {
			adaptation_field_extension_length              8 uimsbf
			ltw_flag                                       1 bslbf
			piecewise_rate_flag                            1 bslbf
			seamless_splice_flag                           1 bslbf
			reserved                                       5 bslbf
			if (ltw_flag == '1') {
				ltw_valid_flag                             1 bslbf
				ltw_offset                                15 uimsbf
			}
			if (piecewise_rate_flag == '1') {
				reserved                                   2 bslbf
				piecewise_rate                            22 uimsbf
			}
			if (seamless_splice_flag == '1'){
				splice_type                                4 bslbf
				DTS_next_AU[32..30]                        3 bslbf
				marker_bit                                 1 bslbf
				DTS_next_AU[29..15]                       15 bslbf
				marker_bit                                 1 bslbf
				DTS_next_AU[14..0]                        15 bslbf
				marker_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_length8

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

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

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

discontinuity_indicator1        不连续指示器,指示当前TS数据包的不连续状态,该字段取1时代表不连续状态为真,否则为假;这个不连续包含系统基本时间的不连续(节目切换时出现)和连续计数器continuity_counter的不连续(trick模式会出现)两种;
random_access_indicator1        随机访问指示器,置为1时,当前PID的TS包有效荷载中开始的下一个PES包,应当包含一个视频(或音频)序列头的第一个字节;
elementary_stream_priority_indicator1        基本流优先级指示器,该字段取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最后一位的字节到达系统目标解码器输入处的预期时间,用于时钟同步;
OPCR42

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

splice_countdown8

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

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

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

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

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

transport_private_data_length8        指示其后的private_data字节数,private_data不应该超出adaptation_field范围;
transport_private_datatransport_private_data_length        private_data
adaptation_field_extension_length8        表示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_flag1        该字段取1时,其后面的ltw_offset值才有效,取0时ltw_offset未定义;
ltw_offset15

       合法的时间窗口偏移量 (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_rate22        该字段仅在ltw_flag和ltw_valid_flag都被设置为' 1 '时才定义,其指定一个假设的比特率R,用于定义与此报文后面的PID相同但不包含ltw_offsett字段的传输流的合法时间窗口的结束时间;
splice_type4

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

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

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

DTS_next_AU33

        表示在当前拼接点上未进行拼接(或无缝拼接)的情况下,在拼接点之后第一个访问单元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包结构
HeaderPSI(PAT、PMT、CAT、NIT)Stuffing Bytes
HeaderAdaptation Field
HeaderAdaptation FieldPES_1
Header(PES_2) ~ (PES_N-1)
HeaderAdaptation FieldPES_N
HeaderNull 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 uimsbf
    section_syntax_indicator     1 bslbf
    '0'                          1 bslbf
    reserved                     2 bslbf
    section_length              12 uimsbf
    transport_stream_id         16 uimsbf
    reserved                     2 bslbf
    version_number               5 uimsbf
    current_next_indicator       1 bslbf
    section_number               8 uimsbf
    last_section_number          8 uimsbf
    for (i=0; i<N;i++) {
        program_number          16 uimsbf
        reserved                 3 bslbf
        if(program_number == '0') {
            network_PID         13 uimsbf
        } else {
            program_map_PID     13 uimsbf
        }
    }
    CRC_32                      32 rpchof
}
PAT字段信息
字段大小/Bit        说明
table_id8

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

        '0x00':                节目关联section                

        '0x01':                条件访问section

        '0x02':                节目映射section

        '0x03-0x3F':       预留

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

        '0xFF':                禁用

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

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

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

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

current_next_indicator1

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

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

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

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

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

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

        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 uimsbf
    section_syntax_indicator     1 bslbf
    '0'                          1 bslbf
    reserved                     2 bslbf
    section_length              12 uimsbf
    program_number              16 uimsbf
    reserved                     2 bslbf
    version_number               5 uimsbf
    current_next_indicator       1 bslbf
    section_number               8 uimsbf
    last_section_number          8 uimsbf
    reserved                     3 bslbf
    PCR_PID                     13 uimsbf
    reserved                     4 bslbf
    program_info_length         12 uimsbf
    for (i=0; i<N; i++) {
        descriptor()
    }
    for (i=0;i<N1;i++) {
    stream_type                  8 uimsbf
    reserved                     3 bslbf
    elementary_PID              13 uimsnf
    reserved                     4 bslbf
    ES_info_length              12 uimsbf
        for (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 uimsbf
    section_syntax_indicator     1 bslbf
    '0'                          1 bslbf
    reserved                     2 bslbf
    section_length              12 uimsbf
    reserved                    18 bslbf
    version_number               5 uimsbf
    current_next_indicator       1 bslbf
    section_number               8 uimsbf
    last_section_number          8 uimsbf
    for (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,显示时间戳两个标签。对于视频来说,由于BPTSDTS相等,所以无须在B帧多插入 DTS,而对于IP帧,由于经过复用后数据包的顺序会发生变化,显示前一定要存储在视频解码器的重新排序缓存器中,经过重新排序后再显示,所以一定要同时插入PTSDTS作为重新排序的依据。而对于音频流来说,音频没有双向预测,它的解码时间就是显示时间,即DTS和PTS是相同的,因此只用一个即可,又因为标准中规定不能单单只出现DTS而没有PTS(见上面的表格《图Figure F-2第二行字段信息》),所以音频只采用PTS即可 

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

        DTS(k) =((SystemClockFrequency\times td_{n}(k)) DIV 300) % 2{_{}}^{33}

        PTS(k) =((SystemClockFrequency\times tp_{n}(k)) DIV 300) % 2{_{}}^{33}

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

        27 000 000 - 810 \leq SystemClockFrequency\leq 27 000 000 + 810

        SystemClockFrequency随时间变化的速率 \leq 75 \times 10^{-3} Hz/s

        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)表示该字节到达系统目标解码器输入处的时间:

        PCRBase(i)=((SystemClockFrequency\times t(i)) DIV 300) % 2^{33}

        PCRExt(i)=((SystemClockFrequency\times t(i))DIV1)%300

        PCR(i)=PCRBase(i)\times 300 + PCRExt(i)

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

        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比较,产生解码和显示的同步信号。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MPEG-2是一种广泛应用于数字视频和音频压缩的标准格式。如果你想下载MPEG-2文件,你可以按照以下步骤操作。 首先,你需要确定你要下载的MPEG-2文件的来源。MPEG-2文件通常可以在一些视频共享网站、软件下载网站或者压缩文件分享平台上找到。你可以通过搜索引擎或者直接访问知名的视频分享网站来寻找你所需的MPEG-2文件。 一旦找到了你需要的文件,通常你可以在下载页面找到一个指向下载的按钮或链接。点击该按钮或链接,启动下载过程。在某些情况下,你可能需要先完成一些简单的验证,比如输入验证码,以确保你是合法的用户。 下载开始后,你可以选择将文件保存到你的计算机上的特定位置。你可以使用默认的保存路径,或者根据自己的需求选择其他路径。请注意,一个MPEG-2文件可能会相对较大,因此请确保你有足够的存储空间。 下载的速度取决于你的网络连接速度和服务器的响应速度。如果你的网络连接速度较慢,可能需要等待一段时间才能将文件完全下载到你的计算机上。 一旦下载完成,你可以在你选择的保存路径中找到这个MPEG-2文件。你可以使用适当的播放器软件来播放它,如Windows Media Player、VLC Media Player等。 总的来说,MPEG-2文件下载相对简单,你只需要按照上述步骤找到可靠的来源,点击下载按钮或链接,等待下载完成,然后在你的计算机上找到并播放下载的MPEG-2文件即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值