原理上很简单,就是使用命令行去调用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
参考 保姆级教程:Laravel中添加Service
暂时就提供一个服务,把图片生成几秒视频。
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 imageFileif(!file_exists($imageFile)){$this->error('imageFile not exists');return;}$targetFile=PathHelper::toAbsolutePath($targetFile);// validate targetFileif(!file_exists($targetFile)){$this->error('targetFile not exists');return;}// validate durationif(!is_numeric($duration)){$this->error('duration must be numeric');return;}$success=$videoMakerContract->imageToBaseVideo($imageFile, $targetFile, $duration);$this->info('success: '.$success);}
参考:保姆级教程:Laravel里如何创建自己的命令行
这里面用到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 的参数可以参考专栏里其他文章