Newer
Older
KaiFengPC / src / components / videoHK / index.vue
@zhangdeliang zhangdeliang on 23 May 9 KB 初始化项目
  1. <template>
  2. <!-- 海康监控视频 实时预览 -->
  3. <div class="videoHKPage">
  4. <div ref="playWnd" :id="containerId" class="playWnd" v-html="AllData.oWebControl === null ? AllData.playText : ''"></div>
  5. </div>
  6. </template>
  7.  
  8. <script setup name="index">
  9. import { ref, reactive, onMounted } from 'vue';
  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: () => 'playWndHK',
  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. { immediate: true }
  109. );
  110. // 监听视频编码数组的改变(批量视频编码)
  111. watch(
  112. () => props.defaultList,
  113. val => {
  114. if (props.defaultList.length > 0) {
  115. PiLiangpreviewVideo();
  116. }
  117. },
  118. { immediate: true }
  119. );
  120. // 监听布局修改
  121. watch(
  122. () => props.layout,
  123. val => {
  124. setLayoutFunc();
  125. }
  126. );
  127.  
  128. // 创建播放实例
  129. const initPlugin = callback => {
  130. AllData.oWebControl = new WebControl({
  131. szPluginContainer: props.containerId, // 指定容器id
  132. iServicePortStart: 15900,
  133. iServicePortEnd: 15909,
  134. szClassId: '23BF3B0A-2C56-4D97-9C03-0CB103AA8F11', // 用于IE10使用ActiveX的clsid
  135. // 创建WebControl实例成功
  136. cbConnectSuccess: () => {
  137. AllData.oWebControl
  138. .JS_StartService('window', {
  139. // WebControl实例创建成功后需要启动服务
  140. dllPath: './VideoPluginConnect.dll',
  141. })
  142. .then(() => {
  143. // 启动插件服务成功
  144. AllData.oWebControl.JS_SetWindowControlCallback({
  145. // 设置消息回调
  146. cbIntegrationCallBack: cbIntegrationCallBack,
  147. });
  148. AllData.oWebControl.JS_CreateWnd(props.containerId, AllData.videoWidth, AllData.videoHeight).then(() => {
  149. init(callback); // 创建播放实例成功后初始化
  150. });
  151. });
  152. },
  153. cbConnectError: () => {
  154. // 创建WebControl实例失败
  155. AllData.oWebControl = null;
  156. AllData.playText = '插件未启动,正在尝试启动,请稍候...';
  157. WebControl.JS_WakeUp('VideoWebPlugin://'); // 程序未启动时执行error函数,采用wakeup来启动程序
  158. AllData.initCount++;
  159. if (AllData.initCount < 3) {
  160. setTimeout(() => {
  161. initPlugin();
  162. }, 3000);
  163. } else {
  164. AllData.playText = `
  165. 插件启动失败,请检查插件是否安装!
  166. <a href=${AllData.href} type="primary" download="视频插件.exe" style='color:#4194fc'>下载地址</a>`;
  167. }
  168. },
  169. cbConnectClose: () => {
  170. AllData.oWebControl = null;
  171. },
  172. });
  173. };
  174.  
  175. // HK插件控制监听的消息回调
  176. const cbIntegrationCallBack = oData => {
  177. // console.log(oData);
  178. if (oData.responseMsg.type == 6) {
  179. // 此时是当前画幅的数据
  180. // console.log(`当前画面的画幅是` + oData.responseMsg.msg.layout, oData.responseMsg.msg.wndNum);
  181. localStorage.setItem('HKlayout', oData.responseMsg.msg.layout);
  182. localStorage.setItem('HKwndNum', oData.responseMsg.msg.wndNum);
  183. }
  184. };
  185.  
  186. // 初始化
  187. const init = callback => {
  188. getPubKey(() => {
  189. AllData.oWebControl
  190. .JS_RequestInterface({
  191. funcName: 'init',
  192. argument: JSON.stringify({
  193. appkey: props.appkey, //API网关提供的appkey
  194. secret: setEncrypt(props.secret), //API网关提供的secret
  195. ip: props.ip, //API网关IP地址z
  196. playMode: props.playMode, //播放模式(决定显示预览还是回放界面)
  197. port: props.port, //端口
  198. snapDir: 'C:\\SnapDir', //抓图存储路径
  199. videoDir: 'C:\\VideoDir', //紧急录像或录像剪辑存储路径
  200. layout: props.layout, //布局
  201. enableHTTPS: 1, //是否启用HTTPS协议
  202. encryptedFields: 'secret', //加密字段
  203. showToolbar: props.showToolbar, //是否显示工具栏
  204. toolBarButtonIDs: props.toolBarButtonIDs,
  205. showSmart: props.showSmart, //是否显示智能信息
  206. buttonIDs: props.buttonIDs, //自定义工具条按钮
  207. protocol: 'hls',
  208. }),
  209. })
  210. .then(() => {
  211. AllData.videoWidth = playWnd.value.offsetWidth;
  212. AllData.videoHeight = playWnd.value.offsetHeight;
  213. // 初始化后resize一次,规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
  214. AllData.oWebControl.JS_Resize(AllData.videoWidth, AllData.videoHeight);
  215. // 判断当前cameraIndexCode中是否有数据 有数据的话就直接进行播放
  216. if (props.defaultList.length > 0) {
  217. // 批量渲染
  218. PiLiangpreviewVideo();
  219. } else if (props.cameraIndexCode.length > 0) {
  220. // 单独渲染
  221. AllData.videoParams.cameraIndexCode = props.cameraIndexCode.trim();
  222. previewVideo();
  223. }
  224. if (callback) {
  225. callback();
  226. }
  227. });
  228. });
  229. };
  230. // 获取公钥
  231. const getPubKey = callback => {
  232. const params = {
  233. funcName: 'getRSAPubKey',
  234. argument: JSON.stringify({ keyLength: 1024 }),
  235. };
  236. AllData.oWebControl.JS_RequestInterface(params).then(res => {
  237. if (res.responseMsg.data) {
  238. AllData.plugKey = res.responseMsg.data;
  239. callback();
  240. }
  241. });
  242. };
  243. // 视频流RSA加密
  244. const setEncrypt = value => {
  245. const encrypt = new JSEncrypt();
  246. encrypt.setPublicKey(AllData.plugKey);
  247. return encrypt.encrypt(value);
  248. };
  249.  
  250. // 视频预览
  251. const previewVideo = () => {
  252. console.log(AllData.videoParams, '单个视频播放');
  253. AllData.oWebControl.JS_RequestInterface({
  254. funcName: 'startPreview',
  255. argument: JSON.stringify(AllData.videoParams),
  256. });
  257. };
  258. // 批量预览
  259. const PiLiangpreviewVideo = () => {
  260. console.log(props.defaultList, '批量批量批量');
  261. AllData.oWebControl.JS_RequestInterface({
  262. funcName: 'startMultiPreviewByCameraIndexCode',
  263. argument: {
  264. list: props.defaultList,
  265. },
  266. });
  267. };
  268. // 显示全屏
  269. const showFullScreen = () => {
  270. AllData.oWebControl.JS_RequestInterface({
  271. funcName: 'setFullScreen',
  272. });
  273. };
  274. // 退出全屏
  275. const exitFullScreen = () => {
  276. AllData.oWebControl.JS_RequestInterface({
  277. funcName: 'exitFullScreen',
  278. });
  279. };
  280. const windowScroll = () => {
  281. if (AllData.oWebControl != null) {
  282. AllData.oWebControl.JS_Resize(AllData.videoWidth, AllData.videoHeight);
  283. }
  284. };
  285. // 获取HK父节点的宽高
  286. const windowResize = () => {
  287. AllData.videoWidth = playWnd.value.offsetWidth;
  288. AllData.videoHeight = playWnd.value.offsetHeight;
  289. if (AllData.oWebControl) {
  290. AllData.oWebControl.JS_Resize(AllData.videoWidth, AllData.videoHeight);
  291. }
  292. };
  293. // 销毁海康插件
  294. const destroyeWnd = () => {
  295. if (AllData.oWebControl) {
  296. AllData.oWebControl.JS_HideWnd();
  297. AllData.oWebControl.JS_Disconnect().then(() => {});
  298. }
  299. };
  300. // 切换布局
  301. const setLayoutFunc = () => {
  302. AllData.oWebControl.JS_RequestInterface({
  303. funcName: 'setLayout',
  304. argument: {
  305. layout: props.layout, // 窗口布局
  306. },
  307. });
  308. if (props.layout != '1x1') {
  309. // 先清除所有画面
  310. clearShiPing();
  311. }
  312. };
  313. // 销毁当前正在播放的所有画面
  314. const clearShiPing = () => {
  315. AllData.oWebControl.JS_RequestInterface({
  316. funcName: 'stopAllPreview',
  317. });
  318. AllData.videoParams.wndId = 0;
  319. };
  320. // 初始化
  321. const createdVideo = () => {
  322. initPlugin(() => {});
  323. };
  324. onMounted(() => {
  325. // 创建实例
  326. initPlugin();
  327.  
  328. // 监听resize事件,使插件窗口尺寸跟随DIV窗口变化
  329. window.addEventListener('resize', windowResize);
  330. // // 监听滚动条scroll事件,使插件窗口跟随浏览器滚动而移动
  331. window.addEventListener('scroll', windowResize);
  332. });
  333. onBeforeUnmount(() => {
  334. if (AllData.oWebControl) {
  335. AllData.oWebControl.JS_HideWnd();
  336. AllData.oWebControl
  337. .JS_DestroyWnd({
  338. funcName: 'destroyeWnd',
  339. })
  340. .then(() => {});
  341. }
  342. document.removeEventListener('resize', windowResize);
  343. document.removeEventListener('scroll', windowScroll);
  344. });
  345. </script>
  346.  
  347. <style lang="scss" scoped>
  348. .videoHKPage {
  349. width: 100%;
  350. height: 100%;
  351. .playWnd {
  352. width: 100%;
  353. height: 100%;
  354. }
  355. }
  356. </style>