## 00 直播的技术点是什么?什么是RTMP?
疫情降临,带动了一大批网课APP。
在线教育的赛道又添了一把火。
那在线直播的技术点有什么?通过什么技术栈实现呢?
目前我们常用的直播通讯协议有几个:RTMP、HLS、HTTP-FLV,RTMP主要是PC端,HLS则是苹果公司基于 HTTP 的流媒体传输协议,也兼容Android、H5,所以现在手机端基本都是用HLS。
直播分为推流和拉流两个过程,推就是我们向服务器推送数据流,拉就是从服务器上拉取数据流到本地来。
今天我们主要讲解如何部署Nginx服务器,并配置视频模块(nginx-rtmp-module),来搞定视频流和实时流的推拉。
当当,有请今天的主角RTMP登场。
RTMP是什么?其全称Routing Table Maintenance Protocol,即实时消息协议,是一种高性能协议。
用于在基于Flash的平台技术之间通过Internet传输数据,音频和视频。最初由Macromedia开发,现在由Adobe拥有。
Nginx RTMP是基于Nginx的媒体流媒体,具有RTMP,HLS和MPEG-DASH实时流媒体。Nginx RTMP模块具有很多功能,包括H264 / AAC支持,HTTP回调支持,用于记录音频/视频的HTTP控制模块等。
在本章中,我们将使用最新的CentOS 7服务器,安装nginx和rtmp模块的配置,以及按需创建RTMP实时流和视频。
## 01 我们要做些什么?
1、安装依赖项;
2、下载带有其他软件包和RTMP模块的Nginx;
3、编译Nginx并从源代码安装;
4、将Nginx配置为服务;
5、配置Nginx RTMP模块;
6、设置第一个RTMP实时流。
## 02 下载软件包
首先,我们将从源代码构建Nginx Web服务器,所以需要安装所需的所有软件包依赖项,包括开发工具,EPEL存储库和其他软件包。
# 安装CentOS的“开发工具”
sudo yum -y groupinstall 'Development Tools'
# 添加EPEL存储库
sudo yum -y install epel-release
# 安装nginx依赖项
sudo yum install -y wget git unzip perl perl-devel perl-ExtUtils-Embed libxslt libxslt-devel libxml2 libxml2-devel gd gd-devel pcre-devel GeoIP GeoIP-devel
然后,我们将下载带有其他依赖项的nginx源代码,包括pcre,zlib和OpenSSL。
cd /usr/local/src
# 下载Nginx 1.14.0并将其解压缩
wget https://nginx.org/download/nginx-1.14.0.tar.gz
# 解压nginx
tar -xzvf nginx-1.14.0.tar.gz
# 下载pcre
wget https://ftp.pcre.org/pub/pcre/pcre-8.42.zip
# 解压pcre
unzip pcre-8.42.zip
# 下载zlib
wget https://www.zlib.net/zlib-1.2.11.tar.gz
# 解压zlib
tar -xzvf zlib-1.2.11.tar.gz
# 下载openssl
wget https://www.openssl.org/source/openssl-1.1.0h.tar.gz
# 解压openssl
tar -xzvf openssl-1.1.0h.tar.gz
重头戏来了。
# 克隆nginx-RTMP模块
git clone https://github.com/sergey-dryabzhinsky/nginx-rtmp-module.git
# 删除多余文件
rm -f *.tar.gz *.zip
# 查看目录下文件
ls -lah
## 03 编译安装nginx及RTMP模块
cd nginx-1.14.0/
使用以下参数配置nginx
./configure --prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib64/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--user=nginx \
--group=nginx \
--build=CentOS \
--builddir=nginx-1.14.0 \
--with-select_module \
--with-poll_module \
--with-threads \
--with-file-aio \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_xslt_module=dynamic \
--with-http_image_filter_module=dynamic \
--with-http_geoip_module=dynamic \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_auth_request_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_degradation_module \
--with-http_slice_module \
--with-http_stub_status_module \
--http-log-path=/var/log/nginx/access.log \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--with-mail=dynamic \
--with-mail_ssl_module \
--with-stream=dynamic \
--with-stream_ssl_module \
--with-stream_realip_module \
--with-stream_geoip_module=dynamic \
--with-stream_ssl_preread_module \
--with-compat \
--with-pcre=../pcre-8.42 \
--with-pcre-jit \
--with-zlib=../zlib-1.2.11 \
--with-openssl=../openssl-1.1.0h \
--with-openssl-opt=no-nextprotoneg \
--add-module=../nginx-rtmp-module \
--with-debug;
编译并安装:
sudo make;sudo make install;
安装完成后,我们需要创建一个新的symlink模块目录,创建一个新的nginx用户和组,并创建一个新的nginx缓存目录。
# 创建软连接
sudo ln -s /usr/lib64/nginx/modules /etc/nginx/modules
# 创建nginx系统用户和组
sudo useradd -r -d /var/cache/nginx/ -s /sbin/nologin -U nginx
# 创建一个新的Nginx缓存目录“/var/cache/nginx”,并将目录所有者更改为“nginx”用户和组
mkdir -p /var/cache/nginx/
chown -R nginx:nginx /var/cache/nginx/
# 测试nginx配置和已安装的nginx版本
nginx -t
nginx -V
展示内容如下:
[root@hostone nginx-1.14.0]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@hostone nginx-1.14.0]# nginx -V
nginx version: nginx/1.14.0 (CentOS)
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
built with OpenSSL 1.1.0h 27 Mar 2018
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --user=nginx --group=nginx --build=CentOS --builddir=nginx-1.14.0 --with-select_module --with-poll_module --with-threads --with-file-aio --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --with-mail=dynamic --with-mail_ssl_module --with-stream=dynamic --with-stream_ssl_module --with-stream_realip_module --with-stream_geoip_module=dynamic --with-stream_ssl_preread_module --with-compat --with-pcre=../pcre-8.42 --with-pcre-jit --with-zlib=../zlib-1.2.11 --with-openssl=../openssl-1.1.0h --with-openssl-opt=no-nextprotoneg --add-module=../nginx-rtmp-module --with-debug
Nginx Web服务器已安装在启用了RTMP模块的CentOS 7上。
接下来,我们为nginx配置服务。
## 04 配置nginx服务
在systemd服务目录中创建一个新的nginx服务文件。
cd /lib/systemd/system/
vim nginx.service
配置如下;
[Unit]
Description=nginx - high performance web server
Documentation=https://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
[Install]
WantedBy=multi-user.target
显示如下,说明启动成功。
[root@hostone system]# systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
## 05 配置Nginx RTMP模块
在这里,我们为RTMP模块单独创建一个conf文件。
进入nginx目录,备份原来的conf,创建新的nginx 配置文件。
cd /etc/nginx/
mv nginx.conf nginx.conf.asli
vim nginx.conf
配置如下:
worker_processes auto;
events {
worker_connections 1024;
}
# RTMP configuration
rtmp {
server {
listen 1935; # Listen on standard RTMP port
chunk_size 4000;
# Define the Application
application show {
live on;
# Turn on HLS
hls on;
hls_path /mnt/hls/;
hls_fragment 3;
hls_playlist_length 60;
# disable consuming the stream from nginx as rtmp
deny play all;
}
}
}
http {
sendfile off;
tcp_nopush on;
aio on;
directio 512;
default_type application/octet-stream;
server {
listen 8080;
location / {
# Disable cache
add_header 'Cache-Control' 'no-cache';
# CORS setup
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length';
# allow CORS preflight requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
types {
application/dash+xml mpd;
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /mnt/;
}
}
}
接着,我们需要为HLS配置创建一个新目录,并且我们已经定义了Web根目录在'/mnt'目录中。
mkdir -p /mnt/hls
chown -R nginx:nginx /mnt/hls
nginx -t
systemctl restart nginx
出现报错:
Job for nginx.service failed because the control process exited with error code. See "systemctl status nginx.service" and "journalctl -xe" for details.
使用命令查看报错信息:
# 查看nginx运行状态
systemctl status nginx
信息如下:
Feb 16 12:29:58 hostone nginx[29459]: nginx: [emerg] bind() to 0.0.0.0:8080 failed (98: Address already in use)
Feb 16 12:29:59 hostone nginx[29459]: nginx: [emerg] bind() to 0.0.0.0:8080 failed (98: Address already in use)
Feb 16 12:29:59 hostone nginx[29459]: nginx: [emerg] bind() to 0.0.0.0:8080 failed (98: Address already in use)
Feb 16 12:30:00 hostone nginx[29459]: nginx: [emerg] bind() to 0.0.0.0:8080 failed (98: Address already in use)
Feb 16 12:30:00 hostone nginx[29459]: nginx: [emerg] bind() to 0.0.0.0:8080 failed (98: Address already in use)
Feb 16 12:30:01 hostone systemd[1]: nginx.service: control process exited, code=exited status=1
Feb 16 12:30:01 hostone nginx[29459]: nginx: [emerg] still could not bind()
Feb 16 12:30:01 hostone systemd[1]: Failed to start nginx - high performance web server.
Feb 16 12:30:01 hostone systemd[1]: Unit nginx.service ente
明显是8080端口被占用,换下conf中的端口。
# 查看8081端口是否被占用
lsof -i:8081
如果没有lsof命令,可以使用netstat或者yum install lsof 安装一下。
更换8080端口为8081端口:
vim /etc/nginx/nginx.conf
重启nginx服务,并查看运行状态:
systemctl restart nginx
systemctl status nginx
展示内容如下:
[root@hostone nginx]# systemctl restart nginx
[root@hostone nginx]# systemctl status nginx
● nginx.service - nginx - high performance web server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
Active: active (running) since Sun 2020-02-16 12:36:25 CST; 28s ago
Docs: https://nginx.org/en/docs/
Process: 29628 ExecStop=/bin/kill -s TERM $MAINPID (code=exited, status=0/SUCCESS)
Process: 29632 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
Process: 29631 ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
Main PID: 29633 (nginx)
CGroup: /system.slice/nginx.service
├─29633 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
├─29635 nginx: worker process
└─29636 nginx: cache manager process
Feb 16 12:36:25 hostone systemd[1]: Stopped nginx - high performance web server.
Feb 16 12:36:25 hostone systemd[1]: Starting nginx - high performance web server...
Feb 16 12:36:25 hostone nginx[29631]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Feb 16 12:36:25 hostone nginx[29631]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Feb 16 12:36:25 hostone systemd[1]: Failed to read PID from file /var/run/nginx.pid: Invalid argument
Feb 16 12:36:25 hostone systemd[1]: Started nginx - high performance web server.
## 06 设置第一个RTMP实时流
在本章中,我们将使用OBS软件从本地计算机广播服务器上的MP4视频产生的RTMP流。
编辑nginx的conf文件,
vim /etc/nginx/nginx.conf
将以下内容粘贴至rtmp { ... }中
# RTMP video on demand for mp4 files
application vod {
play /mnt/mp4s;
}
# RTMP stream using OBS
application stream {
live on;
}
创建一个新目录“mp4s”来存储所有视频,并将所有者更改为nginx用户组:
mkdir -p /mnt/mp4s
chown -R nginx:nginx /mnt/mp4s
测试并重启nginx:
nginx -t
systemctl restart nginx
## 07 测试
终于全部配置安装完成,我们来测试下,使用VLC、OBS来播放器测试RTMP视频流和实时流。
首先下载VLC、OBS软件。
VLC视频播放器官方地址:https://www.videolan.org/。
OBS(Open Broadcaster Software)官方下载地址:https://obsproject.com/welcome。
上传个视频到刚才nginx的RTMP模块vod定义的文件夹/mht/mp4s,我们的视频名叫001.mp4(自己随便找个)。
在本地计算机上打开VLC应用。
使用VLC,打开这个视频,路径为【媒体】->【打开网络串流】->rtmp://ip:1935/vod/001.mp4。
遇到了问题,播放流连接不通。
首先想的是,是不是防火墙有问题,从本地telnet了一下,果然不通,但检查了下服务器,并不是防火墙问题。
然后看了下nginx的运行状态,发下有一行错误被我忽略了。
Feb 16 13:07:11 hostone systemd[1]: Failed to read PID from file /var/run/nginx.pid: Invalid argument
回到添加nginx服务的系统目录中
cd /usr/lib/systemd/system
vi nginx.service
需要注释掉这一行。
# PIDFile=/run/nginx.pid
重新添加服务
# 重新加载系统服务配置
systemctl daemon-reload
# 重启nginx
systemctl restart nginx
# 查看nginx状态
systemctl status nginx
如下:
[root@hostone system]# systemctl status nginx
● nginx.service - nginx - high performance web server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
Active: active (running) since Sun 2020-02-16 13:10:03 CST; 18s ago
Docs: https://nginx.org/en/docs/
Process: 30808 ExecStop=/bin/kill -s TERM $MAINPID (code=exited, status=0/SUCCESS)
Process: 30812 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
Process: 30811 ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
Main PID: 30814 (nginx)
CGroup: /system.slice/nginx.service
├─30814 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
├─30815 nginx: worker process
└─30816 nginx: cache manager process
Feb 16 13:10:03 hostone systemd[1]: Stopped nginx - high performance web server.
Feb 16 13:10:03 hostone systemd[1]: Starting nginx - high performance web server...
Feb 16 13:10:03 hostone nginx[30811]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Feb 16 13:10:03 hostone nginx[30811]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Feb 16 13:10:03 hostone systemd[1]: Started nginx - high performance web server.
已经没有那行错误了。
但是搞了半天发现防火墙端口开了还是不行,忽然想到是不是云服务器厂商限制了。
找到了提供这台机器的小伙伴,一问之下果然如此。太坑了。
用VLC重新打开rtmp://ip:1935/vod/001.mp4。
视频流播放OK了,如图:
接下来是实时直播流。
需要用到OBS直播软件。
安装完成OBS,打开后,添加场景,添加显示器捕获,点击【设置】,如图
推流设置如下:
地址为刚才nginx中配置的stream,rtmp://ip:1935/stream。
然后返回主页面,点击右下角【开始推流】、【开始录制】。
打开VLC,还是打开网络串流,将串流地址同样换为rtmp://ip:1935/stream。
可以看到,直播开始了。
不过延迟有点严重,大概在3秒左右;而且图像传输会在某一刹那失真,估计受带宽影响较大。
明天研究下HLS,web及直播聊天室的创建。
本文分享自微信公众号 - 架构师之殇(ysistrue)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。