## 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源創計劃”,歡迎正在閱讀的你也加入,一起分享。