package com.persagy.cameractl.service; import com.hikvision.artemis.sdk.ArtemisHttpUtil; import com.hikvision.artemis.sdk.config.ArtemisConfig; import com.persagy.cameractl.conf.CameraApiConfig; import com.persagy.cameractl.utils.Camera; import com.persagy.cameractl.utils.CmdStreamThread; import com.persagy.cameractl.utils.EnumTools; import com.persagy.cameractl.utils.ResultClass; import com.persagy.cameractl.utils.JsonTools; import com.persagy.cameractl.utils.OtherTools; import cn.hutool.core.date.DateUtil; import java.io.File; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import net.sf.json.JSONObject; @Component public class HkCameraExecuteApi { Logger logger = LoggerFactory.getLogger(HkCameraExecuteApi.class); @Autowired private CameraApiConfig cameraApiConfig; /** * STEP2:设置OpenAPI接口的上下文 */ final String ARTEMIS_PATH = "/artemis/api/"; /* * 解析返回结果 * */ private ResultClass parseResult(String resultStr) { ResultClass resultClass = new ResultClass(); resultClass.name = false; try { if (resultStr == null || resultStr.equals("")) { resultClass.reason = "结果为空"; return resultClass; } // org.springframework.boot.configurationprocessor.json.JSONObject resultMap=new // org.springframework.boot.configurationprocessor.json.JSONObject(resultStr); Map mapResult = JsonTools.str2Map(resultStr); String msgStr = String.valueOf(mapResult.get("msg")); if (msgStr == null || !msgStr.equals("success")) { resultClass.reason = "错误码:" + String.valueOf(mapResult.get("code")) + ",错误原因:" + String.valueOf(mapResult.get("msg")); return resultClass; } resultClass.name = true; resultClass.resultData = mapResult.get("data"); return resultClass; } catch (Exception e) { logger.error("海康中心平台返回结果非法:" + resultStr); resultClass.reason = "海康中心平台返回结果非法,请查看后台日志"; return resultClass; } }; /* * 发送请求并解析返回结果 * */ private ResultClass SendRequest(String url, String paramString) { /** * STEP1:设置平台参数,根据实际情况,设置host appkey appsecret 三个参数. */ ArtemisConfig.host = cameraApiConfig.getHkApiHost(); // artemis网关服务器ip端口 ArtemisConfig.appKey = cameraApiConfig.getHkApiKey(); // 秘钥appkey ArtemisConfig.appSecret = cameraApiConfig.getHkApiSecret();// 秘钥appSecret /** * STEP3:设置接口的URI地址 */ String previewURLsApi = ARTEMIS_PATH + url; Map path = new HashMap(2) { /** * */ private static final long serialVersionUID = 1L; { put("https://", previewURLsApi);// 根据现场环境部署确认是http还是https } }; /** * STEP4:设置参数提交方式 */ String contentType = "application/json"; /** * STEP6:调用接口 */ String result = ArtemisHttpUtil.doPostStringArtemis(path, paramString, null, null, contentType, null);// post请求application/json类型参数 return parseResult(result); }; /* * 根据监控点获取预览流 */ public ResultClass GetCameraPreviewURL(Camera hkCamera) { try { String url = "video/v2/cameras/previewURLs"; /** * STEP5:组装请求参数 */ JSONObject jsonBody = new JSONObject(); jsonBody.put("cameraIndexCode", hkCamera.cameraIndexCode); jsonBody.put("streamType", hkCamera.streamType); jsonBody.put("protocol", hkCamera.protocol); // 传输协议(传输层协议),0:UDP 1:TCP 默认是TCP 注:GB28181 2011及以前版本只支持UDP传输 // jsonBody.put("transmode", 1); String expandStr = "transcode=" + hkCamera.transcode + "&resolution=" + hkCamera.resolution + "&bitrate=" + hkCamera.bitrate + "&videotype=" + hkCamera.videotype; jsonBody.put("expand", expandStr); String body = jsonBody.toString(); return SendRequest(url, body); } catch (Exception e) { logger.error("海康调用实时预览API出错:", e); ResultClass resultClass = new ResultClass(false, "海康调用实时预览API出错"); return resultClass; } } /* * 根据监控点获取回放流 */ public ResultClass GetCameraPlayBackURL(Camera hkCamera) { try { String reqUrl = "video/v2/cameras/playbackURLs"; /** * STEP5:组装请求参数 * 因为香港置地返回的回放rtsp流总是在剩余大概15秒的时候卡顿,所以传过去的结束时间要加30秒,所以ffmpeg命令里要用-t控制实际读取时长 */ Date dateStart = DateUtil.parse(hkCamera.startDateStr); long startMillSeconds = dateStart.getTime(); Date dateEnd = DateUtil.parse(hkCamera.endDateStr); long endMillSeconds = dateEnd.getTime(); // 先求得真实的回放时长 long temp = endMillSeconds - startMillSeconds; long hourCount = 0; long minuteCount = 0; long secondCount = temp / 1000; long millSecondCount = temp % 1000; // 到了分钟级 if (secondCount >= 60) { minuteCount = secondCount / 60; secondCount = secondCount % 60; // 到了小时级 if (minuteCount >= 60) { hourCount = minuteCount / 60; minuteCount = minuteCount % 60; } } long endMillSeconds2 = endMillSeconds + 30 * 1000; Date enDate2 = DateUtil.date(endMillSeconds2); String endString2 = DateUtil.format(enDate2, "yyyy-MM-dd HH:mm:ss"); JSONObject jsonBody = new JSONObject(); jsonBody.put("cameraIndexCode", hkCamera.cameraIndexCode); jsonBody.put("protocol", hkCamera.protocol); jsonBody.put("beginTime", hkCamera.startDateStr.replace(" ", "T") + ".000+08:00"); jsonBody.put("endTime", endString2.replace(" ", "T") + ".000+08:00"); // 传输协议(传输层协议),0:UDP 1:TCP 默认是TCP 注:GB28181 2011及以前版本只支持UDP传输 // jsonBody.put("transmode", 1); String expandStr = "transcode=" + hkCamera.transcode + "&resolution=" + hkCamera.resolution + "&bitrate=" + hkCamera.bitrate + "&videotype=" + hkCamera.videotype; jsonBody.put("expand", expandStr); String body = jsonBody.toString(); ResultClass resultClass = SendRequest(reqUrl, body); // return resultClass; // hls格式回放时,直接返回 // if (hkCamera.protocol.equals("hls")) // return resultClass; /* * 如果不是hls格式,那么即为rtsp格式,此时需抓取rtsp流并转成mp4 * */ // 调用失败直接返回 if (!resultClass.name) return resultClass; String resultDataStr = JsonTools.obj2Str(resultClass.resultData); Map resultDataMap = JsonTools.str2Map(resultDataStr); String videoUrl = String.valueOf(resultDataMap.get("url")); if (videoUrl == null || videoUrl.equals("")) return new ResultClass(false, "未获取到视频源地址"); String playFilePath = OtherTools.getVideoFilePath(); if (playFilePath.equals("")) { return new ResultClass(false, "回放文件名称生成失败"); } // 抓取视频流转为页面上可播放的MP4 Runtime run = Runtime.getRuntime(); /* * stimeout、rw_timeout的单位为微秒 1秒=1000000微秒 * 因为香港置地返回的回放rtsp流总是在剩余大概15秒的时候卡顿,所以传过去的结束时间要加30秒,所以ffmpeg命令里要用-t控制实际读取时长 * */ String timeDuration = hourCount + ":" + minuteCount + ":" + secondCount + (millSecondCount > 0 ? "." + millSecondCount : ""); String cmdStr = hkCamera.protocol.equals("hls") ? ("ffmpeg -i \"" + videoUrl + "\" -c copy -y \"" + playFilePath + "\"") : ("ffmpeg -t " + timeDuration + " -rtsp_transport tcp -i \"" + videoUrl + "\" -y \"" + playFilePath + "\""); Process p = run.exec(cmdStr); // 读取标准输入流、输出流,防止进程阻塞 CmdStreamThread cmdStreamThread = new CmdStreamThread(p.getInputStream(), p.getErrorStream()); int retCode = p.waitFor(); p.destroy(); if (retCode == 0) { // 正常转换结束 File mp4File = new File(playFilePath); String playFileName = mp4File.getName(); String token = OtherTools.getMp4NamePrefix(playFileName); String url = OtherTools.playMp4RootUrl + token; Map dataMap = new HashMap(); dataMap.put("url", url); dataMap.put("videoUrl", videoUrl); return new ResultClass(true, dataMap); } else { // 转换出错 String errStr = cmdStreamThread.errString != null ? cmdStreamThread.errString : cmdStreamThread.outString; logger.error("ffmpeg抓取rtsp转为mp4时失败,错误信息:" + errStr); return new ResultClass(false, "ffmpeg抓取rtsp转为mp4时失败"); } } catch (Exception e) { logger.error("海康调用回调API出错:", e); ResultClass resultClass = new ResultClass(false, "海康调用回调API出错"); return resultClass; } } /* * 控制命令入口 * */ public ResultClass PtzControllingMain(Camera hkCamera) { // 开始控制命令 ResultClass startResultClass = PtzControlling(hkCamera, 0); // 控制命令执行成功后要调用停止命令 if (startResultClass.name) { // 停止控制 ResultClass endResultClass = PtzControlling(hkCamera, 1); return endResultClass; } return startResultClass; } /* * 根据监控点进行云台控制 */ private ResultClass PtzControlling(Camera hkCamera, int action) { try { String url = "video/v1/ptzs/controlling"; /** * STEP5:组装请求参数 */ JSONObject jsonBody = new JSONObject(); jsonBody.put("cameraIndexCode", hkCamera.cameraIndexCode); // 0 开始 1 停止 jsonBody.put("action", action); int sdkCommandIndex = EnumTools.listSdkCommand.indexOf(hkCamera.command); if (sdkCommandIndex == -1) return new ResultClass(false, "无效的控制命令"); String commandStr = EnumTools.arrHkvisionCommand[sdkCommandIndex]; jsonBody.put("command", commandStr); jsonBody.put("speed", hkCamera.speed); String body = jsonBody.toString(); ResultClass resultClass = SendRequest(url, body); return resultClass; } catch (Exception e) { String str = action == 0 ? "开始时" : "停止时"; logger.error("海康调用控制API," + str + "出错:", e); ResultClass resultClass = new ResultClass(false, "海康调用控制API" + str + "出错"); return resultClass; } } /* 分页获取监控点 */ public ResultClass GetCameraPointsByPage(Camera hkCamera) { try { String url = "resource/v1/cameras"; /** * STEP5:组装请求参数 */ JSONObject jsonBody = new JSONObject(); jsonBody.put("pageNo", hkCamera.pageNo); jsonBody.put("pageSize", hkCamera.pageSize); String body = jsonBody.toString(); return SendRequest(url, body); } catch (Exception e) { logger.error("海康调用分页获取监控点API出错:", e); ResultClass resultClass = new ResultClass(false, "海康调用分页获取监控点API出错"); return resultClass; } } /* * 获取access_token */ public ResultClass GetAccessToken(Camera hkCamera) { try { String url = "v1/oauth/token"; /** * STEP5:组装请求参数 */ JSONObject jsonBody = new JSONObject(); String body = jsonBody.toString(); return SendRequest(url, body); } catch (Exception e) { logger.error("海康调用access_token API出错:", e); ResultClass resultClass = new ResultClass(false, "海康调用access_token API出错"); return resultClass; } } /* * 获取电视墙大屏信息 */ public ResultClass GetDianshiQiang(Camera hkCamera) { try { String url = "tvms/v1/tvwall/allResources"; /** * STEP5:组装请求参数 */ JSONObject jsonBody = new JSONObject(); String body = jsonBody.toString(); ResultClass resultClass = SendRequest(url, body); return resultClass; } catch (Exception e) { logger.error("海康调用电视墙大屏API出错:", e); ResultClass resultClass = new ResultClass(false, "海康调用电视墙大屏API出错"); return resultClass; } } /* * 传入接口名称和参数,方便客户端调用测试 */ public ResultClass GetOtherInfo(Camera hkCamera) { try { String paramStr = ""; if (hkCamera.paramStr != null && !"".equals(hkCamera.paramStr)) { JSONObject jsonBody = new JSONObject(); Map tempMap = JsonTools.str2Map(hkCamera.paramStr); for (Map.Entry entry : tempMap.entrySet()) { jsonBody.put(entry.getKey(), entry.getValue()); } paramStr = jsonBody.toString(); } ResultClass resultClass = SendRequest(hkCamera.url, paramStr); return resultClass; } catch (Exception e) { logger.error("海康" + hkCamera.url + "出错:", e); ResultClass resultClass = new ResultClass(false, "海康调用" + hkCamera.url + "出错"); return resultClass; } } }