HLS 下载音频和视频分开了?这样修复
为什么现代 HLS 流把音频和视频做成独立 manifest,以及 2026 年把它们合成单个可播放 MP4 的三种方法。
你点了”下载”一段 HLS 流,结果得到的是两个文件 —— video.mp4 没声音,audio.mp4 没画面。或者更糟,你只拿到了无声视频,根本没意识到音频在另一份完全不同的 m3u8 里。这不是你下载工具的 bug。这是现代 HLS 的工作方式,而几乎每个市面上的 Chrome HLS 扩展都以同样的方式失败。
本文解释为什么现代 HLS 把音频和视频分开、manifest 实际长什么样、以及三种实际可行的方法把它们合并回可播放的 MP4 —— 从技术用户的一行 FFmpeg 命令,到所有人都能用的一键方案。
现代 HLS 实际长什么样
在 HLS 早期(Apple 2009 年的原始规范,RFC 8216),master playlist 指向一组 media playlist,每个里面有 .ts 段,已经把音频和视频混合在一起:
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=1280000,RESOLUTION=720x480
720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2560000,RESOLUTION=1280x720
1080p.m3u8
每个链接的 m3u8 包含像 seg001.ts 这样的段,你可以直接拼接并播放。一个文件,一条流,一次下载。
但今天大多数生产环境的 HLS 流不是这样。一份现代的 master playlist 看起来更像这样:
#EXTM3U
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="English",DEFAULT=YES,URI="audio/eng/playlist.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Spanish",URI="audio/spa/playlist.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="English",URI="subtitles/eng.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=1280000,RESOLUTION=720x480,CODECS="avc1.4d401e",AUDIO="aac",SUBTITLES="subs"
video/720p/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2560000,RESOLUTION=1280x720,CODECS="avc1.4d401f",AUDIO="aac",SUBTITLES="subs"
video/1080p/playlist.m3u8
视频 manifest 现在只包含视频段 —— 完全没有音频。音频住在一个完全独立的、由 EXT-X-MEDIA 标签(TYPE=AUDIO)引用的 m3u8 中。播放器负责并行下载两者并同步渲染。
为什么每条现代流都这样做
分离不是随意的。每个主要流媒体平台迁移到这种方式有四个具体原因:
1. 多音轨支持
一部包含英语、西班牙语、法语、德语、日语五种音轨的电影,如果音频复用进视频,需要 5× 的存储和 5× 的编码成本。把音频独立成自己的 manifest,让播放器无需重新下载视频就能切换音轨。
2. 自适应码率效率
同一条音轨可以与 240p、480p、720p、1080p 和 4K 视频变体配对。没有分离,每个画质级别都需要自己的音频副本。有了分离,一份音频 manifest 服务所有视频画质。
3. 加密流的密钥管理
现代 HLS 使用 AES-128 或 SAMPLE-AES 加密。分离音频和视频让两者各自有不同的密钥轮换计划。这对直播流很重要 —— 加密密钥每 60 秒轮换一次,用于 DRM 邻近(但不完全 DRM)的保护。
4. CDN 缓存效率
音频段很小(约 20-50 KB)且很少变化。视频段很大(约 1-5 MB)并主导带宽。分离两者让 CDN 可以激进地缓存音频,并对视频采用不同的缓存策略。
这是好工程。这也使得下载更难。
如何把它们合并回来:三种方法
方法 1:FFmpeg 一行命令(技术用户)
如果你能读 master playlist 并识别正确的音频和视频 URI,FFmpeg 可以单次合并而无需重新编码:
ffmpeg \
-i "https://example.com/video/1080p/playlist.m3u8" \
-i "https://example.com/audio/eng/playlist.m3u8" \
-c copy \
-bsf:a aac_adtstoasc \
output.mp4
参数说明:
-c copy—— 流式复制,不重新编码,无损快速-bsf:a aac_adtstoasc—— 当音频是 MPEG-TS 内的 AAC 时必需,否则 iOS / Safari 无法播放产出的 MP4
要找到 URL,打开 Chrome DevTools,转到 Network 标签,按 m3u8 过滤,然后播放视频。你会看到 master playlist 先加载,然后是视频 media playlist,再是音频 media playlist。右键各个,复制 URL,粘贴到上面的 FFmpeg 命令里。
这能用。但每周不止一次做的话就让人厌倦了。
方法 2:yt-dlp / streamlink(半技术用户)
yt-dlp 和 streamlink 都能摄取 master playlist 并自动解析音视频配对:
yt-dlp -f "bv*+ba/b" "https://example.com/master.m3u8"
-f "bv*+ba/b" 格式选择器的意思是”最佳视频加最佳音频,分离失败时回退到最佳单流”。这处理了常见情况,但在以下情况会失败:
- 需要已认证 session(cookie)的流
- 在 Cloudflare 或 token 轮换墙后面的流
- 直播流(yt-dlp 录制 live HLS 不可靠)
对公开 VOD 这是最简单的 CLI 路径。任何在登录 session 内的,见方法 3。
方法 3:能处理它的浏览器扩展(其他所有人)
前两种方法的根本问题在于 m3u8 URL 本身不够。现代流使用:
- 30-120 秒过期的每会话签名 URL
- 原 session 浏览器有但 CLI 工具没有的 cookie
- 反爬虫系统验证的播放器自定义请求头(
Origin、Referer) - 与真实浏览器匹配的 TLS 指纹,而不是 Python
requests库
浏览器扩展住在与视频播放器相同的 session 内。它看到相同的 cookie、发送相同的 headers、继承相同的 TLS 指纹。它也能在页面加载时同时看到音频和视频 manifest,从而无需你在任何地方复制 URL 就能自动配对。
这正是我们做 Video Downloader One-for-All 的目的。具体来说:
- 扩展在你浏览时监听网络中的 HLS manifest 请求
- 看到 master playlist 时,它解析并记录音频 + 视频 manifest URI
- 你点下载时,它使用你现有的浏览器 session 并行抓取两者
- 它在浏览器内运行 FFmpeg.wasm(FFmpeg 的 WebAssembly 构建)把流封装成单个 MP4
- 合并后的文件落到你的下载文件夹,无独立文件
无 DevTools,无命令行,无过期 URL。整个流水线在你的标签页里跑,所以你视频的任何部分都不离开你的机器。
为什么大多数其他扩展在这上面失败
如果你读 Chrome 应用商店上 HLS 扩展近期的 1 星评论,音视频分离问题反复出现:
“Splits into audio and video streams and constantly opens new recordings ad infinitum.” (分成音频和视频流,并且不停地打开新录制。)
“It’s not recording audio and is constantly creating new recordings.” (不录音频,并且一直在创建新录制。)
“我願意付費使用 希望作者趕快更新 不然視訊和音軌都是分開的”
这些引用来自 Stream Recorder,Chrome 应用商店上安装最多的 HLS 扩展,超过 100 万用户。Stream Recorder 自 2025-08-01 以来未收到更新。现代 HLS 流让它失效,因为它的 manifest 解析器早于音视频分离模式。我们在 Stream Recorder 用不了了?2026 年最佳 HLS / m3u8 替代方案 中详细介绍了这点。
其他安装量最高的 HLS 扩展(Live Stream Downloader、FetchV、Video Downloader Plus)以混合的成功度处理分离 —— 一些自动配对,一些只在你选择特定画质时配对,一些根本不处理。
如何验证你的下载工具是否正确处理分离
挑一个已知是分离的 HLS 源 —— 大多数直播平台都可以用作测试。然后:
- 用你想测试的扩展开始下载
- 完成时检查文件大小。一段 5 分钟 1080p 含音频视频应该是 30-80 MB。如果你看到两个约 25 MB 的文件,或者一个 25 MB 无声文件,分离处理坏了。
- 在 VLC 或任何媒体播放器里打开文件。如果音频缺失或不同步,合并步骤失败了。
- 如果你得到一个单一可播放文件,音频与口型同步,分离正确处理。
你可以用我们的扩展做同样的测试:安装它,找一个你知道以前会失败的流,检查产出的文件能不能完整带音频播放。
直播流呢?
对于 live HLS,分离更重要,因为:
- 音频 manifest 独立于视频 manifest 更新(通常每 6-10 秒)
- 录制必须在不漂移的情况下保持两个缓冲同步
- 暂停/恢复需要同时在两条流上 seek
我们的扩展处理这点 —— 见 直播录制页面 了解直播专属的功能面。上面的基础 FFmpeg 命令也能用于 live HLS,只要你把 -c copy 替换为合适的缓冲设置,但 URL 轮换问题是真实存在的,你可能在边界处丢失分段。
当合并产出音频不同步时
有时合并技术上成功了,但音频与视频漂移几百毫秒。这通常意味着:
- 音频和视频 manifest 起始时间不同 —— 播放器通过时间戳对齐处理,但简单的拼接不会
- 一条流用 MPEG-TS 时间戳,另一条用 fragmented MP4 时间戳 —— 它们需要规范化
如果用 FFmpeg 方法发生这个问题,加 -itsoffset 0.0(或一个小的负值)然后重新封装。我们的扩展在封装前自动校正最多约 500 ms 的时间戳偏差。如果你看到超过这个的漂移,发源 URL 给我们 我们会检查。
常见问题
在以前能用的网站上分离会成为问题吗?
部分流媒体平台仍然交付复用的分段 —— 主要是较旧的系统和小规模 CDN。对那些,任何 HLS 下载工具都产出一个文件,因为只有一份 manifest。但主要平台(电视网、视频托管服务、视频点播门户)都在 2022-2025 年间迁移到分离。
为什么浏览器原生的”另存为视频”不工作?
<video> 标签的 source 是 master m3u8。浏览器的”另存为”试图把 m3u8 当文本文件下载,而不是解析后的视频。不解析 manifest 并下载分段,你得到的是一个无用的 2 KB 文本文件。
我能不能直接录屏?
你能,但是:(1)你重新编码视频,损失质量;(2)你通过 OS 音频环回重录音频,源是 44.1 kHz 时常常变成 48 kHz;(3)你不能捕获完整分辨率的视频,除非你的屏幕在源分辨率。直接 HLS 下载逐位保留原始 codec、分辨率和音频质量。
FFmpeg.wasm 方法和原生 FFmpeg 一样快吗?
对于封装操作(不重新编码),WebAssembly FFmpeg 大约以原生 FFmpeg 80-90% 的速度运行。30 分钟视频意味着浏览器里封装大约 5 秒完成 vs 命令行 4 秒 —— 完全在噪声范围内。重新编码会更慢,但封装操作不重新编码。
总结
现代 HLS 中音视频分离是一个永久的变化。流将在未来十年继续把音频和视频分开,因为替代方案是浪费的(存储、编码、CDN 缓存)。
三种方法处理它:
- FFmpeg 命令行 —— 能用但反复使用很烦
- yt-dlp / streamlink —— 对公开 VOD 有效,认证和直播会失败
- 自动配对并合并的浏览器扩展 —— 对登录 session 内的一切都有效
如果你属于第 3 类,安装 Video Downloader One-for-All。音视频分离的情况就是这个扩展存在的具体原因。