105 lines
3.3 KiB
Vue
105 lines
3.3 KiB
Vue
<template>
|
||
<div>
|
||
<video ref="videoPlayer" autoplay playsinline></video>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import axios from "axios";
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
videoPlayer: null,
|
||
source: null, // 用于存储axios的CancelToken.source对象,以便后续取消请求
|
||
};
|
||
},
|
||
mounted() {
|
||
this.videoPlayer = this.$refs.videoPlayer;
|
||
this.startVideoStream();
|
||
},
|
||
methods: {
|
||
startVideoStream() {
|
||
//let url = "https://gep.ljsea.top/device/video_feed?" +"&device_id=" +localStorage.getItem("realvp_device_id") +"&token=" +localStorage.getItem("token"); //视频地址
|
||
|
||
const deviceId = localStorage.getItem("realvp_device_id"); // 替换为实际存储设备id的方式和键名
|
||
const token = localStorage.getItem("token"); // 替换为实际存储token的方式和键名
|
||
const url = `https://gep.ljsea.top/device/video_feed?device_id=${deviceId}&token=${token}`;
|
||
this.source = axios.CancelToken.source();
|
||
axios
|
||
.get(url, {
|
||
responseType: "arraybuffer",
|
||
cancelToken: this.source.token,
|
||
})
|
||
.then((response) => {
|
||
console.log("获取视频流成功");
|
||
const reader = response.data
|
||
.pipeThrough(new window.TextDecoderStream())
|
||
.getReader();
|
||
const processData = () => {
|
||
reader.read().then(({ done, value }) => {
|
||
if (done) {
|
||
return;
|
||
}
|
||
const dataString = new window.TextDecoder().decode(value);
|
||
const parts = dataString.split("\r\n");
|
||
|
||
// 检查是否包含关键的视频流格式标识
|
||
const hasFrameMarker = parts.some((part) =>
|
||
part.startsWith("--frame")
|
||
);
|
||
const hasContentTypeMarker = parts.some(
|
||
(part) => part === "Content-Type: image/jpeg"
|
||
);
|
||
if (!hasFrameMarker || !hasContentTypeMarker) {
|
||
console.error("视频流数据格式不符合预期,无法解析");
|
||
return;
|
||
}
|
||
|
||
parts.forEach((part) => {
|
||
if (part.startsWith("--frame")) {
|
||
const imageData = [];
|
||
let isImageData = false;
|
||
parts.forEach((subPart) => {
|
||
if (isImageData) {
|
||
imageData.push(subPart);
|
||
}
|
||
if (subPart === "Content-Type: image/jpeg") {
|
||
isImageData = true;
|
||
}
|
||
});
|
||
const imageBlob = new Blob(imageData, { type: "image/jpeg" });
|
||
const objectURL = URL.createObjectURL(imageBlob);
|
||
this.videoPlayer.src = objectURL;
|
||
}
|
||
});
|
||
processData();
|
||
});
|
||
};
|
||
processData();
|
||
})
|
||
.catch((error) => {
|
||
if (axios.isCancel(error)) {
|
||
console.log("请求已取消");
|
||
} else {
|
||
console.error("获取视频流出错:", error);
|
||
}
|
||
});
|
||
},
|
||
},
|
||
beforeUnmount() {
|
||
if (this.source) {
|
||
this.source.cancel("组件即将销毁,取消视频流请求");
|
||
}
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
video {
|
||
width: 100%;
|
||
max-width: 800px;
|
||
margin: 0 auto;
|
||
}
|
||
</style>
|