Pu Zhibing
2025-04-10 0f9ecda1919beb1e8fbbca0f669ac86badf70806
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/util/JavaCVStreamUtil.java
@@ -1,5 +1,7 @@
package com.ruoyi.system.util;
import cn.hutool.core.io.FileUtil;
import com.ruoyi.common.core.utils.StringUtils;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.*;
@@ -17,6 +19,8 @@
   
   private static Map<Integer, FFmpegFrameGrabber> grabberMap = new ConcurrentHashMap<>();
   
   private static Map<Integer, OpenCVFrameGrabber> grabberMap1 = new ConcurrentHashMap<>();
   private static Map<Integer, FFmpegFrameRecorder> frameRecorderMap = new ConcurrentHashMap<>();
   
   private static Map<Integer, Boolean> statusMap = new ConcurrentHashMap<>();
@@ -27,14 +31,18 @@
    * 视频拉流和推流
    */
   public static void push_flv(String inputUrl, String outputUrl, Integer deviceNumber){
//      OpenCVFrameGrabber grabber = null;
      FFmpegFrameGrabber grabber = null;
      OpenCVFrameGrabber grabber = null;
//      FFmpegFrameGrabber grabber = null;
      FFmpegFrameRecorder recorder = null;
      try {
         //关闭上一个没有正确关闭的流
         FFmpegFrameGrabber fFmpegFrameGrabber = grabberMap.get(deviceNumber);
         if(null != fFmpegFrameGrabber){
            fFmpegFrameGrabber.close();
         }
         OpenCVFrameGrabber openCVFrameGrabber = grabberMap1.get(deviceNumber);
         if(null != openCVFrameGrabber){
            openCVFrameGrabber.close();;
         }
         FFmpegFrameRecorder fFmpegFrameRecorder = frameRecorderMap.get(deviceNumber);
         if(null != fFmpegFrameRecorder){
@@ -46,15 +54,16 @@
         FFmpegLogCallback.set();
         
         //视频抓帧
         grabber = new FFmpegFrameGrabber(inputUrl);
         grabber.setOption("rtsp_transport", "tcp");
         // 正确设置超时时间
         grabber.setOption("timeout", "120000");
         grabber.start();
         grabberMap.put(deviceNumber, grabber);
//         grabber = new OpenCVFrameGrabber(0);
//         grabber = new FFmpegFrameGrabber(inputUrl);
//         grabber.setOption("rtsp_transport", "tcp");
//         // 正确设置超时时间
//         grabber.setOption("timeout", "120000");
//         grabber.start();
//         grabberMap.put(deviceNumber, grabber);
         grabber = new OpenCVFrameGrabber(0);
         grabber.start();
         grabberMap1.put(deviceNumber, grabber);
         
         //录制视频,推送到流媒体服务器(nginx)
         recorder = new FFmpegFrameRecorder(outputUrl, grabber.getImageWidth(), grabber.getImageHeight());
@@ -69,33 +78,31 @@
         recorder.setAudioOption("crf", "23");
         
         //设置音频编码为AAC
//         if (grabber.getAudioChannels() > 0) {
         if (grabber.getAudioChannels() > 0) {
            recorder.setAudioChannels(grabber.getAudioChannels());
            recorder.setAudioBitrate(grabber.getAudioBitrate());
            recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
//         }
         }
         recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
         //将解码后的帧记录到输出文件中
         //recorder.start通常用于处理已经解码成图像的视频数据
         recorder.start();
         frameRecorderMap.put(deviceNumber, recorder);
         //设置状态为开始
         statusMap.put(deviceNumber, true);
         Frame frame;
         while ((frame = grabber.grab()) != null) {
            recorder.record(frame);
            //判断状态为停止,则结束此线程任务
            if(!statusMap.get(deviceNumber)){
               break;
            }
         }
      } catch (FrameGrabber.Exception | FrameRecorder.Exception e) {
         e.printStackTrace();
      }finally {
         try {
            statusMap.put(deviceNumber, false);
            if(null != grabber){
               grabber.stop();
            }
            if(null != recorder){
               recorder.stop();
            }
         }catch (Exception e){
            e.printStackTrace();
         }
         close(deviceNumber, null);
      }
   }
   
@@ -103,7 +110,7 @@
   /**
    * 视频拉流和推流
    */
   public static void push_hls(String inputUrl, String outputUrl, Integer deviceNumber){
   public static void push_hls(String inputUrl, String outputUrl, Integer deviceNumber, String folderPath){
      OpenCVFrameGrabber grabber = null;
//      FFmpegFrameGrabber grabber = null;
      FFmpegFrameRecorder recorder = null;
@@ -113,6 +120,10 @@
         FFmpegFrameGrabber fFmpegFrameGrabber = grabberMap.get(deviceNumber);
         if(null != fFmpegFrameGrabber){
            fFmpegFrameGrabber.close();
         }
         OpenCVFrameGrabber openCVFrameGrabber = grabberMap1.get(deviceNumber);
         if(null != openCVFrameGrabber){
            openCVFrameGrabber.close();;
         }
         FFmpegFrameRecorder fFmpegFrameRecorder = frameRecorderMap.get(deviceNumber);
         if(null != fFmpegFrameRecorder){
@@ -133,6 +144,7 @@
         
         grabber = new OpenCVFrameGrabber(0);
         grabber.start();
         grabberMap1.put(deviceNumber, grabber);
         
         //录制视频,推送到流媒体服务器(nginx)
         recorder = new FFmpegFrameRecorder(outputUrl, grabber.getImageWidth(), grabber.getImageHeight());
@@ -189,17 +201,7 @@
      } catch (FrameGrabber.Exception | FrameRecorder.Exception e) {
         e.printStackTrace();
      }finally {
         try {
            statusMap.put(deviceNumber, false);
            if(null != grabber){
               grabber.stop();
            }
            if(null != recorder){
               recorder.stop();
            }
         }catch (Exception e){
            e.printStackTrace();
         }
         close(deviceNumber, folderPath);
      }
   }
   
@@ -208,35 +210,38 @@
    * 关闭推流和拉流进程
    * @param deviceNumber
    */
   public static void close(Integer deviceNumber){
   public static void close(Integer deviceNumber, String folderPath){
      //设置状态为停止
      Boolean status = statusMap.get(deviceNumber);
      if(null == status || !status){
         return;
      }
      statusMap.put(deviceNumber, false);
      FFmpegFrameGrabber fFmpegFrameGrabber = null;
      OpenCVFrameGrabber openCVFrameGrabber = null;
      FFmpegFrameRecorder fFmpegFrameRecorder = null;
      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){
         e.printStackTrace();
      }finally {
         try {
            fFmpegFrameGrabber = grabberMap.get(deviceNumber);
            if(null != fFmpegFrameGrabber){
               fFmpegFrameGrabber.close();
            }
            fFmpegFrameRecorder = frameRecorderMap.get(deviceNumber);
            if(null != fFmpegFrameRecorder){
               fFmpegFrameRecorder.close();
            }
         }catch (Exception e){
            e.printStackTrace();
         }
      }
      //开始清除视频文件
      if(StringUtils.isNotEmpty(folderPath)){
         FileUtil.del(folderPath);
      }
   }
}