Newer
Older
DH_Apicture / src / components / videoHK / index.vue
@zhangqy zhangqy on 29 Nov 10 KB first commit
  1. <template>
  2. <div id="index">
  3. <div ref="playWnd" :id="containerId" class="playWnd" v-html="AllData.oWebControl === null ? AllData.playText : ''"></div>
  4. </div>
  5. </template>
  6.  
  7. <script setup name="index">
  8. import { ref, reactive, toRefs, onMounted } from 'vue';
  9.  
  10. const props = defineProps({
  11. // 内网、公网 4个配置
  12. appkey: {
  13. type: String,
  14. default: () => '25124952',
  15. },
  16. secret: {
  17. type: String,
  18. default: () => 'aJOYWAt8CJabjjA1Ekeq',
  19. },
  20. ip: {
  21. type: String,
  22. default: () => '113.57.101.104',
  23. },
  24. port: {
  25. type: Number,
  26. default: () => 8888,
  27. },
  28. // 视频布局
  29. layout: {
  30. type: String,
  31. default: () => '1x1',
  32. },
  33. // 初始播放模式:0-预览,1-回放
  34. playMode: {
  35. type: Number,
  36. default: () => 0,
  37. },
  38. // 是否显示工具栏,0-不显示,非0-显示
  39. showToolbar: {
  40. type: Number,
  41. default: () => 1,
  42. },
  43. // 工具栏按钮
  44. toolBarButtonIDs: {
  45. type: String,
  46. default: () => '4098,4097',
  47. },
  48. // 是否显示智能信息(如配置移动侦测后画面上的线框),0-不显示,非0-显示
  49. showSmart: {
  50. type: Number,
  51. default: () => 1,
  52. },
  53. // 自定义工具条按钮
  54. buttonIDs: {
  55. type: String,
  56. default: () => '0,16,256,257,258,259,512,260,515,516,517,768,769',
  57. },
  58. // 相机编号
  59. cameraIndexCode: {
  60. type: [String, Number],
  61. },
  62. // 视频播放容器id
  63. containerId: {
  64. type: String,
  65. default: () => 'playWnd',
  66. },
  67. // 默认打开的视频
  68. defaultList: {
  69. type: Array,
  70. default: () => [],
  71. },
  72. });
  73.  
  74. const AllData = reactive({
  75. oWebControl: null,
  76. plugKey: '',
  77. // 视频相关参数
  78. videoParams: {
  79. cameraIndexCode: '', //监控点编号
  80. streamMode: 0, //主子码流标识:0-主码流,1-子码流
  81. transMode: 1, //传输协议:0-UDP,1-TCP
  82. gpuMode: 0, //是否启用GPU硬解,0-不启用,1-启用
  83. wndId: 1, //播放窗口序号
  84. },
  85. videoWidth: null,
  86. videoHeight: null,
  87. playText: '启动中...',
  88. initCount: 0, // 启动次数
  89. href: '',
  90. });
  91. // 视频容器的ref对象
  92. const playWnd = ref(null);
  93.  
  94. // 监听视频编码的改变(单个视频编码)
  95. watch(
  96. () => props.cameraIndexCode,
  97. val => {
  98. if (props.cameraIndexCode) {
  99. AllData.videoParams.cameraIndexCode = props.cameraIndexCode.trim();
  100. AllData.videoParams.wndId = -1;
  101. if (AllData.oWebControl) {
  102. previewVideo();
  103. } else {
  104. createdVideo();
  105. }
  106. }
  107. }
  108. );
  109. // 监听视频编码数组的改变(批量视频编码)
  110. watch(
  111. () => props.defaultList,
  112. val => {
  113. if (props.defaultList.length > 0) {
  114. PiLiangpreviewVideo();
  115. }
  116. }
  117. );
  118. // 监听布局修改
  119. watch(
  120. () => props.layout,
  121. val => {
  122. setLayoutFunc();
  123. }
  124. );
  125.  
  126. // 创建播放实例
  127. const initPlugin = callback => {
  128. AllData.oWebControl = new WebControl({
  129. szPluginContainer: props.containerId, // 指定容器id
  130. iServicePortStart: 15900,
  131. iServicePortEnd: 15909,
  132. szClassId: '23BF3B0A-2C56-4D97-9C03-0CB103AA8F11', // 用于IE10使用ActiveX的clsid
  133. // 创建WebControl实例成功
  134. cbConnectSuccess: () => {
  135. AllData.oWebControl
  136. .JS_StartService('window', {
  137. // WebControl实例创建成功后需要启动服务
  138. dllPath: './VideoPluginConnect.dll',
  139. })
  140. .then(() => {
  141. // 启动插件服务成功
  142. AllData.oWebControl.JS_SetWindowControlCallback({
  143. // 设置消息回调
  144. cbIntegrationCallBack: cbIntegrationCallBack,
  145. });
  146. AllData.oWebControl.JS_CreateWnd(props.containerId, AllData.videoWidth, AllData.videoHeight).then(() => {
  147. getVersion(callback);
  148. });
  149. });
  150. },
  151. cbConnectError: () => {
  152. // 创建WebControl实例失败
  153. AllData.oWebControl = null;
  154. AllData.playText = '插件未启动,正在尝试启动,请稍候...';
  155. WebControl.JS_WakeUp('VideoWebPlugin://'); // 程序未启动时执行error函数,采用wakeup来启动程序
  156. AllData.initCount++;
  157. if (AllData.initCount < 3) {
  158. setTimeout(() => {
  159. initPlugin();
  160. }, 3000);
  161. } else {
  162. AllData.playText = `
  163. 插件启动失败,请检查插件是否安装!
  164. <a href=${AllData.href} type="primary" download="视频插件.exe" style='color:#4194fc'>下载地址</a>`;
  165. }
  166. },
  167. cbConnectClose: () => {
  168. AllData.oWebControl = null;
  169. },
  170. });
  171. };
  172.  
  173. // HK插件控制监听的消息回调
  174. const cbIntegrationCallBack = oData => {
  175. console.log(oData);
  176. if (oData.responseMsg.type == 6) {
  177. // 此时是当前画幅的数据
  178. console.log(`当前画面的画幅是` + oData.responseMsg.msg.layout, oData.responseMsg.msg.wndNum);
  179. localStorage.setItem('HKlayout', oData.responseMsg.msg.layout);
  180. localStorage.setItem('HKwndNum', oData.responseMsg.msg.wndNum);
  181. }
  182. };
  183.  
  184. // 初始化
  185. const init = callback => {
  186. getPubKey(() => {
  187. AllData.oWebControl
  188. .JS_RequestInterface({
  189. funcName: 'init',
  190. argument: JSON.stringify({
  191. appkey: props.appkey, //API网关提供的appkey
  192. secret: setEncrypt(props.secret), //API网关提供的secret
  193. ip: props.ip, //API网关IP地址z
  194. playMode: props.playMode, //播放模式(决定显示预览还是回放界面)
  195. port: props.port, //端口
  196. snapDir: 'C:\\SnapDir', //抓图存储路径
  197. videoDir: 'C:\\VideoDir', //紧急录像或录像剪辑存储路径
  198. layout: props.layout, //布局
  199. enableHTTPS: 1, //是否启用HTTPS协议
  200. encryptedFields: 'secret', //加密字段
  201. showToolbar: props.showToolbar, //是否显示工具栏
  202. toolBarButtonIDs: props.toolBarButtonIDs,
  203. showSmart: props.showSmart, //是否显示智能信息
  204. buttonIDs: props.buttonIDs, //自定义工具条按钮
  205. protocol: 'hls',
  206. }),
  207. })
  208. .then(() => {
  209. AllData.videoWidth = playWnd.value.offsetWidth;
  210. AllData.videoHeight = playWnd.value.offsetHeight;
  211. // 初始化后resize一次,规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
  212. AllData.oWebControl.JS_Resize(AllData.videoWidth, AllData.videoHeight);
  213. // 判断当前cameraIndexCode中是否有数据 有数据的话就直接进行播放
  214. if (props.defaultList.length > 0) {
  215. // 批量渲染
  216. PiLiangpreviewVideo();
  217. } else if (props.cameraIndexCode.length > 0) {
  218. // 单独渲染
  219. AllData.videoParams.cameraIndexCode = props.cameraIndexCode.trim();
  220. previewVideo();
  221. }
  222. if (callback) {
  223. callback();
  224. }
  225. });
  226. });
  227. };
  228. // 获取公钥
  229. const getPubKey = callback => {
  230. const params = {
  231. funcName: 'getRSAPubKey',
  232. argument: JSON.stringify({ keyLength: 1024 }),
  233. };
  234. AllData.oWebControl.JS_RequestInterface(params).then(res => {
  235. if (res.responseMsg.data) {
  236. AllData.plugKey = res.responseMsg.data;
  237. callback();
  238. }
  239. });
  240. };
  241. // 视频流RSA加密
  242. const setEncrypt = value => {
  243. const encrypt = new JSEncrypt();
  244. encrypt.setPublicKey(AllData.plugKey);
  245. return encrypt.encrypt(value);
  246. };
  247.  
  248. // 视频预览
  249. const previewVideo = () => {
  250. console.log(AllData.videoParams, '单个视频播放');
  251. AllData.oWebControl.JS_RequestInterface({
  252. funcName: 'startPreview',
  253. argument: JSON.stringify(AllData.videoParams),
  254. });
  255. };
  256. // 批量预览
  257. const PiLiangpreviewVideo = () => {
  258. console.log(props.defaultList, '批量批量批量');
  259. AllData.oWebControl.JS_RequestInterface({
  260. funcName: 'startMultiPreviewByCameraIndexCode',
  261. argument: {
  262. list: props.defaultList,
  263. },
  264. });
  265. };
  266. // 显示全屏
  267. const showFullScreen = () => {
  268. AllData.oWebControl.JS_RequestInterface({
  269. funcName: 'setFullScreen',
  270. });
  271. };
  272. // 退出全屏
  273. const exitFullScreen = () => {
  274. AllData.oWebControl.JS_RequestInterface({
  275. funcName: 'exitFullScreen',
  276. });
  277. };
  278. const windowScroll = () => {
  279. if (AllData.oWebControl != null) {
  280. AllData.oWebControl.JS_Resize(AllData.videoWidth, AllData.videoHeight);
  281. }
  282. };
  283. // 获取HK父节点的宽高
  284. const windowResize = () => {
  285. AllData.videoWidth = playWnd.value.offsetWidth;
  286. AllData.videoHeight = playWnd.value.offsetHeight;
  287. if (AllData.oWebControl) {
  288. AllData.oWebControl.JS_Resize(AllData.videoWidth, AllData.videoHeight);
  289. }
  290. };
  291. // 销毁海康插件
  292. const destroyeWnd = () => {
  293. if (AllData.oWebControl) {
  294. AllData.oWebControl.JS_HideWnd();
  295. AllData.oWebControl.JS_Disconnect().then(() => {});
  296. }
  297. };
  298. // 获取海康插件版本号
  299. const getVersion = callback => {
  300. if (AllData.oWebControl) {
  301. AllData.oWebControl
  302. .JS_RequestInterface({
  303. funcName: 'getVersion',
  304. })
  305. .then(res => {
  306. console.log(res, '插件版本号');
  307.  
  308. if (res.responseMsg.code === 0 && res.responseMsg.data === 'V1.5.2') {
  309. //JS_CreateWnd创建视频播放窗口,宽高可设定
  310. init(callback); // 创建播放实例成功后初始化
  311. console.log('启动插件成功!');
  312. } else {
  313. destroyeWnd();
  314. AllData.playText = `
  315. 插件版本不正确,请重新下载版本安装覆盖!
  316. <a href=${AllData.href} type="primary" download="视频插件.exe" style='color:#4194fc'>下载地址</a>`;
  317. }
  318. });
  319. }
  320. };
  321. // 切换布局
  322. const setLayoutFunc = () => {
  323. AllData.oWebControl.JS_RequestInterface({
  324. funcName: 'setLayout',
  325. argument: {
  326. layout: props.layout, // 窗口布局
  327. },
  328. });
  329. if (props.layout != '1x1') {
  330. // 先清除所有画面
  331. clearShiPing();
  332. }
  333. };
  334. // 销毁当前正在播放的所有画面
  335. const clearShiPing = () => {
  336. AllData.oWebControl.JS_RequestInterface({
  337. funcName: 'stopAllPreview',
  338. });
  339. AllData.videoParams.wndId = 0;
  340. };
  341. // 初始化
  342. const createdVideo = () => {
  343. initPlugin(() => {});
  344. };
  345. onMounted(() => {
  346. // 创建实例
  347. initPlugin();
  348.  
  349. // 监听resize事件,使插件窗口尺寸跟随DIV窗口变化
  350. window.addEventListener('resize', windowResize());
  351. // // 监听滚动条scroll事件,使插件窗口跟随浏览器滚动而移动
  352. window.addEventListener('scroll', windowResize());
  353. });
  354. onBeforeUnmount(() => {
  355. if (AllData.oWebControl) {
  356. AllData.oWebControl.JS_HideWnd();
  357. AllData.oWebControl
  358. .JS_DestroyWnd({
  359. funcName: 'destroyeWnd',
  360. })
  361. .then(() => {});
  362. }
  363. document.removeEventListener('resize', windowResize());
  364. document.removeEventListener('scroll', windowScroll());
  365. });
  366. </script>
  367.  
  368. <style lang="scss" scoped>
  369. #index {
  370. width: 100%;
  371. height: 100%;
  372. .playWnd {
  373. width: 100%;
  374. height: 100%;
  375. }
  376. }
  377. </style>