概述
这几天一直在搭建一个web端的直播平台,需求是无插件,低延迟,开源免费。
但是网上的教程,大多比较零散,没有整合成一套解决方案。
所以搜索了很多资料,也问了不少群里的大佬。本篇博客是一个资源整合贴,也是一个避坑贴。
最终选定的解决方案:ffmpeg推流——>nginx-http-flv-module流服务器——>flv.js前端播放器
直播流协议:http-flv。优势:延迟低,无插件播放。
方案优势:所有组件均为开源免费。ffmpeg成熟、资料多。nginx-http-flv-module流服务器作者仍在维护,功能强大。flv.js是b站的开源播放器,GitHub有1W多star,可以无插件播放http-flv直播流。
下面分别讲解。
nginx-http-flv-module流服务器搭建
我的服务器环境是 Ubuntu 16.04.3 LTS + nginx-1.1.17 + nginx-http-flv-module最新版。具体配置方法如下:
centos7下,nginx-1.1.17不适用,出现各种异常,最后换为nginx-1.8.1.tar.gz解决问题。浪费大量时间!
1.nginx和nginx-http-flv-module的编译安装
下载NGINX和nginx-http-flv-module。
将它们解压到某一路径。
打开NGINX的源代码路径并执行:
将模块编译进NGINX
./configure --add-module=/path/to/nginx-http-flv-module make make install
作者大da一笔带过的事,可花费我了很长时间尝试。
总结:
- /path/to应该修改成你的nginx-http-flv-module文件夹的位置。
- nginx和nginx-http-flv-module源码下载命令
wget http://nginx.org/download/nginx-1.1.17.tar.gz
git clone git://github.com/winshining/nginx-http-flv-module.git
- 解压后的两个文件夹应在同一目录下。
2.修改nginx的配置文件
- 打开配置文件
vim /usr/local/nginx/conf/nginx.conf #打开配置文件
- 删除原内容,复制nginx-http-flv-module的官方GitHub中的配置。在readme的这个位置:
- 一些关键配置:
...
http {
include mime.types;
default_type application/octet-stream;
keepalive_timeout 65;
server {
listen 80; #http-flv的拉流端口
...
# http-flv的相关配置
location /live {
flv_live on; #打开HTTP播放FLV直播流功能
chunked_transfer_encoding on; #支持'Transfer-Encoding: chunked'方式回复
add_header 'Access-Control-Allow-Origin' '*'; #添加额外的HTTP头
add_header 'Access-Control-Allow-Credentials' 'true'; #添加额外的HTTP头
}
...
}
}
rtmp_auto_push on;
rtmp_auto_push_reconnect 1s;
rtmp_socket_dir /tmp;
rtmp {
out_queue 4096;
out_cork 8;
max_streams 128;
timeout 15s;
drop_idle_publisher 15s;
log_interval 5s; #log模块在access.log中记录日志的间隔时间,对调试非常有用
log_size 1m; #log模块用来记录日志的缓冲区大小
server {
listen 1935;
server_name www.test.*; #用于虚拟主机名后缀通配
#ffmpeg推流的application
application myapp {
live on;
gop_cache on; #打开GOP缓存,减少首屏等待时间
}
...
}
...
}
- 注意gop_cache这个参数,on时延迟高,但第一帧画面加载快。off时正好相反,延迟低,第一帧加载略慢。
- 还有很多参数我还不懂怎么调
- 配置完成!
ffmpeg推流设置
- 首先,ffmpeg是个开源且强大的工具,可在官网直接下载。http://ffmpeg.org/download.html
- 再将ffmpeg的bin目录导入环境变量Path。
- 最后,cmd推流命令,详情请参考这篇资料https://www.jianshu.com/p/c141fc7881e7
- 举例,我用笔记本摄像头推流的命令:
ffmpeg -f dshow -i video="Integrated Webcam" -g 25 -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -f flv rtmp://127.0.0.1:1935/myapp/mystream
-g 25:每隔25帧,插入一个关键帧,可提高缓冲速度。而且延迟不会明显增加。
- url根据nginx配置文件的不同,而改变。
rtmp://example.com[:port]/appname/streamname
flv.js的配置
- flv.js是个工程化的前端项目,可以从GitHub下载后,使用工具生成js文件。可参考这篇博客:https://www.jianshu.com/p/8dda2be878b3
- 不懂前端的vue,node.js这些东西,或不想麻烦怎么办?直接导入在线js文件!cdn网址:https://www.bootcdn.cn/flv.js/
- flv.js的在线导入代码:
<script src="https://cdn.bootcss.com/flv.js/1.5.0/flv.js"></script>
- 开始撸播放器的代码,或直接从网上下载个demo改改来用
- 播放器调优,不调调是真的卡,兼容性还差。修改player的创建参数:
var flvPlayer = flvjs.createPlayer({
type: 'flv',
enableWorker: true, //浏览器端开启flv.js的worker,多进程运行flv.js
isLive: true, //直播模式
hasAudio: false, //关闭音频
hasVideo: true,
stashInitialSize: 128,
enableStashBuffer: false, //播放flv时,设置是否启用播放缓存,只在直播起作用。
url: ''
});
- 各参数详细含义可百度。。
- url由nginx配置文件决定,格式
http://example.com:8080/live?port=1935&app=myapp&stream=mystream
至此,整个解决方案已完成搭建。可以根据实际使用情况调整各参数。
效果图:
================================================================================================
++flv.js播放器累计时延的尝试消除
问题:使用中发现,如果最小化播放器的页面,或者进行浏览器页面切换,会增加播放器时延。正如以下资料中描述的“切换前后台带来的累积延时”。
优化切换前后台带来的累积延时
在直播场景中,有一种情况是切换前后台造成累积延时。这里举个例子:在前台时,直播视频在播放,然后退到后台,此时暂停播放器,音视频数据继续缓存,当回到前台时,继续从刚才退出时的视频流数据开始播放,而实际的直播现在已经不在这个时间点了。这段前后台切换的时间里,就积累了一段延时。
对于这种延时改怎么处理呢?
- 第一种方案是播放器采用视频同步音频的策略,然后退到后台时保持音频继续播放(在 iOS 平台需要开启 App 的 Background Audio 能力来配合)。这样可以保持音频一直播放不产生延时,而当回到前台时,视频同步音频直接切换到最新时间戳即可。
- 第二种方案是回到前台时重新刷新直播,重连直播流,这样即可消灭累积延时。但是这种方案的问题是重连直播流的过程需要一定的时间,这样回到前台时会有卡顿,或者出现黑屏,尤其是当你的首屏加载优化不够时,这个卡顿或黑屏时间会较长。所以这种方案在你的首屏加载优化的比较好的情况下可以采用。此外,你可以退到后台时截取视频当前帧贴图到直播间上,从而当切回前台时,防止黑屏,优化体验,实践效果还是不错的。
一种解决方法:我最终在flv.js GitHub的相关issue中找到了一种解决方法。代码如下:
setInterval(function () {
console.log("时延校正判断");
if (!_video.buffered.length) {
return;
}
var end = _video.buffered.end(0);
var diff = end - _video.currentTime;
console.log(diff);
if (diff >= 4) {
console.log("进行时延校正");
_video.currentTime = end;
//alert("时延过长,请点击时延校准");
}
}, 3000)
这种方法对video.buffered.end(0)和video.currentTime进行差值判断。若差值大于一定值,自动进行校准。
其原理是:获取了视频的缓冲范围,如果缓存超过一定长度,就跳跃播放。
也可不进行校准,直接停止播放,提醒用户刷新界面(一些直播网站也是这么做的,用户离开时间过长将拒绝播放)。
感谢网友的资料,感谢群友的思路,感谢各位开源大佬。
================================================================================================
++保存直播视频到服务器
user root; #给Nginx足够的文件访问权限
rtmp {
out_queue 1024;
out_cork 8;
max_streams 128;
timeout 15s;
drop_idle_publisher 15s;
log_interval 5s; #log模块在access.log中记录日志的间隔时间,对调试非常有用
log_size 1m; #log模块用来记录日志的缓冲区大小
server {
listen 1935;
server_name www.test.*; #用于虚拟主机名后缀通配
application myapp {
live on;
record video; #记录直播视频
record_path /tmp/rec; #视频保存路径
record_suffix -%d-%b-%y-%T.flv; #视频保存名:日期+.flv
....