package com.sckj.camera.service; import com.sckj.camera.common.FlowUtils; import com.sckj.camera.common.HikCameraUtils; import com.sckj.camera.manager.HikCameraManager; import com.sckj.camera.model.dto.CameraDTO; import com.sckj.camera.model.dto.ResultDTO; import com.sckj.camera.model.entity.Camera; import com.sckj.camera.model.entity.CameraFile; import com.sckj.camera.model.entity.CameraFlow; import com.sckj.camera.hik.HCNetTools; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.io.File; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; @Service public class HikCameraServiceImpl { private final Logger logger = LoggerFactory.getLogger(HikCameraServiceImpl.class); @Autowired private DeviceServiceImpl deviceService; @Autowired private FlowServiceImpl flowService; @Autowired private FFmpegServiceImpl ffmpegService; @Autowired private CameraFileServiceImpl cameraFileService; @Autowired private HikCameraManager hikCameraManager; @Value("${app.filepath}") private String rootPath; @Value("${rtmp.rtmphost}") private String rtmpServer; @Value("${rtmp.httphost}") private String httpServer; public ResultDTO getChannel(CameraDTO cameraDTO) { ResultDTO resultDTO = new ResultDTO(); StringBuilder str = new StringBuilder(); for (int i = 0;i < cameraDTO.getChannelList().size();i++) { if (i == cameraDTO.getChannelList().size() - 1) { str.append(cameraDTO.getChannelList().get(i)); } else { str.append(cameraDTO.getChannelList().get(i)).append("&"); } } resultDTO.setMsg(str.toString()); return resultDTO; } /** * 开始推流(rtsp->rtmp) * @param cameraDTO 相机信息 * @return ResultDTO */ public ResultDTO startTranscode(CameraDTO cameraDTO) { ResultDTO resultDTO = new ResultDTO(); Camera camera = deviceService.getById(cameraDTO.getCameraId()); if(ObjectUtils.isNotEmpty(camera)){ BeanUtils.copyProperties(camera,cameraDTO); } cameraDTO.setChannelList(Arrays.asList("1")); if (cameraDTO != null) { String appName; int channelNumber; if (cameraDTO.getType() == 0) { //摄像机 appName = cameraDTO.getAccount() + cameraDTO.getIp().replace(".",""); channelNumber = HikCameraUtils.analyzeChannel(cameraDTO.getChannelList().get(0)); } else { //NVR appName = cameraDTO.getAccount() + cameraDTO.getIp().replace(".","") + "to" + cameraDTO.getIpcAddress().replace(".",""); channelNumber = HikCameraUtils.getIpcChannel(cameraDTO.getChannelList(),cameraDTO.getIpcAddress()); } if (channelNumber == -1) { logger.info("实时流-未搜索到ip:" + cameraDTO.getIp() + ", ipc:" + cameraDTO.getIpcAddress() + " 的设备"); } String rtmpUrl = "rtmp://"+ rtmpServer + "/live/" + appName; //rtmp链 String flvUrl = "http://" + httpServer + "/live/" + appName + ".flv"; //http-flv链 boolean runFlag = ffmpegService.taskerIsRun(appName); CameraFlow cameraFlow = flowService.findByRtmpUrl(rtmpUrl); if (cameraFlow != null && !runFlag) { flowService.removeById(cameraFlow.getId()); } if (runFlag) { //已推流 if (cameraFlow != null) { resultDTO.setTasker(appName); resultDTO.setMsg(HikCameraUtils.resultNames[0]); resultDTO.setRtmpUrl(rtmpUrl); resultDTO.setFlvUrl(flvUrl); cameraFlow.setClient(cameraFlow.getClient() + 1); flowService.updateById(cameraFlow); } else { //停止推流 flowService.stopByTasker(appName); resultDTO.setMsg("推流失败"); return resultDTO; } } else { //未推流 //String channelNumberStr = "ch"+channelNumber; //旧通道(2012年之前设备) channelNumber = 1; String channelNumberStr = channelNumber + "02"; //新通道(2012年之后设备,02代表子码流) //String rtspName = cameraDTO.getAccount() + ":" + cameraDTO.getPassword() + "@" + cameraDTO.getIp() + ":554/Streaming/Channels/" + channelNumberStr + "/sub/av_stream"); //旧码流(子码流) String rtspName = cameraDTO.getAccount() + ":" + cameraDTO.getPassword() + "@" + cameraDTO.getIp() + ":554/Streaming/Channels/" + channelNumberStr + "?transportmode=unicast"; //新码流 String rtmpName = rtmpServer + "/live/"; //rtmp服务器推流入口 String tasker= ffmpegService.startTranscoding(appName,rtspName,rtmpName); if (StringUtils.isNotEmpty(tasker)) { resultDTO.setTasker(tasker); resultDTO.setMsg(HikCameraUtils.resultNames[0]); resultDTO.setRtmpUrl(rtmpUrl); resultDTO.setFlvUrl(flvUrl); //添加流记录 cameraFlow = new CameraFlow(); cameraFlow.setCameraId(cameraDTO.getCameraId()); if (cameraDTO.getType() == 0) { cameraFlow.setCameraIpc(cameraDTO.getIp()); } else { cameraFlow.setCameraIpc(cameraDTO.getIpcAddress()); } cameraFlow.setTasker(tasker); cameraFlow.setFlowType(FlowUtils.FlowType.HIK.ordinal()); cameraFlow.setRtsp("rtsp://" + rtspName); cameraFlow.setRtmp(rtmpUrl); cameraFlow.setFlv(flvUrl); cameraFlow.setClient(1); cameraFlow.setCreateTime(new Date()); cameraFlow.setUpdateTime(new Date()); flowService.save(cameraFlow); } else { resultDTO.setMsg("推流失败"); return resultDTO; } } return resultDTO; } else { resultDTO.setMsg("未找到设备"); return resultDTO; } } /** * 回放推流 * @param cameraDTO 相机信息 * @return ResultDTO */ public ResultDTO startBackTranscode(CameraDTO cameraDTO) { ResultDTO resultDTO = new ResultDTO(); if (cameraDTO != null) { String startTime,endTime; DateTimeFormatter sdf = DateTimeFormatter.ofPattern("yyyyMMdd't'HHmmss'z'"); if (cameraDTO.getHistoryDTO().getEndTime() != null) { startTime = sdf.format(cameraDTO.getHistoryDTO().getStartTime()); endTime = sdf.format(cameraDTO.getHistoryDTO().getEndTime()); } else { startTime = sdf.format(cameraDTO.getHistoryDTO().getStartTime()); endTime = null; } String appName; int channelNumber; if (cameraDTO.getType() == 0) { //摄像机 appName = "history" + cameraDTO.getAccount() + cameraDTO.getIp().replace(".", "") + "start" + startTime + "end" + endTime; channelNumber = HikCameraUtils.analyzeChannel(cameraDTO.getChannelList().get(0)); } else { //NVR appName = "history" + cameraDTO.getAccount() + cameraDTO.getIp().replace(".", "") + "to" + cameraDTO.getIpcAddress().replace(".", "") + "start" + startTime + "end" + endTime; channelNumber = HikCameraUtils.getIpcChannel(cameraDTO.getChannelList(), cameraDTO.getIpcAddress()); } if (channelNumber == -1) { logger.info("历史流-未搜索到ip:" + cameraDTO.getIp() + ", ipc:" + cameraDTO.getIpcAddress() + " 的设备"); } String rtmpUrl = "rtmp://"+ rtmpServer + "/live/" + appName; //rtmp链 String flvUrl = "http://" + httpServer + "/live/" + appName + ".flv"; //http-flv链 boolean runFlag = ffmpegService.taskerIsRun(appName); CameraFlow cameraFlow = flowService.findByRtmpUrl(rtmpUrl); if (cameraFlow != null && !runFlag) { flowService.removeById(cameraFlow.getId()); } if (runFlag) { //已推流 if (cameraFlow != null) { resultDTO.setTasker(appName); resultDTO.setMsg(HikCameraUtils.resultNames[0]); resultDTO.setRtmpUrl(rtmpUrl); resultDTO.setFlvUrl(flvUrl); cameraFlow.setClient(cameraFlow.getClient() + 1); flowService.updateById(cameraFlow); } else { //停止推流 flowService.stopByTasker(appName); resultDTO.setMsg("推流失败"); return resultDTO; } } else { //未推流 String channelNumberStr = channelNumber + "01"; //回放流只有主码流 String rtspName; if (endTime != null) { rtspName = cameraDTO.getAccount() + ":" + cameraDTO.getPassword() + "@" + cameraDTO.getIp() + ":554/Streaming/tracks/" + channelNumberStr + "?starttime=" + startTime + "&endtime=" + endTime; } else { rtspName = cameraDTO.getAccount() + ":" + cameraDTO.getPassword() + "@" + cameraDTO.getIp() + ":554/Streaming/tracks/" + channelNumberStr + "?starttime=" + startTime; } String rtmpName = rtmpServer + "/live/"; //rtmp服务器推流入口 String tasker= ffmpegService.startTranscoding(appName,rtspName,rtmpName); if (StringUtils.isNotEmpty(tasker)) { resultDTO.setTasker(tasker); resultDTO.setMsg(HikCameraUtils.resultNames[0]); resultDTO.setRtmpUrl(rtmpUrl); resultDTO.setFlvUrl(flvUrl); //添加流记录 cameraFlow = new CameraFlow(); cameraFlow.setCameraId(cameraDTO.getCameraId()); if (cameraDTO.getType() == 0) { cameraFlow.setCameraIpc(cameraDTO.getIp()); } else { cameraFlow.setCameraIpc(cameraDTO.getIpcAddress()); } cameraFlow.setTasker(tasker); cameraFlow.setFlowType(FlowUtils.FlowType.HIK.ordinal()); cameraFlow.setRtsp("rtsp://" + rtspName); cameraFlow.setRtmp(rtmpUrl); cameraFlow.setFlv(flvUrl); cameraFlow.setClient(1); cameraFlow.setCreateTime(new Date()); cameraFlow.setUpdateTime(new Date()); flowService.save(cameraFlow); } else { resultDTO.setMsg("推流失败"); return resultDTO; } } return resultDTO; } else { resultDTO.setMsg("未找到设备"); return resultDTO; } } /** * 抓图 * @param cameraDTO 相机信息 */ public ResultDTO catchPic(CameraDTO cameraDTO) { ResultDTO resultDTO = new ResultDTO(); if (cameraDTO != null) { String pathName; int channelNumber; if (cameraDTO.getType() == 0) { //摄像机 pathName = cameraDTO.getIp().replace(".", ""); channelNumber = HikCameraUtils.analyzeChannel(cameraDTO.getChannelList().get(0)); } else { //NVR resultDTO.setMsg("NVR设备不支持抓图"); return resultDTO; } HCNetTools hcTool = cameraDTO.getHcTool(); DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); String name = dtf.format(LocalDateTime.now()) + ".jpg"; String path = "/picture/" + pathName + "/"; String filePath = rootPath + path + name; cameraFileService.pathCreator(rootPath + path); boolean success = hcTool.getDVRPic(channelNumber,filePath); if (success) { long size = new File(filePath).length(); CameraFile cameraFile = cameraFileService.saveFileInfo(name,path,size); resultDTO.setMsg(cameraFile.getId().toString()); } return resultDTO; } else { resultDTO.setMsg("未找到设备"); return resultDTO; } } /** * 视频回放下载 * @param cameraDTO */ public ResultDTO downloadBack(CameraDTO cameraDTO) { ResultDTO resultDTO = new ResultDTO(); if (cameraDTO != null) { String pathName; int channelNumber; if (cameraDTO.getType() == 0) { //摄像机 pathName = cameraDTO.getIp().replace(".", ""); channelNumber = HikCameraUtils.analyzeChannel(cameraDTO.getChannelList().get(0)); } else { //NVR pathName = cameraDTO.getIpcAddress().replace(".", ""); channelNumber = HikCameraUtils.getIpcChannel(cameraDTO.getChannelList(), cameraDTO.getIpcAddress()); channelNumber = channelNumber + 32; //远程下载的通道号从32开始 } DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); String name = dtf.format(cameraDTO.getHistoryDTO().getStartTime()) + "TO" + dtf.format(cameraDTO.getHistoryDTO().getEndTime()) + ".mp4"; String path = "/video/" + pathName + "/"; cameraFileService.pathCreator(rootPath + path); Integer fileId = cameraFileService.findByPathAndName(path,name); if (fileId > 0) { resultDTO.setMsg(fileId.toString()); return resultDTO; } hikCameraManager.downloadVideoAsync(cameraDTO,path,name,channelNumber); resultDTO.setMsg("Async"); return resultDTO; } else { resultDTO.setMsg("未找到设备"); return resultDTO; } } /** * 获取视频列表 * @param cameraDTO * @return */ public ResultDTO getVideoFileList(CameraDTO cameraDTO) { ResultDTO resultDTO = new ResultDTO(); if (cameraDTO != null) { int channelNumber; if (cameraDTO.getType() == 0) { //摄像机 channelNumber = HikCameraUtils.analyzeChannel(cameraDTO.getChannelList().get(0)); } else { //NVR channelNumber = HikCameraUtils.getIpcChannel(cameraDTO.getChannelList(), cameraDTO.getIpcAddress()); channelNumber = channelNumber + 32; //远程录像的通道号从33开始 } HCNetTools hcTool = cameraDTO.getHcTool(); List> map = hcTool.getVideoFileList(cameraDTO.getHistoryDTO().getStartTime(),cameraDTO.getHistoryDTO().getEndTime(),channelNumber); resultDTO.setMsg(map); return resultDTO; } else { resultDTO.setMsg("未找到设备"); return resultDTO; } } /** * 云台控制 * @param cameraDTO 相机信息 */ public ResultDTO playControl(CameraDTO cameraDTO) { ResultDTO resultDTO = new ResultDTO(); if (cameraDTO != null) { int channelNumber; if (cameraDTO.getType() == 0) { //摄像机 channelNumber = HikCameraUtils.analyzeChannel(cameraDTO.getChannelList().get(0)); } else { //NVR resultDTO.setMsg("NVR设备不支持云台控制"); return resultDTO; } hikCameraManager.playControlAsync(cameraDTO,channelNumber); resultDTO.setMsg("Async"); return resultDTO; } else { resultDTO.setMsg("未找到设备"); return resultDTO; } } /** * 停止推流 * @param id 相机id */ public Boolean stopRtmp(Integer id) { if (id == null) { return true; } Camera camera = deviceService.getById(id); if (camera != null) { String appName = camera.getAccount() + camera.getIp().replace(".",""); return ffmpegService.stopTranscoding(appName); } else { return true; } } }