使用nginx搭建rtmp+http_flv服务器实现直播推流
1.概述
项目中要实现安卓手机上的直播功能,因为涉及网络安全,不允许使用第三方的直播推流服务器,所以需要自建一台直播推流的视频服务器,将搭建过程记录如下。
2.服务器配置
现场服务器均为Windows Server版本,但nginx安装第三方模块需要在Linux系统下进行,在Windows下的安装非常麻烦,而且稳定性不好,所以考虑在Windows服务器上安装CentOS的虚拟机,在虚拟机上安装nginx,然后使用端口映射到主机端口上实现相关功能
2.1.安装vmware虚拟机软件
在服务器上安装了VMware Workstation 12 Pro
2.2.安装CentOS7操作系统
使用CentOS-7-x86_64-DVD-1908.iso安装操作系统,安装时虚拟机网络使用NAT地址转换
安装后配置开机启用网络
cd /etc/sysconfig/network-scripts/
ls
#此处网卡配置文件名的数字可能为随机数字
#将其中的ONBOOT=yes改为ONBOOT=no 开机启动网络
#如需配置为静态地址,将BOOTPROTO=dhcp修改为static或none,然后配置IPADDR,PREFIX,GATEWAY,DNS1
sudo vi ifcfg-ens33
#重启网络服务
service network restart
#关闭防火墙
systemctl stop firewalld.service
#查看防火墙状态
systemctl status firewalld.service
#禁止防火墙开机启动
systemctl disable firewalld.service
ifcfg-ens33文件的核心内容
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=ens33
UUID=bb7e97e1-a6d4-44e6-80ee-212d82c9ca86
DEVICE=ens33
ONBOOT=yes
IPADDR=172.18.4.6
PREFIX=24
GATEWAY=172.18.4.2
DNS1=172.18.4.2
2.3.设置虚拟机为共享虚拟机
虚拟机必须设置为共享虚拟机才可以开机自启动,在左侧虚拟机列表中,右键虚拟机,然后选择“管理-共享”菜单,按提示一步一步设置为共享虚拟机,设置后即可开机自启动。
2.4.配置端口映射
在菜单:“编辑-虚拟网络编辑器”中打开虚拟网络编辑器,选择类型为“NAT模式”的行,在下面找到【NAT设置】按钮,点击后打开NAT设置窗口,点击添加即可添加端口映射
3.安装Nginx服务器软件
3.1.准备工作
打开命令行,安装编译相关软件
sudo yum -y install unzip gcc-c++ pcre pcre-devel zlib zlib-devel openssl openssl-devel
如果需要在离线机器上安装,则可以预先在能上网的机器上下载安装包,然后在离线机器上进行离线安装
#下载安装包
yumdownloader --resolve kernel-headers glibc-headers libcom_err libselinux libsepol-devel cpp glibc-devel libgomp glibc-common keyutils-libs-devel libcom_err-devel libselinux-devel libverto-devel krb5-libs libkadm5 gcc libstdc++ libstdc++-devel krb5-devel libcrypto.so.10 libssl.so.10 openssl-libs libc.so.6 libgcc_s.so.1 libm.so.6 libpthread.so.0 libstdc++.so.6 unzip gcc-c++ pcre pcre-devel zlib zlib-devel openssl openssl-devel
#压缩为tar包
tar cf rtmp-env.tar *.rpm
#解压tar包到指定目录
tar xf rtmp-env.tar -C ./env/
#离线安装rpm包
sudo rpm -ivh --replacefiles --replacepkgs *.rpm
3.2.下载Nginx源文件
从github下载nginx的源代码
https://github.com/nginx/nginx
#解压tar包
tar xf nginx-1.23.1.tar
注:打不开网站的话,安装【Steam++】软件进行网络加速
下载后,拷贝nginx源文件到/home/nginx下并解压,
解压后目录为/home/nginx/nginx-1.23.1
3.3.下载nginx-http-flv-module模块
从github下载nginx-http-flv-module的源代码
https://github.com/winshining/nginx-http-flv-module
拷贝nginx-http-flv-module源文件并解压到/usr/local/nginx下,nginx目录不存在时则创建之
解压后目录为/usr/local/nginx/nginx-http-flv-module
#解压命令
tar -zxvf nginx-1.23.1.tar.gz
unzip nginx-http-flv-module-master.zip
sudo mkdir /usr/local/nginx
sudo mv nginx-http-flv-module-master /usr/local/nginx/nginx-http-flv-module/
注:nginx-http-flv-module模块是基于 nginx-rtmp-module 的流媒体服务器,所以在编译时无需再引入nginx-rtmp-module,而且nginx-rtmp-module的各项配置也是兼容的。
3.4.编译安装Nginx软件
进入/home/nginx/nginx-1.23.1目录下执行以下命令
sudo ./configure --prefix=/usr/local/nginx --with-http_ssl_module --add-module=/usr/local/nginx/nginx-http-flv-module
sudo make
sudo make install
此时nginx已安装成功,可以执行/usr/local/nginx/sbin/nginx -V查看版本号,会输出以下内容:
nginx version: nginx/1.23.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --add-module=../nginx-http-flv-module
如果安装之后需要增加模块,可以使用configure命令添加配置,然后make,之后不要make install ,将编译的二进制文件手动拷贝到sbin目录下即可
cp ./objs/nginx /usr/local/nginx/sbin/
3.5.修改nginx配置文件
安装后的nginx配置文件中没有rtmp的相关配置,需要自行配置相关内容,以下是完整的配置文件内容
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
rtmp {
server {
listen 1985;
application live {
live on;
gop_cache on;
publish_notify on;
on_publish http://172.16.70.234:8080/swms/oa/index_notifyLiveStart.action;
#on_update http://172.16.70.234:8080/swms/oa/index_notifyLiveStart.action;
on_publish_done http://172.16.70.234:8080/swms/oa/index_notifyLiveStop.action;
}
}
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 8080;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
location /live {
flv_live on;
}
location /flv {
add_header 'Access-Control-Allow-Origin' '*';
flv_live on;
chunked_transfer_encoding on;
}
location /stat {
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl {
root nginx-http-flv-module/;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
其中rtmp段和http->server->location中的/live, /flv, /stat, /stat.xsl为新增段落
3.6.启动nginx
现在就可以启动nginx了,使用以下命令控制nginx
#启动
sudo /usr/local/nginx/sbin/nginx
#停止
sudo /usr/local/nginx/sbin/nginx -s stop
#重新加载配置文件
sudo /usr/local/nginx/sbin/nginx -s reload
3.7.安装nginx为服务
创建服务描述文件
sudo vi /usr/lib/systemd/system/nginx.service
内容如下:
[Unit]
Description=nginx - web server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop
ExecQuit=/usr/local/nginx/sbin/nginx -s quit
PrivateTmp=true
[Install]
WantedBy=multi-user.target
然后重新加载服务配置
systemctl daemon-reload
然后就可以使用服务命令控制nginx了
#停止Nginx服务
sbin/nginx -s stop
#开启Nginx服务
systemctl start nginx
#查看Nginx服务状态,出现【active (running)】表示服务正在运行
systemctl status nginx
#设置开机启动
systemctl enable nginx.service
#查看进程是否已启动
ps aux | grep nginx
#查看端口启用情况
netstat -tunlp
#使用sudo可以查看pid和程序名,然后再按nginx过滤
sudo netstat -tunlp | grep nginx
4.推流测试
使用ffmpeg进行测试
#视频文件推流:
ffmpeg.exe -re -i c:\ffmpeg\inputfile.mp4 -vcodec libx264 -acodec aac -f flv rtmp://127.0.0.1:1985/live/mp4
#桌面推流
ffmpeg -f gdigrab -i desktop -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -f flv rtmp://127.0.0.1:1985/live/desk1
#拉流测试
ffplay.exe rtmp://localhost:1985/live/mp4
5.网页播放
因为rtmp协议在网页上播放时需要使用flash插件,但现在各大浏览器已经不再支持flash插件了,所以需要使用http_flv协议实现网页播放的功能,这也是选择了nginx-http-flv-module模块的原因,在网页上播放http_flv需要使用bilibili开源的flv.js组件
https://github.com/bilibili/flv.js
可以下载源码进行编译,也可以直接下载编译好的Releases 版本的flv.js文件
http://bilibili.github.io/flv.js/dist/flv.js
https://github.com/bilibili/flv.js/releases/download/v1.6.2/flv.js
使用方法如下:
<script src="flv.js"></script>
<video id="videoElement" width="360" height="480"></video>
<script>
var url = 'http://localhost:8080/flv?port=1985&app=live&stream=mp4';
if (url && flvjs.isSupported()) {
var videoElement = document.getElementById('videoElement');
window.flvPlayer = flvjs.createPlayer({
type: 'flv',
url: url
});
flvPlayer.attachMediaElement(videoElement);
flvPlayer.load();
flvPlayer.play();
}
</script>
可以对FlvPlayer进行封装,监听相关事件,实现网络中断再次接通后重新加载播放功能
var liveOpt = {
liveStat:0,//直播是否开始,0未开始 1已开始
livePlayUrl:'http://....',//直播观看地址
flvPlayer:null,
startLive : function(){
if (this.liveStat==1 && flvjs.isSupported()) {
var videoElement = document.getElementById('videoElement');
var flvPlayer = this.flvPlayer = flvjs.createPlayer({
type: 'flv',
isLive:true,
url: this.livePlayUrl
}, {isLive:true});
flvPlayer.attachMediaElement(videoElement);
flvPlayer.on(flvjs.Events.ERROR, ()=>{
console.log('ERROR', arguments);
this.restartHandle = clearTimeout(this.restartHandle);
this.restartHandle = setTimeout(this.restartLive.bind(this), 3000);
});
this.metaArrived = false;
flvPlayer.on(flvjs.Events.METADATA_ARRIVED, ()=>{
console.log('METADATA_ARRIVED', arguments)
if(this.metaArrived){//如果第二次发来Meta信息,说明是断线后重连了,此时重新初始化控件
this.restartLive();
}
this.metaArrived = true;
});
flvPlayer.load();
flvPlayer.play();
}
else{
setTimeout(startLive, 600);
}
},
stopLive : function (){
if(this.flvPlayer){
try{
this.flvPlayer.destroy();
}
catch(e){}
this.flvPlayer = null;
}
},
restartLive:function(){
console.log('try to restart live!')
this.stopHandle && clearTimeout(this.stopHandle);
this.startHandle && clearTimeout(this.startHandle);
this.stopHandle = setTimeout(this.stopLive.bind(this), 1000);
this.startHandle = setTimeout(this.startLive.bind(this), 2000);
}
};
6.降低直播延迟
这一套环境搭建起来之后,跑通测试一番,结果发现在百兆局域网的条件下,延迟最小只能到3秒左右,而且flv.js稳定性还比较差,经常出现卡死不能播放的情况,后来无意中发现一款商用播放器NodePlayer,经测试可以达到1.3s左右的延迟,经过对比发现flv.js使用的是html5的video标签,而NodePlayer默认使用canvas进行渲染,当强制NodePlayer强制使用video标签渲染时,延迟也在3秒左右,所以说应该是使用video标签导致延迟过高,但因为NodePlayer是闭源软件,商用需要收费,所以在这里就不放链接了,给大家一个选择