vlambda博客
学习文章列表

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

本篇文章学习下nginx配置静态资源如何配置。并且以在线播放一个视频为例,学习一些H5规范和HLS协议,拓展我们的知识面。

一、静态资源服务器

1.1 root和alias

假如服务器路径为:/home/sopftpuser/ftp/fossistudy/happydog.jpg

  • root 路径完全匹配访问

配置的时候为:

location / {
root
/home/sopftpuser/ftp;
}

用户访问的时候请求为: http://IP:PORT/fossistudy/happydog.jpg

  • alias 可以为你的路径做一个别名,对用户透明

配置的时候为:

location /static {
alias /home/sopftpuser/ftp;
}

用户访问的时候请求为: http://IP:PORT/static/fossistudy/happydog.jpg

1.2 gzip

我们的商城项目首页中需要下载大量的JS、CSS、图片等资源,这些静态资源可进行适当的压缩进行传输来提高请求效率,并且降低服务器带宽压力。

#开启gzip压缩功能,提高传输效率,节约带宽
gzip on;
#限制最小压缩,小于1字节的文件不会压缩
gzip_min_length 1;
#压缩比,取值范围是1-9,值越大则压缩比越大,越大会越消耗CPU
gzip_comp_level 3;
#进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/json;

1.3 location 的匹配规则

  • 空格 :默认匹配,普通匹配

location / { 
root
/home;
}
  • = :精确匹配

只能匹配到face1.png这张图片,同级目录就算有face2.png是不能访问的。

location = /img/face1.png {     
root /home;
}
  • ~* :匹配正则表达式,不区分大小写

正则匹配且*表示不区分大小写,这样就可以按照后面的规则进行匹配访问,比如下面的示例,可以访问规定的图片格式。

#符合图片的显示 
location ~* \.(GIF|jpg|png|jpeg) {
root /home;
}
  • ~ :匹配正则表达式,区分大小写

#GIF必须大写才能匹配到 
location ~ \.(GIF|jpg|png|jpeg) {
root /home;
}
  • ^~ :以某个字符路径开始

^一般是指非,表示不用正则匹配,这里表示只能以某个路径为前缀去访问,其他路径下的资源不能访问。

location ^~ /img {     
root /home;
}

好了,学习好nginx如何做静态资源的映射后,我们下面将实现网页上展示图片和视频播放的需求。在实现之前,有必要了解一些背景。

二、关于视频在线播放

得益于HTML5video标签,目前支持:

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

通过上面的信息我们发现只有h.264编码的MP4视频(MPEG-LA公司)、VP8编码的webm格式的视频(Google公司)和Theora编码的ogg格式的视频(iTouch开发)可以支持html5<video>标签。

其实视频播放很简单,这里拿播放本地MP4格式的视频为例,我先用potplayer检查下此视频的编码是否符合条件(用potplayer打开后按ESC就可以看到详细的信息):

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

我们看到这个用来测试的MP4视频的音频编码是AAC编码器,这个是符合HTML5播放MP4视频的音频格式的。那么这里的视频编码器是AVC1,它到底是何方神圣呢?

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

他两呢,实际上差别不大,AVC1和H.264是同一个视频编码方案的不同叫法,这个视频编码方案是两个公司一起研发的,这两个公司分别是ITU-T视频编码专家组(VCEG)和ISO/IEC 动态图像专家组(MPEG)。ITU-T把它叫做H.264,ISO把它叫做MPEG-4高级视频编码(Advanced Video Coding,AVC1)。他两的区别是:

h264与AVC1都是FourCC.

FOURCC为AVC1,没有开始码的H.264视频,主要就是用MP4或MKV等封装的文件,也就是你平时在电脑上看的那种,它的数据流开始是1、2或者4个字节表示长度数据。x264编码出来的都是这种。

FOURCC为H264,是带有开始码的H.264视频,一般是用于无线发射、有线广播或者HD-DVD中的。这些数据流的开始都有一个开始码:0x000001 或者 0x00000001.

