You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PHP shell_exec()中用timeout正确实现FFmpeg转码超时控制

问题1:屏蔽FFmpeg日志并正确获取超时状态码

你之前写的if ((int)$result == 124)逻辑本身无法生效:shell_exec() 函数只返回命令打印的输出内容,拿不到进程的退出状态码。就算完全屏蔽FFmpeg的所有日志,$result只会是空字符串,强转成int后值为0,永远匹配不到124的超时状态。

正确实现步骤:

  • 不用给FFmpeg加-loglevel quiet,直接把命令的标准输出、标准错误全部重定向到系统空设备/dev/null,就能彻底丢弃所有FFmpeg日志,包括异常报错输出,比调整日志等级的方式更彻底。
  • 换用exec()函数执行命令,它支持通过第三个参数拿到命令的退出状态码,直接判断这个值就能识别是否超时。
  • 拼接命令时所有文件路径参数必须用escapeshellarg()转义,避免文件名带空格、特殊字符导致命令执行失败,同时防范命令注入风险。

参考代码:

// 拼接转码命令,所有输出重定向到空设备丢弃
$cmd = sprintf(
    'timeout 30 ffmpeg -i %s -vcodec h264 -filter:v fps=30 -acodec aac %s > /dev/null 2>&1',
    escapeshellarg($filetmp),
    escapeshellarg($filetmp . '.mp4')
);
$execOutput = [];
$exitCode = 0;
exec($cmd, $execOutput, $exitCode);

// 直接判断退出码即可识别超时
if ($exitCode === 124) {
    // 此处写超时触发后的业务逻辑
}
问题2:是否需要添加--kill-after=DURATION参数

要不要加这个参数看你的业务场景,先明确timeout的默认工作逻辑:
默认超时触发后,timeout会先给FFmpeg发SIGTERM信号,FFmpeg收到这个信号会正常收尾:写完MP4的文件索引、关闭文件句柄再退出,这种情况下生成的视频文件是可以正常播放的。但如果遇到源文件损坏、磁盘IO卡住这类异常情况,FFmpeg会卡住不响应SIGTERM,进程一直残留占用CPU、内存、IO资源。

选择建议:

  • 如果你的视频源都是可控的、很少有损坏文件,优先保证转码出来的文件能正常播放,就不用加这个参数。
  • 如果经常遇到异常视频导致FFmpeg进程卡死、占满服务器资源的情况,建议加上这个参数,宽限期设3~5秒就够,比如写成timeout --kill-after=5 30 ffmpeg [...]。意思是发完SIGTERM等5秒,要是进程还没退,就直接发SIGKILL信号强制杀进程,避免留僵尸进程耗资源。

注意:被SIGKILL强制杀掉的FFmpeg进程来不及做文件收尾,生成的MP4大概率是损坏的没法播放,加这个参数的话要配套做超时后坏文件清理、转码结果校验的逻辑。

内容的提问来源于stack exchange,提问作者Avatar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 21:21:23