nv_view/provider.rs
1//! [`ViewStateProvider`] trait and motion report types.
2
3use crate::camera_motion::CameraMotionState;
4use crate::ptz::PtzTelemetry;
5use crate::transform::GlobalTransformEstimate;
6use crate::view_state::ViewState;
7use nv_core::MonotonicTs;
8use nv_frame::FrameEnvelope;
9
10/// What the view system receives from the provider each frame.
11///
12/// The provider fills in whichever fields are available. The view system
13/// derives [`MotionSource`](crate::MotionSource) from the field contents
14/// (see the architecture spec §9 for derivation rules).
15#[derive(Clone, Debug, Default)]
16pub struct MotionReport {
17 /// PTZ telemetry, if available from the camera's control interface.
18 pub ptz: Option<PtzTelemetry>,
19
20 /// Frame-to-frame transform estimate (from optical flow, homography, etc.).
21 ///
22 /// This is the primary egomotion signal when PTZ telemetry is absent.
23 pub frame_transform: Option<GlobalTransformEstimate>,
24
25 /// Optional hint about whether the camera is moving.
26 ///
27 /// If `None`, the view system infers motion from the `ptz` deltas
28 /// or `frame_transform` displacement magnitude.
29 pub motion_hint: Option<CameraMotionState>,
30
31 /// Discrete PTZ control events received since the previous frame.
32 ///
33 /// Empty when no PTZ command stream is available. Providers that
34 /// monitor an ONVIF event channel or serial command bus populate
35 /// this with the events that arrived between frames.
36 ///
37 /// The epoch policy considers these events alongside telemetry and
38 /// inferred motion to make segmentation decisions.
39 pub ptz_events: Vec<crate::ptz::PtzEvent>,
40}
41
42/// Context given to [`ViewStateProvider::poll`].
43pub struct MotionPollContext<'a> {
44 /// Monotonic timestamp of the current frame.
45 pub ts: MonotonicTs,
46 /// The current video frame (available for egomotion providers that
47 /// need pixel data for optical flow or feature matching).
48 pub frame: &'a FrameEnvelope,
49 /// The previous frame's view state.
50 pub previous_view: &'a ViewState,
51}
52
53/// User-implementable trait: provides camera motion information each frame.
54///
55/// Required when [`CameraMode::Observed`](nv_core::CameraMode::Observed) is configured.
56///
57/// ## Implementation categories
58///
59/// - **Telemetry providers**: poll ONVIF/serial, populate `ptz` field.
60/// - **Egomotion providers**: run optical flow or feature matching on the frame,
61/// populate `frame_transform` field.
62/// - **External providers**: receive transforms or hints from an outside system.
63///
64/// ## Performance
65///
66/// `poll()` is called on the stage thread, synchronously, **before** any stage
67/// executes. Its latency adds directly to every frame's pipeline latency.
68///
69/// - Telemetry providers should pre-fetch asynchronously and return cached data.
70/// - Egomotion providers run computation directly (typically 1–5ms).
71/// - External providers should return pre-computed data.
72pub trait ViewStateProvider: Send + Sync + 'static {
73 /// Called once per frame. Return the current motion report.
74 fn poll(&self, ctx: &MotionPollContext<'_>) -> MotionReport;
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn motion_report_default_is_empty() {
83 let report = MotionReport::default();
84 assert!(report.ptz.is_none());
85 assert!(report.frame_transform.is_none());
86 assert!(report.motion_hint.is_none());
87 assert!(report.ptz_events.is_empty());
88 }
89
90 #[test]
91 fn motion_report_with_ptz() {
92 use crate::ptz::PtzTelemetry;
93 let report = MotionReport {
94 ptz: Some(PtzTelemetry {
95 pan: 90.0,
96 tilt: 0.0,
97 zoom: 0.5,
98 ts: MonotonicTs::from_nanos(100),
99 }),
100 ..Default::default()
101 };
102 assert!(report.ptz.is_some());
103 assert!(report.frame_transform.is_none());
104 }
105}