Skip to main content

Overview

The stream processing module provides three classes for handling RTSP streams:
  • StreamProcessor - Processes single RTSP streams with person detection and saving
  • MultiStreamManager - Orchestrates multiple concurrent streams
  • DisplayManager - Manages grid display window for multiple streams

StreamProcessor

Processes a single RTSP stream, runs person detection, handles saving (image snapshots or video clips), and optionally feeds frames to a DisplayManager.

Constructor

__init__()

PersonDetector
required
PersonDetector instance to use for person detection. Can be shared across multiple StreamProcessor instances.
str
default:"person"
Base directory where captured images or video clips are saved.
Implementation: stream_processor.py:26-28

Methods

process_rtsp_stream()

Process a single RTSP stream with an optional dedicated display window. Blocks until stream ends or user quits.
str
required
RTSP stream URL to connect to.Example: "rtsp://192.168.1.100:554/stream"
int
default:"15"
Analyze every Nth frame. At 30fps, frame_skip=15 means ~2 detections per second.Additional throttling: Detection also limited to once every 0.5 seconds (line 303).
bool
default:"True"
Show a live annotated window resized to 1280×720. Press ‘q’ to quit.
Optional[str]
default:"None"
Save mode for captures:
  • "image" - Save JPEG snapshots when person enters frame
  • "video" - Record MP4 clips from entry until exit
  • None - Don’t save anything
Behavior:
  1. Connects to RTSP stream with automatic reconnection (up to 5 attempts)
  2. Processes frames continuously
  3. Runs person detection every frame_skip frames (and max once per 0.5s)
  4. Tracks person entry/exit with 3-frame exit confirmation threshold
  5. Saves snapshots or video clips based on save_mode
  6. Displays annotated frames if display=True
  7. Handles Ctrl+C gracefully
Exit Conditions:
  • User presses ‘q’ (when display enabled)
  • User presses Ctrl+C
  • Max reconnection attempts exceeded
  • Stream ends naturally
Console Output Example:
Implementation: stream_processor.py:230-410

process_single_stream()

Process an RTSP stream indefinitely in the calling thread. Designed to be called from a worker thread in multi-stream scenarios.
Union[int, str]
required
Unique identifier for this stream (used in console output and directory naming).
str
required
RTSP stream URL to connect to.
int
default:"15"
Analyze every Nth frame.
Optional[str]
default:"None"
"image", "video", or None.
Optional[DisplayManager]
default:"None"
If provided, updates the shared grid display buffer with annotated frames.
Behavior:
  • Nearly identical to process_rtsp_stream(), but designed for threading
  • Saves files to {output_dir}/stream_{stream_id}/ subdirectories
  • Updates display_manager instead of creating its own window
  • Prefixes all console output with [Stream {stream_id}]
  • Stops when display_manager.is_running becomes False
Usage Pattern:
Implementation: stream_processor.py:34-224

Private Methods

_save_annotated_snapshot()

Internal helper that draws bounding boxes and confidence labels on a frame and saves it as JPEG. Implementation: stream_processor.py:416-434

Person Entry/Exit Detection

StreamProcessor uses a state machine to track person presence: Entry Detection:
  • Person detected in frame where person_present = False
  • Triggers snapshot save (image mode) or starts video recording (video mode)
  • Increments person_entry_count
Exit Detection:
  • Uses 3-frame confirmation threshold (NO_PERSON_EXIT_THRESHOLD = 3)
  • Requires 3 consecutive detection frames with no person
  • Prevents false exits from brief detection failures
  • Stops video recording when person exits
State Variables:
  • person_present (bool): Current presence state
  • no_person_streak (int): Consecutive frames without detection
  • person_entry_count (int): Total number of entries detected
Implementation: stream_processor.py:123-181 and stream_processor.py:311-355

Automatic Reconnection

Both stream processing methods implement automatic reconnection:
Behavior:
  • Waits 2 seconds between reconnection attempts
  • Allows up to 5 consecutive failures
  • Resets failure counter on successful frame read
Implementation: stream_processor.py:89-106 and stream_processor.py:281-296

Video Recording

When save_mode="video", StreamProcessor records MP4 clips: Codec: mp4v (MPEG-4) FPS: Automatically detected from stream via cv2.CAP_PROP_FPS (defaults to 25.0 if invalid) Recording lifecycle:
  1. Person enters frame → Create cv2.VideoWriter
  2. Every frame → Write to video file
  3. Person exits frame → Release writer and finalize file
