点播、直播、事件三种模式,判据只有一个:有没有 #EXT-X-ENDLIST。 列表只增还是滚动,决定了观众能不能回看。
5.2.1 认清了 m3u8 的语法,这一节看它在时间上怎么变。 5.2.3 转向清单里指的那些 .ts 文件本身。
一、三种模式的区别
点播 VOD:有 #EXT-X-ENDLIST,列表是全集,永不删片。
进度条能随便拖。
直播 LIVE:没有 #EXT-X-ENDLIST,只留最近几个切片。
只能看尾部,回看有限。
事件 EVENT:开始不加 ENDLIST,播完才加。
列表只增不删,已播部分可以拖回去。
判据就一条:有没有 #EXT-X-ENDLIST。
有就是「播完了」,播放器会显示总时长与可拖动进度条。
没有就是「还在生成」,播放器会定期重新拉列表。
事件模式是个折中: 它解决「直播想让人回看前面」的需求,代价是列表越来越长。 播十几个小时后,m3u8 本身就能有几百 KB,刷新一次很浪费。
二、滚动窗口是怎么滚的
直播时服务器只保留最近 N 个切片。 每生成一个新切片,最老的一个就被淘汰,列表整体前移一格。
实测窗口 3 个、喂 7 个切片的滚动过程: 第 1 轮 MEDIA-SEQUENCE 是 0,列表里是 seg0、seg1、seg2。 第 5 轮序号变 4,列表滑到 seg4、seg5、seg6。
注意第 1 轮只有 3 个,到第 5 轮窗口滑到了 seg4 到 seg6。 新观众进来只能从 seg4 开始,所以直播的「回看」是有限的。 这正是 HLS 直播延迟的一部分来源。
「回看」(DVR)能留多长,完全由 hls_list_size 决定。
设 3 就是留 3 个切片,设 0 就是不删——那就变成事件模式了。
三、为什么点播能随便拖
因为点播的 m3u8 里写了全部切片的 #EXTINF,
播放器算得出总时长,也知道每个时间点对应哪个切片。
拖动就是「按时间查切片序号,然后发一个 HTTP GET」。
不需要服务端做任何特殊支持——这是 HLS 能架在纯静态存储上的根本原因。
直播拖不动,不是「技术做不到」,而是「数据不在」: 被淘汰的切片已经删了,就算播放器想拖也取不到。 所以「能不能拖」本质上是「服务端留了多少」。
还有一个细节:拖到某个位置后,播放器必须从那个切片的关键帧开始解。 因为每个切片都以关键帧开头,所以 HLS 的拖动天然是「按切片对齐」的, 精度就是一个切片时长。
四、动手 Demo:播放模式——ENDLIST 有无决定点播还是直播
先摆三种模式的对照,再模拟一次「窗口 3 个、喂 7 片」的滚动。 滚动时要盯住 MEDIA-SEQUENCE——它才是观众「能回到哪儿」的边界。
models = [("点播 VOD", "有", "全量,不删", "能拖"),
("直播 LIVE", "无", "只留最近几个", "只能看尾部"),
("事件 EVENT", "最后才加", "只增不删", "已播部分可拖")]
for m, e, ln, seek in models:
print("%-10s ENDLIST=%-6s %-12s %s" % (m, e, ln, seek))
print()
win, total = 3, 7
for t in range(1, total - win + 2):
seq = t - 1
segs = ["seg%d.ts" % i for i in range(seq, seq + win)]
print("第 %d 轮:MEDIA-SEQUENCE=%d,%s" % (t, seq, "、".join(segs)))
print()
# 点播的列表里每片都有 EXTINF,累加就是总时长
durs = [4.0] * total
print("点播总时长 %.1f 秒,能拖到任意切片边界" % sum(durs))
实跑输出:
--------------------------------------------------------------------
播放模式——ENDLIST 有无决定点播还是直播
--------------------------------------------------------------------
**① 三种模式**
模式 ENDLIST 列表长度 能否拖
-------------------------------------------------------------
点播 VOD 有 全量,不删 能拖
直播 LIVE 无 只留最近几个 只能看尾部
事件 EVENT 最后才加 只增不删 已播部分可拖
**判据只有一个:有没有 `#EXT-X-ENDLIST`。**
**有就是「播完了」,播放器会显示总时长与可拖动进度条。**
**没有就是「还在生成」,播放器会定期重新拉列表。**
**② 模拟一个滚动窗口**
**直播时服务器只保留最近 N 个切片,列表每生成一个新切片就滚动一次。**
第 1 轮:MEDIA-SEQUENCE=0,切片 seg0.ts、seg1.ts、seg2.ts
第 2 轮:MEDIA-SEQUENCE=1,切片 seg1.ts、seg2.ts、seg3.ts
第 3 轮:MEDIA-SEQUENCE=2,切片 seg2.ts、seg3.ts、seg4.ts
第 4 轮:MEDIA-SEQUENCE=3,切片 seg3.ts、seg4.ts、seg5.ts
第 5 轮:MEDIA-SEQUENCE=4,切片 seg4.ts、seg5.ts、seg6.ts
**注意第 1 轮只有 3 个,到第 5 轮窗口滑到了 seg4 到 seg6。**
**新观众进来只能从 seg4 开始,所以直播的「回看」是有限的。**
**这正是 HLS 直播延迟的一部分来源。**
**③ 为什么点播能随便拖**
**因为点播的 m3u8 里写了全部切片的 EXTINF,播放器算得出总时长,也知道每个时间点对应哪个切片。**
**拖动就是「按时间查切片序号,然后发一个 HTTP GET」。**
**不需要服务端做任何特殊支持**——**这是 HLS 能架在纯静态存储上的根本原因。**
第 1 轮到第 5 轮,序号从 0 加到 4——窗口固定 3 个,序号只增不减。 新观众永远只能看到「最后 3 个」,他能回到的最早位置是 seg4。 总时长 28 秒是按 7 片 × 4 秒算的,真实直播里这个数会一直变。
30 秒实验
- 把
win改成 6,看第 1 轮有几个切片——只有 6 个,因为总共才喂 7 片,达不到窗口上限。 - 把
total改成 20,看轮数——18 轮,说明窗口固定时轮数与总片数线性相关。 - 把每片时长改成 2.0,看点播总时长——14 秒,总时长只跟片数与片长有关。
常见误区
- 「没有 ENDLIST 就是直播、有就是点播」——大体对,但事件模式中途也没有。
- 「直播不能拖动是播放器的限制」——不是,是旧切片被删了。
- 「MEDIA-SEQUENCE 会跟着窗口回退」——不会,它只增,这是关键。
自测三问(点开对答案)
1. 三种模式的唯一判据是什么? —— **有没有 `#EXT-X-ENDLIST`**;事件模式播完才加。 2. 直播的回看长度由什么决定? —— **`hls_list_size`**,设几个就留几个切片。 3. 为什么拖动精度是一个切片时长? —— **每个切片都以关键帧开头**,只能按切片边界对齐。- ☐ (本节完,下一节 5.2.3 TS 文件)