基于 Nginx 搭建视频直播服务器

近年来,网络视频直播处于蓬勃的发展期,各大直播平台的竞争也趋于白热化。在游戏直播领域,就有许多电子竞技的前职业选手,退役后转行做游戏主播,收入不菲。当然,网络直播的用处不仅仅是娱乐行业,诸如实时视频监控等应用,同样具有广阔的市场。事实上,如果没有太高的并发播放需求,完全可以自己运行一个小型的直播平台。
笔者在参看了大量教程后,借助于 Nginx 和一些拓展模块,成功地在 VPS 上搭建了一台视频直播服务器。经过测试,能够正常地使用 OBS Studio 推流,在浏览器上实现 HLS 视频流播放。下面附上具体步骤,你会发现,视频直播的相关配置其实并不复杂。

下载 Nginx 及扩展模块

首先,需要下载可编译的 Nginx 源代码,以及 nginx-http-flv-module 拓展库。

获取 Nginx 源码

这一步需要根据你所使用的系统的实际情况选择:

  • 未安装或曾使用包管理工具安装了 Nginx:参考文章 Nginx 环境搭建中「源码安装」的「准备工作」步骤获取源码;
  • 此前通过源码编译安装了 Nginx:如果下载的源码没有删除,可以继续使用,具体操作会在后文中讲到;也可以参考上一条下载最新的源码;
  • 如果你已经非常熟悉 Linux 和 Nginx 的安装配置,当然也可以使用你喜欢的其他方式安装。

下载拓展库

GitHub 项目地址:nginx-http-flv-module,克隆到本地即可:

1
2
3
4
5
#为 Nginx 创建扩展模块目录
mkdir nginx_module
cd nginx_module
#下载扩展包到 nginx 扩展模块目录下
git clone https://github.com/winshining/nginx-http-flv-module.git

安装 Nginx

查看 Nginx 配置参数

如果此前已经安装过 Nginx,执行 nginx -V 会输出配置参数,类似于这样:

复制 configure arguments 后的所有参数,例如:

1
--prefix=/usr/local/nginx --user=www --group=www --with-http_stub_status_module --with-http_v2_module --with-http_ssl_module --with-http_gzip_static_module --with-ipv6 --with-http_sub_module

这会在后面用到。

如果是初次安装则可以跳过这一步,使用默认的 configure 参数。

编译 Nginx

首先进入 Nginx 源码目录:

1
cd nginx-1.14.0

然后用 configure 生成 Makefile 脚本。configure 参数是刚才从 nginx -V 中复制的参数,加上 --add-module=/path/to/nginx-http-flv-module,即 nginx-http-flv-module 扩展包的目录。例如

1
./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-ipv6 --with-http_sub_module --add-module=/root/nginx_module/nginx-http-flv-module

之后就可以编译安装了

1
make && make install

再次执行 nginx -V 查看安装状态,如果 configure arguments 后出现 nginx-http-flv-module 说明安装成功!

最后重启 Nginx 服务即可。

1
systemctl restart nginx

注意:在部分系统下需要使用 service 代替 systemctl 命令。

配置 Nginx

配置 HLS 及 http-flv

nginx.conf 进行修改:

1
2
3
#编辑配置
cd /usr/local/nginx/conf
vim nginx.conf

需要修改的是 http 块下 server 的配置,其内容可参照:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
http {
server {
listen 80 default_server;
#listen [::]:80 default_server ipv6only=on;
server_name example.com;
index index.html index.htm index.php;
root /home/www/html/; #服务器的根目录
#error_page 404 /404.html;
include enable-php.conf;

#加入hls支持
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
#或 application/x-mpegURL
video/mp2t ts;
}
alias /home/www/hls/; #视频流文件目录(自己创建,与下方hls_path相同)
expires -1;
add_header Cache-Control no-cache;
}
#加入http-flv支持
location /flv {
flv_live on;
chunked_transfer_encoding on;
}
#server下的其余配置无需改变,此处省略
}
}

这里把 example.com 替换为你的域名或者服务器 IP,后文同理。

然后,在配置文件末尾,http 块之外,加入 rtmp 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
rtmp {
server {
listen 1935;
chunk_size 4000;
application live {
live on;
record off;
#publish_notify on; #推流验证,和下一行需一起使用
#on_publish http://localhost/auth.php; #推流验证的URL,具体可参照后文

hls on;
hls_path /home/www/hls/; #视频流文件目录(自己创建)
hls_fragment 4s; #hls单个切片时长,会影响延迟
hls_playlist_length 32s; #hls总缓存时间,会影响延迟

meta on; #如果http-flv播放时首帧出现问题,可改为off
gop_cache on; #可以减少首帧延迟
}
}
}

参数说明:

  • listen 监听的端口号,rtmp 协议的默认端口号是 1935
  • application rtmp 推流请求路径,这里设置为了 live
  • live on 开启直播
  • record off 不记录数据

