这是自己搭建直播服务器、开发直播平台系列的文章,前面的文章分别为:

一些前面已经提到的问题,这里不再重复。

一、需求

很多直播网站我们都能看到一些截图封面,往往用于列表展示用,如下面所示:

f1.jpg

一个截图封面技能反映出当前直播间在直播什么东西,用户查看浏览的体验也非常好。

本篇文章就是利用 ffmpeg 实现对视频进行截图处理,而且实现每隔一段时间截图一次(目前所有的直播间都是这么干的)。

二、准备工作 ffmpeg

关于ffmpeg的介绍我就不多说了,后面实现hls切片以及保存也要用到。

需要注意的是,这里的ffmpeg是装在web服务器上,而不是装在RTMP流媒体服务器上的。(当然,如果你都用的一台服务器那就不需要考虑)

这里的FFmpeg在web服务器上工作,通过php操作命令,并且加入crontab任务计划。

与装在rtmp服务器上(之后会涉及)不同的是,只需要安装即可,不需要考虑加module,因为我们只是用来切片

1、下载安装

网站以及下载地址:

下载下来之后解压即可,解压后进行编译安装。

configure的时候会需求yasm,直接apt-get install yasm即可!

# --prefix-dist /usr/local/ffmpeg 指定安装目录
# 我自己安装的时候没有指定直接就是 ./configure 了
# 指定安装目录需要将 /usr/local/ffmpeg/bin/ffmpeg 链接到/usr/bin/才能全局使用,否则只能 /usr/local/ffmpeg/bin/ffmpeg 这样使用命令(貌似可以会自动写入/usr/bin/,这个要自己试试就可以)

$ ./configure --prefix=/usr/local/ffmpeg
$ make && make install

安装成功过之后就能使用ffmpeg,关于如何完整的安装ffmpeg,就是加上对各种视频的协议的支持可以看看下面这篇文章(未验证,之后会进行验证):

2、利用ffmpeg 对视频流进行截图

ffmpeg是不仅仅能截图也能截取视频,我们这里只是需要截图,而且是对视频流的截图:

所谓的截图就是截一帧的视频

$ ffmpeg -i rtmp://rtmp-postbird/10000 -f image2 -ss 5 -vframes 1 -s 220*220 /data/live/10000.png

上面的参数解释

  • i —— 视频流
  • f —— 保存格式
  • ss —— 5秒钟之后
  • vframes —— 截取的帧数
  • s —— 截取的大小
  • 保存的路径

因此上面的命令可以理解为:

5秒钟之后,从rtmp://rtmp-postbird/10000 的视频流中截取200*200的图保存在/data/live/10000.png。

更多其他操作可以看看官方文档以及下面的博文:

三、结合系统数据库进行操作

上面我们只是手动的能够截图而已,我们需要做到的是:

  • 通过crontab任务计划定时执行截图工作
  • 截图的时候只截取当前系统中正在直播的视频流(结合系统数据库)
  • 截图的保存名称为流的名称,而且需要覆盖掉旧的截图

1、两个前提:

需要知道如何利用php操作linux系统命令以及如何在linux中调用远程url执行

所以我在之前也写了两篇文章:

能够解决上面两个问题,我们就能够实际的去写php进行相关的业务实现。

2、代码

这里的代码做到的功能是:

  • 通过rtmp视频流的流名称进行唯一的标识与图片名称的命名

    • rtmp://rtmp-postbird/myapp/10000 中10000就是流名称
  • 直接将图片保存在web系统的static文件夹中,这样子可以直接根据名称读取

更多的东西我在代码中已经写得很明白了(框架使用的是thinkphp5,我想即使用了框架也能看懂)

    /**
     * 对正在直播的直播间进行视频流截图
     * - 运行system linux命令
     * - 保存的名称就是直播间的guid的名称
     * - 覆盖掉之前的文件
     */
    function ffmpegPhoto(){
        // 查找所有正在直播的房间的guid
        $allRoomIGuid=Db::name('room')->where(['status'=>1])->select();
        // 循环执行ffmpeg 截图功能
        $countAllRoom=count($allRoomIGuid);
        for($i=0;$i<$countAllRoom;$i++){
            // 从配置中获得ffmpeg截图存放位置
            // 这个是全局配置的,比如 /data/web/public/static/live/
            // 建议这个地址是web网站目录结构中的一个地址,确保权限是777
            $photoPos=Config::get('ffmpeg.photoPos');
            // 获得时间戳文件名
            $fileStamp=$allRoomIGuid[$i]['guid']."_".time();
            // 重命名原来的文件 结合timestamp
            $cmd=" mv ".$photoPos."/".$allRoomIGuid[$i]['guid'].".png ".$photoPos."/".$fileStamp.".png";
            // echo($cmd);
            $result=system($cmd,$res);
            echo $res."-";
            // 从配置中获取视频流
            // 这个也是配置的 值如:rtmp://rtmp-postbird/myapp
            // 而实际的观看流是 rtmp://rtmp-postbird/myapp/10000 10000是guid
            $rtmpUrl=Config::get('view_replace_str.__RTMP_URL__');
            /**
             *  拼接ffmpeg命令行
             *  - 下面命令表示从 rtmp://192.168.124.129/myapp/10000 视频流的2秒后切一个图
             *  - 存放名称路径是下面的代码
             */
            $cmd="ffmpeg -i ".$rtmpUrl."/".$allRoomIGuid[$i]['guid']." -f image2 -ss 1 -vframes 1 -s 400*300 ".$photoPos."/".$allRoomIGuid[$i]['guid'].".png ";
            // 使用system函数执行系统命令
            // echo $cmd;
            $result=system($cmd,$res);
            echo $res."-";
            if($res==1){
                // 如果执行失败 则说明没有生成新的文件,讲原来的mv操作撤销
                $cmd=" mv ".$photoPos."/".$fileStamp.".png ".$photoPos."/".$allRoomIGuid[$i]['guid'].".png";
                system($cmd,$res);
                echo $res."-";
            }
        }
        return "done";
    }

需要说明的问题

  • 保存的文件夹最好是web系统的一部分,能够直接通过代码get到的
  • 保存的文件名一直是guid.png是为了到时候能够直接通过 img src="/.../static/live/1000.png"获得
  • 保存的文件夹一定是777权限,原因可以看php执行system()命令和一个坑
  • 这个只是一个函数,需要映射成对应的可访问url,如:http://url/ffmpeg_photo.html

通过上面的操作,我们已经做好的php执行ffmpeg,可以通过访问url试试能不能实现,如果没有问题,则开始在linux中加入crontab,使用lynx来访问这个url。

如何使用lynx以及如何使用crontab来操作,我在下面的文章中写的很详细了:

我做的crontab的配置如下:

*/1 * * * * lynx -dump http://url/ffmpeg_photo.html >> /data/live.log 2>&1

上面的php代码每次执行的结果($res)我都会输出,然后在linux输出到/data/live.log,方便查找错误。

为了测试,我定时是每分钟都进行截图,因此效果如下(好多图片..):

f2.jpg

但是可以发现里面只有一张是10000.png,其他的都被我重命名了.

四、在网站中使用该图片

使用图片直接用就行了,因为你放在了web系统目录下,可以直接引用的。

f3.jpg