视频直播(一)CentOS 7上安装nginx与nginx-RTMP


## 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源创计划”,欢迎正在阅读的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章