所以,我们就来实际看下能不能直接播放吧,这里先直接引用本地硬盘上的MP4来播放看下效果,简单的HTML代码如下:

<!DOCTYPE HTML>
<html>
<body>
<video src="test.mp4" controls="controls" type="video/mp4">
</video>
</body>
</html>

我这里的src是相对路径,即视频跟html在一个文件夹。这个时候运行此html文件即可在浏览器上播放(没有特殊说明我一律是在谷歌浏览器上做的测试)。

时间证明这种编码格式是可以在浏览器上正常播放的:

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

那么播放其他格式的视频呢?比如xx.ts视频。显然不可以,原因就是上面说的vide标签只支持那三种格式,没有其他格式的type让你选啊。那么TS格式的视频就不能播放了吗?解决这个TS格式的视频播放,可以借助于苹果退出的HLS协议。

三、HLS协议

概述

HLS是什么?维基百科的定义为:

HTTP Live Streaming(缩写是HLS)是一个由苹果公司提出的基于HTTP的流媒体网络传输协议。是苹果公司QuickTime X和iPhone软件系统的一部分。它的工作原理是把整个流分成一个个小的基于HTTP的文件来下载,每次只下载一些。当媒体流正在播放时,客户端可以选择从许多不同的备用源中以不同的速率下载同样的资源,允许流媒体会话适应不同的数据速率。在开始一个流媒体会话时,客户端会下载一个包含元数据的extended M3U (m3u8)playlist文件,用于寻找可用的媒体流。

HLS只请求基本的HTTP报文,与实时传输协议(RTP)不同,HLS可以穿过任何允许HTTP数据通过的防火墙或者代理服务器。它也很容易使用内容分发网络来传输媒体流。

HLS协议规定:

  • 视频的封装格式是TS。

  • 视频的编码格式为H264,音频编码格式为MP3、AAC或者AC-3。

  • 除了TS视频文件本身,还定义了用来控制播放的m3u8文件(文本文件)。

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

首先得有一个任何格式的视频源,上传到服务器上转码为HLS格式的视频(TS和m3u8文件):首先是转码,比如转为H264编码的视频数据,然后就是切片,生成对应的m3u8文件和若干小的TS切片文件。

没有接触过视频的同学,可能会一脸懵逼,这里说的m3u8又是啥玩意?我们可以想想,假设一分钟的视频,我们将其切片,按照10秒一个切片算,就会有6个小切片,那么总得有一个文件来描述播放这个视频需要这六个切片,并且按照顺序加载吧?就像一个索引,因此m3u8就是HLS的索引文件。

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

这里又引出了一级索引和二级索引的概念。实际上都是索引,只是一级索引是二级索引的索引,二级索引才是TS的索引。可以只有一级所以,两层的索引是为了支持多码率。

一级索引和二级索引

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1064000
1000kbps.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=564000
500kbps.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=282000
250kbps.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2128000
2000kbps.m3u8

bandwidth指定视频流的比特率,PROGRAM-ID无用无需关注,每一个#EXT-X-STREAM-INF的下一行是二级index文件的路径,可以用相对路径也可以用绝对路径。例子中用的是相对路径。这个文件中记录了不同比特率视频流的二级index文件路径,客户端可以自己判断自己的现行网络带宽,来决定播放哪一个视频流。也可以在网络带宽变化的时候平滑切换到和带宽匹配的视频流。

#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:10
#EXTINF:10,
2000kbps-00001.ts
#EXTINF:10,
2000kbps-00002.ts
#EXTINF:10,
2000kbps-00003.ts
#EXTINF:10,
2000kbps-00004.ts
#EXTINF:10,

... ...

