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读MYSQL中文乱码的解决方法
Dec 17 PHP
一个PHP模板,主要想体现一下思路
Dec 25 PHP
PHP中将网页导出为Word文档的代码
May 25 PHP
探讨:web上存漏洞及原理分析、防范方法
Jun 29 PHP
php不使用copy()函数复制文件的方法
Mar 13 PHP
php生成PDF格式文件并且加密
Jun 22 PHP
[原创]ThinkPHP让../Public在模板不解析(直接输出)的方法
Oct 09 PHP
thinkPHP使用pclzip打包备份mysql数据库的方法
Apr 30 PHP
Yii2创建表单(ActiveForm)方法详解
Jul 23 PHP
详解Yii2 定制表单输入字段的标签和样式
Jan 04 PHP
ThinkPHP防止重复提交表单的方法实例分析
May 10 PHP
使用tp框架和SQL语句查询数据表中的某字段包含某值
Oct 18 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
ThinkPHP实例化模型的四种方法概述
2014/08/22 PHP
php限制文件下载速度的代码
2015/10/20 PHP
Yii2 rbac权限控制之菜单menu实例教程
2016/04/28 PHP
详谈php ip2long 出现负数的原因及解决方法
2017/04/05 PHP
Laravel使用PHPQRCODE实现生成带有LOGO的二维码图片功能示例
2017/07/07 PHP
深入认识JavaScript中的函数
2007/01/22 Javascript
js对象数组按属性快速排序
2011/01/31 Javascript
关于JavaScript中原型继承中的一点思考
2012/07/25 Javascript
使用javascipt---实现二分查找法
2013/04/10 Javascript
Js点击弹出下拉菜单效果实例
2013/08/12 Javascript
自定义的一个简单时尚js下拉选择框
2013/11/20 Javascript
用C/C++来实现 Node.js 的模块(二)
2014/09/24 Javascript
BootStrap中Table分页插件使用详解
2016/10/09 Javascript
JS实现的简单轮播图运动效果示例
2016/12/22 Javascript
js利用for in循环获取 一个对象的所有属性以及值的实例
2017/03/30 Javascript
Vue+Jwt+SpringBoot+Ldap完成登录认证的示例代码
2018/05/21 Javascript
在vue项目中引用Iview的方法
2018/09/14 Javascript
代码分析vue中如何配置less
2018/09/28 Javascript
深度了解vue.js中hooks的相关知识
2019/06/14 Javascript
vue ssr+koa2构建服务端渲染的示例代码
2020/03/23 Javascript
Vue记住滚动条和实现下拉加载的完美方法
2020/07/31 Javascript
浅析JavaScript中的事件委托机制跟深浅拷贝
2021/01/20 Javascript
[46:00]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#4EG VS Fnatic第一局
2016/03/03 DOTA
python3读取csv和xlsx文件的实例
2018/06/22 Python
Python3 利用requests 库进行post携带账号密码请求数据的方法
2018/10/26 Python
Python对象转换为json的方法步骤
2019/04/25 Python
django基于cors解决跨域请求问题详解
2019/08/06 Python
HTML5 CSS3打造相册效果附源码下载
2014/06/16 HTML / CSS
卡塔尔航空官方网站:Qatar Airways
2017/02/08 全球购物
Qoo10台湾站:亚洲领先的在线市场
2018/05/15 全球购物
教师自我鉴定范文
2013/11/10 职场文书
日语专业毕业生自荐信
2013/11/11 职场文书
销售工作岗位职责
2013/12/24 职场文书
小学音乐课歌曲《堆雪人》教学反思
2016/02/18 职场文书
浅谈mysql执行过程以及顺序
2021/05/12 MySQL
MySQL深分页问题解决思路
2022/12/24 MySQL