站点图标 Linux-技术共享

通过 nginx 搭建一个基于 http-flv 的直播流媒体服务器

前置知识

在搭建服务器之前,我们需要对直播这个概念本身有一个大概的理解。

我们经常听到两个词:推流(push/upstream) 和 拉流(pull/downstream)

推流大概指的是将从某设备上采集到的画面、音频上传到直播流媒体服务器上。

拉流大概指的是从直播流媒体服务器上下载那些推流上来的东西。

 

flv001

 

信息在网络中传播一定要遵循某种协议,否则就乱套了嘛,那么这些所谓的 流 在网络中传播,又有哪些可以遵循的协议呢?大概列举我认识的3个:

RTMP

RTMP 协议是 Adobe 公司设计的一个基于 TCP 传输的协议,被设计用来对基于底层传输协议的多媒体传输流(如音频、视频和交互数据)进行复用和分包。

RTMP 协议是目前最主流的传输协议,但是它最大的问题是,如果需要在浏览器上进行拉流,那么浏览器本身需要支持 flash,而当前众多浏览器厂商已经默认禁用了flash,对于用户体验十分不友好。

HTTP-FLV

flv(flash video) 本身是一种视频格式,也是 Adobe 公司推出的,在网络上传输的视频大多都是以这种格式封装的。而 http-flv 则是将推流推上来的流媒体数据封装成 flv ,并且通过 HTTP 协议进行传输的协议。需要浏览器端支持播放 flv 格式的视频才可以。

在本文中,推流使用的协议是 rtmp ,而拉流时使用的协议是 http-flv。

HLS

HLS(Http Live Streaming) 是苹果提出的基于 HTTP 的流媒体传输协议,他的大致原理是将一个大的视频数据文件切分成若干个小的视频文件,然后客户端拉流的时候依照顺序一个一个地将小视频文件拉下来。HLS最大的优点就是,HTML5可以直接打开播放。

nginx 嘛,众所周知它在 Windows 底下有各种奇奇怪怪的问题,所以我们这一次选择在 linux 底下进行部署这么一套服务器。

其实我在部署这个服务器的时候,使用的是 docker ,但是本文在记录的时候不打算基于 docker 环境进行解释,因为个人对 docker 还有很多不熟悉的地方。

下载源代码

为了让 nginx 拥有处理流媒体的能力,我们需要通过 编译安装 的方式来安装 nginx。

由于在本篇中我们尝试讲清楚的是搭建一个基于 http-flv 的流媒体服务器,所以在编译时,我们需要为 nginx 添加 nginx-http-flv-module 模块。

我们把 nginx 和 nginx-http-flv-module 的源代码都下载到 /tmp 目录下

nginx 版本号目前是 1.19.4,nginx-http-flv-module 的版本号目前是 1.2.6,在下方的命令行中可能有所体现。

1
2
3
cd /tmp
git clone nginx-http-flv-module
wget https://nginx.org/download/nginx-1.19.4.tar.gz

解压刚刚下载的 nginx,并进入到 nginx 的目录

1
2
tar -xzf nginx-1.15.9.tar.gz
cd nginx-1.19.4

编译安装

1
2
3
./configure --add-module=/tmp/nginx-http-flv-module --with-http_ssl_module
make
make install

这么一个过程下来后,nginx 会被安装在 /usr/local/nginx 底下。

需要注意的是,nginx-http-flv-module 是基于 nginx-rtmp-module 开发的,完全兼容 nginx-rtmp-module 的所有功能,所以在编译时无需重复添加 nginx-rtmp-module 模块。

上述命令中还包含了 --with-http_ssl_module 参数,是根据 nginx-rtmp-module 的编译安装说明进行的。

编辑 nginx.conf

使用 vi 或其他编辑工具编辑 /usr/local/nginx/conf/nginx.conf ,内容如下:

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
worker_processes  1;

events {
    worker_connections  1024;
}

rtmp {
    server {
        listen 9999;  # 接受推流的端口号
        chunk_size 8192; # 单一推流数据包的最大容量?

        application pushLive { # 推流时的 uri ,可以自行修改
            live on; # 打开直播
            meta off; # 为了兼容网页前端的 flv.js,设置为 off 可以避免报错
            gop_cache on; # 支持GOP缓存,以减少首屏时间
            allow play all; # 允许来自任何 ip 的人拉流
        }
    }
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       8080;  # http 服务的端口
        server_name  localhost;

        location /pullLive { # 拉流时的 uri ,可以自行修改
            flv_live on; # 打开 http-flv 服务
            chunked_transfer_encoding on;
            add_header 'Access-Control-Allow-Origin' '*'; # 允许跨域
            add_header 'Access-Control-Allow-Credentials' 'true';
        }

    }

}

启动 Nginx

启动位于 /usr/local/nginx/sbin 的 nginx

1
./nginx

当使用如上配置开启 Nginx 时,推流和拉流的地址分别是这样:

  • 推流地址: rtmp://localhost:9999/pushLive/rtmpStream
  • 拉流地址:http://localhost:8080/pullLive/?port=9999&app=pushLive&stream=rtmpStream

其中的 pushLive 指的是配置文件(nginx.conf)中 rtmp 块指定的 application,一个 rtmp server 可以拥有多个 application,只要名字对应的上,叫啥都可以。

示例地址中的 rtmpStream 可以由用户自己指定,只要拉流地址的参数stream对应的上就行了,有点类似于房间的概念,推流要推到哪个application底下的哪个房间的感觉。

使用 OBS 推流

我这里使用的是 OBS 软件进行推流,打开 OBS 设置面板 > 流

 

 
  1. 将服务设置为: 自定义
  2. 服务器设置为不包含房间名的推流地址示例: rtmp://localhost:9999/pushLive/
  3. 流秘钥设置为房间名: rtmpStream

不同版本的 obs 界面可能稍微有点不同

使用 flv.js 拉流

通过 flv.js(源码) 或者 fiv.js(CDN) 可以直接在网页上播放我们刚刚进行推流的音视频。

这里提供最基础的代码:

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
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>直播系统</title>
</head>
<body style="position:relative; text-align:center; top:20px;">
	<video id="videoElement" controls autoplay></video>
</body>

<script src="https://cdn.bootcdn.net/ajax/libs/flv.js/1.5.0/flv.min.js"></script>
<script>
    if (flvjs.isSupported()) {
        var videoElement = document.getElementById('videoElement');
        var flvPlayer = flvjs.createPlayer({
            type: 'flv',
            // 如果是直播流需要设置这个值为 true
            isLive:true,
            // 拉流示例地址,stream参数一定要和推流时所设置的流密钥一致,app是推流的uri
            url: 'http://172.18.195.92:8080/pullLive?port=9999&app=pushLive&stream=rtmpStream'
        });
        flvPlayer.attachMediaElement(videoElement);
        flvPlayer.load();
        flvPlayer.play();
    }
</script>
</html>
 
退出移动版