485 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			485 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| 
 | |
| let $ip,
 | |
|   $port,
 | |
|   $user,
 | |
|   $password,
 | |
|   $loginState,
 | |
|   $stream,
 | |
|   $volume,
 | |
|   $canvas, //canvas播放视频DOM
 | |
|   $video, //video播放视频DOM
 | |
|   $canvas_ivs, //canvas绘图DOM
 | |
|   $video_wrap, //视频外层Wrap
 | |
|   $videoLoading, //“加载中...”提示
 | |
|   WndIndex = 0, //宫格窗口Id
 | |
|   WebCaps = null; //webCapsConfig文件转存变量
 | |
| let isLogin = false; //是否登录
 | |
| let channel = 0; //当前通道
 | |
| let curPage = 1; //视频下载列表的当前页
 | |
| let totalPage = 1; //视频下载列表的总页数
 | |
| let recordArr = []; //视频文件数组
 | |
| let canvasSon = null; //canvas绘图实例
 | |
| let playerInstance = []; //播放|回放实例数组
 | |
| let recordInstance = []; //录像下载实例数组
 | |
| let talkInstance = []; //对讲实例数组
 | |
| let ivsInstance = []; //canvas绘图实例数组
 | |
| let cutInstance = []; //视频裁剪实例数组
 | |
| let onlineChannel = []; //当前成功拉流的视频通道数组
 | |
| let isCuting = false; //是否正在进行视频裁剪
 | |
| let downList = []; //勾选的视频下载列表
 | |
| let downItemIndex = 0; //视频下载索引
 | |
| let canvasParam = {
 | |
|   //canvas绘图默认传参
 | |
|   strokeColor: "#FF0000",
 | |
|   title: "",
 | |
|   resizeEnable: false,
 | |
|   moveEnable: false,
 | |
|   closeEnable: true,
 | |
|   array: true,
 | |
|   showSize: false,
 | |
|   selectType: "inSide",
 | |
|   disappear: true,
 | |
|   selected: false,
 | |
| };
 | |
| const lINENUMBER = 16; //回放列表每页显示录像条数
 | |
| let curEnlargeWnd = 0;
 | |
| 
 | |
| /**
 | |
|  * @description 初始化
 | |
|  */
 | |
