Browse Source

报警回放开发

gao.qiang 10 months ago
parent
commit
02d1f6ea3e

+ 5 - 12
hazard-admin/src/main/java/com/ozs/web/core/util/CameraUtil.java

@@ -255,17 +255,6 @@ public class CameraUtil {
         }
     }
 
-    /**
-     * 报警视频回放新
-     * @param channel
-     * @param cameraCode
-     * @param startTm
-     * @param endTm
-     * @return
-     */
-    public static String alarmHistoryPlay(String channel,String cameraCode, Date startTm, Date endTm) {
-        return  null;
-    }
 
     /**
      * 过滤符合条件的视频
@@ -546,7 +535,11 @@ ffmpeg -i "concat:1.ts|2.ts" -c copy output.mp4
      */
     public static String getRecordUrl(String cameraCode, String channel, Date startTm, Date endTm) {
         String result = null;
-        String url = webUrl + "/api/gb28181/invite?id=" + cameraCode + "&channel=" + channel + "&startTime=" + startTm + "&endTime=" + endTm;
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        // 使用SimpleDateFormat格式化Date对象为字符串
+        String start = sdf.format(startTm);
+        String end = sdf.format(endTm);
+        String url = webUrl + "/api/gb28181/invite?id=" + cameraCode + "&channel=" + channel + "&startTime=" + start + "&endTime=" + end;
         try {
             result = HttpClientUtil.get(url);
             if (result.equals("200")) {

+ 202 - 9
hazard-sdk/src/main/java/com/ozs/controller/upload/GeoHazardMonitorTokenController.java

@@ -1,6 +1,7 @@
 package com.ozs.controller.upload;
 
 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;
@@ -12,6 +13,7 @@ import com.ozs.common.enums.BusinessTypeSdk;
 import com.ozs.common.utils.ApiTokenUtils;
 import com.ozs.common.utils.HttpClientUtil;
 import com.ozs.common.utils.StringUtils;
+import com.ozs.common.utils.http.HttpUtils;
 import com.ozs.common.utils.stateSecrets.SM4Utils;
 import com.ozs.service.entity.BaseCameraManagement;
 import com.ozs.service.entity.BaseDeviceDynamicManagement;
@@ -41,7 +43,14 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import java.nio.charset.StandardCharsets;
 import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /**
@@ -73,6 +82,12 @@ public class GeoHazardMonitorTokenController {
     private RedisCache redisCache;
     @Autowired
     private RedisService redisService;
+    @Value("${base.webUrl}")
+    private String webUrl;
+    @Value("${base.wsUrl}")
+    private String wsUrl;
+    @Value("${base.recordUrl}")
+    private String recordUrl;
 
     /**
      * 获取web访问令牌
@@ -213,15 +228,10 @@ public class GeoHazardMonitorTokenController {
                 respMsgAlarmVo.setCameraCode(reqMsgAlarmVo.getAlarmCamera());
                 respMsgAlarmVo.setIsCancel(2);
                 respMsgAlarmVo.setCancelTime(null);
-                // 记录要合成报警视频的报警id
-//                Map<String, Object> map = redisCache.getCacheMap(RedisConstant.key);
-//                if (ObjectUtils.isEmpty(map)) {
-//                    map = new HashMap<>();
-//                }
-//                map.put(msgAlarm.getAlarmId(), msgAlarm.getAlarmTime());
-//                log.info("map:{}", map);
-//                redisCache.deleteObject(RedisConstant.key);
-//                redisCache.setCacheMap(RedisConstant.key, map);
+                // 合成报警视频
+                String alarmUrl = alarmHistoryPlay(baseCameraManagement.getCameraCode(), baseCameraManagement.getChannel(),msgAlarm.getAlarmTime());
+                msgAlarm.setReleasedUrl(alarmUrl);
+                msgAlarmService.updateById(msgAlarm);
             } else {
                 BeanUtils.copyProperties(reqMsgAlarmVo, msgAlarmVice);
                 String[] imageUrl = reqMsgAlarmVo.getImageUrls();
@@ -320,6 +330,189 @@ public class GeoHazardMonitorTokenController {
         }
     }
 
+
+    /**
+     * 报警视频回放新
+     * @param channel
+     * @param cameraCode
+     * @return
+     */
+    public  String alarmHistoryPlay(String channel,String cameraCode,Date alarmDate) {
+        // 获取当前时间
+        // 将Date对象转换为Instant对象
+        Instant instant = alarmDate.toInstant();
+
+        OffsetDateTime currentTime = instant.atOffset(ZoneOffset.ofHours(8));
+        log.info("currentTime------------->" + currentTime);
+        // 获取报警前的时间
+        OffsetDateTime beforeTenMinutes = currentTime.minusMinutes(Long.parseLong("5"));
+        log.info("beforeTenMinutes------------->" + beforeTenMinutes);
+        // 获取报警后的时间
+        OffsetDateTime afterTenMinutes = currentTime.plusMinutes(Long.parseLong("5"));
+        log.info("afterTenMinutes------------->" + afterTenMinutes);
+        // 格式化时间
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        String result = null;
+        String url = webUrl + "/api/gb28181/invite?id=" + cameraCode + "&channel=" + channel + "&startTime=" + beforeTenMinutes.format(formatter) + "&endTime=" + afterTenMinutes.format(formatter);
+        try {
+            result = HttpClientUtil.get(url);
+            if ("200".equals(result)) {
+                // 将字符串解析为LocalDateTime对象(指定时区为东八区)
+                LocalDateTime startTime = LocalDateTime.parse(beforeTenMinutes.format(formatter), formatter).atOffset(ZoneOffset.ofHours(8)).toLocalDateTime();
+                LocalDateTime endTime = LocalDateTime.parse(afterTenMinutes.format(formatter), formatter).atOffset(ZoneOffset.ofHours(8)).toLocalDateTime();
+                // 将LocalDateTime转换为秒数
+                long seconds = startTime.toEpochSecond(ZoneOffset.ofHours(8));
+                long second = endTime.toEpochSecond(ZoneOffset.ofHours(8));
+                String path = apiSummary(cameraCode + "/" + channel+"/"+seconds+"-"+second);
+                if (org.apache.commons.lang3.StringUtils.isNotEmpty(path)){
+                    String codes = HttpUtils.sendGet(startRecording(cameraCode, "playback"));
+                    log.info("codes------>" + codes);
+                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+                    // 使用SimpleDateFormat将Date对象格式化为指定样式的字符串
+                    String formattedDate = sdf.format(alarmDate);
+                    log.info("-----formattedDate-----------" + formattedDate);
+                    String records = getQueryRecords(alarmDate + "/playback", formattedDate,"flv");
+                    log.info("-----records-----------" + records);
+                    return records;
+                }
+            }
+        } catch (Exception e) {
+            log.info(e.getMessage());
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 调用流媒体获取流列表信息
+     *
+     * @return
+     */
+    public  String apiSummary(String path) {
+        int maxRetries = 5;
+        int retryCount = 0;
+        boolean success = false;
+        JSONArray streamArray = null;
+        while (!success && retryCount < maxRetries) {
+            try {
+                String data = HttpClientUtil.gets(webUrl + "/api/summary");
+                log.info("data------------------>" + data);
+                if (org.apache.commons.lang3.StringUtils.isNotEmpty(data)) {
+                    JSONObject jsonObject = JSONObject.parseObject(data);
+                    streamArray = jsonObject.getJSONArray("Streams");
+                    success = true;
+                }
+            } catch (Exception e) {
+                log.info("Exception caught: " + e.getMessage());
+                // 增加重试计数
+                retryCount++;
+            }
+        }
+        if (!ObjectUtils.isEmpty(streamArray)) {
+            for (int i = 0; i < streamArray.size(); i++) {
+                JSONObject subObj = streamArray.getJSONObject(i);
+                String streamPath = subObj.getString("StreamPath");
+                if (streamPath.equals(path)) {
+                    //取出VideoTracks
+                    JSONArray videoJson = subObj.getJSONArray("VideoTracks");
+                    if (videoJson != null && !videoJson.isEmpty()) {
+                        return wsUrl + "/ws/" + streamPath;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 开启录制功能
+     *
+     * @param cameraCode 相机编码
+     * @param channel    相机通道
+     * @return
+     */
+    public  String startRecording(String cameraCode, String channel) {
+        log.info("-----startRecording------" + webUrl + "/recordpro/api/start?streamPath=" + cameraCode + "/" + channel + "&type=mp4");
+        return webUrl + "/recordpro/api/start?streamPath=" + cameraCode + "/" + channel + "&type=mp4";
+    }
+
+    /**
+     * 根据设备id和通道ID和日期获取设备录像文件
+     *
+     */
+    public String getQueryRecords(String streamPath, String date, String type) {
+
+        log.info("-----getQueryRecords------streamPath-----" + streamPath);
+        log.info("-----getQueryRecords-------date----" + date);
+        log.info("-----getQueryRecords-------type----" + type);
+        try {
+            TimeUnit.SECONDS.sleep(60 * 10);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        String param = "{\n" +
+                "    \"streamPath\":\"" + streamPath + "\",\n" +
+                "    \"date\":\"" + date + "\",\n" +
+                "    \"type\":\"" + type + "\"\n" +
+                "}";
+
+        String jsonStr = HttpUtils.sendPost(webUrl + "/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<String> 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 recordUrl + Constants.RESOURCE_PREFIX + split[1];
+        }
+        return null;
+    }
+
+    public String records(List<String> 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<String> 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);
+    }
+
+
     public static void main(String[] args) {
 //        String parameter = "rjW9XcaNdY1M2rtUj4rYsW+3nqcJUDBuE6Orqvd4vyMhOh3fQGPNava0aOcUA7h0wuxoQtHE3bUP5imxqbRd/iBT7QDkrqtdPP5QLEhQodT8v0l8YMMtb7yohAJfEThLJOJ8Odl0kuTJXEJBMD8pE//K9KpRGDY4eEKPdS26YywnIl6HwK9EweYxVGtfJOP3/N7lwum2ROv7iqYgefXd/IxGEG8eVqEUutGKpeCcM0dds/N3Uq5ri/k/BrpaKcV96GnlR4pWkBjWOW08eGJ78shuUJkC682294W4RUp3NPPR7OTErtVAh65or8pB+RGDZuZQlUJ/QVpWp2ZdCrN5Wjqsi1TIa00oGQbYmMixOF0=";
 //        String s = SM4Utils.decryptData_ECB(parameter, "4370780c9a8c43e5");

+ 4 - 1
hazard-sdk/src/main/resources/application.yml

@@ -9,13 +9,16 @@ base:
   # 实例演示开关
   demoEnabled: true
   # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
-  profile: C:/base/uploadPath
+  profile: /opt/streams
   # 获取ip地址开关
   addressEnabled: false
   # 验证码类型 math 数组计算 char 字符验证
   captchaType: math
   #图片路径前缀
   imgUrl: http://124.70.58.209:18801/picbucket
+  webUrl: http://124.70.58.209:9080
+  wsUrl: ws://124.70.58.209:9080
+  recordUrl: http://124.70.58.209:18082
 
 # 开发环境配置
 server: