柔晶美网络工作室

柔晶美网络工作室,倾心于web技术的博客站点

关注我 微信公众号

您现在的位置是: 首页 > 博客日记

Laravel6.1使用redis队列调用ffmpeg转换视频的方法

2019-10-04 admin laravel  1585

安装FFmpeg在前文已经详细写了,为了方便,只需要yum安装ffmpeg即可。如下代码安装:

sudo rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
sudo rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm
sudo yum install ffmpeg ffmpeg-devel -y

测试安装是否成功

ffmpeg

使用FFmpeg将flv转为mp4

ffmpeg -i beeen.flv -y -vcodec copy -acodec copy beeen.mp4

非常简单,在php使用中,要调用shell_exec,因此,需要在php.ini禁用函数中,删除shell.exec才可以执行。

接下来,用一个极简单的方式,测试laravel使用redis队列是否正常。

在.env文件找到QUEUE_DRIVER=sync改成QUEUE_DRIVER=redis,执行命令生成队列文件

php artisan make:job  ShipinQueue

在app/Jobs目录下有了ShipinQueue文件,编辑此文件,在handle方法下入入如下代码:

file_put_contents('wzb.txt','redis队列测试');
echo '恭喜你执行成功';

启动队列监听

php artisan queue:work

随便找一个可以访问的控制器方法,复制下面代码:

\App\Jobs\ShipinQueue::dispatch()->delay(10);
echo 'redis队列演示';die;

用浏览器访问你刚才的控制器方法,过10秒你会发现在控制台输出"恭喜你执行成功",并且项目的根目录会生成wzb.txt文件.

从上面的简单示例中可以看出,队列使用方法是:

// 这个任务将被分发到默认队列...
Job::dispatch();
// 这个任务将被发送到「emails」队列...
Job::dispatch()->onQueue('emails');

现在,我们正式开始今天的话题,使用redis队列转换视频。为了使用 database 队列驱动,你需要一张数据表来存储任务。执行命令生成数据库

php artisan queue:table
php artisan migrate

为了使用 redis 队列驱动,你需要在 config/database.php 配置文件中配置 Redis 的数据库连接。默认已配置好了,不用修改。

转码,为了方便,我们将用户上传的视频,一律转换成可html5播放的mp4格式,代码如下:

fastcgi_finish_request();//后台运行
//$zmjg = shell_exec("ffmpeg -y  -i $oldfile -strict -2 -map 0:v -map 0:a:1 $newfile");//视频自动转码  -map 0:a:1表示第二个音频轨道
$zmjg = shell_exec("ffmpeg -y  -i $oldfile -b:v 2000k -bufsize 2000k -maxrate 2500k -deinterlace -strict -2 $newfile 1> block.txt 2>&1");//控制码率
//$zmjg = shell_exec("ffmpeg -y  -i $oldfile -b:v 2000k -bufsize 2000k -maxrate 2500k -deinterlace -strict -2 -map 0:v -map 0:a:1 $newfile 1> block.txt 2>&1");//第二条音轨
$spjt = shell_exec("ffmpeg -y -ss 00:00:06 -i $oldfile -f image2 -s 720x480 $images");//视频截图
unlink($oldfile);//转码成功就删除原始文件

上面的代码中,需要使用的变量:

$oldfile:用户上传的文件;

$newfile:转换后保存的文件(都是相对路径);

$images:视频截图保存的位置。

为了方便,我们将转码后的视频和截图都保存在public/uploads/shipin/目录下面。将上面的代码修改一下,放在ShipinQueue.php的handle方法中。此外,为了引入以上变量,需要在构造函数中引入:

public function __construct($oldfile, $newfile,$images)
{
$this->oldfile = $oldfile;
$this->newfile = $newfile;
$this->images = $images;
}