| const init = () => {
 | |
|   let videoStr = "";
 | |
|   for (var i = 0; i < 16; i++) {
 | |
|     videoStr +=
 | |
|       '<div wnd-index="' +
 | |
|       i +
 | |
|       '" style="float: left; background-color: #000; position: relative; width: 100%; height: 100%;overflow:hidden;border:1px solid rgb(125,125,125)"><canvas id="h5_canvas_' +
 | |
|       i +
 | |
|       '" style="width:100%;height:100%;"></canvas><p id="h5_loading_' +
 | |
|       i +
 | |
|       '" class="video_loading"  style="display:none">加载中...</p><video id="h5_video_' +
 | |
|       i +
 | |
|       '" style="display: none;width:100%;height:100%;position:absolute;top:0;left:0"></video><canvas id="h5_ivs_' +
 | |
|       i +
 | |
|       '" style="position: absolute;left: 0;top: 0;width: 100%;height: 100%;" width="500" height="300"></canvas></div>';
 | |
|   }
 | |
|   document.querySelector(".h5-play-wrap").innerHTML = videoStr;
 | |
|   document.querySelectorAll(".h5-play-wrap div").forEach((item, index) => {
 | |
|     item.addEventListener("click", function (event) {
 | |
|       let _wndIndex = event.target.parentNode.getAttribute("wnd-index") - 0;
 | |
|       if (
 | |
|         !(playerInstance[_wndIndex] && playerInstance[_wndIndex].isPlayback)
 | |
|       ) {
 | |
|         channel = event.target.parentNode.getAttribute("channel") - 0;
 | |
|         document.querySelectorAll("#h5_channel_list li").forEach((item) => {
 | |
|           item.classList.remove("fn-fontRed");
 | |
|         });
 | |
|       }
 | |
|       document
 | |
|         .querySelectorAll(".h5-play-wrap div")
 | |
|         .forEach(function (item, index) {
 | |
|           if (index === _wndIndex) {
 | |
|             item.style.borderColor = "rgb(255, 204, 0)";
 | |
|             if (
 | |
|               !(
 | |
|                 playerInstance[_wndIndex] &&
 | |
|                 playerInstance[_wndIndex].isPlayback
 | |
|               )
 | |
|             ) {
 | |
|               if (onlineChannel.indexOf(channel) > -1) {
 | |
|                 document
 | |
|                   .querySelector(
 | |
|                     '#h5_channel_list li[channel="' + channel + '"]'
 | |
|                   )
 | |
|                   .classList.add("fn-fontRed");
 | |
|               }
 | |
|             }
 | |
|             WndIndex = _wndIndex;
 | |
|             setVideoDom();
 | |
|           } else {
 | |
|             item.style.borderColor = "rgb(125, 125, 125)";
 | |
|           }
 | |
|         });
 | |
|     });
 | |
|   });
 | |
|   $ip = $("#h5_ip");
 | |
|   $port = $("#h5_port");
 | |
|   $user = $("#h5_user");
 | |
|   $password = $("#h5_password");
 | |
|   $loginState = $("#h5_loginState");
 | |
|   $stream = $("#h5_stream");
 | |
|   $volume = $("#h5_volume");
 | |
|   $video_wrap = document.querySelector(".h5-play-wrap");
 | |
|   setVideoDom();
 | |
| 
 | |
|   let inputArr = document.querySelectorAll("input[btn-for]");
 | |
|   for (let node of inputArr) {
 | |
|     node.addEventListener("click", bindClickEvent);
 | |
|   }
 | |
| 
 | |
|   let selArr = document.querySelectorAll("select[sel-for]");
 | |
|   for (let node of selArr) {
 | |
|     node.addEventListener("change", bindChangeEvent);
 | |
|   }
 | |
|   [
 | |
|     "fullscreenchange",
 | |
|     "webkitfullscreenchange",
 | |
|     "mozfullscreenchange",
 | |
|     "msfullscreenchange",
 | |
|   ].forEach((item, index) => {
 | |
|     document.addEventListener(item, fullscreenchange, false);
 | |
|   });
 | |
|   onPreview(false);
 | |
| };
 | |
| /**
 | |
|  * @description 切换宫格时重新设置当前视频dom
 | |
|  */
 | |
| const setVideoDom = () => {
 | |
|   $canvas = $("#h5_canvas_" + WndIndex);
 | |
|   $video = $("#h5_video_" + WndIndex);
 | |
|   $canvas_ivs = $("#h5_ivs_" + WndIndex);
 | |
|   $videoLoading = $("#h5_loading_" + WndIndex);
 | |
| };
 | |
| /**
 | |
| /**
 | |
|  * @description 预览
 | |
|  * @param {boolean} isPlayback 是否是回放
 | |
|  * @param {string} url 回放视频的url
 | |
|  * @param {number} playbackIndex 回放视频的索引
 | |
|  * @param {boolean} isChangeStream 是否是切换码流导致的重新拉流
 | |
|  */
 | |
