From b973eb0a7edc6507347f6fd82f961e7498ff5bbc Mon Sep 17 00:00:00 2001 From: 86156 <823267011@qq.com> Date: Sun, 28 Sep 2025 12:01:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thread/MediaTransferFlvByJavacv.java | 212 +++++++----------- 1 file changed, 83 insertions(+), 129 deletions(-) diff --git a/ruoyi-video/src/main/java/com/ruoyi/video/thread/MediaTransferFlvByJavacv.java b/ruoyi-video/src/main/java/com/ruoyi/video/thread/MediaTransferFlvByJavacv.java index fa00c34..53c580c 100644 --- a/ruoyi-video/src/main/java/com/ruoyi/video/thread/MediaTransferFlvByJavacv.java +++ b/ruoyi-video/src/main/java/com/ruoyi/video/thread/MediaTransferFlvByJavacv.java @@ -345,7 +345,6 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable if (enableDetection) initDetectors(); } catch (Exception e) { log.error("初始化检测模型失败:{}", e.getMessage(), e); - // 模型失败不影响推流,但不禁用检测 } if (!createGrabber()) return; @@ -369,15 +368,10 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable long lastDetectionTime = 0; List currentDetections = Collections.emptyList(); // 当前显示的检测结果 - // 检测计数器和性能统计 - int totalDetections = 0; - int successfulDetections = 0; - long totalDetectionTime = 0; - for (; running && grabberStatus && recorderStatus; ) { try { if (transferFlag) { - // 仅转复用(未叠框)- 这部分代码保持不变 + // 仅转复用(未叠框) long startGrab = System.currentTimeMillis(); AVPacket pkt = grabber.grabPacket(); if ((System.currentTimeMillis() - startGrab) > 5000) { @@ -392,17 +386,9 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable recorder.recordPacket(pkt); } } else { - // 转码(可叠框)- 优化这部分以避免栈溢出 + // 转码(可叠框) long startGrab = System.currentTimeMillis(); - Frame frame = null; - - try { - // 直接获取帧,不进行复杂处理 - frame = grabber.grab(); - } catch (Exception e) { - log.error("获取帧异常: {}", e.getMessage()); - continue; // 跳过这一帧 - } + Frame frame = grabber.grab(); if ((System.currentTimeMillis() - startGrab) > 5000) { log.info("{} 网络异常(转码)", cameraDto.getUrl()); @@ -410,128 +396,96 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable break; } - // 如果启用了检测且获取到了有效帧 if (frame != null && enableDetection) { - // 控制检测频率 - long currentTime = System.currentTimeMillis(); - boolean shouldDetect = (currentTime - lastDetectionTime >= DETECTION_INTERVAL_MS); + // 将Frame转换为Mat以进行处理 + Mat mat = toMat.convert(frame); - if (shouldDetect) { - // 每隔一段时间进行一次检测 - try { - // 安全转换为Mat - Mat detectionMat = null; + if (mat != null && !mat.empty()) { + long currentTime = System.currentTimeMillis(); + + // 每隔DETECTION_INTERVAL_MS执行一次检测 + if (currentTime - lastDetectionTime >= DETECTION_INTERVAL_MS) { try { - detectionMat = toMat.convert(frame); - } catch (Exception e) { - log.debug("帧转换异常: {}", e.getMessage()); - continue; // 跳过这一帧 - } - - if (detectionMat != null && !detectionMat.empty()) { + log.debug("执行新一轮检测,上次检测时间: {}ms前", + currentTime - lastDetectionTime); + + // 创建副本进行检测 + Mat detectionMat = new Mat(); + mat.copyTo(detectionMat); + // 执行检测 - try { - // 打印检测开始信息 - log.info("===== 开始执行检测 [{}] =====", new java.text.SimpleDateFormat("HH:mm:ss.SSS").format(new java.util.Date())); - totalDetections++; - - // 记录检测开始时间 - long detectionStartTime = System.currentTimeMillis(); - - // 执行检测 - currentDetections = detector.detect(detectionMat); - - // 计算检测耗时 - long detectionTime = System.currentTimeMillis() - detectionStartTime; - totalDetectionTime += detectionTime; - successfulDetections++; - - // 更新最后检测时间 - lastDetectionTime = currentTime; - latestDetections.set(currentDetections); - - // 打印检测结果 - StringBuilder detectionInfo = new StringBuilder(); - detectionInfo.append("\n===== 检测结果 =====\n"); - detectionInfo.append("检测耗时: ").append(detectionTime).append("ms\n"); - detectionInfo.append("检测目标数: ").append(currentDetections == null ? 0 : currentDetections.size()).append("\n"); - - if (currentDetections != null && !currentDetections.isEmpty()) { - detectionInfo.append("检测到的目标:\n"); - for (int i = 0; i < currentDetections.size(); i++) { - Detection det = currentDetections.get(i); - detectionInfo.append(" ").append(i+1).append(". "); - detectionInfo.append("类型: ").append(det.cls()); - detectionInfo.append(", 置信度: ").append(String.format("%.2f", det.conf())); - } - } else { - detectionInfo.append("未检测到目标\n"); - } - - // 打印检测统计 - detectionInfo.append("\n检测统计:\n"); - detectionInfo.append("总检测次数: ").append(totalDetections).append("\n"); - detectionInfo.append("成功检测次数: ").append(successfulDetections).append("\n"); - detectionInfo.append("平均检测时间: ").append(successfulDetections > 0 ? (totalDetectionTime / successfulDetections) : 0).append("ms\n"); - detectionInfo.append("===== 检测结束 =====\n"); - - log.info(detectionInfo.toString()); - - // 窗口巡检回调 - if (windowMode && detectionListener != null && - currentJobId != null && currentDeviceId != null) { - try { - detectionListener.onDetections(currentJobId, - currentDeviceId, - currentDetections, - currentTime); - } catch (Exception ignore) {} - } - } catch (Exception e) { - log.error("检测异常: {}", e.getMessage(), e); - } finally { - // 确保释放Mat - try { - if (detectionMat != null && !detectionMat.isNull()) - detectionMat.release(); - } catch (Exception ignore) {} + currentDetections = detector.detect(detectionMat); + lastDetectionTime = currentTime; + latestDetections.set(currentDetections); + + // 释放检测Mat + detectionMat.release(); + + // 窗口巡检回调 + if (windowMode && detectionListener != null && + currentJobId != null && currentDeviceId != null) { + detectionListener.onDetections(currentJobId, + currentDeviceId, + currentDetections, + currentTime); } + + log.debug("检测完成,发现 {} 个目标,框将保持3秒", + currentDetections == null ? 0 : currentDetections.size()); + } catch (Exception e) { + log.debug("检测异常: {}", e.getMessage()); + } + } + + // 每一帧都使用最新的检测结果绘制框 + // 这样框会保持在原位置,直到下一次检测更新 + if (currentDetections != null && !currentDetections.isEmpty()) { + try { + // 在当前帧上绘制检测框 + Overlay.draw(currentDetections, mat); + } catch (Exception e) { + log.debug("绘制检测框异常: {}", e.getMessage()); + } + } + + // 更新"最近叠好框的帧"用于存证 + updateLatestAnnotated(mat); + + // 统计(仅窗口巡检时) + if (windowMode) updateStats(currentDetections); + + // 窗口结束判定 + if (windowMode && System.currentTimeMillis() >= windowEndMs) { + finishWindow(); + } + + // 将处理后的Mat转换回Frame + try { + // 创建新的转换器 + OpenCVFrameConverter.ToMat converter = new OpenCVFrameConverter.ToMat(); + Frame processedFrame = converter.convert(mat); + + if (processedFrame != null) { + // 使用处理后的帧替换原始帧 + frame = processedFrame; } } catch (Exception e) { - log.error("检测流程异常: {}", e.getMessage(), e); + log.debug("Mat转Frame异常: {}", e.getMessage()); + // 如果转换失败,继续使用原始帧 } - } - - // 不再尝试将检测结果叠加到当前帧上 - // 而是在UI层面处理叠加,这样可以避免复杂的帧处理和转换 - // 或者使用更简单的方式叠加 - - // 统计(仅窗口巡检时) - if (windowMode) { - try { - updateStats(currentDetections); - } catch (Exception ignore) {} - } - - // 窗口结束判定 - if (windowMode && System.currentTimeMillis() >= windowEndMs) { - try { - finishWindow(); - } catch (Exception ignore) {} + + // 释放Mat + mat.release(); } } - // 直接使用原始帧,避免复杂的转换 + // 记录帧 if (frame != null) { - try { - long now = System.currentTimeMillis(); - if (startTime == 0) startTime = now; - videoTS = 1000 * (now - startTime); - if (videoTS > recorder.getTimestamp()) recorder.setTimestamp(videoTS); - recorder.record(frame); - } catch (Exception e) { - log.error("记录帧异常: {}", e.getMessage()); - } + long now = System.currentTimeMillis(); + if (startTime == 0) startTime = now; + videoTS = 1000 * (now - startTime); + if (videoTS > recorder.getTimestamp()) recorder.setTimestamp(videoTS); + recorder.record(frame); } } } catch (FrameGrabber.Exception e) { @@ -546,7 +500,7 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable log.error("其他异常: {}", e.getMessage()); // 不要立即退出,尝试继续处理 try { - Thread.sleep(100); // 短暂暂停 + Thread.sleep(100); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } @@ -568,7 +522,7 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable safeCloseResources(); } - // 将资源关闭逻辑提取到单独的方法,避免嵌套太深 + // 将资源关闭逻辑提取到单独的方法 private void safeCloseResources() { try { if (detector != null) {