#EXTINF:10,
2000kbps-00096.ts
#EXTINF:10,
2000kbps-00097.ts
#EXTINF:10,
2000kbps-00098.ts
#EXTINF:10,
2000kbps-00099.ts
#EXTINF:10,
2000kbps-00100.ts
#ZEN-TOTAL-DURATION:999.66667
#ZEN-AVERAGE-BANDWIDTH:2190954
#ZEN-MAXIMUM-BANDWIDTH:3536205
#EXT-X-ENDLIST
  • Live 模式就是实时生成M3u8和ts文件。它的索引文件一直处于动态变化的,播放的时候需要不断下载二级index文件,以获得最新生成的ts文件播放视频。如果一个二级index文件的末尾没有#EXT-X-ENDLIST标志,说明它是一个Live视频流。

四、通过HLS协议来播放TS视频

假设有这么一个需求:运营上传图片或TS格式视频到某个FTP上,需要在我们的管理后台上进行在线查看和审核。暂时没有条件进行视频转码,如何来做呢?我们这里先不讨论浏览器上的在线播放器等元素,先考虑如何将这个FTP服务上的图片或视频想办法可以通过HTTP的方式播放出来呢?

不过,如何http在线播放呢?显然,这里的Nginx就可以来实现,作为一个静态资源服务器,FTP的内容实际上也是存在硬盘上的,我们只需要将实际的图片或视频存储的位置找到,配合Nginx就可以转换为HTTP服务。下面来做下演示吧!

首先呢,我在服务器上搭建了一个VSFTPD的FTP服务器。具体如何搭建的呢?我在《》系列的学习中《20、FTP服务端搭建-vsftpd安装》详细记录了搭建过程。

我模拟运营人员通过FTP上传了一张图片和是几个视频:

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

对应到实际的硬盘位置是:

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

知道了实际的位置,那么我就可以进行nginx的配置了,正如之前说的,我用include swg_nginx.conf;引用外部的配置文件:

