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 34d147f..c9ee45e 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 @@ -25,6 +25,7 @@ import org.springframework.util.CollectionUtils; import java.io.ByteArrayOutputStream; import java.net.URL; +import java.nio.ByteBuffer; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -105,6 +106,7 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable // 解码/推理/发送解耦 private final OpenCVFrameConverter.ToMat toMat = new OpenCVFrameConverter.ToMat(); + private final OpenCVFrameConverter.ToMat matToFrameConverter = new OpenCVFrameConverter.ToMat(); private final AtomicReference latestFrame = new AtomicReference<>(); private final AtomicReference> latestDetections = new AtomicReference<>(java.util.Collections.emptyList()); @@ -442,14 +444,16 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable if (enableDetection) { Mat src = latestFrame.get(); - if (src == null || src.empty()) continue; + if (src == null || src.empty()) { + continue; + } // 叠加最近一次检测结果 List dets = latestDetections.get(); if (!CollectionUtils.isEmpty(dets)) { Overlay.draw(dets, src); } - // 更新“最近叠好框的帧”用于存证 + // 更新"最近叠好框的帧"用于存证 updateLatestAnnotated(src); // 统计(仅窗口巡检时) @@ -460,7 +464,27 @@ public class MediaTransferFlvByJavacv extends MediaTransfer implements Runnable finishWindow(); } - frame = toMat.convert(src); + // 完全重新创建Frame,避免使用转换器 + int width = src.cols(); + int height = src.rows(); + int depth = src.depth(); + int channels = src.channels(); + + // 创建新的Frame + frame = new Frame(width, height, Frame.DEPTH_UBYTE, channels); + + // 将Mat数据复制到Frame + ByteBuffer frameBuffer = (ByteBuffer)frame.image[0]; + frameBuffer.clear(); + + // 确保Mat是连续的 + Mat continuous = src.isContinuous() ? src : src.clone(); + byte[] matData = new byte[Math.toIntExact(continuous.total() * continuous.elemSize())]; + continuous.data().get(matData); + + // 复制数据 + frameBuffer.put(matData); + frameBuffer.rewind(); } else { frame = grabber.grab(); } diff --git a/ruoyi-video/src/main/java/com/ruoyi/video/thread/detector/DummyDetector.java b/ruoyi-video/src/main/java/com/ruoyi/video/thread/detector/DummyDetector.java new file mode 100644 index 0000000..7f771b7 --- /dev/null +++ b/ruoyi-video/src/main/java/com/ruoyi/video/thread/detector/DummyDetector.java @@ -0,0 +1,29 @@ +package com.ruoyi.video.thread.detector; + +import com.ruoyi.video.domain.Detection; +import org.bytedeco.opencv.opencv_core.*; + +import java.util.*; + +/** + * 空检测器,用于在模型加载失败时提供回退机制 + */ +public class DummyDetector implements YoloDetector { + private final String name; + + public DummyDetector(String name) { + this.name = name; + System.out.println("警告: 使用DummyDetector替代真实模型 - " + name); + } + + @Override + public String name() { + return name; + } + + @Override + public List detect(Mat bgr) { + // 返回空列表,不进行实际检测 + return Collections.emptyList(); + } +} \ No newline at end of file