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生成便于打印的网页
Oct 09 PHP
PHP5.3.1 不再支持ISAPI
Jan 08 PHP
PHP程序员最常犯的11个MySQL错误小结
Nov 20 PHP
php数组函数序列之array_intersect() 返回两个或多个数组的交集数组
Nov 10 PHP
PHP高自定义性安全验证码代码
Nov 27 PHP
Zend Studio去除编辑器的语法警告设置方法
Oct 24 PHP
PHP中如何调用webservice的实例参考
Apr 25 PHP
php随机生成数字字母组合的方法
Mar 18 PHP
php错误日志简单配置方法
Jul 11 PHP
功能强大的PHP发邮件类
Aug 29 PHP
简述php环境搭建与配置
Dec 05 PHP
php输出形式实例整理
May 05 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
php获取某个目录大小的代码
2008/09/10 PHP
apache+php完美解决301重定向的两种方法
2011/06/08 PHP
php jq jquery getJSON跨域提交数据完整版
2013/09/13 PHP
PHP实现删除非站内外部链接实例代码
2014/06/17 PHP
Laravel框架控制器的middleware中间件用法分析
2019/09/30 PHP
使用composer安装使用thinkphp6.0框架问题【视频教程】
2019/10/01 PHP
prototype.js的Ajax对象
2006/09/23 Javascript
JavaScript判断DOM何时加载完毕的技巧
2012/11/11 Javascript
javascript 实现 秒杀,团购 倒计时展示的记录 分享
2013/07/12 Javascript
js实现可拖动DIV的方法
2013/12/17 Javascript
document节点对象的获取方式示例介绍
2013/12/24 Javascript
jQuery插件zoom实现图片全屏放大弹出层特效
2015/04/15 Javascript
jquery实现兼容IE8的异步上传文件
2015/06/15 Javascript
Vue.js实现简单ToDoList 前期准备(一)
2016/12/01 Javascript
Vue.js组件tree实现省市多级联动
2016/12/02 Javascript
nodejs搭建本地服务器并访问文件的方法
2017/03/03 NodeJs
全面解析vue中的数据双向绑定
2017/05/10 Javascript
JS原生带小白点轮播图实例讲解
2017/07/22 Javascript
JS+canvas绘制的动态机械表动画效果
2017/09/12 Javascript
vue动态路由配置及路由传参的方式
2018/05/23 Javascript
浅谈JavaScript_DOM学习篇_图片切换小案例
2019/03/19 Javascript
Vue看了就会的8个小技巧
2021/01/21 Vue.js
Python遍历pandas数据方法总结
2018/02/09 Python
Python+request+unittest实现接口测试框架集成实例
2018/03/16 Python
mac下如何将python2.7改为python3
2018/07/13 Python
Python字典的基本用法实例分析【创建、增加、获取、修改、删除】
2019/03/05 Python
python实时检测键盘输入函数的示例
2019/07/17 Python
Python单元测试与测试用例简析
2019/11/09 Python
TensorFlow打印输出tensor的值
2020/04/19 Python
python实现学生成绩测评系统
2020/06/22 Python
Python通用唯一标识符uuid模块使用案例
2020/09/10 Python
纺织工程专业个人求职信范文
2014/01/27 职场文书
精通CAD能手自荐书
2014/01/31 职场文书
复试通知单模板
2015/04/24 职场文书
Mysql分库分表之后主键处理的几种方法
2022/02/15 MySQL
V Rising 服务器搭建图文教程
2022/06/16 Servers