更多配置选项可以参考 nginx-http-flv-module 模块在 GitHub 上的文档,此处不做更多介绍。

创建目录

根据前面配置文件中的 hls_path 创建存储 hls 切片文件的子目录,例如 /home/www/hls/。确保 nginx 服务器对该目录具有读写权限。

修改完后执行 nginx -s reload 重载 Nginx 配置。

开始推流

服务器开放 1935 端口

如果服务器设置了防火墙,那么需要开放 1935 端口,允许 TCP 流量。下文以 iptables 为例。

1
2
3
4
5
6
7
8
9
#开放 1935 端口
/sbin/iptables -I INPUT -p tcp --dport 1935 -j ACCEPT
#保存配置
/etc/rc.d/init.d/iptables save
#或 service iptables save
#重启服务
/etc/rc.d/init.d/iptables restart
#查看端口开放状态
/etc/init.d/iptables status

执行 iptables -L 查看防火墙设置是否生效。

使用 OBS 或 ffmpeg 推流

如果要使用 OBS Studio 等软件推流,地址设置为 rtmp://example.com:1935/live/test
ffmpeg 也可以进行推流,用法是:

1
ffmpeg -re -stream_loop -1 -i /path/to/your/video.mp4 -vcodec libx264 -acodec aac -f flv rtmp://example.com:1935/live/test

版本较老的 ffmpeg 无法设置 -stream_loop -1,可以前往官方网站下载最新版本。

ffmpeg 除了指定视频文件,也可以直接从摄像头输出视频流:

1
ffmpeg -f v4l2 -i /dev/video0 -profile:v high -pix_fmt yuvj420p -level:v 4.1 -preset ultrafast -tune zerolatency -vcodec libx264 -r 30 -s 1280x720 -f flv rtmp://example.com:1935/live/test

推流验证

如果配置文件中开启了 publish_notify,那么 on_publish 项设置的 URL 将会被用作推流验证。如果验证失败,使这个页面返回 404 头即可。
比如你设置了 on_publish http://localhost/auth.php,那么在 auth.php 中加入以下内容即可实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
@$name = $_POST['name'];
@$pass = $_POST['pass'];

if (empty($name) || empty($pass)) {
header("HTTP/1.0 404 Not Found");
echo "串流码不正确!";
}
else {
if ($pass == "password") {
echo "串流码正确!";
}
else {
header("HTTP/1.0 404 Not Found");
echo "串流码不正确!";
}
}
?>

这时的推流地址也要对应改为 rtmp://example.com:1935/live/test?pass=password

推流验证的 URL 不支持 https,因此用 localhost 访问比较方便。

HTML5 播放

HLS 播放

在服务器的根目录,例如 /home/www/html/ 下创建 player.html 文件,进行 HLS 播放:

1
2
3
4
5
6
7
8
9
10
11
<html>
<body>
<video autoplay webkit-playsinline controls>
<source src="http://example.com/hls/test.m3u8" type="application/vnd.apple.mpegurl">
<p class="warning">Your browser does not support HTML5 video.</p>
</video>
<video controls>
<source src="http://example.com/hls/test.m3u8" type="application/x-mpegURL">
</video>
</body>
</html>

用浏览器访问这个 player.html,即可观看直播。
如直播没有声音,请参考 ffmpeg 没有声音
附录:浏览器对 hls 的支持

如果浏览器并不原生支持 hls,可使用第三方插件,例如 hls.js;或者使用 video.js 配合 http-streaming,这也是不错的解决方案。

http-flv 播放

对于 http-flv 播放,可以使用 VLC 等软件测试拉流,拉流地址为 http://example.com/flv?app=live&stream=test
如果要实现 HTML5 播放,可以使用 B 站开源的 flv.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<html>
<body>
<video controls autoplay></video>
<script src="https://cdn.jsdelivr.net/npm/flv.js@1/dist/flv.min.js"></script>
<script>
if (flvjs.isSupported()) {
const flvPlayer = flvjs.createPlayer({
type: "flv",
isLive: true,
url: "http://example.com/flv?app=live&stream=test"
});
flvPlayer.attachMediaElement(document.querySelector("video"));
flvPlayer.load();
flvPlayer.play();
}
</script>
</body>
</html>

参考文章:基于 Nginx 搭建 RTMP/HLS 视频直播服务器

原文使用的是 nginx-rtmp-module,而本文介绍的 nginx-http-flv-module 模块功能更加丰富。

本文更新于 2018 年 5 月 30 日:
nginx-http-flv-module 一直在更新中,其配置文件的参数设置可能略有调整,请以文档为准,本文仅供参考。

本文更新于 2018 年 11 月:
在很多文章中都提到了一个 RTMP 源:rtmp://live.hkstv.hk.lxdns.com/live/hks,不过最近它已经失效了,不能用于拉流。你可以使用前面提到的 OBS Studio 和 ffmpeg 进行测试。

本文更新于 2021 年 12 月:
nginx-http-flv-module 并不支持 HTTP/2,这里只能做出取舍了。