m3u8 的标签按用途可分五类:结构、直播、切片、加密、低延迟。 真正常用的不到十个,其余都是特定场景才需要。
5.2.1 只讲了四个必备标签,这一节把标签系统看全。 5.4 转去讲 TS 与 PS 的分工,那是「切片里装什么」的问题。
一、标签分五类
① 结构类:#EXTM3U、#EXT-X-VERSION。
这类决定文件本身怎么被读,必看。
② 直播类:#EXT-X-TARGETDURATION、#EXT-X-MEDIA-SEQUENCE。
决定刷新节奏与序号起算,必看。
③ 切片类:#EXTINF、#EXT-X-BYTERANGE、#EXT-X-DISCONTINUITY。
按需看,做广告插入或单文件切片时必须懂。
④ 加密类:#EXT-X-KEY、#EXT-X-MAP。
用 AES-128 加密时才需要。
⑤ 低延迟类:#EXT-X-PART、#EXT-X-PRELOAD-HINT。
只有 LL-HLS 才出现。
所以「学 m3u8」并不需要背全部标签。
记住结构类与直播类四个,再认得 #EXT-X-KEY 长什么样,
日常排查就够用了。
二、逐行分类一份真列表
拿一份带多看点的列表来逐行看,一共 12 行:
全局标签四行:EXTM3U、VERSION:7、TARGETDURATION:6、MEDIA-SEQUENCE:2048。
不连续点两行:#EXT-X-DISCONTINUITY-SEQUENCE:2 与 #EXT-X-DISCONTINUITY。
加密一行:#EXT-X-KEY:METHOD=AES-128,URI="key.bin"。
切片相关四行:两个 #EXTINF 加两个 .ts 文件名。
结束一行:#EXT-X-ENDLIST。
这份列表有个细节值得注意: MEDIA-SEQUENCE 已经到 2048,说明这场直播已经播了两千多片。 如果每片 6 秒,那就是三个多小时。 序号是「历史总片数」,不是「当前保留几个」——这一点最容易搞混。
三、两个最容易被忽视的标签
① #EXT-X-DISCONTINUITY:表示「时间轴在这里不连续」。
广告插入、码率切换、服务器切换都会插它。
播放器看到它会把解码器重置,否则画面会花。
② #EXT-X-DISCONTINUITY-SEQUENCE:给不连续点编号。
直播滚动时要靠它让新观众知道「已经跳了几次」。
漏了它,从中间进来的观众时间轴会乱。
举个具体场景:直播中途插了一段广告。 广告前后各有一个 DISCONTINUITY。 如果播放器不重置解码器,广告结束的第一帧会引用广告之前的参考帧, 画面就会花屏几帧——这是很多人在做广告插入时踩的坑。
顺带一条工程建议: 自己生成 m3u8 时,只要「切片的 PTS 出现跳变」就补一个 DISCONTINUITY。 宁可多插,不要漏插——多插只是多一次解码器重建,代价很小。
四、动手 Demo:m3u8 格式——哪些标签必须懂,哪些可以不管
先按五类列出常用标签,再拿一份 12 行的真列表逐行分类、量长度。 最后盯住 DISCONTINUITY 这一对——它是广告插入能不能不花屏的关键。
import io, os, tempfile
txt = ("#EXTM3U\n#EXT-X-VERSION:7\n#EXT-X-TARGETDURATION:6\n"
"#EXT-X-MEDIA-SEQUENCE:2048\n"
"#EXT-X-DISCONTINUITY-SEQUENCE:2\n"
"#EXT-X-KEY:METHOD=AES-128,URI=\"key.bin\"\n"
"#EXTINF:6.006,\nseg2048.ts\n"
"#EXT-X-DISCONTINUITY\n"
"#EXTINF:6.006,\nseg2049.ts\n"
"#EXT-X-ENDLIST\n")
kinds = {
"#EXTM3U": "全局", "#EXT-X-VERSION": "全局",
"#EXT-X-TARGETDURATION": "全局", "#EXT-X-MEDIA-SEQUENCE": "全局",
"#EXT-X-DISCONTINUITY-SEQUENCE": "不连续",
"#EXT-X-DISCONTINUITY": "不连续",
"#EXT-X-KEY": "加密", "#EXTINF": "时长",
}
for ln in txt.splitlines():
tag = ln.split(":", 1)[0]
kind = kinds.get(tag, "切片 URI" if not ln.startswith("#") else "其他")
print("%-42s %-8s %d" % (ln, kind, len(ln)))
print()
# 不连续点前后的切片,PTS 应该能对上两个不同的时间基准
print("DISCONTINUITY 出现 %d 次,SEQUENCE 记为 %d"
% (txt.count("#EXT-X-DISCONTINUITY\n"), 2))
实跑输出:
--------------------------------------------------------------------
m3u8 格式——哪些标签必须懂,哪些可以不管
--------------------------------------------------------------------
**① 常用标签分三类**
类别 标签 是否必看
------------------------------------------------------------------------------
结构类 #EXTM3U #EXT-X-VERSION 必看
直播类 #EXT-X-TARGETDURATION #EXT-X-MEDIA-SEQUENCE 必看
切片类 #EXTINF #EXT-X-BYTERANGE #EXT-X-DISCONTINUITY 按需
加密类 #EXT-X-KEY #EXT-X-MAP AES 时要看
低延迟类 #EXT-X-PART #EXT-X-PRELOAD-HINT LL-HLS 才看
**② 真拿一份带多看点的列表来逐行分类**
行 类型 长度
-----------------------------------------------------------------
#EXTM3U 全局标签 7
#EXT-X-VERSION:7 全局标签 16
#EXT-X-TARGETDURATION:6 全局标签 23
#EXT-X-MEDIA-SEQUENCE:2048 全局标签 26
#EXT-X-DISCONTINUITY-SEQUENCE:2 不连续点 31
#EXT-X-KEY:METHOD=AES-128,URI="key.bin" 加密 39
#EXTINF:6.006, 切片时长 14
seg2048.ts 切片 URI 10
#EXT-X-DISCONTINUITY 不连续点 20
#EXTINF:6.006, 切片时长 14
seg2049.ts 切片 URI 10
#EXT-X-ENDLIST 全局标签 14
**③ 两个最容易被忽视的标签**
**① `#EXT-X-DISCONTINUITY`**:**表示「时间轴在这里不连续」。**
**广告插入、码率切换、服务器切换都会插它。**
**播放器看到它会把解码器重置,否则画面会花。**
**② `#EXT-X-DISCONTINUITY-SEQUENCE`**:**给不连续点编号。**
**直播滚动时要靠它让新观众知道「已经跳了几次」。**
**漏了它,从中间进来的观众时间轴会乱。**
12 行里最长的一行是 #EXT-X-KEY:...,39 字节——密钥地址写在 URI 里。
切片 URI 那两行不带 #,所以判类型要分两步:先看有没有 #,再查表。
DISCONTINUITY 在 #EXTINF 之后、下一个 #EXTINF 之前,它的位置就是「新的时间轴从下一条开始」的意思。
30 秒实验
- 把 VERSION 从 7 改成 3,看哪些标签会变非法——
#EXT-X-MAP之类要 6 以上才允许。 - 在第二个
#EXTINF前再加一个 DISCONTINUITY,数出现几次——变 2 次,但顺序会乱,播放器可能直接放弃。 - 把
#EXT-X-KEY的 URI 改成绝对地址,看长度——长很多,这也是加密列表不能太频繁刷新的原因之一。
常见误区
- 「标签越多越专业」——常用就那几个,多的是特定场景才用。
- 「DISCONTINUITY 只影响时间轴显示」——不重置解码器会花屏。
- 「MEDIA-SEQUENCE 是当前列表第一片的序号」——对,但它是历史累计值。
自测三问(点开对答案)
1. m3u8 标签分哪五类? —— **结构、直播、切片、加密、低延迟**;常用的只有前两类。 2. DISCONTINUITY 是干什么的? —— **标记时间轴不连续**,让播放器重置解码器,否则会花屏。 3. MEDIA-SEQUENCE 2048 意味着什么? —— **历史上一共生成过 2048 片以上**,不等于当前列表有几片。- ☐ (本节完,下一节 5.4.1 ES、PES、PS、TS)