这几天一直在搭建一个web端的直播平台,需求是无插件,低延迟,开源免费。
但是网上的教程,大多比较零散,没有整合成一套解决方案。
所以搜索了很多资料,也问了不少群里的大佬。本篇博客是一个资源整合贴,也是一个避坑贴。
最终选定的解决方案:ffmpeg推流——>nginx-http-flv-module流服务器——>flv.js前端播放器
直播流协议:http-flv。优势:延迟低,无插件播放。
方案优势:所有组件均为开源免费。ffmpeg成熟、资料多。nginx-http-flv-module流服务器作者仍在维护,功能强大。flv.js是b站的开源播放器,GitHub有1W多star,可以无插件播放http-flv直播流。
下面分别讲解。
我的服务器环境是 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
来自nginx-http-flv-module的官方GitHub
作者大da一笔带过的事,可花费我了很长时间尝试。
总结:
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 #打开配置文件
...
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缓存,减少首屏等待时间
}
...
}
...
}
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帧,插入一个关键帧,可提高缓冲速度。而且延迟不会明显增加。
rtmp://example.com[:port]/appname/streamname
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: ''
});
http://example.com:8080/live?port=1935&app=myapp&stream=mystream
效果图:
================================================================================================
问题:使用中发现,如果最小化播放器的页面,或者进行浏览器页面切换,会增加播放器时延。正如以下资料中描述的“切换前后台带来的累积延时”。转自:http://www.samirchen.com/live-delay-optimization/
优化切换前后台带来的累积延时
在直播场景中,有一种情况是切换前后台造成累积延时。这里举个例子:在前台时,直播视频在播放,然后退到后台,此时暂停播放器,音视频数据继续缓存,当回到前台时,继续从刚才退出时的视频流数据开始播放,而实际的直播现在已经不在这个时间点了。这段前后台切换的时间里,就积累了一段延时。
对于这种延时改怎么处理呢?
第一种方案是播放器采用视频同步音频的策略,然后退到后台时保持音频继续播放(在 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进行差值判断。若差值大于一定值,自动进行校准。
其原理是:获取了视频的缓冲范围,如果缓存超过一定长度,就跳跃播放。
也可不进行校准,直接停止播放,提醒用户刷新界面(一些直播网站也是这么做的,用户离开时间过长将拒绝播放)。
相关资料:直播中累积延时的优化,低延时直播应用,flv.jsGithub
感谢网友的资料,感谢群友的思路,感谢各位开源大佬。
================================================================================================
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
....