一般点播或者直播服务器都是使用nginx-rtmp-module作为服务器,然后使用ffmpeg或者obs来进行推流,客户端使用rtmp、http-flv、hls或者dash协议拉取转码后的数据,进行播放。
网上很多编译nginx+nginx-rtmp-module的方法,但是很少有可用的openresy+nginx-rtmp-module的编译方法。本文就从模块编译开始介绍下如何搭建点播、直播服务器。
首先下载openresty源码:https://github.com/openresty/openresty;如果仅仅编译nginx-rtmp-module,可以下载https://github.com/arut/nginx-rtmp-module,如果想额外支持http-flv协议,可以下载https://github.com/winshining/nginx-http-flv-module.git,后者包含了前者。
接着我们编译openresty
cd openresty/openresty-1.25.3.1
./configure --add-module=../../nginx-http-flv-module
复制
然后
make
sudo make install
复制
就完成了编译,不过实践过程中遇到了下面几个问题,值得分享下:
openresty/openresty-1.25.3.1/../../nginx-http-flv-module/hls/ngx_rtmp_hls_module.c:2059:27: error: use of undeclared identifier 'NGX_RTMP_FRAME_IDR'
frame.key = (ftype == NGX_RTMP_FRAME_IDR);
^
10 errors generated.
make[2]: *** [objs/addon/hls/ngx_rtmp_hls_module.o] Error 1
make[1]: *** [build] Error 2
make: *** [all] Error 2
复制
出现问题的原因是我们config错误了,nginx-http-flv-module 模块中包含nginx-rtmp-module模块的功能,只需安装nginx-http-flv-module 模块即可。也就是说,下面的配置方法是错误的。
./configure --add-module=../../nginx-rtmp-module --add-module=../../nginx-http-flv-module
复制
然后是make过程中的warning
ld: warning: dylib (/usr/local/Cellar/gcc/11.2.0/lib/gcc/11/libstdc++.dylib) was built for newer macOS version (11.3) than being linked (11.1)
复制
设置下环境变量即可
export MACOSX_DEPLOYMENT_TARGET=11.3
复制
然后是make install的时候遇到的
cp: /openresty/openresty-1.25.3.1/build/resty.index: No such file or directory
make: *** [install] Error 1
复制
build/pod: No such file or directory
make: *** [install] Error 1
复制
上述两个问题,在网上没有找到好的解决办法,目测这俩文件对安装没有大的影响,我的解决办法是在make install之前先创建它俩。
touch build/resty.index
touch build/pod
复制
然后问题就解决了。正确安装后展示如下:
mkdir -p usr/local/openresty/site/lualib usr/local/openresty/site/pod usr/local/openresty/site/manifest
ln -sf usr/local/openresty/nginx/sbin/nginx usr/local/openresty/bin/openresty
复制
然后我们运行下
/usr/local/openresty/bin/openresty
复制
ps aux |grep openresty
xiazemin 28175 0.0 0.0 4268424 732 s016 S+ 4:27下午 0:00.00 grep openresty
root 25010 0.0 0.0 4306592 584 ?? Ss 4:27下午 0:00.00 nginx: master process usr/local/openresty/bin/openresty
复制
没有报错,说明编译成功。
接着我们安装ffmpeg来进行推流,直接brew install ffmpeg会慢到让你怀疑人生。果断放弃,直接采用docker 镜像安装。
docker pull jrottenberg/ffmpeg
Using default tag: latest
latest: Pulling from jrottenberg/ffmpeg
docker.io/jrottenberg/ffmpeg:latest
复制
接着到网上下一个mp4格式的素材到本地。至此,我们的准备工作准备完毕。
然后开始配置我们的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; #not default port 1935
application myapp {
live on;
#为 rtmp 引擎设置最大连接数。默认为 off
max_connections 1024;
# 不开启录制
record off;
}
application hls{
live on;
hls on;
hls_path ./hls;
hls_fragment 1s;
}
}
}
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;
}
#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;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ \.ht {
# deny all;
#}
location /live {
flv_live on;
}
location /hls {
#server hls fragments
types{
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
alias ./hls;
expires -1;
#跨域一定要放开
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
}
# rtmp stat
location /stat {
rtmp_stat all;
#rtmp_stat_format json;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl {
root ./html/rtmp;
}
# rtmp control
location /control {
rtmp_control all;
add_header Access-Control-Allow-Origin *;
}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
复制
rtmp的配置和http的配置类似,包括rtmp、server、application三层。配置完毕后我们启动openresty
ps aux |grep -E "openresty|nginx" |grep -v grep |awk '{print $2}' |xargs sudo kill -9 && /usr/local/openresty/bin/openresty -p $PWD/ -c conf/nginx.conf
复制
接着我们启动ffmpeg进行推流
docker run -v $(pwd):$(pwd) jrottenberg/ffmpeg:latest -re -i $(pwd)/demo.mp4 -vcodec copy -f flv rtmp://host.docker.internal:1985/hls/stream
复制
推流成功后展示如下:
[flv @ 0xae7e00] Failed to update header with correct filesize.
frame= 929 fps= 30 q=-1.0 Lsize= 7624kB time=00:00:30.93 bitrate=2018.7kbits/s speed= 1x
video:7101kB audio:484kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.511305%
复制
推流过程中如果遇到下面错误
Metadata:
handler_name : Core Media Audio
rtmp://host.docker.internal:1985/zbcs/room: Input/output error
复制
原因是推流路径不对,application hls 前缀匹配后,还需要加一层目录,对应着我们的推流密钥。也就是说下面的推流是不对的:
docker run -v $(pwd):$(pwd) jrottenberg/ffmpeg:latest -re -i $(pwd)/demo.mp4 -vcodec copy -f flv rtmp://host.docker.internal:1985/hls
复制
推流成功后我们可以下载工具vlc来进行拉流,在vlc输入
rtmp://localhost:1985/hls/stream
复制
就可以看到视频播放效果,为了防止推流早早结束了,影响我们测试,可以配置循环推流:
docker run -v $(pwd):$(pwd) jrottenberg/ffmpeg:latest -stream_loop -1 -re -i $(pwd)/demo.mp4 -vcodec copy -f flv rtmp://host.docker.internal:1985/hls/stream
复制
回过头来看下我们的hls目录,可以看到下面的文件列表:
% ls ./hls
stream-20.ts stream-23.ts stream-26.ts stream-29.ts
stream-18.ts stream-21.ts stream-24.ts stream-27.ts stream.m3u8
stream-19.ts stream-22.ts stream-25.ts stream-28.ts
复制
一个stream.m3u8 和一批ts文件。转流成功后在我们之前配置的nginx rtmp模块的接收路径下(/hls)会生成m3u8索引文件,m3u8其实就是ts文件的索引,ffmpeg会把一个直播源的数据分割成很多个ts文件,访问m3u8可以获取ts文件的播放顺序,逐个播放,ts文件达到一定数量会自动删除前面无用的ts,并且如果ffmpeg停止转流,文件夹底下的文件也会自动清除。
至此我们完成了点播的推流和播放器拉流。如何进行直播的推流呢?其实很简单,我们把ffmpeg换成推流工具obs即可,和我们日常直播推流一样。obs设置推流服务器地址为
rtmp://localhost:1985/hls/stream
复制
需要注意的是,服务器地址是
rtmp://127.0.0.1:1985/hls/
复制
密钥是
stream
复制
否则会出现推流失败。至此,简单的点播和直播服务器搭建流程介绍完毕。后面详细介绍如何实现网页版的播放端推流、看端拉流、以及播放控制,敬请期待。