<template>
<div id="video_window" class="video_window">
<div class="header-wrapper">
<h3>{{props.device.id}}——{{props.selectedCamera.name}}——Camera</h3>
<el-button
class="close-btn"
circle
@click="handleCloseAspect"
><el-icon><Close /></el-icon></el-button>
</div>
<div class="mainAspect">
<div v-if="videoLoading" class="custom-loading-layer">
<div class="loading-spinner"></div>
<p>视频加载中...</p>
</div>
<video id="videoElement" class="videoElement" ref="flvPlayer" autoplay preload="metadata"></video>
</div>
</div>
</template>
<script setup>
import flvjs from "flv.js"
import { Close } from '@element-plus/icons-vue'
import { computed, onMounted, ref, watch, onUnmounted,defineEmits,nextTick } from 'vue';
import { getAction,videoClose } from '../api';
import {useStatusStore} from '../stores/videoCache'
import { ElMessage } from 'element-plus';
const props = defineProps({
device: {
type: Object,
required: true
},
selectedCamera:{
type: Object,
required: true
}
// const selectedDevice = ref({
// id: null,
// ip: null,
// position: null,
// size: { width: 2, height: 1, depth: 1 },
// status: 'normal', // normal/warning/error
// videos: [
// {name:"Load", channelNo:1},
// {name:"Unload", channelNo:2},
// {name:"DFC", channelNo:3},
// {name:"D/S L", channelNo:4},
// {name:"D/S R", channelNo:5},
// {name:"A/H L", channelNo:6},
// {name:"A/H R", channelNo:7},
// {name:"Wafer", channelNo:8},
// ],
// programs: {
// AAA: true, // 已安装
// BBB: false // 未安装
// }
// });
});
const emit= defineEmits(['close'])
const videCache=useStatusStore();
const originVideoPath='rtsp://admin:sess2025@'
const flvPath=ref(null);
const flvPlayer = ref(null);
let player=null;
const videoLoading=ref(true);
watch(
props,async (newProps) =>{
console.log(newProps.selectedCamera);
if (player) {
player.destroy();
player=null;
videoLoading.value=true;
await closeVideoStream();
await fetchVideoStream();
await nextTick();
initPlayer();
}
},{deep:true}
)
const handleCloseAspect=()=>{
emit('close');
}
const fetchVideoStream=async ()=>{
const res = await getAction(originVideoPath+String(props.device.ip)+":554/streaming/channels/"+String(props.selectedCamera.channelNo)+"01");
if(res.data==="视频加载失败"){
ElMessage.error("播放错误!")
return;
}
flvPath.value=res.data;
console.log(flvPath.value);
};
const closeVideoStream=async ()=>{
const res = await videoClose();
};
const initPlayer=()=>{
if(flvPath.value!==null){
if (flvjs.isSupported()) {
let videoElement = document.getElementById('videoElement')
player = flvjs.createPlayer({
type: 'flv',
isLive: true,
fluid: true,
stashInitialSize: 128,// 减少首桢显示等待时长
url: flvPath.value, //url地址
})
player.attachMediaElement(videoElement)
player.load()
player.on(flvjs.Events.METADATA_ARRIVED,()=>{
videoLoading.value=false;
})
player.play()
}
}else{
return;
}
};
onMounted(async () => {
videoLoading.value=true;
const videoSrc = await fetchVideoStream();
initPlayer();
});
onUnmounted(() => {
if (player) {
closeVideoStream();
player.destroy();
player=null;
}
});
</script>
<style scoped>
.mainAspect{
width: 100%;
height: 90%;
}
.videoElement{
width: 100%;
height: 500px;
transform-origin: center;
}
.video_window{
position: fixed;
top: 15%;
left: 30%;
width: 50%;
height: 70%;
border-radius: 5%;
background-color: white;
}
.close-btn {
position: absolute;
right: 10px;
top: 10px;
z-index: 20;
}
/*加载状态样式 */
.custom-loading-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 10;
color: gray;
}
.loading-spinner {
width: 40px;
height: 40px;
border: 3px solid rgba(255,255,255,0.3);
border-radius: 50%;
border-top-color: gray;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>这个flv能支持两个客户端同时拉流吗