TS系列二:从TS到PAT和PMT


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

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

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

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

什么是PID?

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

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

TS流中PID的分配
PID值说明
PAT 0x0000 -
CAT0x0001-
TSDT 0x0002 -
预留 0x0003 至0x000F
NIT, ST 0x0010 -
SDT , BAT, ST 0x0011 -
EIT, ST 0x0012 -
RST, ST 0x0013 -
TDT, TOT, ST 0x0014 -
网络同步 0x0015
预留使用 0x0016 至 0x001B
带内信令 0x001C
DIT 0x001E
SIT 0x001F
解复用程序需要使用到的表格只有PAT、PMT、SDT;而CA解扰还需要使用CAT;EPG则还要有NIT、EIT、TDT、TOT等表。

使用工具说明

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

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

在这里插入图片描述

一切从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的PID program_map_PID 表示本频道使用哪个PID做为PMT的PID。 因为可以有很多的业务,因此DVB规定PMT的PID可以由用户自己定义

解析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)数据(47 40 00 1C)如下:

位号012345678910111213141516171819202122232425262728293031...
Packet(二进制) 0 1 0 0 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 ...
Packet(十六进制) 4 7 4 0 0 0 1 C ...
Packet Header信息0: sync_byte=0x471 2 3 4: PID (这里是0x07e5)5 6 7 ...

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

Packet Header(包头)信息Demo

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

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

位号 0 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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ...
Binary 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 0 0 1 1 1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 1 0 0 0 0 0 0 0 0 ...
Hex0 0 B 0 1 D 2 2 0 1 C F 0 0 ...
结构0*: table_id=0x001*2*3*4*: section_length (这里是0x01D)5*6*7*8*9*10*...
# 字段名占位具体值次序说明
0*table_id8 bits 0000 0000(即0x00) 第0个字节
00
PAT的table_id只能是0x00
1* section_syntax_indicator 1 bit 1 第1、2个字节
B0 1D
段语法标志位,固定为1
2*zero1 bit0
3* reserved 2 bits 11 (Binary)
4* section_length 12 bits 00 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_number 5 bits 0 01 11 一旦PAT有变化,版本号加1
8* current_next_indicator 1 bit 1 当前传送的PAT表可以使用,若为0则要等待下一个表
9*section_number 4 bits 00 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_number 16 bits-----
- reserved 3 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

位号0 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 ...
Binary 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 ...
Hex0 0 0 0 E 0 1 0 ...
结构1*: program_number = 0x00002*: reserved 3*: network_id = 0x10 ...
# 字段名 占位 具体值 说明
1* program_number 16 bits 0x0000 program_number = 0x0000
2* reserved 3 bits 111 -
3* program_map_PID 13 bits 0x0000 因为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

位号 0 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 ...
Binary 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 1 1 0 0 0 0 1 0 0 1 1 0 0 0 0 ...
Hex4 0 1 3 E 1 3 0 ...
结构1*: program_number = 0x4013(即十进制16403) 2*: reserved 3*: program_map_PID = 0x130(即PMT_PID为0x130) ...
# 字段名 占位 具体值 说明
1* program_number 16 bits 0x4013 program_number = 0x4013(即十进制16403)
2* reserved 3 bits 111 -
3* program_map_PID 13 bits 0x130 因为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表分析

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

分析如下:

位号 0 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 ...
Packet(二进制) 0 1 0 0 0 1 1 1 0 1 0 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 1 ...
Packet(十六进制) 4741 3 0 1 9 ...
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

位号 0 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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
Binary 0 0 0 0 0 0 1 0 1 0 1 1 0 0 0 0 0 1 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 1 0 0 0 1 0 1
Hex 0 2 B 0 4 3 4 0 1 3 C 5
结构 0*: table_id=0x02 1* 2* 3* 4* 5*: 0x4013 = 16403 6* 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

位号 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 ...
Binary 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 ...
Hex 0 0 0 0 E 1 3 1 F 0 0 0 ...
结构 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号码

位号 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 ...
Binary 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 1 0 0 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 ...
Hex 0 2 E 1 3 1 F 0 0 3 ...
结构 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

位号 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 ...
Binary 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 ...
Hex 5 2 0 1 0 1 ...
结构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 PID ES PID ES说明
1 16403 0x130 0x131 MPEG2视频
0x132 MPEG2音频
0x137 MPEG2私用PES
0x138 MPEG2私用PES
2 16408 0x180 0x181 MPEG2视频
0x182 MPEG2音频
0x187 MPEG2私用PES
0x188 MPEG2私用PES
3 16394 0xA0 0xa1 MPEG2视频
0xa2 MPEG2音频
0xa7 MPEG2私用PES
4 16398 0xE0 0xe1 MPEG2视频
0xe2 MPEG2音频
0xe7 MPEG2私用PES

TS的复用与解复用

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

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

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

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

DVB搜台过程

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 PID ES PID ES说明SDT表信息
1 16403 0x130 0x131 MPEG2视频ProSieben
0x132 MPEG2音频
0x137 MPEG2私用PES
0x138 MPEG2私用PES
2 16408 0x180 0x181 MPEG2视频SAT.1
0x182 MPEG2音频
0x187 MPEG2私用PES
0x188 MPEG2私用PES
3 16394 0xA0 0xa1 MPEG2视频KABEL1
0xa2 MPEG2音频
0xa7 MPEG2私用PES
4 16398 0xE0 0xe1 MPEG2视频N24
0xe2 MPEG2音频
0xe7 MPEG2私用PES

NIT表

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值