PHP exec()调用FFmpeg无反应,主因是权限不足、路径错误或stderr被忽略;需确认ffmpeg路径、Web用户执行权限、输出目录写权限,并强制添加2>&1捕获错误输出。

PHP调用FFmpeg合并视频时,为什么exec()没反应?
PHP本身不处理视频,必须依赖外部工具(主要是ffmpeg)。直接写exec("ffmpeg -i ...")常失败,不是PHP问题,而是权限、路径或错误输出被吞掉。常见现象:页面空白、返回空字符串、日志里看不到任何ffmpeg进程。
- 确认
ffmpeg已安装且在系统PATH中,终端执行which ffmpeg能返回路径 - PHP运行用户(如
www-data或nginx)必须有读写临时目录+执行ffmpeg的权限 - 永远加上
2>&1捕获错误:exec("ffmpeg -y -i input.mp4 -i intro.mp4 -filter_complex \"[1:v][1:a][0:v][0:a]concat=n=2:v=1:a=1[v][a]\" -map \"[v]\" -map \"[a]\" output.mp4 2>&1", $output, $return_code) - 检查
$return_code是否为0,非0就看$output里的具体报错(比如No such file or directory多半是路径不对)
用concat协议拼接片头+主视频+片尾,为什么画面黑屏或音画不同步?
FFmpeg的concat有两种模式:concat protocol(文件级拼接)和concat filter(流级合成)。前者快但要求所有视频严格同编码、同分辨率、同帧率;后者灵活但必须先统一参数,否则黑屏/卡顿/音频漂移。
- 推荐用
concat filter,它能自动重采样、缩放、对齐时间基,例如:-filter_complex "[intro:v:0][intro:a:0][main:v:0][main:a:0][outro:v:0][outro:a:0]concat=n=3:v=1:a=1[v][a]" -map "[v]" -map "[a]" - 务必提前用
ffprobe检查三段视频的codec_name、width/height、fps、sample_rate,差异大时先转成统一规格(比如都转成libx264+1280x720+25fps+44100Hz) - 片头/片尾若无音频,要补静音轨,否则
concat会报错:-f lavfi -i anullsrc=channel_layout=stereo:sample_rate=44100
PHP生成临时文件名和清理逻辑,怎么避免并发冲突或磁盘爆满?
用户同时上传多个视频,如果都用temp.mp4硬编码,必然覆盖或混用。更麻烦的是失败后残留大文件占满/tmp。
- 用
uniqid('', true)生成带微秒的唯一ID,再拼上md5($_FILES['video']['tmp_name'])增强防撞能力 - 所有中间文件(片头转码后、主视频转码后、最终输出)都放在同一临时目录下,用同一个前缀,比如
/tmp/vid_5f3a8b2c_ - 用
register_shutdown_function()注册清理函数,确保脚本结束时删掉该前缀的所有文件,哪怕exit()或异常中断也触发 - 加磁盘空间校验:
disk_free_space('/tmp')低于512MB就拒绝任务,避免OOM或IO卡死
Web端上传大视频时,PHP超时或内存溢出怎么办?
PHP默认max_execution_time=30,而一个10分钟MP4转码可能耗时2–5分钟,还没算上传和合并。直接调高超时值治标不治本,关键在异步和分阶段。
立即学习“PHP免费学习笔记(深入)”;
- 上传阶段用
upload_max_filesize和post_max_size放开限制(如2048M),但必须配合前端分片上传(如uppy.js),避免单次POST超时 - 转码任务扔进后台队列:写入MySQL任务表,用
system("nohup php worker.php > /dev/null 2>&1 &")或beanstalkd调度,PHP主线程立即返回任务ID -
memory_limit设为-1(不限制)仅限CLI模式,Web SAPI下仍建议256M以内,靠FFmpeg自己管理内存 - 用
proc_open()替代exec()可实时读取FFmpeg进度(解析frame= 1234行),前端轮询更新进度条
真正难的不是命令拼对,而是视频参数不一致时FFmpeg静默失败、临时文件权限错乱、并发场景下的命名冲突——这些不会报语法错误,但会让整个流程在生产环境随机崩掉。



















