CameraUtil.java 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162
  1. package com.ozs.utils;
  2. import com.alibaba.fastjson2.JSON;
  3. import com.alibaba.fastjson2.JSONArray;
  4. import com.alibaba.fastjson2.JSONObject;
  5. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  6. import com.hikvision.artemis.sdk.ArtemisHttpUtil;
  7. import com.hikvision.artemis.sdk.config.ArtemisConfig;
  8. import com.ozs.common.config.BaseConfig;
  9. import com.ozs.common.constant.Constants;
  10. import com.ozs.common.core.domain.AjaxResult;
  11. import com.ozs.common.core.domain.entity.SysDictData;
  12. import com.ozs.common.core.redis.RedisCache;
  13. import com.ozs.common.exception.base.BaseException;
  14. import com.ozs.common.utils.DateUtils;
  15. import com.ozs.common.utils.HttpClientUtil;
  16. import com.ozs.common.utils.http.HttpUtils;
  17. import com.ozs.entity.BaseTerminal;
  18. import com.ozs.entity.MsgHeartbeatAlarmMessage;
  19. import com.ozs.entity.vo.CamerasVo;
  20. import com.ozs.entity.vo.PlaybackVo;
  21. import com.ozs.framework.config.ServerConfig;
  22. import com.ozs.service.BaseTerminalService;
  23. import com.ozs.service.MsgHeartbeatAlarmMessageService;
  24. import com.ozs.system.mapper.SysDictDataMapper;
  25. import com.ozs.system.service.ISysDictTypeService;
  26. import lombok.SneakyThrows;
  27. import lombok.extern.slf4j.Slf4j;
  28. import org.apache.commons.lang3.StringUtils;
  29. import org.springframework.beans.factory.annotation.Autowired;
  30. import org.springframework.context.annotation.Configuration;
  31. import org.springframework.util.ObjectUtils;
  32. import javax.annotation.PostConstruct;
  33. import java.io.BufferedReader;
  34. import java.io.BufferedWriter;
  35. import java.io.File;
  36. import java.io.FileFilter;
  37. import java.io.IOException;
  38. import java.io.InputStreamReader;
  39. import java.io.OutputStreamWriter;
  40. import java.io.PrintWriter;
  41. import java.text.ParseException;
  42. import java.text.SimpleDateFormat;
  43. import java.time.Instant;
  44. import java.time.LocalDateTime;
  45. import java.time.OffsetDateTime;
  46. import java.time.ZoneOffset;
  47. import java.time.format.DateTimeFormatter;
  48. import java.util.ArrayList;
  49. import java.util.Calendar;
  50. import java.util.Date;
  51. import java.util.GregorianCalendar;
  52. import java.util.HashMap;
  53. import java.util.List;
  54. import java.util.Map;
  55. import java.util.Random;
  56. import java.util.Set;
  57. import java.util.UUID;
  58. import java.util.concurrent.Callable;
  59. import java.util.concurrent.CompletableFuture;
  60. import java.util.concurrent.ExecutionException;
  61. import java.util.concurrent.ExecutorService;
  62. import java.util.concurrent.Executors;
  63. import java.util.concurrent.TimeUnit;
  64. import java.util.concurrent.TimeoutException;
  65. import java.util.stream.Collectors;
  66. /**
  67. * 相机工具
  68. */
  69. @Configuration
  70. @Slf4j
  71. public class CameraUtil {
  72. private static final ExecutorService executor = Executors.newFixedThreadPool(20);
  73. private static String historyUrl;
  74. private static String ffmpegPath;
  75. private static String filePath;
  76. private static String transcribeFilePath;
  77. private static String webUrl;
  78. private static String bakUrl;
  79. private static String bakUrlRtsp;
  80. private static String wsUrl;
  81. private static String httpUrl;
  82. private static CmdCameraUtil cUtil;
  83. private static RedisCache rc;
  84. private static ServerConfig sc;
  85. private static String recordUrl;
  86. private static String hkUrl;
  87. private static String host;
  88. private static String appKey;
  89. private static String appSecret;
  90. private static String rtmpUrl;
  91. @Autowired
  92. private CaneraConfig caneraConfig;
  93. @Autowired
  94. private CmdCameraUtil cmdCameraUtil;
  95. @Autowired
  96. private SysDictDataMapper dictDataMapper;
  97. @Autowired
  98. private RedisCache redisCache;
  99. @Autowired
  100. private ServerConfig serverConfig;
  101. @Autowired
  102. private BaseTerminalService baseTerminalService;
  103. @Autowired
  104. private MsgHeartbeatAlarmMessageService msgHeartbeatAlarmMessageService;
  105. @Autowired
  106. private ISysDictTypeService dictTypeService;
  107. @Autowired
  108. private RtspToMP4 rtspToMP4;
  109. private Map<String, Process> map = new HashMap<>();
  110. public final static String tsFilekey = "mergeVideoTsFile";
  111. /**
  112. * 历史回放
  113. *
  114. * @param fromVideoFileList
  115. * @param ph
  116. * @return
  117. * @throws IOException
  118. */
  119. public static String historyPlay(List<String> fromVideoFileList, String ph, boolean flay) {
  120. // 视频服务映射路径
  121. String NewfilePath = BaseConfig.getProfile() + "/" + ph;
  122. log.info("NewfilePath:{}", NewfilePath);
  123. log.info("fromVideoFileList:{}", fromVideoFileList);
  124. if (ObjectUtils.isEmpty(fromVideoFileList) || fromVideoFileList.size() <= 0) {
  125. throw new BaseException("当前相机无视频录像");
  126. }
  127. executor.submit(new Runnable() {
  128. @Override
  129. public void run() {
  130. try {
  131. txConvetor(fromVideoFileList, NewfilePath, flay);
  132. } catch (IOException e) {
  133. log.error(e.getMessage());
  134. e.printStackTrace();
  135. }
  136. }
  137. });
  138. // executor.shutdown();
  139. return Constants.RESOURCE_PREFIX + "/" + ph;
  140. }
  141. @SneakyThrows
  142. public static void txConvetor(List<String> fromVideoFileList,
  143. String newfilePath,
  144. boolean fly) throws IOException {
  145. /*
  146. * ffmpeg -i 20230411_155847_155947-d4c2265d-d83e-11ed-8e7f-fa163e4e1e9f.flv -c:v copy 1.ts
  147. ffmpeg -i 20230411_155948_160048-f91fea03-d83e-11ed-8e7f-fa163e4e1e9f.flv -c:v copy 2.ts
  148. ffmpeg -i "concat:1.ts|2.ts" -c copy output.mp4
  149. * */
  150. File file = new File(newfilePath);
  151. boolean flay = false;
  152. if (!file.getParentFile().exists()) {
  153. boolean mkdirs = file.getParentFile().mkdirs();
  154. log.info("创建文件夹:{}", file.getParentFile().getPath());
  155. log.info("创建文件夹结果:{}", mkdirs);
  156. flay = true;
  157. }
  158. cUtil.cmd("chomd -R 777 " + file.getParentFile().getPath());
  159. log.info("newfilePath:{}", newfilePath);
  160. StringBuffer sm = new StringBuffer(ffmpegPath + " -i \"concat:");
  161. List<String> fileTs = new ArrayList<>();
  162. for (int t = 0; t < fromVideoFileList.size(); t++) {
  163. File ft = new File(fromVideoFileList.get(t));
  164. if (ft.exists()) {
  165. log.info("file:{}", fromVideoFileList.get(t));
  166. String substring = fromVideoFileList.get(t).substring(0, fromVideoFileList.get(t).lastIndexOf("."));
  167. int x;//定义两变量
  168. Random ne = new Random();//实例化一个random的对象ne
  169. x = ne.nextInt(9999 - 1000 + 1) + 1000;//为变量赋随机值1000-9999
  170. substring = substring + x;//定义两变量
  171. String cmdstr = ffmpegPath + " -i " + fromVideoFileList.get(t) + " -c:v copy " + substring + ".ts";
  172. log.info("转换命令:{}", cmdstr);
  173. cUtil.cmd(cmdstr);
  174. fileTs.add(substring + ".ts");
  175. if (t != fromVideoFileList.size() - 1) {
  176. sm.append(substring + ".ts|");
  177. } else {
  178. sm.append(substring + ".ts\" ");
  179. }
  180. }
  181. }
  182. if (fileTs.size() > 0) {
  183. Map<String, Object> mergeVideoTsFile = rc.getCacheMap(tsFilekey);
  184. if (ObjectUtils.isEmpty(mergeVideoTsFile)) {
  185. mergeVideoTsFile = new HashMap<>();
  186. }
  187. if (!flay) {
  188. // 如果没有解除,把生成的文件放入要删除的定时任务 redis key 中
  189. fileTs.add(newfilePath);
  190. }
  191. mergeVideoTsFile.put(System.currentTimeMillis() + "", fileTs);
  192. rc.deleteObject(tsFilekey);
  193. if (mergeVideoTsFile.size() > 0) {
  194. rc.setCacheMap(tsFilekey, mergeVideoTsFile);
  195. }
  196. sm.append("-c copy " + newfilePath);
  197. log.info("合并命令:{}", sm.toString());
  198. cUtil.cmd(sm.toString());
  199. }
  200. }
  201. /**
  202. * 实时播放的拼接流
  203. *
  204. * @param cameraCode 相机编码
  205. * @param channel 相机通道
  206. * @return
  207. */
  208. public static String getPlayFlv(String cameraCode, String channel, boolean flay) {
  209. if (!flay) {
  210. return bakUrl + "/hdl/" + cameraCode + "/" + channel + ".flv";
  211. }
  212. return wsUrl + "/ws/" + cameraCode + "/" + channel + ".flv";
  213. // if (!flay) {
  214. // return bakUrl + "/ws/" + channel + "/" + cameraCode + ".flv";
  215. // }
  216. // return webUrl + "/ws/" + channel + "/" + cameraCode + ".flv";
  217. }
  218. /**
  219. * Rtsp实时播放的拼接流
  220. *
  221. * @param cameraCode 相机编码
  222. * @param channel 相机通道
  223. * @return
  224. */
  225. public static String getPlayFlvRtsp(String cameraCode, String channel, boolean flay) {
  226. if (!flay) {
  227. return bakUrlRtsp + "/" + channel + "/" + cameraCode;
  228. }
  229. return bakUrlRtsp + "/" + channel + "/" + cameraCode;
  230. // if (!flay) {
  231. // return bakUrl + "/ws/" + channel + "/" + cameraCode + ".flv";
  232. // }
  233. // return webUrl + "/ws/" + channel + "/" + cameraCode + ".flv";
  234. }
  235. public String heartbeatgetPlayFlv(String cameraCode, String channel) {
  236. List<String> pathList = new ArrayList<>();
  237. String data = HttpUtils.sendGet(webUrl + "/rtsp/api/list");
  238. if (StringUtils.isNotEmpty(data)) {
  239. JSONArray jsonArray = JSONArray.parseArray(data);
  240. for (int i = 0; i < jsonArray.size(); i++) {
  241. JSONObject jsonObject = jsonArray.getJSONObject(i);
  242. String name = jsonObject.getString("Path");
  243. pathList.add(name);
  244. }
  245. boolean contains = pathList.contains(cameraCode + "/" + channel);
  246. if (!contains) {
  247. return null;
  248. } else {
  249. return getPlayFlv(cameraCode, channel, true);
  250. }
  251. }
  252. return null;
  253. }
  254. public String heartbeatgetUrl(String cameraCode, String channel) {
  255. CamerasVo camerasVo = new CamerasVo();
  256. camerasVo.setCameraIndexCode(cameraCode);
  257. previewURLs(camerasVo, channel);
  258. return getPlayFlv(cameraCode, channel, true);
  259. }
  260. /**
  261. * web页面实时流接口
  262. *
  263. * @param cameraCode
  264. * @param channel
  265. * @return
  266. */
  267. public static String getPlayFlv(String cameraCode, String channel) {
  268. List<String> pathList = new ArrayList<>();
  269. String data = HttpUtils.sendGet(webUrl + "/rtsp/api/list");
  270. if (StringUtils.isNotEmpty(data)) {
  271. JSONArray jsonArray = JSONArray.parseArray(data);
  272. for (int i = 0; i < jsonArray.size(); i++) {
  273. JSONObject jsonObject = jsonArray.getJSONObject(i);
  274. String name = jsonObject.getString("Path");
  275. pathList.add(name);
  276. }
  277. boolean contains = pathList.contains(cameraCode + "/" + channel);
  278. if (contains) {
  279. return getPlayFlv(cameraCode, channel, true);
  280. } else {
  281. /**
  282. * jsonBody.put("cameraIndexCode", "01ea43e6676f4e47bd6c5cd9e02aa006");
  283. * jsonBody.put("streamType", 0);
  284. * jsonBody.put("protocol","rtsp");
  285. * jsonBody.put("transmode", 1);
  286. * jsonBody.put("expand","streamform=rtp");
  287. */
  288. CamerasVo camerasVo = new CamerasVo();
  289. camerasVo.setCameraIndexCode(cameraCode);
  290. previewURLs(camerasVo, channel);
  291. return getPlayFlv(cameraCode, channel, true);
  292. }
  293. } else {
  294. CamerasVo camerasVo = new CamerasVo();
  295. camerasVo.setCameraIndexCode(cameraCode);
  296. previewURLs(camerasVo, channel);
  297. return getPlayFlv(cameraCode, channel, true);
  298. }
  299. // return getPlayFlv(cameraCode, channel, true);
  300. }
  301. public static String invite(String cameraCode, String channel) {
  302. String result = null;
  303. String url = bakUrl + "/api/gb28181/invite?id=" + cameraCode + "&channel=" + channel;
  304. try {
  305. result = HttpClientUtil.get(url);
  306. log.info("result:{}", result);
  307. } catch (Exception e) {
  308. log.info(e.getMessage());
  309. e.printStackTrace();
  310. }
  311. return result;
  312. }
  313. /**
  314. * 开启录制功能
  315. *
  316. * @param cameraCode 相机编码
  317. * @param channel 相机通道
  318. * @return
  319. */
  320. public static String startRecording(String cameraCode, String channel) {
  321. return historyUrl + "/recordpro/api/start?streamPath=" + channel + "/" + cameraCode;
  322. }
  323. /**
  324. * 关闭录制功能
  325. *
  326. * @param taskId 录像接口返回的任务ID
  327. * @return
  328. */
  329. public static String endRecording(String taskId) {
  330. return historyUrl + "/recordpro/api/stop?id=" + taskId;
  331. }
  332. /**
  333. * 历史回放流(获取)
  334. *
  335. * @param channel 相机通道
  336. * @param startTm 开始时间
  337. * @param endTm 结束时间
  338. * @return
  339. */
  340. public static String historyPlayListStr(String channel, Date startTm, Date endTm, boolean flay) {
  341. List<String> list = filterPlayList(channel, startTm, endTm, filePath);
  342. String uuid = UUID.randomUUID().toString();
  343. String ph = "record/flv/" + DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, new Date())
  344. + "/" + channel + "/"
  345. + uuid + ".mp4";
  346. if (!ObjectUtils.isEmpty(list)) {
  347. try {
  348. return historyPlay(list, ph, flay);
  349. } catch (Exception e) {
  350. log.error(e.getMessage());
  351. e.printStackTrace();
  352. }
  353. } else {
  354. throw new BaseException("当前相机无视频录像");
  355. }
  356. return null;
  357. }
  358. /**
  359. * 过滤符合条件的视频
  360. *
  361. * @param channel
  362. * @param startTm
  363. * @param endTm
  364. * @param mappingUrl
  365. * @return
  366. */
  367. public static List<String> filterPlayList(String channel, Date startTm, Date endTm, String mappingUrl) {
  368. if (StringUtils.isBlank(channel)
  369. || ObjectUtils.isEmpty(startTm)
  370. || ObjectUtils.isEmpty(endTm)) {
  371. return null;
  372. }
  373. List<String> ls = new ArrayList<>();
  374. Map<Date, String> m = new HashMap<>();
  375. // 调用视频服务返回参数
  376. String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, startTm);
  377. String endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, endTm);
  378. String param = "channel=" + channel + "&startTime=" + startTime + "&endTime=" + endTime;
  379. String s = HttpUtils.sendGet(historyUrl + "/api/record/flv/list", param);
  380. // 视频拼接
  381. if (!StringUtils.isBlank(s) && !"null".equals(s) && !s.startsWith("<!DOCTYPE html>")) {
  382. List<Map<String, Object>> maps = JSON.parseArray(s, Map.class);
  383. if (ObjectUtils.isEmpty(maps)) {
  384. return null;
  385. }
  386. for (Map<String, Object> map : maps) {
  387. Object path = map.get("Path");
  388. if (!ObjectUtils.isEmpty(path)) {
  389. String s1 = path.toString();
  390. String substring = s1.substring(s1.lastIndexOf("/") + 1, s1.length());
  391. String substring1 = substring.substring(0, substring.indexOf("-"));
  392. String[] s2 = substring1.split("_");
  393. if (!ObjectUtils.isEmpty(s2)) {
  394. String s3 = s2[0] + s2[1];
  395. String s4 = s2[0] + s2[2];
  396. Date sdate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s3);
  397. if (s2[1].startsWith("23") && s2[2].startsWith("00")) {
  398. sdate = DateUtils.addDays(sdate, -1);
  399. }
  400. Date edate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s4);
  401. /* sdate |startTm| edate |endTm| */
  402. if (startTm.compareTo(sdate) >= 0
  403. && startTm.compareTo(edate) <= 0
  404. && endTm.compareTo(edate) >= 0) {
  405. m.put(sdate, mappingUrl + path.toString());
  406. /* |startTm| sdate edate |endTm| */
  407. } else if (startTm.compareTo(sdate) <= 0 && endTm.compareTo(edate) >= 0) {
  408. m.put(sdate, mappingUrl + path.toString());
  409. /* |startTm| sdate |endTm| edate */
  410. } else if (startTm.compareTo(sdate) <= 0
  411. && endTm.compareTo(sdate) >= 0
  412. && endTm.compareTo(edate) <= 0) {
  413. m.put(sdate, mappingUrl + path.toString());
  414. /* sdate |startTm| |endTm| edate */
  415. } else if (startTm.compareTo(sdate) >= 0 && endTm.compareTo(edate) <= 0) {
  416. m.put(sdate, mappingUrl + path.toString());
  417. }
  418. }
  419. }
  420. }
  421. }
  422. if (!ObjectUtils.isEmpty(m) && m.size() > 0) {
  423. Set<Date> dates = m.keySet();
  424. // 排序
  425. dates.stream().parallel().collect(Collectors.toList()).stream().sorted().forEach(d -> {
  426. ls.add(m.get(d));
  427. });
  428. return ls;
  429. }
  430. return null;
  431. }
  432. /**
  433. * 合并视频(转化文件)
  434. *
  435. * @param fromVideoFileList 视频路径
  436. * @param newfilePath 生产新的视频文件路径
  437. * @throws IOException
  438. */
  439. public static Map<String, String> myConvetor(List<String> fromVideoFileList,
  440. String newfilePath,
  441. String uuid) throws IOException {
  442. /*
  443. * for f in *.flv; do echo "file '$f'" >> mylist.txt; done
  444. ffmpeg -f concat -i mylist.txt -c copy output.flv
  445. * */
  446. File file = new File(newfilePath);
  447. boolean flay = false;
  448. if (!file.getParentFile().exists()) {
  449. file.getParentFile().mkdirs();
  450. log.info("创建文件夹:{}", file.getParentFile().getPath());
  451. flay = true;
  452. }
  453. log.info("newfilePath:{}", newfilePath);
  454. StringBuffer sm = new StringBuffer("for f in ");
  455. String pathStr = null;
  456. for (int t = 0; t < fromVideoFileList.size(); t++) {
  457. File ft = new File(fromVideoFileList.get(t));
  458. if (ft.exists()) {
  459. if (t != fromVideoFileList.size() - 1) {
  460. // sm.append(fromVideoFileList.get(t) + " ");
  461. sm.append(fromVideoFileList.get(t).substring(fromVideoFileList.get(t).lastIndexOf("/") + 1, fromVideoFileList.get(t).length()) + " ");
  462. } else {
  463. // sm.append(fromVideoFileList.get(t));
  464. sm.append(fromVideoFileList.get(t).substring(fromVideoFileList.get(t).lastIndexOf("/") + 1, fromVideoFileList.get(t).length()));
  465. pathStr = fromVideoFileList.get(t).substring(0, fromVideoFileList.get(t).lastIndexOf("/"));
  466. }
  467. }
  468. }
  469. // String substring = newfilePath.substring(0, newfilePath.lastIndexOf("."));
  470. // substring = substring + ".txt";
  471. String substring = uuid + ".txt";
  472. log.info("临时转化的文件:{}", substring);
  473. sm.append("; do echo \"file '$f'\" >> " + substring + "; done");
  474. String commit = sm.toString();
  475. log.info("合并转化文件的命令:{}", commit);
  476. Process proc = Runtime.getRuntime().exec("/bin/bash", null, null);
  477. BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
  478. PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
  479. try {
  480. String commit1 = ffmpegPath + " -f concat -safe 0 -i " + pathStr + "/" + substring + " -c copy " + newfilePath;
  481. log.info("合并视频命令:{}", commit1);
  482. List<String> commands = new ArrayList<>();
  483. if (flay) {
  484. commands.add("chomd -R 777 " + file.getParentFile().getPath());
  485. }
  486. //
  487. commands.add("cd " + pathStr);
  488. // 合并成一个临时文件
  489. commands.add(commit);
  490. // 临时文件转化为 flv
  491. // commands.add(commit1);
  492. log.info("录像视频命令:{}", commands);
  493. for (String line : commands) {
  494. log.info("命令:{}", line);
  495. out.println(line);
  496. }
  497. out.println("exit");// 这个命令必须执行,否则in流不结束。
  498. log.info("命令:{}", "exit");
  499. String rspLine = "";
  500. while ((rspLine = in.readLine()) != null) {
  501. log.info("*****:{}", rspLine);
  502. }
  503. proc.waitFor();
  504. Map<String, String> map = new HashMap<>();
  505. map.put("cmd", commit1);
  506. map.put("path", pathStr + "/" + substring);
  507. return map;
  508. } catch (InterruptedException e) {
  509. log.error(e.getMessage());
  510. e.printStackTrace();
  511. } finally {
  512. in.close();
  513. out.close();
  514. proc.destroy();
  515. }
  516. return null;
  517. }
  518. @PostConstruct
  519. public void init() {
  520. historyUrl = caneraConfig.getHistoryUrl();
  521. ffmpegPath = caneraConfig.getFfmpegPath();
  522. filePath = caneraConfig.getFilePath();
  523. transcribeFilePath = caneraConfig.getTranscribeFilePath();
  524. webUrl = caneraConfig.getWebUrl();
  525. bakUrl = caneraConfig.getBakUrl();
  526. bakUrlRtsp = caneraConfig.getBakUrlRtsp();
  527. rc = redisCache;
  528. cUtil = cmdCameraUtil;
  529. sc = serverConfig;
  530. wsUrl = caneraConfig.getWsUrl();
  531. httpUrl = caneraConfig.getHttpUrl();
  532. recordUrl = caneraConfig.getRecordUrl();
  533. hkUrl = caneraConfig.getHkUrl();
  534. host = caneraConfig.getHost();
  535. appKey = caneraConfig.getAppKey();
  536. appSecret = caneraConfig.getAppSecret();
  537. rtmpUrl = caneraConfig.getRtmpUrl();
  538. }
  539. /**
  540. * 定时任务参数flv文件
  541. *
  542. * @throws IOException
  543. * @throws InterruptedException
  544. */
  545. public void deleteFlv() throws IOException, InterruptedException {
  546. SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
  547. Date date = new Date();
  548. Calendar calendar = new GregorianCalendar();
  549. calendar.setTime(date);
  550. calendar.add(Calendar.DATE, -1); //把日期往后增加一天,整数 往后推,负数往前移动
  551. date = calendar.getTime(); //这个时间就是日期往后推一天的结果
  552. String path = BaseConfig.getProfile() + "/flv/" + DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, date);
  553. File file = new File(path);
  554. if (file.exists()) {
  555. List<String> rspList = new ArrayList<String>();
  556. Process proc = Runtime.getRuntime().exec("/bin/bash", null, null);
  557. BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
  558. PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
  559. String commit = " rm -rf " + path;
  560. List<String> commands = new ArrayList<>();
  561. // 删除
  562. commands.add(commit);
  563. log.info("删除昨天的录像视频命令:{}", commands);
  564. for (String line : commands) {
  565. out.println(line);
  566. }
  567. out.println("exit");// 这个命令必须执行,否则in流不结束。
  568. String rspLine = "";
  569. while ((rspLine = in.readLine()) != null) {
  570. System.out.println(rspLine);
  571. rspList.add(rspLine);
  572. }
  573. int i = proc.waitFor();
  574. log.info("执行结果:{}", i);
  575. in.close();
  576. out.close();
  577. proc.destroy();
  578. }
  579. }
  580. /**
  581. * 定时任务:删除超过配置时长的录制视频
  582. *
  583. * @throws IOException
  584. * @throws InterruptedException
  585. */
  586. public void deleteFlvExceed() throws IOException, InterruptedException, ParseException {
  587. //字典中设置的值
  588. List<SysDictData> sysCameraRecordTime = dictDataMapper.selectDictDataByType("sys_camera_record_time");
  589. SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
  590. Date date = new Date();
  591. Calendar calendar = new GregorianCalendar();
  592. calendar.setTime(date);
  593. //正数,日期天数加
  594. //负数,日期天数减 提前45天
  595. if (!ObjectUtils.isEmpty(sysCameraRecordTime)) {
  596. String dictValue = sysCameraRecordTime.get(0).getDictValue();
  597. calendar.add(Calendar.DAY_OF_YEAR, Integer.parseInt("-" + dictValue));
  598. } else {
  599. calendar.add(Calendar.DAY_OF_YEAR, -45);
  600. }
  601. date = calendar.getTime();
  602. //遍历每个进行视频录制的摄像头
  603. File file = new File(transcribeFilePath);
  604. log.info("file.Name()======================================" + file.getName());
  605. log.info("file.exists()======================================" + file.exists());
  606. if (file.exists() && file.isDirectory()) {
  607. //获取文件夹中所有的子文件夹和文件
  608. File[] files = file.listFiles();
  609. if (!ObjectUtils.isEmpty(files) && files.length > 0) {
  610. for (File file1 : files) {
  611. // file1=/opt/streams/record/flv/34020000001320000167
  612. log.info("file1.Name()======================================" + file1.getName());
  613. if (file1.exists() && file1.isDirectory()) {
  614. //相机文件
  615. File[] fs = file1.listFiles();
  616. if (!ObjectUtils.isEmpty(fs) && fs.length > 0) {
  617. for (File f : fs) {
  618. // f=/opt/streams/record/flv/34020000001320000167/20230328_192033_192037-91509173-cd5a-11ed-8a42-fa163e4e1e9f.flv
  619. //fName=20230328_192033_192037-91509173-cd5a-11ed-8a42-fa163e4e1e9f.flv
  620. String fName = f.getName();
  621. log.info("fName======================================" + fName);
  622. String[] split = fName.split("_");
  623. if (split.length > 0) {
  624. //20230328
  625. String s = split[0];
  626. Date parse = sdf.parse(s);
  627. long fTime = parse.getTime();
  628. long dateTime = date.getTime();
  629. //删除过期文件
  630. if (fTime < dateTime) {
  631. f.delete();
  632. }
  633. }
  634. }
  635. }
  636. }
  637. }
  638. }
  639. }
  640. }
  641. public static File[] getCurFilesList(String filePath) {
  642. File path = new File(filePath);
  643. File[] listFiles = path.listFiles(new FileFilter() {
  644. @Override
  645. public boolean accept(File pathname) {
  646. if (pathname.isFile()) {
  647. return true;
  648. } else {
  649. return false;
  650. }
  651. }
  652. });
  653. return listFiles;
  654. }
  655. public static void execute(String command) {
  656. try {
  657. ProcessBuilder process = new ProcessBuilder(command);
  658. process.inheritIO().start().waitFor();
  659. } catch (Exception e) {
  660. e.printStackTrace();
  661. }
  662. }
  663. /**
  664. * web页面视频回放接口
  665. *
  666. * @param code
  667. * @param startTm
  668. * @param endTm
  669. * @return
  670. */
  671. public static String getRecordList(String code, Date startTm, Date endTm, String channel) {
  672. PlaybackVo playbackVo = new PlaybackVo();
  673. playbackVo.setCameraIndexCode(code);
  674. // 将 Date 转换为 Instant
  675. Instant startInstant = startTm.toInstant();
  676. Instant endInstant = endTm.toInstant();
  677. // 将 Instant 转换为 OffsetDateTime
  678. OffsetDateTime startOffsetDateTime = startInstant.atOffset(ZoneOffset.UTC);
  679. OffsetDateTime endOffsetDateTime = endInstant.atOffset(ZoneOffset.UTC);
  680. // 格式化为字符串
  681. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
  682. String formattedStartTime = startOffsetDateTime.format(formatter);
  683. String formattedEndTime = endOffsetDateTime.format(formatter);
  684. // 将格式化后的时间设置到 playbackVo 中
  685. playbackVo.setBeginTime(formattedStartTime);
  686. playbackVo.setEndTime(formattedEndTime);
  687. playbackVo.setProtocol("rtsp");
  688. playbackVo.setExpand("streamform=rtp");
  689. //对象转换json字符串
  690. String body = JSONObject.toJSONString(playbackVo);
  691. //调用天网接口
  692. String playbackURLs = getPreviewURLs("/api/video/v1/cameras/playbackURLs", body);
  693. JSONObject outJson = (JSONObject) JSONObject.parse(playbackURLs);
  694. log.info("outJson-------->" + outJson);
  695. if ("0".equals(outJson.getString("code"))) {
  696. JSONObject data = outJson.getJSONObject("data");
  697. String urls = data.getString("url");
  698. log.info("urls----------->" + urls);
  699. try {
  700. TimeUnit.SECONDS.sleep(3);
  701. String msg = HttpUtils.sendGet(httpUrl + "/rtsp/api/pull?target=" + urls + "&streamPath=" + code + "/" + channel + "&save=0");
  702. log.info("msg---------->" + msg);
  703. } catch (InterruptedException e) {
  704. e.printStackTrace();
  705. }
  706. return getPlayFlv(code, channel, true);
  707. } else {
  708. return "调用天网接口失败";
  709. }
  710. // return filterRecordList(channel, startTm, endTm, filePath, recordUrl + "profile/");
  711. }
  712. /**
  713. * HTTP流转RTSP流
  714. */
  715. public String streamConversion(String code) {
  716. ExecutorService executor = Executors.newSingleThreadExecutor();
  717. Callable<String> task = new Callable<String>() {
  718. @Override
  719. public String call() throws Exception {
  720. // 执行网络请求...
  721. log.info(ffmpegPath + " -re -i /opt/streams/compress/70b0bd685b0d4df1b4faf74ff5c1e7fd.mp4 -c:v copy -c:a copy -f flv rtmp://10.48.36.47:1935/live/70b0bd685b0d4df1b4faf74ff5c1e7fd");
  722. cmdCameraUtil.cmd(ffmpegPath + " -re -i /opt/streams/compress/" + code + ".mp4 -c:v copy -c:a copy -f flv " + rtmpUrl + "/live/" + code);
  723. return "Response";
  724. }
  725. };
  726. try {
  727. String result = executor.submit(task).get(1, TimeUnit.SECONDS); // 设置5秒超时时间
  728. System.out.println("Response: " + result);
  729. } catch (InterruptedException | ExecutionException | TimeoutException e) {
  730. // 请求超时处理逻辑
  731. System.out.println("Request timeout");
  732. }
  733. executor.shutdown();
  734. return bakUrlRtsp + "/live/" + code;
  735. }
  736. /**
  737. * RTSP流视频压缩
  738. */
  739. public void videoCompression(String code) {
  740. // 执行网络请求...
  741. /**
  742. * /usr/bin/ffmpeg -i /opt/streams/map/70b0bd685b0d4df1b4faf74ff5c1e7fd.mp4 -c:v libx264 -s 640x480 -c:a aac -ar 44100 /opt/streams/compress/70b0bd685b0d4df1b4faf74ff5c1e7fd.mp4
  743. */
  744. log.info(ffmpegPath + " -i /opt/streams/map/" + code + ".mp4 -c:v libx264 -s 640x480 -c:a aac -ar 44100 /opt/streams/compress/" + code + ".mp4");
  745. cmdCameraUtil.cmd(ffmpegPath + " -i /opt/streams/map/" + code + ".mp4 -c:v libx264 -s 640x480 -c:a aac -ar 44100 /opt/streams/compress/" + code + ".mp4");
  746. }
  747. public static List<Map<String, Object>> filterRecordList(String channel,
  748. Date startTm,
  749. Date endTm,
  750. String mappingUrl,
  751. String wUrl) {
  752. List<Map<String, Object>> rmaps = new ArrayList<>();
  753. if (StringUtils.isBlank(channel)
  754. || ObjectUtils.isEmpty(startTm)
  755. || ObjectUtils.isEmpty(endTm)) {
  756. return null;
  757. }
  758. Map<Date, Map<String, Object>> m = new HashMap<>();
  759. // 调用视频服务返回参数
  760. String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, startTm);
  761. String endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, endTm);
  762. String param = "channel=" + channel + "&startTime=" + startTime + "&endTime=" + endTime;
  763. // /api/record/flv/list
  764. String s = HttpUtils.sendGet(webUrl + "/recordpro/api/list", param);
  765. // 视频拼接
  766. if (!StringUtils.isBlank(s) || "null".equals(s)) {
  767. List<Map<String, Object>> maps = JSON.parseArray(s, Map.class);
  768. if (ObjectUtils.isEmpty(maps)) {
  769. return null;
  770. }
  771. for (Map<String, Object> map : maps) {
  772. Object path = map.get("Path");
  773. Object size = map.get("Size");
  774. Object duration = map.get("Duration");
  775. if (!ObjectUtils.isEmpty(path)) {
  776. String s1 = path.toString();
  777. String substring = s1.substring(s1.lastIndexOf("/") + 1, s1.length());
  778. String substring1 = substring.substring(0, substring.indexOf("-"));
  779. String[] s2 = substring1.split("_");
  780. if (!ObjectUtils.isEmpty(s2)) {
  781. Map<String, Object> mo = new HashMap<>();
  782. String s3 = s2[0] + s2[1];
  783. String s4 = s2[0] + s2[2];
  784. Date sdate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s3);
  785. if (s2[1].startsWith("23") && s2[2].startsWith("00")) {
  786. sdate = DateUtils.addDays(sdate, -1);
  787. }
  788. Date edate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s4);
  789. mo.put("startTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, sdate));
  790. mo.put("entTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, edate));
  791. mo.put("url", wUrl + path.toString());
  792. mo.put("path", mappingUrl + path.toString());
  793. mo.put("fileName", substring);
  794. mo.put("size", size);
  795. mo.put("duration", duration);
  796. /* sdate |startTm| edate |endTm| */
  797. if (startTm.compareTo(sdate) >= 0
  798. && startTm.compareTo(edate) <= 0
  799. && endTm.compareTo(edate) >= 0) {
  800. m.put(sdate, mo);
  801. /* |startTm| sdate edate |endTm| */
  802. } else if (startTm.compareTo(sdate) <= 0 && endTm.compareTo(edate) >= 0) {
  803. m.put(sdate, mo);
  804. /* |startTm| sdate |endTm| edate */
  805. } else if (startTm.compareTo(sdate) <= 0
  806. && endTm.compareTo(sdate) >= 0
  807. && endTm.compareTo(edate) <= 0) {
  808. m.put(sdate, mo);
  809. /* sdate |startTm| |endTm| edate */
  810. } else if (startTm.compareTo(sdate) >= 0 && endTm.compareTo(edate) <= 0) {
  811. m.put(sdate, mo);
  812. }
  813. }
  814. }
  815. }
  816. }
  817. if (!ObjectUtils.isEmpty(m) && m.size() > 0) {
  818. Set<Date> dates = m.keySet();
  819. // 排序
  820. dates.stream().parallel().collect(Collectors.toList()).stream().sorted().forEach(d -> {
  821. rmaps.add(m.get(d));
  822. });
  823. log.info("rmaps:{}", rmaps);
  824. return rmaps;
  825. }
  826. return null;
  827. }
  828. /**
  829. * 机车状态修改
  830. */
  831. public void heartbeat() {
  832. List<BaseTerminal> list = baseTerminalService.list();
  833. for (BaseTerminal baseTerminal : list) {
  834. QueryWrapper<MsgHeartbeatAlarmMessage> wrapper = new QueryWrapper<>();
  835. wrapper.eq("terminal_code", wrapper);
  836. wrapper.orderByDesc("create_time");
  837. wrapper.last("limit 1");
  838. MsgHeartbeatAlarmMessage msgHeartbeatAlarmMessage = msgHeartbeatAlarmMessageService.getOne(wrapper);
  839. if (ObjectUtils.isEmpty(msgHeartbeatAlarmMessage)) {
  840. baseTerminal.setStatus(2);
  841. baseTerminalService.updateById(baseTerminal);
  842. } else {
  843. List<SysDictData> heartbeat = dictTypeService.selectDictDataByType("heartbeat");
  844. long timeNow = System.currentTimeMillis();
  845. long createTime = msgHeartbeatAlarmMessage.getCreateTime().getTime();
  846. int times = Integer.parseInt(heartbeat.get(0).getDictValue());
  847. long thereHourMillis = 60 * 1000 * 3 * times;
  848. long timeNew = timeNow - thereHourMillis;
  849. if (timeNew > createTime) {
  850. baseTerminal.setStatus(2);
  851. baseTerminalService.updateById(baseTerminal);
  852. } else {
  853. baseTerminal.setStatus(1);
  854. baseTerminalService.updateById(baseTerminal);
  855. }
  856. }
  857. }
  858. }
  859. /**
  860. * 天网接口
  861. *
  862. * @return
  863. */
  864. public static String getPreviewURLs(String url, String body) {
  865. /**
  866. * STEP1:设置平台参数,根据实际情况,设置host appkey appsecret 三个参数.
  867. */
  868. ArtemisConfig.host = host; // 平台的ip端口
  869. ArtemisConfig.appKey = appKey; // 密钥appkey
  870. ArtemisConfig.appSecret = appSecret;// 密钥appSecret
  871. /**
  872. * STEP2:设置OpenAPI接口的上下文
  873. */
  874. final String ARTEMIS_PATH = "/artemis";
  875. /**
  876. * STEP3:设置接口的URI地址
  877. */
  878. final String previewURLsApi = ARTEMIS_PATH + url;
  879. Map<String, String> path = new HashMap<String, String>(2) {
  880. {
  881. put("https://", previewURLsApi);//根据现场环境部署确认是http还是https
  882. }
  883. };
  884. /**
  885. * STEP4:设置参数提交方式
  886. */
  887. String contentType = "application/json";
  888. /**
  889. * STEP6:调用接口
  890. */
  891. String result = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType, null);// post请求application/json类型参数
  892. log.info("GetCameraPreviewURL----->" + result);
  893. return result;
  894. }
  895. /**
  896. * 车载终端实时流调用的远程天网接口
  897. *
  898. * @param camerasVo
  899. * @param channel
  900. */
  901. public String apiPreviewURLs(CamerasVo camerasVo) {
  902. /**
  903. * jsonBody.put("cameraIndexCode", "01ea43e6676f4e47bd6c5cd9e02aa006");
  904. * jsonBody.put("streamType", 0);
  905. * jsonBody.put("protocol","rtsp");
  906. * jsonBody.put("transmode", 1);
  907. * jsonBody.put("expand","streamform=rtp");
  908. */
  909. camerasVo.setProtocol("rtsp");
  910. camerasVo.setTransmode(1);
  911. camerasVo.setExpand("streamform=rtp");
  912. String body = JSONObject.toJSONString(camerasVo);
  913. String previewURLs = getPreviewURLs("/api/video/v1/cameras/previewURLs", body);
  914. log.info("-------------------------------->>>>>previewURLs" + previewURLs);
  915. JSONObject outJson = JSONObject.parse(previewURLs);
  916. if ("0".equals(outJson.getString("code"))) {
  917. log.info("outJson----->" + outJson);
  918. JSONObject data = outJson.getJSONObject("data");
  919. String urls = data.getString("url");
  920. return urls;
  921. } else {
  922. return "1";
  923. }
  924. }
  925. /**
  926. * web页面实时流调用的远程天网接口
  927. *
  928. * @param camerasVo
  929. * @param channel
  930. */
  931. public static void previewURLs(CamerasVo camerasVo, String channel) {
  932. /**
  933. * jsonBody.put("cameraIndexCode", "01ea43e6676f4e47bd6c5cd9e02aa006");
  934. * jsonBody.put("streamType", 0);
  935. * jsonBody.put("protocol","rtsp");
  936. * jsonBody.put("transmode", 1);
  937. * jsonBody.put("expand","streamform=rtp");
  938. */
  939. camerasVo.setStreamType(0);
  940. camerasVo.setProtocol("rtsp");
  941. camerasVo.setTransmode(1);
  942. camerasVo.setExpand("streamform=rtp");
  943. String body = JSONObject.toJSONString(camerasVo);
  944. String previewURLs = getPreviewURLs("/api/video/v1/cameras/previewURLs", body);
  945. log.info("-------------------------------->>>>>previewURLs" + previewURLs);
  946. JSONObject outJson = JSONObject.parse(previewURLs);
  947. if ("0".equals(outJson.getString("code"))) {
  948. log.info("outJson----->" + outJson);
  949. JSONObject data = outJson.getJSONObject("data");
  950. String urls = data.getString("url");
  951. log.info("urls----->" + urls);
  952. try {
  953. TimeUnit.SECONDS.sleep(3);
  954. String msg = HttpUtils.sendGet(httpUrl + "/rtsp/api/pull?target=" + urls + "&streamPath=" + camerasVo.getCameraIndexCode() + "/" + channel + "&save=0");
  955. log.info("msg---------->" + msg);
  956. } catch (InterruptedException e) {
  957. e.printStackTrace();
  958. }
  959. } else {
  960. log.info("流媒体获取流失败----->");
  961. }
  962. }
  963. /**
  964. * 报警回放本地测试
  965. * 从天网拉回放流,然后根据url把流下载下来变成文件,然后进行视频压缩
  966. *
  967. * @param list
  968. * @param alarmPlayTimeValue
  969. */
  970. public void playbackURLs(List<String> list, String alarmPlayTimeValue) {
  971. log.info("--------------->playbackURLs");
  972. CompletableFuture future = CompletableFuture.supplyAsync(() -> {
  973. log.info("异步任务开始-----》");
  974. for (String code : list) {
  975. PlaybackVo playbackVo = new PlaybackVo();
  976. playbackVo.setCameraIndexCode(code);
  977. // 获取当前时间
  978. OffsetDateTime currentTime = OffsetDateTime.now();
  979. // 获取当前时间的前10分钟时间
  980. OffsetDateTime beforeTenMinutes = currentTime.minusMinutes(Long.parseLong(alarmPlayTimeValue));
  981. // 获取当前时间的后10分钟时间
  982. OffsetDateTime afterTenMinutes = currentTime.plusMinutes(Long.parseLong(alarmPlayTimeValue));
  983. // 格式化时间
  984. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
  985. playbackVo.setBeginTime(beforeTenMinutes.format(formatter));
  986. //现在当前时间:后续需要修改成报警时间的后几分钟
  987. playbackVo.setEndTime(afterTenMinutes.format(formatter));
  988. // jsonBody.put("protocol","rtsp");
  989. // jsonBody.put("expand","streamform=rtp");
  990. playbackVo.setProtocol("rtsp");
  991. playbackVo.setExpand("streamform=rtp");
  992. //对象转换json字符串
  993. String body = JSONObject.toJSONString(playbackVo);
  994. //调用天网接口
  995. log.info("body----->" + body);
  996. String playbackURLs = getPreviewURLs("/api/video/v1/cameras/playbackURLs", body);
  997. log.info("playbackURLs----->" + playbackURLs);
  998. JSONObject outJson = (JSONObject) JSONObject.parse(playbackURLs);
  999. if ("0".equals(outJson.getString("code"))) {
  1000. log.info("outJson----->" + outJson);
  1001. JSONObject data = outJson.getJSONObject("data");
  1002. String urls = data.getString("url");
  1003. log.info("--------------->urls::" + urls);
  1004. String FilePath = "/opt/streams/map/" + code + ".mp4";
  1005. // String FilePath = "/opt/streams/map/01ea43e6676f4e47bd6c5cd9e02aa006.mp4";
  1006. // try {
  1007. // TimeUnit.SECONDS.sleep(62*Integer.parseInt(alarmPlayTimeValue));
  1008. // } catch (InterruptedException e) {
  1009. // e.printStackTrace();
  1010. // }
  1011. Process process = rtspToMP4.StartRecord(ffmpegPath, urls, FilePath);
  1012. log.info("------playbackURLs----->>>>:" + process);
  1013. if (null != process) {
  1014. map.put(code, process);
  1015. }
  1016. try {
  1017. TimeUnit.SECONDS.sleep(70 * Integer.parseInt(alarmPlayTimeValue));
  1018. } catch (InterruptedException e) {
  1019. e.printStackTrace();
  1020. }
  1021. log.info("------videoCompression----->>>>:");
  1022. videoCompression(code);
  1023. }
  1024. }
  1025. return 1;
  1026. });
  1027. future.join();
  1028. }
  1029. public AjaxResult stop(String id) {
  1030. if (map.containsKey(id)) {
  1031. Process process = map.get(id);
  1032. log.info("-----stop------>>>" + process);
  1033. if (null != process) {
  1034. rtspToMP4.stopRecord(process);
  1035. return AjaxResult.success();
  1036. }
  1037. }
  1038. return AjaxResult.error();
  1039. }
  1040. public static void main(String[] args) throws InterruptedException, ParseException, IOException {
  1041. // CameraUtil cameraUtil = new CameraUtil();
  1042. // cameraUtil.closeRecording();
  1043. // String s = "/opt/streams/record/flv/42010001541320001116/20230403_235506_000506-22e1523b-d170-11ed-8a42-fa163e4e1e9f.flv";
  1044. // String fileStr = s.substring(s.lastIndexOf("/") + 1, s.length());
  1045. // String pathStr = s.substring(0, s.lastIndexOf("/"));
  1046. // System.out.println(fileStr);
  1047. // System.out.println(pathStr);
  1048. String s = "20230403235512";
  1049. Date sdate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s);
  1050. sdate = DateUtils.addDays(sdate, -1);
  1051. System.out.println(DateUtils.parseDateToStr(DateUtils.YYYYMMDDHHMMSS, sdate));
  1052. }
  1053. }