<template>
<div class="video" :style="{ height: voidHeight }">
<video ref="videoElement" muted controls autoplay controlslist="nodownload noplaybackrate noremoteplayback" disablePictureInPicture="true" v-if="!imgError"></video>
<div class="img_error" v-if="imgError">
<p>无法连接相关设备</p>
</div>
</div>
</template>
<script>
import flvjs from "flv.js";
export default {
name: "assemblyFlv",
props: ["url", "height", "destroy","playon"], // 视频流路径,播放器高度,是否销毁播放器
data() {
return {
flvPlayer: "",
imgError: false,
voidHeight: "",
playOn:true
};
},
mounted() {
// 判断是否传入高度,如果没有,高度100%
this.height ? (this.voidHeight = this.height) : (this.voidHeight = "100%");
// 页面加载完成后,初始化
this.$nextTick(() => {
this.init(this.url);
});
},
methods: {
// 初始化
init(source) {
if (flvjs.isSupported()) {
this.flvPlayer = flvjs.createPlayer(
{
type: "flv",
url: source,
isLive: true,
},
{
enableWorker: false, //不启用分离线程
enableStashBuffer: false, //关闭IO隐藏缓冲区
reuseRedirectedURL: true, //重用301/302重定向url,用于随后的请求,如查找、重新连接等。
autoCleanupSourceBuffer: true, //自动清除缓存
}
);
var videoElement = this.$refs.videoElement;
this.flvPlayer.attachMediaElement(this.$refs.videoElement);
if (this.url !== "" && this.url !== null) {
this.flvPlayer.load();
//this.flvPlayer.play();
setTimeout(() => { this.flvPlayer.play(); }, 100);
// 加载完成
this.flvPlayer.on(flvjs.Events.LOADING_COMPLETE, () => {
this.imgError = false;
});
// 加载失败
this.flvPlayer.on(
flvjs.Events.ERROR,
() => {
if (this.flvPlayer) {
this.reloadVideo(this.flvPlayer);
}else{
this.imgError = true;
}
},
(error) => {
console.log(error);
}
);
this.flvPlayer.on(flvjs.Events.STATISTICS_INFO, (res) =>{
if(this.playon != false){
if (this.lastDecodedFrame == 0) {
this.lastDecodedFrame = res.decodedFrames;
console.log(this.lastDecodedFrame)
return;
}
if (this.lastDecodedFrame != res.decodedFrames) {
this.lastDecodedFrame = res.decodedFrames;
} else {
this.lastDecodedFrame = 0;
console.log('卡住重连')
if (this.flvPlayer) {
this.reloadVideo(this.flvPlayer);
console.log('卡住重连完成')
}
}
}
});
videoElement.addEventListener("progress", () => {
if(videoElement.buffered.length != 0){
let end = videoElement.buffered.end(0); //获取当前buffered值(缓冲区末尾)
let delta = end - videoElement.currentTime; //获取buffered与当前播放位置的差值
// 延迟过大,通过跳帧的方式更新视频
if (delta > 10 || delta < 0) {
this.flvPlayer.currentTime = this.flvPlayer.buffered.end(0) - 1;
console.log('跳帧')
return;
}
// 追帧
if (delta > 1) {
videoElement.playbackRate = 1.1;
console.log('追帧')
} else {
videoElement.playbackRate = 1;
console.log('正常')
}
}
});
// 点击播放按钮后,更新视频
videoElement.addEventListener("play", () => {
if(videoElement.buffered.length > 0){
let end = videoElement.buffered.end(0) - 1;
this.flvPlayer.currentTime = end;
console.log('播放最新')
}
});
// 网页重新激活后,更新视频
window.onfocus = () => {
if(videoElement.buffered.length > 0){
let end1 = videoElement.buffered.end(0) - 1;
this.flvPlayer.currentTime = end1;
console.log('页面切换')
}
};
}
} else {
this.imgError = true;
}
},
//断线重连
reloadVideo(flvPlayer) {
this.detachMediaElement();
this.init(this.url);
console.log('断线重连')
},
// 销毁
detachMediaElement() {
this.flvPlayer.pause();
this.flvPlayer.unload();
this.flvPlayer.detachMediaElement();
this.flvPlayer.destroy();
this.flvPlayer = "";
},
},
watch: {
url() {
this.imgError = false;
// 切换流之前,判断之前的流是否销毁
this.flvPlayer == "" ? "" : this.detachMediaElement();
// 初始化
this.init(this.url);
},
destroy() {
// 传入开关值
if (this.destroy) {
this.init(this.url);
} else {
this.flvPlayer == "" ? "" : this.detachMediaElement();
}
},
playon() {
this.reloadVideo(this.flvPlayer);
}
},
beforeDestroy() {
this.detachMediaElement();
},
};
</script>
<style scoped>
.video {
position: relative;
height: 100%;
}
.video video {
width: 100%;
height: 100%;
object-fit: fill;
}
.video video::-webkit-media-controls-play-button{
display: none;
}
.video video::-webkit-media-controls-toggle-closed-captions-button {
display: none;
}
.video video::-webkit-media-controls-timeline {
display: none;
}
.video video::-webkit-media-controls-current-time-display {
display: none;
}
.video video::-webkit-media-controls-time-remaining-display {
display: none;
}
.img_error {
position: absolute;
top: 30%;
left: 50%;
margin-left: -120px;
text-align: center;
}
.img_error > img {
margin-bottom: 1em;
}
.img_error > p {
color: #00fdff;
font-weight: bold;
font-size: 1.2em;
}
</style>
欢迎大家补充说明,或提出问题。