← 返回部落格

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-dlpstreamlink 都能擷取 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 秒過期的每 session 簽名 URL
  • 原 session 瀏覽器有但 CLI 工具沒有的 cookie
  • 反爬蟲系統驗證的播放器自訂請求標頭(OriginReferer
  • 與真實瀏覽器匹配的 TLS 指紋,而不是 Python requests 函式庫

瀏覽器擴充功能住在與視訊播放器相同的 session 內。它看到相同的 cookie、傳送相同的標頭、繼承相同的 TLS 指紋。它也能在頁面載入時同時看到音訊和視訊 manifest,從而無需你在任何地方複製 URL 就能自動配對。

這正是我們做 Video Downloader One-for-All 的目的。具體來說:

  1. 擴充功能在你瀏覽時監聽網路中的 HLS manifest 請求
  2. 看到 master playlist 時,它解析並記錄音訊 + 視訊 manifest URI
  3. 你按下載時,它使用你現有的瀏覽器 session 並行擷取兩者
  4. 它在瀏覽器內執行 FFmpeg.wasm(FFmpeg 的 WebAssembly 構建)把串流封裝成單個 MP4
  5. 合併後的檔案落到你的下載資料夾,無獨立檔案

無 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 源 —— 大多數直播平台都可以用作測試。然後:

  1. 用你想測試的擴充功能開始下載
  2. 完成時檢查檔案大小。一段 5 分鐘 1080p 含音訊視訊應該是 30-80 MB。如果你看到兩個約 25 MB 的檔案,或者一個 25 MB 無聲檔案,分離處理壞了。
  3. 在 VLC 或任何媒體播放器裡開啟檔案。如果音訊缺失或不同步,合併步驟失敗了。
  4. 如果你得到一個單一可播放檔案,音訊與口型同步,分離正確處理。

你可以用我們的擴充功能做同樣的測試:安裝它,找一個你知道以前會失敗的串流,檢查產出的檔案能不能完整帶音訊播放。

直播串流呢?

對於 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 快取)。

三種方法處理它:

  1. FFmpeg 指令列 —— 能用但反覆使用很煩
  2. yt-dlp / streamlink —— 對公開 VOD 有效,認證和直播會失敗
  3. 自動配對並合併的瀏覽器擴充功能 —— 對登入 session 內的一切都有效

如果你屬於第 3 類,安裝 Video Downloader One-for-All。音視訊分離的情況就是這個擴充功能存在的具體原因。