TS流分析
扫描二维码
随时随地手机看文章
一 从TS流开始
数字电视机顶盒接收到的是一段段的码流,我们称之为TS(Transport Stream,传输流),每个TS流都携带一些信息,如Video、Audio以及我们需要学习的PAT、PMT等信息。因此,我们首先需要了解TS流是什么,以及TS流是怎样形成、有着怎样的结构。
(一) TS流、PS流、PES流和ES流都是什么?
ES流(Elementary Stream):基本码流,不分段的音频、视频或其他信息的连续码流。
PES流:把基本流ES分割成段,并加上相应头文件打包成形的打包基本码流。
PS流(Program Stream):节目流,将具有共同时间基准的一个或多个PES组合(复合)而成的单一数据流(用于播放或编辑系统,如m2p)。
TS流(Transport Stream):传输流,将具有共同时间基准或独立时间基准的一个或多个PES组合(复合)而成的单一数据流(用于数据传输)。
*NOTE:TS流和PS流的区别:TS流的包结构是长度是固定的;PS流的包结构是可变长度的。这导致了TS流的抵抗传输误码的能力强于PS流(TS码流由于采用了固定长度的包结构,当传输误码破坏了某一TS包的同步信息时,接收机可在固定的位置检测它后面包中的同步信息,从而恢复同步,避免了信息丢失。而PS包由于长度是变化的,一旦某一PS包的同步信息丢失,接收机无法确定下一包的同步位置,就会造成失步,导致严重的信息丢失。因此,在信道环境较为恶劣,传输误码较高时,一般采用TS码流;而在信道环境较好,传输误码较低时,一般采用PS码流。)
由于TS码流具有较强的抵抗传输误码的能力,因此目前在传输媒体中进行传输的MPEG-2码流基本上都采用了TS码流的包格。
(二) TS流是如何产生的?
从上图可以看出,视频ES和音频ES通过打包器和共同或独立的系统时间基准形成一个个PES,通过TS复用器复用形成的传输流。注意这里的TS流是位流格式(分析Packet的时候会解释),也即是说TS流是可以按位读取的。
(三) TS流的格式是怎样的?
TS流是基于Packet的位流格式,每个包是188个字节(或204个字节,在188个字节后加上了16字节的CRC校验数据,其他格式一样)。整个TS流组成形式如下:
Packet Header(包头)信息说明
1
sync_byte
8bits
同步字节
2
transport_error_indicator
1bit
错误指示信息(1:该包至少有1bits传输错误)
3
payload_unit_start_indicator
1bit
负载单元开始标志(packet不满188字节时需填充)
4
transport_priority
1bit
传输优先级标志(1:优先级高)
5
PID
13bits
Packet ID号码,唯一的号码对应不同的包
6
transport_scrambling_control
2bits
加密标志(00:未加密;其他表示已加密)
7
adaptation_field_control
2bits
附加区域控制
8
continuity_counter
4bits
包递增计数器
PID是TS流中唯一识别标志,Packet Data是什么内容就是由PID决定的。如果一个TS流中的一个Packet的Packet Header中的PID是0x0000,那么这个Packet的Packet Data就是DVB的PAT表而非其他类型数据(如Video、Audio或其他业务信息)。下表给出了一些表的PID值,这些值是固定的,不允许用于更改。
表
PID 值
PAT
0x0000
CAT
0x0001
TSDT
0x0002
EIT,ST
0x0012
RST,ST
0x0013
TDT,TOT,ST
0x0014
下面以一个TS流的其中一个Packet中的Packet Header为例进行说明:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
…
Packet(十六进制)
4
7
0
7
e
5
1
2
…
Packet(二进制)
0
1
0
0
0
1
1
1
0
0
0
0
0
1
1
1
1
1
1
0
0
1
0
1
0
0
0
1
0
0
1
0
…
Packet Header 信息
1 sync_byte=0x47
2
3
4
5 PID=0x07e5
6
7
8
…
sync_byte=01000111, 就是0x47,这是DVB TS规定的同步字节,固定是0x47.
transport_error_indicator=0, 表示当前包没有发生传输错误.
payload_unit_start_indicator=0, 含义参考ISO13818-1标准文档
transport_priority=0,表示当前包是低优先级.
PID=00111 11100101即0x07e5, Video PID
transport_scrambling_control=00,表示节目没有加密
adaptation_field_control=01即0x01,具体含义请参考ISO13818-1
continuity_counte=0010即0x02,表示当前传送的相同类型的包是第3个
TS流的基本内容就是这些了。
回顾一下,TS流是一种位流(当然就是数字的),它是由ES流分割成PES后复用而成的;它经过网络传输被机顶盒接收到;数字电视机顶盒接收到TS流后将解析TS流。
TS流是由一个个Packet(包)构成的,每个包都是由Packet Header(包头)和Packet Data(包数据)组成的。其中Packet Header指示了该Packet是什么属性的,并给出了该Packet Data的数据的唯一网络标识符PID。
到这里,我们对TS流已经有了一定的了解,下面将从TS流转向PAT表和PMT表的学习。
二 从TS流到PAT、PMT
说完了TS流的基本概念,就该开始对TS流进行更深入的研究了。首先需要想一想:TS流的本质是什么?它的确是一段码流,并且是一段由数据包(Packet)组成的码流。那么这些数据包究竟是怎样的呢?它和我们收看的电视节目之间又有什么区别?这些都是这部分需要了解的内容。
在上一节中,我们可以看到PID这个被标红的字段频繁地出现。PID是当前TS流的Packet区别于其他Packet类型的唯一识别符,通过读取每个包的Packet Header,我们可以知道这个Packet的数据属于何种类型。上一节列出了几项固定的PID值,它们用于识别存储了特殊信息的Packet。下面要谈的PAT表的PID值就是固定的0x0000。
(一) PAT表(Program Association Table,节目关联表)
由于下面的内容比较繁杂,这里先给出一个大纲,方便查阅:
1. PAT表的描述(表格+分析)
2. PAT表的定义(代码+分析)
3. PAT表的结构(代码+分析)
4. PAT表的解析(代码+分析)
5. 通过一段TS流中一个Packet分析PAT表(表格+分析)
下面,开始正式的分析!
1.PAT表的描述(表格+分析)
PAT表定义了当前TS流中所有的节目,其PID为0x0000,它是PSI的根节点,要查寻找节目必须从PAT表开始查找。
PAT表携带以下信息:
TS流ID
transport_stream_id
该ID标志唯一的流ID
节目频道号
program_number
该号码标志TS流中的一个频道,该频道可以包含很多的节目(即可以包含多个Video PID和Audio PID)
PMT的PID
program_map_PID
表示本频道使用哪个PID做为PMT的PID,因为可以有很多的频道,因此DVB规定PMT的PID可以由用户自己定义
2. PAT表的定义(代码+分析)
PAT表主要包含频道号码和每一个频道对应的PMT的PID号码,这些信息我们在处理PAT表格的时候会保存起来,以后会使用到这些数据。下面将PAT表的定义给出:
[cpp]view plaincopy typedefstructTS_PAT_Program { unsignedprogram_number:16;//节目号 unsignedprogram_map_PID:13;//节目映射表的PID,节目号大于0时对应的PID,每个节目对应一个 }TS_PAT_Program
3. PAT表的结构(代码+分析)
再将PAT表的结构体给出:
[cpp]view plaincopy typedefstructTS_PAT { unsignedtable_id:8;//固定为0x00,标志是该表是PAT表 unsignedsection_syntax_indicator:1;//段语法标志位,固定为1 unsignedzero:1;//0 unsignedreserved_1:2;//保留位 unsignedsection_length:12;//表示从下一个字段开始到CRC32(含)之间有用的字节数 unsignedtransport_stream_id:16;//该传输流的ID,区别于一个网络中其它多路复用的流 unsignedreserved_2:2;//保留位 unsignedversion_number:5;//范围0-31,表示PAT的版本号 unsignedcurrent_next_indicator:1;//发送的PAT是当前有效还是下一个PAT有效 unsignedsection_number:8;//分段的号码。PAT可能分为多段传输,第一段为00,以后每个分段加1,最多可能有256个分段 unsignedlast_section_number:8;//最后一个分段的号码 std::vector