MPEG-TS 基础:包结构、PID、PAT、PMT
做协议分析的人都知道,MPEG-TS 是数字电视、广电、甚至 IP 流里绕不开的东西。说白了,它就是个固定长度的“集装箱”——每个箱子 188 字节,不多不少。我刚开始接触 TS 时,看着一堆十六进制数完全懵圈,后来真正去抓了一次流,才明白它为什么这么设计。
TS 包结构——188 字节的“硬规矩”
每个 TS 包最前面 4 个字节是包头,后面 184 字节是负载。我把头部字段列个表,你对照抓包工具看就清楚了:
| 字段 | 长度(bit) | 作用 |
|---|---|---|
| 同步字节 | 8 | 固定 0x47,定位包起始 |
| 传输错误指示 | 1 | 1 表示当前包有错误,解码器应丢弃 |
| 有效载荷单元起始指示 | 1 | 1 表示负载是 PES 或 PSI 的起始 |
| 传输优先级 | 1 | 用于流中优先级区分 |
| PID | 13 | 包标识符,核心字段 |
| 传输加扰控制 | 2 | 00 未加扰,其他表示加扰模式 |
| 自适应字段控制 | 2 | 01 仅负载,10 仅自适应,11 两者都有 |
| 连续计数器 | 4 | 0~15 循环,检测丢包 |
PID——每路流的“身份证”
13 位 PID,范围 0~8191。其中 0x0000 是 PAT(节目关联表),0x0001 是 CAT,0x1FFF 是空包。其余 PID 可以分配给视频、音频、字幕等。我记得有一次调试机顶盒,发现特定频道黑屏,一查 PID 表才发现视频 PID 写错了……嗯,从那以后我抓流第一件事就是先过滤 PAT。
我个人习惯在 Wireshark 里直接加 ts.pid == 0x0000 过滤,快速定位 PAT 包。你可以试试看。
PAT & PMT——节目信息的“导航地图”
PAT(Program Association Table)承载在 PID=0x0000 的 TS 包中。它本身不包含节目内容,而是告诉你:每个节目的 PMT 在哪个 PID 上。PMT(Program Map Table)则进一步列出每个节目的音视频流 PID、编码格式等信息。
我曾经在工作中遇到一个奇葩问题:某节目只有音频没有视频。抓包后发现 PMT 里确实有两个流,但视频流的 PID 始终没有数据包。最后发现是编码器配置错了。你想想看,如果 PAT/PMT 不完整,解码器根本不知道该去哪个 PID 拿数据。
整体关系——看一眼这张图就懂了
实战中要注意的几个坑
- PAT/PMT 必须周期性发送:标准要求每 100ms 内至少一次。我曾遇到一个编码器配置了“仅开头发一次 PAT”,结果解码器在切换频道时直接黑屏。
- PID 冲突:同一 TS 流内所有 PID 必须唯一。如果两个节目不小心用了同一个视频 PID,解码器会疯掉。
- 空包问题:PID=0x1FFF 的空包可以忽略,但有些设备会用空包做填充速率匹配,不要误以为这些包有数据。
小结
记住一句话:没有 PAT,你连节目在哪都不知道;没有 PMT,你连音视频数据在哪都不知道。理解 TS 包结构 + PID 筛选 + PAT/PMT 解析,就等于拿到了 TS 流的钥匙。动手抓一次流,跟着 PAT 走一遍,你会发现这东西其实没那么玄乎。