PMT (Program Map Table )节目映射表
PMT所在分组的PID由PAT指定,所以要先解出PAT,再解PMT
PMT中包含了属于同一节目的视频、音频和数据原始流的PID。
找到了PMT,解多路复用器就可找到一道节目对应的每个原始流的PID,再根据原始流
PID,去获取原始流。如下图:PID1和PID2分别对应某道节目的视频原始流和音频原始流
的PID。
![](http://blog.21ic.com/uploadfile-/2008-1/53190.91643737.jpg)
![](http://blog.21ic.com/UploadFiles/2008-3/5114636926.jpg)
二、数据结构
(1)TS分组
transport_packet()
{ sync_byte // 8 transport_error_indicator //1 payload_unit_start_indicator //1 transport_priority // 1
PID //13 transport_scrambling_control // 2 adaptation_field_control //2 continuity_counter //4 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 } } } |
sync_byte 同步字节,固定为0x47 ,表示后面的是一个TS分组,当然,后面包中的数据是不会出现0x47的
transport_error_indicator 传输错误标志位,一般传输错误的话就不会处理这个包了
payload_unit_start_indicator 这个位功能有点复杂,字面意思是有效负载的开始标志,根据后面有效负载的内容不同功能也不同,后面用到的时候再说。
transport_priority 传输优先级位,1表示高优先级,传输机制可能用到,解码好像用不着。
PID 这个比较重要,指出了这个包的有效负载数据的类型,告诉我们这个包传输的是什么内容。前面已经叙述过。
transport_scrambling_control加密标志位,表示TS分组有效负载的加密模式。TS分组首部(也就是前面这32bit)是不应被加密的,00表示未加密。
adaption_field_control 翻译为“调整字段控制”,表示TS分组首部后面是否跟随有调整字段和有效负载。01仅含有效负载,10仅含调整字段,11含有调整字段和有效负载。为00的话解码器不进行处理。空分组没有调整字段。
(2)PAT
program_association_section() {
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 for (i=0; i<N;i++) { program_number // 16 reserved // 3 if(program_number == '0') { network_PID // 13 } else { program_map_PID // 13 } } CRC_32 // 32 } |
table_id 固定为0x00 ,标志是该表是PAT
section_syntax_indicator 段语法标志位,固定为1
section_length 表示这个字节后面有用的字节数,包括CRC32。假如后面的字节加上前面的字节数少于188,后面会用0XFF填充。假如这个数值比较大,则PAT会分成几部分来传输。
transport_stream_id 该传输流的ID,区别于一个网络中其它多路复用的流。
version_number 范围0-31,表示PAT的版本号,标注当前节目的版本.这是个非常有用的参数,当检测到这个字段改变时,说明TS流中的节目已经变化了,程序必须重新搜索节目.
current_next_indicator 表示发送的PAT是当前有效还是下一个PAT有效。
section_number 分段的号码。PAT可能分为多段传输,第一段为00,以后每个分段
加1,最多可能有256个分段
last_section_number 最后一个分段的号码
program_number 节目号
network_PID 网络信息表(NIT)的PID,网络信息表提供了该物理网络的一些信息,和电视台相关的。节目号为0时对应的PID为network_PID
program_map_PID 节目映射表的PID,节目号大于0时对应的PID,每个节目对应一个
CRC_32 CRC32校验码
上面program_number,network_PID,program_map_PID 是循环出现的。program_number等于0时对应network_PID,program_number等于其它值时对应program_map_PID。
举个例子,下述流为带PAT的TS分组:
47 40 00 1c 00 00 b0 15 13 f6 e7 00 00 00 00 e0 10 00 01 e0 20 00 02 e0 21 1a 34 b4 77 ff…………..ff
其中红色的四个字节是TS分组头部,用数据结构解出首部,得到PID=0x00,表示为该分组的有效负载是PAT。蓝色的00称为“指针域”----Pointer field,表示了一个偏移量,即从后面第几个字节开始是PAT部分。为00表示后面紧接着的就是PAT:00 b0 15 13 f6 e7 00 00 00 00 e0 10 00 01 e0 20 00 02 e0 21 1a 34 b4 77
再利用PAT的数据结构解出PAT,得到如下信息:
---------------PAT Information-------------
table_id: 00
section_syntax_indicator: 01
section_length: 0015
transport_stream_id: 13f6
version_number: 13
current_next_indicator: 01
section_number: 00
last_section_number: 00
program_number: 0000
network_PID: 0010
program_number: 0001
program_map_PID: 0020
program_number: 0002
program_map_PID: 0021
CRC_32: 1a34b477
可以看出,此PAT只有一段,包含了三个节目,节目号0000对应于network_PID=0010 ,节目号0001对应于program_map_PID =0020,节目号0002对应于program_map_PID =0021,从实际的角度,我们应该把这三个节目号理解为三个频道,第一个频道中的内容是网络信息,第二、三个频道包含了节目信息。在数字电视中,一个频道即对应于一个频点,如498MHZ,一个频道上可以有多个节目,后面的PMT即是告诉了我们某个频道中所有节目对应的PID。
于是现在就搜寻PID=0x0020的TS分组,即是频道2对应的PMT信息。
( 其实楼主的理解不是完全正确,transport_stream_id标识了一个唯一的传输流(每一个传输流对应一个频点,如498MHz),一个PAT表表示一个流里面的信息。
上面的三个节目号理解为三个频道是正确的,但在数字电视中,一个频道对应的也是一个节目,而不是一个频点(当然节目号为0时对应的是NIT的PID)。 )
(3)PMT
TS_program_map_section() { 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 for (i=0; i<N; i++) { descriptor() } for (i=0;i<N1;i++) { stream_type //8 reserved //3 elementary_PID //13 reserved //4 ES_info_length //12 for (i=0; i<N2; i++) { descriptor() } } CRC_32 //32 } |
table_id 固定为0x02 ,标志是该表是PMT
section_syntax_indicator
section_length
version_number
current_next_indicator 以上四个字段意思和PAT相同,可参考上面解释
section_number
last_section_number 以上两个字段意思和PAT相同,不过值都固定为0x00,我觉得这样的原因可能是因为PMT不需要有先后顺序,因为先定义哪个节目都是无所谓。
program_number 节目号,表示该PMT对应的节目
PCR_PID PCR(节目时钟参考)所在TS分组的PID,根据PID可以去搜索相应的TS分组,解出PCR信息。
program_info_length 该节目的信息长度,在此字段之后可能会有一些字节描述该节目的信息
stream_type 指示了PID为elementary_PID的PES分组中原始流的类型,比如视频流,音频流等,见后面的表
elementary_PID 该节目中包括的视频流,音频流等对应的TS分组的PID
ES_info_length 该节目相关原始流的描述符的信息长度。
![](http://blog.21ic.com/uploadfile-/2008-1/60148.83213883.jpg)
还是举个例子,下述是一个包含PMT的TS分组,
47 40 20 1c 00 02 b0 1f 00 01 e7 00 00 e1 00 f0 00 02 e1 00 f0 05 02 03 b2 44 5f 04 e1 10 f0 03 03 01 67 c9 ab c8 d2
红色的四个字节是TS分组头部,蓝色的00是“指针域”,意义同PAT中的指针域。所以下面的数据就是PMT的内容:02 b0 1f 00 01 e7 00 00 e1 00 f0 00 02 e1 00 f0 05 02 03 b2 44 5f 04 e1 10 f0 03 03 01 67 c9 ab c8 d2
再解出PMT,得到下列信息:
table_id: 02
section_syntax_indicator: 01
section_length: 01f
program_number: 0001
version_number: 13
current_next_indicator: 01
section_number: 00
last_section_number: 00
PCR_PID: 0100
program_info_length: 000
descriptor:
steam_type: 00
elementary_PID: 0001
ES_info_length: 000
descriptor:
steam_type: 02
elementary_PID: 0001
ES_info_length: 005
descriptor: 02 03 b2 44 5f
steam_type: 04
elementary_PID: 0011
ES_info_length: 003
descriptor: 03 01 67
CRC_32: c9abc8d2
可以看出,该节目号0001包含了三个流的信息,流类型分别为00,02,04,00的流为保留值,可以不考虑,02表示原始流为视频流,其elementary_PID为0001,04表示原始流为音频流,其elementary_PID为0011,两个流分别还带有descriptor(描述符),说明了该原始流的一些信息。
得到了这个elementary_PID,再从后面的传输流中找到PID为这个值的TS分组,其有效负载即为这个原始流的数据,获取数据送到解码器,即可还原这个视频或音频了。
三、总结
上面的都是一些零散的知识,跟我们实际应用有什么关系呢?下面就是一个简易的应用过程---搜台。搜台过程大致如下:
先调整高频头到一个固定的频率(如498MHZ),如果此频率有数字信号,则相关芯片会自动把TS流数据传送给MPEG- 2 decoder. MPEG-2 decoder先进行数据的同步,也就是等待完整的Packet的到来.然后循环查找是否出现PID== 0x0000的Packet,如果出现了,则马上进入分析PAT的处理,获取了所有的PMT的PID.接着循环查找是否出现PMT,如果发现了,则自动进入PMT分析,获取该频段所有的频道数据并保存.如果没有发现PAT或者没有发现PMT,说明该频段没有信号,进入下一个频率扫描。
上述过程主要涉及到PAT和PMT的一些解码和解复用知识,这也是目前我学习到的,当然,数字电视涉及到的知识远远不止这些,解码方面就还包括调整字段的处理,SI(业务信息)应用,时钟的处理,CA加密解MI系统等,还需要继续的学习和实践。