Pu Zhibing
2025-04-10 153b905185b40182978758d409accbb76f678cb1
修改视频直播方式为http-flv
6个文件已修改
244 ■■■■■ 已修改文件
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/CarController.java 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/controller/OrderController.java 61 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ICarService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CarServiceImpl.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/util/JavaCVStreamUtil.java 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/util/TaskUtil.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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();
    }
}