OSSRS搭建RTMP推流服务器

准备

目前行业里直播还是以TCP占绝对份额,rtmp或者hls都是基于TCP,但是从底层UDP和TCP的特性来看,还是UDP更适合做直播。

文中测试视频:https://pan.baidu.com/s/1Cs9bULQ26zmDjbNqiIyUow 密码:q839
SRS官网:http://winlinvip.github.io/srs.release/releases/
SRS源码:https://github.com/ossrs/srs

直播方案对比

详见下表:

分发 平台 协议 公司 说明
RTMP Windows Flash RTMP Adobe 主流的低延时分发方式, Adobe的RTMP是Flash原生支持方式, FMS(Adobe Media Server前身), 就是Flash Media Server的简写,可见Flash播放RTMP是多么“原生”, 就像浏览器打开http网页一样“原生”, 经测试,Flash播放RTMP流可以10天以上不间断播放。
HLS Apple/ Android HTTP Apple/ Google 延时一个切片以上(一般10秒以上), Apple平台上HLS的效果比PC的RTMP还要好, 而且Apple所有设备都支持, Android最初不支持HLS,后来也支持了, 但测试发现支持得还不如Apple, 不过观看是没有问题,稳定性稍差, 所以有些公司专门做Android上的流媒体播放器。

Docker安装(推荐)

默认配置

1
docker run -d -p 1935:1935 -p 1985:1985 -p 8080:8080 --name srs3 registry.cn-hangzhou.aliyuncs.com/ossrs/srs:3

可用的流

自定义配置

新建配置文件

1
2
3
mkdir -p /usr/local/srs3/conf
touch /usr/local/srs3/conf/z.conf
touch /usr/local/srs3/conf/z.log

配置文件/usr/local/srs3/conf/z.log

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
# the listen ports, split by space.
listen 1935;
http_server {
enabled on;
listen 8080;
dir ./objs/nginx/html;
}
vhost __defaultVhost__ {
tcp_nodelay on
min_latency on;

play {
gop_cache off;
queue_length 10;
mw_latency 100;
}

publish {
mr off;
}

http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
hstrs on;
}
}

运行

1
2
3
4
docker run -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \
-v /usr/local/srs3/conf/z.conf:/usr/local/srs/conf/srs.conf \
-v /usr/local/srs3/conf/z.log:/usr/local/srs/objs/srs.log \
--name srs3 registry.cn-hangzhou.aliyuncs.com/ossrs/srs:3

停止并删除

1
2
docker stop srs3 &&\
docker rm srs3

便捷安装

当流服务器不涉及ffmpeg操作时用该方式

下面这种方式是直接安装官方编译过的,里面不包含ffmpeg库,

如果需要ffmpeg处理流的话需要自行下载ffmpeg,或者用下文编译源码的方式(推荐)

1
2
3
4
5
6
cd /root
wget http://winlinvip.github.io/srs.release/releases/files/SRS-CentOS6-x86_64-2.0.243.zip
unzip -q SRS-CentOS6-x86_64-2.0.243.zip
cd SRS-CentOS6-x86_64-*
sudo bash INSTALL
sudo /etc/init.d/srs start

srs安装后的目录为/usr/local/srs

abort, please install lsb_release

1
yum install -y redhat-lsb

RTMP URL格式:

1
rtmp://ip:[port]/appName/streamName

例如:

1
rtmp://192.168.1.108:1935/live/xiaoming

编译安装

当流服务器涉及ffmpeg操作时用该方式

下面下载官方源码编译,Github下载太慢,我就在gitee上做了个镜像。

这里之所以编译源码是因为之前的直接安装方式并不提供三方的库,比如接下来要用的ffmpeg;

当然我们也可以自己手动安装ffmpeg,然后修改配置文件中默认的ffmpeg路径即可。

注意这里ffmpeg一定要用4.1版本 srs在4.2版本下部分语法不支持 这里坑了我好久

如果之前安装过4.2版本的一定要先删除

查看ffmpeg版本

1
ffmpeg -version

安装srs

1
2
3
4
5
6
cd ~
git clone https://gitee.com/psvmc/srs.git
cp -rf srs/trunk /usr/local/srs2
cd /usr/local/srs2
./configure --full
make

这里没有用下面这种方式安装

1
2
./configure --prefix=/usr/local/srs2 --with-ffmpeg
make && make install

是因为这样安装后ffmpeg的文件夹并没有生成 还要手动再复制过去

我这里安装ffmpeg编译报错

build ffmpeg failed
build ffmpeg-4.1 failed, ret=1

本来srs的编译已经包含x264ffmpeg,我这报错就只能自己手动安装了

上面安装成功的就不用再执行以下命令了

安装编译环境

