原理上很简单,就是使用命令行去调用ffmpeg,然后分析一下输出是不是有错误。
首先安装?symfony/process,主要用于包装一下,用来代替?exec,?passthru,?shell_exec?and?system?。
composer require symfony/process
composer require symfony/filesystem
要注意 Laravel 10.x 是锁定 symfony 6.4的,所以无法安装最新的 7.0 ,但用起来也没什么问题。
照例创建服务,服务类:VideoMakerService,接口类:VideoMakerContract,服务提供类:VideoMakerProvider,快捷名称:videomaker,Facade类:VideoMaker
暂时就提供一个服务,把图片生成几秒视频。
public function imageToBaseVideo(string $imageFile, string $targetFile, float $duration): bool{
// $workingDir=$this->ffmpegTempDir;
$params=[
$this->ffmpegFile,
'-loop', '1',
'-framerate', '30',
'-i', $imageFile,
'-vf', 'scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2,setsar=1',
'-c:v', 'libx264',
'-t', $duration,
'-y',
$targetFile,
];
return ExecHelper::run($params);
}
这里使用了 ExecHelper 来运行,只是对Process做了包装
class ExecHelper{
public static function run(array $params){
$success=false;
$process = new Process($params);
$code=$process->run(function ($type, $buffer): void {
if (Process::ERR === $type) {
Log::debug('ERR > ', $buffer);
} else {
Log::debug('OUT > ', $buffer);
}
});
$success=$code===0;
return $success;
}
}
命令行类:ProcessVideo
public function handle(VideoMakerContract $videoMakerContract)
{
$imageFile = $this->argument('imageFile');
$targetFile = $this->argument('targetFile');
$duration = $this->option('duration');
// print params
$this->info('imageFile: '.$imageFile.' , targetFile: '.$targetFile.' , duration: '.$duration);
// convert to absolute path
$imageFile=PathHelper::toAbsolutePath($imageFile);
// validate imageFile
if(!file_exists($imageFile)){
$this->error('imageFile not exists');
return;
}
$targetFile=PathHelper::toAbsolutePath($targetFile);
// validate targetFile
if(!file_exists($targetFile)){
$this->error('targetFile not exists');
return;
}
// validate duration
if(!is_numeric($duration)){
$this->error('duration must be numeric');
return;
}
$success=$videoMakerContract->imageToBaseVideo($imageFile, $targetFile, $duration);
$this->info('success: '.$success);
}
这里面用到PathHelper就是简要地补全一下路径
class PathHelper{
public static function toAbsolutePath(string $path): string{
return Path::makeAbsolute($path, self::currentPath());
}
public static function currentPath(): string{
return realpath('.');
}
}
复制任意一张图片到 storage/app/tmp/t.jpg
./artisan process:video ./storage/app/tmp/t.jpg ./storage/app/tmp/t.mp4 --duration=5
?
轻松生成 t.mp4?,ffmpeg 的参数可以参考专栏里其他文章