PHP结合Ffmpeg快速搭建流媒体服务的实践记录


Posted in PHP onOctober 31, 2018

一、背景

ffmpeg应该是目前最强大的视频管理程序,当你需要截取视频第一帧,对视频类型进行转换,截取gif图片等一系列对视频的操作,ffmpeg绝对是最好的扩展

笔者想将自己收藏的一些电影放到网站上可以用来随时播放,不过遇到了一个问题,便是如果直接将MP4文件放放到网站目录当中,手机端必须下载整个视频才可以播放,而如果跨外网传输,这实在是不太现实。

为了解决这个问题,便想着搭建一套流媒体服务,这样手机就可以边看边下载,查询了一些资料了了解到需要先将视频分成一小片来传输,比如将MP4转码为M3U8格式,查询了相关转码方法,比较主流的方式是使用ffmpeg这个开源工具

二、操作概要

  • 安装Ffmpeg
  • 服务搭建
  • 功能测试

三、搭建ffmpeg

视频转码的工具可能有很多,但开源且使用人数最多的还是莫过于ffmpeg这个工具,具体功能笔者不在这里详细讲解;安装此工具的方式有很多,比如apt安装、源码安装、docker安装等等,不过docker是跨平台的,因此笔者这里将以docker方式安装为例

3.1 镜像下载

首先笔者需要下载对应的docker镜像,参考命令如下

docker pull jrottenberg/ffmpeg

命令执行过程中将会从远处下载镜像,这个时间由当前的网络带宽所决定,当下载完成之后,可以看到如下参考信息

Using default tag: latest
latest: Pulling from jrottenberg/ffmpeg
b234f539f7a1: Pull complete
55172d420b43: Pull complete
5ba5bbeb6b91: Pull complete
43ae2841ad7a: Pull complete
f6c9c6de4190: Pull complete
2a0ef76bfa54: Pull complete
40ddf796a4bb: Pull complete
32ba137d2764: Pull complete
Digest: sha256:bcf65375f593518de7e450fd6b775d16a047d3ded00957c2e794e2fe8f7e1590
Status: Downloaded newer image for jrottenberg/ffmpeg:latest

3.2 容器运行

当容器下载完毕之后,可以用一些命令进行验证是否能够正常运行,如下参考命令

docker run jrottenberg/ffmpeg

命令执行完毕之后,会返回如下结果

Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...

Getting help:

..... 省略

Audio options:
-aframes number  set the number of audio frames to output
-aq quality   set audio quality (codec-specific)
-ar rate   set audio sampling rate (in Hz)
-ac channels  set number of audio channels
-an     disable audio
-acodec codec  force audio codec ('copy' to copy stream)
-vol volume   change audio volume (256=normal)
-af filter_graph set audio filters

Subtitle options:
-s size    set frame size (WxH or abbreviation)
-sn     disable subtitle
-scodec codec  force subtitle codec ('copy' to copy stream)
-stag fourcc/tag force subtitle tag/fourcc
-fix_sub_duration fix subtitles duration
-canvas_size size set canvas size (WxH or abbreviation)
-spre preset  set the subtitle options to the indicated preset

3.3 查看支持协议

FFmpeg所支持的输入输出协议非常多,比如可以选择file协议作为来源,使用hls协议作为输出结果,具体所支持的协议可以通过如下命令查看

docker run jrottenberg/ffmpeg -protocols

执行命令之后,参考结果如下

ffmpeg version 3.4.2 Copyright (c) 2000-2018 the FFmpeg developers
 built with gcc 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.9) 20160609
 configuration: --disable-debug --disable-doc --disable-ffplay --enable-shared --enable-avresample --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-gpl --enable-libass --enable-libfreetype --enable-libvidstab --enable-libmp3lame --enable-libopenjpeg --enable-libopus --enable-libtheora --enable-libvorbis
 ..... 省略
 Supported file protocols:
Input:
 async
 cache
 concat
 crypto
 data
 ..... 省略
Output:
 crypto
 file
 ..... 省略
 tls
 udp

3.4 转换测试

现在笔者使用FFmpeg对视频进行转码测试,命令非常简单,首先需要通过-v将视频所在的目录挂载到容器中,然后使用-i选项找到容器中对应的视频文件;

接着就可以对编码进行一些选项,比如-hls_time 10便是将文件没10秒输出一个TS文件,-hls_list_size 0 则是在m3u8文件中记录所以ts文件(默认是记录最后五个TS文件),参数最后则填写文件输出路径,具体参考命令如下:

docker run -v /Users/song/video:/root/download jrottenberg/ffmpeg:latest -i /root/download/1.mp4 -hls_time 10 -hls_list_size 0 -f hls /root/download/index.m3u8

命令执行过程中会展示转换进度,参考如下返回所示

Metadata:
 major_brand  : mp42
 minor_version : 0
 compatible_brands: mp42mp41
 encoder   : Lavf57.83.100
 Stream #0:0(eng): Video: h264 (libx264), yuv420p(progressive), 1920x1080, q=-1--1, 30 fps, 90k tbn, 30 tbc (default)
 Metadata:
  creation_time : 2018-08-21T15:09:24.000000Z
  handler_name : Alias Data Handler
  encoder   : Lavc57.107.100 libx264
 Side data:
  cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
 Stream #0:1(eng): Audio: aac, 48000 Hz, stereo, fltp, 128 kb/s (default)
 Metadata:
  creation_time : 2018-08-21T15:09:24.000000Z
  handler_name : Alias Data Handler
  encoder   : Lavc57.107.100 aac
frame= 82 fps= 12 q=29.0 size=N/A time=00:00:02.62 bitrate=N/A speed=0.381x

此时便可以在刚才的挂载点查看TS文件,如下图所示

PHP结合Ffmpeg快速搭建流媒体服务的实践记录

现在笔者将刚才的TS文件都删除,在下面将使用自动化完成。

四、服务搭建

在上一步中笔者已经成功通过终端使用FFmpeg将视频进行转码,下面笔者将结合PHP代码将这些操作完全自动化实现,这样便可以达到通过手机访问网站,服务端自动完成转码播放的需求,这个过程包括创建虚拟主机、编写展示视频列表、视频自动解码三个部分

4.1 创建虚拟主机

首先笔者需要借助nginx搭建一个web服务,这时便需要修改配置文件,但并不记得nginx配置文件存放位置,此时可以借助如下命令

sudo nginx -t

得到结果如下,在结果中可以便可以看到nginx的配置文件存放位置

nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful

使用vim编辑器直接编辑nginx配置文件

vim /usr/local/etc/nginx/nginx.conf

然后在配置文件中加入如下参考配置信息

server {
  listen  8089;
  server_name localhost;
  root /Users/song/mycode/work/test/video;
  location / {
   index index.html index.htm index.php; 
  }

  location ~ \.php$ {
   fastcgi_pass 127.0.0.1:9000;
   fastcgi_index index.php;
   fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
   include  fastcgi_params;
  }

 }

4.2 获取视频列表

nginx配置完成之后,便需要编写PHP代码,通过PHP可以获取到目录的视频列表,然后将其输出到网页当中,参考代码如下所示

<?php
 $list = scandir('/Users/song/video/');

 foreach ($list as $key => $val) {
  if (!in_array(pathinfo($val, PATHINFO_EXTENSION), ['mp4', 'rmvb', 'wmv'])) {
   continue;
  }

  ?>

  <a class="btn btn-default btn-video btn-lg" href="./encode.php?name=<?= $val ?>" role="button">
   <h2><?= $val ?></h2></a>

 <?php }
} ?>

在代码中,首先通过scandir读取文件夹下所有文件,然后进行foreach循环,通过后缀名来判断是否为视频文件,如果是视频文件,则输出一个链接地址方便用户选择。

4.3 进行视频转码

上面的代码在列出视频列表之后,当用户点击链接后就需要使用FFmpeg进行转码,参考代码如下

<?php

//接收必要参数
$name = $_GET['name'] ?? '1.mp4';
$forced = $_GET['forced'] ?? 0;
$fileName = getFileName($name);

$outPath = '/Users/song/video';
$inPath = '/root/download';
$dir = __DIR__;

//判断之前是否已经转码,如果不强制转码便先返回
if (is_dir("$outPath/$fileName") && empty($forced)) {
 header("location:./static/{$fileName}/index.m3u8");
 die;
}

//将目标映射过来
system("ln -s {$outPath} {$dir}/static");

//先创建文件夹
system("mkdir -p {$outPath}/{$fileName}");

//进行转码
$ffmpeg = "docker run -v $outPath:/root/download jrottenberg/ffmpeg:latest";
$cmd = "nohup $ffmpeg -i {$inPath}/{$name} -hls_time 10 -hls_list_size 0 -f hls -r 25 {$inPath}/{$fileName}/index.m3u8 >> ./code.log &";
system($cmd);


//延时执行跳转
returnUrl($fileName);

function getFileName($filename)
{
 $houzhui = substr(strrchr($filename, '.'), 1);
 $result = basename($filename, "." . $houzhui);

 return $result;

}

function returnUrl($fileName)
{
 echo "<a class='btn btn-video btn-lg' href='./static/{$fileName}/index.m3u8'><h1>正在处理中...点击进行跳转</h1></a>";
 die;
}

在上面代码当中,考虑文件是否已经被转码,如果已经转码过了直接返回播放地址,否则创建一个存放TS文件的文件夹,然后进行转码,转码的时候使用nohup命令可以让FFmpeg异步执行,然后PHP返回播放地址。

五、检验与测试

通过前面的步骤,笔者已经完整的搭建了一套流媒体服务器,下面将检验这些服务是否能否正常运行,包括视频列表展示、视频转码是否正常、已经转码的视频能否播放

5.1 视频列表

首先通过浏览器打开URL地址如下

http://localhost:8089/

加载完成之后可以看到如下的视频列表

PHP结合Ffmpeg快速搭建流媒体服务的实践记录

读者如果将上方的代码运行界面有稍有差异,因为笔者为了节省文章篇幅,并没有将样式代码放到文章当中,如需界面好看可以自行编写样式代码。

5.2 视频转码

在视频列表点击一个链接之后,后台PHP程序将会执行转码任务,然后返回一个链接地址,如下图所示

PHP结合Ffmpeg快速搭建流媒体服务的实践记录

此时便代表FFmpeg已经在后台运行,可以通过如下命令进行查看FFmpeg这个容器的运行状态,参考命令如下

docker ps

返回的参考结果如下所示

CONTAINER ID  IMAGE      COMMAND     CREATED    STATUS    PORTS    NAMES
ac3e7233eb9f  jrottenberg/ffmpeg:latest "ffmpeg -i /root/dow…" 1 hours ago  Up 1 hours        keen_feynman

从上面的返回结果当中可以看出当前正有一个任务处于运行状态,此时打开视频输出目录,会看到有多个ts格式的视频文件,这些文件是刚在通过PHP自动执行所产生的,如下图所示

PHP结合Ffmpeg快速搭建流媒体服务的实践记录

当看到如上图的转码视频文件时,便可以通过浏览器进行访问

5.3 视频播放

这里需要记住,HLS协议是苹果公司所开发的,因此除了苹果的浏览器外,其他浏览器默认都是不支持m3u8的解析的,如果需要使用其他浏览器播放,需要安装插件;苹果的默认就支持则不需要

笔者重新通过Safari浏览器打开页面,然后再次选择1.mp4视频,则直接跳转到了播放页面,如下图所示

PHP结合Ffmpeg快速搭建流媒体服务的实践记录

