package com.ozs.utils; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.hikvision.artemis.sdk.ArtemisHttpUtil; import com.hikvision.artemis.sdk.config.ArtemisConfig; import com.ozs.common.config.BaseConfig; import com.ozs.common.constant.Constants; import com.ozs.common.core.domain.AjaxResult; import com.ozs.common.core.domain.entity.SysDictData; import com.ozs.common.core.redis.RedisCache; import com.ozs.common.exception.base.BaseException; import com.ozs.common.utils.DateUtils; import com.ozs.common.utils.HttpClientUtil; import com.ozs.common.utils.http.HttpUtils; import com.ozs.entity.BaseCameraManagement; import com.ozs.entity.BaseTerminal; import com.ozs.entity.BaseTerminalLog; import com.ozs.entity.MsgHeartbeatAlarmMessage; import com.ozs.entity.response.BaseCameraManagementResponse; import com.ozs.entity.vo.CamerasVo; import com.ozs.entity.vo.PlaybackVo; import com.ozs.framework.config.ServerConfig; import com.ozs.service.BaseCameraManagementService; import com.ozs.service.BaseTerminalLogService; import com.ozs.service.BaseTerminalService; import com.ozs.service.MsgHeartbeatAlarmMessageService; import com.ozs.system.mapper.SysDictDataMapper; import com.ozs.system.service.ISysDictTypeService; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.util.ObjectUtils; import javax.annotation.PostConstruct; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; /** * 相机工具 */ @Configuration @Slf4j public class CameraUtil { private static final ExecutorService executor = Executors.newFixedThreadPool(20); private static String historyUrl; private static String ffmpegPath; private static String filePath; private static String transcribeFilePath; private static String webUrl; private static String bakUrl; private static String bakUrlRtsp; private static String wsUrl; private static String wsUrls; private static String httpUrl; private static String httpUrls; private static CmdCameraUtil cUtil; private static RedisCache rc; private static ServerConfig sc; private static String recordUrl; private static String hkUrl; private static String host; private static String appKey; private static String appSecret; private static String rtmpUrl; @Autowired private CaneraConfig caneraConfig; @Autowired private CmdCameraUtil cmdCameraUtil; @Autowired private SysDictDataMapper dictDataMapper; @Autowired private RedisCache redisCache; @Autowired private ServerConfig serverConfig; @Autowired private BaseTerminalService baseTerminalService; @Autowired private MsgHeartbeatAlarmMessageService msgHeartbeatAlarmMessageService; @Autowired private ISysDictTypeService dictTypeService; @Autowired private RtspToMP4 rtspToMP4; @Autowired private BaseCameraManagementService baseCameraManagementService; @Autowired private BaseTerminalLogService baseTerminalLogService; private Map map = new HashMap<>(); public final static String tsFilekey = "mergeVideoTsFile"; /** * 历史回放 * * @param fromVideoFileList * @param ph * @return * @throws IOException */ public static String historyPlay(List fromVideoFileList, String ph, boolean flay) { // 视频服务映射路径 String NewfilePath = BaseConfig.getProfile() + "/" + ph; log.info("NewfilePath:{}", NewfilePath); log.info("fromVideoFileList:{}", fromVideoFileList); if (ObjectUtils.isEmpty(fromVideoFileList) || fromVideoFileList.size() <= 0) { throw new BaseException("当前相机无视频录像"); } executor.submit(new Runnable() { @Override public void run() { try { txConvetor(fromVideoFileList, NewfilePath, flay); } catch (IOException e) { log.error(e.getMessage()); e.printStackTrace(); } } }); // executor.shutdown(); return Constants.RESOURCE_PREFIX + "/" + ph; } @SneakyThrows public static void txConvetor(List fromVideoFileList, String newfilePath, boolean fly) throws IOException { /* * ffmpeg -i 20230411_155847_155947-d4c2265d-d83e-11ed-8e7f-fa163e4e1e9f.flv -c:v copy 1.ts ffmpeg -i 20230411_155948_160048-f91fea03-d83e-11ed-8e7f-fa163e4e1e9f.flv -c:v copy 2.ts ffmpeg -i "concat:1.ts|2.ts" -c copy output.mp4 * */ File file = new File(newfilePath); boolean flay = false; if (!file.getParentFile().exists()) { boolean mkdirs = file.getParentFile().mkdirs(); log.info("创建文件夹:{}", file.getParentFile().getPath()); log.info("创建文件夹结果:{}", mkdirs); flay = true; } cUtil.cmd("chomd -R 777 " + file.getParentFile().getPath()); log.info("newfilePath:{}", newfilePath); StringBuffer sm = new StringBuffer(ffmpegPath + " -i \"concat:"); List fileTs = new ArrayList<>(); for (int t = 0; t < fromVideoFileList.size(); t++) { File ft = new File(fromVideoFileList.get(t)); if (ft.exists()) { log.info("file:{}", fromVideoFileList.get(t)); String substring = fromVideoFileList.get(t).substring(0, fromVideoFileList.get(t).lastIndexOf(".")); int x;//定义两变量 Random ne = new Random();//实例化一个random的对象ne x = ne.nextInt(9999 - 1000 + 1) + 1000;//为变量赋随机值1000-9999 substring = substring + x;//定义两变量 String cmdstr = ffmpegPath + " -i " + fromVideoFileList.get(t) + " -c:v copy " + substring + ".ts"; log.info("转换命令:{}", cmdstr); cUtil.cmd(cmdstr); fileTs.add(substring + ".ts"); if (t != fromVideoFileList.size() - 1) { sm.append(substring + ".ts|"); } else { sm.append(substring + ".ts\" "); } } } if (fileTs.size() > 0) { Map mergeVideoTsFile = rc.getCacheMap(tsFilekey); if (ObjectUtils.isEmpty(mergeVideoTsFile)) { mergeVideoTsFile = new HashMap<>(); } if (!flay) { // 如果没有解除,把生成的文件放入要删除的定时任务 redis key 中 fileTs.add(newfilePath); } mergeVideoTsFile.put(System.currentTimeMillis() + "", fileTs); rc.deleteObject(tsFilekey); if (mergeVideoTsFile.size() > 0) { rc.setCacheMap(tsFilekey, mergeVideoTsFile); } sm.append("-c copy " + newfilePath); log.info("合并命令:{}", sm.toString()); cUtil.cmd(sm.toString()); } } /** * 实时播放的拼接流 * * @param cameraCode 相机编码 * @param channel 相机通道 * @return */ public static String getPlayFlv(String cameraCode, String channel, boolean flay, String state) { log.info("getPlayFlv----master---------" + wsUrl); return wsUrl + "/ws/" + cameraCode + "/" + channel + ".flv"; // if (!flay) { // return bakUrl + "/ws/" + channel + "/" + cameraCode + ".flv"; // } // return webUrl + "/ws/" + channel + "/" + cameraCode + ".flv"; } public static String getPlayFlv(String cameraCode, String channel, boolean flay) { if (!flay) { return bakUrl + "/hdl/" + cameraCode + "/" + channel + ".flv"; } return wsUrl + "/ws/" + cameraCode + "/" + channel + ".flv"; // if (!flay) { // return bakUrl + "/ws/" + channel + "/" + cameraCode + ".flv"; // } // return webUrl + "/ws/" + channel + "/" + cameraCode + ".flv"; } /** * Rtsp实时播放的拼接流 心跳接口使用 * * @param cameraCode 相机编码 * @param channel 相机通道 * @return */ public static String getPlayFlvRtsp(String cameraCode, String channel, boolean flay, String url) { log.info("---------getPlayFlvRtsp----url--" + url); if (url.contains("10.48.31.84")) { log.info("-----getPlayFlvRtsp------11------>" + bakUrlRtsp + "/master/hdl/" + cameraCode + "/" + channel + ".flv"); return bakUrlRtsp + "/master/hdl/" + cameraCode + "/" + channel + "/h264_720.flv"; } else { log.info("-------getPlayFlvRtsp----22------>" + bakUrlRtsp + "/slave/hdl/" + cameraCode + "/" + channel + ".flv"); return bakUrlRtsp + "/slave/hdl/" + cameraCode + "/" + channel + "/h264_720.flv"; } // if (!flay) { // return bakUrl + "/ws/" + channel + "/" + cameraCode + ".flv"; // } // return webUrl + "/ws/" + channel + "/" + cameraCode + ".flv"; } /** * 点播的时候使用 * * @param cameraCode * @param channel * @param flay * @return */ public static String getPlayFlvRtsps(String cameraCode, String channel, boolean flay) { if (!flay) { log.info("-----getPlayFlvRtsps------11------>" + bakUrlRtsp + "/hdl/" + cameraCode + "/" + channel + ".flv"); return bakUrlRtsp + "/hdl/" + cameraCode + "/" + channel + ".flv"; } log.info("-------getPlayFlvRtsps----22------>" + bakUrlRtsp + "/hdl/" + cameraCode + "/" + channel + ".flv"); return bakUrlRtsp + "/hdl/" + cameraCode + "/" + channel + ".flv"; // if (!flay) { // return bakUrl + "/ws/" + channel + "/" + cameraCode + ".flv"; // } // return webUrl + "/ws/" + channel + "/" + cameraCode + ".flv"; } /** * web页面实时流接口 * * @param cameraCode * @param channel * @return */ public String getPlayFlv(String cameraCode, String channel) { int maxRetries = 3; int retryCount = 0; boolean success = false; JSONArray jsonArray = null; List pathList = new ArrayList<>(); String data = HttpUtils.sendGet(webUrl + "/rtsp/api/list"); if (StringUtils.isNotEmpty(data)) { log.info("---------------data---" + data); while (!success && retryCount < maxRetries) { try { jsonArray = JSONArray.parseArray(data); success = true; } catch (Exception e) { e.printStackTrace(); log.info("Exception caught: " + e.getMessage()); // 增加重试计数 retryCount++; } } log.info("---------------jsonArray---" + jsonArray); if (!ObjectUtils.isEmpty(jsonArray)) { for (int i = 0; i < jsonArray.size(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); String name = jsonObject.getString("Path"); pathList.add(name); } boolean contains = pathList.contains(cameraCode + "/" + channel); if (contains) { String cacheObject = redisCache.getCacheObject(cameraCode); return getPlayFlv(cameraCode, channel, true, cacheObject); } else { /** * jsonBody.put("cameraIndexCode", "01ea43e6676f4e47bd6c5cd9e02aa006"); * jsonBody.put("streamType", 0); * jsonBody.put("protocol","rtsp"); * jsonBody.put("transmode", 1); * jsonBody.put("expand","streamform=rtp"); */ CamerasVo camerasVo = new CamerasVo(); camerasVo.setCameraIndexCode(cameraCode); String urLs = previewURLs(camerasVo, channel, httpUrl); log.info("web实时流---" + urLs); if (!urLs.contains("无视频")) { return getPlayFlv(cameraCode, channel, true, urLs); } else { return urLs; } } } else { CamerasVo camerasVo = new CamerasVo(); camerasVo.setCameraIndexCode(cameraCode); String urLs = previewURLs(camerasVo, channel, httpUrl); log.info("web实时流---" + urLs); if (!urLs.contains("无视频")) { return getPlayFlv(cameraCode, channel, true, urLs); } else { return urLs; } } } else { CamerasVo camerasVo = new CamerasVo(); camerasVo.setCameraIndexCode(cameraCode); String urLs = previewURLs(camerasVo, channel, httpUrl); if (!urLs.contains("无视频")) { return getPlayFlv(cameraCode, channel, true, urLs); } else { return urLs; } } } public String heartbeatgetPlayFlv(String cameraCode, String channel, boolean type) { int maxRetries = 3; int retryCount = 0; boolean success = false; JSONArray jsonArray = null; List pathList = new ArrayList<>(); //从redis中获取该相机的IP地址 String cacheObject = redisCache.getCacheObject(cameraCode); if (StringUtils.isEmpty(cacheObject)) { cacheObject = httpUrl; } while (!success && retryCount < maxRetries) { try { String data = HttpUtils.sendGet(cacheObject + "/rtsp/api/list"); log.info("data------------------>" + data); if (StringUtils.isNotEmpty(data)) { jsonArray = JSONArray.parseArray(data); success = true; } } catch (Exception e) { log.info("Exception caught: " + e.getMessage()); // 增加重试计数 retryCount++; } } log.info("jsonArray------------------>" + jsonArray); if (!ObjectUtils.isEmpty(jsonArray)) { for (int i = 0; i < jsonArray.size(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); String name = jsonObject.getString("Path"); pathList.add(name); } boolean contains = pathList.contains(cameraCode + "/" + channel); if (!contains) { return null; } else { return getPlayFlvRtsp(cameraCode, channel, type, cacheObject); } } return null; } public List rtspApiList() { List pathList = new ArrayList<>(); String data = HttpUtils.sendGet(webUrl + "/rtsp/api/list"); log.info("data------------------>" + data); if (StringUtils.isNotEmpty(data)) { JSONArray jsonArray = JSONArray.parseArray(data); log.info("jsonArray------------------>" + jsonArray); if (!ObjectUtils.isEmpty(jsonArray)) { for (int i = 0; i < jsonArray.size(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); String name = jsonObject.getString("Path"); pathList.add(name); } return pathList; } return null; } return null; } public String heartbeatgetUrl(String cameraCode, String channel, boolean type, String url) throws Exception { CamerasVo camerasVo = new CamerasVo(); camerasVo.setCameraIndexCode(cameraCode); String s = previewURLs(camerasVo, channel, url); log.info("-------heartbeatgetUrl---------" + s); if (s.contains("无视频")) { log.info("-------无视频---------"); return s; } else { log.info("-------getPlayFlvRtsp---------" + getPlayFlvRtsp(cameraCode, channel, type, url)); return getPlayFlvRtsp(cameraCode, channel, type, url); } } public String heartbeatgetUrls(String cameraCode, String channel, boolean type) throws Exception { CompletableFuture future = CompletableFuture.supplyAsync(() -> { CamerasVo camerasVo = new CamerasVo(); camerasVo.setCameraIndexCode(cameraCode); String s = previewURLs(camerasVo, channel, httpUrl); if (s.contains("无视频")) { return s; } else { return getPlayFlvRtsps(cameraCode, channel, type); } }); return future.get(); } public static String invite(String cameraCode, String channel) { String result = null; String url = bakUrl + "/api/gb28181/invite?id=" + cameraCode + "&channel=" + channel; try { result = HttpClientUtil.get(url); log.info("result:{}", result); } catch (Exception e) { log.info(e.getMessage()); e.printStackTrace(); } return result; } /** * 开启录制功能 * * @param cameraCode 相机编码 * @param channel 相机通道 * @return */ public static String startRecording(String cameraCode, String channel) { log.info("-----startRecording------" + historyUrl + "/recordpro/api/start?streamPath=" + cameraCode + "/" + channel + "&type=mp4"); return historyUrl + "/recordpro/api/start?streamPath=" + cameraCode + "/" + channel + "&type=mp4"; } /** * 关闭录制功能 * * @param taskId 录像接口返回的任务ID * @return */ public static String endRecording(String taskId) { return historyUrl + "/recordpro/api/stop?id=" + taskId; } /** * 历史回放流(获取) * * @param channel 相机通道 * @param startTm 开始时间 * @param endTm 结束时间 * @return */ public static String historyPlayListStr(String channel, Date startTm, Date endTm, boolean flay) { List list = filterPlayList(channel, startTm, endTm, filePath); String uuid = UUID.randomUUID().toString(); String ph = "record/flv/" + DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, new Date()) + "/" + channel + "/" + uuid + ".mp4"; if (!ObjectUtils.isEmpty(list)) { try { return historyPlay(list, ph, flay); } catch (Exception e) { log.error(e.getMessage()); e.printStackTrace(); } } else { throw new BaseException("当前相机无视频录像"); } return null; } /** * 过滤符合条件的视频 * * @param channel * @param startTm * @param endTm * @param mappingUrl * @return */ public static List filterPlayList(String channel, Date startTm, Date endTm, String mappingUrl) { if (StringUtils.isBlank(channel) || ObjectUtils.isEmpty(startTm) || ObjectUtils.isEmpty(endTm)) { return null; } List ls = new ArrayList<>(); Map m = new HashMap<>(); // 调用视频服务返回参数 String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, startTm); String endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, endTm); String param = "channel=" + channel + "&startTime=" + startTime + "&endTime=" + endTime; String s = HttpUtils.sendGet(historyUrl + "/api/record/flv/list", param); // 视频拼接 if (!StringUtils.isBlank(s) && !"null".equals(s) && !s.startsWith("")) { List> maps = JSON.parseArray(s, Map.class); if (ObjectUtils.isEmpty(maps)) { return null; } for (Map map : maps) { Object path = map.get("Path"); if (!ObjectUtils.isEmpty(path)) { String s1 = path.toString(); String substring = s1.substring(s1.lastIndexOf("/") + 1, s1.length()); String substring1 = substring.substring(0, substring.indexOf("-")); String[] s2 = substring1.split("_"); if (!ObjectUtils.isEmpty(s2)) { String s3 = s2[0] + s2[1]; String s4 = s2[0] + s2[2]; Date sdate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s3); if (s2[1].startsWith("23") && s2[2].startsWith("00")) { sdate = DateUtils.addDays(sdate, -1); } Date edate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s4); /* sdate |startTm| edate |endTm| */ if (startTm.compareTo(sdate) >= 0 && startTm.compareTo(edate) <= 0 && endTm.compareTo(edate) >= 0) { m.put(sdate, mappingUrl + path.toString()); /* |startTm| sdate edate |endTm| */ } else if (startTm.compareTo(sdate) <= 0 && endTm.compareTo(edate) >= 0) { m.put(sdate, mappingUrl + path.toString()); /* |startTm| sdate |endTm| edate */ } else if (startTm.compareTo(sdate) <= 0 && endTm.compareTo(sdate) >= 0 && endTm.compareTo(edate) <= 0) { m.put(sdate, mappingUrl + path.toString()); /* sdate |startTm| |endTm| edate */ } else if (startTm.compareTo(sdate) >= 0 && endTm.compareTo(edate) <= 0) { m.put(sdate, mappingUrl + path.toString()); } } } } } if (!ObjectUtils.isEmpty(m) && m.size() > 0) { Set dates = m.keySet(); // 排序 dates.stream().parallel().collect(Collectors.toList()).stream().sorted().forEach(d -> { ls.add(m.get(d)); }); return ls; } return null; } /** * 合并视频(转化文件) * * @param fromVideoFileList 视频路径 * @param newfilePath 生产新的视频文件路径 * @throws IOException */ public static Map myConvetor(List fromVideoFileList, String newfilePath, String uuid) throws IOException { /* * for f in *.flv; do echo "file '$f'" >> mylist.txt; done ffmpeg -f concat -i mylist.txt -c copy output.flv * */ File file = new File(newfilePath); boolean flay = false; if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); log.info("创建文件夹:{}", file.getParentFile().getPath()); flay = true; } log.info("newfilePath:{}", newfilePath); StringBuffer sm = new StringBuffer("for f in "); String pathStr = null; for (int t = 0; t < fromVideoFileList.size(); t++) { File ft = new File(fromVideoFileList.get(t)); if (ft.exists()) { if (t != fromVideoFileList.size() - 1) { // sm.append(fromVideoFileList.get(t) + " "); sm.append(fromVideoFileList.get(t).substring(fromVideoFileList.get(t).lastIndexOf("/") + 1, fromVideoFileList.get(t).length()) + " "); } else { // sm.append(fromVideoFileList.get(t)); sm.append(fromVideoFileList.get(t).substring(fromVideoFileList.get(t).lastIndexOf("/") + 1, fromVideoFileList.get(t).length())); pathStr = fromVideoFileList.get(t).substring(0, fromVideoFileList.get(t).lastIndexOf("/")); } } } // String substring = newfilePath.substring(0, newfilePath.lastIndexOf(".")); // substring = substring + ".txt"; String substring = uuid + ".txt"; log.info("临时转化的文件:{}", substring); sm.append("; do echo \"file '$f'\" >> " + substring + "; done"); String commit = sm.toString(); log.info("合并转化文件的命令:{}", commit); Process proc = Runtime.getRuntime().exec("/bin/bash", null, null); BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream())); PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true); try { String commit1 = ffmpegPath + " -f concat -safe 0 -i " + pathStr + "/" + substring + " -c copy " + newfilePath; log.info("合并视频命令:{}", commit1); List commands = new ArrayList<>(); if (flay) { commands.add("chomd -R 777 " + file.getParentFile().getPath()); } // commands.add("cd " + pathStr); // 合并成一个临时文件 commands.add(commit); // 临时文件转化为 flv // commands.add(commit1); log.info("录像视频命令:{}", commands); for (String line : commands) { log.info("命令:{}", line); out.println(line); } out.println("exit");// 这个命令必须执行,否则in流不结束。 log.info("命令:{}", "exit"); String rspLine = ""; while ((rspLine = in.readLine()) != null) { log.info("*****:{}", rspLine); } proc.waitFor(); Map map = new HashMap<>(); map.put("cmd", commit1); map.put("path", pathStr + "/" + substring); return map; } catch (InterruptedException e) { log.error(e.getMessage()); e.printStackTrace(); } finally { in.close(); out.close(); proc.destroy(); } return null; } @PostConstruct public void init() { historyUrl = caneraConfig.getHistoryUrl(); ffmpegPath = caneraConfig.getFfmpegPath(); filePath = caneraConfig.getFilePath(); transcribeFilePath = caneraConfig.getTranscribeFilePath(); webUrl = caneraConfig.getWebUrl(); bakUrl = caneraConfig.getBakUrl(); bakUrlRtsp = caneraConfig.getBakUrlRtsp(); rc = redisCache; cUtil = cmdCameraUtil; sc = serverConfig; wsUrl = caneraConfig.getWsUrl(); wsUrls = caneraConfig.getWsUrls(); httpUrl = caneraConfig.getHttpUrl(); httpUrls = caneraConfig.getHttpUrls(); recordUrl = caneraConfig.getRecordUrl(); hkUrl = caneraConfig.getHkUrl(); host = caneraConfig.getHost(); appKey = caneraConfig.getAppKey(); appSecret = caneraConfig.getAppSecret(); rtmpUrl = caneraConfig.getRtmpUrl(); } /** * 定时任务参数flv文件 * * @throws IOException * @throws InterruptedException */ public void deleteFlv() throws IOException, InterruptedException { SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd"); Date date = new Date(); Calendar calendar = new GregorianCalendar(); calendar.setTime(date); calendar.add(Calendar.DATE, -1); //把日期往后增加一天,整数 往后推,负数往前移动 date = calendar.getTime(); //这个时间就是日期往后推一天的结果 String path = BaseConfig.getProfile() + "/flv/" + DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, date); File file = new File(path); if (file.exists()) { List rspList = new ArrayList(); Process proc = Runtime.getRuntime().exec("/bin/bash", null, null); BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream())); PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true); String commit = " rm -rf " + path; List commands = new ArrayList<>(); // 删除 commands.add(commit); log.info("删除昨天的录像视频命令:{}", commands); for (String line : commands) { out.println(line); } out.println("exit");// 这个命令必须执行,否则in流不结束。 String rspLine = ""; while ((rspLine = in.readLine()) != null) { System.out.println(rspLine); rspList.add(rspLine); } int i = proc.waitFor(); log.info("执行结果:{}", i); in.close(); out.close(); proc.destroy(); } } /** * 定时任务:删除超过配置时长的录制视频 * * @throws IOException * @throws InterruptedException */ public void deleteFlvExceed() throws IOException, InterruptedException, ParseException { //字典中设置的值 List sysCameraRecordTime = dictDataMapper.selectDictDataByType("sys_camera_record_time"); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); Date date = new Date(); Calendar calendar = new GregorianCalendar(); calendar.setTime(date); //正数,日期天数加 //负数,日期天数减 提前45天 if (!ObjectUtils.isEmpty(sysCameraRecordTime)) { String dictValue = sysCameraRecordTime.get(0).getDictValue(); calendar.add(Calendar.DAY_OF_YEAR, Integer.parseInt("-" + dictValue)); } else { calendar.add(Calendar.DAY_OF_YEAR, -45); } date = calendar.getTime(); //遍历每个进行视频录制的摄像头 File file = new File(transcribeFilePath); log.info("file.Name()======================================" + file.getName()); log.info("file.exists()======================================" + file.exists()); if (file.exists() && file.isDirectory()) { //获取文件夹中所有的子文件夹和文件 File[] files = file.listFiles(); if (!ObjectUtils.isEmpty(files) && files.length > 0) { for (File file1 : files) { // file1=/opt/streams/record/flv/34020000001320000167 log.info("file1.Name()======================================" + file1.getName()); if (file1.exists() && file1.isDirectory()) { //相机文件 File[] fs = file1.listFiles(); if (!ObjectUtils.isEmpty(fs) && fs.length > 0) { for (File f : fs) { // f=/opt/streams/record/flv/34020000001320000167/20230328_192033_192037-91509173-cd5a-11ed-8a42-fa163e4e1e9f.flv //fName=20230328_192033_192037-91509173-cd5a-11ed-8a42-fa163e4e1e9f.flv String fName = f.getName(); log.info("fName======================================" + fName); String[] split = fName.split("_"); if (split.length > 0) { //20230328 String s = split[0]; Date parse = sdf.parse(s); long fTime = parse.getTime(); long dateTime = date.getTime(); //删除过期文件 if (fTime < dateTime) { f.delete(); } } } } } } } } } public static File[] getCurFilesList(String filePath) { File path = new File(filePath); File[] listFiles = path.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { if (pathname.isFile()) { return true; } else { return false; } } }); return listFiles; } public static void execute(String command) { try { ProcessBuilder process = new ProcessBuilder(command); process.inheritIO().start().waitFor(); } catch (Exception e) { e.printStackTrace(); } } /** * web页面视频回放接口 * * @param code * @param startTm * @param endTm * @return */ public static String getRecordList(String code, Date startTm, Date endTm, String channel) { PlaybackVo playbackVo = new PlaybackVo(); playbackVo.setCameraIndexCode(code); // 将 Date 转换为 Instant Instant startInstant = startTm.toInstant(); Instant endInstant = endTm.toInstant(); // 将 Instant 转换为 OffsetDateTime OffsetDateTime startOffsetDateTime = startInstant.atOffset(ZoneOffset.UTC); OffsetDateTime endOffsetDateTime = endInstant.atOffset(ZoneOffset.UTC); // 格式化为字符串 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); String formattedStartTime = startOffsetDateTime.format(formatter); String formattedEndTime = endOffsetDateTime.format(formatter); // 将格式化后的时间设置到 playbackVo 中 playbackVo.setBeginTime(formattedStartTime); playbackVo.setEndTime(formattedEndTime); playbackVo.setProtocol("rtsp"); playbackVo.setExpand("streamform=rtp"); //对象转换json字符串 String body = JSONObject.toJSONString(playbackVo); //调用天网接口 String playbackURLs = getPreviewURLs("/api/video/v1/cameras/playbackURLs", body); if (StringUtils.isEmpty(playbackURLs)) { return "调用天网接口失败"; } JSONObject outJson = (JSONObject) JSONObject.parse(playbackURLs); log.info("outJson-------->" + outJson); if ("0".equals(outJson.getString("code"))) { JSONObject data = outJson.getJSONObject("data"); String urls = data.getString("url"); log.info("urls----------->" + urls); try { TimeUnit.SECONDS.sleep(3); String msg = HttpUtils.sendGet(httpUrl + "/rtsp/api/pull?target=" + urls + "&streamPath=" + code + "/" + channel + "&save=0"); log.info("msg---------->" + msg); } catch (InterruptedException e) { e.printStackTrace(); } return getPlayFlv(code, channel, true, "master"); } else { return "调用天网接口失败"; } // return filterRecordList(channel, startTm, endTm, filePath, recordUrl + "profile/"); } /** * HTTP流转RTSP流 */ public String streamConversion(String code) { ExecutorService executor = Executors.newSingleThreadExecutor(); Callable task = new Callable() { @Override public String call() throws Exception { // 执行网络请求... 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"); cmdCameraUtil.cmd(ffmpegPath + " -re -i /opt/streams/map/" + code + ".mp4 -c:v copy -c:a copy -f flv " + rtmpUrl + "/live/" + code); return "Response"; } }; try { String result = executor.submit(task).get(5, TimeUnit.SECONDS); // 设置5秒超时时间 System.out.println("Response: " + result); } catch (InterruptedException | ExecutionException | TimeoutException e) { // 请求超时处理逻辑 System.out.println("Request timeout"); } executor.shutdown(); return bakUrlRtsp + "/live/" + code + ".flv"; } /** * RTSP流视频压缩 */ public void videoCompression(String code) { // 执行网络请求... /** * /usr/bin/ffmpeg -i /opt/streams/map/70b0bd685b0d4df1b4faf74ff5c1e7fd.mp4 -c:v libx264 -s 640x480 -c:a aac -ar 44100 /opt/streams/compress/70b0bd685b0d4df1b4faf74ff5c1e7fd.mp4 */ log.info(ffmpegPath + " -i /opt/streams/map/" + code + ".mp4 -c:v libx264 -s 640x480 -c:a aac -ar 44100 /opt/streams/compress/" + code + ".mp4"); cmdCameraUtil.cmd(ffmpegPath + " -i /opt/streams/map/" + code + ".mp4 -c:v libx264 -s 640x480 -c:a aac -ar 44100 /opt/streams/compress/" + code + ".mp4"); } public static List> filterRecordList(String channel, Date startTm, Date endTm, String mappingUrl, String wUrl) { List> rmaps = new ArrayList<>(); if (StringUtils.isBlank(channel) || ObjectUtils.isEmpty(startTm) || ObjectUtils.isEmpty(endTm)) { return null; } Map> m = new HashMap<>(); // 调用视频服务返回参数 String startTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, startTm); String endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, endTm); String param = "channel=" + channel + "&startTime=" + startTime + "&endTime=" + endTime; // /api/record/flv/list String s = HttpUtils.sendGet(webUrl + "/recordpro/api/list", param); // 视频拼接 if (!StringUtils.isBlank(s) || "null".equals(s)) { List> maps = JSON.parseArray(s, Map.class); if (ObjectUtils.isEmpty(maps)) { return null; } for (Map map : maps) { Object path = map.get("Path"); Object size = map.get("Size"); Object duration = map.get("Duration"); if (!ObjectUtils.isEmpty(path)) { String s1 = path.toString(); String substring = s1.substring(s1.lastIndexOf("/") + 1, s1.length()); String substring1 = substring.substring(0, substring.indexOf("-")); String[] s2 = substring1.split("_"); if (!ObjectUtils.isEmpty(s2)) { Map mo = new HashMap<>(); String s3 = s2[0] + s2[1]; String s4 = s2[0] + s2[2]; Date sdate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s3); if (s2[1].startsWith("23") && s2[2].startsWith("00")) { sdate = DateUtils.addDays(sdate, -1); } Date edate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s4); mo.put("startTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, sdate)); mo.put("entTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, edate)); mo.put("url", wUrl + path.toString()); mo.put("path", mappingUrl + path.toString()); mo.put("fileName", substring); mo.put("size", size); mo.put("duration", duration); /* sdate |startTm| edate |endTm| */ if (startTm.compareTo(sdate) >= 0 && startTm.compareTo(edate) <= 0 && endTm.compareTo(edate) >= 0) { m.put(sdate, mo); /* |startTm| sdate edate |endTm| */ } else if (startTm.compareTo(sdate) <= 0 && endTm.compareTo(edate) >= 0) { m.put(sdate, mo); /* |startTm| sdate |endTm| edate */ } else if (startTm.compareTo(sdate) <= 0 && endTm.compareTo(sdate) >= 0 && endTm.compareTo(edate) <= 0) { m.put(sdate, mo); /* sdate |startTm| |endTm| edate */ } else if (startTm.compareTo(sdate) >= 0 && endTm.compareTo(edate) <= 0) { m.put(sdate, mo); } } } } } if (!ObjectUtils.isEmpty(m) && m.size() > 0) { Set dates = m.keySet(); // 排序 dates.stream().parallel().collect(Collectors.toList()).stream().sorted().forEach(d -> { rmaps.add(m.get(d)); }); log.info("rmaps:{}", rmaps); return rmaps; } return null; } /** * 机车状态修改 */ public void heartbeat() { log.info("机车状态修改---------------执行了"); List list = baseTerminalService.list(); for (BaseTerminal baseTerminal : list) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("terminal_code", baseTerminal.getTerminalCode()); wrapper.orderByDesc("create_time"); wrapper.last("limit 1"); BaseTerminalLog baseTerminalLog = baseTerminalLogService.getOne(wrapper); if (ObjectUtils.isEmpty(baseTerminalLog)) { baseTerminal.setStatus(2); baseTerminalService.updateById(baseTerminal); } else { List heartbeat = dictTypeService.selectDictDataByType("heartbeat"); long timeNow = System.currentTimeMillis(); long createTime = baseTerminalLog.getCreateTime().getTime(); int times = Integer.parseInt(heartbeat.get(0).getDictValue()); long thereHourMillis = 60 * 1000 * 3 * times; long timeNew = timeNow - thereHourMillis; if (timeNew > createTime) { baseTerminal.setStatus(2); baseTerminalService.updateById(baseTerminal); } else { baseTerminal.setStatus(1); baseTerminalService.updateById(baseTerminal); } } } } public static String getCameraPreviewURL() { /** * STEP1:设置平台参数,根据实际情况,设置host appkey appsecret 三个参数. */ ArtemisConfig.host = host; // 平台的ip端口 ArtemisConfig.appKey = appKey; // 密钥appkey ArtemisConfig.appSecret = appSecret;// 密钥appSecret /** * STEP2:设置OpenAPI接口的上下文 */ final String ARTEMIS_PATH = "/artemis"; /** * STEP3:设置接口的URI地址 */ final String previewURLsApi = ARTEMIS_PATH + "/api/resource/v1/camera/advance/cameraList"; Map path = new HashMap(2) { { put("https://", previewURLsApi);//根据现场环境部署确认是http还是https } }; /** * STEP4:设置参数提交方式 */ String contentType = "application/json"; /** * STEP5:组装请求参数 */ JSONObject jsonBody = new JSONObject(); jsonBody.put("pageNo", 1); jsonBody.put("pageSize", 999); String body = jsonBody.toJSONString(); /** * STEP6:调用接口 */ String result = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType, null);// post请求application/json类型参数 log.info("GetCameraPreviewURL----->" + result); return result; } /** * 天网接口 * * @return */ public static String getPreviewURLs(String url, String body) { long begin = System.currentTimeMillis(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); log.info("天网接口请求时间: " + sdf.format(new Date(begin))); /** * STEP1:设置平台参数,根据实际情况,设置host appkey appsecret 三个参数. */ ArtemisConfig.host = host; // 平台的ip端口 ArtemisConfig.appKey = appKey; // 密钥appkey ArtemisConfig.appSecret = appSecret;// 密钥appSecret /** * STEP2:设置OpenAPI接口的上下文 */ final String ARTEMIS_PATH = "/artemis"; /** * STEP3:设置接口的URI地址 */ final String previewURLsApi = ARTEMIS_PATH + url; log.info("天网url:{}" + previewURLsApi); Map path = new HashMap(2) { { put("https://", previewURLsApi);//根据现场环境部署确认是http还是https } }; /** * STEP4:设置参数提交方式 */ String contentType = "application/json"; /** * STEP6:调用接口 */ String result = null;// post请求application/json类型参数 try { result = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, contentType, null); } catch (Exception e) { log.info("天网异常信息----->" + e.getMessage()); } log.info("GetCameraPreviewURL----->" + result); long end = System.currentTimeMillis(); log.info("接受天网接口相应时间: " + sdf.format(new Date(end))); log.info("天网接口请求用时时间:" + (end - begin) + "毫秒"); return result; } /** * 车载终端实时流调用的远程天网接口 * * @param camerasVo */ public String apiPreviewURLs(CamerasVo camerasVo) { long begin = System.currentTimeMillis(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); StringBuilder stringBuilder = new StringBuilder(); /** * jsonBody.put("cameraIndexCode", "01ea43e6676f4e47bd6c5cd9e02aa006"); * jsonBody.put("streamType", 0); * jsonBody.put("protocol","rtsp"); * jsonBody.put("transmode", 1); * jsonBody.put("expand","streamform=rtp"); */ camerasVo.setStreamType(0); camerasVo.setProtocol("rtsp"); camerasVo.setTransmode(0); camerasVo.setExpand("streamform=rtp"); String body = JSONObject.toJSONString(camerasVo); String previewURLs = getPreviewURLs("/api/video/v1/cameras/previewURLs", body); log.info("-------------------------------->>>>>previewURLs" + previewURLs); log.info("天网接口请求参数:{}" + camerasVo); if (StringUtils.isEmpty(previewURLs)) { log.info("天网接口异常"); return "天网接口异常"; } else { long end = System.currentTimeMillis(); JSONObject outJson = JSONObject.parse(previewURLs); // stringBuilder.append("测试结果:" + ("0".equals(outJson.getString("code")) ? "成功" : "失败") + "\t"); // stringBuilder.append("调用时间:" + sdf.format(new Date(begin)) + "\t"); // stringBuilder.append("数据返回时间:" + sdf.format(new Date(end)) + "\t"); // stringBuilder.append("延迟:" + (end - begin) + "毫秒"); stringBuilder.append("结果:" + previewURLs); return stringBuilder.toString(); } } public String stopStream(String cameraIndexCode, String channel) { try { //http://10.48.36.47:9080/api/gateway/stop?stream=0235538f5ec241abad7c29cb423f16bb/1 log.info("code-----1111----->" + httpUrl + "/api/gateway/stop?stream=" + cameraIndexCode + "/" + channel + "/h264_720"); String code = HttpClientUtil.getURL(httpUrl + "/api/gateway/stop?stream=" + cameraIndexCode + "/" + channel + "/h264_720"); log.info("code---111111------->" + code); return code; } catch (Exception e) { e.printStackTrace(); } return null; } public String hostStopStream(String straem) { try { //http://10.48.36.47:9080/api/gateway/stop?stream=0235538f5ec241abad7c29cb423f16bb/1 log.info("code-----1111----->" + httpUrl + "/api/gateway/stop?stream=" + straem); String code = HttpClientUtil.getURL(httpUrl + "/api/gateway/stop?stream=" + straem); log.info("code---111111------->" + code); return code; } catch (Exception e) { e.printStackTrace(); } return null; } /** * web页面实时流调用的远程天网接口 * * @param camerasVo * @param channel */ public static String previewURLs(CamerasVo camerasVo, String channel, String url) { /** * jsonBody.put("cameraIndexCode", "01ea43e6676f4e47bd6c5cd9e02aa006"); * jsonBody.put("streamType", 0); * jsonBody.put("protocol","rtsp"); * jsonBody.put("transmode", 1); * jsonBody.put("expand","streamform=rtp"); */ camerasVo.setStreamType(0); camerasVo.setProtocol("rtsp"); camerasVo.setTransmode(0); camerasVo.setExpand("streamform=rtp"); String body = JSONObject.toJSONString(camerasVo); String previewURLs = getPreviewURLs("/api/video/v1/cameras/previewURLs", body); if (StringUtils.isEmpty(previewURLs)) { return "天网无视频-" + camerasVo.getCameraIndexCode(); } log.info("-------------------------------->>>>>previewURLs" + previewURLs); log.info("-------------------------------->>>>>天网接口参数:{}" + camerasVo); JSONObject outJson = JSONObject.parse(previewURLs); if ("0".equals(outJson.getString("code"))) { log.info("outJson----->" + outJson); JSONObject data = outJson.getJSONObject("data"); String urls = data.getString("url"); log.info("urls----->" + urls); try { log.info("httpUrl---------->" + url + "/rtsp/api/pull?target=" + urls + "&streamPath=" + camerasVo.getCameraIndexCode() + "/" + channel + "&save=0"); long begin = System.currentTimeMillis(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); log.info("流媒体开始调用: " + sdf.format(new Date(begin))); String msg = HttpUtils.sendGet(url + "/rtsp/api/pull?target=" + urls + "&streamPath=" + camerasVo.getCameraIndexCode() + "/" + channel + "&save=0"); long end = System.currentTimeMillis(); log.info("流媒体结束调用: " + sdf.format(new Date(end))); log.info("流媒体请求用时时间:" + (end - begin) + "毫秒"); log.info("msg---------->" + msg); if (!msg.contains("ok")) { return "暂无视频-" + camerasVo.getCameraIndexCode(); } rc.setCacheObject(camerasVo.getCameraIndexCode(), url); return "ok"; } catch (Exception e) { return "暂无视频-" + camerasVo.getCameraIndexCode(); } } else { return "天网无视频-" + camerasVo.getCameraIndexCode(); } } /** * 报警回放本地测试 * 从天网拉回放流,然后根据url把流下载下来变成文件,然后进行视频压缩 * * @param list * @param alarmPlayTimeValue */ public String playbackURLs(String code, String frontValue, String laterValue) { try { log.info("--------------->playbackURLs-----异步开始-"); log.info("frontValue------------->" + frontValue); log.info("laterValue------------->" + laterValue); TimeUnit.SECONDS.sleep(65 * Integer.parseInt(laterValue)); log.info("--------------->playbackURLs"); PlaybackVo playbackVo = new PlaybackVo(); playbackVo.setCameraIndexCode(code); // 获取当前时间 OffsetDateTime currentTime = OffsetDateTime.now(); log.info("currentTime------------->" + currentTime); // 获取报警前的时间 OffsetDateTime beforeTenMinutes = currentTime.minusMinutes(Long.parseLong(frontValue)); log.info("beforeTenMinutes------------->" + beforeTenMinutes); // 获取报警后的时间 OffsetDateTime afterTenMinutes = currentTime.plusMinutes(Long.parseLong(laterValue)); log.info("afterTenMinutes------------->" + afterTenMinutes); // 格式化时间 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); playbackVo.setBeginTime(beforeTenMinutes.format(formatter)); log.info("playbackVo.getBeginTime()------------->" + playbackVo.getBeginTime()); playbackVo.setEndTime(afterTenMinutes.format(formatter)); log.info("playbackVo.getEndTime()------------->" + playbackVo.getEndTime()); // jsonBody.put("protocol","rtsp"); // jsonBody.put("expand","streamform=rtp"); playbackVo.setProtocol("rtsp"); playbackVo.setExpand("streamform=rtp"); //对象转换json字符串 String body = JSONObject.toJSONString(playbackVo); //调用天网接口 log.info("body----->" + body); //获取回放视频的url String playbackURLs = getPreviewURLs("/api/video/v1/cameras/playbackURLs", body); if (StringUtils.isEmpty(playbackURLs)) { return "天网无视频-" + code; } log.info("playbackURLs----->" + playbackURLs); JSONObject outJson = (JSONObject) JSONObject.parse(playbackURLs); if ("0".equals(outJson.getString("code"))) { log.info("outJson----->" + outJson); JSONObject data = outJson.getJSONObject("data"); String urls = data.getString("url"); log.info("--------------->urls::" + urls); //向流媒体推报警回放视频 log.info("msg---------->" + httpUrl + "/rtsp/api/pull?target=" + urls + "&streamPath=" + code + "/playback&save=0"); String msg = HttpUtils.sendGet(httpUrl + "/rtsp/api/pull?target=" + urls + "&streamPath=" + code + "/playback&save=0"); log.info("msg---------->" + msg); if (!msg.equals("ok")) { return "暂无视频-" + code; } /** * //两个流媒体的个数 * //第一个是性能高的 * int urlCount = urlCount(httpUrl); * //第二个是性能低的 * int urlCounts = urlCount(httpUrls); * //向流媒体推报警回放视频 * if (urlCount == 0) { * log.info("msg---------->" + httpUrl + "/rtsp/api/pull?target=" + urls + "&streamPath=" + code + "/playback&save=0"); * String msg = HttpUtils.sendGet(httpUrl + "/rtsp/api/pull?target=" + urls + "&streamPath=" + code + "/playback&save=0"); * log.info("msg---------->" + msg); * if (!msg.equals("ok")) { * return "暂无视频-" + code; * } * return "master"; * } else { * if (urlCounts * 2 > urlCount) { * log.info("msg---------->" + httpUrl + "/rtsp/api/pull?target=" + urls + "&streamPath=" + code + "/playback&save=0"); * String msg = HttpUtils.sendGet(httpUrl + "/rtsp/api/pull?target=" + urls + "&streamPath=" + code + "/playback&save=0"); * log.info("msg---------->" + msg); * if (!msg.equals("ok")) { * return "暂无视频-" + code; * } * return "master"; * } else { * log.info("msg---------->" + httpUrls + "/rtsp/api/pull?target=" + urls + "&streamPath=" + code + "/playback&save=0"); * String msg = HttpUtils.sendGet(httpUrls + "/rtsp/api/pull?target=" + urls + "&streamPath=" + code + "/playback&save=0"); * log.info("msg---------->" + msg); * if (!msg.equals("ok")) { * return "暂无视频-" + code; * } * return "slave"; * } * } */ // String FilePath = "/opt/streams/map/" + code + ".mp4"; // Process process = rtspToMP4.StartRecord(ffmpegPath, urls, FilePath); // log.info("------playbackURLs----->>>>:" + process); // if (null != process) { // map.put(code, process); // } // try { // TimeUnit.SECONDS.sleep(204 * Integer.parseInt(alarmPlayTimeValue)); // } catch (InterruptedException e) { // e.printStackTrace(); // } // log.info("------videoCompression----->>>>:"); // videoCompression(code); } else { return "天网无视频-" + code; } } catch (Exception e) { e.printStackTrace(); } return "正常"; } public AjaxResult stop(String id) { if (map.containsKey(id)) { Process process = map.get(id); log.info("-----stop------>>>" + process); if (null != process) { rtspToMP4.stopRecord(process); return AjaxResult.success(); } } return AjaxResult.error(); } public static void main(String[] args) throws InterruptedException, ParseException, IOException { // CameraUtil cameraUtil = new CameraUtil(); // cameraUtil.closeRecording(); // String s = "/opt/streams/record/flv/42010001541320001116/20230403_235506_000506-22e1523b-d170-11ed-8a42-fa163e4e1e9f.flv"; // String fileStr = s.substring(s.lastIndexOf("/") + 1, s.length()); // String pathStr = s.substring(0, s.lastIndexOf("/")); // System.out.println(fileStr); // System.out.println(pathStr); String s = "20230403235512"; Date sdate = DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, s); sdate = DateUtils.addDays(sdate, -1); System.out.println(DateUtils.parseDateToStr(DateUtils.YYYYMMDDHHMMSS, sdate)); } public List heartbeatGetPlayFlv() { int maxRetries = 5; int retryCount = 0; boolean success = false; JSONArray streamArray = null; List baseCameraManagementResponseList = new ArrayList<>(); while (!success && retryCount < maxRetries) { try { String data = HttpClientUtil.gets(webUrl + "/api/summary"); log.info("data------------------>" + data); if (StringUtils.isNotEmpty(data)) { JSONObject jsonObject = JSONObject.parseObject(data); streamArray = jsonObject.getJSONArray("Streams"); success = true; } } catch (Exception e) { // 增加重试计数 retryCount++; } } for (int i = 0; i < streamArray.size(); i++) { BaseCameraManagementResponse baseCameraManagementResponse = new BaseCameraManagementResponse(); JSONObject subObj = streamArray.getJSONObject(i); String subValue = subObj.getString("Subscribers"); String PathValue = subObj.getString("Path"); String type = subObj.getString("Type"); String timestampString = subObj.getString("StartTime"); ZonedDateTime givenTime = ZonedDateTime.parse(timestampString); // 当前时间 Instant currentTime = Instant.now(); // 将给定时间转换为Instant对象 Instant givenInstant = givenTime.toInstant(); // 计算时间差 Duration duration = Duration.between(givenInstant, currentTime); //封装 // 获取小时差 baseCameraManagementResponse.setStartTime(duration.toHours() + "小时前"); baseCameraManagementResponse.setStreamPath(PathValue); baseCameraManagementResponse.setSubscribers(subValue); baseCameraManagementResponse.setType(type); // 寻找第一个斜杠的位置 int slashIndex = PathValue.indexOf("/"); if (slashIndex != -1) { BaseCameraManagementResponse response = new BaseCameraManagementResponse(); String result = PathValue.substring(0, slashIndex); BaseCameraManagement cameraManagement = baseCameraManagementService.getOne(new LambdaQueryWrapper() .eq(BaseCameraManagement::getCameraCode, result)); if (!ObjectUtils.isEmpty(cameraManagement)) { baseCameraManagementResponse.setCameraCode(cameraManagement.getCameraCode()); baseCameraManagementResponse.setInstallMile(cameraManagement.getInstallMile()); } } //取出AudioTracks JSONArray audioJson = subObj.getJSONArray("AudioTracks"); if (audioJson != null && audioJson.size() > 0) { for (int v = 0; v < audioJson.size(); v++) { BaseCameraManagementResponse.AudioTracks audioTracks = new BaseCameraManagementResponse.AudioTracks(); JSONObject arrayJSONObject = audioJson.getJSONObject(v); String name = arrayJSONObject.getString("Name"); String sampleRate = arrayJSONObject.getString("SampleRate"); String channels = arrayJSONObject.getString("Channels"); String bps = arrayJSONObject.getString("BPS"); audioTracks.setBps(bps); audioTracks.setChannels(channels); audioTracks.setName(name); audioTracks.setSampleRate(sampleRate); baseCameraManagementResponse.setAudioTracks(audioTracks); } } //取出VideoTracks JSONArray videoJson = subObj.getJSONArray("VideoTracks"); if (videoJson != null && videoJson.size() > 0) { for (int v = 0; v < videoJson.size(); v++) { BaseCameraManagementResponse.VideoTracks videoTracks = new BaseCameraManagementResponse.VideoTracks(); JSONObject arrayJSONObject = videoJson.getJSONObject(v); String name = arrayJSONObject.getString("Name"); String width = arrayJSONObject.getString("Width"); String height = arrayJSONObject.getString("Height"); String resolution = width + "*" + height; String gop = arrayJSONObject.getString("GOP"); String bps = arrayJSONObject.getString("BPS"); videoTracks.setBps(bps); videoTracks.setGop(gop); videoTracks.setName(name); videoTracks.setResolution(resolution); baseCameraManagementResponse.setVideoTracks(videoTracks); } } baseCameraManagementResponseList.add(baseCameraManagementResponse); } return baseCameraManagementResponseList; } public void removePlayFlv(Integer lineDir, Integer currentMile, Integer visualDistance) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); if (lineDir == 1) { wrapper.gt(BaseCameraManagement::getEndMile, currentMile + visualDistance) .in(BaseCameraManagement::getMonitoringDirection, 1, 3); } else if (lineDir == 2) { wrapper.lt(BaseCameraManagement::getBeginMile, currentMile - visualDistance) .in(BaseCameraManagement::getMonitoringDirection, 2, 3); } wrapper.eq(BaseCameraManagement::getEnableOrNot, 1); //获取应该注销的相机 List list = baseCameraManagementService.list(wrapper); ArrayList codeList = new ArrayList<>(); if (!ObjectUtils.isEmpty(list)) { for (BaseCameraManagement baseCameraManagement : list) { codeList.add(baseCameraManagement.getCameraCode() + "/" + baseCameraManagement.getGraphicsCard()); } } String data = HttpUtils.sendGet(webUrl + "/api/summary"); log.info("data------------------>" + data); ArrayList arrayList = new ArrayList(); if (StringUtils.isNotEmpty(data)) { JSONObject jsonObject = JSONObject.parseObject(data); log.info("jsonObject------------------>" + jsonObject); JSONArray streamArray = jsonObject.getJSONArray("Streams"); log.info("streamArray------------------>" + streamArray); if (!ObjectUtils.isEmpty(streamArray)) { for (int i = 0; i < streamArray.size(); i++) { JSONObject subObj = streamArray.getJSONObject(i); log.info("subObj------------------>" + subObj); String subValue = subObj.getString("Subscribers"); String pathValue = subObj.getString("Path"); //从缓存取出预拉的流的集合 log.info("subValue------------------>" + subValue); log.info("pathValue------------------>" + pathValue); //判断主码流是否订阅者是2 if (subValue.equals("0")) { arrayList.add(pathValue); } } } } if (!ObjectUtils.isEmpty(codeList) && !ObjectUtils.isEmpty(arrayList)) { codeList.retainAll(arrayList); if (!ObjectUtils.isEmpty(codeList)) { for (String pathValue : codeList) { hostStopStream(pathValue); } } } } /** * 根据相机ID找出分组并排序 * * @param baseCameraManagement */ public List getBaseCameraManagementList(Long id, Integer line) { //根据ID获取当前相机的信息 BaseCameraManagement baseCameraManagement = baseCameraManagementService.getById(id); if (!ObjectUtils.isEmpty(baseCameraManagement)) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); //找出同一分组的相机 wrapper.eq(BaseCameraManagement::getGrou, baseCameraManagement.getGrou()); if (line == 1) { wrapper.orderByAsc(BaseCameraManagement::getSort); } else if (line == 2) { wrapper.orderByDesc(BaseCameraManagement::getSort); } List list = baseCameraManagementService.list(wrapper); if (!ObjectUtils.isEmpty(list)) { return list; } else { return null; } } else { return null; } } /** * 根据设备id和通道ID和日期获取设备录像文件 * * @param baseCameraManagement */ public String getQueryRecords(String streamPath, String date, String type, String start,String end) { log.info("-----getQueryRecords------streamPath-----" + streamPath); log.info("-----getQueryRecords-------date----" + date); log.info("-----getQueryRecords-------type----" + type); try { TimeUnit.SECONDS.sleep(60 * (Integer.parseInt(start)+Integer.parseInt(end))); } catch (InterruptedException e) { e.printStackTrace(); } String param = "{\n" + " \"streamPath\":\"" + streamPath + "\",\n" + " \"date\":\"" + date + "\",\n" + " \"type\":\"" + type + "\"\n" + "}"; String jsonStr = HttpUtils.sendPost(httpUrl + "/recordpro/api/query/records", param); log.info("-----getQueryRecords-------jsonStr----" + jsonStr); JSONObject jsonObj = JSON.parseObject(jsonStr); log.info("-----getQueryRecords-------jsonObj----" + jsonObj); JSONArray resultArray = jsonObj.getJSONArray("result"); log.info("-----getQueryRecords-------resultArray----" + resultArray); if (!ObjectUtils.isEmpty(resultArray)) { ArrayList list = new ArrayList<>(); for (int i = 0; i < resultArray.size(); i++) { JSONObject subObj = resultArray.getJSONObject(i); String size = subObj.getString("Size"); String path = subObj.getString("Path"); Object created = subObj.get("Created"); //从缓存取出预拉的流的集合 log.info("size------------------>" + size); log.info("path------------------>" + path); log.info("created------------------>" + created); //判断主码流是否订阅者是2 if (Integer.valueOf(size) > 1000) { list.add(created + "=" + path); } } String records = records(list); log.info("-----getQueryRecords-------records----" + records); String[] split = records.split("="); return caneraConfig.getRecordUrl() + Constants.RESOURCE_PREFIX + split[1]; } return null; } public String records(List objects) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX"); OffsetDateTime maxTime = null; for (String timeString : objects) { String[] split = timeString.split("="); OffsetDateTime time = OffsetDateTime.parse(split[0], formatter); if (maxTime == null || time.isAfter(maxTime)) { maxTime = time; } } Iterator iter = objects.iterator(); while (iter.hasNext()) { String timeString = iter.next(); String[] split = timeString.split("="); OffsetDateTime time = OffsetDateTime.parse(split[0], formatter); if (!time.isEqual(maxTime)) { iter.remove(); } } return objects.get(0); } /** * 流媒体的条数 * * @return */ // public static int urlCount(String url) { // long begin = System.currentTimeMillis(); // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // log.info("urlCountf方法开始时间: " + sdf.format(new Date(begin))); // int maxRetries = 5; // int retryCount = 0; // int count = 0; // boolean success = false; // JSONArray streamArray = null; // while (!success && retryCount < maxRetries) { // try { // String data = HttpClientUtil.gets(url + "/api/summary"); // log.info("data------------------>" + data); // if (StringUtils.isNotEmpty(data)) { // JSONObject jsonObject = JSONObject.parseObject(data); // streamArray = jsonObject.getJSONArray("Streams"); // success = true; // } // } catch (Exception e) { // log.info("Exception caught: " + e.getMessage()); // // 增加重试计数 // retryCount++; // } // } // long zhong = System.currentTimeMillis(); // log.info("urlCountf方法循环时间: " + sdf.format(new Date(zhong))); // if (!ObjectUtils.isEmpty(streamArray)) { //// for (int i = 0; i < streamArray.size(); i++) { //// JSONObject subObj = streamArray.getJSONObject(i); //// String PathValue = subObj.getString("Path"); //// if (PathValue.contains("/h264_720")) { //// count++; //// } //// } // long end = System.currentTimeMillis(); // log.info("urlCountf方法结束时间: " + sdf.format(new Date(end))); // return streamArray.size(); // } else { // long end = System.currentTimeMillis(); // log.info("urlCountf方法结束时间: " + sdf.format(new Date(end))); // return count; // } // } }