您的位置:首页 > 数据库 > Redis

laravel5.5集成FFmpeg,redis队列异步视频转码

2018-01-23 11:17 441 查看

1、laravel PHP-FFmpeg 扩展 下载地址:https://github.com/PHP-FFMpeg/PHP-FFMpeg

2、安装方法:

$ composer require php-ffmpeg/php-ffmpeg


3、使用:

安装redis:

$ composer require predis/predis


配置.env文件:

QUEUE_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=
REDIS_PORT=6379


更改 config/queue.php:

'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => '{default}',
'retry_after' => 36000,//这里设置10个小时转码消耗的最大时间
],
//注意:
//参数项 --timeout 的值应该是中小于配置项retry_after的值
//这是为了确保队列进程总在任务重试以前关闭。
//如果 --timeout 比retry_after 大,则你的任务可能被执行两次。


创建任务:

$ php artisan make:job MakeCoding


编辑 App/Jobs/MakeCoding.php:

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Config;
use App\Models\Element;//你的素材模型 自己定义

class MakeCoding implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* The number of seconds the job can run before timing out.
*
* @var int
*/
public $timeout = 30000; //最大超时时间
public $element_id; //素材id
public $relapath; //素材路径
public $chakge_path; //更改后的路径
public $tries = 3;//最大失败次数
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($relapath, $element_id)
{
$this->relapath    = $relapath;
$this->element_id  = $element_id;
}

/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$path              = public_path() . DIRECTORY_SEPARATOR . $this->relapath;//文件保存在public下
$save_path         = explode('.', $path)[0] . '.mp4';
$this->chakge_path = explode('.', $this->relapath)[0] . '.mp4';
$ffmpeg_path       = Config::get("phpFFmpeg.ffmpeg"); //ffmpeg运行的路径
$ffprobe_path      = Config::get("phpFFmpeg.ffprobe"); //ffprobe运行路径

$ffmpeg = \FFMpeg\FFMpeg::create(array(
'ffmpeg.binaries'  => $ffmpeg_path,
'ffprobe.binaries' => $ffprobe_path,
'timeout'          => 30000, // The timeout for the underlying process
'ffmpeg.threads'   => 12, // The number of threads that FFMpeg should use
));
$default = ini_get('max_execution_time');//取得php最大超时时间,相应的修改apache或nginx的配置文件中的超时时间,和文件上传大小限制
set_time_limit(-1);//设置成永不超时
$video  = $ffmpeg->open($path);
$format = new \FFMpeg\Format\Video\X264('libmp3lame', 'libx264');
$format->on('progress', function ($video, $format, $percentage) {
echo $percentage . '% ';//转码进度
if ($percentage >= 99) {//有的文件转码到99%会认为完成了
          //1、删除源文件
@unlink($path);
//2、修改数据库文件路径信息转码完成,自己定义
@Element::where('id', $this->element_id)->update(['path' => $this->chakge_path, 'trans_status' => '1']);
}
});
$video->save($format, $save_path);
set_time_limit($default);//恢复php的最大超时时间
}
}




添加配置文件 config/phpFFmpeg.php:

<?php
//windows
return [
'ffmpeg' =>'C:/xampp/php/ffmpeg/bin/ffmpeg.exe',
'ffprobe' =>'C:/xampp/php/ffmpeg/bin/ffprobe.exe',
];
 /*linux
return [
'ffmpeg' =>'/usr/local/ffmpeg/bin/ffmpeg',
'ffprobe' =>'/usr/local/ffmpeg/bin/ffprobe',
];*/


FFmpeg执行文件 linux版下载地址:http://pan.baidu.com/s/1c2GUOgC  提取码:n61c

在你的项目目录鼠标 Shift+右键 在此打开命令行 运行队列进程:

$ php artisan queue:work


编辑你的上传文件的 Controller:

<?php

use App\Jobs\MakeCoding;

//这里写伪代码
//1、上传文件
//2、保存到数据库
//3、如果是上传视频,并且不是mp4格式的,那么进行转码
//4、发送任务 参数:素材的真实保存路径和素材id
if ($type == 'video' && 'mp4' != $ext) {
dispatch(new MakeCoding($realpath, $element_id));
}


完成~!

 更多使用教程,看github文档说明。

下面是整理的一个 IOHelper :

