首页 / FFmpeg 入门教程 / HLS 与 DASH 自适应流

FFmpeg 入门教程

HLS 与 DASH 自适应流

本教程共 32 篇 · 第 28 篇 · 更新于 2026-08-09 · 约 5 分钟阅读

FFmpegHLSDASHm3u8自适应码率流媒体切片

本节目标:搞懂 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.m3u8output0.tsoutput1.ts 等切片文件。

Note

HLS 切片必须有关键帧。如果关键帧间隔不规则,切片时长会不精确。加 -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.mpdinit-stream0.m4schunk-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 服务器上就能播,不需要流媒体服务器软件。