flv.js断开重连-画面卡顿-跳帧重连
1、播放页面卡住不动是进行截图并在一定时间内重新连接,
2、重连阶段显示截取卡住画面把图片显示等待视频流上来不至于video标签显示成黑屏;
vue写法
<video src=""
autoplay
muted
loop
:controls="false"
style="background: #000"
:ref=" (el) => item.videoRef = el " //video元素标签
@dblclick="videomaxck" //全屏事件
:poster="item.loadurl" 放显示图片
></video>
var item={
videoRef: "", //video元素标签
statusTime: 15, // 请求时长不播放状态为超时
status: 0, //0离线, 1正常,2超时,
intervalStatusTime: null, // 请求前10秒定时器实例
inspectionTime: 30, // 巡检时长
intervalInspectionTime: null, //正常巡检定时器实例
playerRef: null,//flvjs视频数据
loadurl:null,//图片url
data:{},//数据信息
};
//videoEle:video元素标签;streamUrl:播放url地址;item整个对象;channel:通道号
const startStream = (videoEle, streamUrl, item,channel) => {
//--先断开已连接的
if (item.playerRef) {
if (item.playerRef._receivedCanPlay) {
//播放过进行暂停释放
item.playerRef.pause();//--
}
item.playerRef.unload();//--
item.playerRef.detachMediaElement();//--
if (item.playerRef._mseSourceOpened || item.playerRef._receivedCanPlay) {
item.playerRef.destroy();
}
item.playerRef = null;
}
var mediaDataSource = {
type: 'flv',
hasAudio: channel == 1 ?false : true,//根据通道号判断是否带音频
hasVideo: true,
isLive: true,
url: streamUrl,
withCredentials: false
};
item.playerRef = flvjs.createPlayer(mediaDataSource, {
enableWorker: false,
lazyLoadMaxDuration: 3 * 60,
seekType: 'range',
autoCleanupSourceBuffer:true,
fixAudioTimestampGap:false,
stashInitialSize:128,//减少播放等待时间
enableStashBuffer:false,
lazyLoadRecoverDuration:1,
lazyLoad: false,
});
item.playerRef.attachMediaElement(videoEle);
item.playerRef.load();
item.playerRef.play();
//判断flv.js断开重连
if (item.playerRef) {
item.playerRef.on(flvjs.Events.ERROR,(err,errdet)=>{
if (item.data) {
videoEle.playbackRate = 1;
//截取卡住video画面成图片
getchangeJietu(videoEle,item);
//重连
startStream(videoEle,streamUrl,item,channel);
}
})
//判断画面卡顿-跳帧
item.playerRef.on(flvjs.Events.STATISTICS_INFO,(errs)=>{
if (item.data) {
if (item.playerRef.lastDecodedFrame == 0) {
item.playerRef.lastDecodedFrame = errs.decodedFrames;
item.playerRef.errorCount = 0;//记录画面卡住多少次
item.playerRef.lastDFrame = 0;//用于判断是否第一次画面卡住
return;
}
if (item.playerRef.lastDecodedFrame != errs.decodedFrames) {
item.playerRef.lastDecodedFrame = errs.decodedFrames;
item.playerRef.errorCount = 0;
item.playerRef.lastDFrame = 0;
} else {
if (item.playerRef.buffered.length>0) {
let end = item.playerRef.buffered.end(0); //获取当前时间值
let diff = end - item.playerRef.currentTime; //获取相差差值
item.playerRef.errorCount = 0;
item.playerRef.lastDFrame = 0;
// 延迟过大或帧率不正常,通过跳帧的方式更新视频
if (diff > 10 || (end > 0 && diff < 0)) {
item.playerRef.currentTime = item.playerRef.buffered.end(0);// 手动跳帧到最后
if (diff <= 1) {
// 正常帧率,正常播放
videoEle.playbackRate = 1;
}else if (diff <= 10) {
// 10秒内的延时,1.1倍速播放
videoEle.playbackRate = 1.1;
} else if (diff <= 20) {
// 20秒内的延时,1.2倍速播放
videoEle.playbackRate = 1.2;
}else if(diff>=130 ){
//此处可能出现播放界面卡住但有视频流在导致差值过大会一直卡住界面直接重新连接
if (item.data) {
videoEle.playbackRate = 1;
//截取卡住video画面成图片
getchangeJietu(videoEle,item);
//重连
startStream(videoEle,streamUrl,item,channel);
}
}
return ;
}
}else {
item.playerRef.errorCount=item.playerRef.errorCount+1;
if (item.playerRef.lastDFrame==0) {
//首次页面卡住记录卡住最后一帧解码帧
item.playerRef.lastDFrame=item.playerRef.lastDecodedFrame;
//截取卡住video画面成图片
getchangeJietu(videoEle,item);
}
//卡住页面5秒并且最后解码帧一致重新连接
if (item.playerRef.errorCount>10 && item.playerRef.lastDFrame==item.playerRef.lastDecodedFrame) {
if (item.data) {
videoEle.playbackRate = 1;
//重新连接
startStream(videoEle,streamUrl,item,channel);
}
}
}
}
}
})
}
};
// video卡住画面截图
const getchangeJietu = (videoRef,item) => {
if (videoRef) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d"); //设置canvas绘制2d图,
const width = videoRef.videoWidth; //设置canvas宽
const height = videoRef.videoHeight; //设置canvas高
canvas.width = width || 200;
canvas.height = height || 200;
ctx.drawImage(videoRef, 0, 0, width, height); //将video视频绘制到canvas中
const images = canvas.toDataURL("image/png"); //canvas的api中的toDataURL()保存图像
if (item.playerRef.statisticsInfo.decodedFrames>0) {
//解码帧大于0进行图片替换否则会截取黑屏;
item.loadurl=images;
}
}
};
// 停止视频播放
function stopStream(item) {
if (item.playerRef) {
if (item.playerRef._receivedCanPlay) {
//播放过进行暂停释放
item.playerRef.pause();//--
item.playerRef.destroy();
}
item.playerRef.unload();//--
item.playerRef.detachMediaElement();//--
item.playerRef = null;
item.data = null;
item.loadurl=null;
}
}
//全屏
const videomaxck=(e)=>{
if (e.currentTarget.requestFullscreen) {
e.currentTarget.requestFullscreen();
} else if (e.currentTarget.mozRequestFullScreen) {
e.currentTarget.mozRequestFullScreen();
} else if (e.currentTarget.webkitRequestFullScreen) {
e.currentTarget.webkitRequestFullScreen();
}
}