# RTSP Windowed People Flow Design **Date:** 2026-04-08 **Goal:** Extend the existing people-flow project with an RTSP mode that samples one frame per second from a live stream, computes people-flow and demographics, and writes a JSON summary every 30 minutes while preserving the existing offline video and batch modes. ## Scope - Keep the existing `video` and `batch` commands unchanged. - Add a new `rtsp` command for continuous live-stream processing. - Sample one frame per second based on wall-clock time instead of processing every decoded frame. - Maintain a 30-minute independent counting window. - Write one timestamped JSON file per finished window. - Refresh a `latest.json` file on every window flush. - Do not save annotated RTSP video by default. - Back up the current project before implementation. ## Approach The current codebase already has reusable counting and attribute aggregation logic. The least risky change is to keep the offline pipeline as-is and add a dedicated RTSP processing path that reuses the same `LineCrossCounter` and `AttributeAggregator` components. The RTSP path will: 1. Open an RTSP stream with OpenCV. 2. Read frames continuously. 3. Run inference only when at least one second has elapsed since the last processed frame. 4. Accumulate counts inside the current 30-minute window. 5. Flush a window summary to JSON when the window boundary is reached. 6. Reset all per-window state and continue into the next window. 7. Retry the stream connection when the RTSP source drops. ## Data Flow ### Command Layer - `main.py` adds an `rtsp` subcommand with an `--input` RTSP URL. - Existing global arguments such as `--config`, `--output-dir`, `--line`, and `--device` remain shared. - RTSP mode disables video writing by default unless explicitly enabled in config later. ### Configuration Add a new RTSP config section with: - `sample_interval_seconds` - `window_seconds` - `reconnect_delay_seconds` - `stream_open_timeout_seconds` - `idle_sleep_seconds` - `output_subdir` This keeps timing and output behavior configurable without changing code. ### Processing Loop Each processed frame will: 1. Pass through YOLO tracking. 2. Extract `person` track observations. 3. Optionally run DeepFace sampling on eligible tracks. 4. Update the line-cross counter. 5. Check whether the active 30-minute window should be flushed. Skipped frames are decoded only to keep the stream current; they do not go through YOLO or DeepFace. ### Window Boundaries Each window starts when the RTSP pipeline starts or right after the previous flush. The summary payload includes: - `source_type` - `source` - `window_index` - `window_start` - `window_end` - `window_duration_seconds` - `total_people` - `age_counts` - `gender_counts` - `unknown_attributes` - `tracks` After flushing: - The timestamped JSON is written under `windows/`. - `latest.json` is overwritten with the same payload. - The counting and attribute state is reset. ## Output Layout For `--output-dir /path/output`, the RTSP outputs live under: - `/path/output/rtsp_stream/` - `/path/output/rtsp_stream/latest.json` - `/path/output/rtsp_stream/windows/stats_YYYY-MM-DD_HH-MM-SS.json` The timestamp in the filename is the window end time. ## Error Handling - If the RTSP stream cannot be opened, retry after a configurable delay. - If frame reads fail mid-stream, release the capture and reconnect. - If DeepFace analysis fails on a crop, treat that sample as unknown and keep running. - If a window has zero crossings, still write a valid JSON payload with zero counts so downstream consumers can distinguish inactivity from pipeline failure. ## Compatibility - `video` mode still writes annotated video and a final JSON after full processing. - `batch` mode still writes a final CSV summary. - Existing config keys remain valid. ## Testing Strategy - Validate CLI parsing for the new `rtsp` command. - Validate config loading with the new RTSP section. - Validate that RTSP mode writes windowed JSON payloads and refreshes `latest.json`. - Validate that 30-minute windows reset counts instead of accumulating indefinitely. - Keep offline mode behavior intact by running `--help` and Python compile checks.