|
@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.ozs.common.config.BaseConfig;
|
|
|
import com.ozs.common.constant.Constants;
|
|
|
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.http.HttpUtils;
|
|
@@ -13,6 +14,7 @@ import com.ozs.service.entity.BaseCameraManagement;
|
|
|
import com.ozs.service.service.BaseCameraManagementService;
|
|
|
import com.ozs.system.mapper.SysDictDataMapper;
|
|
|
import com.ozs.web.core.config.CaneraConfig;
|
|
|
+import lombok.SneakyThrows;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
@@ -44,7 +46,9 @@ import java.util.stream.Collectors;
|
|
|
@Component
|
|
|
public class CameraUtil {
|
|
|
|
|
|
+ private static final ExecutorService executor = Executors.newFixedThreadPool(20);
|
|
|
private static String historyUrl;
|
|
|
+ private static String recordUrl;
|
|
|
private static String ffmpegPath;
|
|
|
private static String filePath;
|
|
|
private static String transcribeFilePath;
|
|
@@ -60,6 +64,9 @@ public class CameraUtil {
|
|
|
|
|
|
@Autowired
|
|
|
private SysDictDataMapper dictDataMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RedisCache redisCache;
|
|
|
@Resource
|
|
|
BaseCameraManagementService baseCameraManagementService;
|
|
|
|
|
@@ -80,28 +87,27 @@ public class CameraUtil {
|
|
|
if (ObjectUtils.isEmpty(fromVideoFileList) || fromVideoFileList.size() <= 0) {
|
|
|
throw new BaseException("当前相机无视频录像");
|
|
|
}
|
|
|
- ExecutorService executor = Executors.newFixedThreadPool(10);
|
|
|
-
|
|
|
executor.submit(new Runnable() {
|
|
|
@Override
|
|
|
public void run() {
|
|
|
try {
|
|
|
- Map<String, String> map = myConvetor(fromVideoFileList, NewfilePath, uuid);
|
|
|
- if (!ObjectUtils.isEmpty(map)) {
|
|
|
- cUtil.cmd(map.get("cmd"));
|
|
|
- //删除生成的ts文件
|
|
|
- File file1 = new File(map.get("path"));
|
|
|
- if (file1.exists()) {
|
|
|
- file1.delete();
|
|
|
- }
|
|
|
- }
|
|
|
+// Map<String, String> map = myConvetor(fromVideoFileList, NewfilePath, uuid);
|
|
|
+// if (!ObjectUtils.isEmpty(map)) {
|
|
|
+// cUtil.cmd(map.get("cmd"));
|
|
|
+// //删除生成的ts文件
|
|
|
+// File file1 = new File(map.get("path"));
|
|
|
+// if (file1.exists()) {
|
|
|
+// file1.delete();
|
|
|
+// }
|
|
|
+// }
|
|
|
+ txConvetor(fromVideoFileList, NewfilePath, uuid);
|
|
|
} catch (IOException e) {
|
|
|
log.error(e.getMessage());
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
- executor.shutdown();
|
|
|
+// executor.shutdown();
|
|
|
|
|
|
return Constants.RESOURCE_PREFIX + "/" + ph;
|
|
|
}
|
|
@@ -359,15 +365,66 @@ public class CameraUtil {
|
|
|
}
|
|
|
|
|
|
|
|
|
- @PostConstruct
|
|
|
- public void init() {
|
|
|
- historyUrl = caneraConfig.getHistoryUrl();
|
|
|
- ffmpegPath = caneraConfig.getFfmpegPath();
|
|
|
- filePath = caneraConfig.getFilePath();
|
|
|
- transcribeFilePath = caneraConfig.getTranscribeFilePath();
|
|
|
- webUrl = caneraConfig.getWebUrl();
|
|
|
- bakUrl = caneraConfig.getBakUrl();
|
|
|
- cUtil = cmdCameraUtil;
|
|
|
+ @SneakyThrows
|
|
|
+ public static void txConvetor(List<String> fromVideoFileList,
|
|
|
+ String newfilePath,
|
|
|
+ String uuid) 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.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(ffmpegPath + " -i \"concat:");
|
|
|
+ List<String> fileTs = new ArrayList<>();
|
|
|
+ for (int t = 0; t < fromVideoFileList.size(); t++) {
|
|
|
+ File ft = new File(fromVideoFileList.get(t));
|
|
|
+ if (ft.exists()) {
|
|
|
+ // 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
|
|
|
+ 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) {
|
|
|
+ sm.append("-c copy " + newfilePath);
|
|
|
+ log.info("合并命令:{}", sm.toString());
|
|
|
+ cUtil.cmd(sm.toString());
|
|
|
+ }
|
|
|
+ Thread.sleep(2000L);
|
|
|
+ for (String fileT : fileTs) {
|
|
|
+ File ft = new File(fileT);
|
|
|
+ if (ft.exists()) {
|
|
|
+ ft.delete();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static List<Map<String, Object>> getRecordList(String channel, Date startTm, Date endTm) {
|
|
|
+ return filterRecordList(channel, startTm, endTm, filePath, recordUrl + "/");
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -480,6 +537,51 @@ public class CameraUtil {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ 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 substring = s.substring(0, s.lastIndexOf("."));
|
|
|
+ System.out.println(substring);
|
|
|
+// 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 static File[] getCurFilesList(String filePath) {
|
|
|
+ File path = new File(filePath);
|
|
|
+ File[] listFiles = path.listFiles(new java.io.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();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 定时任务:关闭录制视频
|
|
|
*
|
|
@@ -572,46 +674,142 @@ public class CameraUtil {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public static File[] getCurFilesList(String filePath) {
|
|
|
- File path = new File(filePath);
|
|
|
- File[] listFiles = path.listFiles(new java.io.FileFilter() {
|
|
|
+ @PostConstruct
|
|
|
+ public void init() {
|
|
|
+ historyUrl = caneraConfig.getHistoryUrl();
|
|
|
+ ffmpegPath = caneraConfig.getFfmpegPath();
|
|
|
+ filePath = caneraConfig.getFilePath();
|
|
|
+ transcribeFilePath = caneraConfig.getTranscribeFilePath();
|
|
|
+ webUrl = caneraConfig.getWebUrl();
|
|
|
+ bakUrl = caneraConfig.getBakUrl();
|
|
|
+ recordUrl = caneraConfig.getRecordUrl();
|
|
|
+ cUtil = cmdCameraUtil;
|
|
|
+ }
|
|
|
|
|
|
- @Override
|
|
|
- public boolean accept(File pathname) {
|
|
|
- if (pathname.isFile()) {
|
|
|
- return true;
|
|
|
- } else {
|
|
|
|
|
|
- return false;
|
|
|
- }
|
|
|
+ public static List<Map<String, Object>> filterRecordList(String channel,
|
|
|
+ Date startTm,
|
|
|
+ Date endTm,
|
|
|
+ String mappingUrl,
|
|
|
+ String webUrl) {
|
|
|
+ List<Map<String, Object>> rmaps = new ArrayList<>();
|
|
|
+
|
|
|
+ if (StringUtils.isBlank(channel)
|
|
|
+ || ObjectUtils.isEmpty(startTm)
|
|
|
+ || ObjectUtils.isEmpty(endTm)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ Map<Date, Map<String, Object>> 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)) {
|
|
|
+ List<Map<String, Object>> maps = JSON.parseArray(s, Map.class);
|
|
|
+ if (ObjectUtils.isEmpty(maps)) {
|
|
|
+ return null;
|
|
|
}
|
|
|
- });
|
|
|
+ for (Map<String, Object> 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<String, Object> mo = new HashMap<>();
|
|
|
|
|
|
- return listFiles;
|
|
|
- }
|
|
|
+ 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", webUrl + 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);
|
|
|
|
|
|
- public static void execute(String command) {
|
|
|
- try {
|
|
|
- ProcessBuilder process = new ProcessBuilder(command);
|
|
|
- process.inheritIO().start().waitFor();
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
+ /* |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<Date> 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 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 void mergeVideo() {
|
|
|
+ Date date = new Date();
|
|
|
+ Calendar calendar = new GregorianCalendar();
|
|
|
+
|
|
|
+
|
|
|
+ Map<String, Object> alarmIdMap = redisCache.getCacheMap("WAIT_MERGE_VIDEO_ALARM_ID");
|
|
|
+ log.info("WAIT_MERGE_VIDEO_ALARM_ID:{}", alarmIdMap);
|
|
|
+ if (!ObjectUtils.isEmpty(alarmIdMap)) {
|
|
|
+ Set<String> alarmIds = alarmIdMap.keySet();
|
|
|
+ if (!ObjectUtils.isEmpty(alarmIds) && alarmIds.size() > 0) {
|
|
|
+ for (String alarmId : alarmIds) {
|
|
|
+ Object oTime = alarmIdMap.get(alarmId);
|
|
|
+ Date alarmTime = (Date) oTime;
|
|
|
+ // 判断当前时间是否超过报警时间 20分钟
|
|
|
+ calendar.setTime(alarmTime);
|
|
|
+ calendar.add(calendar.MINUTE, 20); //把日期往后增加一天,整数 往后推,负数往前移动
|
|
|
+ alarmTime = calendar.getTime(); //这个时间就是日期往后推一天的结果
|
|
|
+ if (date.compareTo(alarmTime) > 0) {
|
|
|
+ // 表示已经超过报警时间20分钟,可以合成视频
|
|
|
+ String cameraChannelByAlarmId = baseCameraManagementService.getCameraChannelByAlarmId(alarmId);
|
|
|
+ if (!StringUtils.isBlank(cameraChannelByAlarmId)) {
|
|
|
+ log.info("报警UUID:{},相机通道:{},开始时间:{},结束时间:{}", alarmId, cameraChannelByAlarmId, (Date) oTime, date);
|
|
|
+ String url = historyPlayListStr(cameraChannelByAlarmId, (Date) oTime, date);
|
|
|
+ redisCache.setCacheObject("STREAMING_ALARM_VIDEO:" + alarmId, url);
|
|
|
+ redisCache.expire("STREAMING_ALARM_VIDEO:" + alarmId, 365L, TimeUnit.DAYS);
|
|
|
+ alarmIdMap.remove(alarmId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ redisCache.setCacheMap("WAIT_MERGE_VIDEO_ALARM_ID", alarmIdMap);
|
|
|
+
|
|
|
}
|
|
|
}
|