|  | @@ -5,6 +5,7 @@ import com.alibaba.fastjson2.JSONObject;
 | 
	
		
			
				|  |  |  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.HttpClientUtil;
 | 
	
	
		
			
				|  | @@ -14,6 +15,7 @@ import com.ozs.entity.MsgAlarm;
 | 
	
		
			
				|  |  |  import com.ozs.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;
 | 
	
	
		
			
				|  | @@ -37,6 +39,7 @@ 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;
 | 
	
	
		
			
				|  | @@ -56,6 +59,11 @@ public class CameraUtil {
 | 
	
		
			
				|  |  |      private SysDictDataMapper dictDataMapper;
 | 
	
		
			
				|  |  |      @Resource
 | 
	
		
			
				|  |  |      BaseCameraManagementService baseCameraManagementService;
 | 
	
		
			
				|  |  | +    private static RedisCache rc;
 | 
	
		
			
				|  |  | +    @Autowired
 | 
	
		
			
				|  |  | +    private RedisCache redisCache;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public final static String tsFilekey = "mergeVideoTsFile";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /**
 | 
	
	
		
			
				|  | @@ -66,7 +74,7 @@ public class CameraUtil {
 | 
	
		
			
				|  |  |       * @return
 | 
	
		
			
				|  |  |       * @throws IOException
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  | -    public static String historyPlay(List<String> fromVideoFileList, String ph, String uuid) {
 | 
	
		
			
				|  |  | +    public static String historyPlay(List<String> fromVideoFileList, String ph, boolean flay) {
 | 
	
		
			
				|  |  |          // 视频服务映射路径
 | 
	
		
			
				|  |  |          String NewfilePath = BaseConfig.getProfile() + "/" + ph;
 | 
	
		
			
				|  |  |          log.info("NewfilePath:{}", NewfilePath);
 | 
	
	
		
			
				|  | @@ -74,32 +82,89 @@ 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();
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | +                    txConvetor(fromVideoFileList, NewfilePath, flay);
 | 
	
		
			
				|  |  |                  } catch (IOException e) {
 | 
	
		
			
				|  |  |                      log.error(e.getMessage());
 | 
	
		
			
				|  |  |                      e.printStackTrace();
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  | -        executor.shutdown();
 | 
	
		
			
				|  |  | +//        executor.shutdown();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          return Constants.RESOURCE_PREFIX + "/" + ph;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @SneakyThrows
 | 
	
		
			
				|  |  | +    public static void txConvetor(List<String> 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<String> 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<String, Object> mergeVideoTsFile = rc.getCacheMap(tsFilekey);
 | 
	
		
			
				|  |  | +            if (ObjectUtils.isEmpty(mergeVideoTsFile)) {
 | 
	
		
			
				|  |  | +                mergeVideoTsFile = new HashMap<>();
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            if (!flay) {
 | 
	
		
			
				|  |  | +                // 如果没有解除,把生成的文件放入要删除的定时任务 redis key 中
 | 
	
		
			
				|  |  | +                fileTs.add(newfilePath);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            mergeVideoTsFile.put(new Date().getTime() + "", 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());
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  |      /**
 | 
	
		
			
				|  |  |       * 实时播放的拼接流
 | 
	
		
			
				|  |  |       *
 | 
	
	
		
			
				|  | @@ -169,15 +234,15 @@ public class CameraUtil {
 | 
	
		
			
				|  |  |       * @param endTm   结束时间
 | 
	
		
			
				|  |  |       * @return
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  | -    public static String historyPlayListStr(String channel, Date startTm, Date endTm) {
 | 
	
		
			
				|  |  | +    public static String historyPlayListStr(String channel, Date startTm, Date endTm, boolean flay) {
 | 
	
		
			
				|  |  |          List<String> list = filterPlayList(channel, startTm, endTm, filePath);
 | 
	
		
			
				|  |  |          String uuid = UUID.randomUUID().toString();
 | 
	
		
			
				|  |  | -        String ph = "flv/" + DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, new Date())
 | 
	
		
			
				|  |  | +        String ph = "record/flv/" + DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, new Date())
 | 
	
		
			
				|  |  |                  + "/" + channel + "/"
 | 
	
		
			
				|  |  | -                + uuid + ".flv";
 | 
	
		
			
				|  |  | +                + uuid + ".mp4";
 | 
	
		
			
				|  |  |          if (!ObjectUtils.isEmpty(list)) {
 | 
	
		
			
				|  |  |              try {
 | 
	
		
			
				|  |  | -                return historyPlay(list, ph, uuid);
 | 
	
		
			
				|  |  | +                return historyPlay(list, ph, flay);
 | 
	
		
			
				|  |  |              } catch (Exception e) {
 | 
	
		
			
				|  |  |                  log.error(e.getMessage());
 | 
	
		
			
				|  |  |                  e.printStackTrace();
 | 
	
	
		
			
				|  | @@ -376,6 +441,7 @@ public class CameraUtil {
 | 
	
		
			
				|  |  |          transcribeFilePath = caneraConfig.getTranscribeFilePath();
 | 
	
		
			
				|  |  |          webUrl = caneraConfig.getWebUrl();
 | 
	
		
			
				|  |  |          bakUrl = caneraConfig.getBakUrl();
 | 
	
		
			
				|  |  | +        rc = redisCache;
 | 
	
		
			
				|  |  |          cUtil = cmdCameraUtil;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 |