MP4兼容性安全底线是-c:v libx264 -c:a aac,因浏览器仅原生支持H.264与AAC;混用-crf和-b:v会导致码率优先而忽略CRF;scale=1280:-2可能引发裁切,应显式保证宽高为偶数。

PHP 本身不转码,它只是调用 FFmpeg 的“指挥员”;真正决定 MP4 质量、体积和兼容性的,是传给 ffmpeg 的那一串参数——错一个,就可能生成播不了、卡顿、或大得离谱的文件。
为什么 -c:v libx264 是 MP4 的安全底线
MP4 容器能塞进很多编码,但浏览器只认 H.264(libx264)和 AAC。用 libx265 或 vp9 输出 MP4 文件,看似成功,实际在 Safari、部分安卓 WebView 里会静音、黑屏甚至报 MediaError.MEDIA_ERR_DECODE。
- 必须显式写
-c:v libx264 -c:a aac,不能依赖 FFmpeg 自动选择 - 避免
-c copy直拷贝:源文件编码不兼容时,MP4 封装会失败或播放异常 - 若需 HDR 或高帧率,得加
-pix_fmt yuv420p -r 30显式降级,否则 iOS Safari 拒绝解码
-crf 23 和 -b:v 1000k 到底该选谁
-crf(Constant Rate Factor)是质量优先模式,适合单版本输出;-b:v(target bitrate)是码率优先,适合多清晰度自适应场景。混用会导致 FFmpeg 忽略 -crf,并可能因码率压得太死而出现块状失真。
- 做单档 Web 播放:用
-crf 21~23(数字越小越清晰),配-preset medium - 做 HLS 多码率:必须用
-b:v,例如-b:v 800k -maxrate 800k -bufsize 1200k - 别写
-crf 23 -b:v 1000k—— FFmpeg 会以码率为准,-crf形同虚设
分辨率缩放时 -vf scale=1280:-2 的陷阱
-vf scale=1280:-2 看似聪明:保持宽高比、自动算高度。但它有个致命副作用——当原始视频高度不是偶数时,FFmpeg 会向下取整到最近偶数(H.264 编码强制要求宽高为偶数),导致画面轻微裁切或拉伸。
立即学习“PHP免费学习笔记(深入)”;
- 更稳妥写法:
-vf "scale=1280:trunc(ow/a/2)*2",显式保证偶数 - 移动端适配建议加
-vf "scale='min(1280,iw)':min(720,ih)',pad=1280:720:(1280-iw)/2:(720-ih)/2:black",避免黑边错位 - 别信
scale=1280:-1—— 在新版 FFmpeg 中已被弃用,会直接报错
PHP 调用时最容易被忽略的三个执行细节
你写的命令在终端能跑通,不等于 PHP 里也能跑通。Web 服务器用户(如 www-data)权限、环境变量、路径解析全都不一样。
- 务必用
escapeshellarg()包裹所有路径变量,比如escapeshellarg($inputPath),否则含空格或中文的路径直接中断 - 不要依赖 PATH 环境变量,写绝对路径调用:
/usr/bin/ffmpeg -i ... - 用
proc_open()替代shell_exec(),能捕获实时 stderr 输出,遇到Invalid data found when processing input这类错误才能立刻定位是源文件损坏还是参数错位
参数组合没有银弹,但每条都得经得住「换设备、换网络、换浏览器」三连测;最常出问题的不是 FFmpeg 版本,而是你传给它的那行命令里,某个空格、引号或冒号的位置不对。



















