海康开发平台
官网地址:
插件下载地址:https://open.hikvision.com/download/5c67f1e2f05948198c909700?type=20
视频教程地址:https://open.hikvision.com/videoSupport?direction=%E7%BB%BC%E5%90%88%E5%AE%89%E9%98%B2%E7%AE%A1%E7%90%86%E5%B9%B3%E5%8F%B0&tagName=%E8%A7%86%E9%A2%91%E6%92%AD%E6%94%BE%E5%8F%8A%E6%8E%A7%E5%88%B6
实现步骤:
插件安装
代码实现
引入资源包
公共组件
页面掉用
*注意当前页面:uid唯一
<template>
<div class="main" ref="playWndBox">
<div :id="props.uid" class="playWnd">
{{ mesgText }}
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, getCurrentInstance} from 'vue'
const props = defineProps({
uid: {
type: String,
default: 'playWnd'
},
initOption: {
type: Object,
default: () => {
return{
appkey: "****", //海康提供的appkey
ip: "*****", //海康提供的ip
secret: "*****",//海康提供的secret
port: ***, //端口号默认443
playMode: 0, // 0 预览 1回放
layout: "1x1", //页面展示的模块数【16】
}
}
},
playWndHeight: {
type: Number,
default: 200
},
playWndWidth: {
type: Number,
default: 400
}
})
const playWndBox = ref(null)
let playWndHeight = ref(200)
let playWndWidth = ref(400)
let pubKey = ref('')
let oWebControl = ref(null);
const mesgText = ref('加载中...')
let tagDomObj;
const getWH = () => {
// 获取页面的实例对象
let pageInstance = getCurrentInstance();
// 获取dom节点对象
tagDomObj = playWndBox.value;
playWndHeight.value = tagDomObj.clientHeight;
playWndWidth.value = tagDomObj.clientWidth;
console.log("盒子宽高",props.uid,playWndWidth.value,playWndHeight.value,tagDomObj);
}
onMounted(() => {
})
onBeforeUnmount(() => {
if (oWebControl.value) {
// 先让窗口隐藏,规避可能的插件窗口滞后于浏览器消失问题
oWebControl.value?.JS_HideWnd();
// 销毁当前播放的视频
oWebControl.value?.JS_RequestInterface({ funcName: "destroyWnd" });
// 断开与插件服务连接
oWebControl.value?.JS_Disconnect();
console.log("销毁播放器");
}
})
// ***注意*** 一个容器uid只能注册一次
const initPlugin = () => {
getWH();
oWebControl.value = new WebControl({
szPluginContainer: props.uid, // 指定容器id
iServicePortStart: 15900, // 指定起止端口号,建议使用该值
iServicePortEnd: 15900,
szClassId: "23BF3B0A-2C56-4D97-9C03-0CB103AA8F11", // 用于IE10使用ActiveX的clsid
cbConnectSuccess: () => {
// 创建WebControl实例成功
oWebControl.value
.JS_StartService("window", {
// WebControl实例创建成功后需要启动服务
// 值"./VideoPluginConnect.dll"写死
dllPath: "./VideoPluginConnect.dll",
})
.then(
function () {
// 设置消息回调
oWebControl.value.JS_SetWindowControlCallback({
// cbIntegrationCallBack: cbIntegrationCallBack,
});
//JS_CreateWnd创建视频播放窗口,宽高可设定
oWebControl.value
.JS_CreateWnd(props.uid,0,0,{ bEmbed: true })//这一部分很重要,两个参数为你盒子的宽高,这样是写死是防止组件加载之前出现白屏;bEmbed: true 防止窗口闪烁
.then(function () {
// 创建播放实例成功后初始化
console.log("HKvidoe 创建实例成功---");
init();
});
},
function () {
// 启动插件服务失败
}
);
},
// 创建WebControl实例失败
cbConnectError: function () {
// 这里写创建WebControl实例失败时的处理步骤,下面的代码仅做参看,具体实现步骤根据个人需求进行编写!!!!!!!!
mesgText.value = "插件启动失败,请检查插件是否安装!";
// console.log(0);
// oWebControl.value.value = null;
// // 程序未启动时执行error函数,采用wakeup来启动程序
// window.WebControl.JS_WakeUp("VideoWebPlugin://");
// initCount++;
// if (initCount < 3) {
// setTimeout(function () {
// initPlugin();
// }, 3000);
// } else {
// setTimeout(function () {
// setTimeout(function () {
// $router.push('/home/PlugDown')
// }, 4000)
// }, 4000)
// }
},
cbConnectClose: () => {
mesgText.value = "连接已断开!";
// 异常断开:bNormalClose = false
// JS_Disconnect正常断开:bNormalClose = true
// console.log("cbConnectClose");
oWebControl.value = null;
},
});
// oWebControl.value.JS_CuttingPartWindow(500, 500, 500, 500);
}
const emit = defineEmits(['createSuccess'])
// 初始化
const init = (callback) => {
getPubKey(() => {
let appkey = props.initOption.appkey; //综合安防管理平台提供的appkey,必填
let secret = setEncrypt(props.initOption.secret); //综合安防管理平台提供的secret,必填
let ip = props.initOption.ip; //综合安防管理平台IP地址,必填
let playMode = props.initOption.playMode; //初始播放模式:0-预览,1-回放
let port = props.initOption.port; //综合安防管理平台端口,若启用HTTPS协议,默认443
let snapDir = "D:\\SnapDir"; //抓图存储路径
let videoDir = "D:\\VideoDir"; //紧急录像或录像剪辑存储路径
let layout = props.initOption.layout; //playMode指定模式的布局
let enableHTTPS = 1; //是否启用HTTPS协议与综合安防管理平台交互,这里总是填1
let encryptedFields = "secret"; //加密字段,默认加密领域为secret
let showToolbar = 0; //是否显示工具栏,0-不显示,非0-显示
let showSmart = 0; //是否显示移动框线框,0-不显示,非0-显示
let buttonIDs =
"0,16,256,257,258,259,260,512,513,514,515,516,517,768,769"; //自定义工具条按钮
// var toolBarButtonIDs = "2049,2304" // 工具栏上自定义按钮
oWebControl.value
.JS_RequestInterface({
funcName: "init",
argument: JSON.stringify({
appkey: appkey, //API网关提供的appkey
secret: secret, //API网关提供的secret
ip: ip, //API网关IP地址
playMode: playMode, //播放模式(决定显示预览还是回放界面)
port: port, //端口
snapDir: snapDir, //抓图存储路径
videoDir: videoDir, //紧急录像或录像剪辑存储路径
layout: layout, //布局
enableHTTPS: enableHTTPS, //是否启用HTTPS协议
encryptedFields: encryptedFields, //加密字段
showToolbar: showToolbar, //是否显示工具栏
showSmart: showSmart, //是否显示智能信息
buttonIDs, //自定义工具条按钮
}),
})
.then(function (oData) {
oWebControl.value.JS_HideWnd();
if(oData?.responseMsg?.msg == "success"){
console.log(oData,"HKvidoe 初始化成功---");
emit("createSuccess")
}
oWebControl.value.JS_Resize(playWndWidth.value, playWndHeight.value); // 初始化后resize一次,规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
if (callback) {
callback();
}
});
});
}
// RSA 加密
let setEncrypt = (value) => {
let encrypt = new window.JSEncrypt();
encrypt.setPublicKey(pubKey);
return encrypt.encrypt(value);
}
// 获取公钥
const getPubKey = (callback) => {
oWebControl.value
.JS_RequestInterface({
funcName: "getRSAPubKey",
argument: JSON.stringify({
keyLength: 1024,
}),
})
.then(function (oData) {
if (oData.responseMsg.data) {
pubKey = oData.responseMsg.data;
callback();
}
});
}
// 调用这个函数可进行视频播放
// 视频预览功能
const previewVideo = (data='342fcd690e1441a9bef72b97ff7f8032') => {
getWH()
let cameraIndexCode = data; // 获取输入的监控点编号值,必填
let streamMode = 0; // 主子码流标识:0-主码流,1-子码流
let transMode = 1; // 传输协议:0-UDP,1-TCP
let gpuMode = 0; // 是否启用GPU硬解,0-不启用,1-启用
let wndId = -1; // 播放窗口序号(在2x2以上布局下可指定播放窗口)
cameraIndexCode = cameraIndexCode.replace(/(^\s*)/g, "");
cameraIndexCode = cameraIndexCode.replace(/(\s*$)/g, "");
oWebControl.value.JS_RequestInterface({
funcName: "startPreview",
argument: JSON.stringify({
cameraIndexCode: cameraIndexCode, // 监控点编号
streamMode: streamMode, // 主子码流标识
transMode: transMode, // 传输协议
gpuMode: gpuMode, // 是否开启GPU硬解
wndId: wndId, // 可指定播放窗口
}),
})
.then(function (data) {
console.log("预览的回调",data);
oWebControl.value.JS_SetWindowControlCallback({
});
});
}
// 视频回放功能
const previewBackVideo = (data='342fcd690e1441a9bef72b97ff7f8032',dateTime=[]) => {
let cameraIndexCode = data; // 获取输入的监控点编号值,必填
var startTimeStamp = new Date(dateTime[0].replace('-', '/').replace('-', '/')).getTime(); //回放开始时间戳,必填
var endTimeStamp = new Date(dateTime[1].replace('-', '/').replace('-', '/')).getTime(); //回放结束时间戳,必填
var recordLocation = 0; //录像存储位置:0-中心存储,1-设备存储
var transMode = 1; //传输协议:0-UDP,1-TCP
var gpuMode = 0; //是否启用GPU硬解,0-不启用,1-启用
var wndId = -1; //播放窗口序号(在2x2以上布局下可指定播放窗口)
oWebControl.value.JS_RequestInterface({
funcName: "startPlayback",
argument: JSON.stringify({
cameraIndexCode: cameraIndexCode, //监控点编号
startTimeStamp: Math.floor(startTimeStamp / 1000).toString(), //录像查询开始时间戳,单位:秒
endTimeStamp: Math.floor(endTimeStamp / 1000).toString(), //录像结束开始时间戳,单位:秒
recordLocation: recordLocation, //录像存储类型:0-中心存储,1-设备存储
transMode: transMode, //传输协议:0-UDP,1-TCP
gpuMode: gpuMode, //是否启用GPU硬解,0-不启用,1-启用
wndId:wndId //可指定播放窗口
})
})
.then(function (data) {
console.log("预览的回调",data);
oWebControl.value.JS_SetWindowControlCallback({
});
});
}
// 窗口刷新问题
const resetWindow = () => {
oWebControl.value.JS_Resize(playWndWidth.value, playWndHeight.value);
oWebControl.value.JS_HideWnd();
oWebControl.value.JS_ShowWnd();
}
// 隐藏窗口
const hideWindow = () => {
oWebControl.value.JS_HideWnd();
}
// 显示窗口
const showWindow = () => {
oWebControl.value.JS_ShowWnd();
}
defineExpose({previewVideo,resetWindow,hideWindow,showWindow,initPlugin,previewBackVideo});
</script>
<style lang="less" scoped>
.main {
position: relative;
height: 100%;
width: 100%;
background: transparent;
border: 1px solid #C0C0C0;
.playWnd{
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
height: 100%;
width: 100%;
}
}
</style>
最终效果
大华开发平台ICC
官网地址:
插件下载地址:https://open-icc.dahuatech.com/#/home
实现步骤
插件安装
代码实现
引入资源
公共组件
页面调用
代码实现
<template>
<div :id="props.uid" class="v_box"></div>
</template>
<script setup>
import {onMounted,nextTick,onBeforeUnmount} from "vue"
let videoPlayer;
const props = defineProps({
// 唯一标识
uid:{
type:String,
default:"video-play-box"
},
// 初始化参数
initOption:{
type:Object,
default:()=>{
return{
host: "***", // icc 平台ip
port: "***", // icc 平台端口 https 默认 443
username: "***", // icc 平台用户名
password: "****", // icc 平台密码
}
}
},
// 隐藏的Class
shieldClass:{
type:Array,
default:()=>{
return[]
}
},
uid:{
type:String,
default:"video-play-box"
},
// 0-实时预览 3-录像回放 7-录像回放(支持倒放)
windowType:{
type:String,
default:"0"
}
})
const emit = defineEmits(['createSuccess'])
// 初始化登录
const doInitVideo = () => {
videoPlayer = new VideoPlayer({
videoId: props.uid, // 唯一标识,必填,不能重复
windowType: props.windowType, // 播放器类型,必传, 0 - 实时预览,3 - 录像回放,7- 录像回放(支持倒放)
usePluginLogin: true, // 采用登录 (请默认传true,插件内部自动拉流)
pluginLoginInfo: props.initOption,
division: 1, // 默认展示的窗口数量, 必传
draggable: false, // 窗口拖拽 【暂不支持】
showBar: false, // 底部操作栏, 选传,【true - 显示, false - 隐藏】
shieldClass:props.shieldClass, // 如果DOM元素被插件挡住了,把DOM元素的类名传入。
coverShieldClass: [], // 如果插件要在dom内滚动,需要把DOM元素的类名传入,请查看案例-遮挡
parentIframeShieldClass: [], // 有 iframe 时,top层 的 dom 元素被插件挡住了,把DOM元素的类名传入。
// 下面均为回调函数,请按需使用,具体可在 API 内进行功能的体验和查看。
// 创建播放器成功回调
createSuccess: (versionInfo) => {
// 该回调触发后,我们可以进行实时预览/录像回放等操作
emit("createSuccess",versionInfo)
console.log("创建成功11!!阿萨!");
return
type == 0 ? doPlay(channelId) : startPlayback(channelId);
//[]: 隐藏顶部按钮 不传显示所有 回放不支持此功能
videoPlayer.setTabControlBtn([]);
},
// 创建播放器失败回调
createError: (err) => {
// 有错误码,可打印查看错误信息
console.log("创建失败 !!!", JSON.stringify(err));
},
// 插件公共回调
dhPlayerMessage: (info, err) => { },
// 实时预览成功回调
realSuccess: (info) => { },
// 实时预览失败回调
realError: (info, err) => { },
// 对讲成功回调
talkSuccess: (info) => { },
// 对讲失败回调
talkError: (info, err) => { },
// 录像播放成功回调
playbackSuccess: (info) => { },
// 录像播放失败回调
playbackError: (info, err) => { },
// 录像播放完成回调
playbackFinish: (info) => { },
// 抓图成功回调
snapshotSuccess: ({ base64Url, path }, info) => {
var byteCharacters = atob(
base64Url.replace(/^data:image\/(png|jpeg|jpg);base64,/, "")
);
var byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
var blob = new Blob([byteArray], {
type: undefined,
});
var aLink = document.createElement("a");
aLink.download = "图片名称.jpg"; //这里写保存时的图片名称
aLink.href = URL.createObjectURL(blob);
aLink.click();
},
// 本地录像下载成功回调
videoDownloadSuccess: (path, info) => {
alert("本地录像地址:" + path);
},
// 关闭视频窗口回调
closeWindowSuccess: ({ isAll, snum, channelList }) => { },
// 鼠标单击窗口回调
clickWindow: (snum) => { },
// 鼠标双击窗口回调
dbClickWindow: (snum) => { },
// 播放器窗口的数量回调
changeDivision: (division) => { },
// rtsp 流下载录像成功回调
downloadRecordSuccess: (info) => { },
// rtsp 流下载录像失败回调
downloadRecordError: (info, err) => { },
});
console.log("大华实时摄像头",videoPlayer);
};
// 实时播放
const doPlay = (id = "*****") => {
videoPlayer.startReal([
{
channelId: id, // 通道id 【必传】
channelName: "通道名称", // 通道名称 (用于本地录像下载)
snum: 0, // 即将要播放的窗口序号,从0开始 【必传】
streamType: 1, // 1-主码流 2-辅码流 (可不传,默认主码流)
deviceType: 5, // 设备类别 (用于对讲使用)
cameraType: "1", // 摄像头类型 (用于云台)
capability: "00000000000000000000000000000001", // 能力集 (用于云台)
},
]);
};
// 回放预览
const startPlayback = (id ="*****") => {
let startTime = props.dateValue[0];
let endTime = props.dateValue[1];
videoPlayer.startPlayback([
{
channelId: id, // 通道id
channelName: "通道名称", // 通道名称 (用于本地录像下载和错误提示)
startTime: startTime, // 开始时间
endTime: endTime, // 结束时间
recordSource: 2, // 2-录像 3-中心
streamType: 0, // 0-所有码流 1-主码流 2-辅码流
snum: 0, // 播放的窗口序号 (从0开始计数,表示第一个窗口)
},
]);
};
// 全屏
const setFullScreen = ()=>{
videoPlayer.setFullScreen()
}
// 销毁
const doDestroy = () => {
videoPlayer?.destroy().then((res) => {
console.log("销毁成功");
});
}
onMounted(() => {
// doInitVideo()
})
onBeforeUnmount(() =>{
doDestroy()
})
defineExpose({startPlayback,doPlay,setFullScreen,doInitVideo,doDestroy});
</script>
<style scoped lang="less">
.v_box{
height: 100%;
width: 100%;
}
</style>
最终效果
问题:海康、大华、华为的实时视频,在同一个项目里面,用到【海康的web插件、大华的web插件、HLS推流】,有什么比较好的方案,一套代码解决?