1
2
yum install -y automake autoconf libtool gcc gcc-c++ 
yum install -y make

安装yasm插件

1
2
3
4
wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz
tar -xvf yasm-1.3.0.tar.gz
cd yasm-1.3.0/
./configure && make && make install

安装nasm

1
2
3
4
5
6
7
cd ~
wget https://www.nasm.us/pub/nasm/releasebuilds/2.14.02/nasm-2.14.02.tar.gz
tar -zxvf nasm-2.14.02.tar.gz
cd nasm-2.14.02
./configure
make && make install
cd ..

安装 srs

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
yum install -y git
# 下载
rm -rf /usr/local/srs2
cd ~
git clone https://gitee.com/psvmc/srs.git
cp -rf srs/trunk /usr/local/srs2

# 安装三方依赖
cd /usr/local/srs2/3rdparty/

# 安装 x264:
wget https://code.videolan.org/videolan/x264/-/archive/stable/x264-stable.tar.gz
tar -zxvf x264-stable.tar.gz
cd x264-stable
./configure --enable-static --enable-shared
make && make install
cd ..

# 安装fdk-aac
wget https://jaist.dl.sourceforge.net/project/opencore-amr/fdk-aac/fdk-aac-0.1.5.tar.gz
tar -zxvf fdk-aac-0.1.5.tar.gz
cd fdk-aac-0.1.5
./configure
make && make install
cd ..

# 安装 ffmpeg:
unzip ffmpeg-4.1.zip
cd ffmpeg-4.1
./configure --enable-gpl --enable-libx264 --enable-nonfree --enable-libfdk-aac
make && make install

# 安装 srs:
cd /usr/local/srs2
./configure --full
make

测试ffmpeg

1
ffmpeg -version

报错:

ffmpeg: error while loading shared libraries: libx264.so.157: cannot open sh

解决方法

1
vi /etc/ld.so.conf

添加libx264.so所在路径

1
/usr/local/lib

退出后执行

1
ldconfig

常用配置

低延迟配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# the listen ports, split by space.
listen 1935;
vhost __defaultVhost__ {
tcp_nodelay on
min_latency on;

play {
gop_cache off;
queue_length 10;
mw_latency 100;
}

publish {
mr off;
}
}
1
2
cd /usr/local/srs2
nohup ./objs/srs -c conf/realtime.conf>log.txt &

结束进程

1
2
lsof -i:1935
kill -9 PID

转封装成FLV流

详细配置:https://github.com/ossrs/srs/wiki/v2_CN_SampleHttpFlv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
listen              1935;
max_connections 1000;
http_server {
enabled on;
listen 8080;
dir ./objs/nginx/html;
}
vhost __defaultVhost__ {
http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
hstrs on;
}
}

生成的流地址为:

  • RTMP流地址为:rtmp://rtmp.psvmc.cn/live/livestream
  • HTTP FLV: http://rtmp.psvmc.cn:8080/live/livestream.flv

安全策略

详细配置:https://github.com/ossrs/srs/wiki/v2_CN_Security

目前只支持基于IP的安全策略,实用性不大。

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
vhost your_vhost {
# security for host to allow or deny clients.
# @see https://github.com/ossrs/srs/issues/211
security {
# whether enable the security for vhost.
# default: off
enabled on;
# the security list, each item format as:
# allow|deny publish|play all|<ip>
# for example:
# allow publish all;
# deny publish all;
# allow publish 127.0.0.1;
# deny publish 127.0.0.1;
# allow play all;
# deny play all;
# allow play 127.0.0.1;
# deny play 127.0.0.1;
# SRS apply the following simple strategies one by one:
# 1. allow all if security disabled.
# 2. default to deny all when security enabled.
# 3. allow if matches allow strategy.
# 4. deny if matches deny strategy.
allow play all;
allow publish all;
}
}

本地录制FLV

详细配置:https://github.com/ossrs/srs/wiki/v2_CN_DVR

直播流保存本地文件。

1
2
3
4
5
6
7
8
9
10
vhost __defaultVhost__ {
dvr {
enabled on;
dvr_path /data/rtmplive/[app]/[stream]/[2006]/[01]_[02]/[15]_[04]_[05]_[999].flv;
dvr_plan session;
dvr_duration 30;
dvr_wait_keyframe on;
time_jitter full;
}
}

流转发

详细配置:https://github.com/ossrs/srs/wiki/v1_CN_SampleForward

1
2
3
vhost __defaultVhost__ {
forward 127.0.0.1:19350;
}

Forward VS Edge

Forward架构和CDN架构的最大区别在于,CDN属于大规模集群,边缘节点会有成千上万台,源站2台(做热备),还需要有中间层。CDN的客户很多,流也会有很多。所以假若源站将每个流都转发给边缘,会造成巨大的浪费(有很多流只有少数节点需要)。

