教程目录

PSI/SI教程

如果你是PSI/SI的初学者, 那么就让一切都从这里开始吧...



本资料集由 林晓州 收集和整理,并提供共享。
邮箱: 1139904786@qq.com
网址: http://120.25.83.13




©2016 · OneLib智库 · 挖掘自己的财富

第二章:从TS到PAT和PMT

从PAT表开始,解析TS流

说完了TS流相关的基本概念,就该开始对TS流进行更深入的研究了。 首先需要想一想:TS流的本质是什么? TS是一段码流,并且是一段由数据包(Packet)组成的码流。 那么我们要如何组织和处理如此庞大的数据包呢?

如果我们把码流看作一本书,那么我们就需要给这本书制作一个目录;有了这样的目录,我们就可以“按图索骥”地得到我们需要的信息。

是的,PSI/SI就是这样“目录”。而PAT则是“目录”的“目录”。 通过PAT及其他 PSI 信息,我们可以一点一点地把整个TS流的信息组织和管理起来,从而分离出不同的业务(Service), 以及该业务的视频、音频、图文(Teletext)、字幕(Subtitle)、其他音轨等分量; 再根据 SI 信息,我们就可以得到每个业务的名称、事件(Event)等附加信息, 从而形成 EPG ,更好地管理各个业务。

需要区分的一点是,不管是PSI还是SI,都只是一种“管理信息”,它并不包含任何的视频或音频数据。

什么是PID

Introduction of PID

在上一节《预备知识》中,我们可以看到 PID(Packet Identifier) 这个被标红的字段频繁地出现。

PID 是当前TS流的Packet区别于其他Packet类型的唯一识别符,通过读取每个包的Packet Header, 我们可以知道这个Packet的数据属于何种类型。下表列出了几项固定的 PID 值,它们用于识别存储了特殊信息的Packet。 下面要谈的PAT表的 PID 值就是固定的0x0000。

TS流中PID的分配

解复用程序需要使用到的表格只有PAT、PMT、SDT;而CA解扰还需要使用CAT;EPG则还要有NIT、EIT、TDT、TOT等表。

使用工具说明

Tools Introduction

使用码流分析软件来分析一段码流,会事半功倍:泽华源码流分析软件Tsparse

下图是使用 泽华源码流分析软件 的界面。在打开码流并分析完毕后,点击下方选项卡“语法分析”可以出现这个窗口。


一切从PAT开始

Begin with PAT

PAT表(Program Association Table,节目关联表) 定义了当前TS流中所有的节目,其PID为0x0000,它是PSI的根节点,要查寻找节目必须从PAT表开始查找。PAT表携带以下信息:

TS流IDtransport_stream_id该ID标志唯一的流ID
节目频道号program_number该号码标志TS流中的一个频道,该频道可以包含很多的节目(即可以包含多个Video PID和Audio PID)
PMT的PIDprogram_map_PID表示本频道使用哪个PID做为PMT的PID。
因为可以有很多的业务,因此DVB规定PMT的PID可以由用户自己定义

解析PAT表的数据包

Analyze the Package of PAT

上一幅图中,右下角粉红色的数据即为PAT表的数据包。

根据在上一章 《预备知识》中提到的包的分析方法,可以将上图的的数据这样划分:

包头(Package Header)包数据(Package Data)
47 40 00 1C00 B0 1D 22 01 CF 00 00 00 00 E0 10 40 13 E1 30 40 18 E1 ... FF FF

注:表格内数据均为16进制数值。前4个字节为包头,后面的184个字节为包数据。


PAT表的包头

Package Header of PAT

细分其表头(Package Header)数据(47 40 00 1C)如下:

位号012345 6789101112 13141516171819 20212223242526 2728293031...
Packet(二进制) 0100 0111 0100 0000 0000 0000 0001 1100 ...
Packet(十六进制) 47 40 00 1C ...
Packet Header信息 0*: sync_byte=0x47 1*2*3*4*: PID (这里是0x0000) 5*6* 7* ...

拖动可显示更多数据

上表中,第一行为表头的位号(0-31,共32位), 第二行为每位的二进制数值, 第三行为每个字节的16进制数值, 最后一行的数据说明参看下面的表格。

