设为首页收藏本站

安徽论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 13974|回复: 0

php实现ffmpeg处理视频的实践

[复制链接]

110

主题

0

回帖

342

积分

中级会员

Rank: 3Rank: 3

积分
342
发表于 2022-3-26 11:00:36 | 显示全部楼层 |阅读模式
网站内容均来自网络,本站只提供信息平台,如有侵权请联系删除,谢谢!
最近有一个项目需要使用ffmpeg处理视频,这里我写了一个demo,方便我们来实现视频操作
ffmpeg操作demo
  1. <?php

  2. namespace common\helpers;

  3. use common\models\Config;
  4. use common\models\VideoApiLog;
  5. use Yii;
  6. use yii\helpers\ArrayHelper;
  7. use common\helpers\Universal;
  8. use yii\helpers\FileHelper;
  9. use yii\httpclient\Client;
  10. use yii\web\ServerErrorHttpException;

  11. /**
  12. * ffmpeg视频处理
  13. *
  14. * @author wangjian
  15. * @since 0.1
  16. */
  17. class FfmpegVideo
  18. {

  19.     public $ffmpeg = 'ffmpeg';


  20.     public function __construct($ffmpeg = null)
  21.     {
  22.         if ($ffmpeg) {
  23.             $this->ffmpeg = $ffmpeg;
  24.         }
  25.     }


  26.     /**
  27.      * 添加视频文字滚动
  28.      * @param $source string 视频
  29.      * @param $saveFile string 保存文件
  30.      * @param $text string 水印文字
  31.      * @param array $options 水印样式
  32.      * @param int $step 每秒步长
  33.      * @param int $star 出现时间
  34.      */
  35.     public function titleMod($source, $saveFile, $text, $options = [], $step = 20, $star = 0)
  36.     {
  37.         $command = $this->ffmpeg .' -y -i '. $source .' -async 1 -metadata:s:v:0 start_time=0 -vf ';

  38.         $fonts = Yii::getAlias('@webroot') . "/fonts/simsun.ttc";
  39.         $fonts = str_replace('\\', '/', $fonts);
  40.         $fonts = str_replace(':', '\\:', $fonts);
  41.         $command .= '"drawtext=fontfile=\''. $fonts .'\': text=\''. $text .'\'';

  42.         foreach ($options as $key => $value) {
  43.             $command .= ':' . $key . '=' . $value;
  44.         }

  45.         $command .= ':x=\'if(gte(t,'. $star .'),((t-'. $star .') * '. $step .'),NAN)\'';

  46.         $command .= '" ';
  47.         $command .= $saveFile;
  48.         exec($command, $output, $result_code);
  49.         if ($result_code == 0) {
  50.             return true;
  51.         }
  52.         return  false;
  53.     }


  54.     /**
  55.      * 图片水印
  56.      * @param $source string 视频
  57.      * @param $saveFile string 保存文件
  58.      * @param $waterImage string 水印图片
  59.      * @param $left integer 水印水平位置
  60.      * @param $top integer 水印垂直位置
  61.      * @param null $star 水印开始时间
  62.      * @param null $duration 水印时长
  63.      */
  64.     public function imageWater($source, $saveFile, $waterImage, $left, $top, $star = null, $duration = null)
  65.     {
  66.         $waterImage = str_replace('\\', '/', $waterImage);
  67.         $waterImage = str_replace(':', '\\:', $waterImage);
  68.         $command = $this->ffmpeg . ' -y -i '. $source .' -vf "movie=\''. $waterImage .'\'[watermark];';
  69.         $command .= '[in][watermark] overlay='. $left .':'. $top;
  70.         if ($star) {
  71.             $end = ($duration) ? $star + $duration : $star;
  72.             $command .= ':enable=\'between(t,'. $star .','. $end .')\'';
  73.         }
  74.         $command .= '[out] " ' . $saveFile;
  75.         exec($command, $output, $result_code);
  76.         if ($result_code == 0) {
  77.             return true;
  78.         }
  79.         return  false;
  80.     }


  81.     /**
  82.      * 给视频添加文字水印
  83.      * @param $source string 视频
  84.      * @param $saveFile string 保存文件
  85.      * @param $text string 水印文字
  86.      * @param array $options 水印样式
  87.      * @param null $star 水印开始时间
  88.      * @param null $duration 水印时长
  89.      */
  90.     public function titleWater($source, $saveFile, $text, $options = [], $star = null, $duration = null)
  91.     {
  92.         $command = $this->ffmpeg .' -y -i '. $source .' -vf ';
  93.         $fonts = Yii::getAlias('@webroot') . "/fonts/STZHONGS.TTF";
  94.         $fonts = str_replace('\\', '/', $fonts);
  95.         $fonts = str_replace(':', '\\:', $fonts);
  96.         $command .= '"drawtext=fontfile=\''. $fonts .'\': text=\''. $text .'\'';

  97.         foreach ($options as $key => $value) {
  98.             $command .= ':' . $key . '=' . $value;
  99.         }
  100.         if ($star) {
  101.             $end = ($duration) ? $star + $duration : $star;
  102.             $command .= ':enable=\'between(t,'. $star .','. $end .')\'';
  103.         }
  104.         $command .= '" ';
  105.         $command .= $saveFile;

  106.         exec($command, $output, $result_code);
  107.         if ($result_code == 0) {
  108.             return true;
  109.         }
  110.         return  false;
  111.     }

  112.     /**
  113.      * 将音频合并到视频中
  114.      * @param $videoFile string 视频文件
  115.      * @param $audioFile string 音频文件
  116.      * @param $saveFile string 保存文件
  117.      * @param $delay integer 声音插入延时秒数
  118.      */
  119.     public function mergeVideoAudio($videoFile, $audioFile, $saveFile, $delay = null)
  120.     {
  121.         $delayTime = 0;
  122.         if ($delay) {
  123.             $delayTime = $delay * 1000;
  124.         }
  125.         $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;
  126.         exec($command, $output, $result_code);
  127.         if ($result_code == 0) {
  128.             return true;
  129.         }
  130.         return  false;
  131.     }


  132.     /**
  133.      * 静音
  134.      */
  135.     public function audioMute($source, $saveFile)
  136.     {
  137.         $command =  $this->ffmpeg . ' -y -i '. $source .' -filter:a "volume=0" ' . $saveFile;
  138.         exec($command, $output, $result_code);
  139.         if ($result_code == 0) {
  140.             return true;
  141.         }
  142.         return  false;
  143.     }


  144.     /**
  145.      * 提取视频的音频
  146.      * @param $source string 需要提取声音的视频
  147.      * @param $saveFile string 提取声音后保存的音频
  148.      * @return bool
  149.      */
  150.     public function collectAudio($source, $saveFile)
  151.     {
  152.         $command =  $this->ffmpeg . ' -y -i '. $source .' -vn -acodec copy ' . $saveFile;
  153.         exec($command, $output, $result_code);
  154.         if ($result_code == 0) {
  155.             return true;
  156.         }
  157.         return  false;
  158.     }

  159.     /**
  160.      * 去除视频声音
  161.      * @param $source string 需要去除声音的视频
  162.      * @param $saveFile string 去除声音后保存的视频
  163.      */
  164.     public function removeAudio($source, $saveFile)
  165.     {
  166.         $command =  $this->ffmpeg . ' -y -i '. $source .' -an ' . $saveFile;

  167.         exec($command, $output, $result_code);
  168.         if ($result_code == 0) {
  169.             return true;
  170.         }
  171.         return  false;
  172.     }

  173.     /**
  174.      * 视频拼接
  175.      * @param $sources array 需要拼接的视频/音频
  176.      * @param $saveFile string 拼接后的视频/音频
  177.      */
  178.     public function spliceVideo($sources, $saveFile)
  179.     {
  180.         $commands = [];
  181.         $temporaryFile = [];
  182.         $basePath = sys_get_temp_dir();
  183.         $index = 0;
  184.         foreach ($sources as $i => $source) {
  185.             $file = $basePath . '/' . $i . '.ts';
  186.             $commands[$index] = $this->ffmpeg . ' -y -i '. $source .' -vcodec copy -acodec copy -vbsf h264_mp4toannexb ' . $file;
  187.             $temporaryFile[] = $file;
  188.             $index++;
  189.         }
  190.         $commands[$index] = $this->ffmpeg . ' -y -i "concat:'. implode('|', $temporaryFile) .'"  -acodec copy -vcodec copy -absf aac_adtstoasc ' . $saveFile;
  191.         foreach ($commands as $command) {
  192.             exec($command, $output, $result_code);
  193.         }

  194.         foreach ($temporaryFile as $file) {
  195.             @unlink($file);
  196.         }
  197.         return true;

  198.     }


  199.     /**
  200.      * 视频剪切
  201.      * @param $source string 需要剪切视频/音频
  202.      * @param $saveFile string 剪切后保存视频/音频
  203.      * @param $star string 剪切开始时间
  204.      * @param null $duration string 剪切时长
  205.      */
  206.     public function clipVideo($source, $saveFile, $star, $duration = null)
  207.     {
  208.         $command = $this->ffmpeg . ' -y -ss '. $star;
  209.         if ($duration) {
  210.             $command .= ' -t '. $duration;
  211.         }
  212.         $command .= ' -i '. $source .' -acodec copy ' . $saveFile;
  213.         exec($command, $output, $result_code);
  214.         if ($result_code == 0) {
  215.             return true;
  216.         }
  217.         return  false;
  218.     }

  219.     const ROTATE_90 = 'transpose=1';
  220.     const ROTATE_180 = 'hflip,vflip';
  221.     const ROTATE_270 = 'transpose=2';

  222.     /**
  223.      * 视频旋转
  224.      * @param $source string 需要旋转的视频
  225.      * @param $saveFile string 旋转后视频
  226.      * @param $rotate string 旋转角度
  227.      */
  228.     public function transposeVideo($source, $saveFile, $rotate)
  229.     {

  230.         $command = $this->ffmpeg . ' -y -i ' . $source . ' -vf ""transpose=1"" ' . $saveFile;
  231.         exec($command, $output, $result_code);
  232.         if ($result_code == 0) {
  233.             return true;
  234.         }
  235.         return  false;
  236.     }

  237.     /**
  238.      * 视频转码
  239.      * @param $source string 需要转码的视频/音频
  240.      * @param $saveFile string 转码后的视频/音频
  241.      */
  242.     public function acodecVideo($source, $saveFile)
  243.     {
  244.         $command = $this->ffmpeg . ' -y -i '. $source .' -acodec copy -vcodec copy -f mp4 ' . $saveFile;
  245.         exec($command, $output, $result_code);
  246.         if ($result_code == 0) {
  247.             return true;
  248.         }
  249.         return  false;
  250.     }

  251.     /**
  252.      * 视频拼接
  253.      * @param $sources array 需要拼接的视频/音频
  254.      * @param $saveFile string 拼接后的视频/音频
  255.      */
  256.     public function concatVideo($sources, $saveFile)
  257.     {
  258.         $file = $this->createTemporaryFile();
  259.         $fileStream = @fopen($file, 'w');
  260.         if($fileStream === false) {
  261.             throw new ServerErrorHttpException('Cannot open the temporary file.');
  262.         }

  263.         $count_videos = 0;
  264.         if(is_array($sources) && (count($sources) > 0)) {
  265.             foreach ($sources as $videoPath) {
  266.                 $line = "";
  267.                 if($count_videos != 0)
  268.                     $line .= "\n";
  269.                 $line .= "file '". str_replace('\\','/',$videoPath) ."'";

  270.                 fwrite($fileStream, $line);
  271.                 $count_videos++;
  272.             }
  273.         }
  274.         else {
  275.             throw new ServerErrorHttpException('The list of videos is not a valid array.');
  276.         }

  277.         $command = $this->ffmpeg .' -y -f concat -safe 0 -i '. $file . ' -c copy ' . $saveFile;
  278.         exec($command, $output, $result_code);
  279.         fclose($fileStream);
  280.         @unlink($file);//删除文件
  281.         if ($result_code == 0) {
  282.             return true;
  283.         }
  284.         return  false;
  285.     }

  286.     /**
  287.      * 创建一个临时文件
  288.      */
  289.     public function createTemporaryFile()
  290.     {
  291.         $basePath = sys_get_temp_dir();
  292.         if (false === $file = @tempnam($basePath, null)) {
  293.             throw new ServerErrorHttpException('Unable to generate a temporary filename');
  294.         }
  295.         return $file;
  296.     }

  297.     /**
  298.      * 获取视频信息
  299.      * @param $source string 需要获取时长的资源
  300.      */
  301.     public function getAttributes($source)
  302.     {
  303.         ob_start();
  304.         $command = $this->ffmpeg . ' -i "'. $source .'" 2>&1';
  305.         passthru($command);
  306.         $getContent = ob_get_contents();
  307.         ob_end_clean();
  308.         $duration = 0;
  309.         $widht = 0;
  310.         $height = 0;
  311.         if (preg_match("/Duration: (.*?), start: (.*?), bitrate: (\d*) kb\/s/", $getContent, $match)) {
  312.             $matchs = explode(':', $match[1]);
  313.             $duration = $matchs[0] * 3600 + $matchs[1] * 60 + $matchs[2]; //转换播放时间为秒数
  314.         }

  315.         if (preg_match("/Video: (.*?), (.*?), (.*?)[,\s]/", $getContent, $match)) {
  316.             $matchs = explode('x', $match[3]);
  317.             $widht = $matchs[0];
  318.             $height = $matchs[1];
  319.         }

  320.         return [
  321.             'duration' => intval($duration),
  322.             'widht' => intval($widht),
  323.             'height' => intval($height),
  324.         ];
  325.     }
  326. }
复制代码
使用简单示例


这里注意如果无法执行ffmpeg,实例化时需要传入ffmpeg的安装地址,例如linux下ffmpeg安装地址为/usr/local/ffmepg,那么实例化时需要传入/usr/local/ffmpeg/bin/ffmpeg
1:给视频添加文字

  1. $ffmpeg = new FfmpegVideo();
  2. $ffmpeg ->titleWater(
  3.     'XXX',//原视频
  4.     'XXX',//处理后保存视频
  5.     'XXX',//文字
  6.     [
  7.         'x' => 30,//水平距离
  8.         'y' => 30,//垂直距离
  9.         'fontsize' => 20,//文字大小
  10.         'fontcolor' => 'red',//文字颜色
  11.         'shadowy' => 2,//文字阴影
  12.     ],
  13.     200,//每秒移动步长
  14.     2//文字出现时间(秒)
  15. );
复制代码
2:将视频设为静音
  1. $ffmpeg = new FfmpegVideo();
  2. $ffmpeg->audioMute(
  3.     'XXX',//原视频
  4.     'XXX',//处理后保存视频
  5. );
复制代码
3:视频裁剪
  1. $ffmpeg = new FfmpegVideo();
  2. $ffmpeg->clipVideo(
  3.     'XXX',//原视频
  4.     'XXX',//处理后保存视频
  5.     0,//裁剪开始时间
  6.     10//裁剪时长
  7. );
