php實現ffmpeg處理視頻的實踐
最近有一個項目需要使用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; /** * 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',//視頻 );
到此這篇關於php實現ffmpeg處理視頻的實踐的文章就介紹到這瞭,更多相關php ffmpeg處理視頻內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- php如何利用ffmpeg獲取視頻第一幀為縮略圖
- FFmpeg Principle學習open_output_file打開輸出文件
- java調用FFmpeg實現視屏壓縮功能的詳細步驟
- Android NDK開發之FFmpeg視頻添加水印
- ffmpeg網頁視頻流m3u8 ts實現視頻下載