看到这里,搭建流媒体就基本已经完成了,如果需要将更多视频播放,只需要将视频文件存放到指定的视频目录,网页中便会自动读取出来,页面可能太简化,读者可以根据自己的需要将html页面美化一下。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
PHP与javascript对多项选择的处理
Oct 09 PHP
第八节--访问方式
Nov 16 PHP
探讨:web上存漏洞及原理分析、防范方法
Jun 29 PHP
php 批量替换html标签的实例代码
Nov 26 PHP
PHP has encountered a Stack overflow问题解决方法
Nov 03 PHP
PHP中is_dir()函数使用指南
May 08 PHP
PHP处理会话函数大总结
Aug 05 PHP
CI框架出现mysql数据库连接资源无法释放的解决方法
May 17 PHP
php删除数组指定元素实现代码
May 03 PHP
Laravel6.0.4中将添加计划任务事件的方法步骤
Oct 15 PHP
PHP pthreads v3下同步处理synchronized用法示例
Feb 21 PHP
laravel7学习之无限级分类的最新实现方法
Sep 30 PHP
php图片裁剪函数
Oct 31 #PHP
php+js实现裁剪任意形状图片
Oct 31 #PHP
workerman结合laravel开发在线聊天应用的示例代码
Oct 30 #PHP
golang实现php里的serialize()和unserialize()序列和反序列方法详解
Oct 30 #PHP
swoole_process实现进程池的方法示例
Oct 29 #PHP
PHP大文件分片上传的实现方法
Oct 28 #PHP
PHP array_reduce()函数的应用解析
Oct 28 #PHP
You might like
我常用的几个类
2006/10/09 PHP
通过JavaScript或PHP检测Android设备的代码
2011/03/09 PHP
Trying to clone an uncloneable object of class Imagic的解决方法
2012/01/11 PHP
php面向对象中static静态属性和静态方法的调用
2015/02/08 PHP
PHP入门教程之正则表达式基本用法实例详解(正则匹配,搜索,分割等)
2016/09/11 PHP
Yii框架通过请求组件处理get,post请求的方法分析
2019/09/03 PHP
js DOM模型操作
2009/12/28 Javascript
JQuery教学之性能优化
2014/05/14 Javascript
avascript中的自执行匿名函数应用示例
2014/09/15 Javascript
js实现定时进度条完成后切换图片
2017/01/04 Javascript
如何用js判断dom是否有存在某class的值
2017/02/13 Javascript
vue2组件实现懒加载浅析
2017/03/29 Javascript
jquery实现图片轮播器
2017/05/23 jQuery
layui实现动态和静态分页
2018/04/28 Javascript
JavaScript使用math.js进行精确计算操作示例
2018/06/19 Javascript
vue.js单文件组件中非父子组件的传值实例
2018/09/13 Javascript
解决ng-repeat产生的ng-model中取不到值的问题
2018/10/02 Javascript
Node.js从字符串生成文件流的实现方法
2019/08/18 Javascript
python文件名和文件路径操作实例
2017/09/29 Python
python3 遍历删除特定后缀名文件的方法
2018/04/23 Python
windows下添加Python环境变量的方法汇总
2018/05/14 Python
caffe binaryproto 与 npy相互转换的实例讲解
2018/07/09 Python
浅谈python常用程序算法
2019/03/22 Python
详解Python3 对象组合zip()和回退方式*zip
2019/05/15 Python
浅谈Python3 numpy.ptp()最大值与最小值的差
2019/08/24 Python
python实现提取str字符串/json中多级目录下的某个值
2020/02/27 Python
Python第三方包之DingDingBot钉钉机器人
2020/04/09 Python
解决python Jupyter不能导入外部包问题
2020/04/15 Python
用HTML5中的Canvas结合公式绘制粒子运动的教程
2015/05/08 HTML / CSS
美国专业级皮肤病和spa品质护肤品的高级零售网站:SkinCareRx
2017/02/06 全球购物
初中教师业务学习材料
2014/05/12 职场文书
环境科学专业求职信
2014/08/04 职场文书
个人整改措施书面材料
2014/10/24 职场文书
2015年中个人总结范文
2015/03/10 职场文书
2015学校六五普法工作总结
2015/04/22 职场文书
作弊检讨书范文
2015/05/06 职场文书