Packet Header(包头)信息Demo
#标识位数说明
0*sync_byte8 bits固定是0x47
1*transport_error_indicator1 bits值为0,表示当前包没有发生传输错误。错误指示信息(1:该包至少有1bits传输错误)
2*payload_unit_start_indicator1 bits值为1,含义参考ISO13818-1标准文档。负载单元开始标志(packet不满188字节时需填充)
3*transport_priority1 bits值为0,表示当前包是低优先级。传输优先级标志(1:优先级高)
4*PID13 bitsPID=0x0000,说明是PAT表。Packet ID号码,唯一的号码对应不同的包
5*transport_scrambling_control2 bits值为0x00,表示节目没有加密。加密标志(00:未加密;其他表示已加密)
6*adaptation_field_control2 bits值为0x01,具体含义请参考ISO13818-1。附加区域控制
7*continuity_counter4 bits值为0xC,表示当前传送的相同类型的包是第12个。包递增计数器

PAT表的包数据

Package Data of PAT

该包的数据部分(Package Data)为:
00 B0 1D 22 01 CF 00 00 00 00 E0 10 40 13 E1 30 40 18 E1 80 40 0A E0 A0 40 0E E0 B5 10 A5 84 FF ... FF FF

注意到这里有一个绿色的 00, 这是因为在包头后需要除去一个字节才是有效数据(payload_unit_start_indicator="1")。 因此,真正要分析的数据应该是红色部分:
B0 1D 22 01 CF 00 00 00 00 E0 10 40 13 E1 30 40 18 E1 80 40 0A E0 A0 40 0E E0 B5 10 A5 84 FF ... FF FF


解析前8个字节

下面对前8个字节(0-7字节,共计64 bits)进行分析:
B0 1D 22 01 CF 00 00 00 00 E0 10 40 13 E1 30 40 18 E1 80 40 0A E0 A0 40 0E E0 B5 10 A5 84 FF ... FF FF

位号 0123 4567 891011 12131415 16171819 20212223 24252627 28293031 32333435 36373839 40414243 44454647 48495051 52535455 ...
Binary 0000 0000 1011 0000 0001 1101 0010 0010 0000 0001 1100 1111 0000 0000 ...
Hex 00 B0 1D 22 01 CF 00 ...
结构 0*: table_id=0x00 1*2*3*4*: section_length (这里是0x01D) 5*6* 7*8*9*10* ...

拖动可显示更多数据

#字段名占位具体值次序说明
0*table_id8 bits0000 0000(即0x00)第0个字节
00
PAT的table_id只能是0x00
1*section_syntax_indicator1 bit1

第1、2个字节
B0 1D
段语法标志位,固定为1
2*zero1 bit0
3*reserved2 bits11 (Binary)
4*section_length12 bits00 00 00 01 11 01(即0x1D,十进制值为29)意思是 段长度为29字节
5*transport_stream_id16 bits‭00 10 00 10 00 00 00 01‬(即0x2201)第3、4个字节
22 01
TS的识别号
6*reserved2 bits11

第5个字节
CF
TS的识别号
7*version_number5 bits0 01 11一旦PAT有变化,版本号加1
8*current_next_indicator1 bit1当前传送的PAT表可以使用,若为0则要等待下一个表
9*section_number4 bits00 00(即0x00)第6个字节
00
给出section号,在sub_table中,
第一个section其section_number为"0x00",
每增加一个section,section_number加一
10*last_section_number4 bits00 00(即0x00)第7个字节
00
sub_table中最后一个section的section_number
循环开始(循环内的数据解析见下一节内容!)
-program_number16 bits-----
-reserved3 bits-----
-network_id

program_map_PID
13 bits----program_number为0x0000时,
这里是network_id(NIT的PID);
其余情况是program_map_PID(PMT的PID)
循环结束
-CRC_3232 bits--最后4个字节-

解析循环部分

下面对后续几个字节(第8个字符开始)进行分析:
B0 1D 22 01 CF 00 00 00 00 E0 10 40 13 E1 30 40 18 E1 80 40 0A E0 A0 40 0E E0 B5 10 A5 84 FF ... FF FF

在上一小节节的表格中,每一个循环都是4个字节(32 bits),我们在这里就先解析第一个循环:
B0 1D 22 01 CF 00 00 00 00 E0 10 40 13 E1 30 40 18 E1 80 40 0A E0 A0 40 0E E0 B5 10 A5 84 FF ... FF FF

位号 0123 4567 891011 12131415 16171819 20212223 24252627 28293031 ...
Binary 0000 0000 0000 0000 1110 0000 0001 0000 ...
Hex 00 00 E0 10 ...
结构 1*: program_number = 0x0000 2*: reserved 3*: network_id = 0x10 ...

拖动可显示更多数据

#字段名占位具体值说明
1*program_number16 bits0x0000program_number = 0x0000
2*reserved3 bits111-
3*program_map_PID13 bits0x0000因为program_number为0x0000,
所以这里是network_id(NIT的PID)

