HLS 与 DASH 自适应流
本教程共 32 篇 · 第 28 篇 · 更新于 2026-08-09 · 约 5 分钟阅读
本节目标:搞懂 HLS 和 DASH 是怎么把视频切成小片段分发的,会用 FFmpeg 生成 m3u8 播放列表和多码率自适应流,也能输出 DASH 的 mpd。
前面讲的都是本地文件播放。这一章看流媒体——把视频放到网上,让观众通过浏览器或播放器看。两大主流方案是 HLS(苹果)和 DASH(国际标准),它们的核心思想一样:把视频切成小片段,用一个播放列表告诉播放器按什么顺序播。
一、HLS 是什么
HLS(HTTP Live Streaming)把视频切成一个个小片段(通常是 .ts 或 .m4s 文件),再生成一个 .m3u8 播放列表。播放器按列表依次下载片段,边下边播。
playlist.m3u8
├── seg_000.ts (第 0–10 秒)
├── seg_001.ts (第 10–20 秒)
├── seg_002.ts
└── ...
它的好处是:
- 走 HTTP 协议,普通 CDN 和 Web 服务器就能分发,不用特殊服务器。
- 自适应码率:可以同时提供 1080p、720p、480p 多套切片,播放器根据网速自动切换,不卡就看高清,卡了就降到流畅。
- 兼容性好:iOS/Android/浏览器/智能电视全支持。
二、最简单的 MP4 转 HLS
ffmpeg -i input.mp4 -c:v libx264 -c:a aac \
-hls_time 10 \
-hls_list_size 0 \
-f hls output.m3u8
参数解释:
-f hls:输出 HLS 格式-hls_time 10:每个切片 10 秒(HLS 规范建议 6–10 秒)-hls_list_size 0:播放列表保留所有片段(不设 0 则只保留最近几个,适合直播)
执行后会生成 output.m3u8 和 output0.ts、output1.ts 等切片文件。
NoteHLS 切片必须有关键帧。如果关键帧间隔不规则,切片时长会不精确。加
-g 60 -keyint_min 60(假设 30fps,每 60 帧一个关键帧,即 2 秒)可以让关键帧对齐,切片更整齐。
三、常用 HLS 参数
| 参数 | 作用 | 典型值 |
|---|---|---|
-hls_time n | 每片时长(秒) | 6–10 |
-hls_list_size n | 列表保留片段数,0=全部 | VOD 用 0,直播用 6–10 |
-hls_segment_filename | 切片命名模板 | seg_%03d.ts |
-hls_flags delete_segments | 直播时删除旧切片 | 配合 list_size |
-hls_flags independent_segments | 每片可独立解码 | 多码率必备 |
-hls_playlist_type event | 事件直播(列表追加) | event/vod |
-hls_base_url | 切片 URL 前缀 | CDN 地址 |
给切片自定义命名:
ffmpeg -i input.mp4 -c:v libx264 -c:a aac \
-hls_time 10 -hls_list_size 0 \
-hls_segment_filename "seg_%03d.ts" \
-f hls output.m3u8
四、多码率自适应 HLS
真正发挥 HLS 威力的是多码率(ABR)。一条命令生成 1080p/720p/480p 三档,并输出一个 master 播放列表:
ffmpeg -re -i input.mp4 \
-map 0:v:0 -map 0:v:0 -map 0:v:0 -map 0:a:0 \
-c:v libx264 -preset medium -crf 23 \
-filter:v:0 scale=1920:-2 -maxrate:v:0 5000k -bufsize:v:0 10000k \
-filter:v:1 scale=1280:-2 -maxrate:v:1 2500k -bufsize:v:1 5000k \
-filter:v:2 scale=854:-2 -maxrate:v:2 1000k -bufsize:v:2 2000k \
-c:a aac -b:a 128k \
-var_stream_map "v:0,a:0 v:1,a:0 v:2,a:0" \
-master_pl_name master.m3u8 \
-f hls -hls_time 6 -hls_list_size 0 \
-hls_flags independent_segments \
-hls_segment_filename "stream_%v/data%03d.ts" \
"stream_%v/index.m3u8"
生成结果:
master.m3u8 ← 总入口,引用三套子流
stream_0/index.m3u8 ← 1080p
stream_0/data000.ts ...
stream_1/index.m3u8 ← 720p
stream_1/data000.ts ...
stream_2/index.m3u8 ← 480p
stream_2/data000.ts ...
播放器打开 master.m3u8,会根据网速自动选合适的清晰度。关键参数是 -var_stream_map,它定义了每个子流包含哪些视频和音频;-master_pl_name 生成总播放列表。
五、DASH:MPD 和 fMP4
DASH(Dynamic Adaptive Streaming over HTTP)是 MPEG 推出的国际标准,原理和 HLS 类似,播放列表文件叫 .mpd(Media Presentation Description),切片通常用 fragmented MP4(.m4s)。
ffmpeg -i input.mp4 -c:v libx264 -c:a aac \
-f dash -seg_duration 10 \
-adaptation_sets "id=0,streams=v id=1,streams=a" \
output.mpd
会生成 output.mpd、init-stream0.m4s、chunk-stream0-00001.m4s 等文件。
多码率 DASH:
ffmpeg -i input.mp4 \
-map 0:v:0 -map 0:v:0 -map 0:a:0 \
-c:v libx264 \
-filter:v:0 scale=1920:-2 -b:v:0 5000k \
-filter:v:1 scale=1280:-2 -b:v:1 2500k \
-c:a aac -b:a 128k \
-f dash -seg_duration 10 \
-adaptation_sets "id=0,streams=v id=1,streams=a" \
output.mpd
YouTube、Netflix 主要用 DASH;苹果生态偏 HLS。实际项目中 HLS 更常见,因为 iOS 原生只支持 HLS(Safari 对 DASH 支持有限),Android 和浏览器两者都能通过 MSE/hls.js/dash.js 播放。
六、点播 vs 直播
HLS/DASH 都支持两种模式:
- VOD(点播):
.m3u8列出所有片段,播放列表不再变化。加-hls_playlist_type vod,配合-hls_list_size 0。 - 直播(Live):播放列表不断滚动,旧片段被新片段替换。加
-hls_flags delete_segments,用-hls_list_size 6只保留最近 6 个片段。 - Event(事件直播):片段不断追加但不删除,回看全程,结束后变成 VOD。用
-hls_playlist_type event。
Tip切片不是越短越好。10 秒切片能显著降低服务器请求数、减少编码开销,适合大多数场景。低延迟直播才考虑 2–4 秒的短切片或 LL-HLS。普通视频网站用 6–10 秒就够了。
七、播放 m3u8
本地测试可以用:
ffplay output.m3u8- 浏览器装 hls.js 或直接用 Safari
- VLC:媒体 → 打开网络串流 → 输入
.m3u8地址
把整个目录(.m3u8 + .ts 或 .m4s)扔到任何 HTTP 服务器上就能播,不需要流媒体服务器软件。