DASH 影片沒有聲音怎麼辦?MPD 排查

解決 MPD 或 MPEG-DASH 影片下載後沒有聲音的問題,涵蓋音影片分軌、CORS、DRM 與不完整清單。

DASH 下載出來沒聲音,十之八九是踩到同一個坑:影片和音訊是兩條獨立的軌道,你只把影片軌道拖回家了。這篇照 MPD 的實際處理流程拆解,告訴你聲音是在哪一步弄丟的、怎麼撈回來。


先理解:DASH 為什麼把聲音弄丟

MPD 不是「一條 URL 拉一個檔案」那麼簡單。它是一棵 XML 樹,用 AdaptationSet 把影片、音訊、字幕分成不同群組,每組裡再按位元率/畫質掛多個 Representation。看結構就懂了:

MPD
├── AdaptationSet: Video
│   └── Representation 1080p
│       ├── init segment(fMP4 頭,含編解碼器設定)
│       ├── segment-001.m4s
│       ├── segment-002.m4s
│       └── ...
└── AdaptationSet: Audio
    └── Representation 128kbps
        ├── init segment
        ├── segment-001.m4s
        ├── segment-002.m4s
        └── ...
                    ↓
            FFmpeg WASM 合併
                    ↓
              output.mp4

這和 HLS 完全是兩種脾氣。HLS 通常把音影片塞進同一個 TS 分片,你拉分片就能拼出有聲的;DASH 走 fMP4,音影片分開傳,下載時必須同時抓兩條軌道再合併。你的工具只認影片軌道的話,出來就是一部默劇。兩者差異對比見 影片嗅探 — 支援的影片格式,MPD 的 AdaptationSetRepresentationSegmentTemplate 完整層級拆解見 DASH 深度篇

FlowPick 的 DASH 處理流程:解析 MPD → 識別影片/音訊軌道 → 分別下載分片與初始化段 → FFmpeg WASM 合併。詳細實作見 影片嗅探 — 音影片分離處理下載引擎架構 — DASH 串流的特殊處理

快速處理

照這個順序先走一遍,能解決大多數情況:

  1. 打開原影片頁面,讓影片播起來(很多網站不播放就不發 MPD)。
  2. 用 FlowPick 偵測 MPD 清單。
  3. 在軌道列表裡同時勾選影片軌道和音訊軌道
  4. 挑一條和影片畫質匹配的音訊(語言、位元率對上就行)。
  5. 等合併步驟跑完,再打開聽聲音。

照這個流程還啞,就按下面的症狀對號入座。


症狀一:只選了影片軌道

表現:下載飛快,檔案幾 MB 到幾十 MB,播放器打開有畫面沒聲音。

最常見,沒有之一。DASH 下載器預設按位元率降序排軌道,很多人只勾了最上面那行 1080p,沒注意到再往下的「Audio」是另一組。用 ffprobe 一句話確認檔案裡到底有沒有音訊流:

ffprobe -hide_banner output.mp4

輸出裡只有 Stream #0:0: Video、沒有 Stream #0:1: Audio,就是這個問題。回到 MPD,把音訊軌道一起勾上再下。FlowPick 會自動匹配同語言、位元率最高的音訊軌,不用你手動算。


症狀二:MPD 裡壓根沒有音訊軌道

表現:軌道列表裡翻遍了都沒有音訊,或者只有一條「無聲」的影片流。

MPD 是動態產生的,同一個影片在不同地區、不同登入狀態下拿到的清單可能不一樣。常見三種:

  • 地區限制:某個地區只下發影片軌道,或只下發某一種語言。
  • 登入狀態:沒登入時 MPD 裡沒有音訊 AdaptationSet,登入後才冒出來。
  • 請求頭:部分網站靠 Referer/Cookie 決定要不要給你音訊軌。

把 MPD 位址摳下來用 curl 驗證(位址換成你自己的):

curl -sL -H "Referer: https://www.example.com/watch/123" \
     "https://cdn.example.com/master.mpd" > master.mpd

# 看清單裡到底有沒有音訊 AdaptationSet
grep -c 'AdaptationSet.*type="audio"' master.mpd
# 輸出 0 = 真沒有音訊軌;>0 = 有,是沒勾上(回到症狀一)

輸出 0 的話,回到原影片頁面、保持登入狀態,用擴充功能重新偵測。AdaptationSetRepresentationSegmentTemplate 這些節點具體長什麼樣,MPD 入門 講得比教科書清楚。


症狀三:CORS / 403 / 404

表現:影片軌下得動,音訊分片一拉就 403/404,或者線上工具直接報 CORS。

線上工具跑在 flowpick.com 域名下,帶不上目標站的 Cookie 和原頁面 Referer,來源端一驗證就攔——這是防盜連,不是沒聲音本身。處理方式:

  • 有防盜連的網站,改用擴充功能,在原影片頁面裡操作,Referer/Cookie 自動帶上。
  • v1.1.1+ 的擴充功能自帶防盜連代理,預覽和下載會自動補 Referer 和 Cookie,還會在存檔前檢查回應,避免把 HTML 錯誤頁存成媒體。
  • 音訊分片 URL 帶 ?token=xxx&expires=yyy 的,幾分鐘就過期,趁熱下,別中途去吃飯。
防盜連代理是 v1.1.1 新增的,升級後 Bilibili、微博這類網站的成功率會明顯提升。升級方法見 安裝指南 — 更新擴充功能,特性詳情見 v1.1.1 更新日誌。Referer 問題的完整排查(含 curl 重現)見 M3U8 排查 — 403 與防盜連,方法對 DASH 一樣適用。

症狀四:音訊分片下載不全

表現:軌道都勾了,合併後還是沒聲音或聲音斷斷續續,控制台裡能翻到幾個音訊分片的失敗記錄。

音影片是分開下的,影片全下完了,音訊可能還剩一兩片沒到位,合併時只能帶殘的進去。先確認到底是不是分片掉了:

# 逐個探音訊分片的 HTTP 狀態(把 URL 換成你的)
for i in $(seq 1 200); do
  url="https://cdn.example.com/audio/seg-$i.m4s"
  status=$(curl -s -o /dev/null -w "%{http_code}" "$url")
  echo "seg-$i.m4s -> $status"
done

出現 403/404/5xx,就是有分片拉不到。對策:

  • 網路會抖的話把並行數調低(2-3),減少掉包重試壓力,音訊軌本來就沒幾個分片,慢點無所謂。
  • 個別分片 5xx 的,等一會兒重下,來源端可能正在做 CDN 回源。
  • 一直斷在同一片,多半是臨時 Token 過期,回原頁面重新偵測拿新 MPD。

並行數與效能的關係見 下載引擎架構 — 並行數與效能的關係,重試和退避邏輯見 下載引擎架構 — 重試機制


症狀五:檔案大小正常但沒聲音

表現:檔案不小,ffprobe 裡音訊流也在,但播放就是沒聲音,或音畫對不上。

這種一般不是下載問題,是合併或編碼環節的事:

表現原因處理
有音訊流但播放無聲混合器沒把音訊配對好(H.265 影片 + 異常音訊標識)換輸出格式,或用 ffmpeg 命令列重裝一遍
音畫不同步SegmentTimeline 時間戳不連續用 FFmpeg 重新編碼修復
VLC 能播、系統播放器不能播播放器缺解碼器(VP9/AV1/Opus)換 VLC / PotPlayer,不是檔案問題

用 ffmpeg 把音訊單獨抽出來,驗證它本身是不是好的:

ffmpeg -i output.mp4 -map 0:a -c copy audio.m4a
# 抽出來的 audio.m4a 能正常播放 → 音訊沒壞,問題在合併環節

FFmpeg WASM 的轉封裝原理見 格式轉換 — FFmpeg WASM 轉封裝,音影片合併流程見 格式轉換 — 音影片分離合併


症狀六:DRM 保護

表現:MPD 裡有 <ContentProtection>,或播放前要載入 Widevine/PlayReady 的 CDM 模組。

這種下不了,FlowPick 明確拒絕處理——這是特性不是 bug。DRM 是版權方用硬體級加密鎖死的,聲稱能解 DRM 的下載器要嘛在撒謊要嘛違法。別浪費時間和磁碟。法律與技術底線見 串流下載合法性指南

DRM 偵測方式與完整不支援清單見 已知限制 — DRM 保護內容。DASH 音影片分離的已知邊界情況見 已知限制 — 分離音影片串流

診斷工具速查

F12 打開開發人員工具,幾個高頻檢查點:

檢查面板操作
MPD 有沒有被請求Network過濾框輸入 mpd,重新整理頁面播放影片
音訊分片狀態碼Network過濾框輸入 .m4s,看 Status 欄和 size
請求帶了什麼頭Network → 選中請求 → Headers看 Request Headers 的 Referer/Cookie 在不在
合併報錯Consoleffmpegwasm

環境資訊有疑問的,可以在 Console 裡跑下面這段,產生環境報告方便回報:

const report = {
  ua: navigator.userAgent,
  fsa: 'showDirectoryPicker' in window,
  sab: typeof SharedArrayBuffer !== 'undefined',
  coi: self.crossOriginIsolated,
  storage: await navigator.storage?.estimate().catch(() => null),
  ts: new Date().toISOString(),
}
console.log(JSON.stringify(report, null, 2))

報告只含瀏覽器環境資訊,不含任何瀏覽記錄或個人資料。


什麼時候真的下不了

  • DRM 保護(Widevine / PlayReady / FairPlay)
  • 需要破解登入或付費牆的內容
  • MSE 自訂分片、不發原生 MPD 的網站
  • 私無損或單獨加密的多音軌串流

這些是設計上不支援,不是 bug。碰到這些,正確的行為是報錯而不是靜默產出壞檔案——這也是 FlowPick 的態度。法律與技術底線詳見 串流下載合法性指南


相關文件