继续解析下一个循环:
B0 1D 22 01 CF 00 00 00 00 E0 10 40 13 E1 30 40 18 E1 80 40 0A E0 A0 40 0E E0 B5 10 A5 84 FF ... FF FF

位号 0123 4567 891011 12131415 16171819 20212223 24252627 28293031 ...
Binary 0100 0000 0001 0011 1110 0001 0011 0000 ...
Hex 40 13 E1 30 ...
结构 1*: program_number = 0x4013(即十进制16403) 2*: reserved 3*: program_map_PID = 0x130(即PMT_PID为0x130) ...

拖动可显示更多数据

#字段名占位具体值说明
1*program_number16 bits0x4013program_number = 0x4013(即十进制16403)
2*reserved3 bits111-
3*program_map_PID13 bits0x130因为program_number不为0x0000,
所以这里是program_map_PID = 0x130(即PMT_PID为0x130)

通过这个循环,我们可以知道,在这个TS中,有一个节目号为0x4013(即十进制16403)的节目,其PMT的PID为0x130。那么要想获取这个节目的详细信息,就要去解析PID为0x130的PMT表。(关于PMT表的解析可参看下一节内容)

为了不占用过多空间来显示这样重复的内容,关于更多循环的分析就不显示在正文,如果你仍想看,可以 点击这里显示或隐藏


循环汇总

将所有循环遍历完毕后,我们就能找出4个节目。下图是码流分析软件的截图。


PMT PID列表

下面表格是通过对PAT表分析后得到的数据。在分析完PMT表后,还将对这张表进行补充。

#节目号PMT PID
1164030x130
2164080x180
3163940xA0
4163980xE0

小结

对我们来说,PAT就是一个总入口。PAT告诉了我们,这个TS流中有几个节目,以及它们的PMT PID分别是多少。有了PMT的PID,我们就可以继续下一步了。

PMT表分析

Analyze of PMT

PMT表概述

PMT表中包含的数据如下:
    (1) 当前频道中包含的所有Video数据的PID
    (2) 当前频道中包含的所有Audio数据的PID
    (3) 和当前频道关联在一起的其他数据的PID(如Teletext、Subtitle、其他音轨等的PID)

只要我们处理了PMT,那么我们就可以获取频道中所有的PID信息, 如当前频道包含多少个Video、共多少个Audio和其他数据,还能知道每种数据对应的PID分别是什么。 这样如果我们要选择其中一个Video和Audio收看,那么只需要把要收看的节目的Video PID和Audio PID保存起来, 在处理Packet的时候进行过滤即可实现。


PMT表的数据包总览

以PMT PID=0x130来分析。我们找到PID为0x130的PMT表:


PMT表的数据包包头

表头的分析方式和PAT表头的相同,就不详细介绍了。

数据包头是红色部分:
47 41 30 19 00 02 B0 43 40 13 C5 00 00 E1 31 F0 00 02 E1 31
F0 03 52 01 01 04 04 E1 32 F0 09 0A 04 64 75 01 52 01 03 06
E1 37 F0 0A 52 01 0A 56 05 64 65 75 09 00 06 E1 38 F0 0C 0A
04 64 65 75 01 6A 01 00 52 01 11 28 09 C3 CB FF FF ... FF FF

分析如下:

位号012345 6789101112 13141516171819 20212223242526 2728293031...
Packet(二进制) 0100 0111 0100 0001 0011 0000 0001 1001 ...
Packet(十六进制) 47 41 30 19 ...
Packet Header信息 - ---PMT PID (这里是0x130) -- - ...

拖动可显示更多数据


PMT表的数据包数据

数据内容是红色部分:
47 41 30 19 00
片段1:02 B0 43 40 13 C5
片段2:00 00 E1 31 F0 00
片段3:02 E1 31 F0 03
片段3补充:52 01 01
片段4:04 E1 32 F0 09
0A 04 64 75 01 52 01 03 06
E1 37 F0 0A 52 01 0A 56 05 64 65 75 09 00 06 E1 38 F0 0C 0A
04 64 65 75 01 6A 01 00 52 01 11 28 09 C3 CB FF FF ... FF FF

片段1:02 B0 43 40 13 C5

位号 0123 4567 891011 12131415 16171819 20212223 24252627 28293031 32333435 36373839 40414243 44454647
Binary 0000 0010 1011 0000 0100 0011 0100 0000 0001 0011 1100 0101
Hex 02 B0 43 40 13 C5
结构 0*: table_id=0x021*2*3* 4*5*: 0x4013 = 164036*7*: 0x02 8*

拖动可显示更多数据