Filename format:
Example:
Implementation: stream_processor.py:79-82, 148-159, 175-179, 329-339, 351-354

MultiStreamManager

Orchestrates concurrent processing of multiple RTSP streams. Each stream runs in its own daemon thread via StreamProcessor.

Constructor

__init__()

PersonDetector
required
PersonDetector instance shared across all streams.
str
default:"person"
Base directory for all stream outputs. Each stream creates a subdirectory: {output_dir}/stream_{id}/
Implementation: multi_stream_manager.py:31-34

Methods

process_multiple_streams()

Start all streams and block until they finish (or Ctrl+C).
Union[List[str], Dict[Union[int, str], str]]
required
RTSP stream URLs. Can be:List format (auto-numbered 1, 2, 3, …):
Dict format (custom IDs):
int
default:"15"
Analyze every Nth frame (applied to all streams).
Optional[str]
default:"None"
"image", "video", or None (applied to all streams).
bool
default:"False"
Show a live grid window with all streams. Press ‘q’ to quit.
Behavior:
  1. Creates output directory structure
  2. Optionally starts DisplayManager with grid window
  3. Spawns one daemon thread per stream
  4. Waits for all threads to complete or display window to close
  5. Handles Ctrl+C gracefully
  6. Cleans up display manager on exit
Console Output Example:
Implementation: multi_stream_manager.py:36-103 Complete Usage Example:

DisplayManager

Manages a single resizable grid window that composites frames from multiple streams in real time.

Constructor

__init__()

int
default:"640"
Width of each stream cell in the grid (pixels).
int
default:"360"
Height of each stream cell in the grid (pixels).
Grid Layout:
  • Automatically calculates grid dimensions based on number of streams
  • Uses square-ish layout: cols = ceil(sqrt(n)), rows = ceil(n / cols)
  • Total window size: (cell_width * cols, cell_height * rows)
Examples:
  • 1 stream: 1×1 grid (640×360)
  • 2 streams: 2×1 grid (1280×360)
  • 3 streams: 2×2 grid (1280×720)
  • 4 streams: 2×2 grid (1280×720)
  • 9 streams: 3×3 grid (1920×1080)
Implementation: display_manager.py:22-30

Properties

is_running

Returns whether the display thread is currently running. Useful for stream threads to detect when the user has closed the display window. Implementation: display_manager.py:36-38

Methods

start()

Register stream IDs and start the display thread.
List[Union[int, str]]
required
List of stream identifiers that will be displayed. Order determines grid position (left-to-right, top-to-bottom).Example:
Behavior:
  • Initializes frame buffer for each stream (all None initially)
  • Sets is_running = True
  • Spawns daemon thread running _loop()
  • Returns immediately (non-blocking)
Implementation: display_manager.py:40-48

stop()

Signal the display thread to stop and wait for it to finish (up to 2 seconds). Behavior:
  • Sets is_running = False
  • Waits for display thread with 2-second timeout
  • Destroys all OpenCV windows
  • Clears frame buffer
Implementation: display_manager.py:50-57

update_frame()

Update the display buffer for a specific stream. Thread-safe.
Union[int, str]
required
Stream identifier (must match one from start()).
cv2.typing.MatLike
required
OpenCV image matrix to display. Will be resized to (cell_width, cell_height) automatically.
Thread Safety: Protected by internal lock (self._lock). Usage Pattern:
Implementation: display_manager.py:59-62

Internal Methods

_build_grid()

Compose all buffered frames into a single grid image. Called internally by display loop. Behavior:
  • Locks frame buffer during composition
  • Resizes each frame to cell dimensions
  • Shows “Connecting…” placeholder for streams without frames yet
  • Arranges frames in grid layout
  • Returns single composited image
Implementation: display_manager.py:68-109

_loop()

Display thread main loop. Renders the grid at ~30 fps until stopped. Behavior:
  • Creates window: "Person Detection - All Streams"
  • Updates display every 30ms (~33 fps)
  • Stops when is_running = False or user presses ‘q’
  • Destroys window on exit
Implementation: display_manager.py:111-124

Complete Usage Example


Integration Example

Complete example showing how all three classes work together:

Implementation References

  • StreamProcessor: stream_processor.py (435 lines)
  • MultiStreamManager: multi_stream_manager.py (104 lines)
  • DisplayManager: display_manager.py (125 lines)