| const onPreview = (isPlayback, url, playbackIndex, isChangeStream) => {
 | |
|   if (
 | |
|     playerInstance[WndIndex] &&
 | |
|     onlineChannel.indexOf(channel) > -1 &&
 | |
|     !isChangeStream
 | |
|   ) {
 | |
|     alert("通道" + (channel + 1) + "已存在!");
 | |
|     return;
 | |
|   }
 | |
|   onStopPreview();
 | |
|   var player = null;
 | |
|   // if(!isLogin) {
 | |
|   //     alert('请先登录再预览!');
 | |
|   //     return;
 | |
|   // }
 | |
|   // let curChannel = channel + 1; //无插件通道号从1开始
 | |
|   // let stream = $stream.value - 0 || 0;
 | |
|   // let firstTime = 0;
 | |
|   // let ip = $ip.value;
 | |
|   // let port = $port.value - 0;
 | |
|   // let username = $user.value;
 | |
|   // let password = $password.value;
 | |
| 
 | |
| 
 | |
|   let options = {
 | |
|     wsURL: "ws://" + "221.214.127.18" + ":" + "8200" + "/rtspoverwebsocket",
 | |
|     rtspURL:
 | |
|       "rtsp://" +
 | |
|       "221.214.127.18" +
 | |
|       ":" +
 | |
|       "8200" +
 | |
|       "/cam/realmonitor?channel=1" +
 | |
|       "&subtype=0" +
 | |
|       "&proto=Private3",
 | |
|     username: "admin",
 | |
|     password: "pyss2017",
 | |
|     lessRateCanvas: true,
 | |
|     playback: isPlayback,
 | |
|     isPrivateProtocol: false,
 | |
|     realm: RPC.realm, //设备登录返回的realm
 | |
|     playbackIndex: playbackIndex,
 | |
|   };
 | |
|   player = new PlayerControl(options);
 | |
| 
 | |
|   player.on("MSEResolutionChanged", function (e) {
 | |
|     console.log(e);
 | |
|   });
 | |
|   player.on("PlayStart", function (e) {
 | |
|     console.log(e);
 | |
|     $videoLoading.style.display = "none";
 | |
|     let curWndType =
 | |
|       document.querySelector("[sel-for=onChangeWdnNum]").value - 0;
 | |
|     if (!player.isPlayback) {
 | |
|       onlineChannel.push(channel);
 | |
|       updateChannelList();
 | |
|       // if(curWndType !== 1) {
 | |
|       //     clickNextWnd();
 | |
|       // }
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   player.on("GetFrameRate", function (e) {
 | |
|     console.log("GetFrameRate: " + e);
 | |
|   });
 | |
|   player.on("FrameTypeChange", function (e) {
 | |
|     console.log("FrameTypeChange: " + e);
 | |
|   });
 | |
|   player.on("Error", function (e) {
 | |
|     //console.log('Error: ' + JSON.stringify(e))
 | |
|   });
 | |
|   player.on("IvsDraw", function (e) {
 | |
|     //console.log('IvsDraw: ' + JSON.stringify(e))
 | |
|   });
 | |
|   player.on("WorkerReady", function () {
 | |
|     player.connect();
 | |
|   });
 | |
|   player.init($canvas, $video);
 | |
|   $canvas.parentNode.setAttribute("channel", channel);
 | |
|   $videoLoading.style.display = "";
 | |
| };
 | |
| /**
 | |
|  * @description 更新通道列表
 | |
|  */
 | |
| const updateChannelList = () => {
 | |
|   document.querySelectorAll("#h5_channel_list li").forEach((item) => {
 | |
|     item.classList.remove("fn-fontBlue");
 | |
|     item.classList.remove("fn-fontRed");
 | |
|     if (onlineChannel.indexOf(item.getAttribute("channel") - 0) > -1) {
 | |
|       item.classList.add("fn-fontBlue");
 | |
|     }
 | |
|   });
 | |
| };
 | |
| /**
 | |
|  * @description 停止预览
 | |
|  */
 | |
| const onStopPreview = () => {
 | |
|   if (playerInstance[WndIndex]) {
 | |
|     playerInstance[WndIndex].stop();
 | |
|     playerInstance[WndIndex].close();
 | |
|     playerInstance[WndIndex] = null;
 | |
|     let _index = onlineChannel.indexOf(channel);
 | |
|     onlineChannel.splice(_index, 1);
 | |
|     updateChannelList();
 | |
|     let dom = $canvas;
 | |
|     if (dom.style.display === "none") {
 | |
|       dom = $video;
 | |
|     }
 | |
|     dom.style.display = "none";
 | |
|     if (talkInstance[WndIndex]) {
 | |
|       talkInstance[WndIndex].talk("off");
 | |
|       talkInstance[WndIndex] = null;
 | |
|     }
 | |
|     if (recordInstance[WndIndex]) {
 | |
|       recordInstance[WndIndex].startRecord(false);
 | |
|       recordInstance[WndIndex] = null;
 | |
|     }
 | |
|   }
 | |
| };
 | |
| /**
 | |
|  * @description 设置样式
 | |
|  * @param {object} obj dom元素
 | |
|  * @param {*} json css样式
 | |
|  */
 | |
| function setStyle(obj, json) {
 | |
|   for (let i in json) {
 | |
|     obj.style[i] = json[i];
 | |
|   }
 | |
| }
 | |
| /**
 | |
|  * @description 绑定click事件
 | |
|  * @param {object} event event对象
 | |
|  */
 | |
| function bindClickEvent(event) {
 | |
|   let $el = event.target,
 | |
|     method = $el.getAttribute("btn-for"),
 | |
|     disabled = $el.getAttribute("disabled");
 | |
|   if (!disabled) {
 | |
|     eval(method + "()");
 | |
|   }
 | |
| }
 | |
| /**
 | |
|  * @description 绑定change事件
 | |
|  * @param {object} event event对象
 | |
|  */
 | |
| function bindChangeEvent(event) {
 | |
|   let $el = event.target,
 | |
|     method = $el.getAttribute("sel-for"),
 | |
|     disabled = $el.getAttribute("disabled");
 | |
|   if (!disabled) {
 | |
|     eval(method + "()");
 | |
|   }
 | |
| }
 | |
| /**
 | |
|  * @description 设置登录状态
 | |
|  * @param {boolean} bool 设备是否已经登录
 | |
|  */
 | |
| function setLoginState(bool) {
 | |
|   isLogin = bool;
 | |
| }
 | |
| /**
 | |
|  * @description 转换数据坐标
 | |
|  * @param {*} x1 左上角x坐标
 | |
|  * @param {*} y1 左上角y坐标
 | |
|  * @param {*} x2 右下角x坐标
 | |
|  * @param {*} y2 右下角y坐标
 | |
|  * @param {*} width 宫格宽
 | |
|  * @param {*} height 宫格高
 | |
|  */
 | |
| function zoomArea(x1, y1, x2, y2, width, height) {
 | |
|   // 小框区域的数据
 | |
|   let rectArea = {
 | |
|     width: x2 - x1,
 | |
|     height: y2 - y1,
 | |
|     centerX: (x1 + x2) / 2, // 圆心坐标
 | |
|     centerY: (y1 + y2) / 2,
 | |
|   };
 | |
|   // 放大比例,控件放大倍数上限是20
 | |
|   let scale = Math.min(width / rectArea.width, height / rectArea.height, 20);
 | |
| 
 | |
|   // 原始窗口信息
 | |
|   let sourceWin = {
 | |
|     width: width,
 | |
|     height: height,
 | |
|     centerX: width / 2,
 | |
|     centerY: height / 2,
 | |
|   };
 | |
| 
 | |
|   // 放大后的窗口区域
 | |
|   let bigWinArea = {
 | |
|     width: width * scale,
 | |
|     height: height * scale,
 | |
|     left: sourceWin.centerX - rectArea.centerX * scale,
 | |
|     top: sourceWin.centerY - rectArea.centerY * scale,
 | |
|   };
 | |
| 
 | |
|   // 数据矫正
 | |
|   if (bigWinArea.left > 0) {
 | |
|     bigWinArea.left = 0;
 | |
|   }
 | |
|   if (bigWinArea.left < sourceWin.width - bigWinArea.width) {
 | |
|     bigWinArea.left = sourceWin.width - bigWinArea.width;
 | |
|   }
 | |
|   if (bigWinArea.top > 0) {
 | |
|     bigWinArea.top = 0;
 | |
|   }
 | |
|   if (bigWinArea.top < sourceWin.height - bigWinArea.height) {
 | |
|     bigWinArea.top = sourceWin.height - bigWinArea.height;
 | |
|   }
 | |
|   return bigWinArea;
 | |
| }
 | |
| /**
 | |
|  * @description 获取全屏状态
 | |
|  */
 | |
| function getFull() {
 | |
|   return (
 | |
|     window.top.document.mozFullScreen ||
 | |
|     window.top.document.webkitIsFullScreen ||
 | |
|     window.top.document.msFullscreenElement
 | |
|   );
 | |
| }
 | |
| /**
 | |
|  * @description 全屏状态改变的回调事件
 | |
|  */
 | |
| function fullscreenchange() {
 | |
|   if (getFull()) {
 | |
|     return;
 | |
|   } else {
 | |
|     exitfullScreen();
 | |
|   }
 | |
| }
 | |
| /**
 | |
|  * @description 设置全屏
 | |
|  */
 | |
| function setfullScreen() {
 | |
|   let docElm = window.top.document.documentElement;
 | |
|   if (docElm.requestFullScreen) {
 | |
|     docElm.requestFullScreen();
 | |
|   } else if (docElm.mozRequestFullScreen) {
 | |
|     docElm.mozRequestFullScreen();
 | |
|   } else if (docElm.webkitRequestFullScreen) {
 | |
|     docElm.webkitRequestFullScreen();
 | |
|   } else if (docElm.msRequestFullscreen) {
 | |
|     docElm.msRequestFullscreen();
 | |
|   }
 | |
|   handleFullscreen(true);
 | |
| }
 | |
| /**
 | |
|  * @description 退出全屏
 | |
|  */
 | |
| function exitfullScreen() {
 | |
|   let docElm = window.top.document.documentElement;
 | |
|   if (docElm.exitFullscreen) {
 | |
|     docElm.exitFullscreen();
 | |
|   } else if (docElm.mozCancelFullScreen) {
 | |
|     docElm.mozCancelFullScreen();
 | |
|   } else if (docElm.webkitCancelFullScreen) {
 | |
|     docElm.webkitCancelFullScreen();
 | |
|   } else if (docElm.msExitFullscreen) {
 | |
|     docElm.msExitFullscreen();
 | |
|   }
 | |
|   handleFullscreen(false);
 | |
| }
 | |
| /**
 | |
|  * @description 处理全屏开关时的窗口大小
 | |
|  * @param {boolean} bool 是否要全屏
 | |
|  */
 | |
| function handleFullscreen(bool) {
 | |
|   if (bool) {
 | |
|     let wrap = {
 | |
|       position: "absolute",
 | |
|       left: 0,
 | |
|       top: 0,
 | |
|       width: window.screen.width + "px",
 | |
|       height: window.screen.height + "px",
 | |
|       overflow: "visible",
 | |
|     };
 | |
|     setStyle($video_wrap, wrap);
 | |
|   } else {
 | |
|     let wrap = {
 | |
|       position: "relative",
 | |
|       overflow: "hidden",
 | |
|       width: "500px",
 | |
|       height: "300px",
 | |
|     };
 | |
|     setStyle($video_wrap, wrap);
 | |
|   }
 | |
| }
 | |
| /**
 | |
|  * @description ptz云台事件
 | |
|  * @param {string} type 云台事件类型
 | |
|  * @param {boolean} isStop 是否停止相应事件
 | |
|  */
 | |
| window.onHandlePTZ = function (type, isStop) {
 | |
|   let stepVal = $("#h5_ptz_step").value - 0;
 | |
|   let arg2 = 0;
 | |
|   let arg2Arr = ["LeftUp", "RightUp", "LeftDown", "RightDown"];
 | |
|   let presetArr = ["GotoPreset", "SetPreset", "ClearPreset"];
 | |
|   let presetNum = $("#h5_preset").value - 0;
 | |
|   if (arg2Arr.indexOf(type) > -1) {
 | |
|     arg2 = stepVal;
 | |
|   }
 | |
|   if (!isStop) {
 | |
|     if (presetArr.indexOf(type) > -1) {
 | |
|       /**
 | |
|        * RPC.PTZManager 云台相关
 | |
|        * @param {string} 方法
 | |
|        * @param {number} channel 通道
 | |
|        * @param {object} 参数集合
 | |
|        */
 | |
|       RPC.PTZManager("start", channel, {
 | |
|         code: type,
 | |
|         arg1: presetNum,
 | |
|         arg2: 0,
 | |
|         arg3: 0,
 | |
|       });
 | |
|     } else {
 | |
|       RPC.PTZManager("start", channel, {
 | |
|         code: type,
 | |
|         arg1: stepVal,
 | |
|         arg2: arg2,
 | |
|         arg3: 0,
 | |
|       });
 | |
|     }
 | |
|   } else {
 | |
|     RPC.PTZManager("stop", channel, {
 | |
|       code: type,
 | |
|       arg1: stepVal,
 | |
|       arg2: arg2,
 | |
|       arg3: 0,
 | |
|     });
 | |
|   }
 | |
| };
 | |
| //进入页面自动初始化
 | |
| init();
 |