海康摄像头开发小记

4,318 阅读2分钟

最开始参考了这个大佬的代码后来根据根据自己的业务需求做了修改, 导入官方下载的三个文件

image.png

踩坑记录:

  • 1.一开始以为多个摄像头视频就生成多个插件,这是一个误区,应该在初始化插件时用iWndowType控制数量。
  • 2.销毁时,如果生成了多个插件销毁就会出现问题,只能销毁最后一个,这也是为什么要用iWndowType控制数量的原因,数量是

image.png

  • 3.初始化成功后就可以用循环登录,将要显示的设备全部循环登录好,然后用鼠标点击视频窗口,再执行预览,这样就可以了。

相关代码

这里是我的项目代码,其中video_num用的是若依的字典,也就是上面图片的数据。

<template>
    <div class="app-container">
        <el-row :gutter="20">
            <el-col :span="3" :xs="24" v-loading="loading">
                <div class="head-container">
                    <el-input
                        v-model="monitorName"
                        placeholder="请输入监控名称"
                        clearable
                        prefix-icon="Search"
                        style="margin-bottom: 20px"
                    />
                </div>
                <div class="head-container">
                    <el-tree
                        :data="playBackList"
                        :props="{ label: 'monitorName', children: 'children' }"
                        :expand-on-click-node="false"
                        :filter-node-method="filterNode"
                        ref="deptTreeRef"
                        node-key="id"
                        highlight-current
                        default-expand-all
                        @node-click="handleNodeClick"
                    />
                </div>
            </el-col>
            <el-col :span="21" :xs="24">
                <div class="head-container">
                    <el-button type="primary" plain @click="OnVideo" :disabled="IsVideo">
                        开始预览
                    </el-button>
                    <el-form-item label="选择监控数量" style="margin-left: 20px">
                        <el-select
                            v-model="VideoNum"
                            :disabled="IsVideo"
                            filterable
                            placeholder="选择监控数量"
                        >
                            <el-option
                                v-for="item in video_num"
                                :key="item.value"
                                :label="item.label"
                                :value="Number(item.value)"
                            />
                        </el-select>
                    </el-form-item>
                    <el-form-item label="已选监控名称" style="margin-left: 20px">
                        <el-tag
                            class="text"
                            v-for="item in playlist"
                            :key="item.monitorId"
                            @close="handleClose(item)"
                            :disable-transitions="false"
                            closable
                            type="primary"
                        >
                            {{ item.monitorName }}
                        </el-tag>
                    </el-form-item>
                </div>
                <div class="container" v-if="IsVideo">
                    <Video :data="playlist" :VideoNum="VideoNum" v-model="IsVideo" />
                </div>
            </el-col>
        </el-row>
    </div>
</template>
<script setup>
import { getMonitorList } from '@/api/supervisory/index.js';
import { reactive, onBeforeUnmount, watch } from 'vue';
import Video from '@/views/supervisory/components/index.vue';
const { proxy } = getCurrentInstance();
const loading = ref(true);
const playBackList = ref([]);
const monitorName = ref('');
const playlist = ref([]);
const queryParams = reactive({
    pageNum: 1,
    pageSize: 10,
});
const { video_num } = proxy.useDict('video_num');
const VideoNum = ref(1);
const IsVideo = ref(false);
const getList = () => {
    loading.value = true;
    getMonitorList(queryParams.value).then(response => {
        playBackList.value = response.rows;
        loading.value = false;
    });
};

/** 通过条件过滤节点  */
const filterNode = (value, data) => {
    if (!value) return true;
    return data.label.indexOf(value) !== -1;
};

/** 节点单击事件 */
const handleNodeClick = data => {
    if (IsVideo.value) return proxy.$modal.msgError('请先关闭监控');
    // 判断是否已存在
    const isExist = playlist.value.some(item => item.monitorId === data.monitorId);
    if (!isExist) {
        if (Number(VideoNum.value) * Number(VideoNum.value) > playlist.value.length) {
            playlist.value.push(data);
        } else {
            proxy.$modal.msgError('数量过多');
        }
    }
};

const handleClose = async item => {
    if (IsVideo.value) return proxy.$modal.msgError('请先关闭监控');
    await playlist.value.splice(playlist.value.indexOf(item), 1);
};
const OnVideo = () => {
    if (playlist.value < 1) return proxy.$modal.msgError('请选择监控');
    IsVideo.value = true;
};
getList();
// 销毁插件
const destroyPlugin = async item => {
    console.log('销毁', item.monitorIp);
    WebVideoCtrl.I_Logout(`${item.monitorIp}_${item.monitorPort}`).then(
        () => {
            console.log('退出成功');
            WebVideoCtrl.I_DestroyPlugin();
        },
        () => {
            console.log('退出失败!');
        }
    );
};

onBeforeUnmount(() => {
    console.log('销毁');
    WebVideoCtrl.I_StopAllPlay().then(() => {
        for (let i = 0; i < playBackList.value.length; i++) {
            destroyPlugin(playBackList.value[i]);
        }
    });
});
</script>
<style lang="scss">
.head-container {
    display: flex;
    .text {
        margin-right: 20px;
    }
}
.container {
    display: flex;
    flex-wrap: wrap;
    color: #fff;
    text-align: center;
}
</style>

``

<template>
    <div v-loading="loading">
        <div id="boxId" style="width: 1200px; height: 600px"></div>
        <div style="margin-top: 10px">
            <el-button
                type="primary"
                @click="startRealPlay"
                :disabled="!data[g_iWndIndex]?.monitorIp"
            >
                预览{{ data[g_iWndIndex]?.monitorName }}
            </el-button>
            <el-button
                type="primary"
                @click="capturePicData"
                :disabled="!data[g_iWndIndex]?.monitorIp"
            >
                抓图{{ data[g_iWndIndex]?.monitorName }}
            </el-button>
            <el-button type="warning" @click="destroyPlugin">关闭监控</el-button>
        </div>
    </div>
</template>
<script setup>
import { saveMonitorImage, uploadImg } from '@/api/supervisory/index.js';

import { ElButton } from 'element-plus';
const props = defineProps({
    data: {
        type: Object,
        default: true,
    },
    VideoNum: {
        type: Number,
        default: 1,
    },
});
import { ElMessage } from 'element-plus';
const emit = defineEmits();
const loading = ref(true);
var g_iWndIndex = ref(0);
const WebVideoCtrl = window.WebVideoCtrl;
// 初始化插件参数及插入插件
const init = () => {
    WebVideoCtrl.I_InitPlugin({
        bWndFull: true, //是否支持单窗口双击全屏,默认支持 true:支持 false:不支持
        iWndowType: Number(props.VideoNum),
        cbSelWnd: function (xmlDoc) {
            g_iWndIndex.value = parseInt($(xmlDoc).find('SelectWnd').eq(0).text(), 10);
            console.log('窗口', g_iWndIndex.value);
        },
        cbDoubleClickWnd: function () {},
        cbEvent: (iEventType, iParam1) => {
            if (2 == iEventType) {
                // 回放正常结束
                console.log('窗口' + iParam1 + '回放结束!');
            } else if (-1 == iEventType) {
                console.log('设备' + iParam1 + '网络错误!');
            }
        },

        cbInitPluginComplete: function () {
            WebVideoCtrl.I_InsertOBJECTPlugin('boxId').then(
                () => {
                    // 检查插件是否最新
                    WebVideoCtrl.I_CheckPluginVersion().then(bFlag => {
                        if (bFlag) {
                            alert('检测到新的插件版本,双击开发包目录里的HCWebSDKPlugin.exe升级!');
                        } else {
                            console.log('初始化成功');
                            for (let i = 0; i < props.data.length; i++) {
                                login(props.data[i], i + 1);
                            }
                            //判断for循环结束
                            setTimeout(() => {
                                loading.value = false;
                            }, props.data.length * 2000);
                        }
                    });
                },
                () => {
                    alert(
                        '插件初始化失败,请确认是否已安装插件;如果未安装,请双击开发包目录里的HCWebSDKPlugin.exe安装!'
                    );
                }
            );
        },
    });
};
// 抓图
const capturePicData = type => {
    var oWndInfo = WebVideoCtrl.I_GetWindowStatus(g_iWndIndex.value);
    if (oWndInfo != null) {
        WebVideoCtrl.I_CapturePicData().then(
            res => {
                // 创建一个FormData对象,并将Blob对象添加到其中
                const formData = new FormData();
                formData.append('file', base64ToBlob('data:image/jpeg;base64,' + res, 'image/png'));
                uploadImg(formData).then(res => {
                    console.log(res.fileName);
                    saveMonitorImage({
                        monitorId: props.data[g_iWndIndex.value].monitorId,
                        imgPath: res.fileName,
                    }).then(r => {
                        ElMessage.success('抓图成功');
                    });
                });
            },
            function () {}
        );
    }
};

// 将base64字符串转换为Blob对象
function base64ToBlob(base64) {
    const byteCharacters = atob(base64.split(',')[1]);
    const byteArrays = [];

    for (let offset = 0; offset < byteCharacters.length; offset += 512) {
        const slice = byteCharacters.slice(offset, offset + 512);
        const byteNumbers = new Array(slice.length);
        for (let i = 0; i < slice.length; i++) {
            byteNumbers[i] = slice.charCodeAt(i);
        }
        const byteArray = new Uint8Array(byteNumbers);
        byteArrays.push(byteArray);
    }
    return new Blob(byteArrays, { type: 'image/jpeg' });
}
// 销毁插件
const destroyPlugin = () => {
    for (let i = 0; i < props.data.length; i++) {
        WebVideoCtrl.I_Logout(`${props.data[i].monitorIp}_${props.data[i].monitorPort}`).then(
            () => {
                console.log('退出成功');
                WebVideoCtrl.I_DestroyPlugin();
                emit('update:modelValue', false);
            },
            () => {
                console.log('退出失败!');
            }
        );
    }
};

//  登录
const login = (item, index) => {
    console.log('登录', item);
    WebVideoCtrl.I_Login(
        item.monitorIp,
        1,
        item.monitorPort,
        item.monitorAccount,
        item.monitorPassword,
        {
            timeout: 3000,
            success: function (xmlDoc) {
                getDevicePort(item, index); //获取端口
            },
            error: function (error) {
                console.log(error);
            },
        }
    );
};

// 获取端口
const getDevicePort = (item, index) => {
    if (!item) {
        return;
    }
    WebVideoCtrl.I_GetDevicePort(item.monitorIp, item.monitorPort).then(
        oPort => {
            console.log('登录成功', item.monitorIp);
        },
        oError => {
            ElMessage.error(oError.errorMsg);
        }
    );
};
// 开始预览
const startRealPlay = () => {
    var oWndInfo = WebVideoCtrl.I_GetWindowStatus(g_iWndIndex.value);
    var startRealPlay = function () {
        WebVideoCtrl.I_StartRealPlay(
            `${props.data[g_iWndIndex.value].monitorIp}_${
                props.data[g_iWndIndex.value].monitorPort
            }`,
            {
                iStreamType: 1,
                iChannelID: 1, //播放通道
                bZeroChannel: false,
                success: function () {
                    console.log(' 开始预览成功!');
                },
                error: function (oError) {
                    console.log(' 开始预览失败!', oError.errorMsg);
                },
            }
        );
    };

    if (oWndInfo != null) {
        // 已经在播放了,先停止
        WebVideoCtrl.I_Stop({
            success: () => {
                startRealPlay();
            },
        });
    } else {
        startRealPlay();
    }
};
init();
</script>

目前功能已经满足基本需求,希望对你有帮助