可见,forward只适用于所有边缘节点都需要所有的流。CDN是某些边缘节点需要某些流。

forward的瓶颈在于流的数目,假设每个SRS只侦听一个端口:

1
系统中流的数目 = 编码器的流数目 × 节点数目 × 端口数目

考虑5个节点,每个节点起4个端口,即有20个SRS边缘。编码器出5路流,则有20 * 5 = 100路流

同样的架构,对于CDN的边缘节点来讲,系统的流数为用户访问边缘节点的流,假设没有用户访问,系统中就没有流量。某个区域的用户访问某个节点上的流,系统中只有一路流,而不是forward广播式的多路流。

另外,forward需要播放器随机访问多个端口,实现负载均衡,或者播放器访问api服务器,api服务器实现负载均衡,对于CDN来讲也不合适(需要客户改播放器)。

总之,forward适用于小型规模的集群,不适用于CDN大规模集群应用。

转封装成HLS流

详细配置:https://github.com/ossrs/srs/wiki/v2_CN_SampleHLS

1
2
3
4
5
6
7
8
9
10
listen              1935;
max_connections 1000;
vhost __defaultVhost__ {
hls {
enabled on;
hls_path ./objs/nginx/html;
hls_fragment 10;
hls_window 60;
}
}

生成的流地址为:

  • RTMP流地址为:rtmp://rtmp.psvmc.cn/live/livestream
  • HLS流地址为: http://rtmp.psvmc.cn/live/livestream.m3u8

HTTP回调

详细配置:https://github.com/ossrs/srs/wiki/v2_CN_HTTPCallback

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vhost __defaultVhost__ {
http_hooks {
enabled on;
on_connect http://127.0.0.1:8085/api/v1/clients http://localhost:8085/api/v1/clients;
on_close http://127.0.0.1:8085/api/v1/clients http://localhost:8085/api/v1/clients;
on_publish http://127.0.0.1:8085/api/v1/streams http://localhost:8085/api/v1/streams;
on_unpublish http://127.0.0.1:8085/api/v1/streams http://localhost:8085/api/v1/streams;
on_play http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions;
on_stop http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions;
on_dvr http://127.0.0.1:8085/api/v1/dvrs http://localhost:8085/api/v1/dvrs;
on_hls http://127.0.0.1:8085/api/v1/hls http://localhost:8085/api/v1/hls;
on_hls_notify http://127.0.0.1:8085/api/v1/hls/[app]/[stream]/[ts_url][param];
}
}

SRS的回调事件包括:

事件 数据 说明
on_connect { “action”: “on_connect”, “client_id”: 1985, “ip”: “192.168.1.10”, “vhost”: “video.test.com”, “app”: “live”, “tcUrl”: “rtmp://x/x?key=xxx”, “pageUrl”: “http://x/x.html" } 当客户端连接到指定的vhost和app时
on_close { “action”: “on_close”, “client_id”: 1985, “ip”: “192.168.1.10”, “vhost”: “video.test.com”, “app”: “live”, “send_bytes”: 10240, “recv_bytes”: 10240 } 当客户端关闭连接,或者SRS主动关闭连接时
on_publish { “action”: “on_publish”, “client_id”: 1985, “ip”: “192.168.1.10”, “vhost”: “video.test.com”, “app”: “live”, “tcUrl”: “rtmp://x/x?key=xxx”, “stream”: “livestream” } 推流到服务器时
on_unpublish { “action”: “on_unpublish”, “client_id”: 1985, “ip”: “192.168.1.10”, “vhost”: “video.test.com”, “app”: “live”, “stream”: “livestream” } 当客户端停止发布流时
on_play { “action”: “on_play”, “client_id”: 1985, “ip”: “192.168.1.10”, “vhost”: “video.test.com”, “app”: “live”, “stream”: “livestream”, “pageUrl”: “http://a.com/i.html", “param”:”?k=v” } 当客户端开始播放流时
on_stop { “action”: “on_stop”, “client_id”: 1985, “ip”: “192.168.1.10”, “vhost”: “video.test.com”, “app”: “live”, “stream”: “livestream” } 当客户端停止播放时。备注:停止播放可能不会关闭连接,还能再继续播放。
on_dvr { “action”: “on_dvr”, “client_id”: 1985, “ip”: “192.168.1.10”, “vhost”: “video.test.com”, “app”: “live”, “stream”: “livestream”, “cwd”: “/opt”, “file”: “./l.xxx.flv” } 当DVR录制关闭一个flv文件时

其中:

  • 事件:发生该事件时,即回调指定的HTTP地址。
  • HTTP地址:可以支持多个,以空格分隔,SRS会依次回调这些接口。
  • 数据:SRS将数据POST到HTTP接口。
  • 返回值:SRS要求HTTP服务器返回HTTP200并且response内容为整数错误码(0表示成功),其他错误码会断开客户端连接。

启动自带接口服务器

1
python research/api-server/server.py 8085

启动srs

1
./objs/srs -c conf/http.hooks.callback.conf

测试推流

1
ffmpeg -re -stream_loop -1 -i /data/rtmptest.mp4 -vcodec copy -acodec copy -f flv -y rtmp://127.0.0.1:1935/live/test

FFMpeg转码

详细配置:

用于流处理或处理并转发RTMP服务器。

SRS转码的主要流程包括:

  1. 编码器推送RTMP流到SRS的vhost。
  2. SRS的vhost若配置了转码,则进行转码。
  3. 转码后,按照配置,推送到SRS本身或者其他RTMP服务器。

流处理

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
listen              1935;
max_connections 1000;
daemon off;
srs_log_tank console;
vhost __defaultVhost__ {
transcode {
enabled on;
ffmpeg ./objs/ffmpeg/bin/ffmpeg;
engine ff {
enabled on;
vfilter {
}
vcodec libx264;
vthreads 4;
vprofile main;
vpreset medium;
vparams {
}
acodec libfdk_aac;
aparams {
}
output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
}
}
}

处理并转发RTMP服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vhost __defaultVhost__ {
transcode {
enabled on;
ffmpeg ./objs/ffmpeg/bin/ffmpeg;
engine ff {
enabled on;
vfilter {
}
vcodec copy;
acodec copy;
output rtmp://livepush.psvmc.cn/live/test;
}
}
}

启动

1
2
3
4
cd /usr/local/srs2
./objs/srs -c conf/ffmpeg.transcode.conf
# 或
nohup ./objs/srs -c conf/ffmpeg.transcode.conf>log.txt &

推流

1
ffmpeg -re -stream_loop -1 -i /usr/local/srs2/doc/source.200kbps.768x320.flv -vcodec copy -acodec copy -f flv -y rtmp://127.0.0.1:1935/live/test

测试服务器上ffmpeg是否能处理流成功

1
ffmpeg -f flv -i rtmp://127.0.0.1:1935/live/test -vcodec libx264 -threads 4 -profile:v main -preset medium -acodec copy -f flv -y rtmp://127.0.0.1:1935/live/test2

涉及的流包括:

  • 编码器推送流:rtmp://rtmp.psvmc.cn:1935/live/test
  • 观看原始流:rtmp://rtmp.psvmc.cn/live/test
  • 命令转码流:rtmp://rtmp.psvmc.cn/live/test2
  • 观看转码流:rtmp://rtmp.psvmc.cn/live/test_ff

推流测试

1
ffmpeg -re -stream_loop -1 -i /data/rtmptest.mp4 -vcodec copy -acodec copy -f flv -y rtmp://rtmp.psvmc.cn:1935/live/test

低版本FFMpeg循环播放

1
2
3
4
5
6
for((;;)); do \
/usr/bin/ffmpeg -re -i /data/rtmptest.mp4 \
-vcodec copy -acodec copy \
-f flv -y rtmp://rtmp.psvmc.cn:1935/live/test; \
sleep 1; \
done

播放地址

注册服务

添加文件 /etc/init.d/srs.sh

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
#!/bin/sh
# chkconfig: 2345 85 15
# description:auto_run

#程序根位置
MY_ROOT=/usr/local/srs2/

#运行程序位置
MY_PATH="${MY_ROOT}objs/srs"

#LOG位置
LOG_PATH="$MY_ROOT"log.txt

#开始方法
start() {
cd $MY_ROOT
nohup $MY_PATH -c conf/z.conf>$LOG_PATH &
echo "$MY_PATH start success."
}

#结束方法
stop() {
kill -9 `ps -ef|grep $MY_PATH|grep -v grep|grep -v stop|awk '{print $2}'`
echo "$MY_PATH stop success."
}

case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Userage: $0 {start|stop|restart}"
exit 1
esac

赋权

1
chmod +x /etc/init.d/srs.sh

添加为系统服务

1
chkconfig --add srs.sh

开机自启动

1
chkconfig srs.sh on

查看

1
chkconfig --list

启动

1
service srs.sh start

停用

1
service srs.sh stop

查看启动情况

1
lsof -i:1935

流播放

建议网页播放都用flv封装一下

flv.js:https://github.com/Bilibili/flv.js

在线测试地址:

测试Demo

链接: https://pan.baidu.com/s/1uGZNn48dRnZ09feOa8_gbQ 密码: d3n4