使用PHP FFMPEG合并不同画质视频时触发致命错误的原因
尝试用PHP-FFmpeg合并两个不同质量的远程视频链接时出现执行失败,相同链接合并正常,不同链接报错,具体报错信息如下:
Fatal error: Uncaught Alchemy\BinaryDriver\Exception\ExecutionFailureException: ffmpeg failed to execute command '/bin/ffmpeg' '-i' 'https://checkout.spiritualsociety.co/windsor_test/medium.mp4' '-i' 'https://checkout.spiritualsociety.co/windsor_test/low.mp4' '-filter_complex' '[0:v:0] [0:a:0] [1:v:0] [1:a:0] concat=n=2:v=1:a=1 [v] [a]' '-map' '[v]' '-map' '[a]' '-b:a' '128k' 'videos/1684954817.mp4': Error Output: ffmpeg version 2.8.15 Copyright (c) 2000-2018 the FFmpeg developers built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-36) configuration: --prefix=/usr --bindir=/usr/bin --datadir=/usr/share/ffmpeg --incdir=/usr/include/ffmpeg --libdir=/usr/lib64 --mandir=/usr/share/man --arch=x86_64 --optflags='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic' --extra-ldflags='-Wl,-z,relro ' --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libvo-amrwbenc --enable-version3 --enable-bzlib --disable-crystalhd -- in /home/spiritualsociety/public_html/windsor_test/mergevedio/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Media/Concat.php on line 259
使用的代码:
<?php require 'vendor/autoload.php'; $ffmpeg = FFMpeg\FFMpeg::create(); $video = $ffmpeg->open('https://checkout.spiritualsociety.co/windsor_test/medium.mp4'); $format = new FFMpeg\Format\Video\X264('libmp3lame', 'libx264'); $format->setAudioCodec("libmp3lame", "libx264"); $video ->concat(array('https://checkout.spiritualsociety.co/windsor_test/medium.mp4', 'https://checkout.spiritualsociety.co/windsor_test/low.mp4')) ->saveFromDifferentCodecs($format, 'videos/'.time() . '.mp4');
问题根源与解决方法
1. 视频参数不匹配(核心原因)
FFmpeg的concat滤镜要求所有输入视频的分辨率、帧率、像素格式、音频采样率、通道数完全一致。你合并的medium和low是不同质量的视频,参数必然存在差异,导致滤镜执行失败。
解决步骤:
- 先将所有待合并视频统一为相同参数(以其中一个视频为基准)
- 处理完成后再执行合并操作
2. FFmpeg版本过旧
报错显示使用的是FFmpeg 2.8.15,这是2018年的旧版本,对现代编码和滤镜的支持有限,处理参数不匹配视频的容错性差。建议升级到FFmpeg 4.x或更高版本,新版本对concat的兼容性和错误提示更友好。
3. 代码优化与修正
- 原代码中
setAudioCodec方法错误传入了两个参数,该方法仅需指定音频编码(视频编码由X264格式类默认处理) - 远程视频建议先下载到本地临时文件,避免网络波动影响,同时方便参数检查与处理
优化后的完整代码:
<?php require 'vendor/autoload.php'; // 临时文件目录 $tempDir = sys_get_temp_dir(); $video1Temp = $tempDir . '/video1.mp4'; $video2Temp = $tempDir . '/video2.mp4'; $video2Processed = $tempDir . '/video2_processed.mp4'; // 下载远程视频到本地 file_put_contents($video1Temp, file_get_contents('https://checkout.spiritualsociety.co/windsor_test/medium.mp4')); file_put_contents($video2Temp, file_get_contents('https://checkout.spiritualsociety.co/windsor_test/low.mp4')); try { $ffmpeg = FFMpeg\FFMpeg::create(); // 获取基准视频参数(以第一个视频为准) $baseVideo = $ffmpeg->open($video1Temp); $baseFormat = $baseVideo->getFormat(); $targetWidth = $baseFormat->get('width'); $targetHeight = $baseFormat->get('height'); $targetFps = $baseFormat->get('frame_rate'); // 处理第二个视频,匹配基准参数 $video2 = $ffmpeg->open($video2Temp); $video2->filters() ->resize(new FFMpeg\Coordinate\Dimension($targetWidth, $targetHeight)) ->framerate(new FFMpeg\Coordinate\FrameRate($targetFps)); $video2->save(new FFMpeg\Format\Video\X264('libmp3lame'), $video2Processed); // 合并视频 $concat = $baseVideo->concat([$video1Temp, $video2Processed]); $concat->saveFromDifferentCodecs(new FFMpeg\Format\Video\X264('libmp3lame'), 'videos/' . time() . '.mp4'); echo "合并成功!"; } catch (Exception $e) { // 输出完整错误信息便于排查 echo "错误:" . $e->getMessage() . "\n"; if ($e instanceof Alchemy\BinaryDriver\Exception\ExecutionFailureException) { echo "FFmpeg输出:" . $e->getOutput(); } } finally { // 清理临时文件 foreach ([$video1Temp, $video2Temp, $video2Processed] as $file) { if (file_exists($file)) unlink($file); } }
4. 捕获完整错误日志
原报错未显示FFmpeg的具体错误原因(比如分辨率不匹配提示),可以通过try-catch捕获完整输出,快速定位问题:
try { // 你的合并逻辑 } catch (Alchemy\BinaryDriver\Exception\ExecutionFailureException $e) { print_r($e->getOutput()); // 打印FFmpeg的详细错误输出 }
内容的提问来源于stack exchange,提问作者Abhishek Chatterjee

