首页 > 编程语言 >php实现ffmpeg处理视频的实践

php实现ffmpeg处理视频的实践

时间:2023-02-05 16:36:23浏览次数:43  
标签:视频 code return ffmpeg saveFile command result php

最近有一个项目需要使用FFmpeg处理视频,这里我写了一个demo,方便我们来实现视频操作

ffmpeg操作demo

<?PHP

namespace 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;


class FfmpegVideo
{

    public $ffmpeg = 'ffmpeg';


    public function __construct($ffmpeg = null)
    {
        if ($ffmpeg) {
            $this->ffmpeg = $ffmpeg;
        }
    }


    
    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;
    }


    
    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;
    }


    
    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;
    }

    
    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;
    }


    
    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;
    }

    
    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;
    }

    
    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;

    }


    
    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';

    
    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;
    }

    
    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;
    }

    
    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;
    }

    
    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',//视频
);

标签:视频,code,return,ffmpeg,saveFile,command,result,php
From: https://www.cnblogs.com/dituirenwu/p/17093533.html

相关文章

  • php中的标量数据类型总结
    php的数据类型可以分为三大类,分别是标量数据类型、复合数据类型和特殊数据类型。其中,标量数据类型是数据结构的最基础单元,只能存储一个数据。在 php 中的标量数据类型分......
  • PHP中最低级别的错误类型总结
    php的错误有很多种,包括warning、notice、deprecated、fetalerror等。其中notice不叫通知,而叫通知级别的错误,warning也不叫警告,而叫警告级别的错误。错误大致分为下面几个......
  • mac m1 安装php扩展
    安装xdebug进入https://pecl.php.net/package/Xdebug选择对应的版本下载php8.0下载xdebug-3.2.0.tgz解压tar-zxvfxdebug-3.2.0.tgz进入解压目录执行phpi......
  • 在macOS系统中编译FFmpeg(简单编译)
    官方文档:https://trac.ffmpeg.org/wiki/CompilationGuide/macOS步骤:gitclonehttps://git.ffmpeg.org/ffmpeg.git./configure--disable-x86asmmakemakeinstall(......
  • ThinkPHP6.0 模型搜索器的使用
    搜索器用于封装查询条件表达式,必须在模型中定义,只有使用模型操作数据时才能用搜索器。调用搜索器时使用的是数据表字段,可以不用定义搜索器方法,默认是=条件;如果不是数据......
  • 刷了一个月AI歌唱的视频 做一个大胆预测
    现在的AI热点转到ChatAI和AI唱歌去了很好理解(现在每天在看Neuro的切片感慨这才是看V的初心可惜Neuro这个形象在创立的时候只是一个ChatAI和游戏用的GameBOT并不是同一......
  • 群晖 WebStation PHP 使用 curl 进行 http 请求(群晖 WebStation php 安装第三方库)
    在群晖中,安装WebStation后,在安排配置PHP后,发现编写的php文件中有很多第三方库是无法适用的,运行就是500错误页面。遇到这种情况,我们需要为php添加对应的脚本库,具体......
  • 【PHP 随记】—— Composer 安装项目以及项目的扩展
    文章目录​​1、Composer安装项目​​​​①项目安装示例​​​​②相关问题解决​​​​③框架搜索指南​​​​2、Composer安装项目的扩展​​使用Composer更轻松......
  • 【PHP 随记】—— laravel 项目环境搭建
    文章目录​​1、安装laravel以及phpstorm开发插件​​​​2、配置虚拟主机与绑定hosts文件​​​​①配置虚拟主机​​​​②hosts绑定​​​​③验证​​​​3、......
  • 7 视频流系统设计
    视频流系统设计设计YoutubeScenario月活跃用户(MAU):20亿日活跃用户(DAU):1.5亿每天观看视频数量:50亿每分钟上传视频时长:500个小时用户平均观看时间:40分......