HkCameraExecuteApi.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. package com.persagy.cameractl.service;
  2. import com.hikvision.artemis.sdk.ArtemisHttpUtil;
  3. import com.hikvision.artemis.sdk.config.ArtemisConfig;
  4. import com.persagy.cameractl.conf.CameraApiConfig;
  5. import com.persagy.cameractl.utils.Camera;
  6. import com.persagy.cameractl.utils.CmdStreamThread;
  7. import com.persagy.cameractl.utils.EnumTools;
  8. import com.persagy.cameractl.utils.ResultClass;
  9. import com.persagy.cameractl.utils.JsonTools;
  10. import com.persagy.cameractl.utils.OtherTools;
  11. import cn.hutool.core.date.DateUtil;
  12. import java.io.File;
  13. import java.util.Date;
  14. import java.util.HashMap;
  15. import java.util.Map;
  16. import org.slf4j.Logger;
  17. import org.slf4j.LoggerFactory;
  18. import org.springframework.beans.factory.annotation.Autowired;
  19. import org.springframework.stereotype.Component;
  20. import net.sf.json.JSONObject;
  21. @Component
  22. public class HkCameraExecuteApi {
  23. Logger logger = LoggerFactory.getLogger(HkCameraExecuteApi.class);
  24. @Autowired
  25. private CameraApiConfig cameraApiConfig;
  26. /**
  27. * STEP2:设置OpenAPI接口的上下文
  28. */
  29. final String ARTEMIS_PATH = "/artemis/api/";
  30. /*
  31. * 解析返回结果
  32. * */
  33. private ResultClass parseResult(String resultStr) {
  34. ResultClass resultClass = new ResultClass();
  35. resultClass.name = false;
  36. try {
  37. if (resultStr == null || resultStr.equals("")) {
  38. resultClass.reason = "结果为空";
  39. return resultClass;
  40. }
  41. // org.springframework.boot.configurationprocessor.json.JSONObject resultMap=new
  42. // org.springframework.boot.configurationprocessor.json.JSONObject(resultStr);
  43. Map<String, Object> mapResult = JsonTools.str2Map(resultStr);
  44. String msgStr = String.valueOf(mapResult.get("msg"));
  45. if (msgStr == null || !msgStr.equals("success")) {
  46. resultClass.reason = "错误码:" + String.valueOf(mapResult.get("code")) + ",错误原因:"
  47. + String.valueOf(mapResult.get("msg"));
  48. return resultClass;
  49. }
  50. resultClass.name = true;
  51. resultClass.resultData = mapResult.get("data");
  52. return resultClass;
  53. } catch (Exception e) {
  54. logger.error("海康中心平台返回结果非法:" + resultStr);
  55. resultClass.reason = "海康中心平台返回结果非法,请查看后台日志";
  56. return resultClass;
  57. }
  58. };
  59. /*
  60. * 发送请求并解析返回结果
  61. * */
  62. private ResultClass SendRequest(String url, String paramString) {
  63. /**
  64. * STEP1:设置平台参数,根据实际情况,设置host appkey appsecret 三个参数.
  65. */
  66. ArtemisConfig.host = cameraApiConfig.getHkApiHost(); // artemis网关服务器ip端口
  67. ArtemisConfig.appKey = cameraApiConfig.getHkApiKey(); // 秘钥appkey
  68. ArtemisConfig.appSecret = cameraApiConfig.getHkApiSecret();// 秘钥appSecret
  69. /**
  70. * STEP3:设置接口的URI地址
  71. */
  72. String previewURLsApi = ARTEMIS_PATH + url;
  73. Map<String, String> path = new HashMap<String, String>(2) {
  74. /**
  75. *
  76. */
  77. private static final long serialVersionUID = 1L;
  78. {
  79. put("https://", previewURLsApi);// 根据现场环境部署确认是http还是https
  80. }
  81. };
  82. /**
  83. * STEP4:设置参数提交方式
  84. */
  85. String contentType = "application/json";
  86. /**
  87. * STEP6:调用接口
  88. */
  89. String result = ArtemisHttpUtil.doPostStringArtemis(path, paramString, null, null, contentType, null);// post请求application/json类型参数
  90. return parseResult(result);
  91. };
  92. /*
  93. * 根据监控点获取预览流
  94. */
  95. public ResultClass GetCameraPreviewURL(Camera hkCamera) {
  96. try {
  97. String url = "video/v2/cameras/previewURLs";
  98. /**
  99. * STEP5:组装请求参数
  100. */
  101. JSONObject jsonBody = new JSONObject();
  102. jsonBody.put("cameraIndexCode", hkCamera.cameraIndexCode);
  103. jsonBody.put("streamType", hkCamera.streamType);
  104. jsonBody.put("protocol", hkCamera.protocol);
  105. // 传输协议(传输层协议),0:UDP 1:TCP 默认是TCP 注:GB28181 2011及以前版本只支持UDP传输
  106. // jsonBody.put("transmode", 1);
  107. String expandStr = "transcode=" + hkCamera.transcode + "&resolution=" + hkCamera.resolution + "&bitrate="
  108. + hkCamera.bitrate + "&videotype=" + hkCamera.videotype;
  109. jsonBody.put("expand", expandStr);
  110. String body = jsonBody.toString();
  111. return SendRequest(url, body);
  112. } catch (Exception e) {
  113. logger.error("海康调用实时预览API出错:", e);
  114. ResultClass resultClass = new ResultClass(false, "海康调用实时预览API出错");
  115. return resultClass;
  116. }
  117. }
  118. /*
  119. * 根据监控点获取回放流
  120. */
  121. public ResultClass GetCameraPlayBackURL(Camera hkCamera) {
  122. try {
  123. String reqUrl = "video/v2/cameras/playbackURLs";
  124. /**
  125. * STEP5:组装请求参数
  126. * 因为香港置地返回的回放rtsp流总是在剩余大概15秒的时候卡顿,所以传过去的结束时间要加30秒,所以ffmpeg命令里要用-t控制实际读取时长
  127. */
  128. Date dateStart = DateUtil.parse(hkCamera.startDateStr);
  129. long startMillSeconds = dateStart.getTime();
  130. Date dateEnd = DateUtil.parse(hkCamera.endDateStr);
  131. long endMillSeconds = dateEnd.getTime();
  132. // 先求得真实的回放时长
  133. long temp = endMillSeconds - startMillSeconds;
  134. long hourCount = 0;
  135. long minuteCount = 0;
  136. long secondCount = temp / 1000;
  137. long millSecondCount = temp % 1000;
  138. // 到了分钟级
  139. if (secondCount >= 60) {
  140. minuteCount = secondCount / 60;
  141. secondCount = secondCount % 60;
  142. // 到了小时级
  143. if (minuteCount >= 60) {
  144. hourCount = minuteCount / 60;
  145. minuteCount = minuteCount % 60;
  146. }
  147. }
  148. long endMillSeconds2 = endMillSeconds + 30 * 1000;
  149. Date enDate2 = DateUtil.date(endMillSeconds2);
  150. String endString2 = DateUtil.format(enDate2, "yyyy-MM-dd HH:mm:ss");
  151. JSONObject jsonBody = new JSONObject();
  152. jsonBody.put("cameraIndexCode", hkCamera.cameraIndexCode);
  153. jsonBody.put("protocol", hkCamera.protocol);
  154. jsonBody.put("beginTime", hkCamera.startDateStr.replace(" ", "T") + ".000+08:00");
  155. jsonBody.put("endTime", endString2.replace(" ", "T") + ".000+08:00");
  156. // 传输协议(传输层协议),0:UDP 1:TCP 默认是TCP 注:GB28181 2011及以前版本只支持UDP传输
  157. // jsonBody.put("transmode", 1);
  158. String expandStr = "transcode=" + hkCamera.transcode + "&resolution=" + hkCamera.resolution + "&bitrate="
  159. + hkCamera.bitrate + "&videotype=" + hkCamera.videotype;
  160. jsonBody.put("expand", expandStr);
  161. String body = jsonBody.toString();
  162. ResultClass resultClass = SendRequest(reqUrl, body);
  163. // return resultClass;
  164. // hls格式回放时,直接返回
  165. // if (hkCamera.protocol.equals("hls"))
  166. // return resultClass;
  167. /*
  168. * 如果不是hls格式,那么即为rtsp格式,此时需抓取rtsp流并转成mp4
  169. * */
  170. // 调用失败直接返回
  171. if (!resultClass.name)
  172. return resultClass;
  173. String resultDataStr = JsonTools.obj2Str(resultClass.resultData);
  174. Map<String, Object> resultDataMap = JsonTools.str2Map(resultDataStr);
  175. String videoUrl = String.valueOf(resultDataMap.get("url"));
  176. if (videoUrl == null || videoUrl.equals(""))
  177. return new ResultClass(false, "未获取到视频源地址");
  178. String playFilePath = OtherTools.getVideoFilePath();
  179. if (playFilePath.equals("")) {
  180. return new ResultClass(false, "回放文件名称生成失败");
  181. }
  182. // 抓取视频流转为页面上可播放的MP4
  183. Runtime run = Runtime.getRuntime();
  184. /*
  185. * stimeout、rw_timeout的单位为微秒 1秒=1000000微秒
  186. * 因为香港置地返回的回放rtsp流总是在剩余大概15秒的时候卡顿,所以传过去的结束时间要加30秒,所以ffmpeg命令里要用-t控制实际读取时长
  187. * */
  188. String timeDuration = hourCount + ":" + minuteCount + ":" + secondCount
  189. + (millSecondCount > 0 ? "." + millSecondCount : "");
  190. String cmdStr = hkCamera.protocol.equals("hls")
  191. ? ("ffmpeg -i \"" + videoUrl + "\" -c copy -y \"" + playFilePath + "\"")
  192. : ("ffmpeg -t " + timeDuration + " -rtsp_transport tcp -i \"" + videoUrl + "\" -y \"" + playFilePath
  193. + "\"");
  194. Process p = run.exec(cmdStr);
  195. // 读取标准输入流、输出流,防止进程阻塞
  196. CmdStreamThread cmdStreamThread = new CmdStreamThread(p.getInputStream(), p.getErrorStream());
  197. int retCode = p.waitFor();
  198. p.destroy();
  199. if (retCode == 0) {
  200. // 正常转换结束
  201. File mp4File = new File(playFilePath);
  202. String playFileName = mp4File.getName();
  203. String token = OtherTools.getMp4NamePrefix(playFileName);
  204. String url = OtherTools.playMp4RootUrl + token;
  205. Map<String, String> dataMap = new HashMap<String, String>();
  206. dataMap.put("url", url);
  207. dataMap.put("videoUrl", videoUrl);
  208. return new ResultClass(true, dataMap);
  209. } else {
  210. // 转换出错
  211. String errStr = cmdStreamThread.errString != null ? cmdStreamThread.errString
  212. : cmdStreamThread.outString;
  213. logger.error("ffmpeg抓取rtsp转为mp4时失败,错误信息:" + errStr);
  214. return new ResultClass(false, "ffmpeg抓取rtsp转为mp4时失败");
  215. }
  216. } catch (Exception e) {
  217. logger.error("海康调用回调API出错:", e);
  218. ResultClass resultClass = new ResultClass(false, "海康调用回调API出错");
  219. return resultClass;
  220. }
  221. }
  222. /*
  223. * 控制命令入口
  224. * */
  225. public ResultClass PtzControllingMain(Camera hkCamera) {
  226. // 开始控制命令
  227. ResultClass startResultClass = PtzControlling(hkCamera, 0);
  228. // 控制命令执行成功后要调用停止命令
  229. if (startResultClass.name) {
  230. // 停止控制
  231. ResultClass endResultClass = PtzControlling(hkCamera, 1);
  232. return endResultClass;
  233. }
  234. return startResultClass;
  235. }
  236. /*
  237. * 根据监控点进行云台控制
  238. */
  239. private ResultClass PtzControlling(Camera hkCamera, int action) {
  240. try {
  241. String url = "video/v1/ptzs/controlling";
  242. /**
  243. * STEP5:组装请求参数
  244. */
  245. JSONObject jsonBody = new JSONObject();
  246. jsonBody.put("cameraIndexCode", hkCamera.cameraIndexCode);
  247. // 0 开始 1 停止
  248. jsonBody.put("action", action);
  249. int sdkCommandIndex = EnumTools.listSdkCommand.indexOf(hkCamera.command);
  250. if (sdkCommandIndex == -1)
  251. return new ResultClass(false, "无效的控制命令");
  252. String commandStr = EnumTools.arrHkvisionCommand[sdkCommandIndex];
  253. jsonBody.put("command", commandStr);
  254. jsonBody.put("speed", hkCamera.speed);
  255. String body = jsonBody.toString();
  256. ResultClass resultClass = SendRequest(url, body);
  257. return resultClass;
  258. } catch (Exception e) {
  259. String str = action == 0 ? "开始时" : "停止时";
  260. logger.error("海康调用控制API," + str + "出错:", e);
  261. ResultClass resultClass = new ResultClass(false, "海康调用控制API" + str + "出错");
  262. return resultClass;
  263. }
  264. }
  265. /* 分页获取监控点 */
  266. public ResultClass GetCameraPointsByPage(Camera hkCamera) {
  267. try {
  268. String url = "resource/v1/cameras";
  269. /**
  270. * STEP5:组装请求参数
  271. */
  272. JSONObject jsonBody = new JSONObject();
  273. jsonBody.put("pageNo", hkCamera.pageNo);
  274. jsonBody.put("pageSize", hkCamera.pageSize);
  275. String body = jsonBody.toString();
  276. return SendRequest(url, body);
  277. } catch (Exception e) {
  278. logger.error("海康调用分页获取监控点API出错:", e);
  279. ResultClass resultClass = new ResultClass(false, "海康调用分页获取监控点API出错");
  280. return resultClass;
  281. }
  282. }
  283. /*
  284. * 获取access_token
  285. */
  286. public ResultClass GetAccessToken(Camera hkCamera) {
  287. try {
  288. String url = "v1/oauth/token";
  289. /**
  290. * STEP5:组装请求参数
  291. */
  292. JSONObject jsonBody = new JSONObject();
  293. String body = jsonBody.toString();
  294. return SendRequest(url, body);
  295. } catch (Exception e) {
  296. logger.error("海康调用access_token API出错:", e);
  297. ResultClass resultClass = new ResultClass(false, "海康调用access_token API出错");
  298. return resultClass;
  299. }
  300. }
  301. /*
  302. * 获取电视墙大屏信息
  303. */
  304. public ResultClass GetDianshiQiang(Camera hkCamera) {
  305. try {
  306. String url = "tvms/v1/tvwall/allResources";
  307. /**
  308. * STEP5:组装请求参数
  309. */
  310. JSONObject jsonBody = new JSONObject();
  311. String body = jsonBody.toString();
  312. ResultClass resultClass = SendRequest(url, body);
  313. return resultClass;
  314. } catch (Exception e) {
  315. logger.error("海康调用电视墙大屏API出错:", e);
  316. ResultClass resultClass = new ResultClass(false, "海康调用电视墙大屏API出错");
  317. return resultClass;
  318. }
  319. }
  320. /*
  321. * 传入接口名称和参数,方便客户端调用测试
  322. */
  323. public ResultClass GetOtherInfo(Camera hkCamera) {
  324. try {
  325. String paramStr = "";
  326. if (hkCamera.paramStr != null && !"".equals(hkCamera.paramStr)) {
  327. JSONObject jsonBody = new JSONObject();
  328. Map<String, Object> tempMap = JsonTools.str2Map(hkCamera.paramStr);
  329. for (Map.Entry<String, Object> entry : tempMap.entrySet()) {
  330. jsonBody.put(entry.getKey(), entry.getValue());
  331. }
  332. paramStr = jsonBody.toString();
  333. }
  334. ResultClass resultClass = SendRequest(hkCamera.url, paramStr);
  335. return resultClass;
  336. } catch (Exception e) {
  337. logger.error("海康" + hkCamera.url + "出错:", e);
  338. ResultClass resultClass = new ResultClass(false, "海康调用" + hkCamera.url + "出错");
  339. return resultClass;
  340. }
  341. }
  342. }