简介:视频压缩,PHP实现在线压缩视频,PHP开发视频压缩在线
PHP本身没有提供压缩视频的函数,但是我们可以利用ffmpeg这个工具对视频进行压缩。
视频压缩主要分为五个类别进行压缩:
我们可以直接使用 ffmpeg 中的 ffprobe 来获取视频的信息。命令如下:
ffprobe -i video.mp4
输出信息如下:
如果是PHP代码执行上述命令,我们很难获取自己想要的信息。ffmpeg提供了格式化的参数,可以利用这一点获取json格式的信息。命令参数如下:
ffprobe -v error -show_streams -print_format json 视频路径
上面的参数一个都不能少哦!
-show_streams:表示返回视频流相关的信息,比如宽高,比特率,帧率等
-print_format:指定返回的格式
返回的是一个二维数组,具体的大家可以自己执行一下看看具体的内容。现在就可以遍历二维数组获取视频相关信息了
先来看看视频压缩的命令:
ffmpeg -hwaccel auto -r 20 -i 视频路径 -c:v libx264 -b:v 862k -s 512x512 -b:a 64k -y 输出视频的路径
注意:上面获取视频信息是ffprobe,这里是ffmpeg
输出路径不能与源视频的路径相关,否则会直接报错
-r 指定输出视频的帧率,即每一秒显示的帧数
-c:v 指定视频编码格式。这个是-vcodec的缩写或者说别名,推荐:libx264
-b:v 指定视频的比特率
-s 指定输出视频的宽高即分辨率。格式:宽x高 注意宽和高必须是2的倍数,否则会报错
-b:a 指定音频码:64k
有了执行命令,我们就可以通过PHP去执行这些命令,从而实现视频压缩。PHP中有很多执行shell脚本命令的参数,我个人使用的是 shell_exec
如果使用shell_exec函数执行命令时,可能会报错,提示该函数已被禁用。我们可以修改php的配置文件,找到 disable_functions 配置项,将shell_exec函数移除重启php-fpm即可
关于php配置文件,我们可以通过 php --ini 查看配置文件具体路径
下面是我个人封装的一个ffmpeg视频压缩的类库,大家可以借鉴一下:
<?php
class FFmpegHelper
{
protected static $ffmpeg_path = 'ffmpeg';
protected static $ffprobe_path = 'ffprobe';
protected static function execShell($command)
{
if (function_exists('shell_exec')){
return shell_exec($command);
}
throw new \Exception('无法执行命令行');
}
/**
* 根据最大值计算视频的分辨率
* @param $width 视频的宽度
* @param $height 视频的高度
* @param int $max 视频最大宽高
* @return array
*/
public static function getMaxResolution($width,$height,$max=600)
{
if(max($width,$height)>$max){
if($height>$width){
$width = intval(round($max * $width / $height));
if($width%2==1) $width++;
return ['width'=>$width,'height'=>$max];
}
$height = intval(round($max * $height / $width));
if($height%2==1) $height++;
return ['width'=>$max,'height'=>$height];
}
return ['width'=>$width,'height'=>$height];
}
/**
* 获取视频的分辨率信息
* @param string $video_path 视频路径
* @return array|null
* @throws \Exception
*/
public static function getVideoResolution($video_path)
{
$command = "%s -v error -show_streams -print_format json %s";
$command = sprintf($command,self::$ffprobe_path,$video_path);
$streamsData = self::execShell($command);
$streamsInfo = json_decode($streamsData,true);
// 遍历流信息以找到视频流
foreach ($streamsInfo['streams'] as $stream) {
if ($stream['codec_type'] === 'video') {
// 返回分辨率信息
return [
'width' => $stream['width'], //宽
'height' => $stream['height'], //高
'bit_rate' => $stream['bit_rate'], //比特率
'r_frame_rate' => $stream['r_frame_rate'] //帧率
];
}
}
return null;
}
/**
* 视频压缩
* @param string $source_path 原视频的路径
* @param string $output_path 压缩后输出视频的路径,不能与原视频路径相同
* @return string|null
* @throws \Exception
*/
public static function imgCompress($source_path,$output_path)
{
$resolution = self::getVideoResolution($source_path);
if($resolution){
$resolution = self::getMaxResolution($resolution['width'],$resolution['height']);
$command = "%s -hide_banner -loglevel error -hwaccel auto -r 20 -i %s -c:v libx264 -b:v 862k -s %sx%s -y %s";
$command = sprintf($command,self::$ffmpeg_path,$source_path,$resolution['width'],$resolution['height'],$output_path);
}else{
$command = "%s -hide_banner -loglevel error -hwaccel auto -r 20 -i %s -c:v libx264 -b:v 862k -y %s";
$command = sprintf($command,self::$ffmpeg_path,$source_path,$output_path);
}
self::execShell($command);
return is_file($output_path);
}
}
获取视频分辨率信息时,可能会出错,所以我们需要兼容一下。
由于我们无法知道是否正确的执行成功,我这里使用is_file来检查一遍生成后的视频文件是否存在,存在表示执行成功,否则执行失败。
如果不想自己去封装ffmpeg,又不想使用我上面封装的代码,可以使用php-ffmpeg来执行视频压缩命令。具体的操作,可以看看我之前的文章【php-ffmpeg相关操作简介】
有遗漏或者不对的可以在我的公众号留言哦