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 什么是PEAR?
Mar 19 PHP
PHP+MySQL 制作简单的留言本
Nov 02 PHP
通过5个php实例细致说明传值与传引用的区别
Aug 08 PHP
深入理解:XML与对象的序列化与反序列化
Jun 08 PHP
php中文验证码实现示例分享
Jan 12 PHP
php5.2 Json不能正确处理中文、GB编码的解决方法
Mar 28 PHP
php根据指定位置和长度获得子字符串的方法
Mar 17 PHP
php实现生成验证码实例分享
Apr 10 PHP
php中二分法查找算法实例分析
Sep 22 PHP
PHP 文件上传后端处理实用技巧方法
Jan 06 PHP
Symfony2针对输入时间进行查询的方法分析
Jun 28 PHP
PHP编程获取图片的主色调的方法【基于Imagick扩展】
Aug 02 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
Laravel框架中实现使用阿里云ACE缓存服务
2015/02/10 PHP
PHP框架laravel的.env文件配置教程
2017/06/07 PHP
JQuery 学习笔记 选择器之二
2009/07/23 Javascript
javascript 支持链式调用的异步调用框架Async.Operation
2009/08/04 Javascript
js 获取服务器控件值的代码
2010/03/05 Javascript
js预加载图片方法汇总
2015/06/15 Javascript
jQuery实现仿QQ空间装扮预览图片的鼠标提示效果代码
2015/10/30 Javascript
利用Bootstrap实现表格复选框checkbox全选
2016/12/21 Javascript
selenium 与 chrome 进行qq登录并发邮件操作实例详解
2017/04/06 Javascript
详解微信小程序 登录获取unionid
2017/06/27 Javascript
jQuery实现拼图小游戏(实例讲解)
2017/07/24 jQuery
jQuery Ajax 实现分页 kkpager插件实例代码
2017/08/10 jQuery
React 高阶组件入门介绍
2018/01/11 Javascript
微信小程序button标签open-type属性原理解析
2020/01/21 Javascript
vue移动端下拉刷新和上滑加载
2020/10/27 Javascript
[08:42]DOTA2每周TOP10 精彩击杀集锦vol.2
2014/06/25 DOTA
Python 面向对象 成员的访问约束
2008/12/23 Python
python之import机制详解
2014/07/03 Python
跟老齐学Python之用Python计算
2014/09/12 Python
python实现泊松图像融合
2018/07/26 Python
python读取xlsx的方法
2018/12/25 Python
Scrapy-Redis结合POST请求获取数据的方法示例
2019/05/07 Python
python flask 如何修改默认端口号的方法步骤
2019/07/12 Python
tensorflow 环境变量设置方式
2020/02/06 Python
基于Python实现人脸自动戴口罩系统
2020/02/06 Python
python画图常规设置方式
2020/03/05 Python
基于K.image_data_format() == 'channels_first' 的理解
2020/06/29 Python
python 调整图片亮度的示例
2020/12/03 Python
HTML5新特性之type=file文件上传功能
2018/02/02 HTML / CSS
期末自我鉴定
2014/01/23 职场文书
运动会解说词100字
2014/01/31 职场文书
机电职业生涯规划书范文
2014/03/08 职场文书
员工薪酬激励方案
2014/06/13 职场文书
幼儿园迎新生欢迎词
2015/09/30 职场文书
2016感恩父亲节主题广播稿
2015/12/18 职场文书
python 下载文件的几种方式分享
2021/04/07 Python