云晁每周小课堂--认识TS流
TS流简介
MPEG-TS(Transport stream)即Mpeg传输流定义于ITU-T Rec. H.222.0和ISO 13818-1标准中,属于MPEG2的系统层。MPEG2-TS面向的传输介质是网络和卫星等可靠性较低的传输介质,这一点与面向较可靠介质如DVD等的MPEG PS不同。
一、TS数据包
TS流中每一个包长为188字节(还有个别的是192和204个字节)。包的结构为,包头为4个字节(第一个字节为0x47,字节由解码器识别,使包头和有效负载可相互分离。),负载为184个字节。在TS流里可以填入很多类型的数据,如视频、音频等。
TS header如下表所示:
名称 |
长度(位) |
同步字节(sync_byte) |
8 |
传输错误标记位(transport_error_indicator) |
1 |
载荷单元起始标记位(payload_unit_start_indicator |
1 |
传输优先级(transport_priority) |
1 |
分组ID (PID) |
13 |
传输加扰控制(transport_scrambling_control) |
2 |
适配域控制(adaptation_field_control) |
2 |
连续计数(continuity_counter) |
4 |
1. 同步字节:该值为0x47。用于定位TS包的起始位置。
2. 传输错误标记符:值为1时表明至少有1个错误位存在于关联的TS包中。
3. 负载单元起始标记符:负载单元起始符用于PES包或PSI数据。当TS包的负载为PES 数据时该值为1表明TS数据包是PES数据的起始字节,当TS包的负载为PSI数据时该值为1表明TS数据包包含PSI数据的第一个字节且TS数据包负载的第一个字节为pointer_field。
4. 传输优先级:值为1表明该TS包比拥有相同PID的数据包有更高的优先级。
5. PID: PID用于标识数据包的分组。PID 0保留给PAT表,PID 1保留给CAT 表,PID0X0002-0X000F也是保留值,PID 0X1FFF是空包的保留PID。
6. 传输加扰控制:这两位表明传输流负载的加扰模式。当有适配域存在时传输流包头不应该被加扰。空包的传输加扰控制应该设置为00。
7. 适配域控制:这两位表明传输流包头后是否带有适配域和负载。00是保留值;01没有适配域,只有负载;10只有适配域,没有负载;11适配域后跟随着负载。空包的适配域控制值应该为01。解码器应该将适配域控制值为00的TS包丢弃。
8. 连续计数:连续计数从0到15循环计数。在TS流中,重复包可能被发送两次,并且最大发送两次。重复包和适配域控制为00或10的TS包的连续计数和前一个有相同PID的包相同。当“discontinuity_indicator”设置为1时,连续计数的值可以不连续。
9. 数据字节:数据字节应该是来自PES包,PSI数据段,规范中未定义的私有数据。数据字节的长度应该是184减去适配域的长度。
二、适配域
适配域如下表所示:
名称 |
长度(位) |
|||
适配域长度(adaptation_field_length) |
8 |
|||
如果适配域长度大于0 |
连续计数标记位(discontinuity_indicator 1) |
1 |
||
随机访问标记位(random_access_indicator) |
1 |
|||
ES流优先级标记位(elementary_stream_priority_indicator) |
1 |
|||
PCR标记位(PCR_flag) |
1 |
|||
OPCR标记位(OPCR_flag) |
1 |
|||
拼接点标记(splicing_point_flag) |
1 |
|||
传输私有数据标记位(transport_private_data_flag) |
1 |
|||
适配域扩展标记位(adaptation_field_extension_flag) |
1 |
|||
如果PCR_flag为1 |
PCR基本值(program_clock_reference_base) |
33 |
||
保留位 |
6 |
|||
PCR扩展值 |
15 |
|||
如果OPRC_flag为1 |
原PCR基本值(original_program_clock_reference_base) |
33 |
||
保留位 |
6 |
|||
原PCR扩展值 |
9 |
|||
如果splicing_point_flag为1 |
拼接倒数计数(splice_countdown) |
8 |
||
如果transport_private_data_flag为1 |
私有数据长度(transport_private_data_length) |
8 |
||
从0到transport_private_data_length |
私有数据 |
8 |
||
如果adaptation_field_extension_flag为1 |
适配域扩展长度 |
8 |
||
ltw_flag |
1 |
|||
piecewise_rate_flag |
1 |
|||
seamless_splice_flag |
1 |
|||
从0到N |
填充数据(stuffing_byte) |
8 |
||
1. 适配域长度:adaptation_field_length给出适配域从该值之后的字节长度。该值为0是在TS包中通过适配域插入填充数据。对于携带PES数据的TS包,如果PES数据长度不够时填充数据被用来补足TS包。
2. 连续计数标记位:当该值为1时表示当前的传输流包处于不连续状态。该值被用来表示系统时间的不连续和continuity_counter的不连续。系统时间的不连续指的是对于被设置为PCR_PID的TS包,下一个PCR包将代表新的系统时钟。在任何TS包中都可以使用discontinuity_indicator表示continuity_counter的不连续。对于包含ES流的TS包continuity_counter的不连续发生后,ES流的第一个字节应该是ES流的访问点。
3. 随机访问点:该值为1时表明该TS包和随后的有相同PID的TS包有对当前点进行随机访问的信息。对于视频下一个PES包的起始字节应该为sequence header,对于音频下一个PES包的字节应该是音频帧的第一个字节。
4. ES流优先级标记位:该值表示对于有相同PID的TS包,当前TS包所携带ES流数据的优先级。1具有更高的优先级。对于视频如果TS包中包含有帧内编码的数据可以将该值设为1。
5. PCR标记位:该值为1表示适配域中包含有PCR内容。
6. 原PCR标记位:该值为1表示适配域中包含有OPCR内容。
7. 拼接点标记位:该值为1表示适配域中包含有拼接读秒。
8. 传输私有数据标记位:该值为1表示适配域有1个以上的私有字节。
9. 适配域扩展标记位:该值为1表示有适配域扩展数据。
10.PCR:PCR有42位,分为两部分。第一部分为基本部分,33位,精度为90KHz,第二部分位扩展部分,9位,精度为27MHz。
11.PCR =PCR_BASE x 300 + PCR_EXT
12.OPCR:OPCR用于通过一个传输流重构传输流。当重构传输流时OPCR被复制到PCR域。
三、PSI信息
1. PSI信息被用来解析节目。PSI不能被加扰。在TS流中,PSI包括4个表:PAT表,PMT表,NIT表和CAT表。PAT表关联节目号和PMT表PID;PMT表给出节目组成流的PID;NIT表给出物理网络参数,诸如FDM频率,发射机编号;CAT表关联1到多个EMM流。
2. 在TS包中通过pointer_field表示PSI分段的开始。Pointer_field是 个8位域,其值表示从pointer_field之后到PSI第一个分段的第一个字节间的字节长度。
-
四、PAT表
PAT表列出TS流中所包含的节目号以及节目所对应的PMT PID和NIT PID。节目号是节目的数字标签,节目号0x0000被保留给网络PID。一个PAT表可以被分成多个section。PAT结构如下表所示。
名称 |
长度(位) |
||
表ID(table_id) |
8 |
||
section_syntax_indicator |
1 |
||
‘0’ |
1 |
||
reserved |
2 |
||
section_length |
12 |
||
transport_stream_id |
16 |
||
reserved |
2 |
||
version_number |
5 |
||
current_next_indicator |
1 |
||
section_number |
8 |
||
last_section_number |
8 |
||
重复0到N个节目 |
program_number |
16 |
|
reserved |
3 |
||
如果节目号为0 |
NIT PID |
13 |
|
如果节目号不为0 |
PMT PID |
||
CRC |
32 |
1. table_id: 应该被设置为0x00,表示是该表是PAT表
2. section_syntax_indicator:应该被设置为1
3. section_length: 12位域,前两位应该为00。该值给出了从section_length之后到CRC间(包含CRC)的PAT分段的字节数。Section长度不能超过1021
4. Transport_stream_id:传输流标签,用于标识该传输流以区别网络内的其它复用流。
5. Version_number:PAT表的版本号。当PAT表改变时版本号应该加1,到达31后回绕成0。当current_next_indicator是1时版本号用于当前的PAT表,当current_next_indicator为0时版本号用于下一个PAT表。
6. Current_next_indicator:为1时表示PAT表当前可用,为0时表示下个PAT表可用。
7. Section_number:给出这个section的序号。PAT表的第一个section的序号应该为0x00。
8. Last_section_number:给出PAT表的最后一个section序号。
9. Program_number:给出PMT PID所关联节目的节目号。如果节目号为0x0000,所关联的PID将是网络PID。
10.Network_PID:给出NIT PID。
11.Program_map_PID:给出节目所关联的PMT表的PID。
12.CRC_32:PAT section的CRC校验值。
五、PMT表
只要我们处理了PMT,那么我们就可以获取频道中所有的PID信息,如当前频道包含多少个Video、共多少个Audio和其他数据,还能知道每种数据对应的PID分别是什么。这样如果我们要选择其中一个Video和Audio收看,那么只需要把要收看的节目的Video PID和Audio PID保存起来,在处理Packet的时候进行过滤即可实现。PMT如下表所示:
名称 |
长度(位) |
|
table_id |
8 |
|
section_syntax_indicator |
1 |
|
‘0’ |
1 |
|
reserved |
2 |
|
section_length |
12 |
|
program_number |
16 |
|
reserved |
2 |
|
version_number |
5 |
|
current_next_indicator |
1 |
|
section_number |
8 |
|
last_section_number |
8 |
|
reserved |
3 |
|
PCR_PID |
13 |
|
reserved |
4 |
|
program_info_length |
12 |
|
重复0到N个descriptor |
descriptor |
|
重复0到N1个ES流 |
stream_type |
8 |
reserved |
3 |
|
elementary_PID |
13 |
|
reserved |
4 |
|
ES_info_length |
12 |
|
重复0到N2个descriptor |
descriptor |
|
CRC_32 |
32 |
1. Table_id:应该被设置成0x02。
2. Section_syntax_indicator:应该被设置成1。
3. Section_length:12位域,前两位应该为00。该值给出了从 section_length之后到CRC间(包含CRC)的PMT分段的字节数。Section长度不能超过1021。
4. Program_number:给出PMT表所关联的节目号。一个节目定义只能被包含在一个节目映射section中,这就意味着节目定义不能超过1016个字节。
5. Version_number:PMT表的版本号。当PMT表改变时版本号应该加1,到达31后回绕成0。当current_next_indicator是1时版本号用于当前的PMT表,当current_next_indicator为0时版本号用于下一个PMT表。
6. Current_next_indicator:为1时表示PMT表当前可用,为0时表示下个PMT表可用。
7. Section_number:这个值应该总是为0x00。
8. Last_section_number:这个值应该总是为0x00。
9. PCR_PID:指出包含节目PCR的TS分组PID。对于没有PCR的私有流节目这个值应该为0x1FFF。
10.Program_info_length;12位域,前两位应该为00。给出其后所跟descriptors的字节长度。
11.Stream_tyep:给出elementary_PID所关联的ES流的类型。
12.Elementary_PID:给出ES流的PID。
13.ES_info_length:12位域,前两位应该为00。给出其后所跟descriptors的字节长度。
14.CRC_32:PMT CRC校验值。
六、PES包
PES(分组的ES),ES形成的分组称为PES分组,是用来传递ES的一种数据结构。PES流是ES流经过PES打包器处理后形成的数据流,在这个过程中完成了将ES流分组、打包、加入包头信息等操作(对ES流的第一次打包)。PES流的基本单位是PES包。PES包由包头和payload组成。
PES包的语法定义如下表所示:
名称 |
长度(位) |
||
packet_start_code_prefix |
24 |
||
stream_id |
8 |
||
PES_packet_length |
16 |
||
如果stream_id 不是program_stream_map, padding_stream, private_stream_2, ECM, EMM, program_stream_directory, DSMCC_stream, ITU-T Rec. H.222.1 type E_stream |
'10' |
2 |
|
PES_scrambling_control |
2 |
||
PES_priority |
1 |
||
data_alignment_indicator |
1 |
||
copyright |
1 |
||
original_or_copy |
1 |
||
PTS_DTS_flags |
2 |
||
ESCR_flag |
1 |
||
ES_rate_flag |
1 |
||
DSM_trick_mode_flag |
1 |
||
additional_copy_info_flag |
1 |
||
PES_CRC_flag |
1 |
||
PES_extension_flag |
1 |
||
PES_header_data_length |
8 |
||
如果PTS_DTS_flags 等于'10' |
'0010' |
4 |
|
PTS [32..30] |
3 |
||
marker_bit |
1 |
||
PTS [29..15] |
15 |
||
marker_bit |
1 |
||
PTS [14..0] |
15 |
||
marker_bit |
1 |
||
如果PTS_DTS_flags 等于'11' |
'0011' |
4 |
|
PTS [32..30] |
3 |
||
marker_bit |
1 |
||
PTS [29..15] |
15 |
||
marker_bit |
1 |
||
PTS [14..0] |
15 |
||
marker_bit |
1 |
||
'0001' |
4 |
||
DTS [32..30] |
3 |
||
marker_bit |
1 |
||
DTS [29..15] |
15 |
||
marker_bit |
1 |
||
DTS [14..0] |
5 |
||
marker_bit |
1 |
||
从0到N1 |
stuffing_byte |
8 |
|
从0到N2 |
PES_packet_data_byte |
8 |
|
如果stream_id 是 program_stream_map, private_stream_2, ECM, EMM, program_stream_directory, DSMCC_stream, ITU-T Rec. H.222.1 type E stream |
从0到PES_packet_length |
PES_packet_data_byte |
8 |
如果stream_id 是 padding_stream |
从0到PES_packet_length |
padding_byte |
8 |
1. packet_start_code_prefix:packet起始码前缀和其后的stream_id共同标识了PES包的起始位置。Packet起始码前缀的值为:0x000001
2. stream_id:该值给出了所关联ES流的类型和编号。
3. Pes_packet_length:给出从其后所开始的PES包的字节数。
4. Pes_scrambling_control:指出PES负载的加扰模式。当加扰位于PES层时,PES包头不应该被加扰。
5. Pes_priority:指出这个PES包负载的优先级。Pes_priority为1时具有更高的优先级。
6. Data_alignment_indicator:值为1时表明PES包头后立刻紧跟着视频起始码或音频同步字。
7. Copyright:该值为1时表明PES包负载有版权保护。
8. Original_or_copy:该值为1时表明PES包负载是原始的,为0时是复制的。
9. PTS_DTS_flags:2位域,为10时PES包头中有PTS域,为11时PES包头中有PTS和DTS域。
10.ESCR_flag:为1时表明PES包头中有ESCR及扩展域。
11.ES_rate_flag:为1时表明PES包头中有ES_rate域。
12.DSM_trick_mode_flag:为1时表明有trick mode域。
13.Additional_copy_info_flag:为1时表明有additional_copy_info域。
14.PES_CRC_flag:为1时表明CRC域存在于PES包中。
15.PES_extension_flag:为1时表明扩展域存在于PES包头中。
16.PES_header_data_length:指出PES包头中所包含的可选域和填充字节的长度。
17.Marker_bit:该值为1。
18.PTS:PES包在解码器上的播放时间。PTS有33位,分成3个域。PTS的时间单位为系统时钟频率的300分之一(27000000/300),即90KHz。
19.DTS:PES包的解码时间。DTS有33位,分成3个域。DTS的时间单位为系统时钟频率的300分之一(27000000/300),即90KHz。
七、TS流的解析过程
l 定位TS包的sync_byte,获得TS包,解析TS包头,根据PID决定TS包的类型(PAT,PMT,PES…)。
l 解析PAT表。对PID为0的TS包进行解析,获取PAT表,从中解析出TS流中所包含的节目号以及节目所对应的NIT PID和PMT PID。
l 解析PMT表。根据已知的PMT PID信息对相应的TS包进行解析,获取PMT表,从中解析出节目的PCR_PID,音视频ES PID。
l 解析PES包。根据已知的ES PID信息对相应的TS包进行解析,获取对应音视频的帧数据,并解析出音视频包帧的PTS,DTS值。
l 解析PCR值。根据PMT表中所获取的PCR_PID,对相应的TS包进行解析,从适配域中获取PCR值。