#字段名占位具体值说明
0*table_id8 bits0x02
1*Section_syntax_indicator1 bit1通常设为“1”
2*zero1 bit0
3*Reserved2 bits11
4*Section_length12 bits0x43段长度,从program_number开始,到CRC_32(含)的字节总数
5*program_number16 bits0x4013节目号为16403
6*Reserved2 bits11
7*Version_number5 bits00010 = 0x02
8*Current_next_indicator1 bit1当前未来标志符

片段2:00 00 E1 31 F0 00

位号 48495051 52535455 56575859 60616263 64656667 68697071 72737475 76777878 79808182 83848586 87888990 91929394 ...
Binary 0000 0000 0000 0000 1110 0001 0011 0001 1111 0000 0000 0000 ...
Hex 00 00 E1 31 F0 00 ...
结构 9*10* 11*12*13*14* ...

拖动可显示更多数据

#字段名占位具体值说明
9*Section_number8 bits0x00当前段号码
10*last_section_number8 bits0x00最后段号码,含义和PAT中的对应字段相同
11*reserved3 bits0x00
12*PCR_PID13 bits0x0131PCR(节目参考时钟)所在TS分组的PID
13*reserved4 bits1111
14*program_info_length12 bits0x00节目信息长度
(之后的是N个描述符结构,一般可以忽略掉,这个字段就代表描述符总的长度,单位是Bytes)
紧接着就是频道内部包含的节目类型和对应的PID号码了

注意,上面的program_info_length之后的是N个描述符结构,但一般可以忽略掉。这个字段就代表描述符总的长度,单位是Bytes;这里是0x00,也就是意味着后面没有描述符结构。


片段3:02 E1 31 F0 03
因为program_info_length=0x00,所以紧接着的是频道内部包含的节目类型和对应的PID号码

位号 95969798 99100101102 103104105106 107108109110 111112113114 115116117118 119120121122 123124125126 127128129130 131132133134 ...
Binary 0000 0010 1110 0001 0011 0001 1111 0000 0000 0011 ...
Hex 02 E1 31 F0 03 ...
结构 15* 16*17* 18*19* ...

拖动可显示更多数据

#字段名占位具体值说明
15*stream_type8 bits0x02流类型,标志是Video还是Audio还是其他数据。这里是MPEG2视频类型
16*reserved3 bits111
17*elementary_PID13 bits0x131该节目的音频或视频PID。这里是视频PID=0x131
18*reserved4 bits1111
19*ES_info_length12 bits0x003后面紧跟着3个字节的描述子

片段3补充:52 01 01
因为ES_info_length=0x03,所以后续的三个字节,为Stream identifier descriptor

位号 135136137138 139140141142 143144145146 147148149150 151152153154 155156157158 ...
Binary 0101 0010 0000 0001 0000 0001 ...
Hex 52 01 01 ...
结构 20* 21*22* ...

拖动可显示更多数据

#字段名占位具体值说明
20*descriptor_tag8 bits0x52
21*descriptor_length8 bits0x01
22*component_tag8 bits0x01

至此,第一段单元流(Elementary Stream)的信息解析出来了。这是视频ES(MPEG2),其PID为0x131


片段4:04 E1 32 F0 09
接下来,继续第二个单元流信息解析。参照片段3的方式,先讲下一个单元流的基本信息解析出来:
0000 0100    111    0 0001 0011 0010    1111    0000 0000 1001

#字段名占位具体值说明
23*stream_type8 bits0x04流类型,标志是Video还是Audio还是其他数据。这里是MPEG2音频类型
24*reserved3 bits111
25*elementary_PID13 bits0 0001 0011 0010 = 0x132该节目的音频或视频PID。这里是音频PID=0x132
26*reserved4 bits1111
27*ES_info_length12 bits0000 0000 1001 = 0x09后面紧跟着9个字节的描述子

上图是完整的PID为0x132的ES信息,可以看到这个ES有两个描述子(descriptor)。 解析时,第一个字节代表了描述子tag,第二个代表该描述子的长度。

看第一个描述子ISO_639_language_descriptor,第一个字节值为0xa,长度为0x4
看第二个描述子stream_identifier_descriptor,第一个字节值为0x52,长度为0x1

其余单元流和PMT PID的分析略。


PMT表的数据包数据小结

根据PAT和PMT的信息,我们可以得到下面的信息:

#节目号PMT PIDES PIDES说明
1164030x1300x131MPEG2视频
0x132MPEG2音频
0x137MPEG2私用PES
0x138MPEG2私用PES
2164080x1800x181MPEG2视频
0x182MPEG2音频
0x187MPEG2私用PES
0x188MPEG2私用PES
3163940xA00xa1MPEG2视频
0xa2MPEG2音频
0xa7MPEG2私用PES
4163980xE00xe1MPEG2视频
0xe2MPEG2音频
0xe7MPEG2私用PES

