第二章:TS序列基础——MPEG-TS概念、包结构及包头字段归纳

这一章,我们得把地基打牢。

很多新人一上来就抱着分析仪抓TS流,看到满屏的十六进制就懵了。相信我,这很正常。想读懂TS流,你得先搞清楚传输流的“基本单元”——TS包长什么样。

2.1 MPEG-TS:它到底是什么?

MPEG-TS,全称是 MPEG-2 Transport Stream。你想想看,电视台要用一个频道同时播好几个节目,怎么做到的?就是靠TS把视频、音频、字幕、电子节目单全搅在一起,打包发送。

说白了,它是一个“复用容器”。里面装的不仅仅是音视频数据,还有各种控制表和系统信息。它被设计在高误码率的信道中传输,因此天生自带纠错和同步机制。我个人习惯,把它看作一根“数据水管”,内部划分成等长的小节(TS包),每一节都有编号和标签,方便接收端重新组装。

核心概念速查:

TS = Transport Stream(传输流),面向广播/网络等有损信道。

2.2 TS包结构:188字节的讲究

TS包长度固定为188字节(部分应用场景有204字节的变体,但188是基础)。为什么是188?这跟当时ATM信元的对齐需求有关,我们不需要深究,记住这个长度就行。

整个包可以拆成三段:包头 + 自适应区(可选) + 有效载荷。

  1. 包头(4字节):这是灵魂。后面重点讲。
  2. 自适应区:可长可短,后面讲PTS/DTS时再细说。
  3. 有效载荷:剩下的字节,装的是真正的音视频数据或控制表。

2.3 包头字段解析:你必须要啃下的骨头

来看看这4字节包头。我在刚接触分析仪时,第一步就是盯着这4个字节看,慢慢就找到感觉了。

字段名称 比特数 取值范围/说明 我的解读
同步字节 8 固定 0x47 TS包的门神。找到它就找到了包的起点。
传输错误指示 1 0或1 前级解码器发现不能纠错的错误时置1。我遇到过一个情况,就是这位置1了,后面还傻乎乎地解析,当然全是乱码。
载荷单元起始指示 1 0或1 如果置1,说明有效载荷里是一个新PES包或新PSI表的起点。这是分析的关键。
传输优先级 1 0或1 废话少说,基本不用管。
PID 13 0x0000 - 0x1FFF 这是最重要的字段。 数据流的身份证。0x0000是PAT表,0x0010是NIT表,0x1FFF是空包。其他字段区分不同的视频、音频流。
传输加扰控制 2 0~3 00表示未加密。01/10/11分别表示不同等级的加密。搞解密的人喜欢在这个字段上下功夫。
自适应区控制 2 0~3 01=无自适应区,只有有效载荷;10=只有自适应区,无有效载荷;11=自适应区+有效载荷。我新手时忽略了它,导致解析偏移,代码崩溃,现在做工具时会特别检查这个字段。
连续计数器 4 0~15,循环 同一个PID包的序列号。解码器靠它判断是否丢包。如果跳数,说明网络有损耗。
避坑指南: 我曾经在处理多节目复用流时,连续计数器的值设计踩了坑。发送端同时发送PAT和PMT,两者用了同一套计数器(虽然有不同PID)。我傻乎乎地按PID单独校验,结果发现计数整体是错乱的。后来才明白:计数器是按PID分别维护的!

2.4 关于同步字节 0x47

你问我为什么是 0x47? 0x47的二进制是 0100 0111。你想,在比特流里,每隔188个字节就有一个 0100 0111 这样的模式。分析仪就是靠这个来锁定TS包的边界。

我用过的协议分析仪,一般都有“自动同步”功能,就是不断扫描数据,找到连续若干个 0x47 的位置。如果在1M字节范围内找不到1个同步字节,那基本可以断定这不是TS流。但这个同步字节不够强壮。如果数据里恰好有 0x47 连续重复,就会被误判。嗯,这里要注意。

给初学者的提醒: 当你第一次在十六进制窗口中看到一串 47 xx xx xx ... 47 xx xx xx,你就知道,这就是TS流的真面目。第一字节永远是这个标记。

2.5 本章知识体系:一张图看懂

我来画一张图,把TS包的层级关系理清楚。你对照着看一下,会清晰很多。

TS包结构框架 TS Packet (188 字节) 包头 4 字节 自适应区 0 ~ 183 字节 (可选) 有效载荷 剩余字节 包头内部字段 (4字节): 0x47 传输错误指示 (1) 起始指示 (1) PID (13) 加扰控制 (2) 自适应控制 (2) 连续计数器 (4) 核心信息卡: 同步字节 0x47 :TS包的“门神”,每188字节重复一次 PID 0x0000 : PAT表 | PID 0x0010 : NIT表 | PID 0x1FFF : 空包

2.6 实践小练习:动手解析

光看不练是假把式。我们对着一个真实的TS包来拆解它。

// 原始TS包流 (十六进制)
47 00 00 10 00 01 F0 00 00 00 00 00 00 00 00 00
00 00 ... (共188字节)
  1. 字节0:0x47 -> 同步字节。OK。
  2. 字节1-2:打包成16位 0x0010。哎呀,这里面藏着PID的前8位和部分标志位。我得教你拆一下:0x0010 二进制是 0000 0000 0001 0000。高8位是 0x00,低8位是 0x10。有效的PID是13位:从最高位开始取13位,得到 0 0000 0001 0000 = 0x0010 (NIT表)。
  3. 字节3:0x10 -> 二进制 0001 0000。前四位是连续计数器?不对!自适应控制在后,加扰控制在前。你查引用表:自适应控制是2位,这里是 01(仅有效载荷)。加扰控制是 00(未加扰)。后面的4位是连续计数器 0000。

看到了吗?通过这4个字节,我们就定位到了PID和有效载荷的位置。这就是协议分析仪解码的第一步。

在实际工作中,这种逐字段的解析能力非常基础。当你拿着分析仪抓到的未知流时,能手动校验几个包,比完全依赖自动解析要可靠得多。