在handle方法中,使用$this调用:

    public function handle()
    {
fastcgi_finish_request();//后台运行
//$zmjg = shell_exec("ffmpeg -y  -i $oldfile -strict -2 -map 0:v -map 0:a:1 $newfile");//视频自动转码  -map 0:a:1表示第二个音频轨道
$zmjg = shell_exec("ffmpeg -y  -i $this->oldfile -b:v 2000k -bufsize 2000k -maxrate 2500k -deinterlace -strict -2 $this->newfile 1> block.txt 2>&1");//控制码率
//$zmjg = shell_exec("ffmpeg -y  -i $oldfile -b:v 2000k -bufsize 2000k -maxrate 2500k -deinterlace -strict -2 -map 0:v -map 0:a:1 $newfile 1> block.txt 2>&1");//第二条音轨
$spjt = shell_exec("ffmpeg -y -ss 00:00:06 -i $this->oldfile -f image2 -s 720x480 $this->images");//视频截图
unlink($this->oldfile);//转码成功就删除原始文件
    }

在控制器中,需要传入以上三个变量。

if (file_exists($oldfile)){
\App\Jobs\ShipinQueue::dispatch($oldfile,$newfile,$images)->delay(10);
}

上传视频测试看看是否正常。先启动队列监听

php artisan queue:work

结果报错了,在failed_jobs表中记录了错误:

Symfony\Component\Debug\Exception\FatalThrowableError: Call to undefined function App\Jobs\fastcgi_finish_request() in /www/wwwroot/blog.dzbfsj.com/app/Jobs/ShipinQueue.php:34
Stack trace:
#0 [internal function]: App\Jobs\ShipinQueue->handle()

删除后台运行,加上文件存在判断,将其修改为:

    public function handle()
    {
if (file_exists($this->oldfile)){
//$zmjg = shell_exec("ffmpeg -y  -i $oldfile -strict -2 -map 0:v -map 0:a:1 $newfile");//视频自动转码  -map 0:a:1表示第二个音频轨道
$zmjg = shell_exec("ffmpeg -y  -i $this->oldfile -b:v 2000k -bufsize 2000k -maxrate 2500k -deinterlace -strict -2 $this->newfile 1> block.txt 2>&1");//控制码率
//$zmjg = shell_exec("ffmpeg -y  -i $oldfile -b:v 2000k -bufsize 2000k -maxrate 2500k -deinterlace -strict -2 -map 0:v -map 0:a:1 $newfile 1> block.txt 2>&1");//第二条音轨
$spjt = shell_exec("ffmpeg -y -ss 00:00:06 -i $this->oldfile -f image2 -s 720x480 $this->images");//视频截图
//unlink($this->oldfile);//转码成功就删除原始文件
}
    }

后台运行监测正常,但还需要将视频url和截图url更新成新的。

//保存后转码并更新视频链接
$form->saved(function (Form $form) {
$oldurl = $form->url;
$wjm = explode("_", $oldurl);
$filename = end($wjm);//文件名
$hz = explode(".", $oldurl);//文件后缀
$hz = '.'.end($hz);
$whzfile = str_replace($hz,'',$filename);//无后缀文件名
$oldfile = 'storage/'.str_replace('_','/',$oldurl);//上传的文件
$newfile = 'uploads/shipin/'.$whzfile.'.mp4';//转码后视频保存位置
$images = 'uploads/shipin/'.$whzfile.'.jpg';//视频截图位置
if (file_exists($oldfile)){
ShipinQueue::dispatch($oldfile,$newfile,$images);//队列
/**
$default = ini_get('max_execution_time');//取得php最大超时时间
set_time_limit(-1);//设置成永不超时
shell_exec("ffmpeg -y  -i $oldfile -b:v 2000k -bufsize 2000k -maxrate 2500k -deinterlace -strict -2 $newfile 1> block.txt 2>&1");//控制码率
shell_exec("ffmpeg -y -ss 00:00:06 -i $oldfile -f image2 -s 720x480 $images");//视频截图
unlink($oldfile);//转码成功就删除原始文件
set_time_limit($default);//恢复php的最大超时时间
**/
}
$id = $form->model()->id;
$gxurl = ShipinModel::where('id',$id)->first();
$gxurl->url = $newfile;
$gxurl->images = $images;
$gxurl->save();
});

