当前位置:首页 > PHP教程 > php应用 > 列表

php实现ffmpeg处理视频的实践

发布:smiling 来源: PHP粉丝网  添加日期:2022-05-20 11:10:26 浏览: 评论:0 

本文主要介绍了php实现ffmpeg处理视频的实践,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。

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

ffmpeg操作demo

  1. <?php 
  2.  
  3. namespace common\helpers; 
  4.  
  5. use common\models\Config; 
  6. use common\models\VideoApiLog; 
  7. use Yii; 
  8. use yii\helpers\ArrayHelper; 
  9. use common\helpers\Universal; 
  10. use yii\helpers\FileHelper; 
  11. use yii\httpclient\Client; 
  12. use yii\web\ServerErrorHttpException; 
  13.  
  14. /** 
  15.  * ffmpeg视频处理 
  16.  * 
  17.  * @author wangjian 
  18.  * @since 0.1 
  19.  */ 
  20. class FfmpegVideo 
  21. { 
  22.  
  23.     public $ffmpeg = 'ffmpeg'; 
  24.  
  25.  
  26.     public function __construct($ffmpeg = null) 
  27.     { 
  28.         if ($ffmpeg) { 
  29.             $this->ffmpeg = $ffmpeg; 
  30.         } 
  31.     } 
  32.  
  33.  
  34.     /** 
  35.      * 添加视频文字滚动 
  36.      * @param $source string 视频 
  37.      * @param $saveFile string 保存文件 
  38.      * @param $text string 水印文字 
  39.      * @param array $options 水印样式 
  40.      * @param int $step 每秒步长 
  41.      * @param int $star 出现时间 
  42.      */ 
  43.     public function titleMod($source, $saveFile, $text, $options = [], $step = 20, $star = 0) 
  44.     { 
  45.         $command = $this->ffmpeg .' -y -i '. $source .' -async 1 -metadata:s:v:0 start_time=0 -vf '; 
  46.  
  47.         $fonts = Yii::getAlias('@webroot') . "/fonts/simsun.ttc"; 
  48.         $fonts = str_replace('\\', '/', $fonts); 
  49.         $fonts = str_replace(':', '\\:', $fonts); 
  50.         $command .= '"drawtext=fontfile=\''. $fonts .'\': text=\''. $text .'\''; 
  51.  
  52.         foreach ($options as $key => $value) { 
  53.             $command .= ':' . $key . '=' . $value; 
  54.         } 
  55.  
  56.         $command .= ':x=\'if(gte(t,'. $star .'),((t-'. $star .') * '. $step .'),NAN)\''; 
  57.  
  58.         $command .= '" '; 
  59.         $command .= $saveFile; 
  60.         exec($command, $output, $result_code); 
  61.         if ($result_code == 0) { 
  62.             return true; 
  63.         } 
  64.         return  false; 
  65.     } 
  66.  
  67.  
  68.     /** 
  69.      * 图片水印 
  70.      * @param $source string 视频 
  71.      * @param $saveFile string 保存文件 
  72.      * @param $waterImage string 水印图片 
  73.      * @param $left integer 水印水平位置 
  74.      * @param $top integer 水印垂直位置 
  75.      * @param null $star 水印开始时间 
  76.      * @param null $duration 水印时长 
  77.      */ 
  78.     public function imageWater($source, $saveFile, $waterImage, $left, $top, $star = null, $duration = null) 
  79.     { 
  80.         $waterImage = str_replace('\\', '/', $waterImage); 
  81.         $waterImage = str_replace(':', '\\:', $waterImage); 
  82.         $command = $this->ffmpeg . ' -y -i '. $source .' -vf "movie=\''. $waterImage .'\'[watermark];'; 
  83.         $command .= '[in][watermark] overlay='. $left .':'. $top; 
  84.         if ($star) { 
  85.             $end = ($duration) ? $star + $duration : $star; 
  86.             $command .= ':enable=\'between(t,'. $star .','. $end .')\''; 
  87.         } 
  88.         $command .= '[out] " ' . $saveFile; 
  89.         exec($command, $output, $result_code); 
  90.         if ($result_code == 0) { 
  91.             return true; 
  92.         } 
  93.         return  false; 
  94.     } 
  95.  
  96.  
  97.     /** 
  98.      * 给视频添加文字水印 
  99.      * @param $source string 视频 
  100.      * @param $saveFile string 保存文件 
  101.      * @param $text string 水印文字 
  102.      * @param array $options 水印样式 
  103.      * @param null $star 水印开始时间 
  104.      * @param null $duration 水印时长 
  105.      */ 
  106.     public function titleWater($source, $saveFile, $text, $options = [], $star = null, $duration = null) 
  107.     { 
  108.         $command = $this->ffmpeg .' -y -i '. $source .' -vf '; 
  109.         $fonts = Yii::getAlias('@webroot') . "/fonts/STZHONGS.TTF"; 
  110.         $fonts = str_replace('\\', '/', $fonts); 
  111.         $fonts = str_replace(':', '\\:', $fonts); 
  112.         $command .= '"drawtext=fontfile=\''. $fonts .'\': text=\''. $text .'\''; 
  113.  
  114.         foreach ($options as $key => $value) { 
  115.             $command .= ':' . $key . '=' . $value; 
  116.         } 
  117.         if ($star) { 
  118.             $end = ($duration) ? $star + $duration : $star; 
  119.             $command .= ':enable=\'between(t,'. $star .','. $end .')\''; 
  120.         } 
  121.         $command .= '" '; 
  122.         $command .= $saveFile; 
  123.  
  124.         exec($command, $output, $result_code); 
  125.         if ($result_code == 0) { 
  126.             return true; 
  127.         } 
  128.         return  false; 
  129.     } 
  130.  
  131.     /** 
  132.      * 将音频合并到视频中 
  133.      * @param $videoFile string 视频文件 
  134.      * @param $audioFile string 音频文件 
  135.      * @param $saveFile string 保存文件 
  136.      * @param $delay integer 声音插入延时秒数 
  137.      */ 
  138.     public function mergeVideoAudio($videoFile, $audioFile, $saveFile, $delay = null) 
  139.     { 
  140.         $delayTime = 0; 
  141.         if ($delay) { 
  142.             $delayTime = $delay * 1000; 
  143.         } 
  144.         $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; 
  145.         exec($command, $output, $result_code); 
  146.         if ($result_code == 0) { 
  147.             return true; 
  148.         } 
  149.         return  false; 
  150.     } 
  151.  
  152.  
  153.     /** 
  154.      * 静音 
  155.      */ 
  156.     public function audioMute($source, $saveFile) 
  157.     { 
  158.         $command =  $this->ffmpeg . ' -y -i '. $source .' -filter:a "volume=0" ' . $saveFile; 
  159.         exec($command, $output, $result_code); 
  160.         if ($result_code == 0) { 
  161.             return true; 
  162.         } 
  163.         return  false; 
  164.     } 
  165.  
  166.  
  167.     /** 
  168.      * 提取视频的音频 
  169.      * @param $source string 需要提取声音的视频 
  170.      * @param $saveFile string 提取声音后保存的音频 
  171.      * @return bool 
  172.      */ 
  173.     public function collectAudio($source, $saveFile) 
  174.     { 
  175.         $command =  $this->ffmpeg . ' -y -i '. $source .' -vn -acodec copy ' . $saveFile; 
  176.         exec($command, $output, $result_code); 
  177.         if ($result_code == 0) { 
  178.             return true; 
  179.         } 
  180.         return  false; 
  181.     } 
  182.  
  183.     /** 
  184.      * 去除视频声音 
  185.      * @param $source string 需要去除声音的视频 
  186.      * @param $saveFile string 去除声音后保存的视频 
  187.      */ 
  188.     public function removeAudio($source, $saveFile) 
  189.     { 
  190.         $command =  $this->ffmpeg . ' -y -i '. $source .' -an ' . $saveFile; 
  191.  
  192.         exec($command, $output, $result_code); 
  193.         if ($result_code == 0) { 
  194.             return true; 
  195.         } 
  196.         return  false; 
  197.     } 
  198.  
  199.     /** 
  200.      * 视频拼接 
  201.      * @param $sources array 需要拼接的视频/音频 
  202.      * @param $saveFile string 拼接后的视频/音频 
  203.      */ 
  204.     public function spliceVideo($sources, $saveFile) 
  205.     { 
  206.         $commands = []; 
  207.         $temporaryFile = []; 
  208.         $basePath = sys_get_temp_dir(); 
  209.         $index = 0; 
  210.         foreach ($sources as $i => $source) { 
  211.             $file = $basePath . '/' . $i . '.ts'; 
  212.             $commands[$index] = $this->ffmpeg . ' -y -i '. $source .' -vcodec copy -acodec copy -vbsf h264_mp4toannexb ' . $file; 
  213.             $temporaryFile[] = $file; 
  214.             $index++; 
  215.         } 
  216.         $commands[$index] = $this->ffmpeg . ' -y -i "concat:'. implode('|', $temporaryFile) .'"  -acodec copy -vcodec copy -absf aac_adtstoasc ' . $saveFile; 
  217.         foreach ($commands as $command) { 
  218.             exec($command, $output, $result_code); 
  219.         } 
  220.  
  221.         foreach ($temporaryFile as $file) { 
  222.             @unlink($file); 
  223.         } 
  224.         return true; 
  225.  
  226.     } 
  227.  
  228.  
  229.     /** 
  230.      * 视频剪切 
  231.      * @param $source string 需要剪切视频/音频 
  232.      * @param $saveFile string 剪切后保存视频/音频 
  233.      * @param $star string 剪切开始时间 
  234.      * @param null $duration string 剪切时长 
  235.      */ 
  236.     public function clipVideo($source, $saveFile, $star, $duration = null) 
  237.     { 
  238.         $command = $this->ffmpeg . ' -y -ss '. $star; 
  239.         if ($duration) { 
  240.             $command .= ' -t '. $duration; 
  241.         } 
  242.         $command .= ' -i '. $source .' -acodec copy ' . $saveFile; 
  243.         exec($command, $output, $result_code); 
  244.         if ($result_code == 0) { 
  245.             return true; 
  246.         } 
  247.         return  false; 
  248.     } 
  249.  
  250.     const ROTATE_90 = 'transpose=1'; 
  251.     const ROTATE_180 = 'hflip,vflip'; 
  252.     const ROTATE_270 = 'transpose=2'; 
  253.  
  254.     /** 
  255.      * 视频旋转 
  256.      * @param $source string 需要旋转的视频 
  257.      * @param $saveFile string 旋转后视频 
  258.      * @param $rotate string 旋转角度 
  259.      */ 
  260.     public function transposeVideo($source, $saveFile, $rotate) 
  261.     { 
  262.  
  263.         $command = $this->ffmpeg . ' -y -i ' . $source . ' -vf ""transpose=1"" ' . $saveFile; 
  264.         exec($command, $output, $result_code); 
  265.         if ($result_code == 0) { 
  266.             return true; 
  267.         } 
  268.         return  false; 
  269.     } 
  270.  
  271.     /** 
  272.      * 视频转码 
  273.      * @param $source string 需要转码的视频/音频 
  274.      * @param $saveFile string 转码后的视频/音频 
  275.      */ 
  276.     public function acodecVideo($source, $saveFile) 
  277.     { 
  278.         $command = $this->ffmpeg . ' -y -i '. $source .' -acodec copy -vcodec copy -f mp4 ' . $saveFile; 
  279.         exec($command, $output, $result_code); 
  280.         if ($result_code == 0) { 
  281.             return true; 
  282.         } 
  283.         return  false; 
  284.     } 
  285.  
  286.     /** 
  287.      * 视频拼接 
  288.      * @param $sources array 需要拼接的视频/音频 
  289.      * @param $saveFile string 拼接后的视频/音频 
  290.      */ 
  291.     public function concatVideo($sources, $saveFile) 
  292.     { 
  293.         $file = $this->createTemporaryFile(); 
  294.         $fileStream = @fopen($file, 'w'); 
  295.         if($fileStream === false) { 
  296.             throw new ServerErrorHttpException('Cannot open the temporary file.'); 
  297.         } 
  298.  
  299.         $count_videos = 0; 
  300.         if(is_array($sources) && (count($sources) > 0)) { 
  301.             foreach ($sources as $videoPath) { 
  302.                 $line = ""; 
  303.                 if($count_videos != 0) 
  304.                     $line .= "\n"; 
  305.                 $line .= "file '". str_replace('\\','/',$videoPath) ."'"; 
  306.  
  307.                 fwrite($fileStream, $line); 
  308.                 $count_videos++; 
  309.             } 
  310.         } 
  311.         else { 
  312.             throw new ServerErrorHttpException('The list of videos is not a valid array.'); 
  313.         } 
  314.  
  315.         $command = $this->ffmpeg .' -y -f concat -safe 0 -i '. $file . ' -c copy ' . $saveFile; 
  316.         exec($command, $output, $result_code); 
  317.         fclose($fileStream); 
  318.         @unlink($file);//删除文件 
  319.         if ($result_code == 0) { 
  320.             return true; 
  321.         } 
  322.         return  false; 
  323.     } 
  324.  
  325.     /** 
  326.      * 创建一个临时文件 
  327.      */ 
  328.     public function createTemporaryFile() 
  329.     { 
  330.         $basePath = sys_get_temp_dir(); 
  331.         if (false === $file = @tempnam($basePath, null)) { 
  332.             throw new ServerErrorHttpException('Unable to generate a temporary filename'); 
  333.         } 
  334.         return $file; 
  335.     } 
  336.  
  337.     /** 
  338.      * 获取视频信息 
  339.      * @param $source string 需要获取时长的资源 
  340.      */ 
  341.     public function getAttributes($source) 
  342.     { 
  343.         ob_start(); 
  344.         $command = $this->ffmpeg . ' -i "'. $source .'" 2>&1'; 
  345.         passthru($command); 
  346.         $getContent = ob_get_contents(); 
  347.         ob_end_clean(); 
  348.         $duration = 0; 
  349.         $widht = 0; 
  350.         $height = 0; 
  351.         if (preg_match("/Duration: (.*?), start: (.*?), bitrate: (\d*) kb\/s/", $getContent, $match)) { 
  352.             $matchs = explode(':', $match[1]); 
  353.             $duration = $matchs[0] * 3600 + $matchs[1] * 60 + $matchs[2]; //转换播放时间为秒数 
  354.         } 
  355.  
  356.         if (preg_match("/Video: (.*?), (.*?), (.*?)[,\s]/", $getContent, $match)) { 
  357.             $matchs = explode('x', $match[3]); 
  358.             $widht = $matchs[0]; 
  359.             $height = $matchs[1]; 
  360.         } 
  361.  
  362.         return [ 
  363.             'duration' => intval($duration), 
  364.             'widht' => intval($widht), 
  365.             'height' => intval($height), 
  366.         ]; 
  367.     } 
  368. } 

使用简单示例

这里注意如果无法执行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. );

Tags: ffmpeg

分享到: