用PHP将m3u8转mp4不丢音轨的关键是正确调用ffmpeg并添加-bsf:a aac_adtstoasc参数,以解决ADTS格式AAC音频在MP4容器中的兼容问题;需确保m3u8可访问、ts分片无防盗链、加密流提供key/IV,优先使用-c copy零重编码封装。

PHP 本身不能直接转封装或解码/编码音视频,所以“用 PHP 把 m3u8 转成 mp4 不丢音轨”本质上是调用外部工具(主要是 ffmpeg),PHP 负责拼命令、执行和监控。关键在 ffmpeg 参数是否正确,而非 PHP 逻辑。
确认 m3u8 是可下载的直播/点播流
m3u8 只是播放列表(文本),真正内容是它引用的 .ts 分片。要转成 mp4,必须能访问所有 ts 文件(HTTP 可达、无防盗链、无动态 token)。如果是加密流(#EXT-X-KEY),需先解密,否则音轨会缺失或解码失败。
- 用浏览器或 curl 打开 m3u8 地址,确认能正常返回文本,且里面的 .ts 链接也能逐个访问
- 检查是否有
#EXT-X-KEY:行;如有,需额外提供解密 key 和 IV,ffmpeg 才能正确读取音视频流
用 ffmpeg 合并 + 转封装(推荐:最快且不重编码)
如果原始 ts 分片音视频同步完好、编码格式兼容(如 H.264 + AAC),直接合并封装为 mp4 即可,零质量损失、不丢音轨、速度快。
PHP 中执行示例:
立即学习“PHP免费学习笔记(深入)”;
$playlist = 'https://example.com/video/index.m3u8';
$output = '/path/to/output.mp4';
<p>// 关键参数说明:
// -allowed_extensions ALL → 允许加载 .ts(默认只认常见扩展)
// -bsf:a aac_adtstoasc → 把 ADTS 格式 AAC 转为 MP4 兼容的 ASC(保音轨核心!)
// -c copy → 流复制,不重新编码
$cmd = "ffmpeg -i \"{$playlist}\" -c copy -bsf:a aac_adtstoasc -y \"{$output}\" 2>&1";</p><p>$outputLog = shell_exec($cmd);</p>- 务必加
-bsf:a aac_adtstoasc:很多 m3u8 的 AAC 音频是 ADTS 封装,直接 copy 到 mp4 容器会因格式不兼容导致播放无声或音轨丢失 - 避免用
-c:v copy -c:a copy拆开写,容易漏掉音频处理;-c copy更稳妥 - 若提示 “Invalid data found when processing input”,大概率是网络不稳定或 ts 下载超时,可加
-timeout 10000000 -reconnect 1 -reconnect_at_eof 1 -reconnect_streamed 1
需要重编码时:确保音轨被显式包含
如果源流有异常(如音视频时间基不一致、编码不兼容),需解码再编码。此时必须明确指定音频流,否则 ffmpeg 可能默认只选视频。
$cmd = "ffmpeg -i \"{$playlist}\" -c:v libx264 -c:a aac -b:a 128k -movflags +faststart -y \"{$output}\"";
- 用
-c:a aac显式启用 AAC 编码,比-c copy更可靠应对复杂流 -
-movflags +faststart让 mp4 支持边下边播(网页播放更友好) - 若原流含多音轨(如中/英),用
-map 0:v:0 -map 0:a:0精确选择主音视频流
PHP 执行注意事项
不要用 exec() 直接暴露命令,注意路径、权限、超时和错误捕获。
- 确保 web 用户(如 www-data)有权限执行 ffmpeg 且磁盘可写
- 用
escapeshellarg()包裹路径和 URL,防命令注入:escapeshellarg($playlist) - 设置执行超时:
set_time_limit(300);(5分钟,按视频长度调整) - 检查返回值:
exec($cmd . ' 2>&1', $out, $returnCode); if ($returnCode !== 0) { /* 处理错误 */ }



















