一、流媒体
流媒体(Streaming media),也叫做流式媒体。是指将一连串的多媒体数据压缩后,经过互联网分段发送数据,在互联网上即时传输影音以供观赏的一种技术与过程。此技术使得数据包可以像流水一样发送。
流媒体文件一般都较大,如果使用下载的方式进行传输,所需要的存储容量也较大;同时由于网络带宽的限制,下载常常要花数分钟甚至数小时,所以这种处理方法延迟也很大。使用流式传输时,将声音和视频等时基媒体数据分段,连续实时发送到用户的设备,用户不必等到整个文件全部下载完毕,而只需经过几秒或十数秒的启动延时即可进行观看。当声音和视频等时基媒体在客户机上播放时,文件的剩余部分将在后台从服务器继续下载。流式不仅使启动延时成十倍、百倍地缩短,而且不需要太大的缓存容量。流式传输避免了用户必须等待整个文件全部下载完才能观看的缺点。流媒体的一个非常典型、火爆的应用场景:直播。近几年,直播行业是蒸蒸日上。
二、流媒体协议
常见的流媒体协议有:RTMP、HLS 等。
1、RTMP(Real-Time Messaging Protocol),译为:实时消息传输协议,由 Adobe 公司出品。默认基于 TCP 的 1935 端口。
2、HLS(HTTP Live Streaming),基于 HTTP 的流媒体网络传输协议,苹果公司出品。参考:RFC 8216。
本文主要介绍如何搭建一台 RTMP 服务器,为学习 RTMP 协议做准备。想研究清楚 RTMP ,我们可以使用抓包的方式窥探 RTMP 数据包的格式(抓包工具可以使用 Wireshark)。想要抓包就需要有推流操作,前提是我们要有一个 RTMP 服务器,那么下面开始 RTMP 服务器环境的搭建。
三、服务器环境搭建
我们自己想要搭建一个 RTMP 服务器环境有 2 种方式:1、购买云服务器;2、使用虚拟机搭建。本文选择的是使用虚拟机的方式搭建,那么接下来服务器系统是应该选择 MacOS 还是 Windows 呢?都不是!绝大部分公司的服务器都不会用这两款操作系统,实际工作中服务器使用的是 Linux 系统,MacOS 和 Windows 这么好用,也都是可以作为服务器系统的,为什么偏偏选择 Linux 呢?是因为 Linux 可以裁剪安装。所以我们也选择使用 Linux 系统来搭建一个 RTMP 服务器环境,Linux 最大的使用场景就是做服务器。下面我们要安装的 CentOS 就是 Linux 系统,Linux 系统衍生出来的版本非常多,比如 Ubuntu、Red Hat 等等。当然以学习为目的使用 MacOS 或者 Windows 搭建服务器环境也是可以的。
1、安装虚拟机软件
我本地的系统是 MacOS,首先在我们本地安装一个虚拟机软件,我使用的虚拟机软件是 VMWare。
2、安装 CentOS
2.1、下载 CentOS
CentOS 可以从网站 centoschina 中下载,上面有 CentOS 的各种版本,我这里下载的是 CentOS-7-x86_64-DVD-1810.iso, CentOS 7.6 是目前比较主流的版本(PS:系统版本只要有一点差异,有些操作就会不一样,最后的效果也会不一样)。
2.2、选择安装方法,选择从光盘和映像中安装,选择我们下载到本地的镜像文件 CentOS-7-x86_64-DVD-1810.iso,使用非快捷安装的方式进行安装
2.2、语言选择,选择简体中文即可:
2.3、进入安装信息摘要,不要着急操作等待扫描加载完成,设置完成页面如下。首先日期和时间、键盘、语音支持选项不需要我们更改:
2.4、检查安装源,不需要操作:
2.5、软件选择,最小安装只有命令行界面,没有图形界面,比较适合做服务器,是一个最小 Linux 系统,但是可能对于不会命令行的新手不太友好。我们选择 GNOME 桌面选项,选择GNOME 桌面选项安装后就是一个有图像界面的 Linux 系统,同时附加选项可以勾选:1、传统 X Windows 系统的兼容性;2、兼容性程序库;3、开发工具。如下图:
2.6、上一步操作完成后等待检查依赖完成,继续选择安装位置选项,建议我们自己来分区,把硬盘空间分成三个区:boot
(引导区)、swap
(交换分区)、root
(根区),选择其他存储选项下的我要配置分区:
进入到手动配置分区页面,,我们点击 + 开始分区:
添加 boot
(引导区),分配 1G 大小即可,设备类型选择标准分区
,文件系统选择ext4
:
添加 swap
(交换分区),分配 2G 大小即可,一般来说内存给的多少空间建议分配多少空间,设备类型选择标准分区
,文件系统选择swap
:
添加 root
(根分区),省下多少空间就给根分区分配多少空间,期望容量不填写即可。设备类型选择标准分区
,文件系统选择ext4
:
2.7、设置网络,打开以太网:
2.8、设置 ROOT 密码和创建用户,最后等待安装完成:
2.9、带有图形界面的 Linux 系统安装完成页面如下:
3、安装服务器软件
我们在 MacOS 上虚拟出一个 Linux 系统,但是我们还不能称之为服务器。想让 Linux 系统变成一个服务器,我们还需要安装一个服务器软件并启动 RTMP 服务,服务器软件一旦启动,就会占用 Linux 系统的一个端口,RTMP 服务默认占用1935 端口
。客户端推流推到 1935 端口
,RTMP 服务器软件通过1935 端口
就可以得到流数据,客户端也可以通过 1935 端口
进行拉流。
接下来安装服务器软件 nginx。不同的服务器软件干的事情是不一样的,比较知名的两款服务器软件是 tomcat 和 nginx。tomcat 一般用做 Java 服务器。nginx 一般用做反向代理和前端网页服务器。nginx 虽然是一款高性能的开源web服务器,但是默认是不支持 RTMP 的。同时需要安装一个模块 nginx-rtmp-module。
3.2、下载 nginx 和 nginx-rtmp-module
首先在 nginx 官网 下载最新稳定版本的 nginx。在 github 下载 nginx-rtmp-module,最新稳定版本在 tags 中查找。
我把 nginx 和 nginx-rtmp-module 下载到了本地 MacOS 系统,需要把这两个文件共享到 Linux 服务器上去。可以在 MacOS 和 Linux 两个系统之间设置一个共享文件夹。首先在虚拟机硬件设置->共享->启用共享文件夹并添加一个共享文件夹 nginx-shared
,然后重启 Linux 系统:
然后把 MacOS 系统下的共享文件夹nginx-shared
挂载到 Linux 系统的 mnt/nginx-shared
文件夹(mnt 用于临时挂载其他文件系统):
# Linux 系统终端
# 查看文件夹共享成功与否
[root@centos76 ~]# vmware-hgfsclient
tmp-shared
# 在 /mnt 下创建文件夹 rtmp-shared
[root@centos76 ~]# mkdir /mnt/rtmp-shared
# 挂载到对应目录
[root@centos76 ~]# vmhgfs-fuse .host:/rtmp-shared /mnt/rtmp-shared
在mnt/nginx-shared
文件下可以看到文件 nginx-1.20.1.tar.gz 和 nginx-rtmp-module-1.2.2.tar.gz 说明已经挂载成功,在 Linux 系统下访问mnt/nginx-shared
就相当于访问本地 MacOS 系统下的nginx-shared
文件夹:
[root@centos76 ~]# ls /mnt/rtmp-shared
nginx-1.20.1.tar.gz nginx-rtmp-module-1.2.2.tar.gz
3.2、配置 & 编译 nginx
解压 nginx-1.20.1.tar.gz 和 nginx-rtmp-module-1.2.2.tar.gz:
# 解压 nginx-1.20.1.tar.gz
[root@centos76 rtmp]# tar -zxvf nginx-1.20.1.tar.gz
# 解压 nginx-rtmp-module-1.2.2.tar.gz
[root@centos76 rtmp]# tar -zxvf nginx-rtmp-module-1.2.2.tar.gz
构建编译环境,编译 nginx 源码时需要和 nginx-rtmp-module 源码一起编译,nginx 是主代码,nginx-rtmp-module 可以理解为是一个插件(nginx 源码可单独编译,nginx-rtmp-module 源码是不可以单独编译的,单独编译的 nginx 是不支持 RTMP 的,将 nginx-rtmp-module 源码一起参与编译是为了增加 nginx 的功能,让其支持 RTMP):
[root@centos76 rtmp]# cd nginx-1.20.1
# --prefix=设置安装路径
# --add-module=参与编译的子模块
[root@centos76 nginx-1.20.1]# ./configure --prefix=/usr/local/nginx --add-module=../nginx-rtmp-module-1.2.2 --with-http_ssl_module
执行完configure
,打印了+ ngx_rtmp_module was configured
说明成功编译了nginx-rtmp-module,但是出现了另外一个问题,PCRE
这个库找不到。
...
+ ngx_rtmp_module was configured
checking for PCRE library ... not found
checking for PCRE library in /usr/local/ ... not found
checking for PCRE library in /usr/include/pcre/ ... not found
checking for PCRE library in /usr/pkg/ ... not found
checking for PCRE library in /opt/Local/ ... not found
...
接下来需要使用使用 yum
来安装一下pcre
(yum
类似于brew
),prce
可以理解为是已经编译好的库,可以直接拿来用,但是如果是被拿来参与其他库的编译,必须安装 prce
对应的 devel 包:
[root@centos76 nginx-1.20.1]# yum install -y pcre pcre-devel
安装完成pcre
执行configure
命令,发现pcre
找到了,但又有一个新的问题,openssl
找不到:
...
+ ngx_rtmp_module was configured
checking for PCRE library ... found
checking for PCRE JIT support ... found
checking for OpenSSL library ... not found
checking for OpenSSL library in /usr/local/ ... not found
checking for OpenSSL library in /usr/pkg/ ... not found
checking for OpenSSL library in /opt/local/ ... not found
...
继续安装openssl
:
[root@centos76 nginx-1.20.1]# yum install -y openssl openssl-devel
安装完成openssl
再次执行configure
命令,最终打印了creating objs/Makefile
,到目前为止说明已经没有问题了,并且会在目录nginx-1.20.1
下生成一个Makefile
文件。
...
creating objs/Makefile
Configuration summary
+ using system PCRE library
+ using system OpenSSL library
+ using system zlib library
...
我们发现 nginx 不仅依赖了pcre
和openssl
,也依赖了zlib
,为什么刚刚不报错呢?是因为当前 Linux 已经安装了zlib
,我们在安装 Linux 的时候勾选了开发工具
,勾选开发工具
会帮我们安装一些开发常用的库,比如gcc
、zlib
等等 。
PS:熟悉 nginx 的话,也可以一条指令安装依赖库:
[root@centos76 nginx-1.20.1]# yum install -y pcre pcre-devel openssl openssl-devel zlib zlib-devel
最后执行 make
命令开始编译:
[root@centos76 nginx-1.20.1]# make & make install
编译安装完成后/usr/local/nginx
文件夹下会有 4 个文件夹:
[root@centos76 nginx-1.20.1]# cd /usr/local/nginx
[root@centos76 nginx]# ls -l
drwxr-xr-x. 2 root root 4096 6月 23 9:16 conf # 配置文件
drwxr-xr-x. 2 root root 4096 6月 22 10:48 html
drwxr-xr-x. 2 root root 4096 6月 22 10:58 logs
drwxr-xr-x. 2 root root 4096 6月 22 10:48 sbin # 可行性程序
3.3、启动 nginx
执行sbin
目录下的nginx
可执行程序,就在后台启动了一台 nginx 服务器:
[root@centos76 nginx]# ./sbin/nginx
nginx 服务器启动成功后,在 Linux 系统下打开浏览器输入虚拟机 IP 地址就可以看到如下页面(我们看到的页面文件是在 nginx 的html
目录下)。nginx 服务器默认支持 http
协议,并且默认监听80 端口
(http
协议默认也是80 端口
),可以查看conf
目录下的配置文件nginx.conf
:
同时查看80 端口
占用情况,会发现80 端口
正在被 nginx 和 firefox 浏览器占用:
[root@centos76 nginx]# lsof -i:80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 9116 root 7u IPv4 61486 0t0 TCP *:http (LISTEN)
nginx 9118 nobody 3u IPv4 236966 0t0 TCP wangleiios:http->wangleiios:33302 (ESTABLISHED)
nginx 9118 nobody 7u IPv4 61486 0t0 TCP *:http (LISTEN)
firefox 25366 root 65u IPv4 236965 0t0 TCP wangleiios:33302->wangleiios:http (ESTABLISHED)
目前 Linux 系统和本地 MacOS 系统是处在同一个局域网中,可以互相ping
通,那么在本地 MacOS 系统下的浏览器是否可以访问 nginx 服务器呢?你会发现访问不了,是因为 Linux 服务器防火墙把80 端口
关闭了,不对外开放,所以还需要我们打开端口:
# 查看端口情况,返回 no 代表被关闭
[root@centos76 nginx]# firewall-cmd --query-port=80/tcp
no
# 获取 zone 名称,一般是 public
[root@centos76 nginx]# firewall-cmd --get-active-zones
public
# 打开端口
[root@centos76 nginx]# firewall-cmd --zone=public --add-port=80/tcp --permanent
success
# 重启防火墙,再次查看端口情况,就会返回 yes 了
[root@centos76 nginx]# firewall-cmd --reload
success
这样我们就可以从外部访问 nginx 服务器了。接下来我们希望它能监听1935 端口
,支持 RTMP 协议。首先修改conf
目录下的核心配置文件nginx.conf
,添加如下文本(文本中 rtmp 和 http 同级别):
rtmp {
server {
listen 1935; # 监听端口
chunk_size 4000; # 消息快大小,通常情况下,一个有效的消息,如果数据量超出当前 chunk_size 的话,则会被拆分成多个分块来分批传输
application live { # 请求路径/应用名称 例如:http://192.168.1.7:1935/live/01
live on;
}
}
}
修改nginx.conf
之前如果 nginx 已经启动,那么需要重启 nginx,配置文件才能生效:
# 查看 nginx 的 PID
[root@centos76 nginx]# lsof -i:80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 9116 root 7u IPv4 61486 0t0 TCP *:http (LISTEN)
nginx 9118 nobody 3u IPv4 236966 0t0 TCP wangleiios:http->wangleiios:33302 (ESTABLISHED)
nginx 9118 nobody 7u IPv4 61486 0t0 TCP *:http (LISTEN)
firefox 25366 root 65u IPv4 236965 0t0 TCP wangleiios:33302->wangleiios:http (ESTABLISHED)
# 杀死 nginx 进程
[root@centos76 nginx]# kill -9 9116 9118
# 启动 nginx
[root@centos76 nginx]# ./sbin/nginx
# 查看 1935 端口情况
[root@centos76 nginx]# lsof -i:1935
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 9116 root 6u IPv4 61485 0t0 TCP *:macromedia-fcs (LISTEN)
nginx 9118 nobody 6u IPv4 61485 0t0 TCP *:macromedia-fcs (LISTEN)
虽然已经成功开启了 RTMP 服务,但是此时外界是无法访问的,同样的需要把1935 端口
开放给外界:
[root@centos76 nginx]# firewall-cmd --zone=public --add-port=1935/tcp --permanent
# 重启防火墙
[root@centos76 nginx]# firewall-cmd --reload
这样就成功开启了一个外界可访问的 RTMP 服务(仅限于局域网内)。
四、使用 FFmpeg 进行推流&拉流
1、使用 FFmpeg 命令行进行推流,我们把一个 mp4 文件当做直播源,推到我们刚刚搭建的 RTMP 服务器上:
$ ffmpeg -i in.mp4 -f flv rtmp://192.168.1.10:1935/live/01
2、使用 ffplay
进行播放
$ ffplay rtmp://192.168.1.10:1935/live/01
这样就实现了简单的推流和拉流,后面就可以利用我们实现的 RTMP 服务器,使用抓包工具去分析 RTMP 协议了。