Nginx添加RTMP模块搭建RTMP推流服务器

前言

搭建基于nginx + nginx-rtmp-module的rtmp协议的推流服务器。

环境Centos 7 + Nginx

我平常nginx都是用yum安装的,这里需要编译安装

所以这篇文章最大可能和yum安装的nginx保持相同的配置

yum安装目录介绍

  • /usr/sbin/nginx 执行文件
  • /usr/lib64/nginx/modules/ 依赖模块目录
  • /etc/nginx 配置文件路径
  • /usr/share/nginx 默认的站点目录

安装Nginx和相关依赖

0、查看Nginx的版本和依赖

1
nginx -V

1、安装Nginx及其依赖库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#安装Nginx的编译环境gcc
yum install -y gcc-c++

#Nginx的http模块使用pcre解析正则表达式所以安装perl兼容的正则表达式库
yum install -y pcre pcre-devel

#Nginx使用zlib对http包的内容进行gzip
yum install -y zlib zlib-devel

#Nginx不仅支持http协议,还支持https(即在ssl协议上传输http),如果使用了https,需要安装OpenSSL库
yum install -y openssl openssl-devel

#安装Nginx
yum install -y nginx

2、下载可编译的nginx

1
2
3
4
5
cd /usr/local/
wget http://nginx.org/download/nginx-1.12.2.tar.gz
tar zxvf nginx-1.12.2.tar.gz
rm nginx-1.12.2.tar.gz
mv nginx-1.12.2 nginx

3、备份文件

1
2
cp -r /etc/nginx /etc/nginx_bak
mv /usr/sbin/nginx /usr/sbin/nginx_bak

下载rtmp模块

仓库地址:nginx-rtmp-module

1
2
cd /usr/lib64/nginx/modules/
git clone https://github.com/arut/nginx-rtmp-module.git

添加依赖

1
2
3
4
cd /usr/local/nginx/
./configure --prefix=/usr/local/nginx --conf-path=/usr/local/nginx/nginx.conf --add-module=/usr/lib64/nginx/modules/nginx-rtmp-module
make
make install

添加Nginx环境变量,可以在命令行直接输入Nginx命令

1
vim /etc/profile

在最后添加Nginx的路径

1
2
export NGINX_HOME=/usr/local/nginx
export PATH=$PATH:$NGINX_HOME/sbin

重新编译环境变量

1
source /etc/profile

配置Nginx的rtmp服务站点:

1
vim /usr/local/nginx/conf/nginx.conf

在http内部添加

1
include /etc/nginx/conf.d/*.conf;

在文件底部(和http同级)添加下面内容:

1
2
3
4
5
6
7
8
9
10
11
12
rtmp {
server {
listen 1935; #监听的端口
chunk_size 4000;
application tv_file {
live on; #开启实时
hls on; #开启hls
hls_path /usr/local/nginx/html/tv_file; #rtmp推流请求路径,文件存放路径
hls_fragment 5s; #每个TS文件包含5秒的视频内容
}
}
}

启动nginx

1
2
cd /usr/local/nginx/sbin
./nginx

查看端口是否能访问

1
telnet 你的ip地址 1935

http-flv

nginx-rtmp-module是不支持直接转换为http-flv的,所以就没法在Web端不使用flash的前提下播放流。

所以就有基于nginx-rtmp-module开发的nginx-http-flv-module

官方GitHub:https://github.com/winshining/nginx-http-flv-module/blob/master/README.CN.md

安装

nginx-http-flv-module 包含了 nginx-rtmp-module 所有的功能,所以不要nginx-http-flv-modulenginx-rtmp-module 一起编译。

下载 NGINXnginx-http-flv-module

将它们解压到某一路径。

打开 NGINX 的源代码路径并执行:

将模块编译进NGINX

1
2
3
./configure --add-module=/path/to/nginx-http-flv-module
make
make install

或者

将模块编译为动态模块

1
2
3
./configure --add-dynamic-module=/path/to/nginx-http-flv-module
make
make install

注意

如果将模块编译为动态模块,那么 NGINX 的版本号必须大于或者等于 1.9.11。

配置

关于 nginx-rtmp-module 用法的详情,请参考 README.md

注意

这里没有http-flv的配置 http-flv见下文

配置

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
rtmp {
server {
listen 1935;
chunk_size 4000;

# TV mode: one publisher, many subscribers
application mytv {
# enable live streaming
live on;

# record first 1K of stream
record all;
record_path /tmp/av;
record_max_size 1K;

# append current timestamp to each flv
record_unique on;

# publish only from localhost
allow publish 127.0.0.1;
deny publish all;

#allow play all;
}

# Transcoding (ffmpeg needed)
application big {
live on;

# On every pusblished stream run this command (ffmpeg)
# with substitutions: $app/${app}, $name/${name} for application & stream name.
#
# This ffmpeg call receives stream from this application &
# reduces the resolution down to 32x32. The stream is the published to
# 'small' application (see below) under the same name.
#
# ffmpeg can do anything with the stream like video/audio
# transcoding, resizing, altering container/codec params etc
#
# Multiple exec lines can be specified.

exec ffmpeg -re -i rtmp://localhost:1935/$app/$name -vcodec flv -acodec copy -s 32x32
-f flv rtmp://localhost:1935/small/${name};
}

application small {
live on;
# Video with reduced resolution comes here from ffmpeg
}

application webcam {
live on;

# Stream from local webcam
exec_static ffmpeg -f video4linux2 -i /dev/video0 -c:v libx264 -an
-f flv rtmp://localhost:1935/webcam/mystream;
}

application mypush {
live on;

# Every stream published here
# is automatically pushed to
# these two machines
push rtmp1.example.com;
push rtmp2.example.com:1934;
}

application mypull {
live on;

# Pull all streams from remote machine
# and play locally
pull rtmp://rtmp3.example.com pageUrl=www.example.com/index.html;
}

application mystaticpull {
live on;
# Static pull is started at nginx start
pull rtmp://rtmp4.example.com pageUrl=www.example.com/index.html name=mystream static;
}

# video on demand
application vod {
play /var/flvs;
}

application vod2 {
play /var/mp4s;
}

# Many publishers, many subscribers
# no checks, no recording
application videochat {
live on;
# The following notifications receive all
# the session variables as well as
# particular call arguments in HTTP POST
# request

# Make HTTP request & use HTTP retcode
# to decide whether to allow publishing
# from this connection or not
on_publish http://localhost:8080/publish;

# Same with playing
on_play http://localhost:8080/play;

# Publish/play end (repeats on disconnect)
on_done http://localhost:8080/done;

# All above mentioned notifications receive
# standard connect() arguments as well as
# play/publish ones. If any arguments are sent
# with GET-style syntax to play & publish
# these are also included.
# Example URL:
# rtmp://localhost/myapp/mystream?a=b&c=d

# record 10 video keyframes (no audio) every 2 minutes
record keyframes;
record_path /tmp/vc;
record_max_frames 10;
record_interval 2m;

# Async notify about an flv recorded
on_record_done http://localhost:8080/record_done;
}


# HLS

# For HLS to work please create a directory in tmpfs (/tmp/hls here)
# for the fragments. The directory contents is served via HTTP (see
# http{} section in config)
#
# Incoming stream must be in H264/AAC. For iPhones use baseline H264
# profile (see ffmpeg example).
# This example creates RTMP stream from movie ready for HLS:
#
# ffmpeg -loglevel verbose -re -i movie.avi -vcodec libx264
# -vprofile baseline -acodec libmp3lame -ar 44100 -ac 1
# -f flv rtmp://localhost:1935/hls/movie
#
# If you need to transcode live stream use 'exec' feature.
#
application hls {
live on;
hls on;
hls_path /tmp/hls;
}

# MPEG-DASH is similar to HLS
application dash {
live on;
dash on;
dash_path /tmp/dash;
}
}
}

# HTTP can be used for accessing RTMP stats
http {

server {

listen 8080;

# This URL provides RTMP statistics in XML
location /stat {
rtmp_stat all;

# Use this stylesheet to view XML as web page
# in browser
rtmp_stat_stylesheet stat.xsl;
}

location /stat.xsl {
# XML stylesheet to view RTMP stats.
# Copy stat.xsl wherever you want
# and put the full directory path here
root /path/to/stat.xsl/;
}

location /hls {
# Serve HLS fragments
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /tmp;
add_header Cache-Control no-cache;
}

location /dash {
# Serve DASH fragments
root /tmp;
add_header Cache-Control no-cache;
}
}
}

发布

为了简单起见,不用转码:

1
ffmpeg -re -i MEDIA_FILE_NAME -c copy -f flv rtmp://example.com[:port]/appname/streamname

注意

一些旧版本的 FFmpeg 不支持选项 -c copy,可以使用选项 -vcodec copy -acodec copy 替代。

appname 用于匹配 rtmp 配置块中的 application 块(更多详情见下文)。

streamname 可以随意指定,但是不能省略。

RTMP 默认端口1935,如果要使用其他端口,必须指定 :port

播放

HTTP-FLV 方式

1
http://example.com[:port]/dir?[port=xxx&]app=appname&stream=streamname

注意

  • 如果使用 ffplay 命令行方式播放流,那么必须为上述的 url 加上引号,否则 url 中的参数会被丢弃(有些不太智能的 shell 会把 “&” 解释为”后台运行”)。
  • 如果使用 flv.js 播放流,那么请保证发布的流被正确编码,因为 flv.js 只支持 H.264 编码的视频和 AAC/MP3 编码的音频

参数 dir 用于匹配 http 配置块中的 location 块(更多详情见下文)。

HTTP 默认端口80, 如果使用了其他端口,必须指定 :port

RTMP 默认端口1935,如果使用了其他端口,必须指定 port=xxx

参数 app 的值(appname)用来匹配 application 块,但是如果请求的 app 出现在多个 server 块中,并且这些 server 块有相同的地址和端口配置,那么还需要用匹配主机名的 server_name 配置项来区分请求的是哪个 application 块,否则,将匹配第一个 application 块。

参数 stream 的值(streamname)用来匹配发布的流的名称。

例子

假设在 http 配置块中的 listen 配置项是:

1
2
3
4
5
6
7
8
9
http {
server {
listen 8080; #不是默认的 80 端口

location /live {
flv_live on;
}
}
}

rtmp 配置块中的 listen 配置项是:

1
2
3
4
5
6
7
8
rtmp {
server {
listen 1985; #不是默认的 1935 端口
application myapp {
live on;
}
}
}

并且发布的流的名称是 mystream,那么基于 HTTP 的播放 url 是:

1
http://example.com:8080/live?port=1985&app=myapp&stream=mystream

注意

由于一些播放器不支持 HTTP 块传输, 这种情况下最好在指定了 flv_live on; 的 location 中指定 chunked_transfer_encoding off,否则播放会失败。

RTMP 方式

1
rtmp://example.com[:port]/appname/streamname

HLS 方式

1
http://example.com[:port]/hls/streamname.m3u8

DASH 方式

1
http://example.com[:port]/dash/streamname.mpd

常见的播放器

flv.js 只支持 H.264 编码的视频和 AAC/MP3 编码的音频

推流测试地址

http://rtmp.psvmc.cn