1
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:camera/camera.dart';
|
||||
|
||||
import '../detection/detection_result.dart';
|
||||
import '../detection/detector_worker.dart';
|
||||
import '../feedback/false_target_capture.dart';
|
||||
import 'camera_view_model.dart';
|
||||
|
||||
/// 抽帧节流 + 后台推理(对应 Kotlin FrameAnalyzer)。
|
||||
@@ -33,10 +35,41 @@ class FrameAnalyzer {
|
||||
/// 图像流回调是否到达(诊断用)
|
||||
int framesReceived = 0;
|
||||
|
||||
/// 假目标上报快照:armed 时下一帧(节流前)拷贝单平面像素并交付。
|
||||
/// Completer 泛型必须可空:运行时 future 类型决定 .timeout(onTimeout) 的
|
||||
/// 回调签名,非空 Completer 会让 `() => null` 触发运行时子类型错误
|
||||
Completer<FrameSnapshot?>? _snapCompleter;
|
||||
|
||||
FrameAnalyzer({DetectorWorker? worker, required this.viewModel}) {
|
||||
attachWorker(worker);
|
||||
}
|
||||
|
||||
/// 取下一帧快照(假目标上报用;在节流判定之前捕获,~33ms 内必有帧)
|
||||
Future<FrameSnapshot?> takeSnapshot() {
|
||||
final existing = _snapCompleter;
|
||||
if (existing != null && !existing.isCompleted) {
|
||||
return existing.future;
|
||||
}
|
||||
final c = Completer<FrameSnapshot?>();
|
||||
_snapCompleter = c;
|
||||
return c.future;
|
||||
}
|
||||
|
||||
/// 帧到达(节流判定前):armed 则拷贝像素完成快照
|
||||
void _captureIfNeeded(
|
||||
Uint8List plane, int bytesPerRow, int width, int height, bool bgra) {
|
||||
final c = _snapCompleter;
|
||||
if (c == null || c.isCompleted) return;
|
||||
_snapCompleter = null;
|
||||
c.complete(FrameSnapshot(
|
||||
plane: Uint8List.fromList(plane),
|
||||
bytesPerRow: bytesPerRow,
|
||||
width: width,
|
||||
height: height,
|
||||
bgra: bgra,
|
||||
));
|
||||
}
|
||||
|
||||
/// 替换推理 worker(null = 停识别仅预览)。旧 worker 在此释放;若相机已
|
||||
/// 启动则新 worker 立即接管后续帧——重启相机会重新 initialize
|
||||
/// (iOS ~1s+)且预览闪断,原地替换即时生效(2026-09-03)。
|
||||
@@ -114,6 +147,11 @@ class FrameAnalyzer {
|
||||
|
||||
void analyze(CameraImage image, int rotationDegrees,
|
||||
{bool rgbaOrder = false}) {
|
||||
final p = image.planes.isNotEmpty ? image.planes.first : null;
|
||||
if (p != null) {
|
||||
_captureIfNeeded(
|
||||
p.bytes, p.bytesPerRow, image.width, image.height, !rgbaOrder);
|
||||
}
|
||||
if (!_canSend()) return;
|
||||
worker!.analyze(image, rotationDegrees, rgbaOrder: rgbaOrder);
|
||||
}
|
||||
@@ -129,6 +167,9 @@ class FrameAnalyzer {
|
||||
required bool rgbaOrder,
|
||||
int rotationDegrees = 0,
|
||||
}) {
|
||||
if (planes.isNotEmpty) {
|
||||
_captureIfNeeded(planes.first, strides.first, width, height, isBgra);
|
||||
}
|
||||
if (!_canSend()) return;
|
||||
worker!.analyzeRaw(
|
||||
planes: planes,
|
||||
|
||||
Reference in New Issue
Block a user