最近有一个我的项目须要应用ffmpeg解决视频,这里我写了一个demo,不便咱们来实现视频操作

ffmpeg操作demo

<?phpnamespace common\helpers;use common\models\Config;use common\models\VideoApiLog;use Yii;use yii\helpers\ArrayHelper;use common\helpers\Universal;use yii\helpers\FileHelper;use yii\httpclient\Client;use yii\web\ServerErrorHttpException;/** * ffmpeg视频解决 * * @author wangjian * @since 0.1 */class FfmpegVideo{    public $ffmpeg = 'ffmpeg';    public function __construct($ffmpeg = null)    {        if ($ffmpeg) {            $this->ffmpeg = $ffmpeg;        }    }    /**     * 增加视频文字滚动     * @param $source string 视频     * @param $saveFile string 保留文件     * @param $text string 水印文字     * @param array $options 水印款式     * @param int $step 每秒步长     * @param int $star 呈现工夫     */    public function titleMod($source, $saveFile, $text, $options = [], $step = 20, $star = 0)    {        $command = $this->ffmpeg .' -y -i '. $source .' -async 1 -metadata:s:v:0 start_time=0 -vf ';        $fonts = Yii::getAlias('@webroot') . "/fonts/simsun.ttc";        $fonts = str_replace('\\', '/', $fonts);        $fonts = str_replace(':', '\\:', $fonts);        $command .= '"drawtext=fontfile=\''. $fonts .'\': text=\''. $text .'\'';        foreach ($options as $key => $value) {            $command .= ':' . $key . '=' . $value;        }        $command .= ':x=\'if(gte(t,'. $star .'),((t-'. $star .') * '. $step .'),NAN)\'';        $command .= '" ';        $command .= $saveFile;        exec($command, $output, $result_code);        if ($result_code == 0) {            return true;        }        return  false;    }    /**     * 图片水印     * @param $source string 视频     * @param $saveFile string 保留文件     * @param $waterImage string 水印图片     * @param $left integer 水印程度地位     * @param $top integer 水印垂直地位     * @param null $star 水印开始工夫     * @param null $duration 水印时长     */    public function imageWater($source, $saveFile, $waterImage, $left, $top, $star = null, $duration = null)    {        $waterImage = str_replace('\\', '/', $waterImage);        $waterImage = str_replace(':', '\\:', $waterImage);        $command = $this->ffmpeg . ' -y -i '. $source .' -vf "movie=\''. $waterImage .'\'[watermark];';        $command .= '[in][watermark] overlay='. $left .':'. $top;        if ($star) {            $end = ($duration) ? $star + $duration : $star;            $command .= ':enable=\'between(t,'. $star .','. $end .')\'';        }        $command .= '[out] " ' . $saveFile;        exec($command, $output, $result_code);        if ($result_code == 0) {            return true;        }        return  false;    }    /**     * 给视频增加文字水印     * @param $source string 视频     * @param $saveFile string 保留文件     * @param $text string 水印文字     * @param array $options 水印款式     * @param null $star 水印开始工夫     * @param null $duration 水印时长     */    public function titleWater($source, $saveFile, $text, $options = [], $star = null, $duration = null)    {        $command = $this->ffmpeg .' -y -i '. $source .' -vf ';        $fonts = Yii::getAlias('@webroot') . "/fonts/STZHONGS.TTF";        $fonts = str_replace('\\', '/', $fonts);        $fonts = str_replace(':', '\\:', $fonts);        $command .= '"drawtext=fontfile=\''. $fonts .'\': text=\''. $text .'\'';        foreach ($options as $key => $value) {            $command .= ':' . $key . '=' . $value;        }        if ($star) {            $end = ($duration) ? $star + $duration : $star;            $command .= ':enable=\'between(t,'. $star .','. $end .')\'';        }        $command .= '" ';        $command .= $saveFile;        exec($command, $output, $result_code);        if ($result_code == 0) {            return true;        }        return  false;    }    /**     * 将音频合并到视频中     * @param $videoFile string 视频文件     * @param $audioFile string 音频文件     * @param $saveFile string 保留文件     * @param $delay integer 声音插入延时秒数     */    public function mergeVideoAudio($videoFile, $audioFile, $saveFile, $delay = null)    {        $delayTime = 0;        if ($delay) {            $delayTime = $delay * 1000;        }        $command =  $this->ffmpeg . ' -y -i '. $audioFile .' -i '. $videoFile .' -c:v copy -c:a aac -strict experimental -filter_complex "[0]adelay='. $delayTime .'|'. $delayTime .'[del1],[1][del1]amix" ' . $saveFile;        exec($command, $output, $result_code);        if ($result_code == 0) {            return true;        }        return  false;    }    /**     * 静音     */    public function audioMute($source, $saveFile)    {        $command =  $this->ffmpeg . ' -y -i '. $source .' -filter:a "volume=0" ' . $saveFile;        exec($command, $output, $result_code);        if ($result_code == 0) {            return true;        }        return  false;    }    /**     * 提取视频的音频     * @param $source string 须要提取声音的视频     * @param $saveFile string 提取声音后保留的音频     * @return bool     */    public function collectAudio($source, $saveFile)    {        $command =  $this->ffmpeg . ' -y -i '. $source .' -vn -acodec copy ' . $saveFile;        exec($command, $output, $result_code);        if ($result_code == 0) {            return true;        }        return  false;    }    /**     * 去除视频声音     * @param $source string 须要去除声音的视频     * @param $saveFile string 去除声音后保留的视频     */    public function removeAudio($source, $saveFile)    {        $command =  $this->ffmpeg . ' -y -i '. $source .' -an ' . $saveFile;        exec($command, $output, $result_code);        if ($result_code == 0) {            return true;        }        return  false;    }    /**     * 视频拼接     * @param $sources array 须要拼接的视频/音频     * @param $saveFile string 拼接后的视频/音频     */    public function spliceVideo($sources, $saveFile)    {        $commands = [];        $temporaryFile = [];        $basePath = sys_get_temp_dir();        $index = 0;        foreach ($sources as $i => $source) {            $file = $basePath . '/' . $i . '.ts';            $commands[$index] = $this->ffmpeg . ' -y -i '. $source .' -vcodec copy -acodec copy -vbsf h264_mp4toannexb ' . $file;            $temporaryFile[] = $file;            $index++;        }        $commands[$index] = $this->ffmpeg . ' -y -i "concat:'. implode('|', $temporaryFile) .'"  -acodec copy -vcodec copy -absf aac_adtstoasc ' . $saveFile;        foreach ($commands as $command) {            exec($command, $output, $result_code);        }        foreach ($temporaryFile as $file) {            @unlink($file);        }        return true;    }    /**     * 视频剪切     * @param $source string 须要剪切视频/音频     * @param $saveFile string 剪切后保留视频/音频     * @param $star string 剪切开始工夫     * @param null $duration string 剪切时长     */    public function clipVideo($source, $saveFile, $star, $duration = null)    {        $command = $this->ffmpeg . ' -y -ss '. $star;        if ($duration) {            $command .= ' -t '. $duration;        }        $command .= ' -i '. $source .' -acodec copy ' . $saveFile;        exec($command, $output, $result_code);        if ($result_code == 0) {            return true;        }        return  false;    }    const ROTATE_90 = 'transpose=1';    const ROTATE_180 = 'hflip,vflip';    const ROTATE_270 = 'transpose=2';    /**     * 视频旋转     * @param $source string 须要旋转的视频     * @param $saveFile string 旋转后视频     * @param $rotate string 旋转角度     */    public function transposeVideo($source, $saveFile, $rotate)    {        $command = $this->ffmpeg . ' -y -i ' . $source . ' -vf ""transpose=1"" ' . $saveFile;        exec($command, $output, $result_code);        if ($result_code == 0) {            return true;        }        return  false;    }    /**     * 视频转码     * @param $source string 须要转码的视频/音频     * @param $saveFile string 转码后的视频/音频     */    public function acodecVideo($source, $saveFile)    {        $command = $this->ffmpeg . ' -y -i '. $source .' -acodec copy -vcodec copy -f mp4 ' . $saveFile;        exec($command, $output, $result_code);        if ($result_code == 0) {            return true;        }        return  false;    }    /**     * 视频拼接     * @param $sources array 须要拼接的视频/音频     * @param $saveFile string 拼接后的视频/音频     */    public function concatVideo($sources, $saveFile)    {        $file = $this->createTemporaryFile();        $fileStream = @fopen($file, 'w');        if($fileStream === false) {            throw new ServerErrorHttpException('Cannot open the temporary file.');        }        $count_videos = 0;        if(is_array($sources) && (count($sources) > 0)) {            foreach ($sources as $videoPath) {                $line = "";                if($count_videos != 0)                    $line .= "\n";                $line .= "file '". str_replace('\\','/',$videoPath) ."'";                fwrite($fileStream, $line);                $count_videos++;            }        }        else {            throw new ServerErrorHttpException('The list of videos is not a valid array.');        }        $command = $this->ffmpeg .' -y -f concat -safe 0 -i '. $file . ' -c copy ' . $saveFile;        exec($command, $output, $result_code);        fclose($fileStream);        @unlink($file);//删除文件        if ($result_code == 0) {            return true;        }        return  false;    }    /**     * 创立一个临时文件     */    public function createTemporaryFile()    {        $basePath = sys_get_temp_dir();        if (false === $file = @tempnam($basePath, null)) {            throw new ServerErrorHttpException('Unable to generate a temporary filename');        }        return $file;    }    /**     * 获取视频信息     * @param $source string 须要获取时长的资源     */    public function getAttributes($source)    {        ob_start();        $command = $this->ffmpeg . ' -i "'. $source .'" 2>&1';        passthru($command);        $getContent = ob_get_contents();        ob_end_clean();        $duration = 0;        $widht = 0;        $height = 0;        if (preg_match("/Duration: (.*?), start: (.*?), bitrate: (\d*) kb\/s/", $getContent, $match)) {            $matchs = explode(':', $match[1]);            $duration = $matchs[0] * 3600 + $matchs[1] * 60 + $matchs[2]; //转换播放工夫为秒数        }        if (preg_match("/Video: (.*?), (.*?), (.*?)[,\s]/", $getContent, $match)) {            $matchs = explode('x', $match[3]);            $widht = $matchs[0];            $height = $matchs[1];        }        return [            'duration' => intval($duration),            'widht' => intval($widht),            'height' => intval($height),        ];    }}

应用简略示例

这里留神如果无奈执行ffmpeg,实例化时须要传入ffmpeg的装置地址,例如linux下ffmpeg装置地址为/usr/local/ffmepg,那么实例化时须要传入/usr/local/ffmpeg/bin/ffmpeg

1:给视频增加文字

$ffmpeg = new FfmpegVideo();$ffmpeg ->titleWater(    'XXX',//原视频    'XXX',//解决后保留视频    'XXX',//文字    [        'x' => 30,//程度间隔        'y' => 30,//垂直距离        'fontsize' => 20,//文字大小        'fontcolor' => 'red',//文字色彩        'shadowy' => 2,//文字暗影    ],    200,//每秒挪动步长    2//文字呈现工夫(秒));

2:将视频设为静音

$ffmpeg = new FfmpegVideo();$ffmpeg->audioMute(    'XXX',//原视频    'XXX',//解决后保留视频);

3:视频裁剪

$ffmpeg = new FfmpegVideo();$ffmpeg->clipVideo(    'XXX',//原视频    'XXX',//解决后保留视频    0,//裁剪开始工夫    10//裁剪时长);

4:视频拼接

$ffmpeg = new FfmpegVideo();$ffmpeg->concatVideo(    ['XXX', 'XXX'],//须要拼接的视频    'XXX',//解决后保留视频);

5:将音频合并到视频中

$ffmpeg = new FfmpegVideo();$ffmpeg->mergeVideoAudio(    'XXX',//视频    'XXX',//音频    'XXX',//解决后保留视频    0//音频插入视频延时工夫(秒));

6:获取视频信息(长,宽,时长)

$ffmpeg = new FfmpegVideo();$ffmpeg->getAttributes(    'XXX',//视频);

其余办法可查看demo