准备
文中测试视频: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上的流媒体播放器。 |
便捷安装
当流服务器不涉及ffmpeg操作时用该方式
下面这种方式是直接安装官方编译过的,里面不包含ffmpeg库,
如果需要ffmpeg处理流的话需要自行下载ffmpeg,或者用下文编译源码的方式(推荐)
代码语言:javascript复制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
代码语言:javascript复制yum install -y redhat-lsb
RTMP URL格式:
代码语言:javascript复制rtmp://ip:[port]/appName/streamName
例如:
代码语言:javascript复制rtmp://192.168.1.108:1935/live/xiaoming
编译安装
当流服务器涉及ffmpeg操作时用该方式
下面下载官方源码编译,Github下载太慢,我就在gitee上做了个镜像。
这里之所以编译源码是因为之前的直接安装方式并不提供三方的库,比如接下来要用的ffmpeg;
当然我们也可以自己手动安装ffmpeg,然后修改配置文件中默认的ffmpeg路径即可。
注意这里ffmpeg一定要用4.1版本 srs在4.2版本下部分语法不支持 这里坑了我好久 如果之前安装过4.2版本的一定要先删除
查看ffmpeg版本
代码语言:javascript复制ffmpeg -version
安装srs
代码语言:javascript复制cd ~
git clone https://gitee.com/psvmc/srs.git
cp -rf srs/trunk /usr/local/srs2
cd /usr/local/srs2
./configure --full
make
这里没有用下面这种方式安装
代码语言:javascript复制./configure --prefix=/usr/local/srs2 --with-ffmpeg
make && make install
是因为这样安装后ffmpeg的文件夹并没有生成 还要手动再复制过去
我这里安装ffmpeg编译报错
build ffmpeg failed build ffmpeg-4.1 failed, ret=1
本来srs的编译已经包含x264和ffmpeg,我这报错就只能自己手动安装了
上面安装成功的就不用再执行以下命令了
安装编译环境
代码语言:javascript复制yum install -y automake autoconf libtool gcc gcc-c
yum install -y make
安装yasm插件
代码语言:javascript复制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
代码语言:javascript复制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
代码语言:javascript复制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
代码语言:javascript复制ffmpeg -version
报错:
ffmpeg: error while loading shared libraries: libx264.so.157: cannot open sh
解决方法
代码语言:javascript复制vi /etc/ld.so.conf
添加libx264.so所在路径
代码语言:javascript复制/usr/local/lib
退出后执行
代码语言:javascript复制ldconfig
低延迟配置运行
代码语言:javascript复制cd /usr/local/srs
nohup ./objs/srs -c conf/realtime.conf>log.txt &
结束进程
代码语言:javascript复制lsof -i:1935
kill -9 PID
常用配置
低延迟配置
代码语言:javascript复制listen 1935;
max_connections 1000;
daemon off;
srs_log_tank console;
vhost __defaultVhost__ {
gop_cache off;
queue_length 10;
min_latency on;
mr {
enabled off;
}
mw_latency 100;
tcp_nodelay on;
}
安全策略
详细配置:https://github.com/ossrs/srs/wiki/v2_CN_Security
目前只支持基于IP的安全策略,实用性不大。
代码语言:javascript复制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
直播流保存本地文件。
代码语言:javascript复制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
代码语言:javascript复制vhost __defaultVhost__ {
forward 127.0.0.1:19350;
}
Forward VS Edge
Forward架构和CDN架构的最大区别在于,CDN属于大规模集群,边缘节点会有成千上万台,源站2台(做热备),还需要有中间层。CDN的客户很多,流也会有很多。所以假若源站将每个流都转发给边缘,会造成巨大的浪费(有很多流只有少数节点需要)。
可见,forward只适用于所有边缘节点都需要所有的流。CDN是某些边缘节点需要某些流。
forward的瓶颈在于流的数目,假设每个SRS只侦听一个端口:
代码语言:javascript复制系统中流的数目 = 编码器的流数目 × 节点数目 × 端口数目
考虑5个节点,每个节点起4个端口,即有20个SRS边缘。编码器出5路流,则有20 * 5 = 100路流
。
同样的架构,对于CDN的边缘节点来讲,系统的流数为用户访问边缘节点的流
,假设没有用户访问,系统中就没有流量。某个区域的用户访问某个节点上的流,系统中只有一路流,而不是forward广播式的多路流。
另外,forward需要播放器随机访问多个端口,实现负载均衡,或者播放器访问api服务器,api服务器实现负载均衡,对于CDN来讲也不合适(需要客户改播放器)。
总之,forward适用于小型规模的集群,不适用于CDN大规模集群应用。
转封装成FLV流
详细配置:https://github.com/ossrs/srs/wiki/v2_CN_SampleHttpFlv
代码语言:javascript复制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
转封装成HLS流
详细配置:https://github.com/ossrs/srs/wiki/v2_CN_SampleHLS
代码语言:javascript复制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
代码语言:javascript复制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表示成功),其他错误码会断开客户端连接。
启动自带接口服务器
代码语言:javascript复制python research/api-server/server.py 8085
启动srs
代码语言:javascript复制./objs/srs -c conf/http.hooks.callback.conf
测试推流
代码语言:javascript复制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转码
详细配置:
- https://github.com/ossrs/srs/wiki/v2_CN_SampleFFMPEG
- https://github.com/ossrs/srs/wiki/v2_CN_FFMPEG
用于流处理或处理并转发RTMP服务器。
SRS转码的主要流程包括:
- 编码器推送RTMP流到SRS的vhost。
- SRS的vhost若配置了转码,则进行转码。
- 转码后,按照配置,推送到SRS本身或者其他RTMP服务器。
流处理
代码语言:javascript复制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服务器
代码语言:javascript复制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;
}
}
}
启动
代码语言:javascript复制cd /usr/local/srs2
./objs/srs -c conf/ffmpeg.transcode.conf
# 或
nohup ./objs/srs -c conf/ffmpeg.transcode.conf>log.txt &
推流
代码语言:javascript复制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是否能处理流成功
代码语言:javascript复制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:1935/live/test
- 命令转码流:rtmp://rtmp.psvmc.cn:1935/live/test2
- 观看转码流:rtmp://rtmp.psvmc.cn:1935/live/test_ff
示例配置
配置路径:/usr/local/srs/conf/z.conf
listen 1935;
max_connections 1000;
daemon off;
srs_log_tank console;
http_server {
enabled on;
listen 8080;
dir ./objs/nginx/html;
}
vhost __defaultVhost__ {
gop_cache off;
queue_length 10;
min_latency on;
mr {
enabled off;
}
mw_latency 100;
tcp_nodelay on;
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;
}
http_remux {
enabled on;
mount [vhost]/[app]/[stream].flv;
hstrs on;
}
}
结束
代码语言:javascript复制lsof -i:1935
kill pid
启动
代码语言:javascript复制cd /usr/local/srs
nohup ./objs/srs -c conf/z.conf>./log.txt &
推流
代码语言:javascript复制ffmpeg -re -stream_loop -1 -i /data/rtmptest.mp4 -vcodec copy -acodec copy -f flv -y rtmp://rtmp.psvmc.cn:1935/live/test
低版本FFMpeg循环播放
代码语言:javascript复制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
播放地址
- rtmp://rtmp.psvmc.cn:1935/live/test
- http://rtmp.psvmc.cn:8080/live/test.flv