php通过调用ffmpeg实现图片与视频合成,需先用-loop生成3秒封面视频,再用concat协议合并;关键要校验参数一致性、使用escapeshellarg防护路径、临时文件清理及错误捕获。

PHP 本身不直接处理视频,但可以通过执行系统命令调用 ffmpeg 工具来实现「用一张图片 + 一个视频」合成带片头的视频(例如:3秒封面图 + 原视频)。关键在于构造正确的 ffmpeg 命令,并用 PHP 安全、可靠地运行它。
准备前提:确保 ffmpeg 可用
先确认服务器已安装 ffmpeg,且 PHP 能调用到:
- 终端运行 ffmpeg -version 看是否输出版本信息
- PHP 中用 exec('which ffmpeg', $out); print_r($out); 检查路径(常见为 /usr/bin/ffmpeg 或 /usr/local/bin/ffmpeg)
- 若在共享主机或无 shell 权限环境,此方案不可行,需换用支持服务端转码的云 API
核心命令:图片 + 视频拼接(最简可行方案)
目标:把一张 1920×1080 的 PNG/JPG(时长设为 3 秒)放在原视频前面,保持原视频分辨率、编码、音频不变。
ffmpeg 命令示例:
ffmpeg -loop 1 -i cover.jpg -i input.mp4 -c:v libx264 -t 3 -pix_fmt yuv420p -c:a aac -shortest cover_part.mp4 -y ffmpeg -f concat -safe 0 -i list.txt -c copy output_with_intro.mp4 -y
但更推荐「单命令流式拼接」,避免中间文件和重编码损失:
ffmpeg -loop 1 -t 3 -i cover.jpg -i input.mp4 -filter_complex "[0:v]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2[v0]; [1:v][1:a]trim=duration=300[v1][a1]" -map "[v0]" -map "[v1]" -map "[a1]" -c:v libx264 -c:a aac -shortest output.mp4
实际 PHP 中建议分步更可控(尤其调试阶段):
- 第一步:把图片转成与目标视频同参数的 3 秒视频片段(cover.mp4)
- 第二步:用 concat 协议合并两个视频(需先生成 list.txt 描述文件)
PHP 执行示例(含错误检查与路径安全)
假设:$cover = '/path/to/cover.jpg',$video = '/path/to/input.mp4',$output = '/path/to/output.mp4'
<?php $ffmpeg = '/usr/bin/ffmpeg';
$cover = escapeshellarg($cover);
$video = escapeshellarg($video);
$output = escapeshellarg($output);
// 步骤1:生成3秒封面视频(自动适配输入视频分辨率)
$cmd1 = "$ffmpeg -loop 1 -i $cover -vf \"scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2\" -t 3 -c:v libx264 -c:a aac -pix_fmt yuv420p -y /tmp/cover_temp.mp4 2>&1";
exec($cmd1, $log1, $return1);
if ($return1 !== 0) {
die("封面生成失败:" . implode("\n", $log1));
}
// 步骤2:生成 concat 列表文件
$listContent = "file '/tmp/cover_temp.mp4'\nfile $video";
file_put_contents('/tmp/list.txt', $listContent);
// 步骤3:合并
$cmd2 = "$ffmpeg -f concat -safe 0 -i /tmp/list.txt -c copy -y $output 2>&1";
exec($cmd2, $log2, $return2);
if ($return2 !== 0) {
unlink('/tmp/cover_temp.mp4');
unlink('/tmp/list.txt');
die("合并失败:" . implode("\n", $log2));
}
unlink('/tmp/cover_temp.mp4');
unlink('/tmp/list.txt');
echo "完成:$output";
?>
⚠️ 注意:
- escapeshellarg() 必须使用,防路径含空格或特殊字符导致命令截断
- /tmp/ 目录需 PHP 有读写权限;生产环境建议用唯一子目录隔离
- -c copy 在 concat 阶段要求两个视频编码/格式兼容(如都为 H.264+AAC+MP4),否则要改用 -c:v libx264 -c:a aac 重编码
- 若原视频分辨率不是 1920×1080,应先用 ffprobe 获取尺寸再动态设置 scale 参数
进阶建议:提升稳定性与体验
实际项目中建议补充:
- 用 ffprobe 提前读取原视频宽高、帧率、音频采样率,让封面视频参数严格对齐
- 加超时控制:exec("timeout 300 $cmd", ...)(Linux)防卡死
- 记录日志到文件而非仅 echo,便于排查
- 合并完成后用 filesize() 校验输出是否明显过小(可能静音/黑屏)
- 前端提交后异步处理(如写队列),避免 HTTP 超时
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











