npm install --save flv.js
npm install --save hls.js
详细使用不做介绍,自行查阅文档API,提几点注意事项:
- 必须在DOM加载完成后再执行直播视频流的填充方法
- 同时播放多个视频可能会导致性能问题,包括视频的加载时间、占用带宽和系统资源
- 在离开这个页面的时候必须销毁播放容器,不然会占用TCP个数,导致其他页面的监控也播放不了
<script setup>
import loadingImg from "@/assets/img/bg.png";
import flvJs from "flv.js";
import Hls from "hls.js";
const props = defineProps({
url: {
type: String,
default: "",
},
poster: {
type: String,
default: loadingImg,
},
width: {
type: String,
default: "100%",
},
height: {
type: String,
default: "100%",
},
});
const player = ref(null);
const videoElementRef = ref();
const url = computed(() => props.url);
const createVideo = () => {
const videoElement = videoElementRef.value;
if (url.value.includes(".m3u8")) {
if (!Hls.isSupported()) {
console.log("不支持的格式");
return;
}
const hls = new Hls();
hls.loadSource(url.value);
hls.attachMedia(videoElement);
player.value = hls;
} else if (url.value.includes(".flv")) {
if (!flvJs.isSupported()) {
console.log("不支持的格式");
return;
}
const flvPlayer = flvJs.createPlayer({
type: "flv",
url: url.value,
});
flvPlayer.attachMediaElement(videoElement);
flvPlayer.load();
player.value = flvPlayer;
} else {
console.log("不支持的格式");
return;
}
};
const playVideo = () => {
player.value?.play();
};
const suspendVideo = () => {
player.value?.pause();
};
const destroyVideo = () => {
if (player.value) {
player.value?.pause();
player.value?.unload();
player.value?.detachMediaElement();
player.value = null;
}
};
defineExpose({ createVideo, destroyVideo, playVideo, suspendVideo });
</script>
<template>
<div class="video-player">
<video
ref="videoElementRef"
preload="auto"
controls
:style="{ width: width, height: height }"
muted="false"
:poster="poster"
></video>
</div>
</template>
<style lang="css" scoped>
.video-player {
}
</style>
使用
<script setup>
import videoFlv from '@/components/video-flv/video-flv.vue'
const videoFlvRef = ref()
const videoFlvIndex = ref(0)
// 测试地址
const list = reactive([
{url:'https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv'}
])
const changeVideoFlv = (index) => {
videoFlvIndex.value = index;
if (index == 0) {
videoFlvRef.value[list.value.length - 1].destroyVideo();
videoFlvRef.value[index + 1].destroyVideo();
videoFlvRef.value[index]?.createVideo();
nextTick(() => {
videoFlvRef.value[index]?.playVideo();
});
} else if (index == list.value.length - 1) {
videoFlvRef.value[0].destroyVideo();
videoFlvRef.value[index - 1].destroyVideo();
videoFlvRef.value[index]?.createVideo();
nextTick(() => {
videoFlvRef.value[index]?.playVideo();
});
} else {
videoFlvRef.value[index - 1].destroyVideo();
videoFlvRef.value[index + 1].destroyVideo();
videoFlvRef.value[index]?.createVideo();
nextTick(() => {
videoFlvRef.value[videoFlvIndex.value]?.playVideo();
});
}
};
onMounted(() => {
changeVideoFlv(0);
});
onBeforeUnmount(() => {
// 销毁 直播流
for (let index = 0; index < list.value.length; index++) {
videoFlvRef.value[index].destroyVideo();
}
});
</script>
<template>
<el-carousel
:autoplay="false"
indicator-position="none"
type="card"
width="100%"
height="550px"
@change="changeVideoFlv"
>
<el-carousel-item v-for="(item, index) in list" :key="index" >
<dv-border-box10
:color="['#4ccee3', '#4ccee3']"
style="padding: 10px; box-sizing: border-box"
>
<video-flv
ref="videoFlvRef"
width="100%"
height="550px"
:url="item.url"
/>
</dv-border-box10>
</el-carousel-item>
</el-carousel>
</template>