From 4d71b4d96904612169c07ab6d4805c9daa3f55cf Mon Sep 17 00:00:00 2001
From: Rain_ <904416525@qq.com>
Date: Thu, 24 Jul 2025 15:17:51 +0800
Subject: [PATCH] =?UTF-8?q?flx:=E6=8F=90=E4=BA=A4=E5=A4=A7=E5=8D=8Eicc?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.env.development | 3 +-
.../videoManagement/dhPlayer.vue | 265 ++
.../videoManagement/index.vue | 11 +-
.../videoManagement/videoPlayer.js | 2713 +++++++++++++++++
4 files changed, 2990 insertions(+), 2 deletions(-)
create mode 100644 src/views/sevenLargeScreen/videoManagement/dhPlayer.vue
create mode 100644 src/views/sevenLargeScreen/videoManagement/videoPlayer.js
diff --git a/.env.development b/.env.development
index b07f194..9776b17 100644
--- a/.env.development
+++ b/.env.development
@@ -53,7 +53,8 @@ VITE_API_URL = 'http://192.168.34.221:8111' #雄哥本地
# 大连金笔
# VITE_API_URL = 'http://101.43.164.214:11126'
# 测试
-VITE_API_URL = 'http://jxj.zhgdyun.com:9500'
+# VITE_API_URL = 'http://jxj.zhgdyun.com:9500'
+VITE_API_URL = 'http://192.168.34.221:19112'
# 上传
VITE_ULD_API_URL = 'http://192.168.34.155:8012/onlinePreview?url='
diff --git a/src/views/sevenLargeScreen/videoManagement/dhPlayer.vue b/src/views/sevenLargeScreen/videoManagement/dhPlayer.vue
new file mode 100644
index 0000000..45c6c27
--- /dev/null
+++ b/src/views/sevenLargeScreen/videoManagement/dhPlayer.vue
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/sevenLargeScreen/videoManagement/index.vue b/src/views/sevenLargeScreen/videoManagement/index.vue
index cb9719f..81c2be4 100644
--- a/src/views/sevenLargeScreen/videoManagement/index.vue
+++ b/src/views/sevenLargeScreen/videoManagement/index.vue
@@ -133,6 +133,7 @@
+
@@ -151,6 +152,8 @@
import Card from "@/components/card.vue";
// import ysyPlayAndPlayback from "@/components/ysyPlayAndPlayback.vue";
import ysyPlayer from "./ysy-player.vue";
+import DHPlayer from "./dhPlayer.vue";
+
import { Fold, Expand, Search } from "@element-plus/icons-vue";
import { ref, onMounted, onBeforeUnmount, computed, Ref, onBeforeMount, watch } from "vue";
import { ElMessage } from "element-plus";
@@ -223,6 +226,7 @@ let pubKey = ref("");
let initCount = ref(0);
let oWebControl: any = null;
let cameraIndexCode = ref
>([]);
+const dhVideoList = ref([] as any);
// let objData = ref({
// appkey: "23914849", //海康提供的appkey
// ip: "221.12.137.200", //海康提供的ip
@@ -327,7 +331,10 @@ const checkVideo = async (item: any) => {
if (item.serialNumber) {
ysyParams.value = item;
cameraIndexCode.value = item.serialNumber;
- if (videoType.value !== 1) {
+ dhVideoList.value = [item];
+
+
+ if (videoType.value !== 1 && videoType.value !== 4) {
previewVideo(cameraIndexCode.value);
}
if (videoType.value === 1) {
@@ -395,6 +402,8 @@ const handleVideoConfig = (videoData: any) => {
oWebControl.JS_Disconnect();
}
// emitter.emit("selectMonitor", videoData);
+ } else if (videoData.videoType === 4) {
+ dhVideoList.value = [videoData];
} else {
initPlugin();
}
diff --git a/src/views/sevenLargeScreen/videoManagement/videoPlayer.js b/src/views/sevenLargeScreen/videoManagement/videoPlayer.js
new file mode 100644
index 0000000..9a33c22
--- /dev/null
+++ b/src/views/sevenLargeScreen/videoManagement/videoPlayer.js
@@ -0,0 +1,2713 @@
+/**
+ * @version v1.2.2
+ * @date 2025-4-12
+ * @desc 正式版本
+ */
+(function () {
+ window.dhPlayerControl = Object.assign({
+ videoWS: null,
+ wsConnectCount: 0,
+ wsSession: 0,
+ videoList: {}, // 每次创建后,每个videoId 对应的数据类
+ hwndList: {}, // 每次创建后对应的 {hwnd: videoId} 键值对
+ callBackList: {},
+ wsConnect: false,
+ loginFlag: "LOGIN_PENDING",
+ connectPort: [8000, 8001, 8002, 8003, 8004],
+ curPortIndex: 0,
+ }, window.dhPlayerControl || {}, {
+ noCardPlayerFlag: false,
+ DHPlayerVersion: '',
+ pkgDHPlayerVerion: [2505151714], // 配套的插件版本号
+ pluginLoginInfo: {},
+ isPIframe: false,
+ windowState: 'wsPending',
+ dhMessage: { // 错误码对应错误信息描述
+ 701: {
+ code: 701,
+ message: "当前正在对讲,无法打开音频",
+ i18nKey: 'video.player.error701',
+ type: 'msg'
+ },
+ 702: {
+ code: 702,
+ message: "当前设备正在对讲",
+ i18nKey: 'video.player.error702',
+ type: 'msg'
+ },
+ 703: {
+ code: 703,
+ message: "当前其他设备正在对讲",
+ i18nKey: 'video.player.error703',
+ type: 'msg'
+ },
+ 704: {
+ code: 704,
+ message: "抓图鉴权",
+ i18nKey: 'video.player.error704',
+ type: 'option'
+ },
+ 705: {
+ code: 705,
+ message: "本地录像下载鉴权",
+ i18nKey: 'video.player.error705',
+ type: 'option'
+ },
+ 706: {
+ code: 706,
+ message: "主/辅码流切换",
+ i18nKey: 'video.player.error706',
+ type: 'option'
+ }
+ }
+ })
+ //在Function的原型上自定义myBind()方法
+ Function.prototype.myBind = function myBind(context) {
+ //获取要操作的函数
+ var _this = this
+ //获取实参(context除外)
+ var args = Array.prototype.slice.call(arguments, 1)
+
+ //判断当前浏览器是否兼容bind()方法
+ if ('bind' in Function.prototype) {
+ //如果浏览器兼容bind()方法,则使用bind()方法,并返回bind()方法执行后的结果
+ return _this.bind(context, args)
+ }
+ //如果不兼容bind()方法,则返回一个匿名函数
+ return function () {
+ _this.apply(context, args)
+ }
+ }
+
+ if (!document.getElementsByClassName) {
+ document.getElementsByClassName = function (className, element) {
+ var children = (element || document).getElementsByTagName('*')
+ var elements = new Array()
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i]
+ var classNames = child.className.split(' ')
+ for (var j = 0; j < classNames.length; j++) {
+ if (classNames[j] == className) {
+ elements.push(child)
+ break
+ }
+ }
+ }
+ return elements
+ }
+ }
+
+ /**
+ * 匹配插件上的版本信息
+ * @param {*} param
+ * @param {*} type
+ * @returns Object 版本匹配信息
+ */
+ function getVersionInfo() {
+ if (window.dhPlayerControl.pkgDHPlayerVerion.includes(window.dhPlayerControl.DHPlayerVersion)) {
+ return {
+ isEqual: true,
+ code: 0,
+ i18nKey: "video.player.plugin.version.ok",
+ message: '创建成功'
+ }
+ }
+ if (window.dhPlayerControl.pkgDHPlayerVerion[0] > window.dhPlayerControl.DHPlayerVersion) {
+ return {
+ isEqual: false,
+ code: -1,
+ i18nKey: 'video.player.plugin.version.low.redownload',
+ message: '当前电脑上的插件版本过低,建议升级插件!'
+ }
+ }
+ if (window.dhPlayerControl.pkgDHPlayerVerion[window.dhPlayerControl.pkgDHPlayerVerion.length - 1] < window.dhPlayerControl.DHPlayerVersion) {
+ return {
+ isEqual: true,
+ code: 1,
+ i18nKey: 'video.player.plugin.version.high.redownload',
+ message: '创建成功'
+ }
+ }
+ }
+
+ /**
+ * 内部方法 封装请求参数
+ * @param {*} param
+ * @param {*} type 接口类型
+ * @returns Object 请求参数
+ */
+ function getAjaxParam(param, type) {
+ // 处理对讲参数
+ let processTalkParam = function (param) {
+ if (param.channelId) {
+ let tempArr = param.channelId.split('$1$0$')
+ !tempArr && (tempArr = param.channelId.split('$'))
+ return tempArr
+ } else {
+ return [param.deviceCode, param.channelSeq]
+ }
+ }
+ let obj = {
+ // 实时预览参数
+ real: {
+ data: {
+ channelId: param.channelId || '',
+ streamType: Number(param.streamType) || 1, // 默认主码流
+ dataType: Number(param.dataType) || 1 // 默认是视频
+ }
+ },
+ // 对讲参数
+ talk: {
+ data: {
+ audioBit: 16,
+ sampleRate: 8000,
+ audioType: 2,
+ talkType: getTalkType(param.deviceType),
+ deviceCode: processTalkParam(param)[0],
+ channelSeq: processTalkParam(param)[1],
+ enableGBParamAutoAdapt: 1,
+ // urlType: 1,
+ // audioTypeList: [1, 2, 8]
+ }
+ },
+ // 停止对讲参数
+ stopTalk: {
+ data: {
+ deviceCode: processTalkParam(param)[0],
+ channelSeq: processTalkParam(param)[1],
+ talkType: getTalkType(param.deviceType),
+ session: param.session
+ }
+ },
+ // 通过时间录像回放参数
+ playbackByTime: {
+ clientType: "WINPC",
+ clientMac: "30:9c:23:79:40:08",
+ clientPushId: "",
+ project: "PSDK",
+ method: "SS.Playback.StartPlaybackByTime",
+ data: {
+ nvrId: "",
+ optional: "/admin/API/SS/Playback/StartPlaybackByTime",
+ recordType: "0", // 录像类型:1=一般录像,2=报警录像
+ recordSource: param.recordSource, // 录像来源:1=全部,2=设备,3=中心 4-统一云
+ streamType: param.streamType || 0, // 码流类型: 0=所有码流,1=主码流,2=辅码流
+ channelId: param.channelId,
+ startTime: param.bBack === 0 ? (param.currentPlayTime || param.startTime) : param.startTime,
+ endTime: param.bBack === 0 ? param.endTime : (param.currentPlayTime || param.endTime)
+ }
+ },
+ // 通过文件录像回放参数
+ playbackByFile: {
+ clientType: "WINPC",
+ clientMac: "30:9c:23:79:40:08",
+ clientPushId: "",
+ project: "PSDK",
+ method: "SS.Playback.StartPlaybackByFile",
+ data: {
+ ssId: "1001",
+ optional: "/evo-apigw/admin/API/SS/Playback/StartPlaybackByFile",
+ startTime: param.bBack === 0 ? param.currentPlayTime : param.playStartTime,
+ endTime: param.bBack === 0 ? param.playEndTime : param.currentPlayTime,
+ fileName: "{fe69f729-9d4b-42d4-b6a0-56189aaa4e1e}",
+ diskId: "1540852944-1540853395",
+ nvrId: "",
+ recordSource: param.recordSource,
+ channelId: param.channelId,
+ playbackMode: "0",
+ streamId: "5875"
+ }
+ },
+ // 查询录像参数
+ queryRecord: {
+ clientType: "WINPC",
+ clientMac: "30:9c:23:79:40:08",
+ clientPushId: "",
+ project: "PSDK",
+ method: "SS.Record.QueryRecords",
+ "data": {
+ cardNo: "",
+ optional: "/admin/API/SS/Record/QueryRecords",
+ diskPath: "",
+ startIndex: "",
+ streamType: param.streamType || 0, // 码流类型:0= 所有码流, 1=主码流, 2=辅码流
+ recordType: "0", // 录像类型:0=全部,1=手动录像,2=报警录像,3=动态监测,4=视频丢失,5=视频遮挡,6=定时录像,7=全天候录像,8=文件录像转换
+ recordSource: param.recordSource, // 录像来源:1=全部,2=设备,3=中心 4-统一云
+ endIndex: "",
+ startTime: param.startTime,
+ endTime: param.endTime,
+ channelId: param.channelId,
+ }
+ }
+ }
+ // 对应的窗口号
+ obj[type].snum = param.snum
+ return JSON.parse(JSON.stringify(obj[type]))
+ }
+
+ /**
+ * 获取对讲类型
+ * @param { Number } deviceType
+ * @returns talkType 对讲类型 1-设备对讲 2-通道对讲
+ * @desc 如果是EVS{1}, NVS{3},NVR{6}, DVR{10}, smartNVR{14}[已弃用],IVSS{43},需要发起通道对讲。
+ */
+ function getTalkType(deviceType) {
+ let channelTalk = [1, 3, 6, 10, 14, 43]
+ if (channelTalk.includes(Number(deviceType))) {
+ return 2
+ }
+ return 1
+ }
+
+
+ /**
+ * 内部方法
+ * @desc 判断当前dom是否被 visibility: hidden 或者 display: none
+ * @param {*} data
+ * @returns { Boolean } visible
+ */
+ function isDomVisible(el) {
+ // var loopable = true,
+ // visible = getComputedStyle(el).display != 'none' && getComputedStyle(el).visibility != 'hidden';
+ // 代码保留,不删除,递归访问
+ // while(loopable && visible) {
+ // el = el.parentNode;
+ // if(el && el != document.body) {;
+ // visible = getComputedStyle(el).display != 'none' && getComputedStyle(el).visibility != 'hidden';
+ // }else {
+ // loopable = false;
+ // }
+ // }
+ return el && (window.getComputedStyle(el).display != 'none' || window.getComputedStyle(el).visibility != 'hidden') || false;
+ }
+
+ /**
+ * 内部方法
+ * @desc rtsp路径拼接token
+ * @param {Object} 接口返回的rtsp对象
+ */
+ function dealUrl(data) {
+ let path = data.url
+ let compareUrl = ""
+ if (path.includes('|')) {
+ path = path.split("|").map(item => {
+ // 视频子系统兼容
+ if (item.includes(window.location.hostname)) {
+ compareUrl = item + (data.token ? '?token=' + data.token : '')
+ return null
+ }
+ return item + (data.token ? '?token=' + data.token : '')
+ }).filter(item => item).join('|')
+ path = compareUrl ? (compareUrl + '|') + path : path
+ // 兼容视频子系统
+ } else {
+ path = path + (data.token ? '?token=' + data.token : '')
+ }
+ return path
+ }
+
+ /**
+ * 内部方法
+ * @desc 处理当前浏览器的缩放比例
+ */
+ function getWindowSize() {
+ var width = window.dhPlayerControl.isPIframe ? this.setting.topInnerWidth : window.top.innerWidth,
+ height = window.dhPlayerControl.isPIframe ? this.setting.topInnerHeight : window.top.innerHeight
+ return {
+ width: width,
+ height: height
+ }
+ }
+
+ /**
+ * 内部方法
+ * @desc 获取当前浏览器最左侧距离主屏的位置
+ */
+ function getScreenX() {
+ // 造个假数据,模拟客户端返回
+ let screenInfo = window.osRatio || [1, 1] // [主屏的缩放比例, 副屏的缩放比例]
+ let defaultScreenX = window.screenX
+ let availX = window.screen.availLeft
+ let x = 0
+ if (availX <= 0) {
+ // 不需要计算主屏的位置
+ x = defaultScreenX >= -2 && defaultScreenX <= 9 ? 0 : defaultScreenX
+ // availX === 0 ? 0 : 1 为 0 表示在主屏上面, 小于 0 表示在副屏上,所以获取的分辨率不同。
+ x = x * screenInfo[availX === 0 ? 0 : 1]
+ } else {
+ // 需要计算主屏的位置
+ let sideX = defaultScreenX - availX
+ sideX = sideX >= -2 && sideX <= 9 ? 0 : sideX
+ // 计算主屏和副屏的真实距离后相加,即为x
+ x = availX * screenInfo[0] + sideX * screenInfo[1]
+ }
+ return x
+ }
+ /**
+ * 内部方法
+ * @desc 获取页面缩放比例
+ */
+ function detectZoom() {
+ var ratio = 0,
+ screen = window.screen,
+ ua = navigator.userAgent.toLowerCase()
+ if (window.devicePixelRatio !== undefined) {
+ ratio = window.devicePixelRatio
+ } else if (~ua.indexOf('msie')) {
+ if (screen.deviceXDPI && screen.logicalXDPI) {
+ ratio = screen.deviceXDPI / screen.logicalXDPI
+ }
+ } else if (window.outerWidth !== undefined && window.innerWidth !== undefined) {
+ ratio = window.outerWidth / window.innerWidth
+ }
+
+ if (ratio) {
+ ratio = Math.round(ratio * 100)
+ }
+ return ratio
+ }
+
+
+ function socketOpen(curPortIndex = 0) {
+ if (typeof WebSocket === 'undefined') {
+ this.setting.createError && this.setting.createError({
+ code: 1005,
+ data: null,
+ success: false,
+ i18nKey: 'browser.not.support.socket',
+ message: "您的浏览器不支持socket!"
+ })
+ return
+ }
+ window.dhPlayerControl.videoWS = new WebSocket(`ws:127.0.0.1:${[window.dhPlayerControl.connectPort[curPortIndex]]}`)
+ window.dhPlayerControl.videoWS.onopen = function () {
+ window.dhPlayerControl.manualCloseWS = false
+ window.dhPlayerControl.windowState = 'wsSuccess' // websocket连接成功
+ window.dhPlayerControl.curPortIndex = curPortIndex
+ heartbeat.call(this)
+ let _isSupport = isSupport()
+ for (let key in window.dhPlayerControl.videoList) {
+ let currentThis = window.dhPlayerControl.videoList[key]
+ currentThis.send({
+ method: 'common.version',
+ info: {},
+ })
+ if (_isSupport.success) {
+ if(currentThis.setting.usePluginLogin) {
+ currentThis.loginServer()
+ window.dhPlayerControl.loginFlag = "LOGIN_PENDING"
+ let p = new Promise((resolve, reject) => {
+ let interval = setInterval(() => {
+ if(window.dhPlayerControl.loginFlag !== "LOGIN_PENDING") {
+ clearInterval(interval)
+ resolve()
+ }
+
+ }, 300)
+ })
+ p.then(() => {
+ currentThis.create()
+ window.isResetConnect = currentThis.setting.isResetConnect
+ })
+ } else {
+ currentThis.create()
+ window.isResetConnect = currentThis.setting.isResetConnect
+ }
+
+ } else {
+ currentThis.setting.createError(_isSupport)
+ }
+ }
+ }
+ window.dhPlayerControl.videoWS.onmessage = socketMessage
+ window.dhPlayerControl.videoWS.onclose = () => {
+ if(window.dhPlayerControl.windowState === 'wsPending' || window.dhPlayerControl.windowState === 'noPlugin') {
+ if(curPortIndex < window.dhPlayerControl.connectPort.length - 1) {
+ window.dhPlayerControl.timer = setTimeout(() => {
+ window.dhPlayerControl.videoWS = null
+ socketOpen(curPortIndex + 1)
+ clearTimeout(window.dhPlayerControl.timer)
+ }, 300)
+ return
+ }
+ // 未成功过,轮询端口
+ window.dhPlayerControl.windowState = 'noPlugin' // websocket连接失败
+ for (var key in window.dhPlayerControl.videoList) {
+ var currentThis = window.dhPlayerControl.videoList[key]
+ currentThis.setting.createError && currentThis.setting.createError({
+ code: 1001,
+ data: null,
+ i18nKey: 'video.player.plugin.not.installed',
+ message: '插件未安装',
+ success: false
+ })
+ }
+ } else {
+ // 表示成功过,不需要再轮训判断端口了
+ window.dhPlayerControl.windowState = 'wsError' // websocket连接失败
+ if (window.isResetConnect && !window.dhPlayerControl.manualCloseWS) {
+ console.log("----------无法与插件建立连接-------");
+ for (var key in window.dhPlayerControl.videoList) {
+ var currentThis = window.dhPlayerControl.videoList[key]
+ currentThis.setting.createError && currentThis.setting.createError({
+ code: 1003,
+ data: null,
+ i18nKey: 'websocket.reload',
+ message: '无法与播放器建立连接,正在尝试重连...',
+ success: false
+ })
+ }
+ setTimeout(() => {
+ window.dhPlayerControl.videoWS = null
+ socketOpen(window.dhPlayerControl.curPortIndex)
+ }, 3000)
+ } else {
+ for (var key in window.dhPlayerControl.videoList) {
+ var currentThis = window.dhPlayerControl.videoList[key]
+ currentThis.setting.createError && currentThis.setting.createError({
+ code: 1003,
+ data: null,
+ i18nKey: 'websocket.disconnect',
+ message: '无法与播放器建立连接',
+ success: false
+ })
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * 内部方法
+ * @desc 插件心跳,保活
+ */
+ function heartbeat() {
+ var that = this
+ clearInterval(window.wsHeart)
+ window.wsHeart = setInterval(function () {
+ that.send(JSON.stringify({
+ method: 'common.heartbeat',
+ info: {},
+ id: window.dhPlayerControl.wsConnectCount++
+ }))
+ }, 10 * 1000)
+ }
+
+ function dataURLtoBlob(dataurl) {
+ var mime = 'image/jpeg',
+ bstr = atob(dataurl),
+ n = bstr.length,
+ u8arr = new Uint8Array(n)
+ while (n--) {
+ u8arr[n] = bstr.charCodeAt(n)
+ }
+ return new Blob([u8arr], {
+ type: mime
+ })
+ }
+ function downloadFileByBase64(base64, name) {
+ var myBlob = dataURLtoBlob(base64)
+ var myUrl = URL.createObjectURL(myBlob)
+ return myUrl
+ }
+
+ /**
+ * 前端与插件链接成功后,接收插件返回的信息
+ * @param {*} evt
+ * @returns
+ */
+ function socketMessage(evt) {
+ if (evt.data == null || evt.data == '') {
+ return
+ }
+ window.dhPlayerControl.wsSession = data && data.session || window.dhPlayerControl.wsSession
+ var data = JSON.parse(evt.data)
+ if(data.method && ![
+ 'window.osRatio','video.window.clicked',
+ 'video.window.dbclicked',
+ 'video.division.change',
+ 'video.customDivision.change',
+ 'video.downloadFileSize',
+ 'video.download.mp4.result',
+ 'video.downloadByTime'].includes(data.method)) {
+ localStorage.printLog && console.log('client->web: ', data.method, data.info);
+ }
+ // 登录校验
+ if(data.method === 'window.loginServer') {
+ switch(data.info.code) {
+ case 0:
+ case 3:
+ window.dhPlayerControl.loginFlag = "LOGIN_PENDING"
+ break;
+ case 1:
+ case 2:
+ window.dhPlayerControl.loginFlag = "LOGIN_SUCCESS"
+ break;
+ case 4:
+ window.dhPlayerControl.loginFlag = "LOGIN_ERROR"
+ default:
+ break;
+ }
+ }
+ if(data.method === 'window.loginServer.notify') {
+ if (data.info.result === 0) {
+ window.dhPlayerControl.loginFlag = "LOGIN_SUCCESS"
+ } else {
+ window.dhPlayerControl.loginFlag = "LOGIN_ERROR"
+ }
+ }
+ // 赋值版本号信息
+ if (data && data.data && data.data.ver) {
+ window.dhPlayerControl.DHPlayerVersion = Number(data.data.ver)
+ }
+ // 获取屏幕分辨率
+ if (data.method === 'window.osRatio') {
+ window.osRatio = data.info.dpi
+ }
+ // 保证 hwnd 是 number 类型
+ if (data.info && typeof data.info.hwnd === 'number') {
+ var videoInfo = window.dhPlayerControl.videoList[window.dhPlayerControl.hwndList[data.info.hwnd]]
+ var hwndInfo = videoInfo.setting
+ if (typeof data.info.snum === 'number') {
+ var channelInfo = hwndInfo.channelList.filter(item => item.snum === data.info.snum)[0]
+ }
+ switch (data.method) {
+ case 'window.message':
+ hwndInfo.dhPlayerMessage && hwndInfo.dhPlayerMessage(channelInfo, window.dhPlayerControl.dhMessage[data.info.eventCode])
+ break
+ case 'video.change.substream':
+ if (channelInfo.byUrl) {
+ return hwndInfo.dhPlayerMessage && hwndInfo.dhPlayerMessage(channelInfo, {...window.dhPlayerControl.dhMessage[706], streamType: Number(data.info.substream)})
+ }
+ channelInfo.streamType = Number(data.info.substream)
+ videoInfo.startReal([channelInfo], { isSubStream: true })
+ break
+ case 'video.notifyrealmonitor':
+ // 表示成功
+ if (Number(data.info.result) === 0) {
+ hwndInfo.realSuccess && hwndInfo.realSuccess(channelInfo, hwndInfo.channelList)
+ }
+ // 拉流失败
+ if (Number(data.info.result) === 10704) {
+ hwndInfo.realError && hwndInfo.realError(channelInfo, { code: 10704, message: '打开视频失败', i18nKey: 'video.player.play.fail'})
+ }
+ // 拉流超时
+ if (Number(data.info.result) === -405) {
+ hwndInfo.realError && hwndInfo.realError(channelInfo, { code: 10705, message: '打开视频超时', i18nKey: 'video.player.play.timeout'})
+ }
+ videoInfo.setWindowDragEnable()
+ break
+ // 实时预览播放过程中的断线重连
+ case 'video.reopenvideo':
+ if (channelInfo.byUrl) {
+ return hwndInfo.realError(channelInfo, { code: 204, message: '流异常断开,请重新连接~', i18nKey: 'video.player.stream.disconnect.reload'});
+ }
+ data.info.count++
+ videoInfo.startReal([channelInfo], { isReOpen: true, count: data.info.count++ })
+ break;
+ case 'video.notifyplayback':
+ // 表示成功
+ if (Number(data.info.result) === 0) {
+ hwndInfo.playbackSuccess && hwndInfo.playbackSuccess(channelInfo, hwndInfo.channelList)
+ }
+ videoInfo.setWindowDragEnable()
+ break
+ case 'web.seekRecord':
+ hwndInfo.channelList.forEach((item, index) => {
+ if (item.snum === data.info.snum) {
+ // 非集成状态下,抛出回调
+ if (item.byUrl) {
+ hwndInfo.switchStartTime && hwndInfo.switchStartTime({
+ startTime: data.info.seekTime,
+ snum: data.info.snum
+ })
+ return
+ }
+ if (data.info.seekTime < item.startTime) {
+ hwndInfo.playbackError && hwndInfo.playbackError(channelInfo, {
+ code: 201,
+ i18nKey: 'play.record.error.201.tip1',
+ message: '当前时间不得小于开始时间'
+ })
+ return
+ }
+ if (data.info.seekTime > item.endTime) {
+ hwndInfo.playbackError && hwndInfo.playbackError(channelInfo, {
+ code: 201,
+ i18nKey: 'play.record.error.201.tip2',
+ message: '当前时间不得大于结束时间'
+ })
+ return
+ }
+ let currentIndex = item.records && item.records.findIndex(r => {
+ return Number(r.startTime) <= data.info.seekTime && Number(r.endTime) > data.info.seekTime
+ })
+ // 如果
+ if(currentIndex >= 0) {
+ item.currentIndex = currentIndex
+ console.log(`当前拖拽到第${item.currentIndex}录像`);
+ item.currentPlayTime = data.info.seekTime
+ item.bBack = Number(data.info.bBack)
+ videoInfo.closeVideo(data.info.snum).then(res => {
+ videoInfo.startPlayback(item, {
+ isConnect: true,
+ scaleSteps: Number(data.info.scaleSteps),
+ })
+ })
+ } else {
+ console.log("当前位置无录像,不能拖拽")
+ }
+ }
+ })
+ break
+ case 'web.replay':
+ hwndInfo.channelList.forEach((item, index) => {
+ if (item.snum === data.info.snum) {
+ // 非集成状态下
+ if (item.byUrl) {
+ hwndInfo.replay && hwndInfo.replay(data.info.snum, data.info.seekTime)
+ return
+ }
+ item.bBack = Number(data.info.bBack)
+ if (!item.bBack) {
+ if (item.currentIndex === item.records.length - 1) {
+ hwndInfo.playbackFinish && hwndInfo.playbackFinish({
+ snum: data.info.snum,
+ channelId: data.info.channelId,
+ code: 201,
+ i18nKey: 'video.player.playback.complete',
+ message: '录像已全部播放完成'
+ })
+ // videoInfo.closeVideo(data.info.snum)
+ // hwndInfo.channelList.splice(index, 1)
+ return
+ }
+ item.currentIndex++
+ item.currentPlayTime = item.records[item.currentIndex].startTime
+ } else {
+ if (item.currentIndex === 0) {
+ hwndInfo.playbackFinish && hwndInfo.playbackFinish({
+ snum: data.info.snum,
+ channelId: data.info.channelId,
+ code: 201,
+ i18nKey: "video.player.playback.complete",
+ message: '录像已全部播放完成'
+ })
+ // videoInfo.closeVideo(data.info.snum)
+ // hwndInfo.channelList.splice(index, 1)
+ return
+ }
+ item.currentIndex--
+ item.currentPlayTime = item.records[item.currentIndex].endTime
+ }
+ if (item.recordSource === 2) {
+ // 设备录像要关闭一次视频
+ videoInfo.closeVideo(data.info.snum).then(() => {
+ videoInfo.startPlayback(item, {
+ isConnect: true,
+ scaleSteps: Number(data.info.scaleSteps)
+ })
+ })
+ } else {
+ // 中心录像不需要
+ videoInfo.startPlayback(item, {
+ isConnect: true,
+ bContinue: true,
+ scaleSteps: Number(data.info.scaleSteps)
+ })
+ }
+ }
+ })
+ break
+ case 'video.close':
+ let i = -1
+ hwndInfo.channelList.forEach((item, index) => {
+ // 获取到要被删除的数据 (插件内部关闭且存在窗口统一)
+ if (item.snum === data.info.snum) {
+ if (!item.closed) {
+ i = index
+ } else {
+ delete item.closed
+ }
+ }
+ })
+ if (i >= 0) {
+ hwndInfo.channelList.splice(i, 1)
+ // 删除掉窗口和channelId都匹配上的
+ hwndInfo.closeWindowSuccess && hwndInfo.closeWindowSuccess({
+ snum: data.info.snum,
+ channelList: hwndInfo.channelList
+ })
+ }
+ break
+ case 'video.notifytalk':
+ // 判断是否有对讲
+ if (data.info.bOpen) {
+ let talkFlag = false
+ hwndInfo.channelList.forEach(item => {
+ if (item.byUrl) {
+ talkFlag = true
+ // 告诉前端传入url对讲回调
+ hwndInfo.notifyTalk && hwndInfo.notifyTalk({ channelId: data.info.channelId, snum: data.info.snum })
+ return
+ }
+ if (item.isTalk) {
+ talkFlag = true
+ hwndInfo.request.stopTalk && hwndInfo.request.stopTalk(getAjaxParam(item, 'stopTalk')).then(() => {
+ delete item.isTalk
+ videoInfo.startTalk(data.info.snum)
+ }).catch(err => {
+ // 表示当前不存在
+ if (err.code === 2051) {
+ videoInfo.startTalk(data.info.snum)
+ }
+ })
+ }
+ })
+ !talkFlag && videoInfo.startTalk(data.info.snum)
+ } else {
+ hwndInfo.channelList.forEach(item => {
+ if (item.snum === data.info.snum) {
+ hwndInfo.request.stopTalk && hwndInfo.request.stopTalk(getAjaxParam(item, 'stopTalk')).then(() => {
+ console.log('关闭对讲')
+ })
+ }
+ videoInfo.closeTalk()
+ })
+ }
+ break
+ case 'talk.close':
+ hwndInfo.snum = data.info.wndId
+ hwndInfo.closeTalkSuccess && hwndInfo.closeTalkSuccess(data.info.wndId)
+ break
+ case 'web.captureCallBack':
+ var imageUrl = data.info.PicBuf ? downloadFileByBase64(data.info.PicBuf) : ''
+ hwndInfo.snapshotSuccess && hwndInfo.snapshotSuccess({
+ base64Url: data.info.PicBuf,
+ path: imageUrl
+ }, channelInfo)
+ break
+ case 'window.LocalRecordFinish':
+ hwndInfo.videoDownloadSuccess && hwndInfo.videoDownloadSuccess(data.info.path, channelInfo)
+ break
+ case 'video.window.clicked':
+ channelInfo = hwndInfo.channelList.filter(item => item.snum === data.info.wndIndex)[0]
+ hwndInfo.clickWindow && hwndInfo.clickWindow(data.info.wndIndex, channelInfo)
+ break
+ case 'video.window.dbclicked':
+ channelInfo = hwndInfo.channelList.filter(item => item.snum === data.info.wndIndex)[0]
+ hwndInfo.dbClickWindow && hwndInfo.dbClickWindow(data.info.wndIndex, channelInfo)
+ break
+ case 'video.division.change':
+ hwndInfo.division = data.info.division
+ hwndInfo.changeDivision && hwndInfo.changeDivision(data.info.division)
+ videoInfo.setWindowDragEnable()
+ break
+ case 'video.customDivision.change':
+ hwndInfo.division = JSON.stringify(data.info)
+ hwndInfo.changeDivision && hwndInfo.changeDivision(JSON.stringify(data.info))
+ videoInfo.setWindowDragEnable()
+ break
+ case 'video.downloadFileSize':
+ hwndInfo.downloadProgress && hwndInfo.downloadProgress(data.info)
+ break
+ case 'video.download.mp4.result':
+ hwndInfo.downloadRecordSuccess && hwndInfo.downloadRecordSuccess(data.info)
+ break;
+ case 'video.downloadByTime':
+ if (Number(data.info.errCode) === 0) {
+ hwndInfo.downloadRecordSuccess && hwndInfo.downloadRecordSuccess(data.info)
+ } else {
+ let errMessage = {
+ 142: "rtsp断开连接",
+ 135: "视频异常",
+ 141: "SS服务异常"
+ }
+ hwndInfo.downloadRecordError && hwndInfo.downloadRecordError(data.info, {
+ code: Number(data.info.errCode),
+ mesage: errMessage[Number(data.info.errCode)]
+ })
+ }
+ default:
+ break
+ }
+ }
+ var onError = null
+ var onSuccess = null
+ if (window.dhPlayerControl.callBackList[data['id']]) {
+ onError = window.dhPlayerControl.callBackList[data['id']].onError
+ onSuccess = window.dhPlayerControl.callBackList[data['id']].onSuccess
+ }
+ if (data.code != 0) {
+ if (onError && typeof onError === 'function') {
+ onError(data)
+ delete window.dhPlayerControl.callBackList[data['id']]
+ }
+ return
+ }
+ if (onSuccess && typeof onSuccess === 'function') {
+ onSuccess(data)
+ delete window.dhPlayerControl.callBackList[data['id']]
+ }
+ }
+ //主动关闭socket
+ function socketClose() {
+ window.dhPlayerControl.manualCloseWS = true
+ window.dhPlayerControl.videoWS && window.dhPlayerControl.videoWS.close()
+ window.dhPlayerControl.videoWS = null
+ window.wsHeart = clearInterval(window.wsHeart)
+ }
+
+ /**
+ * @desc 获取操作系统
+ */
+ function getOsInfo() {
+ var userAgent = window.navigator.userAgent.toLowerCase()
+ var version = ''
+ if (userAgent.indexOf('win') > -1) {
+ if (userAgent.indexOf('windows nt 5.0') > -1 || userAgent.indexOf('Windows 2000') > -1) {
+ version = 'Windows 2000'
+ } else if (userAgent.indexOf('windows nt 5.1') > -1 || userAgent.indexOf('Windows XP') > -1) {
+ version = 'Windows XP'
+ } else if (userAgent.indexOf('windows nt 5.2') > -1 || userAgent.indexOf('Windows 2003') > -1) {
+ version = 'Windows 2003'
+ } else if (userAgent.indexOf('windows nt 6.0') > -1 || userAgent.indexOf('Windows Vista') > -1) {
+ version = 'Windows Vista'
+ } else if (userAgent.indexOf('windows nt 6.1') > -1 || userAgent.indexOf('windows 7') > -1) {
+ version = 'Windows 7'
+ } else if (userAgent.indexOf('windows nt 6.2') > -1 || userAgent.indexOf('windows 8') > -1) {
+ version = 'Windows 8'
+ } else if (userAgent.indexOf('windows nt 6.3') > -1) {
+ version = 'Windows 8.1'
+ } else if (userAgent.indexOf('windows nt 6.4') > -1 || userAgent.indexOf('windows nt 10') > -1) {
+ version = 'Windows 10'
+ } else {
+ version = 'Unknown'
+ }
+ } else if (userAgent.indexOf('iphone') > -1) {
+ version = 'Iphone'
+ } else if (userAgent.indexOf('mac') > -1) {
+ version = 'Mac'
+ } else if (
+ userAgent.indexOf('x11') > -1 ||
+ userAgent.indexOf('unix') > -1 ||
+ userAgent.indexOf('sunname') > -1 ||
+ userAgent.indexOf('bsd') > -1
+ ) {
+ version = 'Unix'
+ } else if (userAgent.indexOf('linux') > -1) {
+ if (userAgent.indexOf('android') > -1) {
+ version = 'Android'
+ } else {
+ version = 'Linux'
+ }
+ } else {
+ version = 'Unknown'
+ }
+ return version
+ }
+
+ /**
+ * @desc 获取浏览器和对应浏览器版本
+ */
+ function getBroswerVersion() {
+ // 浏览器判断和版本号读取
+ var Sys = {}
+ var userAgent = navigator.userAgent.toLowerCase()
+ var s;
+ (s = userAgent.match(/edg\/([\d.]+)/)) ?
+ (Sys.edge = s[1]) :
+ (s = userAgent.match(/rv:([\d.]+)\) like gecko/)) ?
+ (Sys.ie = s[1]) :
+ (s = userAgent.match(/msie ([\d.]+)/)) ?
+ (Sys.ie = s[1]) :
+ (s = userAgent.match(/firefox\/([\d.]+)/)) ?
+ (Sys.firefox = s[1]) :
+ (s = userAgent.match(/chrome\/([\d.]+)/)) ?
+ (Sys.chrome = s[1]) :
+ (s = userAgent.match(/opera.([\d.]+)/)) ?
+ (Sys.opera = s[1]) :
+ (s = userAgent.match(/version\/([\d.]+).*safari/)) ?
+ (Sys.safari = s[1]) :
+ 0
+
+ if (Sys.edge)
+ return {
+ broswer: 'Edg',
+ version: Sys.edge
+ }
+ if (Sys.ie)
+ return {
+ broswer: 'IE',
+ version: Sys.ie
+ }
+ if (Sys.firefox)
+ return {
+ broswer: 'Firefox',
+ version: Sys.firefox
+ }
+ if (Sys.chrome)
+ return {
+ broswer: 'Chrome',
+ version: Sys.chrome
+ }
+ if (Sys.opera)
+ return {
+ broswer: 'Opera',
+ version: Sys.opera
+ }
+ if (Sys.safari)
+ return {
+ broswer: 'Safari',
+ version: Sys.safari
+ }
+
+ return {
+ broswer: '',
+ version: '0'
+ }
+ }
+
+
+ function broswerInfo() {
+ var _version = getBroswerVersion()
+ if (_version.broswer === 'IE') {
+ return 0
+ } else if (_version.broswer === 'Chrome' || _version.broswer === 'Edg') {
+ return 1
+ } else if (_version.broswer === 'Firefox') {
+ return 2
+ } else {
+ return -1
+ }
+ }
+
+ /**
+ * 内部方法
+ * @desc 判断当前操作系统和浏览器版本类型是否支持DHPlayer
+ */
+ function isSupport() {
+ let supportedOS = ['Windows 7', 'Windows 10', 'Windows 8', 'Windows 8.1', 'Unix', 'Linux']
+ let supportedBroswer = ['Chrome', 'Firefox', 'Edg']
+ let osVersion = getOsInfo()
+ let { broswer, version } = getBroswerVersion()
+ console.log("当前识别的操作系统版本为: ", osVersion, "浏览器为: ", broswer, version + "版本")
+ if (!supportedOS.includes(osVersion)) {
+ return {
+ code: 1002,
+ success: false,
+ i18nKey: 'window.system.not.support',
+ message: '电脑系统不支持!仅支持win7, win8, win8.1, win10, Unix, Linux 系统'
+ }
+ }
+ if (!supportedBroswer.includes(broswer)) {
+ return {
+ code: 1002,
+ success: false,
+ i18nKey: 'browser.not.support',
+ message: '当前浏览器不支持! 仅支持谷歌,火狐,edge浏览器'
+ }
+ }
+ if (Number(version.split('.')[0]) < 76 || osVersion === 'unix') {
+ return {
+ code: 1002,
+ success: false,
+ i18nKey: 'browser.version.low',
+ message: '当前的浏览器版本不支持!请使用较高版本的浏览器!'
+ }
+ }
+ return {
+ code: 1000,
+ success: true
+ }
+ }
+
+ // 获取iframe的位置
+ function getIframeRect(name) {
+ var outLeft = 0
+ var outTop = 0
+ var pOutContent
+ if (window.dhPlayerControl.isPIframe) {
+ pOutContent = this.setting.pIframeRect
+ outLeft = pOutContent.left || 0
+ outTop = pOutContent.top || 0
+ } else {
+ // 表示顶层window
+ if(window.parent === window) {
+ return {
+ outLeft: 0,
+ outTop: 0
+ }
+ }
+ var iframes = window.parent.document.getElementsByTagName('iframe')
+ var pIframe = null
+ var dom = ''
+ let getpIframe = (index) => {
+ if (!iframes[index]) return
+ try {
+ if (name) {
+ dom = iframes[index].contentWindow.document.getElementsByClassName(name)[0]
+ } else {
+ dom = iframes[index].contentWindow.document.getElementById(this.setting.videoId)
+ }
+ if (dom) {
+ pIframe = iframes[index]
+ } else {
+ getpIframe(index + 1)
+ }
+ } catch (err) {
+ getpIframe(index + 1)
+ }
+ }
+ iframes.length && getpIframe(0)
+ if (pIframe) {
+ pOutContent = pIframe.getBoundingClientRect()
+ outLeft = pOutContent.left
+ outTop = pOutContent.top
+ }
+ }
+ return {
+ outLeft,
+ outTop
+ }
+ }
+
+ // 获取遮挡的位置数据
+ function computedRect(className, isIframe) {
+ let doms = null;
+ let { outLeft, outTop } = getIframeRect.call(this)
+ if (isIframe) {
+ outLeft = 0
+ outTop = 0
+ }
+ // 处理dom的位置数据
+ let processDoms = (doms) => {
+ let rectArr = []
+ doms.length && doms.forEach(item => {
+ let rect = item && item.getBoundingClientRect() || null
+ if (rect && (rect.width || rect.height)) {
+ rectArr = [...rectArr, rect.left + (this.setting.outContent.left || outLeft), rect.top + (this.setting.outContent.top || outTop), rect.width, rect.height]
+ }
+ })
+ return rectArr
+ }
+ if (isIframe) {
+ doms = window.top.document.querySelectorAll(`.${className}`)
+ } else {
+ doms = window.document.querySelectorAll(`.${className}`)
+ }
+ return processDoms(doms)
+ }
+
+ // 获取位置
+ function getRect(name) {
+ var el = ''
+ var videoId = this.setting.videoId
+ if (name) {
+ el = document.getElementsByClassName(name)[0]
+ } else {
+ el = document.getElementById(videoId)
+ }
+ if (!el) {
+ return {}
+ }
+ var rect = el.getBoundingClientRect()
+ var { outTop, outLeft } = getIframeRect.call(this, name)
+ var left = rect.left + (this.setting.outContent.left || outLeft)
+ var top = rect.top + (this.setting.outContent.top || outTop)
+ var right = left + rect.width
+ var bottom = top + rect.height
+ return {
+ left,
+ top,
+ right,
+ bottom,
+ width: rect.width,
+ height: rect.height
+ }
+ }
+ // 请求录像文件信息
+ function queryRecord(param, type = 'queryRecord') {
+ return new Promise((resolve, reject) => {
+ // 查询录像
+ if (param.records && param.records.length) {
+ resolve(param)
+ }
+ if (!this.setting.request[type]) {
+ reject({
+ code: 207,
+ i18nKey: 'video.player.please.input.recordings.interface',
+ message: '请通过 request 属性传入查询录像接口'
+ })
+ return
+ }
+ this.setting.request[type](getAjaxParam(param, type)).then(res => {
+ if (!param.records || param.records === []) {
+ if (!res.records || !res.records.length) {
+ reject({
+ code: 201,
+ channelInfo: param,
+ i18nKey: 'video.player.selected.channel.search.empty',
+ message: `通道 ${param.channelName || param.name || '未知'} 未查询到录像文件`
+ })
+ return
+ }
+ param.records = res.records.sort((a, b) => a.startTime - b.startTime)
+ param.currentIndex = 0
+ this.setting.channelList[this.setting.channelList.findIndex(item => item.channelId === param.channelId && item.snum === param.snum)] = param
+ }
+ resolve(res)
+ }).catch(err => {
+ reject(err)
+ })
+ })
+ }
+ // 处理获取过来的rtsp流
+ function processRtsp(data, param) {
+ // 内外网环境会有多个rtspUrl
+ data.records = param.records;
+ data.rtspUrl = dealUrl(data)
+ return data
+ }
+
+ /**
+ * 根据文件获取流
+ * @param {*} param
+ */
+ function getPlayBackRtspByFile(param, isConnect, type = 'playbackByFile') {
+ let that = this
+ return new Promise((resolve, reject) => {
+ let byFileParam = getAjaxParam(param, type)
+ queryRecord.call(this, param)
+ .then((res) => {
+ if (!that.setting.request[type]) {
+ reject({
+ code: 207,
+ i18nKey: 'video.player.please.afferent.interface.playbackbyfile',
+ message: '请通过 request 属性传入 “根据时间查询录像” 接口'
+ })
+ return
+ }
+ let records = res.records[param.currentIndex]
+ // let rec = records[0]
+ param.playStartTime = records.startTime
+ param.playEndTime = records.endTime
+ param.currentPlayTime = isConnect ? param.currentPlayTime : param.playStartTime
+ let sTime = param.bBack === 0 ? String(param.currentPlayTime) : String(param.playStartTime)
+ let eTime = param.bBack === 0 ? String(param.playEndTime) : String(param.currentPlayTime)
+ byFileParam.data = {
+ ssId: records.ssId,
+ optional: "/evo-apigw/admin/API/SS/Playback/StartPlaybackByFile",
+ startTime: sTime,
+ endTime: eTime,
+ fileName: records.recordName,
+ diskId: `${sTime}-${eTime}`,
+ nvrId: "",
+ recordSource: param.recordSource,
+ channelId: param.channelId,
+ playbackMode: "0",
+ streamId: records.streamId
+ }
+ that.setting.request[type](byFileParam).then(res => {
+ resolve(processRtsp(res, param))
+ }).catch(err => {
+ reject(err)
+ })
+ })
+ .catch(err => {
+ reject(err)
+ })
+ })
+ }
+
+ /**
+ * 根据时间获取流
+ * @param {*} option
+ * @returns
+ */
+ function getPlayBackRtspByTime(param, type = "playbackByTime") {
+ // 设备录像也需要去查询当日有录像的时间段
+ return new Promise((resolve, reject) => {
+ queryRecord.call(this, param)
+ .then(() => {
+ if (!this.setting.request[type]) {
+ reject({
+ code: 207,
+ i18nKey: 'video.player.please.afferent.interface.playbackbytime',
+ message: '请通过 request 属性传入 “通过时间播放录像” 接口'
+ })
+ return
+ }
+ this.setting.request[type](getAjaxParam(param, type)).then(res => {
+ resolve(processRtsp(res, param))
+ }).catch(err => {
+ reject(err)
+ })
+ }).catch(err => {
+ reject(err)
+ })
+ })
+ }
+ var VideoPlayer = function (option) {
+ if (!option) {
+ throw new Error('请传入配置参数')
+ }
+ if (this instanceof VideoPlayer) {
+ var _setting = {
+ isResetConnect: true, // websocket连接断开时,是否自动重新连接, true表示是, false表示否
+ // isIE: !!window.ActiveXObject || 'ActiveXObject' in window, //判断是否为IE
+ videoId: 'DHVideoPlayer',
+ windowType: 0, // 0-实时预览,3-录像回放,7-录像回放(支持倒放)
+ outContent: {
+ left: 0,
+ right: 0,
+ width: 0,
+ height: 0
+ },
+ show: true, //当前窗口显示状态,隐藏:false,显示:true
+ option_id: {},
+ refreshTimer: null,
+ browserType: 1,
+ version: 0,
+ stopRefresh: false, //停止一直刷新
+ showBar: true, //是否显示下方控制栏。 true: 显示, false:隐藏
+ hwnd: '', //窗口句柄
+ division: 1, //子窗口数
+ pIframeShieldData: [], // 跨域iframe下的遮挡信息
+ documentTitle: "", // iframe模式下,需要获取到顶层的top,防止位置聚焦时发生偏移
+ topInnerWidth: 0, // iframe模式下的顶层宽度
+ topInnerHeight: 0, // iframe模式下的顶层高度
+ parentIframeShieldRect: [], // iframe模式下遮罩的数据信息
+ pIframeRect: [], // iframe模式下 iframe的数据信息
+ topMozInnerScreenX: 0, // iframe模式下 火狐需要的数据信息
+ topMozInnerScreenY: 0, // iframe模式下 火狐需要的数据信息
+ oldPosition: "", // 存储循环数据中的上次位置数据
+ oldShield: "", // 存储循环数据中的上次遮挡数据
+ request: {}, // 存储请求
+ channelList: [], // 存储当前播放器正在播放的视频
+ draggable: false, // 是否支持拖拽,默认不支持
+ showBorder: true, // 是否显示播放器边框
+ visible: true, // 控制播放器的显示和隐藏
+ domVisible: true, // 当前挂载的 dom 元素是否 true-显示/ false-隐藏, 默认true
+ usePluginLogin: false, // 是否插件内部鉴权
+ pluginLoginInfo: { // 插件登录信息
+ host: '',
+ port: '' || '443',
+ username: '',
+ password: '',
+ }
+ }
+ this.setting = Object.assign({}, _setting, option)
+ this.adjustCount = 0
+ this.focus = false
+ this.init()
+ } else {
+ return new VideoPlayer(option)
+ }
+ }
+ VideoPlayer.fn = VideoPlayer.prototype = {
+ // 浏览器关闭或者刷新
+ onbeforeunload: function () {
+ this.destroy(true).then(() => {
+ socketClose.call(this)
+ })
+ },
+ // 改变setting的参数值
+ _update(param) {
+ let paramType = (value, type) => Object.prototype.toString.call(value).includes(type)
+ let { windowType, isResetConnect, request, division, visible, draggable, showBar, showBorder, shieldClass, coverShieldClass, parentIframeShieldClass, language } = param
+ // 断线重连 (不对外开放,默认支持断线重连)
+ paramType(isResetConnect, 'Boolean') && !(isResetConnect === this.setting.isResetConnect) && (this.setting.isResetConnect = isResetConnect)
+ // 显隐播放器
+ paramType(visible, 'Boolean') && !(visible === this.setting.visible) && (this.setting.visible = visible, visible ? this.show() : this.hide())
+ // 显影控制栏
+ paramType(showBar, 'Boolean') && !(showBar === this.setting.showBar) && this.showControlBar(showBar)
+ // 播放器是否支持拖拽
+ paramType(draggable, 'Boolean') && !(draggable === this.setting.draggable) && (this.setting.draggable = draggable, this.setWindowDragEnable())
+ // 显隐选中的窗口边框
+ paramType(showBorder, 'Boolean') && !(showBorder === this.setting.showBorder) && (this.setting.showBorder = showBorder, this.setWindowBorder())
+ // 窗口分割
+ !(division == this.setting.division) && this.changeDivision(division)
+ // 接口转换
+ paramType(request, 'Object') && (this.setting.request = { ...request })
+ // 遮挡类的改变
+ paramType(shieldClass, 'Array') && (this.setting.shieldClass = shieldClass)
+ paramType(parentIframeShieldClass, 'Array') && (this.setting.parentIframeShieldClass = parentIframeShieldClass)
+ paramType(coverShieldClass, 'Array') && (this.setting.coverShieldClass = coverShieldClass)
+ // 重新创建
+ windowType = Number(windowType);
+ if ([0, 1, 2, 3, 7].includes(windowType) && windowType !== Number(this.setting.windowType) || language !== this.setting.language) {
+ this.setting.language = language
+ if (this.setting.socketTimer) {
+ clearTimeout(this.setting.socketTimer)
+ };
+ this.setting.socketTimer = setTimeout(() => {
+ this.setting.windowType = windowType
+ this.create()
+ }, this.setting.usePluginLogin ? 1000 : 300)
+ }
+ },
+ //发送消息
+ send: function (option, callBack) {
+ option.session = window.dhPlayerControl.wsSession
+ option.id = window.dhPlayerControl.wsConnectCount++
+ if (option.info) {
+ option.info.browserType = this.setting.browserType
+ if (option.method !== 'window.destroy') {
+ option.info.hwnd = option.method === 'window.create' ? undefined : this.setting.hwnd
+ }
+ }
+
+ if (callBack && Object.keys(callBack).length) {
+ window.dhPlayerControl.callBackList[option['id']] = callBack
+ }
+ if (!['window.change', 'window.shield', 'browserFocusBlur', 'window.show', 'window.loginServer', 'video.toolbar.showButton', 'window.enableDrag', 'video.division.change'].includes(option.method)) {
+ localStorage.printLog && console.log('web->client: ', option.method, option.info)
+ }
+ window.dhPlayerControl.videoWS &&
+ window.dhPlayerControl.videoWS.readyState == 1 &&
+ window.dhPlayerControl.videoWS.send(JSON.stringify(option))
+ },
+
+ // 创建视频窗口
+ create: function () {
+ var rect = getRect.call(this)
+ var _info = Object.assign({}, {}, rect)
+ var windowSize = getWindowSize.call(this)
+ var zoom = detectZoom()
+ _info.isCustomDivision = isNaN(this.setting.division)
+ _info.num = isNaN(this.setting.division) ? null : this.setting.division // 窗口数量
+ _info.customDivision = isNaN(this.setting.division) ? JSON.parse(this.setting.division) : null
+ _info.toolBar = this.setting.showBar ? 1 : 0 // 是否显示控制栏
+ _info.windowType = this.setting.windowType - 0 // 判断当前为实时预览还是录像回放 0-实时预览 3-录像回放
+ _info.clientAreaHeight = (windowSize.height * zoom) / 100
+ _info.clientAreaWidth = (windowSize.width * zoom) / 100
+ _info.authority = false // 操作栏上的按钮是否走权限判断(兼容视频子系统,需要传true,对外false)
+ this.setTopBind = this.setTop.myBind(this)
+ this.onbeforeunloadBind = this.onbeforeunload.myBind(this)
+ this.visibilitychangeBind = this.setVisible.myBind(this)
+ var that = this
+ this.setLanguage() // 设置语言
+ this.destroy().then(() => {
+ this.send(
+ {
+ method: 'window.create',
+ info: _info
+ },
+ {
+ onSuccess: function (data) {
+ console.log("chuangjian chneggg ")
+ if (data.data && typeof data.data.hwnd === 'number') {
+ var hwnd = data.data.hwnd
+ console.log(`${[0, 2].includes(that.setting.windowType) ? '实时预览窗口' : '录像回放窗口'}创建成功 hwnd: ${hwnd}\n插件版本: ${window.dhPlayerControl.DHPlayerVersion}`);
+ that.setting.hwnd = hwnd
+ window.dhPlayerControl.videoList[that.setting.videoId].setting = that.setting
+ window.dhPlayerControl.hwndList[hwnd] = that.setting.videoId
+ }
+ that.setTopBind = that.setTop.myBind(that)
+ window.addEventListener('beforeunload', that.onbeforeunloadBind)
+ document.addEventListener('click', that.setTopBind)
+ that.handleAdjust()
+ let i = 0
+ while (i <= 3) {
+ that.setting.oldPosition = ''
+ that.setting.oldShield = ''
+ that.changePosition()
+ i++
+ }
+ that.setTabControlBtn()
+ that.setWindowDragEnable()
+ that.setWindowBorder(that.setting.showBorder)
+ // 初始化的时候手动调用show方法,避免出现播放器不显示的问题
+ // 前提条件: 保证在当前页面上时触发,否则不触发。
+ document.visibilityState === 'visible' ? that.show() : that.hide()
+ document.addEventListener('visibilitychange', that.visibilitychangeBind, true)
+ // 是否是插件内部鉴权,是的话则先登录
+ if(that.setting.usePluginLogin) {
+ if(window.dhPlayerControl.loginFlag === "LOGIN_SUCCESS") {
+ that.setting.createSuccess && that.setting.createSuccess(getVersionInfo())
+ } else if(window.dhPlayerControl.loginFlag === "LOGIN_ERROR"){
+ that.setting.createError && that.setting.createError({
+ code: 1004,
+ msg: "登录失败, 请检查登录信息",
+ i18nKey: "dhplayer.login.failed"
+ })
+ }
+ }else {
+ that.setting.createSuccess && that.setting.createSuccess(getVersionInfo())
+ }
+ },
+ onError: function () {
+ // 断开连接
+ socketClose();
+ // 重连
+ let socketTimer = setTimeout(() => {
+ socketOpen();
+ clearTimeout(socketTimer)
+ }, 3000)
+ // that.setting.createError && that.setting.createError({
+ // code: 1006,
+ // data: null,
+ // message: '插件创建失败,刷新重试',
+ // success: false
+ // })
+ }
+ }
+ )
+ })
+ },
+
+ /**
+ * @name 设置语言
+ * @param language zh-中文 en-英文
+ * */
+ setLanguage(language) {
+ return new Promise((resolve, reject) => {
+ this.send({
+ method: "common.updateLanguage",
+ info:{
+ LanguageType: language || this.setting.language || (localStorage.language === 'en' ? 'en' : 'zh') ,
+ }
+ }, {
+ onSuccess: () => {
+ resolve()
+ }
+ })
+ })
+ },
+ // 设置播放器上方的操作按
+ setTabControlBtn(btnList, snum) {
+ // let showBtn = ["BTN_STREAM", "BTN_PTZ", "BTN_QUICKPLAY", "BTN_VOICE", "BTN_TALK", "BTN_RECORD", "BTN_PIC", "BTN_ENLARGE", "BTN_CLOSE"]
+ let showBtn = ["BTN_STREAM", "BTN_VOICE", "BTN_TALK", "BTN_RECORD", "BTN_PIC", "BTN_ENLARGE", "BTN_CLOSE"]
+ this.send({
+ method: "video.toolbar.showButton",
+ info: {
+ space: 15,
+ snum,
+ btns: btnList || showBtn
+ }
+ })
+ },
+ // 判断当前浏览器是否在tab页面上
+ setVisible() {
+ document.visibilityState == 'hidden' ? this.hide() : this.show()
+ },
+ //页面聚焦
+ setTop() {
+ this.focus = true
+ document.visibilityState == 'visible' && this.browserFocusBlur()
+ },
+ browserFocusBlur: function () {
+ this.send({
+ method: 'browserFocusBlur',
+ info: {
+ show: this.setting.show,
+ focus: this.focus
+ }
+ })
+ },
+ //刷新窗口位置
+ handleAdjust: function () {
+ var _this = this
+ // 每帧执行一次,减少DHplayer延时
+ !this.setting.stopRefresh && this.changePosition()
+ !this.setting.stopRefresh && this.windowShield(this.cover())
+
+ // 实时判断 dom 元素是否可见
+ let el = document.getElementById(this.setting.videoId);
+ if (this.setting.domVisible !== isDomVisible(el)) {
+ this.setting.domVisible ? this.hide() : this.show()
+ this.setting.domVisible = isDomVisible(el)
+ }
+ this.setting.refreshTimer = window.requestAnimationFrame(function () {
+ return _this.handleAdjust()
+ })
+ },
+ removeClickEventListener: function () {
+ document.removeEventListener('click', this.setTopBind)
+ },
+ addClickEventListener: function () {
+ document.addEventListener('click', this.setTopBind)
+ },
+ /**
+ * 销毁当前播放器
+ * @param isRefresh 表示页面刷新或者关闭情况
+ * @return Promise对象
+ */
+ destroy: function (isRefresh = false) {
+ return new Promise((resolve, reject) => {
+ let that = window.dhPlayerControl.videoList[this.setting.videoId]
+ if (!that || (that.setting && typeof that.setting.hwnd !== 'number')) {
+ resolve()
+ } else {
+ this.send({
+ method: 'window.destroy',
+ info: {
+ hwnd: that.setting.hwnd,
+ isRefresh
+ }
+ }, {
+ onSuccess: () => {
+ document.removeEventListener('click', this.setTopBind)
+ document.removeEventListener('visibilitychange', this.visibilitychangeBind, true)
+ window.removeEventListener('beforeunload', this.onbeforeunloadBind)
+ console.log(`销毁成功, hwnd: ${that.setting.hwnd}`);
+ resolve()
+ },
+ onError: () => {
+ document.removeEventListener('click', this.setTopBind)
+ document.removeEventListener('visibilitychange', this.visibilitychangeBind, true)
+ window.removeEventListener('beforeunload', this.onbeforeunloadBind)
+ console.log(`销毁成功, hwnd: ${that.setting.hwnd}`);
+ resolve()
+ }
+ })
+ }
+ })
+ },
+ /**
+ * 设置水印
+ * @param { Object } option 参数
+ * @param { Number } snum 窗口数量
+ * @param { String } item.color 水印颜色
+ * @param { Number } item.fontSize 水印尺寸
+ * @param { Number } item.fontWeight 字体粗细
+ * @param { String } item.position 水印位置
+ * @param { Number } item.text 文本
+ */
+ waterMark: function (option) {
+ option.forEach(item => {
+ let rgb = item.color.split(',');
+ let position = item.position.split(',');
+ this.send({
+ method: 'video.setOSDInfo',
+ info: {
+ snum: item.snum,
+ R: rgb[0] || 255,
+ G: rgb[1] || 255,
+ B: rgb[2] || 255,
+ fontSize: item.fontSize || 14,
+ positionX: position[0] || 1,
+ positionY: position[1] || 1,
+ osdInfo: item.text || '',
+ fontWeight: item.fontWeight || 0
+ },
+ })
+ })
+ },
+ // 设置窗口是否支持拖拽
+ setWindowDragEnable: function () {
+ this.send({
+ method: 'window.enableDrag',
+ info: {
+ enable: this.setting.draggable
+ }
+ })
+ },
+ // 设置全屏
+ setFullScreen: function () {
+ this.send({
+ method: 'video.fullScreen',
+ info: {}
+ })
+ },
+ /**
+ * 设置窗口边框
+ * @param {*} showBorder true-显示边框 false-不显示边框
+ */
+ setWindowBorder: function (showBorder) {
+ this.setting.showBorder = showBorder
+ this.send({
+ method: 'window.videoWndFrameLine',
+ info: {
+ enable: this.setting.showBorder
+ }
+ })
+ },
+ /**
+ * @method chooseWindow 支持用户选择子窗口
+ * @param { Number } snum 选择的子窗口,从0开始
+ * @param { Function } cb 选中窗口回调
+ */
+ chooseWindow: function (snum, cb) {
+ this.send({
+ method: 'window.select',
+ info: {
+ snum
+ }
+ })
+ cb && cb(this.setting.channelList.filter(item => item.snum === snum)[0])
+ },
+ /**
+ * @method openAudio 开启、关闭声音
+ * @param { Number } option.isEnable 0-关闭,1-开启
+ * @param { Number } option.snum 选择的子窗口,从0开始
+ */
+ openAudio: function (option) {
+ this.send({
+ method: 'video.enableAudio',
+ info: {
+ snum: option.snum,
+ isEnable: option.isEnable,
+ videoType: Number(this.setting.windowType) === 0 ? 0 : 1, // 0-预览音频,1-回放音频
+ }
+ })
+ },
+
+ /**
+ * @method startReal 实时预览集成
+ * @param { Array } option
+ * @param { String } item.channelId 通道Id (必传)
+ * @param { String } item.channelName 通道名称(目前用于本地录像下载)
+ * @param { Number } item.streamType 码流类型 1 主码流 2 辅码流 (默认主码流)
+ * @param { Number } item.dataType 音视频类型 1-视频 2-音频 3-音视频 (默认视频)
+ * @param { Number } item.deviceType 设备类别(用于对讲)
+ * @param { Number } item.gbDevice 是否国标接入或国标级联(用于对讲)
+ * @param { Number|String } item.cameraType 摄像头类型(用于云台)
+ * @param { Number } item.capability 能力集(用于云台)
+ * @param { Boolean } isReOpen 是否断线重连
+ * @param { Boolean } isSubStream 主辅码流切换 true 是 false 否
+ * @param { String } deviceCode: option.channelId.split('$1$0$')[0],
+ * @param { String } deviceType: option.deviceType,
+ * @param { Number } talkType: getTalkType(option.deviceType),
+ */
+ startReal: function (option, { isReOpen, isSubStream, count } = {}, type = 'real') {
+ let tempList = []
+ // 切换窗口数
+ let maxNum = option.map(item => item.snum + 1).sort((a, b) => b - a)[0]
+ if (maxNum > 64) {
+ this.setting.realError && this.setting.realError(item, {
+ code: 209,
+ i18nKey: 'video.player.support.max',
+ maxNum: maxNum,
+ message: '最大只支持64路播放'
+ })
+ }
+ if (!isNaN(this.setting.division) && this.setting.division < maxNum) {
+ this.changeDivision(maxNum)
+ }
+ option.forEach(item => {
+ let flag = false
+ this.setting.channelList = this.setting.channelList.map(realItem => {
+ if (realItem.snum === item.snum) {
+ flag = true
+ return { ...item, closed: true } // close标识位:表示外部主动删除
+ }
+ return realItem
+ })
+ if (!flag) {
+ tempList.push({ ...item })
+ }
+
+ // 如果有视频的关闭则优先关闭视频
+ let playVideo = () => {
+ // 如果是插件登录
+ if (this.setting.usePluginLogin) {
+ this.realByUrl({
+ ...item,
+ path: '',
+ }, { isReOpen, isSubStream, count }, true)
+ return
+ } else {
+ if (!this.setting.request[type]) {
+ this.setting.realError && this.setting.realError(item, {
+ code: 207,
+ i18nKey: 'video.player.please.afferent.interface.real',
+ message: '请通过 request 属性传入实时预览接口'
+ })
+ return
+ }
+ this.setting.request[type](getAjaxParam(item, type)).then(res => {
+ if (res.url) {
+ this.realByUrl({
+ ...item,
+ path: dealUrl(res),
+ }, { isReOpen, isSubStream, count }, true)
+ }
+ }).catch(err => {
+ this.setting.channelList = this.setting.channelList.filter(realItem => realItem.snum !== item.snum)
+ this.setting.realError && this.setting.realError(item, err)
+ })
+ }
+ }
+
+ if (!isReOpen && !isSubStream && flag) {
+ this.closeVideo(item.snum).then(() => {
+ playVideo()
+ })
+ return
+ }
+ playVideo()
+ })
+ this.setting.channelList = [...this.setting.channelList, ...tempList]
+ // 强绑定
+ window.dhPlayerControl.videoList[this.setting.videoId].setting.channelList = [...this.setting.channelList]
+ },
+ /**
+ * @method realByUrl 通过rtsp流地址进行实时预览
+ * @param { Number } option.snum 选择的子窗口,从0开始
+ * @param { String } option.channelId 通道id
+ * @param { String } option.channelName 通道名称(目前用于本地录像下载)
+ * @param { String } option.path rtsp地址
+ * @param { Boolean } option.redirect 重定向,默认false (拼接地址需要改为true,接口返回地址为false)
+ * @param { String } option.cameraType 云台使用,相机类型 【暂不使用】
+ * @param { Number } option.decodeMode 解码模式 软解-0 硬解-1 快速硬解-2 [默认快速硬解]
+ * @param { Boolean } isSubStream 是否为主辅码流切换,true 表示是 false表示否
+ * @param { Boolean } isReOpen 是否为实时预览断线重连
+ * @param { Boolean } count 当前是第几次重连
+ */
+ realByUrl: function (option, { isSubStream, isReOpen, count } = {}, isProj) {
+ let sendVideo = () => {
+ this.send({
+ method: 'video.realmonitor',
+ info: {
+ snum: option.snum,
+ path: option.path,
+ channelId: option.channelId,
+ channelName: option.channelName || '',
+ redirect: typeof option.redirect === 'boolean' ? option.redirect : false,
+ camerType: option.cameraType,
+ decodeMode: typeof option.decodeMode === 'number' ? option.decodeMode : 2,
+ bStreamChange: !!isSubStream,
+ reopenvideo: !!isReOpen,
+ streamType: option.streamType || 1,
+ count,
+ deviceCode: option.channelId && option.channelId.split('$1$0$')[0] || '',
+ deviceType: option.deviceType,
+ talkType: getTalkType(option.deviceType),
+ }
+ })
+ }
+ // 非集成情况
+ if (!isProj) {
+ let index = this.setting.channelList.findIndex(item => item.snum === option.snum)
+ if (index >= 0) {
+ this.setting.channelList[index] = { ...option, byUrl: true, closed: true }
+ } else {
+ this.setting.channelList.push({ ...option, byUrl: true })
+ }
+ // 强绑定
+ window.dhPlayerControl.videoList[this.setting.videoId].setting.channelList = [...this.setting.channelList];
+ if (!isReOpen && !isSubStream) {
+ this.closeVideo(option.snum).then(() => {
+ sendVideo()
+ })
+ }
+ return
+ }
+ let timer = setInterval(() => {
+ clearInterval(timer)
+ if(this.setting.hwnd >= 0) {
+ sendVideo()
+ } else {
+ this.realByUrl(option, { isSubStream, isReOpen, count }, isProj)
+ }
+ }, 200)
+ },
+ /**
+ * @method startTalk 对讲集成
+ * @param { Number } snum 选择的子窗口,从0开始
+ */
+ startTalk: async function (snum = 0, type = 'talk') {
+ let talkIndex = this.setting.channelList.findIndex(item => item.snum === snum)
+ if (talkIndex < 0) {
+ return this.setting.talkError(talkParam, {
+ code: 206,
+ i18nKey: 'video.player.current.window.no.live.view',
+ message: '请先调用实时预览接口'
+ })
+ }
+ let talkParam = this.setting.channelList[talkIndex]
+ let param = getAjaxParam(talkParam, type).data
+ if (!this.setting.request[type]) {
+ this.setting.talkError && this.setting.talkError(talkParam, {
+ code: 207,
+ i18nKey: 'video.player.please.afferent.interface.talk.and.stopTalk',
+ message: '请通过 request 属性传入对讲接口和停止对讲接口'
+ })
+ return
+ }
+ this.setting.request[type]({ data: param }).then(res => {
+ talkParam.session = res.session
+ // 保证所有参数都统一
+ let { audioBit, audioType, sampleRate } = res
+ talkParam.isTalk = true
+ this.talkByUrl({
+ redirect: false,
+ audioBit,
+ audioType,
+ sampleRate,
+ path: dealUrl(res),
+ channelId: talkParam.channelId,
+ talkType: getTalkType(talkParam.deviceType),
+ gbDevice: typeof res.gbDevice !== undefined && Boolean(res.gbDevice) || Boolean(talkParam.gbDevice),
+ snum
+ })
+ }).catch(err => {
+ this.setting.talkError && this.setting.talkError(talkParam, err)
+ })
+ },
+
+ /**
+ * @method talkByUrl 通过rtsp流进行对讲
+ * @param { Number } option.snum 窗口号
+ * @param { String } option.channelId 通道id
+ * @param { String } option.path rtsp地址
+ * @param { Number } option.audioType 音频类型 0-default 1-PCM 2-G711a 3-AMR 4-G711U 5-G726 6-AAC 7-G722 8-G711
+ * @param { Number } option.audioBit 位数 8 、16
+ * @param { Number } option.sampleRate 采样频率 8000、16000、32000、48000、8192
+ * @param { Number } option.talkType 对讲类型 1-设备 2-通道
+ * @param { Boolean } option.gbDevice 是否是国标设备
+ */
+ talkByUrl: function (option) {
+ // 发送对讲
+ this.send({
+ method: 'video.starttalk',
+ info: {
+ snum: option.snum,
+ path: option.path,
+ channelId: option.channelId,
+ redirect: false, // 写死
+ audioType: option.audioType,
+ audioBit: option.audioBit,
+ sampleRate: option.sampleRate,
+ talkType: option.talkType,
+ gbDevice: option.gbDevice
+ }
+ })
+ },
+
+ /**
+ * @method startPlayback 录像回放集成
+ * @param { Array } option
+ * @param { String } item.channelId 通道Id
+ * @param { String } item.channelName 通道名称(目前用于本地录像下载)
+ * @param { String } item.name 通道名称
+ * @param { Number } item.streamType 码流类型 0 所有码流 1 主码流 2 辅码流 (默认所有码流)
+ * @param { String } item.startTime 开始时间 '2022-10-26 00:00:00'
+ * @param { String } item.endTime 结束时间 '2022-10-26 23:59:59'
+ * @param { Number } item.recordSource 录像类型 2-设备录像 3-中心录像
+ * @param { Number } option.snum 窗口号
+ * @param { Boolean } isConnect 是否拖拽/播放下一段录像
+ * @param { Boolean } bContinue 是否为播放下一段录像(用于告诉客户端)
+ * @param { Boolean } scaleSteps 当前录像进度条的显示状态
+ */
+ startPlayback: function (option, { isConnect, bContinue, scaleSteps } = {}) {
+ let timeFormatter = (time) => {
+ return parseInt(new Date(time).getTime() / 1000)
+ }
+ let getPlayBackRtsp = (param) => {
+ if (Number(param.recordSource) === 3 || Number(param.recordSource === 4)) {
+ // 中心录像-按文件
+ getPlayBackRtspByFile.call(this, param, isConnect).then(res => {
+ if (res.code === 201) {
+ return this.setting.playbackError && this.setting.playbackError(param, res)
+ }
+ param.endTime = Number(param.records[param.records.length - 1].endTime)
+ this.playbackByUrl({
+ ...param,
+ path: res.rtspUrl,
+ records: res.records,
+ redirect: false,
+ bContinue,
+ scaleSteps,
+ isLastFile: param.currentIndex === res.records.length - 1
+ }, true)
+ }).catch(err => {
+ this.setting.playbackError && this.setting.playbackError(param, err)
+ })
+ } else if (Number(param.recordSource) === 2) {
+ // 设备录像-按时间
+ getPlayBackRtspByTime.call(this, param).then(res => {
+ param.endTime = Number(param.records[param.records.length - 1].endTime)
+ this.playbackByUrl({
+ ...param,
+ path: res.rtspUrl,
+ records: res.records,
+ redirect: false,
+ bContinue,
+ scaleSteps,
+ isLastFile: param.currentIndex === res.records.length - 1
+ }, true)
+ }).catch(err => {
+ this.setting.playbackError && this.setting.playbackError(param, err)
+ })
+ } else if (Number(param.recordSource) === 1) {
+ // 自动识别
+ queryRecord.call(this, param)
+ .then(() => {
+ let recordSource = param.records[0].recordSource
+ param.recordSource = Number(recordSource)
+ if (Number(recordSource) === 3 || Number(recordSource) === 4) {
+ // 中心录像-按文件
+ getPlayBackRtspByFile.call(this, param, isConnect).then(res => {
+ if (res.code === 201) {
+ return this.setting.playbackError && this.setting.playbackError(param, res)
+ }
+ param.endTime = Number(param.records[param.records.length - 1].endTime)
+ this.playbackByUrl({
+ ...param,
+ path: res.rtspUrl,
+ records: res.records,
+ redirect: false,
+ bContinue,
+ scaleSteps,
+ isLastFile: param.currentIndex === res.records.length - 1
+ }, true)
+ }).catch(err => {
+ this.setting.playbackError && this.setting.playbackError(param, err)
+ })
+ }
+ if (Number(recordSource) === 2) {
+ // 设备录像-按时间
+ getPlayBackRtspByTime.call(this, param).then(res => {
+ param.endTime = Number(param.records[param.records.length - 1].endTime)
+ this.playbackByUrl({
+ ...param,
+ path: res.rtspUrl,
+ records: res.records,
+ redirect: false,
+ bContinue,
+ scaleSteps,
+ isLastFile: param.currentIndex === res.records.length - 1
+ }, true)
+ }).catch(err => {
+ this.setting.playbackError && this.setting.playbackError(param, err)
+ })
+ }
+ }).catch(err => {
+ this.setting.playbackError && this.setting.playbackError(param, err)
+ })
+ } else {
+ this.setting.playbackError && this.setting.playbackError(
+ param,
+ {
+ code: 404,
+ i18nKey: 'video.player.only.play.device.and.center.recordings',
+ message: '只能播放设备录像和中心录像!'
+ })
+ }
+ }
+ if (isConnect) {
+ getPlayBackRtsp(option)
+ } else {
+ let channelList = []
+ // 切换窗口数
+ let maxNum = option.map(item => item.snum + 1).sort((a, b) => b - a)[0]
+ if (!isNaN(this.setting.division) && this.setting.division < maxNum) {
+ this.changeDivision(maxNum)
+ }
+ option.forEach(item => {
+ // 对时间做格式化处理
+ item.startTime = timeFormatter(item.startTime)
+ item.endTime = timeFormatter(item.endTime)
+ // 如果开始时间大于结束时间,则调换位置
+ if (item.startTime > item.endTime) {
+ let tempTime = item.startTime
+ item.startTime = item.endTime
+ item.endTime = tempTime
+ }
+ item.bBack = 0
+ let flag = true
+ this.setting.channelList.forEach((oItem, oIndex) => {
+ if (oItem.snum === item.snum) {
+ flag = false
+ this.setting.channelList[oIndex] = { ...item, closed: true }
+ this.closeVideo(item.snum).then(() => {
+ // 播放视频
+ if (this.setting.usePluginLogin) {
+ this.playbackByUrl({
+ ...item,
+ path: '',
+ records: [],
+ redirect: false,
+ bContinue,
+ scaleSteps
+ }, true)
+ } else {
+ getPlayBackRtsp({ ...item })
+ }
+ })
+ }
+ })
+ if (flag) {
+ channelList.push({ ...item })
+ }
+ })
+ channelList.forEach(item => {
+ if (this.setting.usePluginLogin) {
+ this.playbackByUrl({
+ ...item,
+ path: '',
+ records: [],
+ redirect: false,
+ bContinue,
+ scaleSteps
+ }, true)
+ } else {
+ getPlayBackRtsp({ ...item })
+ }
+ })
+ this.setting.channelList = [...this.setting.channelList, ...channelList]
+ // 强绑定
+ window.dhPlayerControl.videoList[this.setting.videoId].setting.channelList = [...this.setting.channelList]
+ }
+ },
+
+ /**
+ * @method playbackByUrl 通过rtsp录像回放
+ * @param { Number } option.snum 选择的子窗口,从0开始
+ * @param { String } option.channelId 通道id
+ * @param { String } option.channelName 通道名称(目前用于本地录像下载)
+ * @param { String } option.path rtsp地址
+ * @param { Array } option.records 包含某个时间段的录像文件信息
+ * @param { Date } option.startTime 时间相关均为时间戳(new Date().getTime() / 1000)
+ * @param { Date } option.endTime 时间相关均为时间戳(new Date().getTime() / 1000)
+ * @param { Number } option.recordSource 录像类型 2-设备录像 3-中心录像 4-统一云
+ * @param { Number } option.decodeMode 解码模式 软解-0 硬解-1 快速硬解-2 [默认快速硬解]
+ * @param { Boolean } option.redirect 重定向,默认false (拼接地址需要改为true,接口返回地址为false)
+ * @param { Boolean } option.bContinue 是否继续播放录像 true-是 false-否
+ * @param { Boolean } bContinue 是否续播
+ * @param { Number } scaleSteps 录像进度条样式
+ * @param { Boolean } isLastFile 是否为最后一段录像?
+ */
+ playbackByUrl: function (option, isProj) {
+ // 非集成情况
+ if (!isProj) {
+ let index = this.setting.channelList.findIndex(item => item.snum === option.snum)
+ if (index >= 0) {
+ this.setting.channelList[index] = { ...option, byUrl: true }
+ } else {
+ this.setting.channelList.push({ ...option, byUrl: true })
+ }
+ }
+ this.send({
+ method: 'video.playback',
+ info: {
+ snum: option.snum,
+ path: option.path,
+ records: option.records,
+ startTime: option.startTime,
+ endTime: option.endTime,
+ recordSource: option.recordSource,
+ playStartTime: option.playStartTime || option.startTime,
+ playEndTime: option.playEndTime || option.endTime,
+ currentPlayTime: option.currentPlayTime || option.playStartTime,
+ channelId: option.channelId,
+ channelName: option.channelName || option.name || '',
+ decodeMode: typeof option.decodeMode === 'number' ? option.decodeMode : 2,
+ redirect: typeof option.redirect === 'boolean' ? option.redirect : false,
+ bBack: option.bBack || 0,
+ bContinue: !!option.bContinue,
+ scaleSteps: option.scaleSteps || 0,
+ lastFile: !!option.isLastFile
+ }
+ })
+ },
+ /**
+ * @method startDownloadRecord 开始下载录像-集成
+ * @param {*} option 参数同 startPlayback 方法
+ */
+ startDownloadRecord: function (option) {
+ let timeFormatter = (time) => {
+ return parseInt(new Date(time).getTime() / 1000)
+ }
+ let getPlayBackRtsp = (param) => {
+ if (Number(param.recordSource) === 3 || Number(param.recordSource) === 4) {
+ // 中心录像-按文件
+ getPlayBackRtspByFile.call(this, param).then(res => {
+ if (res.code === 201) {
+ return this.setting.downloadError && this.setting.downloadError(param, res)
+ }
+ param.endTime = Number(param.records[param.records.length - 1].endTime)
+ this.downloadRecord({
+ snum: param.snum,
+ url: res.rtspUrl,
+ records: res.records,
+ startTime: param.startTime,
+ endTime: param.endTime,
+ })
+ }).catch(err => {
+ this.setting.downloadError && this.setting.downloadError(param, err)
+ })
+ } else if (Number(param.recordSource) === 2) {
+ // 设备录像-按时间
+ getPlayBackRtspByTime.call(this, param).then(res => {
+ param.endTime = Number(param.records[param.records.length - 1].endTime)
+ this.downloadRecord({
+ snum: param.snum,
+ url: res.rtspUrl,
+ records: res.records,
+ startTime: param.startTime,
+ endTime: param.endTime,
+ })
+ }).catch(err => {
+ this.setting.downloadError && this.setting.downloadError(param, err)
+ })
+ } else {
+ this.setting.downloadError && this.setting.downloadError(
+ param,
+ {
+ code: 404,
+ i18nKey: 'video.player.only.download.device.and.center.recordings',
+ message: '只能下载设备录像和中心录像!'
+ })
+ }
+ }
+ if (option.length > 4) {
+ return this.setting.downloadError({
+ code: 401,
+ i18nKey: 'video.player.download.recordings.max',
+ message: "最多支持4路录像同时下载"
+ });
+ }
+ option.forEach(item => {
+ // 对时间做格式化处理
+ item.startTime = timeFormatter(item.startTime)
+ item.endTime = timeFormatter(item.endTime)
+ // 如果开始时间大于结束时间,则调换位置
+ if (item.startTime > item.endTime) {
+ let tempTime = item.startTime
+ item.startTime = item.endTime
+ item.endTime = tempTime
+ }
+ item.bBack = 0
+ getPlayBackRtsp(item)
+ })
+ },
+ /**
+ * 处理DHPlayer位置
+ * @param {*} option
+ * @param {*} callBack
+ * @returns
+ */
+ changePosition: function (option, callBack) {
+ var windowSize = getWindowSize.call(this)
+ var zoom = detectZoom()
+ var rect = getRect.call(this)
+ for (let i in rect) {
+ rect[i] = (rect[i] * zoom) / 100
+ }
+ var _info = Object.assign({}, {}, rect, option)
+ _info.clientAreaHeight = (windowSize.height * zoom) / 100
+ _info.clientAreaWidth = (windowSize.width * zoom) / 100
+ _info.browserScreenX = getScreenX()
+ // 暂时用不到
+ _info.screenX = window.screenX
+ _info.screenY = window.screenY
+ // 火狐需要传的内容
+ if (!window.dhPlayerControl.isPIframe) {
+ _info.mozInnerScreenX = (window.top.mozInnerScreenX * zoom) / 100
+ _info.mozInnerScreenY = (window.top.mozInnerScreenY * zoom) / 100
+ } else {
+ _info.mozInnerScreenX = (this.setting.topMozInnerScreenX * zoom) / 100
+ _info.mozInnerScreenY = (this.setting.topMozInnerScreenY * zoom) / 100
+ }
+ delete _info.width
+ delete _info.height
+ _info.show = document.visibilityState === 'hidden' ? false : true
+ _info.title = window.dhPlayerControl.isPIframe ? this.setting.documentTitle : window.top.document.title
+ let sendPosition = () => {
+ this.send(
+ {
+ method: 'window.change',
+ info: _info
+ },
+ callBack
+ )
+ }
+ // 位置改变后就触发遮挡
+ if (this.setting.oldPosition === JSON.stringify(_info)) {
+ // 位置固定后,改变三次位置,强制触发三次遮挡,处理位置偏移问题。
+ while (this.adjustCount < 3) {
+ this.adjustCount++
+ sendPosition()
+ this.windowShield(this.cover(), true)
+ }
+ return
+ }
+ // 位置发生改变,强制触发遮挡事件
+ this.adjustCount = 0
+ this.setting.oldPosition = JSON.stringify(_info)
+ sendPosition()
+ },
+ // 隐藏视频
+ hide: function () {
+ this.setting.show = false
+ this.setting.stopRefresh = true
+ this.send({
+ method: 'window.show',
+ info: {
+ show: false
+ }
+ })
+ },
+ //显示视频
+ show: function () {
+ var that = this
+ this.setting.stopRefresh = false
+ this.setting.show = true
+ this.send({
+ method: 'window.show',
+ info: {
+ show: true
+ }
+ },
+ {
+ onSuccess: function () {
+ if (that.setting.refreshTimer) {
+ window.cancelAnimationFrame(that.setting.refreshTimer)
+ }
+ that.setting.oldPosition = ""
+ that.handleAdjust()
+ that.setting.showWindowSuccess && that.setting.showWindowSuccess()
+ },
+ onError: this.setting.showWindowError
+ }
+ )
+ },
+
+ /**
+ * @method downloadRecord 录像下载
+ * @param { Object } option
+ * @param { Number } option.snum 选择的子窗口,从0开始
+ * @param { String } option.url 下载地址
+ * @param { Array } option.records 包含某个时间段的录像文件信息
+ * @param { Number } option.startTime 时间相关均为时间戳,具体参考大华播放控件开发手册
+ * @param { Number } option.endTime 时间相关均为时间戳,具体参考大华播放控件开发手册
+ * @param { Boolean } option.redirect 默认 false
+ */
+ downloadRecord: function (option) {
+ this.send({
+ method: 'video.downloadByTime',
+ info: {
+ channelId: option.channelId,
+ snum: option.snum,
+ url: option.url,
+ records: option.records,
+ startTime: option.startTime,
+ endTime: option.endTime,
+ redirect: typeof option.redirect === 'boolean' ? option.redirect : false
+ }
+ })
+ },
+ /**
+ * @method closeVideo 关闭指定窗口视频或全部关闭
+ * @param { Number } option.snum 选择的子窗口, 不传默认全部关闭
+ */
+ closeVideo: function (snum) {
+ return new Promise((resolve) => {
+ this.send({
+ method: 'video.close',
+ info: {
+ snum: typeof snum === 'number' ? snum : 0,
+ isAll: typeof snum === 'number' ? false : true
+ }
+ }, {
+ onSuccess: function() {
+ resolve()
+ }
+ })
+ })
+ },
+ /**
+ * @method closeTalk 关闭对讲
+ */
+ closeTalk: function () {
+ this.send({
+ method: 'video.closetalk',
+ info: {
+ snum: 0,
+ isAll: true
+ }
+ })
+ },
+ /**
+ * @method continuePlayback 操作录像
+ * @param { Number } option.snum 选择的子窗口,从0开始
+ * @param { Number } option.state 窗口状态:0-暂停,1-继续
+ */
+ controlPlayback: function (option) {
+ this.send({
+ method: 'video.playbackChangeState',
+ info: {
+ snum: option.snum,
+ state: option.state
+ }
+ })
+ },
+
+ //显示下方控制栏, show: true-显示,false-隐藏
+ showControlBar: function (show = true) {
+ this.setting.showBar = show
+ this.send({
+ method: 'video.setToolBarShow',
+ info: {
+ isShow: show ? 1 : 0
+ }
+ })
+ },
+ /**
+ * @method continuePlayback 本地录像下载
+ * @param { Number } snum 选择的子窗口,从0开始
+ */
+ localRecordDownload: function (snum) {
+ this.send({
+ method: 'vidoe.localRecord',
+ info: {
+ snum
+ }
+ })
+ },
+ /**
+ * @method video.division.change 切换当前控件展示的窗口数量
+ * @param {*} division 当前控件展示的窗口数量
+ * @param {String} 分割窗口数类型 normal-正常 custom-自定义
+ * @desc 代码手动调用该方法没有提供回调,此处添加回调
+ */
+ changeDivision: function (info) {
+ if (info) {
+ // 自定义的情况
+ if (isNaN(info)) {
+ this.setting.division = info
+ this.send({
+ method: 'video.customDivision.change',
+ info: JSON.parse(info)
+ })
+ this.setting.changeDivision && this.setting.changeDivision(info)
+ } else {
+ this.setting.division = Number(info)
+ this.send({
+ method: "video.division.change",
+ info: {
+ "division": this.setting.division
+ }
+ })
+ this.setting.changeDivision && this.setting.changeDivision(this.setting.division)
+ }
+ this.setWindowDragEnable()
+ }
+ },
+ //窗口抓图
+ snapshot: function (snum) {
+ this.send({
+ method: 'video.snapic',
+ info: {
+ snum
+ }
+ })
+ },
+ // 视频被遮挡处理
+ windowShield: function (option, flag, callBack) {
+ var windowSize = getWindowSize.call(this)
+ var zoom = detectZoom()
+ var _info = {}
+ _info.region = this.getShieldRect(option).map(item => item * zoom / 100)
+ _info.clientAreaHeight = (windowSize.height * zoom) / 100
+ _info.clientAreaWidth = (windowSize.width * zoom) / 100
+ if (!flag && this.setting.oldShield === JSON.stringify(_info)) {
+ return
+ }
+ this.setting.oldShield = JSON.stringify(_info)
+ this.send(
+ {
+ method: 'window.shield',
+ info: _info
+ },
+ callBack
+ )
+ },
+ // 视频插件版本号
+ version: function (callBack) {
+ this.send({
+ method: 'common.version',
+ info: {}
+ },
+ callBack
+ )
+ },
+ /**
+ * 视频是否显示规划线
+ * @param { Object } option
+ * @param { Number } snum 窗口号
+ * @param { isEnableIVS } 是否显示规则框 true-显示 false-隐藏
+ * @param { ivsType } 规则框类型 1-智能规则框,2-智能目标框 (不传默认为1) 7-辅助帧
+ */
+ isEnableIvs: function (option) {
+ this.send({
+ method: 'video.enableIvs',
+ info: {
+ snum: option.snum,
+ isEnableIVS: option.isEnableIVS,
+ ivsType: option.ivsType
+ },
+ })
+ },
+
+ getWindowState: function (callBack) {
+ this.send({
+ method: 'window.getWindowState',
+ info: {},
+ },
+ callBack
+ )
+ },
+ // 防止插件超出浏览器显示
+ cover: function () {
+ var rect = getRect.call(this)
+ var left = rect.left,
+ top = rect.top,
+ right = rect.right,
+ bottom = rect.bottom,
+ width = rect.width,
+ height = rect.height,
+ arr = [],
+ windowSize = getWindowSize.call(this)
+
+ let shieldFn = (domSize) => {
+ if (domSize && domSize[0]) {
+ // 超过上方则遮挡
+ if (top < domSize[0].top) {
+ arr.push(left, top, width + 1, domSize[0].top - top)
+ }
+ // 超过下方则遮挡
+ if (bottom > domSize[0].bottom) {
+ arr.push(left, domSize[0].bottom, width + 1, bottom - domSize[0].bottom)
+ }
+ // 左侧遮挡
+ if (left < domSize[0].left) {
+ arr.push(left, top, domSize[0].left - left + 1, height)
+ }
+ // 右侧遮挡
+ if (right > domSize[0].right) {
+ arr.push(domSize[0].right, top, right - domSize[0].right + 1, height)
+ }
+ }
+ }
+ // 处理有iframe下, 超出最外侧body遮挡的问题
+ shieldFn([
+ {
+ top: 0,
+ left: 0,
+ right: windowSize.width,
+ bottom: windowSize.height
+ }
+ ])
+ // 处理当前window下的遮挡问题
+ let pOutContent, outLeft, outTop
+ if (window.dhPlayerControl.isPIframe) {
+ pOutContent = this.setting.pIframeRect
+ outLeft = pOutContent.left
+ outTop = pOutContent.top
+ } else {
+ var iframes = window.parent.document.getElementsByTagName('iframe')
+ var pIframe = null
+ var dom = null
+ let getpIframe = (index) => {
+ if (!iframes[index]) return
+ try {
+ dom = iframes[index].contentWindow.document.getElementById(this.setting.videoId)
+ if (dom) {
+ pIframe = iframes[index]
+ } else {
+ getpIframe(index + 1)
+ }
+ } catch (err) {
+ getpIframe(index + 1)
+ }
+ }
+ iframes.length && getpIframe(0)
+ if (pIframe) {
+ pOutContent = pIframe.getBoundingClientRect()
+ }
+ }
+ pOutContent && shieldFn([{
+ top: pOutContent.top,
+ left: pOutContent.left,
+ right: pOutContent.left + pOutContent.width,
+ bottom: pOutContent.top + pOutContent.height
+ }])
+ // 处理DOM元素遮挡问题,主要用于滚动页面,超出隐藏的问题
+ if (this.setting.coverShieldClass && this.setting.coverShieldClass.length) {
+ this.setting.coverShieldClass.forEach((item) => {
+ let dom = document.getElementsByClassName(item)[0]
+ let domSize = dom ? dom.getClientRects() : null
+ domSize = [
+ {
+ left: domSize[0].left,
+ top: domSize[0].top,
+ bottom: domSize[0].bottom,
+ right: domSize[0].right
+ }
+ ]
+ if (pOutContent) {
+ domSize[0].left = domSize[0].left + pOutContent.left
+ domSize[0].top = domSize[0].top + pOutContent.top
+ domSize[0].bottom = domSize[0].top + domSize[0].height
+ domSize[0].right = domSize[0].left + domSize[0].width
+ }
+ domSize && shieldFn(domSize)
+ })
+ }
+ return arr
+ },
+
+ /**
+ * @desc 登录平台
+ * @param {String} host ip
+ * @param {String} port 端口
+ * @param {String} username 用户名
+ * @param {String} password 密码
+ * */
+ loginServer: function () {
+ this.send({
+ method: 'window.loginServer',
+ info: {
+ host: this.setting.pluginLoginInfo.host,
+ port: String(this.setting.pluginLoginInfo.port), // 自动转换为字符串
+ username: this.setting.pluginLoginInfo.username,
+ password: this.setting.pluginLoginInfo.password
+ }
+ })
+
+ },
+
+ // 退出登录
+ logoutServer: function () {
+ return new Promise((resolve, reject) => {
+ this.send({
+ method: 'window.logoutServer',
+ info: {}
+ })
+ setTimeout(() => {
+ resolve()
+ }, 2000)
+ })
+ },
+
+ // 获取登录状态信息
+ getLoginState: function () {
+ this.send({
+ method: 'window.getLoginState',
+ info: {},
+ },
+ )
+ },
+
+ // 获取登录信息
+ getLoginInfo: function () {
+ this.send({
+ method: 'window.getLoginInfo',
+ info: {},
+ },
+ )
+ },
+
+ // 扩展方法
+ extendOption: function (ids, option) {
+ var map = {}
+ for (var i = 0; i < ids.length; i++) {
+ map[ids[i]] = this.setting[ids[i]]
+ }
+ return Object.assign({}, map, option)
+ },
+ //遮挡部分位置获取
+ getShieldRect: function (option) {
+ // 获取位置信息
+ var shieldClass = this.setting.shieldClass || [],
+ arr = option || []
+ for (var i = 0; i < shieldClass.length; i++) {
+ arr = [...arr, ...computedRect.call(this, shieldClass[i])]
+ }
+ if (window.dhPlayerControl.isPIframe) {
+ arr.push(...this.setting.pIframeShieldData)
+ } else {
+ var parentIframeShieldClass = this.setting.parentIframeShieldClass || []
+ for (i = 0; i < parentIframeShieldClass.length; i++) {
+ arr = [...arr, ...computedRect.call(this, parentIframeShieldClass[i], true)]
+ }
+ }
+ return arr
+ },
+ MainCall: function (option) {
+ var dom = document.getElementById(this.setting.ieDom)
+ this.setting.option_id[option.id] = option
+ dom && dom.MainCall(option.method, JSON.stringify(option))
+ },
+ init: function () {
+ // 判断是不是跨域
+ try {
+ // 不是跨域
+ console.log(window.top.origin)
+ window.dhPlayerControl.isPIframe = false
+ this.initPlayer()
+ } catch (err) {
+ // 是跨域
+ console.log("存在跨域iframe")
+ window.dhPlayerControl.isPIframe = true
+ addEventListener('message', e => {
+ if (e.data.methods === 'title') {
+ this.setting.documentTitle = e.data.title || document.title
+ }
+ if (e.data.methods === 'rect') {
+ this.setting.topInnerWidth = e.data.topInnerWidth || 0
+ this.setting.topInnerHeight = e.data.topInnerHeight || 0
+ this.setting.pIframeRect = e.data.pIframeRect || 0
+ this.setting.topMozInnerScreenX = e.data.topMozInnerScreenX || 0
+ this.setting.topMozInnerScreenY = e.data.topMozInnerScreenY || 0
+ }
+ if (e.data.methods == 'shieldRect') {
+ this.setting.pIframeShieldData = e.data.pIframeShieldData || []
+ }
+ })
+ this.initPlayer()
+ }
+ },
+ initPlayer: function () {
+ let hwnd = ''
+ if (window.dhPlayerControl.videoList[this.setting.videoId]) {
+ hwnd = window.dhPlayerControl.videoList[this.setting.videoId].setting.hwnd
+ }
+ window.dhPlayerControl.videoList[this.setting.videoId] = this
+ this.setting.hwnd = hwnd
+ if (!window.dhPlayerControl.wsConnect) {
+ window.dhPlayerControl.wsConnect = true
+ socketOpen.call(this)
+ } else {
+ if (window.dhPlayerControl.windowState === 'wsSuccess' && (!this.setting.usePluginLogin || window.dhPlayerControl.loginFlag !== 'LOGIN_PENDING')) {
+ // 建立连接后, 确保每次初始化是否支持
+ let _isSupport = isSupport()
+ if (!_isSupport.success) {
+ return this.setting.createError && this.setting.createError(_isSupport)
+ }
+ if (this.setting.socketTimer) {
+ clearTimeout(this.setting.socketTimer)
+ };
+ this.setting.socketTimer = setTimeout(() => {
+ this.create()
+ }, this.setting.usePluginLogin ? 1000 : 300)
+ } else if (window.dhPlayerControl.windowState === "noPlugin") {
+ this.setting.createError && this.setting.createError({
+ code: 1001,
+ success: false,
+ i18nKey: 'video.player.plugin.not.installed',
+ message: "插件未安装"
+ })
+ } else if(window.dhPlayerControl.windowState === "wsError") {
+
+ this.setting.createError && this.setting.createError({
+ code: 1003,
+ success: false,
+ message: "无法与播放器建立连接" + window.isResetConnect ? ', 正在重连...' : ""
+ })
+ } else {
+ setTimeout(() => {
+ this.initPlayer()
+ }, 300)
+ }
+ }
+ this.setting.browserType = broswerInfo()
+ }
+ }
+ window.VideoPlayer = window.VideoPlayer || VideoPlayer
+})()
\ No newline at end of file