[toc]
什么是流媒体服务器
流媒体服务器(Streaming Media Server)是一种用于存储和传输音频、视频、直播等媒体内容的服务器软件。它通过网络将媒体文件实时传输给用户,而不需要用户先下载完整文件。流媒体服务器支持按需播放、实时广播等功能,常见的使用场景包括在线视频、音频点播、直播视频等。
视频流媒体数据传输往往对流媒体服务器编解码能力和协议转换有要求,因为不同的编码格式和不同的协议适用的场景不同。例如,RTMP协议延迟低,但是web浏览器不支持,需要将其转为HLS或者是FLV才能进行播放。
Nginx如何实现流媒体服务器
Nginx作为web服务器的一种,本身关注点在静态资源代理、正反向代理方面,实现作为流媒体服务器使用是依赖“插件”来扩展。例如:nginx-rtmp-module插件和nginx-http-flv-module插件。
为Nginx安装nginx-http-flv-module
概述
nginx中的模块虽然就是类似插件的概念,但是它无法像VsCode那样轻松的安装扩展。针对像 nginx-http-flv-module 这样的 nginx 模块,仅能通过重新编译 nginx 源码的方式完成“插件的安装”。
nginx-http-flv-module 基于 nginx-rtmp-module 二次开发,拥有 nginx-rtmp-module 全部的功能,同时具备HTTP-FLV播放,这个功能就很Nice,有了这个就可以实现在浏览器中观看直播,针对推送端无需额外的配置,一个直播流推送到流媒体服务器,直接可以输出多种流,包括:rtmp、hls、flv,rtmp用于在桌面应用程序中播放,hls和flv用于在浏览器中播放,当然hls也可以在桌面应用程序中播放,在浏览器播放方式中flv的画面延迟明显由于hls。
需要注意的是 nginx-http-flv-module 要求nginx的版本大于等于1.2.6。由于nginx-http-flv-module包含了 nginx-rtmp-module 模块,所以不可将 nginx-http-flv-module 和 nginx-rtmp-module 同时编译,当我们编译完 nginx-http-flv-module 之后,其实就已经拥有了 nginx-rtmp-module 的完整功能。
流程
- 查看当前nginx 的版本(假设安装位置为:/usr/local/nginx)
- 下载当前版本nginx的源代码
- 下载 nginx-http-flv-module 模块源代码
- 重新编译nginx并追加nginx-http-flv-module
- 将新编译好的 nginx 可执行文件拷贝到当前nginx安装目录(/usr/local/nginx/sbin)
操作步骤
使用如下命令查看当前已经安装的nginx的版本
[root@bogon sbin]# ./nginx -V nginx version: nginx/1.18.0 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) built with OpenSSL 1.0.2k-fips 26 Jan 2017 TLS SNI support enabled configure arguments: --prefix=/usr/local/nginx --with-http_dav_module --with-http_stub_status_module --with-http_addition_module --with-http_sub_module --with-http_flv_module --with-http_mp4_module --with-pcre --with-http_ssl_module --with-http_gzip_static_module
V:小v仅打印版本号,大V既打印版本号,也打印扩展信息,这里要使用大V
拿到版本号的目的是待会要下载该版本的源代码
注意保存打印内容中的 arguments 后面的内容,后面编译会用到
下载 nginx 源码和 nginx-http-flv-module 的源码,示例代码如下:
wget http://nginx.org/download/nginx-1.18.0.tar.gz tar -zxvf nginx-1.18.0.tar.gz git clone https://github.com/winshining/nginx-http-flv-module.git
进入nginx源码目录,使用如下命令重新编译nginx:
./configure --prefix=/usr/local/nginx --with-http_dav_module --with-http_stub_status_module --with-http_addition_module --with-http_sub_module --with-http_flv_module --with-http_mp4_module --with-pcre --with-http_ssl_module --with-http_gzip_static_module --add-module=/home/cml/nginx-http-flv-module make
- 使用configure 配置编译环境
- 将上面 保存的“arguments 后面的内容”作为configure 的第一个参数
- 第二个参数为 --add-module=/home/cml/nginx-http-flv-module ,即添加一个模块,模块源代码位置是 /home/cml/nginx-http-flv-module
- 使用make命令执行编译编译
编译成功后,在 objs中会有一个 名为nginx的可执行文件,这个就是编译好的nginx了, 里面包含已经安装的功能和新增加的nginx-rtmp-module,将这个可执行文件拷贝到当前安装目录(/usr/local/nginx/sbin)中就可以了。
注意拷贝之前需要停止nginx,否则会报当前文件繁忙,无法覆盖的错误。
通过如下命令验证安装是否正常:
nginx -V
若打印的信息中包含nginx-http-flv-module,说明安装好了。
配置流媒体服务器
当安装好了 nginx-http-flv-module 之后,就可以创建流媒体应用了。所谓的创建流媒体应用其实就是编写 nginx 的配置文件,如果需要创建一个名为 live 的流媒体应用,那么可以在 nginx.conf 中做如下配置
#以下内容放可在 nginx.conf 的最后,rtmp 配置块为顶级配置块
rtmp_auto_push on ;
rtmp {
server {
listen 1935; #监听的端口
notify_method get;
chunk_size 4000;
application live { #rtmp推流请求路径
live on;
# 添加 hls 支持
hls on;
hls_path /usr/local/nginx/html/hls;
hls_fragment 3;
hls_playlist_length 60;
# 允许从任何源push 流
allow publish all ;
# 允许从任何地方来播放流
allow play all;
# 20s内没有push,就断开连接
drop_idle_publisher 20s ;
}
}
}
- listen 1935:指定流媒体服务器的运行端口
- live :为流媒体应用的应用的名称,也即流媒体应用的唯一标识
- live on : 添加直播的支持
- hls_path:指定生成的m3u8文件的位置
之后就是创建http-flv端点和hls端点了,目的是让直播流可以在http协议上面传输直播画面。
若不创建,将仅可以使用rtmp协议拉流,即rtmp://ip:1935/live/stream_no;若创建了就可以使用hls或者flvjs来拉流播放了。
创建http-flv端点和hls端点同样是编辑nginx.conf来实现,如下示例配置:
server {
listen 82;
server_name rtmpserver;
# 创建hls端点
location /hls {
add_header 'Access-Control-Allow-Origin' '*' ;
add_header 'Access-Control-Allow-Credentials' 'true' ;
types {
application/vnd.apple.mpegurl m3u8 ;
video/mp2t ts;
}
alias /usr/local/nginx/html/hls;
expires -1 ;
add_header 'Cache-Control' 'no-cache';
}
# 创建 flv 端点
location /flv {
flv_live on ;
chunked_transfer_encoding on;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
}
}
- listen 82 :指定 hls端点和flv端点的监听端口,此端口可以自定义,针对hls端点和flv端点可以分开设置不同的监听端口
- hls端点的标识为 hls,此标识可以自定义,拉流的时候会用到
- alias:指定m3u8文件的访问路径,需要和 "创建流媒体应用"中的hls_path配置保持一致
- flv端点的标识为flv,此标识可以自定义,拉流的时候会用到
使用OBS推流
OBS 是非常成熟的软件了,安装参考官网:https://obsproject.com/
假设约定的推拉流地址为 rtmp://192.168.1.115:1935/live/room-1
设置直播流来源为 视频采集设备 和 浏览器,其中视频采集设备就是笔记本的摄像头,浏览器为OBS内置浏览器并打开 https://time.is/zh/ 这个网址。最终的直播画面就是两个采集终端的画面叠加在一起,底部是一个网址,网页中有一个时钟,顶部是摄像头。
设置直播服务器和推流码:
- 服务器:即流媒体应用的地址,即 rtmp://192.168.1.115:1935/live
- 推流码:即当前推流唯一标识,可以随意指定,保证推拉流地址一致即可,示例为: room-1
点击开始直播,OBS就开始向流媒体服务器推流了。
此时就可以使用拉流客户端拉取直播画面了,同时hls_path 下将生成m3u8文件,文件名称为 room-1.m3u8。
使用VLC拉RTMP
VLC是非常成熟的软件了,安装参考官网。
VLC拉流使用rtmp进行,拉流地址为:
rtmp://192.168.1.115:1935/live/room-1
使用flv.js拉流
基于flv.js编写一个视频播放器,新建一个html文件,示例代码如下:
flvjs_player.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FLV.js Example</title>
<script src="https://cdn.jsdelivr.net/npm/flv.js@1.5.0/dist/flv.min.js"></script>
</head>
<body>
<h1>FLV.js Player</h1>
<video id="videoElement" width="640" height="360" controls></video>
<button id="playButton">Click to Play Video</button>
<script>
// Check if the browser supports FLV.js
if (flvjs.isSupported()) {
var videoElement = document.getElementById('videoElement');
var flvPlayer = flvjs.createPlayer({
type: 'flv',
url: 'http://192.168.1.115:82/flv?port=1935&app=live&stream=room-1' // Replace with your FLV video URL
});
flvPlayer.attachMediaElement(videoElement);
flvPlayer.load();
// Play video on button click
document.getElementById('playButton').addEventListener('click', function() {
flvPlayer.play().catch(function(error) {
console.error('Error playing video:', error);
});
});
} else {
console.error('FLV.js is not supported in this browser.');
}
</script>
</body>
</html>
使用jls.js拉m3u8
基于hls.js编写一个视频播放器,新建一个html文件,示例代码如下:
m3u8_play.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HLS.js Example</title>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
</head>
<body>
<h1>HLS.js Player</h1>
<video id="videoElement" width="640" height="360" controls></video>
<script>
var video = document.getElementById('videoElement');
// 检查浏览器是否支持 HLS.js
if (Hls.isSupported()) {
var hls = new Hls();
// 加载并播放 .m3u8 文件
hls.loadSource('http://192.168.1.115:82/hls/room-1.m3u8'); // 替换为你的 .m3u8 URL
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, function() {
video.play(); // 加载后自动播放
});
hls.on(Hls.Events.ERROR, function(event, data) {
if (data.fatal) {
switch (data.fatal) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.error("网络错误");
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.error("媒体错误");
break;
case Hls.ErrorTypes.OTHER_ERROR:
console.error("其他错误");
break;
default:
console.error("无法播放视频");
break;
}
}
});
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
// 如果浏览器原生支持 HLS(例如 Safari),直接播放
video.src = 'http://192.168.1.92:82/hls/room-1.m3u8';
video.play();
} else {
console.error('HLS.js 不支持此浏览器');
}
</script>
</body>
</html>
总结
本文介绍了流媒体服务器的特性及各种流媒体传输协议的适用场景,并详细阐述了使用 nginx-http-flv-module 扩展Nginx作为流媒体服务器的详细步骤,并提供了在VLC,flv.js,hls.js下的流媒体拉流播放示例。