复制代码
4:视频拼接
  1. $ffmpeg = new FfmpegVideo();
  2. $ffmpeg->concatVideo(
  3.     ['XXX', 'XXX'],//需要拼接的视频
  4.     'XXX',//处理后保存视频
  5. );
复制代码
5:将音频合并到视频中
  1. $ffmpeg = new FfmpegVideo();
  2. $ffmpeg->mergeVideoAudio(
  3.     'XXX',//视频
  4.     'XXX',//音频
  5.     'XXX',//处理后保存视频
  6.     0//音频插入视频延时时间(秒)
  7. );
复制代码
6:获取视频信息(长,宽,时长)
  1. $ffmpeg = new FfmpegVideo();
  2. $ffmpeg->getAttributes(
  3.     'XXX',//视频
  4. );
复制代码
到此这篇关于php实现ffmpeg处理视频的实践的文章就介绍到这了,更多相关php ffmpeg处理视频内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
                                                        
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
免责声明
1. 本论坛所提供的信息均来自网络,本网站只提供平台服务,所有账号发表的言论与本网站无关。
2. 其他单位或个人在使用、转载或引用本文时,必须事先获得该帖子作者和本人的同意。
3. 本帖部分内容转载自其他媒体,但并不代表本人赞同其观点和对其真实性负责。
4. 如有侵权,请立即联系,本网站将及时删除相关内容。
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表