PHP调用FFmpeg处理视频慢的根源在于链路多环节叠加:阻塞式调用(如shell_exec)、低效预设(如-preset medium)、I/O权限问题、Web服务器超时限制;应改用proc_open异步执行、选用-ultrafast预设、严格路径转义、拆分异步任务并显式配置编码参数。

PHP调用FFmpeg处理视频慢,不是PHP本身拖慢了,而是整个链路中多个环节叠加导致的——命令执行方式、FFmpeg参数配置、I/O与权限控制、以及Web环境限制共同作用的结果。
PHP调用方式不当造成阻塞和等待
直接用 shell_exec() 或 exec() 启动FFmpeg,会让PHP进程完全卡住,直到转码结束才返回。大视频可能耗时几十秒甚至几分钟,期间用户无响应、Nginx/Apache可能超时断连。
- 改用
proc_open()可以边运行边读取输出,便于监控进度(如解析frame=行) - 必须显式定义
stdin、stdout、stderr三根管道,并用fgets()循环读取,避免缓冲区满导致FFmpeg挂起 - 记得调用
proc_close()释放资源,否则进程残留会逐渐耗尽系统句柄
FFmpeg默认编码预设严重拖慢速度
FFmpeg的 -preset medium(默认值)为压缩率优化,牺牲大量CPU时间。对预览、中间生成、批量处理等非发布场景,属于典型“用力过猛”。
- 开发/调试阶段优先用
-preset ultrafast或superfast,速度可提升5–10倍,画质损失肉眼难辨 - 若需兼顾质量与速度,
-preset veryfast是更稳妥的默认选择 - 避免使用
slow、veryslow,除非输出用于归档或分发,且有充足等待时间
文件I/O与权限问题引发隐性延迟
PHP进程用户(如 www-data)若对输入路径无读取权、对输出目录无写入权,FFmpeg可能静默失败或反复重试;路径含空格、中文未转义也会触发shell解析错误,导致命令卡在启动阶段。
立即学习“PHP免费学习笔记(深入)”;
- 所有路径必须用
escapeshellarg()包裹,例如:escapeshellarg($inputPath) - 检查输出目录是否存在、权限是否正确:
is_writable($outputDir) - 错误捕获不能只看返回值是否为空,要合并
2>&1并搜索error、Invalid、No such file等关键词
Web服务器与PHP运行环境施加额外限制
Apache/Nginx + PHP-FPM 架构下,存在多层超时:PHP的 max_execution_time、FPM的 request_terminate_timeout、反向代理的 proxy_read_timeout,任一触发都会中断FFmpeg进程。
- 不要让PHP脚本直接承担长时间转码任务,应拆分为“提交任务→异步执行→轮询状态”模式
- 禁用输出缓冲:
ob_end_clean()+flush(),防止日志或错误被缓存而无法及时捕获 - 对大文件合成(如帧序列转MP4),优先用
-c:v libx264 -pix_fmt yuv420p显式指定编码器,避免FFmpeg自动探测耗费数秒



















