ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/CarController.java
@@ -52,14 +52,23 @@ @RequestMapping("/car") public class CarController { @Value("${live.output.path}") private String outputPath; @Value("${live.hls.output-path}") private String hlsOutputPath; @Value("${live.ip}") private String liveIp; @Value("${live.hls.ip}") private String hlsIp; @Value("${live.port}") private Integer livePort; @Value("${live.hls.port}") private Integer hlsPort; @Value("${live.flv.ip}") private String flvIp; @Value("${live.flv.rtmp-port}") private Integer flvRtmpPort; @Value("${live.flv.http-port}") private Integer flvHttpPort; @Resource private ICarService carService; @Resource @@ -122,32 +131,17 @@ Enterprise enterprise = enterpriseService.getById(car.getEnterpriseId()); R<UPRealvideoMsgStartupAckVo> msgStartupAckVoR = realVideoMsgClient.startupRealVideo(Integer.valueOf(enterprise.getCode()), car.getVehicleNumber()); if (200 == msgStartupAckVoR.getCode()) { String path = outputPath + "hls\\" + car.getVehicleNumber() + "\\live.m3u8"; String folderPath = outputPath + "hls\\" + car.getVehicleNumber(); FileUtil.mkParentDirs(path); File file = new File(path); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { throw new RuntimeException(e); } } UPRealvideoMsgStartupAckVo data = msgStartupAckVoR.getData(); RealVideoResp resp = new RealVideoResp(); //执行拉流和推流 ExecutorService executorService = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); executorService.execute(new Runnable() { @Override public void run() { JavaCVStreamUtil.push_hls(data.getUrl(), path, id, folderPath); } }); resp.setServerIp(liveIp); resp.setServerPort(livePort); // live_hls(data.getUrl(), car); // resp.setServerIp(hlsIp); // resp.setServerPort(hlsPort); live_flv(data.getUrl(), car.getId()); resp.setServerIp(flvIp); resp.setServerPort(flvHttpPort); return R.ok(resp); } @@ -165,7 +159,7 @@ if (null == car) { return R.fail("失败"); } String folderPath = outputPath + "hls\\" + car.getVehicleNumber(); String folderPath = hlsOutputPath + "hls\\" + car.getVehicleNumber(); JavaCVStreamUtil.close(id, folderPath); return R.ok(); } @@ -197,30 +191,14 @@ if (200 == startupAckVoR.getCode()) { UPPlaybackMsgStartupAckVo data = startupAckVoR.getData(); RealVideoResp resp = new RealVideoResp(); String path = outputPath + "hls\\" + car.getVehicleNumber() + "\\live.m3u8"; String folderPath = outputPath + "hls\\" + car.getVehicleNumber(); FileUtil.mkParentDirs(path); File file = new File(path); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { throw new RuntimeException(e); } } //执行拉流和推流 ExecutorService executorService = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); executorService.execute(new Runnable() { @Override public void run() { JavaCVStreamUtil.push_hls(data.getUrl(), path, req.getId(), folderPath); } }); resp.setServerIp(liveIp); resp.setServerPort(livePort); // live_hls(data.getUrl(), car); // resp.setServerIp(hlsIp); // resp.setServerPort(hlsPort); live_flv(data.getUrl(), car.getId()); resp.setServerIp(flvIp); resp.setServerPort(flvHttpPort); return R.ok(resp); } return R.fail(startupAckVoR.getMsg()); @@ -313,4 +291,46 @@ } return R.ok(list); } public void live_hls(String input, Car car){ String path = hlsOutputPath + "hls\\" + car.getVehicleNumber() + "\\live.m3u8"; String folderPath = hlsOutputPath + "hls\\" + car.getVehicleNumber(); FileUtil.mkParentDirs(path); File file = new File(path); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { throw new RuntimeException(e); } } //执行拉流和推流 ExecutorService executorService = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); executorService.execute(new Runnable() { @Override public void run() { JavaCVStreamUtil.push_hls(input, path, car.getId(), folderPath); } }); carService.taskPlayDetection(car.getId()); } public void live_flv(String input, Integer id){ String url = "rtmp://" + flvIp + ":" + flvRtmpPort + "/flv/" + id; //执行拉流和推流 ExecutorService executorService = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); executorService.execute(new Runnable() { @Override public void run() { JavaCVStreamUtil.push_flv(input, url, id); } }); // carService.taskPlayDetection(id); } } ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/OrderController.java
@@ -75,14 +75,23 @@ @Resource private RedisTemplate redisTemplate; @Value("${live.output.path}") private String outputPath; @Value("${live.hls.output-path}") private String hlsOutputPath; @Value("${live.ip}") private String liveIp; @Value("${live.hls.ip}") private String hlsIp; @Value("${live.port}") private Integer livePort; @Value("${live.hls.port}") private Integer hlsPort; @Value("${live.flv.ip}") private String flvIp; @Value("${live.flv.rtmp-port}") private Integer flvRtmpPort; @Value("${live.flv.http-port}") private Integer flvHttpPort; @GetMapping("/getOrderList") @@ -187,8 +196,23 @@ if (200 == startupAckVoR.getCode()) { UPPlaybackMsgStartupAckVo data = startupAckVoR.getData(); RealVideoResp resp = new RealVideoResp(); String path = outputPath + "hls\\" + car.getVehicleNumber() + "\\live.m3u8"; String folderPath = outputPath + "hls\\" + car.getVehicleNumber(); //执行拉流和推流 // live_hls(data.getUrl(), car); // resp.setServerIp(hlsIp); // resp.setServerPort(hlsPort); live_flv(data.getUrl(), car.getId()); resp.setServerIp(flvIp); resp.setServerPort(flvHttpPort); return R.ok(resp); } return R.fail(startupAckVoR.getMsg()); } public void live_hls(String input, Car car){ String path = hlsOutputPath + "hls\\" + car.getVehicleNumber() + "\\live.m3u8"; String folderPath = hlsOutputPath + "hls\\" + car.getVehicleNumber(); FileUtil.mkParentDirs(path); File file = new File(path); if (!file.exists()) { @@ -206,13 +230,24 @@ executorService.execute(new Runnable() { @Override public void run() { JavaCVStreamUtil.push_hls(data.getUrl(), path, id, folderPath); JavaCVStreamUtil.push_hls(input, path, car.getId(), folderPath); } }); resp.setServerIp(liveIp); resp.setServerPort(livePort); return R.ok(resp); carService.taskPlayDetection(car.getId()); } return R.fail(startupAckVoR.getMsg()); public void live_flv(String input, Integer id){ String url = "rtsp://" + flvIp + ":" + flvRtmpPort + "/flv/" + id; //执行拉流和推流 ExecutorService executorService = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); executorService.execute(new Runnable() { @Override public void run() { JavaCVStreamUtil.push_flv(input, url, id); } }); carService.taskPlayDetection(id); } } ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ICarService.java
@@ -37,5 +37,5 @@ * 检测视频播放,清除没有播放的视频流 * @return */ void taskPlayDetection(); void taskPlayDetection(Integer deviceNumber); } ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CarServiceImpl.java
@@ -31,6 +31,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * @author zhibing.pu @@ -39,8 +42,8 @@ @Service public class CarServiceImpl extends ServiceImpl<CarMapper, Car> implements ICarService { @Value("${live.output.path}") private String outputPath; @Value("${live.hls.output-path}") private String hlsOutputPath; @Resource private UPExgMsgRegisterClient upExgMsgRegisterClient; @@ -162,13 +165,20 @@ * 检测视频播放,清除没有播放的视频流 */ @Override public void taskPlayDetection() { List<Car> list = this.list(); for (Car car : list) { public void taskPlayDetection(Integer deviceNumber) { Car car = this.getById(deviceNumber); try { ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); executorService.scheduleWithFixedDelay(new Runnable() { @Override public void run() { if(!redisTemplate.hasKey("live:" + car.getId())){ String folderPath = outputPath + "hls\\" + car.getVehicleNumber(); String folderPath = hlsOutputPath + "hls\\" + car.getVehicleNumber(); JavaCVStreamUtil.close(car.getId(), folderPath); } }}, 1, 1, TimeUnit.MINUTES); }catch (Exception e){ e.printStackTrace(); } } ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/util/JavaCVStreamUtil.java
@@ -2,19 +2,25 @@ import cn.hutool.core.io.FileUtil; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.system.service.ICarService; import org.bytedeco.ffmpeg.global.avcodec; import org.bytedeco.ffmpeg.global.avutil; import org.bytedeco.javacv.*; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * 音视频推流拉流工具类 * 参考资料:https://juejin.cn/post/7311230172237561866 * * @author zhibing.pu * @Date 2025/4/8 16:03 */ @Component public class JavaCVStreamUtil { private static Map<Integer, FFmpegFrameGrabber> grabberMap = new ConcurrentHashMap<>(); @@ -25,6 +31,11 @@ private static Map<Integer, Boolean> statusMap = new ConcurrentHashMap<>(); @Resource private RedisTemplate redisTemplate; @Resource private ICarService carService; /** @@ -42,7 +53,8 @@ } OpenCVFrameGrabber openCVFrameGrabber = grabberMap1.get(deviceNumber); if(null != openCVFrameGrabber){ openCVFrameGrabber.close();; openCVFrameGrabber.close(); ; } FFmpegFrameRecorder fFmpegFrameRecorder = frameRecorderMap.get(deviceNumber); if(null != fFmpegFrameRecorder){ @@ -123,7 +135,8 @@ } OpenCVFrameGrabber openCVFrameGrabber = grabberMap1.get(deviceNumber); if(null != openCVFrameGrabber){ openCVFrameGrabber.close();; openCVFrameGrabber.close(); ; } FFmpegFrameRecorder fFmpegFrameRecorder = frameRecorderMap.get(deviceNumber); if(null != fFmpegFrameRecorder){ @@ -208,6 +221,7 @@ /** * 关闭推流和拉流进程 * * @param deviceNumber */ public static void close(Integer deviceNumber, String folderPath){ @@ -223,17 +237,14 @@ try { fFmpegFrameGrabber = grabberMap.get(deviceNumber); if(null != fFmpegFrameGrabber){ fFmpegFrameGrabber.flush(); fFmpegFrameGrabber.close(); } openCVFrameGrabber = grabberMap1.get(deviceNumber); if(null != openCVFrameGrabber){ openCVFrameGrabber.flush(); openCVFrameGrabber.close(); } fFmpegFrameRecorder = frameRecorderMap.get(deviceNumber); if(null != fFmpegFrameRecorder){ fFmpegFrameRecorder.flush(); fFmpegFrameRecorder.close(); } }catch (Exception e){ @@ -244,4 +255,6 @@ FileUtil.del(folderPath); } } } ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/util/TaskUtil.java
@@ -81,14 +81,4 @@ public void taskUpdateCarStatus() { carService.taskUpdateCarStatus(); } /** * 视频播放检测 */ @Scheduled(fixedRate = 1000 * 300) public void taskPlayDetection() { carService.taskPlayDetection(); } }