98 lines
2.4 KiB
Dart
98 lines
2.4 KiB
Dart
import 'package:camera/camera.dart';
|
||
|
||
import '../detection/detection_result.dart';
|
||
import '../detection/detector_worker.dart';
|
||
import 'camera_view_model.dart';
|
||
|
||
/// 抽帧节流 + 后台推理(对应 Kotlin FrameAnalyzer)。
|
||
/// 推理在后台 isolate(DetectorWorker)执行,主 isolate 只投递帧与收结果。
|
||
class FrameAnalyzer {
|
||
/// 连续检测:100ms 一帧
|
||
int intervalMs = 100;
|
||
|
||
/// null = 模型加载失败,仅预览不分析
|
||
final DetectorWorker? worker;
|
||
final CameraViewModel viewModel;
|
||
|
||
int _lastDetectMs = 0;
|
||
|
||
/// 诊断计数:推理调用/异常次数
|
||
int detectCalls = 0;
|
||
int detectErrors = 0;
|
||
String? lastError;
|
||
|
||
/// 最近一次完整处理(预处理+推理+运动检测)耗时 ms(worker 侧)
|
||
int lastProcessMs = 0;
|
||
|
||
/// 图像流回调是否到达(诊断用)
|
||
int framesReceived = 0;
|
||
|
||
FrameAnalyzer({required this.worker, required this.viewModel}) {
|
||
worker?.onResult = _onResult;
|
||
worker?.onError = _onError;
|
||
}
|
||
|
||
void recordStreamError(String msg) {
|
||
lastError = msg;
|
||
detectErrors++;
|
||
}
|
||
|
||
void _onResult(
|
||
List<DetectionResult> results,
|
||
List<MotionRegion> motion,
|
||
List<MotionRegion> novelty,
|
||
int rotation,
|
||
int width,
|
||
int height,
|
||
int processMs) {
|
||
detectCalls++;
|
||
lastProcessMs = processMs;
|
||
viewModel.onFramesAnalyzed(
|
||
results,
|
||
rotation,
|
||
width,
|
||
height,
|
||
motion,
|
||
novelty,
|
||
detectCalls: detectCalls,
|
||
detectErrors: detectErrors,
|
||
lastError: lastError,
|
||
framesReceived: framesReceived,
|
||
lastProcessMs: lastProcessMs,
|
||
);
|
||
}
|
||
|
||
void _onError(String msg) {
|
||
detectErrors++;
|
||
lastError = msg;
|
||
viewModel.onFramesAnalyzed(
|
||
const [],
|
||
90,
|
||
0,
|
||
0,
|
||
const [],
|
||
const [],
|
||
detectCalls: detectCalls,
|
||
detectErrors: detectErrors,
|
||
lastError: lastError,
|
||
framesReceived: framesReceived,
|
||
lastProcessMs: lastProcessMs,
|
||
);
|
||
}
|
||
|
||
void analyze(CameraImage image, int rotationDegrees) {
|
||
framesReceived++;
|
||
final w = worker;
|
||
if (w == null) return;
|
||
final now = DateTime.now().millisecondsSinceEpoch;
|
||
if (now - _lastDetectMs < intervalMs) return;
|
||
_lastDetectMs = now;
|
||
if (w.busy) return; // 上一帧未返回则丢帧,避免在途积压
|
||
w.analyze(image, rotationDegrees);
|
||
}
|
||
|
||
void reset() => _lastDetectMs = 0;
|
||
|
||
void dispose() => worker?.dispose();
|
||
}
|