笔者想将本身收藏的一些电影放到网站上能够用来随时播放,不过遇到了一个问题,即是若是直接将MP4文件放放到网站目录当中,手机端必须下载整个视频才能够播放,而若是跨外网传输,这实在是不太现实。php
为了解决这个问题,便想着搭建一套流媒体服务,这样手机就能够边看边下载,查询了一些资料了了解到须要先将视频分红一小片来传输,好比将MP4转码为M3U8格式,查询了相关转码方法,比较主流的方式是使用ffmpeg这个开源工具html
1. 安装Ffmpeg
2. 服务搭建
3. 功能测试
复制代码
视频转码的工具可能有不少,但开源且使用人数最多的仍是莫过于ffmpeg这个工具,具体功能笔者不在这里详细讲解;安装此工具的方式有不少,好比apt安装、源码安装、docker安装等等,不过docker是跨平台的,所以笔者这里将以docker方式安装为例nginx
首先笔者须要下载对应的docker镜像,参考命令以下web
docker pull jrottenberg/ffmpeg
复制代码
命令执行过程当中将会从远处下载镜像,这个时间由当前的网络带宽所决定,当下载完成以后,能够看到以下参考信息docker
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
复制代码
当容器下载完毕以后,能够用一些命令进行验证是否可以正常运行,以下参考命令canvas
docker run jrottenberg/ffmpeg
复制代码
命令执行完毕以后,会返回以下结果ubuntu
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
复制代码
FFmpeg所支持的输入输出协议很是多,好比能够选择file协议做为来源,使用hls协议做为输出结果,具体所支持的协议能够经过以下命令查看vim
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
复制代码
如今笔者使用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文件,以下图所示
如今笔者将刚才的TS文件都删除,在下面将使用自动化完成。
在上一步中笔者已经成功经过终端使用FFmpeg将视频进行转码,下面笔者将结合PHP代码将这些操做彻底自动化实现,这样即可以达到经过手机访问网站,服务端自动完成转码播放的需求,这个过程包括建立虚拟主机、编写展现视频列表、视频自动解码三个部分
首先笔者须要借助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;
}
}
复制代码
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循环,经过后缀名来判断是否为视频文件,若是是视频文件,则输出一个连接地址方便用户选择。
上面的代码在列出视频列表以后,当用户点击连接后就须要使用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返回播放地址。
经过前面的步骤,笔者已经完整的搭建了一套流媒体服务器,下面将检验这些服务是否可否正常运行,包括视频列表展现、视频转码是否正常、已经转码的视频可否播放
首先经过浏览器打开URL地址以下
http://localhost:8089/
复制代码
加载完成以后能够看到以下的视频列表
读者若是将上方的代码运行界面有稍有差别,由于笔者为了节省文章篇幅,并无将样式代码放到文章当中,如需界面好看能够自行编写样式代码。
在视频列表点击一个连接以后,后台PHP程序将会执行转码任务,而后返回一个连接地址,以下图所示
此时便表明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自动执行所产生的,以下图所示
当看到如上图的转码视频文件时,即可以经过浏览器进行访问
这里须要记住,HLS协议是苹果公司所开发的,所以除了苹果的浏览器外,其余浏览器默认都是不支持m3u8的解析的,若是须要使用其余浏览器播放,须要安装插件;苹果的默认就支持则不须要
笔者从新经过Safari浏览器打开页面,而后再次选择1.mp4
视频,则直接跳转到了播放页面,以下图所示
看到这里,搭建流媒体就基本已经完成了,若是须要将更多视频播放,只须要将视频文件存放到指定的视频目录,网页中便会自动读取出来,页面可能太简化,读者能够根据本身的须要将html页面美化一下。
若是对笔者的实战文章较为感兴趣,能够关注笔者新书《PHP Web安全开发实战》,现已在各大平台上架销售,封面以下图所示
做者:汤青松
微信:songboy8888
日期:2018-10-28