4、TS格式深度解析:TS的Packet结构(188字节)、PES封装、PAT/PMT表、TS在HLS中的分片延迟
聊到封装格式对延迟的影响,TS(Transport Stream)是个绕不开的话题。很多做直播的老工程师一听到TS,第一反应就是“稳”,但第二反应往往是“延迟有点高”。
我个人习惯把TS比作一个集装箱货轮——每个箱子大小固定,装得满满当当,但装卸流程复杂。你想想看,188字节一个包,这尺寸在MPEG-2时代是精心设计过的,适合在有损信道里传输。但到了今天,这个固定尺寸反而成了延迟的“隐形杀手”。
4.1 TS Packet结构:188字节的“铁律”
TS包的大小为什么是188字节?我记得刚入行时也问过这个问题。其实原因很简单:当年ATM信元是53字节,MPEG-2为了兼容性,选了188字节(4个ATM信元 + 填充)。这个尺寸一直沿用至今。
每个TS包的结构如下:
| 字段 | 长度(字节) | 说明 |
|---|---|---|
| 同步字节 | 1 | 固定为0x47,用于包同步 |
| 传输错误指示符 | 1 bit | 置1表示当前包有错误 |
| 有效载荷单元起始指示符 | 1 bit | 标识PES或PSI数据的起始位置 |
| 传输优先级 | 1 bit | 高优先级包优先传输 |
| PID | 13 bits | 包标识符,核心字段 |
| 传输加扰控制 | 2 bits | 加扰模式 |
| 自适应字段控制 | 2 bits | 00=保留,01=无自适应字段,10=仅有自适应字段,11=两者都有 |
| 连续计数器 | 4 bits | 0-15循环,用于检测丢包 |
| 自适应字段(可选) | 可变 | 包含PCR、填充字节等 |
| 有效载荷 | 可变 | PES数据或PSI表 |
关键点:PID是TS包的“身份证”。同一个视频流的所有包共享同一个PID。解复用器就是靠PID来区分音频、视频和字幕流的。
这里有个坑——自适应字段。我曾经在项目里遇到过,某个编码器在PCR(节目时钟参考)插入时,把自适应字段撑得很大,导致有效载荷只剩几个字节。你想想看,188字节的包,有效载荷只有10个字节,传输效率低得吓人。所以,自适应字段的长度直接影响有效带宽。
4.2 PES封装:从ES到TS的“中间人”
原始的音视频数据(ES,Elementary Stream)不能直接塞进TS包。中间需要一层PES(Packetized Elementary Stream)封装。PES的作用说白了就是给ES数据加个“信封”,写上时间戳、数据长度等信息。
PES包的结构:
- PES起始码:固定为0x000001,后面跟流ID
- PES长度:表示PES包的长度(0表示长度可变)
- 可选字段:PTS/DTS(解码时间戳/显示时间戳)、ESCR、ES速率等
- PES数据:实际的ES数据
个人经验:PES包的大小不是固定的。对于视频,我通常建议一个PES包包含一个视频帧。这样在解封装时,可以精确地按帧提取数据。但要注意,如果PES包太大,会占用多个TS包,增加解复用的复杂度。
嗯,这里要注意:PTS和DTS是PES里最重要的字段。PTS告诉解码器“什么时候显示这帧”,DTS告诉解码器“什么时候解码这帧”。对于B帧来说,DTS和PTS是不同的,这也是延迟的一个来源。
4.3 PAT/PMT表:TS流的“导航系统”
一个TS流里可能包含多个节目(比如多个频道)。解复用器怎么知道哪个PID对应哪个节目?这就需要PAT(节目关联表)和PMT(节目映射表)了。
PAT表:PID固定为0x0000。它列出了所有节目的编号,以及每个节目对应的PMT表的PID。
PMT表:PID由PAT指定。它列出了某个节目包含的所有流(视频、音频、字幕等),以及每个流的PID和编码类型。
我画了一张图,帮你理清它们的关系:
避坑指南:我曾经遇到过一个奇葩问题——PAT表每100ms才发送一次,而PMT表每500ms才发送一次。结果解复用器启动后,要等500ms才能拿到完整的节目信息。这在直播场景下,意味着首屏延迟直接多了500ms。所以,PAT/PMT的发送间隔直接影响加入直播的延迟。我建议PAT每40ms发送一次,PMT每100ms发送一次。
4.4 TS在HLS中的分片延迟
HLS(HTTP Live Streaming)是TS最典型的应用场景。HLS把TS流切成一个个小文件(分片),每个分片通常包含2-10秒的数据。客户端通过下载这些分片来实现播放。
分片延迟是怎么来的?我拆解给你看:
- 编码延迟:编码器需要积累一个GOP(Group of Pictures)的数据才能开始输出。GOP越大,延迟越高。
- 分片生成延迟:切片器需要等待一个分片的数据全部到达,才能生成完整的TS文件。如果分片时长是6秒,那至少等6秒。
- 索引更新延迟:HLS的m3u8索引文件需要定期更新。通常每过一个分片时长,索引才会更新一次。
- 客户端下载延迟:客户端下载分片需要时间,尤其是网络不好时。
你想想看,如果每个分片是6秒,那从采集到播放,延迟轻松超过10秒。这就是为什么HLS的延迟通常比RTMP高。
核心结论:TS格式的固定包结构(188字节)和PES封装机制,决定了它在低延迟场景下不如FLV或fMP4。但TS的强项是抗丢包和兼容性——在有线电视、卫星广播等场景下,TS依然是王者。
我记得有一次做HLS低延迟优化,把分片时长从6秒砍到2秒,同时把GOP大小从60帧降到30帧。延迟从12秒降到了4秒左右。但代价是服务器压力大了3倍,因为分片数量暴增。嗯,这就是典型的“用计算换延迟”。
最后说一句:TS格式虽然“老”,但它的设计思想——固定包长、PID复用、PSI表导航——至今仍在影响很多现代协议。理解TS,就是理解流媒体封装的底层逻辑。