再测试上传,发现路径错误。这是最大的坑!!!浪费一上午时间,后来发现,在控制器中不需要加public,但在队列任务中必须加public路径前缀!!!而且修改本文件后要执行php artisan queue:restart才生效

修改后正常的队列文件如下:

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;
class ShipinQueue implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    protected $oldfile;
    protected $newfile;
    protected $images;
public function __construct($oldfile, $newfile,$images)
{
$this->oldfile = $oldfile;
$this->newfile = $newfile;
$this->images = $images;
}
    public function handle()
    {
$default = ini_get('max_execution_time');//取得php最大超时时间
//特别要注意路径,需要从public开始,不能省略,和控制器中的引用路径不同,
修改本文件后要执行php artisan queue:restart才生效
    $oldfile = 'public/'.$this->oldfile;
    $newfile = 'public/'.$this->newfile;
    $images = 'public/'.$this->images;
    if (file_exists($oldfile)){
set_time_limit(-1);//设置成永不超时
shell_exec("ffmpeg -y  -i $oldfile -b:v 2000k -bufsize 2000k -maxrate 2500k -deinterlace 
-strict -2 $newfile 1> block.txt 2>&1");
shell_exec("ffmpeg -y -ss 00:00:06 -i $oldfile -f image2 -s 720x480 $images");//视频截图
unlink($oldfile);//转码成功就删除原始文件
set_time_limit($default);//恢复php的最大超时时间
    }
    }
}

监测任务完全正常了(红色的为截图,不影响截图功能)。

接下来,要让队列在后台永久运行,安装 supervisor

# sudo su - #切换为root用户
# yum install epel-release 
# yum install -y supervisor
# systemctl enable supervisord # 开机自启动 
# systemctl start supervisord # 启动supervisord服务
# systemctl status supervisord # 查看supervisord服务状态 
# ps -ef|grep supervisord # 查看是否存在supervisord进程

配置 Supervisor:

先修改 /etc/supervisord.conf 文件内容,将最后一句用;注释,并添加新的一句:

; files = supervisord.d/*.ini
files = /etc/supervisor/conf.d/*.conf

在 /etc/supervisor/ 下创建 conf.d 文件夹(mkdir直接创建),及 shipin.conf (以项目名称命名的),添加内容如下(注意路径要directory=/www/wwwroot/blog.dzbfsj.com/和你的系统相同,我的是宝塔面板,这是关键):

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php artisan queue:work
directory=/www/wwwroot/blog.dzbfsj.com/
autostart=true
autorestart=true
user=root
numprocs=1
redirect_stderr=true
stdout_logfile=/www/wwwlogs/worker.log

执行命令使配置文件生效

supervisorctl reread
supervisorctl update

重启 supervisord 或者修改了 /etc/supervisord.conf 执行

supervisorctl reload

接下来,开始正式运行:

supervisorctl start laravel-worker:*

查看运行状态

supervisorctl status
//提示RUNNING代表成功

查看进程 (ps -ef | grep ProjectName)

ps -ef|grep laravel

常用命令

service supervisord start   #启动
service supervisord stop    #停止
service supervisord status  #状态
supervisorctl reread
supervisorctl update
supervisorctl reload
supervisorctl status
supervisorctl shutdown  #关闭所有任务
supervisorctl stop|start program_name #启动或停止服务
supervisorctl status #查看所有任务状态

如果修改了laravel的队列文件,需要执行以来命令更新:

php artisan queue:restart
php artisan queue:work

如果不想安装这个,可以直接在终端运行这个,再关闭终端:

php artisan queue:work --daemon

或者:

nohup /www/server/php/73/bin/php /www/wwwroot/blog.dzbfsj.com/artisan queue:work 2>&1 > /dev/null &

如果是宝塔面板的话,已集成了该工具,直接在面板安装插件即可(不支持php7.3):

全部安装完毕。

注意,默认队列60秒超时,进行会被Killed,需要执行:

php artisan queue:work --timeout=0

文章评论


需要 登录 才能发表评论
热门评论
0条评论

暂时没有评论!