用 ffmpeg 把 m3u8 合并成 mp4:音视频分离与 TS 拼接的坑
你拿到了一个
.m3u8和一堆.ts分片,怎么做成一个能直接播放的.mp4?网上一搜全是ffmpeg -i index.m3u8 out.mp4,可真到自己手上,常常是"合并完没声音""画面卡一下""文件巨大"。本文把 m3u8 合并最常见的几个坑讲清楚。TL;DR:能直接
ffmpeg -i x.m3u8 x.mp4是幸运;更多时候要处理"音视频分离""AES 解密""TS 拼接花屏"。记住一句话——优先让 ffmpeg 自己读 m3u8(它懂索引),别手动下载分片再拼;需要带密钥/请求头时,用 keyinfo 或 headers 参数交给 ffmpeg。
目录
- 一、最理想的情况:一条命令搞定
- 二、坑一:音视频分离,合并后"没声音"
- 三、坑二:AES-128 加密,直接合并黑屏
- 四、坑三:手动拼 TS 花屏
- 五、坑四:体积暴涨,因为被重新编码
- 六、一个稳妥的命令模板
- 七、合规与温馨提示
一、最理想的情况:一条命令搞定
如果 m3u8 里的视频、音频都在同一清单里、且无加密,ffmpeg 能直接吃:
ffmpeg -i "https://cdn.example.com/index.m3u8" -c copy out.mp4
-c copy 是关键:只封装、不重新编码,所以快且不损画质。但现实很少这么理想。
二、坑一:音视频分离,合并后"没声音"
很多 HLS 用 #EXT-X-MEDIA 把音频单独列一条清单。此时主 m3u8 只含视频,ffmpeg 只下了画面,于是"能播但没声"。
解法:把音频清单也交给 ffmpeg,让它自己 mux:
# 用 -i 分别喂视频流和音频流清单,再 map 到一起
ffmpeg -i "video.m3u8" -i "audio.m3u8" \
-map 0:v -map 1:a -c copy out.mp4
经验:遇到"无声 mp4",先怀疑是不是音视频分离,而不是怀疑 ffmpeg 坏了。
三、坑二:AES-128 加密,直接合并黑屏
若 m3u8 里有 #EXT-X-KEY:METHOD=AES-128,URI="keyurl",分片是被加密的。ffmpeg 若拿不到 key(比如 key 地址要带 Cookie/Referer),就会解不出、黑屏。
解法:让 ffmpeg 带身份去取 key,或先把 key 下到本地用 keyinfo:
# 方式 A:直接喂带请求头的 m3u8(ffmpeg 会一并处理 key)
ffmpeg -headers "Referer: https://example.com" -i "index.m3u8" -c copy out.mp4
# 方式 B:key 在本地的 keyinfo 文件
# keyinfo 内容:
# https://cdn.example.com/key
# /local/path/keyfile
# <IV,可选>
ffmpeg -i "index.m3u8" -c copy -hls_key_info_file keyinfo out.mp4
四、坑三:手动拼 TS 花屏
有人会先把所有 .ts 用 cat 拼成大文件再转。这在有 B 帧、或 TS 不连续时极易花屏/卡顿。
正确做法:别手动拼,让 ffmpeg 读 m3u8 自己按顺序解封装。m3u8 就是那个"正确的顺序说明书"。
五、坑四:体积暴涨,因为被重新编码
如果你忘了 -c copy,ffmpeg 默认会重新编码,不仅慢,还可能让体积翻倍、画质下降。除非确实需要转码(比如目标设备不支持某编码),否则永远先试 -c copy。
六、一个稳妥的命令模板
综合上面的坑,常用模板长这样:
ffmpeg \
-headers "User-Agent: Mozilla/5.0\nReferer: https://example.com" \
-i "index.m3u8" \
-c copy \
out.mp4
带身份、不重编码、让 ffmpeg 自己读索引——这三点是 90% 场景下的"不出错基线"。
七、合规与温馨提示
技术是中性的,用法见人心。我们强烈建议:
- 仅下载你自己拥有版权或平台明确允许保存的内容;
- 尊重创作者与平台服务条款,不用于盗版传播、商业侵权;
- 下载内容请用于个人学习、备份与离线观看。
m3u8 合并的坑,本质是"你有没有把索引、密钥、音轨这三件事都交代清楚"。ffmpeg 足够聪明,只要你别手动拆它、别让它重编码,它几乎能自己把分片拼成干净的 mp4。如果你在合并时遇到过更离谱的报错,欢迎在评论区贴出来一起看。