TS的复用与解复用

Multiplexing and Demultiplexing of Transport Stream

在数字电视系统的前端,所有的数据(视频、音频、PSI/SI信息)都会被复用器(Multiplexer)复用成TS流,从而进行传送(见下图)。

TS复用(Multiplexing)

当机顶盒等接收器收到的数据,自然就是被复用后的一个个包(Package)了。这样的数据是不能直接使用的。 这时候,我们要做的就是把被复用的TS流 解复用(Demultiplexing, 简称Demux)

解复用的意义在于,由于TS流是一种复用的码流,里面混杂了多种类型的包;解复用TS流可以将类型相同的Packet存入相同缓存,分别处理。 这样就可以将Video、Audio或者其他业务信息(如PSI/SI信息)的数据区分开来。

上一小节制成的表格,其实就是解复用获得的信息。 通过它,我们可以组织起这个频点下的所有 节目。 以节目号为16403的 节目 为例, 过滤PID为0x131的所有包数据,就可以组成这个节目的视频; 过滤PID为0x132的所有包数据,就可以组成这个节目的音频; 这样,节目16403需要的视音频数据就集齐了;当然,要正常播放这个台,还需要时钟来同步。

DVB搜台过程

Process of DVB Scanning

DVB搜台过程

机顶盒先调整高频头到一个固定的频率(一般是主频点,如深圳天威的主频点是259MHZ),如果此频率有数字信号, 则COFDM芯片(如MT352)会自动把TS流数据传送给MPEG-2 decoder。 MPEG-2 decoder先进行数据的同步,也就是等待完整的Packet的到来.然后循环查找是否出现PID==0x0000的Packet; 如果出现了,则马上进入分析PAT的处理,获取了所有的PMT的PID。 接着循环查找是否出现PMT,如果发现了,则自动进入PMT分析,获取该频段所有的频道数据并保存。 如果没有发现PAT或者没有发现PMT,说明该频段没有信号,进入下一个频率扫描。

在解析TS流的时候,首先寻找PAT表,根据PAT获取所有PMT表的PID;再寻找PMT表,获取该频段所有节目数据并保存。 这样,只需要知道节目的PID就可以根据PacketHeade给出的PID过滤出不同的Packet,从而观看不同的节目。 这些就是PAT表和PMT表之间的关系。


SDT表

由于PID是一串枯燥的数字,用户不方便记忆、且容易输错,所以需要有一张表将节目名称和该节目的PID对应起来,DVB设计了 SDT表 来解决这个问题。 该表格标志一个节目的名称,并且能和PMT中的PID联系起来,这样用户就可以通过直接选择节目名称来选择节目了。

根据SDT表信息(这里不再详细解析),我们可以把上一小节总结的表格进一步补充:

#节目号PMT PIDES PIDES说明SDT表信息
1164030x1300x131MPEG2视频ProSieben
0x132MPEG2音频
0x137MPEG2私用PES
0x138MPEG2私用PES
2164080x1800x181MPEG2视频SAT.1
0x182MPEG2音频
0x187MPEG2私用PES
0x188MPEG2私用PES
3163940xA00xa1MPEG2视频KABEL1
0xa2MPEG2音频
0xa7MPEG2私用PES
4163980xE00xe1MPEG2视频N24
0xe2MPEG2音频
0xe7MPEG2私用PES

NIT表

在国内,NIT表一般会给出整个网络的频点列表。 在搜索主频点的同时解析出NIT表,就可以得到这个网络的频点列表。 机顶盒按顺序对所有频点锁频、解析,就可以将整个网络的业务搜索出来了。

但在国外,一般不会有这样的情况。首先,小运营商只是租用其中一个或几个频点,不可能对整个网络“指手画脚”,自然就不能定义NIT表了。 而大运营商,它们有自己的业务群(Bouquet),更倾向于使用BAT表来组织自己的节目。

参考文档

References

#文档名称作者
1《1.从TS流到PAT和PMT》林晓州
2《PSI/SI深入学习》林晓州
3《En300468.V1.7.1_Specification for SI in DVB Systems.pdf》European Standard
4《数字视频广播中文业务信息规范》国家广播电影电视总局
5《数字电视业务PSI-SI学习系列》网络

版本信息

Version Information

#发布日期版本更新内容作者审核
12013年08月09日V1.0文档《1.从TS流到PAT和PMT》林晓州——
22016年02月19日V2.0整合了多个文档资料,对PSI/SI学习所需的知识进行系统的总结。林晓州——