CameraUtil.java 62 KB

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