server {
listen 81;
server_name oursnail.cn;

location /static {
alias /home/sopftpuser/ftp;
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

可以看到,我用了alias别名映射到了文件的根目录,重启我们看下情况。访问http://111.231.119.253:81/static/fossistudy/happydog.jpg

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

403权限不够,我们看下FTP目录的用户是sopftpuser,但是nginx的工作进程用户是nobody,我们知道nobody这个用户几乎没有什么权限,我们来改下nginx.conf中的第一行user root;重启:

[root@VM-0-13-centos sbin]# ps -ef | grep nginx
root 24603 1 0 16:47 ? 00:00:00 nginx: master process ./nginx
root 24604 24603 0 16:47 ? 00:00:00 nginx: worker process
root 24622 31987 0 16:47 pts/0 00:00:00 grep --color=auto nginx

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

这次可以正常访问图片了,说明确实是用户这个问题。

那么视频呢,由于TS视频不是标准格式视频,浏览器上无法正常解析和播放。直接访问上传的test.mp4格式视频:http://111.231.119.253:81/static/fossistudy/test.mp4,可以看到由于是标准格式的视频,浏览器二话不说直接支持播放:

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

对于mp4这样的视频,也可以用一些开源的工具来实现定定制化的网页在线播放的开发,比如我这里可以使用video.js来做播放器,最简单的代码为:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>videojs视频播放DEMO</title>
</head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.3.0/video-js.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.3.0/video.min.js"></script>
<body>
<h3>视频播放</h3>
<video id="example_video_1" class="video-js vjs-default-skin" controls preload="none" poster="http://vjs.zencdn.net/v/oceans.png">
<source src="http://111.231.119.253:81/static/fossistudy/test.mp4" type="video/mp4">
</video>
</body>
</html>
<script>
var player = videojs('example_video_1', {
muted: true,
controls: true,
height: 300,
width: 400,
loop: true,
// 更多配置.....
});
</script>

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

对于片源是.ts格式的视频,我们需要模仿HLS协议,生成m3u8索引文件,最后通过HTTP协议实现播放,它利用到的typetype="application/x-mpegURL"。具体的索引文件我最好改了改:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:93
#EXTINF:92.008578,
jrsoftmfww31.ts
#EXT-X-ENDLIST
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>videojs视频播放DEMO</title>
</head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.3.0/video-js.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.3.0/video.min.js"></script>
<body>
<h3>视频播放</h3>
<video id="example_video_1" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="none" poster="http://cyberplayer.bcelive.com/thumbnail.jpg">
<source src="http://111.231.119.253:81/static/fossistudy/test.m3u8" type="application/x-mpegURL">
</video>
</body>
</html>
<script>
var player = videojs('example_video_1', {
muted: true,
controls: true,
height: 600,
width: 800,
loop: true,
// 更多配置.....
});
</script>

我们再来用potplayer来看下这个jrsoftmfww31.ts视频的编码:

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

可以看到视频编码为H264,但是音频编码为MPEG Audio,播放效果是:可以看到视频,但是听不到声音。这里的原因就很简单了,无法对这个音频编码进行解码。我们需要将这个视频转码为表格的视频H264和音频AAC编码。经过ffmpeg进行转码之后,就可以正常播放并听到声音啦。

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

总结

好了,又说了一大堆,核心就是Nginx可以作为一个静态资源服务器提供图片、视频等HTTP展示的方式。并且学习了H5中视频在线播放的规范,以及学习了HLS协议,这是一个非常重要的协议,做视频相关的人都会比较熟悉。

不过上面说的播放TS的方案有点弊病:

  • 需要额外生成m3u8文件

  • HLS协议适用于小切片,比如10秒一个小切片,下载播放很快,但是我这里没有做切片,一个大TS直接播放,如果视频本身很大或者带宽太小,则会起播很慢

有人说,为什么不用ffmpeg切片处理呢?有了这个,也不用限制视频源是什么编码了,我统统可以同一转码,原因是要结合实际情况考虑:

  • ffmpeg对cpu的消耗较大,一般承载管理后台管理系统的机器CPU不会太好,因此需要升级服务器配置。

  • 我们的原视频不能动,那么再切片的话,就是相当于double了下,对于存储也是一种压力。

也有人说,为什么不采取直接调用本地VLC播放器的方式播放视频呢?VLC是一款通用的播放器,支持佷多格式的视频播放。

实现起来也很简单,这里就啰嗦提一嘴如何来做。

首先就是要下载VLC和相关文件:点我下载。

  • 解压缩PukkaSoftVLCPlayer.zip,双击安装VLC播放器,安装时注意VLC播放器安装路径。

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

  • 复制压缩包下VLCProtocol.exe、vlc-protocol-deregister.bat、vlc-protocol-register.bat到VLC播放器安装路径。

28、【yummyfood商城-集群版本】-Nginx作为静态资源服务器

  • 右键点击vlc-protocol-register.bat,选择“以管理员权限运行”,如果弹出以下窗口说明配置成功。

OK,下面就是写页面,特别简单:

<!DOCTYPE html>
<html>
<head>
<title>播放器</title>
</head>
<body>
<h1>VLC Web Plugin DEMO</h1>
<a href="vlc://http://111.231.119.253:81/static/fossistudy/test.m3u8">播放</a>
</body>
</html>

效果为点击播放的时候,浏览器弹出打开VLC软件进行播放:

不过这个方案同样不适用于我的场景:

  • 首先需要使用者按照此说明文档操作,可能会有人抵触,如果再遇到浏览器兼容问题,则会。。

  • 其次企业中可能本地浏览器不能直接访问现网管理后台,需要通过中间比如4A平台跳转再登陆,可能就无法安装VLC了。

  • 最后就是我测试发现无法正常拖拽进度,还未解决。

感谢

  • https://zhuanlan.zhihu.com/p/58434013

  • https://www.jianshu.com/p/426425cad08a

  • https://www.cnblogs.com/bhlsheji/p/4551169.html

  • https://www.runoob.com/html/html5-video.html