From 0dcba4fd1cb536ab426622e31213d8a0194449ff Mon Sep 17 00:00:00 2001
From: puzhibing <393733352@qq.com>
Date: 星期五, 25 四月 2025 14:12:30 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/util/JavaCVStreamUtil.java |  132 +++++++++++++++++++++++++------------------
 1 files changed, 77 insertions(+), 55 deletions(-)

diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/util/JavaCVStreamUtil.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/util/JavaCVStreamUtil.java
index 1ad357d..0b80278 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/util/JavaCVStreamUtil.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/util/JavaCVStreamUtil.java
@@ -1,8 +1,11 @@
 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.*;
+import org.springframework.stereotype.Component;
 
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -10,34 +13,49 @@
 /**
  * 音视频推流拉流工具类
  * 参考资料: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<>();
+	
+	private static Map<Integer, OpenCVFrameGrabber> grabberMap1 = new ConcurrentHashMap<>();
 	
 	private static Map<Integer, FFmpegFrameRecorder> frameRecorderMap = new ConcurrentHashMap<>();
 	
 	private static Map<Integer, Boolean> statusMap = new ConcurrentHashMap<>();
 	
 	
+	public static void main(String[] args) {
+		String url = "rtmp://127.0.0.1:1935/flv/test";
+		JavaCVStreamUtil.push_flv("C:\\Users\\39373\\Desktop\\图片\\trailer.mp4", url, 0);
+	}
+	
+	
+	
 	
 	/**
 	 * 视频拉流和推流
 	 */
-	public static void push_flv(String inputUrl, String outputUrl, Integer deviceNumber){
+	public static void push_flv(String inputUrl, String outputUrl, Integer deviceNumber) {
 //		OpenCVFrameGrabber grabber = null;
 		FFmpegFrameGrabber grabber = null;
 		FFmpegFrameRecorder recorder = null;
 		try {
 			//关闭上一个没有正确关闭的流
 			FFmpegFrameGrabber fFmpegFrameGrabber = grabberMap.get(deviceNumber);
-			if(null != fFmpegFrameGrabber){
+			if (null != fFmpegFrameGrabber) {
 				fFmpegFrameGrabber.close();
 			}
+			OpenCVFrameGrabber openCVFrameGrabber = grabberMap1.get(deviceNumber);
+			if (null != openCVFrameGrabber) {
+				openCVFrameGrabber.close();
+			}
 			FFmpegFrameRecorder fFmpegFrameRecorder = frameRecorderMap.get(deviceNumber);
-			if(null != fFmpegFrameRecorder){
+			if (null != fFmpegFrameRecorder) {
 				fFmpegFrameRecorder.close();
 			}
 			
@@ -52,50 +70,52 @@
 			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());
 			recorder.setFormat("flv");
 			// 设置视频比特率
 			recorder.setVideoBitrate(grabber.getVideoBitrate());
-//			// 设置帧率
-//			recorder.setFrameRate(grabber.getVideoFrameRate());
-//			// 设置关键帧间隔
-//			recorder.setGopSize((int) grabber.getVideoFrameRate());
+			// 设置帧率
+			recorder.setFrameRate(grabber.getVideoFrameRate());
+			// 设置关键帧间隔
+			recorder.setGopSize((int) grabber.getVideoFrameRate());
 			// CRF 是一种用于控制视频/音频质量的参数,它允许在保持目标质量的同时动态地调整比特率。较低的CRF值表示更高的质量,但也可能导致较大的文件大小
 			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;
+				}
+				Thread.sleep(500);
 			}
 		} 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();
-			}
+		} catch (InterruptedException e) {
+			throw new RuntimeException(e);
+		} finally {
+			close(deviceNumber, null);
 		}
 	}
 	
@@ -103,7 +123,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;
@@ -111,11 +131,16 @@
 		try {
 			//关闭上一个没有正确关闭的流
 			FFmpegFrameGrabber fFmpegFrameGrabber = grabberMap.get(deviceNumber);
-			if(null != fFmpegFrameGrabber){
+			if (null != fFmpegFrameGrabber) {
 				fFmpegFrameGrabber.close();
 			}
+			OpenCVFrameGrabber openCVFrameGrabber = grabberMap1.get(deviceNumber);
+			if (null != openCVFrameGrabber) {
+				openCVFrameGrabber.close();
+				;
+			}
 			FFmpegFrameRecorder fFmpegFrameRecorder = frameRecorderMap.get(deviceNumber);
-			if(null != fFmpegFrameRecorder){
+			if (null != fFmpegFrameRecorder) {
 				fFmpegFrameRecorder.close();
 			}
 			
@@ -133,6 +158,7 @@
 			
 			grabber = new OpenCVFrameGrabber(0);
 			grabber.start();
+			grabberMap1.put(deviceNumber, grabber);
 			
 			//录制视频,推送到流媒体服务器(nginx)
 			recorder = new FFmpegFrameRecorder(outputUrl, grabber.getImageWidth(), grabber.getImageHeight());
@@ -182,61 +208,57 @@
 			while ((frame = grabber.grab()) != null) {
 				recorder.record(frame);
 				//判断状态为停止,则结束此线程任务
-				if(!statusMap.get(deviceNumber)){
+				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();
-			}
+		} finally {
+			close(deviceNumber, folderPath);
 		}
 	}
 	
 	
 	/**
 	 * 关闭推流和拉流进程
+	 *
 	 * @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){
+			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){
+			if (null != fFmpegFrameRecorder) {
+				fFmpegFrameRecorder.flush();
 				fFmpegFrameRecorder.close();
 			}
-		}catch (Exception e){
+		} 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);
 		}
 	}
+	
+	
 }

--
Gitblit v1.7.1