PSI/SI表的深度摘要-3

8 篇文章 1 订阅

以前理解PSI的包和段都还不够深刻,以至于写的复用部分,表生成部分逻辑性,可用性不高,虽然使用没啥问题的。在写复用模块的时候,对PSI理解度不够的话,再去改复用模块,挺麻烦的,很费神。

常用的PSI/SI表:

PSI表(4类):PAT,PMT,CAT,NIT(NIT当前网络 和 NIT其他网络)。

SI表:BAT,SDT(SDT当前TS 和 SDT其他TS),TDT,TOT,

EIT(1.EIT现行传输流,当前/后续事件信息;2.其他传输流,当前/后续事件信息;3.现行传输流,事件时间表信息;4.其他传输流,事件时间表信息)

也就是说,举个例子:NIT当前网络段NIT_Current只有1子表;NIT其他网络NIT_Others可能多个子表,那么可能添加多个段到NIT_Others节点下。同理,只要有Current的都只有1个子表(顶多256个分段,看section_number,EIT_current除外,和节目号也有关)。

今天再整理一下:

1.PSI各种表最基本单位是段section,若以包packet来进行复用,遇到一个表由多个段组成的时候,就感觉明显了,解析各种表也应该由段语法来解析。

所以,分析PSI文件的时候,我就根据pid和crc32来判断是一个唯一的段。当这个crc32重复1次时,这个段就重复了1次(crc32重复1次);来了n次,则crc32重复n次。

PAT,PMT,CAT都没有其他流信息(“PSI 中的PAT、CAT、PMT只提供了它所在的复用流(现行符复用流)的信息”,解释一下就是PAT,CAT,PMT都只有1个段),

所以,只有1个段,若文件中有多个PAT段,那么就出现重复段(用TSExpert可以看见该段重复了多少次,但该软件重复次数应减1;比如2个PAT段,重复为1,但TSExpert显示的是2;若写为出现次数为2,那比较恰当TSExpert写得非常优秀的了。);

其他的PSI表可能很多个段,特别是EIT表,甚至上万个段,解析起来很麻烦;那你需要比较当前的段的crc32是否和这万多个段是否重复,效率是比较低的。

理论上,发觉2个相同crc32后直接判断重复了,那我们不必读取下一个包了,觉得PSI表获取齐了;但这样还是有bug,EIT段就是可能忽然增加几个段的,所以,程序员需要选择把文件读取完毕,效率低一些还是只要有2个相同的crc32就断定这个段获取齐全,不必读取整个文件了。

2.发表:

(1).一个SDT段有6个包,若这个段发送期间,有BAT的段假设为2个包进入,那怎么准确提取SDT表的信息呢?

(2).提取PSI表信息时候,是必须先分析完PAT表,从中获取PMT表后,再解析其他表的吗?(PAT表解析PMT表就是:节目号<--->PMT表的pid)

答1:各种PSI表发表间隔,发表规则是有规定的。比如,一个SDT表有多个段,那发表的时候,是一个段一个段的逐个发送(一个段由多个包组成),发送的时候是发送一个段,而这个段之间是不允许有其他PSI表进入发送的,但发送的这个段各个包之间会插入音视频的pid包(这个是我用软件观察各个包的发表顺序总结的)。这个EIT段和下个EIT段之间的时间间隔才是EIT的发表间隔。所以,问题1的情况是不允许存在的情况。另外,我们可以设想一下,在标准以太网环境中,MTU通常设置为1500字节,一个段一般不大于1024字节,一个UDP包最大7*188B=1316B,所以,一次可以发完一个分段的数据(6*188=1128B,去除包头6*4+1=25B,能装完一个分段的数据的)。

答2:当一个文件用来分析的时候,可能先出来PMT表等,SDT表等,那等我先解析PAT表后解析出PMT表,再将读取文件的指针放到文件开头,再解析其他表,这样效率不是不高?!

所以,我觉得直接将文件预想为足够大,PMT不可能只出现在PAT前,解析了PAT表后一定能再次解析到PMT表,这样就不必再将文件指针放到文件开头,继续分析就是的了。有时候算法能照顾大多数情况就可以的了,面面俱到还是比较困难的。

3.段结构:

(1).其实1个PSI表的段语法虽然看上去都不同,但实际上是遵从段语法的,在写程序时,我觉得应该一个段结构=段头(段信息)+段内容+crc32构成。

段头的长度是固定的(8字节,到last_section_number为止),内容也是固定的,只是x_id(16位)在SDT表中是transport_stream_id ,BAT中bouquet_id,NIT中network_id,EIT中service_id,PAT中 Transport_tream_id,PMT中 Program_number 。CAT比较特殊,x_id是保留的了,全部置1。

TDT和TOT不遵从于段语法,段语法指示符  section_syntax_indicator: 1 位字段,为“0” 。而上面这些PSI/SI全部是遵从段语法,section_syntax_indicator=1的。

所以,建议TDT和TOT不遵从段语法,可以取个统称叫时间信息表,需单独处理提取出 时间段结构Time_section_st;其他表则用段结构Psi_section_st。下一步,有这 段结构信息的表就可以用其段内容进行分析了,比如Psi_section_st->分析为PAT段Psi_section
 

4.表的解析:

(1).先找到PAT表,获知到每个节目的PMT表的pid(一般3套节目3个PMT表),再解析PMT表。那么,这就意味着一个ts流含5个包:先来3个PMT包,再来1个PAT包,最后1个PMT包,则前3个PMT的包由于没解析PAT表,而会显示未知包,最后显示出来的就只有1个PAT包,1个PMT包的了。

(2).相同的pid包则连续计数是顺序相接的,比如SDT表和BAT表,TDT表和TOT表,需要靠table_id来区分是什么表的了。

22:33 2018/1/22

其他知识:

一个分段(多个包构成的段)内是可以插入别的pid的PSI包的:比如一个比较长的BAT分段,section_length=919(<1021Byte),需6个包装载,这6个包之间就可能有别的psi包(比如EIT包)。
故码流分析的时候,

方法1:

先找到起始包(Payload_unit_start_indicator==1),记录该包位置iPacket,再把续帧找齐了,再分析下一个包(iPacket+1)。

方法2:

按pid和table_id把文件全部读取一遍,再过滤出该分段(效率低,速度慢了呢)。

方法3:

先过滤pid,再用table_id分析出各个不同的psi分段,估计这种方法用的最多。比如过滤出0x11的包(可能是SDT或者BAT),再用table_id判断,table_id=0x42是SDT的当前sdt分段,0x46是其他sdt分段,0x4A是bat表,比如1个0x42分段由6个188的包构成,Payload_unit_start_indicator ==1,第1个包具有段头信息(section_number等段信息),后续5个包则没有这些信息。 这6个包之间可以插入别的psi包(因pid不同,故不会引起冲突),但不能SDT表中间插入了BAT表的分包。


20:30 2023/7/3

【1个分段的构成】:

       最多6个包;分段内容=1.table_id 1B  +2. secLen 2B +3.分段内容(包含crc32);也可以看作另外一种结构 分段内容 = 段头(8B) + 分段内容(包含crc32)
      标准规定:段长度 section_length:12 位字段,前两位置“00”。它表示从该字段的下一个字节开始的本段的字节长度,并包含4字节的CRC。section_length 不能超过 1021,这样整个段的最大长度为 1024 字节。
      按道理说,6个包可以装的段数据为:包1:188-5(包头4B+1B Point_files)-3(table_id 1B+ secLen 2B)=180;包2:~包6:5*184=920; 故可以装1100字节;但标准固定只能1021字节,剩余的用0xFF填充的。 

16:04 2023/7/18

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值