feat(video):重构视频监控模块并优化实时预览功能
- 移除旧的 DahuaVideoController 控制器及相关接口 - 在 NetSDKService 中实现基于 FFmpeg 的实时流转码与推送逻辑 - 新增对 H.264 和 HEVC 编码格式的识别与动态转码支持 - 实现 FLV 流封装及 WebSocket 推送机制 - 添加 WebSocket 会话管理与多用户连接跟踪 - 更新平台视频管理控制器中的通道标识字段 - 配置文件中增加大华设备连接参数- 调整日志级别为 debug 以便于开发调试 - 完善资源清理逻辑,确保登出时释放所有相关句柄和进程dev_dahua
parent
54ca5e9e4c
commit
566b1ae944
|
|
@ -1,9 +1,12 @@
|
|||
VITE_BASE=/
|
||||
# VITE_BASE_URL=http://192.168.0.25:8095/
|
||||
VITE_BASE_URL=http://192.168.0.37:8095/
|
||||
VITE_BASE_URL=http://192.168.4.40:8095/
|
||||
|
||||
#websocket t掉线
|
||||
VITE_ON_LINE_WEB_SOCKET_URL=ws://192.168.0.37:8869
|
||||
VITE_ON_LINE_WEB_SOCKET_URL=ws://192.168.4.40:8869
|
||||
|
||||
#websocket 在线学习
|
||||
VITE_LEARNING_WEB_SOCKET_URL=ws://192.168.0.37:8899
|
||||
VITE_LEARNING_WEB_SOCKET_URL=ws://192.168.4.40:8899
|
||||
|
||||
#websocket 大华设备视频
|
||||
VITE_DAHUA_WEB_SOCKET_URL=ws://192.168.4.40:8866
|
||||
|
|
|
|||
|
|
@ -4,9 +4,12 @@ VITE_BASE_URL=http://172.16.70.226:8081/sx_yjb/
|
|||
#VITE_BASE_URL=https://qaaqwh.qhdsafety.com/integrated_whb/
|
||||
|
||||
#websocket t掉线
|
||||
VITE_ON_LINE_WEB_SOCKET_URL=ws://183.251.104.38:10103
|
||||
VITE_ON_LINE_WEB_SOCKET_URL=ws://172.16.70.226:8869
|
||||
# VITE_ON_LINE_WEB_SOCKET_URL=wss://qaaqwh.qhdsafety.com/disconnected/
|
||||
|
||||
#websocket 在线学习
|
||||
VITE_LEARNING_WEB_SOCKET_URL=ws://183.251.104.38:10102
|
||||
VITE_LEARNING_WEB_SOCKET_URL=ws://172.16.70.226:8899
|
||||
#VITE_LEARNING_WEB_SOCKET_URL=wss://qaaqwh.qhdsafety.com/onlinelearning/
|
||||
|
||||
#websocket 大华设备视频
|
||||
VITE_DAHUA_WEB_SOCKET_URL=ws://172.16.70.226:8866
|
||||
|
|
|
|||
|
|
@ -19,4 +19,8 @@ interface ImportMetaEnv {
|
|||
* websocket 在线学习
|
||||
*/
|
||||
readonly VITE_LEARNING_WEB_SOCKET_URL: string
|
||||
/**
|
||||
* websocket 大华设备视频
|
||||
*/
|
||||
readonly VITE_DAHUA_WEB_SOCKET_URL: string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,12 +20,14 @@
|
|||
"dayjs": "^1.11.10",
|
||||
"echarts": "^5.4.3",
|
||||
"element-plus": "^2.6.1",
|
||||
"flv.js": "^1.6.2",
|
||||
"hls.js": "^1.6.13",
|
||||
"html2canvas": "^1.4.1",
|
||||
"jspdf": "^2.5.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mitt": "^3.0.1",
|
||||
"mp4box": "^0.5.2",
|
||||
"mpegts.js": "^1.8.0",
|
||||
"nanoid": "^5.0.4",
|
||||
"normalize.css": "^8.0.1",
|
||||
"pako": "^2.1.0",
|
||||
|
|
@ -3362,6 +3364,11 @@
|
|||
"es6-symbol": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/es6-promise": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmmirror.com/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
|
||||
},
|
||||
"node_modules/es6-symbol": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz",
|
||||
|
|
@ -4110,6 +4117,15 @@
|
|||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/flv.js": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmmirror.com/flv.js/-/flv.js-1.6.2.tgz",
|
||||
"integrity": "sha512-xre4gUbX1MPtgQRKj2pxJENp/RnaHaxYvy3YToVVCrSmAWUu85b9mug6pTXF6zakUjNP2lFWZ1rkSX7gxhB/2A==",
|
||||
"dependencies": {
|
||||
"es6-promise": "^4.2.8",
|
||||
"webworkify-webpack": "^2.1.5"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.11",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||
|
|
@ -5445,6 +5461,15 @@
|
|||
"integrity": "sha512-GcCH0fySxBurJtvr0dfhz0IxHZjc1RP+F+I8xw+LIwkU1a+7HJx8NCDiww1I5u4Hz6g4eR1JlGADEGJ9r4lSfA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/mpegts.js": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmmirror.com/mpegts.js/-/mpegts.js-1.8.0.tgz",
|
||||
"integrity": "sha512-ZtujqtmTjWgcDDkoOnLvrOKUTO/MKgLHM432zGDI8oPaJ0S+ebPxg1nEpDpLw6I7KmV/GZgUIrfbWi3qqEircg==",
|
||||
"dependencies": {
|
||||
"es6-promise": "^4.2.5",
|
||||
"webworkify-webpack": "github:xqq/webworkify-webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
|
|
@ -7681,6 +7706,11 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/webworkify-webpack": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "git+ssh://git@github.com/xqq/webworkify-webpack.git#24d1e719b4a6cac37a518b2bb10fe124527ef4ef",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
|
|
|||
|
|
@ -22,12 +22,14 @@
|
|||
"dayjs": "^1.11.10",
|
||||
"echarts": "^5.4.3",
|
||||
"element-plus": "^2.6.1",
|
||||
"flv.js": "^1.6.2",
|
||||
"hls.js": "^1.6.13",
|
||||
"html2canvas": "^1.4.1",
|
||||
"jspdf": "^2.5.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mitt": "^3.0.1",
|
||||
"mp4box": "^0.5.2",
|
||||
"mpegts.js": "^1.8.0",
|
||||
"nanoid": "^5.0.4",
|
||||
"normalize.css": "^8.0.1",
|
||||
"pako": "^2.1.0",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<el-dialog v-model="dialogVisible" title="播放后台转码视频" width="50%">
|
||||
<el-dialog v-model="dialogVisible" title="播放大华设备视频" width="50%">
|
||||
<!-- 原生video播放器 - 移除了controls属性以去掉默认控制栏 -->
|
||||
<video ref="videoRef" playsinline class="video-player"></video>
|
||||
|
||||
|
|
@ -11,12 +11,10 @@
|
|||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import Hls from "hls.js"; // 引入HLS解析库
|
||||
import { ref, watch, nextTick } from "vue";
|
||||
import mpegts from "mpegts.js"; // 引入mpegts.js解析库
|
||||
import { ElMessage } from "element-plus";
|
||||
import { getTranscodeStatus, stopTransCode } from "@/request/video_info.js"; // 后端“停止转码”接口
|
||||
|
||||
// 接收父组件传递的属性
|
||||
const props = defineProps({
|
||||
|
|
@ -24,54 +22,35 @@ const props = defineProps({
|
|||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
src: {
|
||||
type: String,
|
||||
required: true, // 必须传递HLS流地址
|
||||
},
|
||||
videoId: {
|
||||
type: String,
|
||||
required: true, // 视频Id
|
||||
channel: {
|
||||
type: Number,
|
||||
default: 0, // 通道号,默认为0
|
||||
},
|
||||
});
|
||||
|
||||
// 向父组件传递事件
|
||||
const emit = defineEmits(["update:visible", "onStop"]);
|
||||
const emit = defineEmits(["update:visible"]);
|
||||
|
||||
// 控制弹窗显示(内部响应props.visible)
|
||||
const dialogVisible = ref(props.visible);
|
||||
const videoRef = ref(null); // video元素引用
|
||||
const isPlaying = ref(false); // 视频播放状态
|
||||
let hlsInstance = null; // HLS实例(用于管理流解析)
|
||||
let player = null; // MPEGTS播放器实例
|
||||
|
||||
// 监听父组件visible变化,同步到内部dialogVisible
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
dialogVisible.value = newVal;
|
||||
}
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
dialogVisible.value = newVal;
|
||||
}
|
||||
);
|
||||
|
||||
// 定义定时器变量
|
||||
let checkInterval = null;
|
||||
|
||||
// 弹窗打开时执行的方法
|
||||
const onDialogOpen = () => {
|
||||
// 每3秒调用一次接口
|
||||
checkInterval = setInterval(async () => {
|
||||
try {
|
||||
// 假设接口名为checkVideoProgress,需自行导入
|
||||
const response = await getTranscodeStatus({ id: props.videoId });
|
||||
if (response.progress > 2) {
|
||||
handlePlay();
|
||||
// 播放后清除定时器
|
||||
if (checkInterval) {
|
||||
clearInterval(checkInterval);
|
||||
checkInterval = null;
|
||||
}
|
||||
}
|
||||
// 可根据需要处理接口返回结果
|
||||
} catch (error) {}
|
||||
}, 3000); // 3秒间隔
|
||||
// 确保DOM更新完成后再初始化播放器
|
||||
nextTick(() => {
|
||||
// 大华设备直接播放
|
||||
handlePlay();
|
||||
});
|
||||
};
|
||||
|
||||
// 监听内部dialogVisible变化,通知父组件
|
||||
|
|
@ -84,127 +63,110 @@ watch(dialogVisible, (newVal) => {
|
|||
}
|
||||
});
|
||||
|
||||
// 播放视频
|
||||
const handlePlay = () => {
|
||||
const video = videoRef.value;
|
||||
if (!video) {
|
||||
ElMessage.error("视频播放器初始化失败");
|
||||
// 初始化MPEGTS播放器
|
||||
const initMpegtsPlayer = () => {
|
||||
// 如果播放器已存在,先销毁
|
||||
if (player) {
|
||||
player.destroy();
|
||||
player = null;
|
||||
}
|
||||
|
||||
// 确保video元素已准备好
|
||||
if (!videoRef.value) {
|
||||
console.error("无法获取video元素");
|
||||
return;
|
||||
}
|
||||
|
||||
// 先清空之前的资源
|
||||
video.src = "";
|
||||
// 使用mpegts.js创建播放器实例
|
||||
if (mpegts.isSupported()) {
|
||||
const videoElement = videoRef.value;
|
||||
|
||||
// 构建WebSocket URL,包含认证信息和通道号
|
||||
const baseUrl = import.meta.env.VITE_DAHUA_WEB_SOCKET_URL || "ws://localhost:8866";
|
||||
const separator = baseUrl.includes('?') ? '&' : '?';
|
||||
const websocketUrl = `${baseUrl}${separator}user=user1&channel=${props.channel}`;
|
||||
|
||||
// 检查src是否有效
|
||||
if (!props.src) {
|
||||
ElMessage.error("视频源地址为空");
|
||||
return;
|
||||
}
|
||||
|
||||
// HLS.js 支持检测
|
||||
if (Hls.isSupported()) {
|
||||
// 如果已有实例,先销毁
|
||||
if (hlsInstance) {
|
||||
hlsInstance.destroy();
|
||||
// 如果播放器已存在,先销毁
|
||||
if (player) {
|
||||
player.destroy();
|
||||
player = null;
|
||||
}
|
||||
|
||||
hlsInstance = new Hls({
|
||||
maxBufferLength: 30, // 增加缓冲长度
|
||||
maxMaxBufferLength: 60,
|
||||
// 创建mpegts.js播放器,让它自己管理WebSocket连接
|
||||
player = mpegts.createPlayer({
|
||||
type: "flv",
|
||||
isLive: true,
|
||||
hasAudio: false,
|
||||
hasVideo: true,
|
||||
url: websocketUrl, // 直接提供WebSocket URL给mpegts.js
|
||||
}, {
|
||||
enableWorker: false,
|
||||
lazyLoad: false,
|
||||
reuseRedirectedURL: false
|
||||
});
|
||||
|
||||
// 监听错误事件
|
||||
hlsInstance.on(Hls.Events.ERROR, (event, data) => {
|
||||
if (data.fatal) {
|
||||
switch (data.type) {
|
||||
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||
hlsInstance.startLoad();
|
||||
break;
|
||||
case Hls.ErrorTypes.MEDIA_ERROR:
|
||||
hlsInstance.recoverMediaError();
|
||||
break;
|
||||
default:
|
||||
// 无法恢复的错误,需要重新初始化
|
||||
destroyPlayer();
|
||||
handlePlay();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 将播放器附加到video元素
|
||||
player.attachMediaElement(videoElement);
|
||||
|
||||
// 监听播放器事件
|
||||
player.on(mpegts.Events.MEDIA_INFO, (mediaInfo) => {
|
||||
console.log('媒体信息:', mediaInfo);
|
||||
});
|
||||
|
||||
hlsInstance.loadSource(props.src);
|
||||
hlsInstance.attachMedia(video);
|
||||
|
||||
hlsInstance.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||
video.play().then(() => {
|
||||
isPlaying.value = true;
|
||||
});
|
||||
player.on(mpegts.Events.ERROR, (type, details) => {
|
||||
console.error('播放器错误:', type, details);
|
||||
ElMessage.error(`播放器错误: ${type}`);
|
||||
});
|
||||
} else if (video.canPlayType("application/vnd.apple.mpegurl")) {
|
||||
// Safari等原生支持HLS的浏览器
|
||||
video.src = props.src;
|
||||
video.addEventListener("loadedmetadata", () => {
|
||||
video
|
||||
.play()
|
||||
.then(() => {
|
||||
isPlaying.value = true;
|
||||
ElMessage.success("视频开始播放");
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(`播放失败:${err.message}`);
|
||||
});
|
||||
|
||||
// 加载并播放
|
||||
player.load();
|
||||
player.play().catch((e) => {
|
||||
console.error("播放失败:", e);
|
||||
ElMessage.error("播放失败: " + e.message);
|
||||
});
|
||||
} else {
|
||||
ElMessage.error("您的浏览器不支持HLS视频流播放,请更换浏览器");
|
||||
ElMessage.error("浏览器不支持mpegts.js");
|
||||
}
|
||||
};
|
||||
|
||||
// 销毁播放器时清除定时器
|
||||
const destroyPlayer = () => {
|
||||
// 清除定时器
|
||||
if (checkInterval) {
|
||||
clearInterval(checkInterval);
|
||||
checkInterval = null;
|
||||
// 播放视频
|
||||
const handlePlay = () => {
|
||||
// 先清空之前的资源
|
||||
if (videoRef.value) {
|
||||
videoRef.value.src = "";
|
||||
}
|
||||
|
||||
// 原有逻辑保持不变
|
||||
isPlaying.value = false;
|
||||
if (hlsInstance) {
|
||||
hlsInstance.destroy();
|
||||
hlsInstance = null;
|
||||
// 大华设备播放
|
||||
playDahuaVideo();
|
||||
};
|
||||
|
||||
// 播放大华设备视频
|
||||
const playDahuaVideo = () => {
|
||||
if (!mpegts.isSupported()) {
|
||||
ElMessage.error("您的浏览器不支持MPEG-TS视频播放");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 初始化并播放
|
||||
initMpegtsPlayer();
|
||||
} catch (error) {
|
||||
ElMessage.error("播放器初始化失败:" + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
// 销毁播放器时清除资源
|
||||
const destroyPlayer = () => {
|
||||
// 销毁MPEGTS播放器,它会自动处理WebSocket连接的关闭
|
||||
if (player) {
|
||||
player.destroy();
|
||||
player = null;
|
||||
}
|
||||
|
||||
if (videoRef.value) {
|
||||
const video = videoRef.value;
|
||||
video.pause();
|
||||
video.src = "";
|
||||
}
|
||||
handleStopTranscode();
|
||||
};
|
||||
|
||||
// 停止转码(调用后端接口)
|
||||
const handleStopTranscode = async () => {
|
||||
try {
|
||||
await stopTransCode({ id: props.videoId }); // 调用后端“停止转码”接口
|
||||
emit("onStop"); // 通知父组件“转码已停止”
|
||||
dialogVisible.value = false; // 关闭弹窗
|
||||
} catch (error) {
|
||||
if (error !== "cancel") {
|
||||
ElMessage.error(`停止转码失败:${error.message || "未知错误"}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.video-player {
|
||||
width: 100%;
|
||||
min-height: 600px;
|
||||
object-fit: contain; /* 保持视频比例 */
|
||||
background-color: #000; /* 增加黑色背景,使视频区域更明显 */
|
||||
}
|
||||
|
||||
.video-controls {
|
||||
margin-top: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</script>
|
||||
|
|
@ -18,9 +18,6 @@
|
|||
<el-button native-type="reset" @click="fnResetPagination"
|
||||
>重置</el-button
|
||||
>
|
||||
<el-button type="success" @click="handleStartTranscode"
|
||||
>播放后台转码视频</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
|
@ -106,12 +103,11 @@
|
|||
@get-data="fnResetPagination"
|
||||
/>
|
||||
|
||||
<!-- 转码视频播放器(修改后:双向绑定visible + 传递src) -->
|
||||
<!-- 大华设备视频播放器 -->
|
||||
<play-video
|
||||
v-model:visible="data.transcodeVideoDialog.visible"
|
||||
:src="data.transcodeVideoDialog.src"
|
||||
:video-id="data.transcodeVideoDialog.id"
|
||||
@on-stop="onTranscodeStopped"
|
||||
v-model:visible="data.dahuaVideoDialog.visible"
|
||||
:channel="data.dahuaVideoDialog.channel"
|
||||
@update:visible="handlePlayVideoClose"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -130,8 +126,7 @@ import {ElMessage, ElMessageBox} from "element-plus";
|
|||
import SelectingPoints from "./components/selecting_points.vue";
|
||||
import LayoutVideo from "@/components/video/index.vue";
|
||||
import {setVideoManagerList} from "@/request/eightwork_videomanager.js";
|
||||
import PlayVideo from "@/views/video_manager/video_manager/components/playVideo.vue"; // 引入新播放器组件
|
||||
import {startTransCode, stopTransCode} from "@/request/video_info.js"; // 转码接口
|
||||
import PlayVideo from "@/views/video_manager/video_manager/components/playVideo.vue"; // 引入大华播放器组件
|
||||
|
||||
const data = reactive({
|
||||
addDialog: {
|
||||
|
|
@ -155,42 +150,18 @@ const data = reactive({
|
|||
videomanagerId: "",
|
||||
visible: false,
|
||||
},
|
||||
transcodeVideoDialog: {
|
||||
dahuaVideoDialog: {
|
||||
visible: false,
|
||||
src: "http://localhost:8100/api/hls/stream.m3u8", // 后端转码后HLS流的访问路径
|
||||
id: "",
|
||||
channel: 0 // 通道号
|
||||
},
|
||||
});
|
||||
|
||||
// 启动转码并显示播放器
|
||||
const handleStartTranscode = async () => {
|
||||
try {
|
||||
await startTransCode(); // 调用后端“启动转码”接口
|
||||
data.transcodeVideoDialog.visible = true; // 显示播放器弹窗
|
||||
} catch (error) {
|
||||
ElMessage.error("启动转码失败: " + (error.message || "未知错误"));
|
||||
}
|
||||
};
|
||||
|
||||
// 转码停止后的回调
|
||||
const onTranscodeStopped = async () => {
|
||||
await stopTransCode(); // 调用后端“停止转码”接口
|
||||
};
|
||||
|
||||
// 列表数据逻辑(保持不变)
|
||||
// 列表数据逻辑
|
||||
const {list, pagination, searchForm, fnGetData, fnResetPagination} =
|
||||
useListData(getHkVideoManagerList);
|
||||
|
||||
// 其他方法(保持不变)
|
||||
// const fnSetPositioning = async (row) => {
|
||||
// data.selectingPointsDialog.id = row.PLS_ID ? row.PLS_ID : "";
|
||||
// data.selectingPointsDialog.indexCode = row.indexCode;
|
||||
// data.selectingPointsDialog.regionPathName = row.regionPathName;
|
||||
// data.selectingPointsDialog.camName = row.name;
|
||||
// data.selectingPointsDialog.videomanagerId = row.videomanagerId;
|
||||
// data.selectingPointsDialog.visible = true;
|
||||
// };
|
||||
|
||||
// 其他方法
|
||||
const fnUpToBi = async (videomanagerId) => {
|
||||
await ElMessageBox.confirm("确定要置顶吗?置顶后将会默认展示在Bi页", {
|
||||
type: "warning",
|
||||
|
|
@ -200,14 +171,16 @@ const fnUpToBi = async (videomanagerId) => {
|
|||
};
|
||||
|
||||
const fnPreviewVideo = async (row) => {
|
||||
try {
|
||||
const resData = await startTransCode({url: row.url, id: row.PLS_ID}); // 调用后端“启动转码”接口
|
||||
data.transcodeVideoDialog.visible = true; // 显示播放器弹窗
|
||||
data.transcodeVideoDialog.id = row.PLS_ID; // 显示播放器弹窗
|
||||
data.transcodeVideoDialog.src =
|
||||
"http://172.16.70.226:7811/" + resData.videoUrl + "stream.m3u8";
|
||||
} catch (error) {
|
||||
ElMessage.error("启动转码失败: " + (error.message || "未知错误"));
|
||||
// 直接播放大华设备视频
|
||||
data.dahuaVideoDialog.visible = true;
|
||||
data.dahuaVideoDialog.channel = row.channel;
|
||||
console.log("播放大华设备视频:", row.channel);
|
||||
};
|
||||
|
||||
const handlePlayVideoClose = (visible) => {
|
||||
if (!visible) {
|
||||
// 视频播放窗口关闭时的处理逻辑
|
||||
console.log("视频播放窗口已关闭");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue