<template>
|
<div style="height: 100%; position: relative;">
|
<div style="width: 100%; height: 100%; border-radius: 9px; background: #f5f5f5; display: flex; justify-content: center; align-items: center; flex-direction: column">
|
<video id="video" style="width: 100%; height: 100%; border-radius: 9px; display: none" muted controls></video>
|
<el-empty description="暂无视频信息" :image-size="80"></el-empty>
|
</div>
|
<div v-if="showError" class="error-box" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.8); display: flex; justify-content: center; align-items: center; z-index: 9999;">
|
<div class="error-content" style="text-align: center; color: #fff;">
|
<i class="el-icon-warning" style="font-size: 48px; color: #E6A23C; margin-bottom: 16px;"></i>
|
<p style="margin: 8px 0; font-size: 16px;">视频播放失败</p>
|
<p style="margin: 8px 0; font-size: 16px;">请稍后重试</p>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import { playDetection, closeRealVideo } from './service'
|
import flvjs from 'flv.js'
|
export default {
|
props: {
|
serverIp: {
|
type: String,
|
required: null
|
},
|
serverPort: {
|
type: Number,
|
required: null
|
},
|
carId: {
|
type: Number,
|
required: null
|
},
|
urlLink: {
|
type: String,
|
required: null,
|
},
|
},
|
data() {
|
return {
|
flvPlayer: null,
|
timer: null,
|
showError: false
|
}
|
},
|
watch: {
|
urlLink: {
|
handler(newUrl) {
|
if (newUrl) {
|
this.destroyPlayer();
|
this.playDetection();
|
}
|
},
|
immediate: true
|
}
|
},
|
mounted() {
|
if (this.urlLink) {
|
this.playDetection();
|
}
|
},
|
beforeDestroy() {
|
this.destroyPlayer();
|
},
|
methods: {
|
playDetection() {
|
this.showError = false;
|
if (!flvjs.isSupported()) {
|
this.showError = true;
|
this.$emit('video-error');
|
return;
|
}
|
|
playDetection(this.carId).then(res => {
|
if (this.flvPlayer) {
|
this.destroyPlayer();
|
}
|
|
try {
|
this.flvPlayer = flvjs.createPlayer({
|
type: 'flv', //视频类型
|
isLive: true, //是否为直播
|
cors: true, //是否开启跨域
|
hasAudio: false, //是否开启音频
|
hasVideo: true, //是否开启视频
|
url: this.urlLink, // 后端拿到的视频路径
|
enableWorker: true, //启用 Web Worker 进程来加速视频的解码和处理过程
|
enableStashBuffer: false, // 启用数据缓存机制,提高视频的流畅度和稳定性。
|
stashInitialSize: 1024, // 初始缓存大小。单位:字节。建议针对直播:调整为1024kb
|
stashInitialTime: 0.2, // 缓存初始时间。单位:秒。建议针对直播:调整为200毫秒
|
seekType: 'range', // 建议将其设置为"range"模式,以便更快地加载视频数据,提高视频的实时性。
|
lazyLoad: false, //关闭懒加载模式,从而提高视频的实时性。建议针对直播:调整为false
|
lazyLoadMaxDuration: 0.2, // 懒加载的最大时长。单位:秒。建议针对直播:调整为200毫秒
|
deferLoadAfterSourceOpen: false // 不预先加载视频数据,在 MSE(Media Source Extensions)打开后立即加载数据,提高视频的实时性。建议针对直播:调整为false
|
});
|
|
let video = document.getElementById('video');
|
if (!video) {
|
throw new Error('Video element not found');
|
}
|
|
this.flvPlayer.attachMediaElement(video);
|
this.flvPlayer.load();
|
|
this.flvPlayer.play().then(() => {
|
// 显示视频元素
|
video.style.display = 'block';
|
// 隐藏空状态
|
const emptyElement = video.parentElement.querySelector('.el-empty');
|
if (emptyElement) {
|
emptyElement.style.display = 'none';
|
}
|
|
this.timer = setInterval(() => {
|
playDetection(this.carId);
|
}, 5000);
|
}).catch(err => {
|
console.error('视频播放失败:', err);
|
this.showError = true;
|
this.destroyPlayer();
|
this.$emit('video-error');
|
});
|
|
this.flvPlayer.on('error', (err) => {
|
console.error('视频播放器错误:', err);
|
this.showError = true;
|
this.destroyPlayer();
|
this.$emit('video-error');
|
});
|
|
} catch (err) {
|
console.error('创建播放器失败:', err);
|
this.showError = true;
|
this.destroyPlayer();
|
this.$emit('video-error');
|
}
|
}).catch(err => {
|
console.error('获取视频流失败:', err);
|
this.showError = true;
|
this.destroyPlayer();
|
this.$emit('video-error');
|
});
|
},
|
destroyPlayer() {
|
if (this.flvPlayer) {
|
if (this.timer) {
|
clearInterval(this.timer);
|
this.timer = null;
|
}
|
try {
|
this.flvPlayer.pause();
|
this.flvPlayer.unload();
|
this.flvPlayer.detachMediaElement();
|
this.flvPlayer.destroy();
|
} catch (err) {
|
console.error('销毁播放器失败:', err);
|
} finally {
|
this.flvPlayer = null;
|
}
|
closeRealVideo(this.carId).catch(err => {
|
console.error('关闭视频流失败:', err);
|
});
|
|
// 恢复空状态的显示
|
const video = document.getElementById('video');
|
if (video) {
|
video.style.display = 'none';
|
const emptyElement = video.parentElement.querySelector('.el-empty');
|
if (emptyElement) {
|
emptyElement.style.display = 'block';
|
}
|
}
|
}
|
}
|
}
|
}
|
</script>
|
|
<style scoped>
|
/* 移除之前的样式,使用内联样式确保样式生效 */
|
</style>
|