1 <?php
2 /**
3  * IO公共操作类
4  */
5 class IOHelper
6 {
7     /**
8      * 获取音频或视频信息
9      * @param  [string] $path     [文件路径]
10      * @return [array]  result    [文件信息]
11      */
12     public static function getMediaInfo($path)
13     {
14         $result = array();
15         $cmd    = sprintf('/home/samba/ffmpeg/bin/ffprobe -v quiet -print_format json -show_format -show_streams "%s" 2>&1', $path);//你的FFMpeg执行文件地址自己定义
16         exec($cmd, $arr);
17         $obj = json_decode(implode($arr));
18
19         if ($obj && property_exists($obj, "format")) {
20             $type           = $obj->format->format_name;
21             $result["Type"] = $type;
22
23             if (false === stripos($type, "_pipe")) {
24                 $result["Duration"]        = (int) $obj->format->duration; //持续时间
25                 $result["DisplayDuration"] = self::formatTime($obj->format->duration); //格式化后的时间
26                 $result["byte_size"]       = (int) $obj->format->size; //字节大小
27                 $result["format_size"]     = self::formatSize($obj->format->size); //格式化后的大小
28             }
29
30             if ("mp3" != $type) {
31                 foreach ($obj->streams as $stream) {
32                     //视频流和音频流
33                     if ($stream->codec_type == "video") {
34                         //找到视频流
35                         $result["Resolution"] = sprintf("%sx%s", @$stream->width, @$stream->height); //分辨率
36                         break;
37                     }
38                 }
39             }
40         }
41
42         return $result;
43     }
44
45     /**
46      * 返回格式化后的时间格式
47      */
48     private static function formatTime($sec)
49     {
50         $sec           = $sec % (24 * 3600);
51         $hours         = floor($sec / 3600);
52         $remainSeconds = $sec % 3600;
53         $minutes       = floor($remainSeconds / 60);
54         $seconds       = intval($sec - $hours * 3600 - $minutes * 60);
55
56         return sprintf("%s:%s:%s", str_pad($hours, 2, "0", STR_PAD_LEFT), str_pad($minutes, 2, "0", STR_PAD_LEFT), str_pad($seconds, 2, "0", STR_PAD_LEFT));
57     }
58
59     /**
60      * 返回格式化后的文件尺寸
61      */
62     public static function formatSize($bytes, $decimals = 2)
63     {
64         $size       = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
65         $factor     = floor((strlen($bytes) - 1) / 3);
66         $byte       = $bytes / pow(1024, $factor);
67         $formatSize = floor($byte * 100) / 100;
68
69         return sprintf("%.{$decimals}f", $formatSize) . @$size[$factor];
70     }
71     /**
72      * *
73      * @return boolean [是否是windows系统]
74      */
75     public static function isWin()
76     {
77         if (substr(PHP_OS, 0, 3) === 'WIN') {
78             return true;
79         }
80         return false;
81     }
82     /**
83      * 判断目录是否为空
84      * @param  [string] $dir [目录路径]
85      * @return [bool]        [true/false]
86      */
87     public static function isEmptyDir($dir)
88     {
89         if (!is_dir($dir)) {
90             return "$dir is not a directory";
91         }
92         $handle = opendir($dir);
93         while (($file = readdir($handle)) !== false) {
94             if ($file != "." && $file != "..") {
95                 closedir($handle);
96                 return false;
97             }
98         }
99         closedir($handle);
100
101         return true;
102     }
103
104     /**
105      * 删除一个目录
106      * @param  [string] $dir [目录路径]
107      * @return [type]      [description]
108      */
109     public static function removeDir($dir)
110     {
111         if (! is_dir($dir))
112         {
113             return "$dir is not a directory";
114         }
115         $handle = opendir($dir);
116         while (($file = readdir($handle)) !== false)
117         {
118             if ($file != "." && $file != "..")
119             {
120                 is_dir("$dir/$file") ? removeDir("$dir/$file") : unlink("$dir/$file");
121             }
122         }
123         if (readdir($handle) == false)
124         {
125             closedir($handle);
126             rmdir($dir);
127         }
128     }
129
130     /**
131      * 生成一个文件
132      * @param  [type] $path [description]
133      * @param  [type] $data [description]
134      * @return [type]       [description]
135      */
136     public static function writeFile ($path, $data)
137     {
138         //$dir = str_replace('/'.basename($path),'',$path);
139         //@mkdir($dir,0777,true);
140         $fp = fopen($path, 'w');
141         if(fwrite($fp, $data)){
142             return true;
143         }
144         fclose($fp);
145         return false;
146     }
147
148     /**
149      * 自定义获取文件md5
150      * @param  [string] $file [文件路径]
151      * @return [string]       [md5值]
152      */
153     public static function md5($file)
154     {
155         if(! $fp = fopen($file, 'r')){
156             return false;
157         }
158
159         $size = filesize($file);
160         // 1024*1024 = 1MB
161         if (1048576 > $size) {
162             return  md5_file($file);
163         }
164
165         $file_path = '';
166         $file_path_temp = '';
167
168         fseek($fp, 0); // 1 - 2012
169         $file_path .= fread($fp, 2012);
170
171         fseek($fp, $size / 2 - 1999); // size/2 - 1999
172         $file_path .= fread($fp, 1999);
173
174         fseek($fp, -2010, SEEK_END); // -2010
175         $file_path .= fread($fp, 2010);
176
177         fclose($fp);
178
179         //自己定义你的临时文件路径
180         $file_path_temp = sprintf("%s/%s_%s", public_path(), time(), basename($file));
181
182         if(! $fp_temp = fopen($file_path_temp, "wb")){
183             return false;
184         }
185         //写入截取的文件片段
186         fwrite($fp_temp, $file_path);
187         fclose($fp_temp);
188
189         $md5 = md5_file($file_path_temp);
190         unlink($file_path_temp);
191
192         return $md5;
193     }
194 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: