use nv_core::config::{CameraMode, SourceSpec};
use nv_core::error::StageError;
use nv_core::health::HealthEvent;
use nv_core::id::StageId;
use nv_perception::{Stage, StageContext, StageOutput};
use nv_runtime::{FeedConfig, OutputEnvelope, OutputSink, Runtime};
use std::sync::Arc;
struct PassthroughStage;
impl Stage for PassthroughStage {
fn id(&self) -> StageId {
StageId("passthrough")
}
fn process(&mut self, _ctx: &StageContext<'_>) -> Result<StageOutput, StageError> {
Ok(StageOutput::empty())
}
}
struct PrintSink {
label: &'static str,
}
impl OutputSink for PrintSink {
fn emit(&self, output: Arc<OutputEnvelope>) {
println!(
"[{}] feed={:?} seq={} detections={}",
self.label,
output.feed_id,
output.frame_seq,
output.detections.len(),
);
}
}
fn main() -> Result<(), nv_core::error::NvError> {
let runtime = Runtime::builder().max_feeds(4).build()?;
let mut health_rx = runtime.health_subscribe();
let mut output_rx = runtime.output_subscribe();
let feeds = [
("cam-lobby", "rtsp://192.168.1.10/stream"),
("cam-entrance", "rtsp://192.168.1.11/stream"),
("cam-parking", "rtsp://192.168.1.12/stream"),
];
let mut handles = Vec::new();
for (label, url) in feeds {
let config = FeedConfig::builder()
.source(SourceSpec::rtsp(url))
.camera_mode(CameraMode::Fixed)
.stages(vec![Box::new(PassthroughStage)])
.output_sink(Box::new(PrintSink { label }))
.build()?;
let handle = runtime.add_feed(config)?;
println!("Started feed {:?} ({label})", handle.id());
handles.push(handle);
}
println!("Running {} feeds...", runtime.feed_count()?);
std::thread::spawn(move || {
while let Ok(event) = health_rx.blocking_recv() {
match event {
HealthEvent::SourceConnected { feed_id } => {
println!("Health: feed {feed_id:?} connected");
}
HealthEvent::FeedStopped { feed_id, reason } => {
println!("Health: feed {feed_id:?} stopped: {reason:?}");
}
HealthEvent::OutputLagged { messages_lost } => {
println!("Health: output lagged, {messages_lost} messages lost");
}
_ => {}
}
}
});
std::thread::spawn(move || {
while let Ok(output) = output_rx.blocking_recv() {
println!(
"Output: feed={:?} seq={} latency={:?}",
output.feed_id, output.frame_seq, output.provenance.total_latency,
);
}
});
std::thread::sleep(std::time::Duration::from_secs(5));
for handle in &handles {
let m = handle.metrics();
println!(
"Feed {:?}: processed={}, dropped={}, restarts={}",
handle.id(),
m.frames_processed,
m.frames_dropped,
m.restarts,
);
}
runtime.shutdown()?;
println!("Runtime shut down cleanly.");
Ok(())
}