From fed7dea24aa6bc2978c660d3f8e28a67979bf6f2 Mon Sep 17 00:00:00 2001 From: 4670101279 Date: Thu, 15 Sep 2022 09:23:59 +0800 Subject: [PATCH] youhua --- .../com/ruoyi/api/app/TestApiController.java | 19 ++ .../camera/controller/CameraController.java | 27 +- .../code/camera/scheduled/RegisterServer.java | 1 + .../src/main/java/utils/RegisterUtil.java | 19 +- .../src/main/java/utils/RtspConvert.java | 300 ++++++++++++++++++ ruoyi-common/pom.xml | 6 + .../java/com/ruoyi/quartz/task/RyTask.java | 10 + 7 files changed, 373 insertions(+), 9 deletions(-) create mode 100644 ruoyi-code/src/main/java/utils/RtspConvert.java diff --git a/ruoyi-api/src/main/java/com/ruoyi/api/app/TestApiController.java b/ruoyi-api/src/main/java/com/ruoyi/api/app/TestApiController.java index c199c3a..4e1e436 100644 --- a/ruoyi-api/src/main/java/com/ruoyi/api/app/TestApiController.java +++ b/ruoyi-api/src/main/java/com/ruoyi/api/app/TestApiController.java @@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import utils.RtspConvert; @RestController @@ -16,4 +17,22 @@ public class TestApiController { return R.ok(); } + + @RequestMapping("/openPullM3u8") + public R openPullM3u8(){ + RtspConvert convert = new RtspConvert(); + String ip = "192.168.1.40"; + String userName = "admin"; + String pwd = "admin123"; + String m3u8 = convert.rtsp2Hls(ip, userName, pwd); + System.out.println("***********************************" + m3u8); + return R.ok(); + } + + @RequestMapping("/closePullM3u8") + public R closePullM3u8(){ + RtspConvert convert = new RtspConvert(); + convert.closeAllProcess(); + return R.ok(); + } } diff --git a/ruoyi-code/src/main/java/com/ruoyi/code/camera/controller/CameraController.java b/ruoyi-code/src/main/java/com/ruoyi/code/camera/controller/CameraController.java index 2182f91..2e3b5bc 100644 --- a/ruoyi-code/src/main/java/com/ruoyi/code/camera/controller/CameraController.java +++ b/ruoyi-code/src/main/java/com/ruoyi/code/camera/controller/CameraController.java @@ -1,5 +1,6 @@ package com.ruoyi.code.camera.controller; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.ruoyi.code.camera.domain.Camera; import com.ruoyi.code.camera.domain.LogInfo; import com.ruoyi.code.camera.service.ICameraService; @@ -16,10 +17,7 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import sdk.java.lib.netmanager.NetEnums; import sdk.java.lib.netmanager.NetStructs; -import utils.CameraUtil; -import utils.RegisterUtil; -import utils.run_device_cfg; -import utils.run_device_log_search; +import utils.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; @@ -267,4 +265,25 @@ public class CameraController extends BaseController CameraUtil.setNowTime(new NativeLong(Long.parseLong(camera.getLoginId()))); return R.ok(); } + + @RequestMapping("/resetPullRtsp") + public R resetPullRtsp(){ + List list = cameraService.list(new QueryWrapper().eq("status","0").isNotNull("login_id").ne("login","")); + if(list.isEmpty()){ + return R.error("设备未在线"); + } + RtspConvert convert = new RtspConvert(); + convert.closeAllProcess(); + for (Camera camera : list) { + try { + String m3u8 = convert.rtsp2Hls(camera.getIp(), camera.getUsername(), camera.getPassword()); + System.out.println("拉流成功,地址:" + m3u8); + Thread.sleep(2000); + } catch (Exception e) { + logger.error(e.getMessage()); + return R.error("重启失败"); + } + } + return R.ok(); + } } diff --git a/ruoyi-code/src/main/java/com/ruoyi/code/camera/scheduled/RegisterServer.java b/ruoyi-code/src/main/java/com/ruoyi/code/camera/scheduled/RegisterServer.java index 1666421..6455729 100644 --- a/ruoyi-code/src/main/java/com/ruoyi/code/camera/scheduled/RegisterServer.java +++ b/ruoyi-code/src/main/java/com/ruoyi/code/camera/scheduled/RegisterServer.java @@ -47,6 +47,7 @@ public class RegisterServer { private void start(){ String ip = IPUtils.getLocalIpAddress(); + System.out.println(ip); if(sercer_ip.equals(ip)){ R result = cameraService.register(); if("0".equals(result.get("code").toString())){ diff --git a/ruoyi-code/src/main/java/utils/RegisterUtil.java b/ruoyi-code/src/main/java/utils/RegisterUtil.java index baf3c67..1853a7e 100644 --- a/ruoyi-code/src/main/java/utils/RegisterUtil.java +++ b/ruoyi-code/src/main/java/utils/RegisterUtil.java @@ -57,9 +57,10 @@ import java.util.*; ///////////////////////////////////////////////////////////////////////////////////////////////////// @Component public class RegisterUtil implements ActionListener { - + //linux服务器 +// private String m_jtfServerIP = "192.168.1.219"; + //公司windows服务器 private String m_jtfServerIP = "172.16.46.58"; -// private String m_jtfServerIP = "192.168.1.11"; private String m_jtfServerPort = "8020"; private String m_jtfDevUsername = "admin"; private String m_jtfDevPassword = "admin123"; @@ -128,7 +129,11 @@ public class RegisterUtil implements ActionListener { */ public RegisterUtil() { - initialize(); + + String os = System.getProperty("os.name"); + if(os.toLowerCase().startsWith("win")){ + initialize(); + } initilizeRyNetLib(); loginListenThreadController = new LoginListenThreadController(this); } @@ -587,8 +592,12 @@ public class RegisterUtil implements ActionListener { // 用户可以自定义 fDisConnectCB NetLib.instance.Net_Init(_cbDisConnectCallBack, new NativeLong(1)); - NetLib.instance.Net_SetLogFolder("D:\\soft\\control\\TmpAutoReg"); - + String os = System.getProperty("os.name"); + if(os.toLowerCase().startsWith("win")){ + NetLib.instance.Net_SetLogFolder("D:\\soft\\control\\TmpAutoReg"); + }else { + NetLib.instance.Net_SetLogFolder("/usr/local/water-monitor-api/TmpAutoReg"); + } NetLib.instance.Net_SetLogOption(7); // GlobalTool.createDirectory(this.m_strFilePath); diff --git a/ruoyi-code/src/main/java/utils/RtspConvert.java b/ruoyi-code/src/main/java/utils/RtspConvert.java new file mode 100644 index 0000000..37614e2 --- /dev/null +++ b/ruoyi-code/src/main/java/utils/RtspConvert.java @@ -0,0 +1,300 @@ +package utils; + +import cn.hutool.core.util.RuntimeUtil; +import com.alibaba.fastjson.JSON; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.http.HttpUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.PreDestroy; +import java.io.*; +import java.util.Date; +import java.util.concurrent.ConcurrentHashMap; + +/** + * rtsp 转 hlv协议 + * + * @author kzw + */ +@Service +@Slf4j +@EnableScheduling +public class RtspConvert { + //转换map + private static ConcurrentHashMap coverMap = new ConcurrentHashMap<>(); + //拉流命令 + private static final String ffmpegCmd = "ffmpeg -i \"%s\" -c copy -f hls -hls_time 5.0 -hls_list_size 2 -hls_flags 2 %s"; + + //ffmpeg -i "rtsp://admin:admin123@192.168.1.40:554/stream/realtime?channel=1&streamtype=0" -c copy -f hls -hls_time 4.0 -hls_list_size 2 -hls_flags 2 "D:\video\test.m3u8" + @PreDestroy + public void closeProcess() { + log.info("关闭ffmpeg转换进程,java程序不一定关闭process进程"); + closeAllProcess(); + for (String ip : coverMap.keySet()) { + try { + log.error("开始停止{}", ip); + coverMap.get(ip).stopTask(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /** + * ffmpeg -i "rtsp://admin:xxx@192.168.0.251:554/Streaming/Channels/101" -c copy -f hls -hls_time 5.0 -hls_list_size 5 -hls_flags 2 F:\resources\hls\2000\live.m3u8 + */ + /** + * 检查设备ip是否能正常访问 + */ + private boolean checkDeviceOnline(String ip) { + String res = HttpUtils.sendGet("http://" + ip); + if (StringUtils.isNotBlank(res)) { + return true; + } + return false; + } + + /** + * 转换rtsp并获取hls文件路径 + */ + public String rtsp2Hls(String ip, String userName, String pwd) { + System.out.println(JSON.toJSON(coverMap)); + if (coverMap.containsKey(ip)) { + CoverThread thread = coverMap.get(ip); + if (thread == null || thread.getTaskState() != CoverThread.running) { + } else { + return StringUtils.replace(thread.getM3U8File(), RuoYiConfig.getProfile(), ""); + } + } + String rtspUrl = "rtsp://" + userName + ":" + pwd + "@" + ip + ":554/stream/realtime?channel=1&streamtype=0"; + String m3u8File = RuoYiConfig.getProfile() + File.separator + "hls" +// String m3u8File = "D:" + File.separator + "ruoyi" + File.separator + "uploadPath" + File.separator + "hls" + + File.separator + ip.replaceAll("\\.", "_") + File.separator + "live.m3u8"; + startTransform(ip, rtspUrl, m3u8File, userName, pwd); + CoverThread thread = coverMap.get(ip); + if (thread != null) { + return StringUtils.replace(thread.getM3U8File(), RuoYiConfig.getProfile(), ""); + } + return null; + } + + /** + * 开启转换 + */ + private void startTransform(String ip, String rtspUrl, String m3u8Path, String userName, String pwd) { + log.info("转换rtsp, {},{},{}", ip, rtspUrl, m3u8Path); + String memKey = "startLive" + ip; + synchronized (memKey.intern()) { + if (coverMap.containsKey(ip)) { + stopTransform(ip); + } + CoverThread thread = new CoverThread(ip, rtspUrl, m3u8Path, userName, pwd); + coverMap.put(ip, thread); + thread.start(); + } + } + + /** + * 停止转换 + */ + public void stopTransform(String ip) { + String memKey = "startLive" + ip; + synchronized (memKey.intern()) { + System.out.println(JSON.toJSON(coverMap)); + if (coverMap.containsKey(ip)) { + CoverThread thread = coverMap.get(ip); + if (thread != null && thread.getTaskState() != CoverThread.fail) { + System.out.println("停止转换ip"+ip); + thread.stopTask(); + } + } + } + } + + /** + * 监控所有的转换线程 + */ + @Scheduled(cron = "0 0/8 * * * ?") + public synchronized void monitorThreads() { + for (String ip : coverMap.keySet()) { + CoverThread thread = coverMap.get(ip); + if (thread != null && thread.getTaskState() != CoverThread.running) { + //线程出现异常 + rtsp2Hls(ip, thread.getUserName(), thread.getPwd()); + } + } + } + + public void closeAllProcess(){ + String command = "taskkill /f /im ffmpeg.exe"; + if(!isWin()){ + command = "/usr/local/water-monitor-api/closeFFmpeg.sh"; + } + System.out.println("command ["+command+"]"); + String result = RuntimeUtil.execForStr(command); + System.out.println("command result ["+result+"]"); + coverMap.clear(); + } + + public boolean isWin(){ + String os = System.getProperty("os.name"); + return os.toLowerCase().startsWith("win"); + } + + public class RunThread extends Thread { + private InputStream is; + private String printType; + + RunThread(InputStream is, String printType) { + this.is = is; + this.printType = printType; + } + + @Override + public void run() { + try { + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + String line; + while ((line = br.readLine()) != null) { + log.info(printType + ">" + line); + } + } catch (IOException ioe) { + log.info("RunThread error:", ioe); + } + } + } + + /** + * 执行命令线程 + */ + private class CoverThread extends Thread { + private String ip; + private String rtspUrl; + private String m3u8File; + private String userName; + private String pwd; + private int taskState = 0; //运行状态 0未开始 1进行中 -1失败 + private static final int notStart = 0; + private static final int running = 1; + private static final int fail = -1; + private Process process = null; + + CoverThread(String ip, String rtspUrl, String m3u8File, String userName, String pwd) { + this.ip = ip; + this.rtspUrl = rtspUrl; + this.m3u8File = m3u8File; + this.userName = userName; + this.pwd = pwd; + setName("m3u8-" + ip); + this.taskState = notStart; + } + + @Override + public void run() { + try { + FileUtils.forceMkdir(new File(m3u8File).getParentFile()); + if (!checkDeviceOnline(ip)) { + log.warn("设备{},离线", ip); + this.taskState = fail; + return; + } + String command = String.format(ffmpegCmd, rtspUrl, m3u8File); + this.taskState = running; + + //判断是操作系统是linu2x还是windows + String[] comds; + if (isWin()) { + comds = new String[]{"cmd", "/c", command}; +// comds = new String[]{"cmd", "/c", "start", "/b", "cmd.exe", "/k", command}; + } else { + comds = new String[]{"/bin/sh", "-c", command}; + } + + // 开始执行命令 + log.info("执行命令:" + command); + process = Runtime.getRuntime().exec(comds); + + //开启线程监听(此处解决 waitFor() 阻塞/锁死 问题) + new RunThread(process.getInputStream(), "INFO").start(); + new RunThread(process.getErrorStream(), "ERROR").start(); + int flag = process.waitFor(); + log.info("结束{}", ip); + } catch (Exception e) { + log.error("出现异常" + e.getMessage(), e); + this.taskState = fail; + } finally { + if (process != null) { + try { + process.exitValue(); + } catch (Exception e) { + } + try { + process.destroyForcibly(); + } catch (Exception e) { + } + } + } + } + + + + /** + * 获取任务执行状态 + */ + public int getTaskState() { + return taskState; + } + + /** + * 立即停止任务 + */ + public void stopTask() { + if (process != null) { + try { + process.destroy(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public String getM3U8File() { + return this.m3u8File; + } + + public String getUserName() { + return userName; + } + + public String getPwd() { + return pwd; + } + } + + public void openTask(){ + + } + + + + public static void main(String[] args) throws Exception { + RtspConvert convert = new RtspConvert(); + convert.closeAllProcess(); + String ip = "192.168.1.40"; + String userName = "admin"; + String pwd = "admin123"; + String m3u8 = convert.rtsp2Hls(ip, userName, pwd); + System.out.println("***********************************" + m3u8); +// Thread.sleep(10 * 1000); +// convert.stopTransform(ip); +// System.out.println("************************************结束**************"); + } +} diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index e1306d6..a7af7f7 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -149,6 +149,12 @@ bcprov-jdk16 1.46 + + + cn.hutool + hutool-all + 5.0.6 + diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java index a93be98..720c8b1 100644 --- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java +++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java @@ -63,6 +63,16 @@ public class RyTask } } + //定时时间校准 + public void resetCameraTime(){ + ICameraService cameraService = BeanUtil.getBean(ICameraService.class); + List list = cameraService.list(new QueryWrapper().eq("status","1").isNotNull("login_id")); + for (Camera c : list) { + CameraUtil.setNowTime(new NativeLong(Long.parseLong(c.getLoginId()))); + sleep(10); + } + } + //重启注册服务 public void restartServer(){ ICameraService cameraService = BeanUtil.getBean(ICameraService.class);