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 的态度。法律和技术底线详见 流媒体下载合法性指南


相关文档