Skip to main content

A cross-platform CLI to view RTMP/RTSP video streams (incl. 360) in a small window.

Project description

Streamcatcher

A cross-platform Python CLI that connects to an RTSP or RTMP video stream and views it in a small desktop window — including 360° panoramic cameras, which it reprojects into a flat pan/tilt/zoom "look-around" viewport. Pure Python, powered by OpenCV.

Status: early development, built in small, tested vertical slices. Live video playback, the 360° equirectangular look-around viewport, snapshots, auto-reconnect, and an HTTP control API all work today. Video only — OpenCV does not decode audio.

Features

  • View RTSP/RTMP streams in a native window (OpenCV — video only, no audio).
  • 360° support: reproject an equirectangular panorama into a flat look-around viewport.
  • Look around live: W/A/S/D to pan and tilt, +/- to zoom, q to quit.
  • Snapshots: press p in the viewer to save the current view, or grab one frame headlessly with --snapshot (current directory) or --snapshot out.jpg.
  • Auto-reconnect: when a live stream drops, reconnect with exponential backoff (retries forever by default; --no-reconnect to exit on the first drop).
  • Offline-first: the package and the entire test suite run with no network, no credentials, and no live stream. OpenCV is lazy-imported only on the live path, and an offline stub backend (-b stub) needs nothing at all.
  • Secrets-safe: stream URLs (which may embed user:pass@host) are wrapped in SecretStr and scrubbed from logs by a redacting filter.

Install

Requires Python 3.12+. Streamcatcher is not on PyPI yet, so install from source:

pip install git+https://github.com/ThugipanSivanesan/Streamcatcher

The live viewer pulls in opencv-python; no separate system media player (VLC, ffmpeg app, …) is required.

Usage

# View a plain 2D stream in a window
streamcatcher play rtsp://camera.local:554/stream1

# View a 360° equirectangular camera with a look-around viewport
streamcatcher play rtsp://123.456.7.890/live/live -p equirect

# Capture a single frame in the current directory and exit  no window (respects -p)
streamcatcher play rtsp://cam/live --snapshot

# Or choose the exact output path
streamcatcher play rtsp://cam/live --snapshot shot.jpg

In the viewer window: W/A/S/D (or drag the mouse) aim · +/- zoom · p snapshot · q quit. The p hotkey writes a timestamped streamcatcher-snapshot-YYYYMMDD-HHMMSS.jpg in the current directory.

Flag Values Env var
--backend / -b opencv (live window, default), stub (offline no-op) STREAMCATCHER_BACKEND
--projection / -p flat (default), equirect STREAMCATCHER_PROJECTION
--snapshot optional PATH — save one frame and exit; defaults to a timestamped JPEG in the current directory
--reconnect / --no-reconnect auto-reconnect on drop (default on) STREAMCATCHER_RECONNECT_ENABLED

play opens a real OpenCV window by default; pass -b stub (or set STREAMCATCHER_BACKEND=stub) for the offline no-op backend used in development and tests.

How it works

  • Playback: OpenCV (cv2.VideoCapture + highgui) opens its own native window from a plain Python CLI. RTSP is forced over TCP to reduce dropped packets.
  • 360° reprojection: pure-NumPy equirectangular→pinhole remap tables are fed to cv2.remap. The math is deterministic and unit-tested with no GPU, window, or live stream needed.
  • Headless control core: StreamSession drives open / read / render / look-around / close with no window attached — the same core the HTTP control API sits on.
  • CLI: Typer.

HTTP control API

Install the [api] extra and run the server so another program — or an AI agent — can open sessions, drive the look-around, and pull frames:

pip install 'streamcatcher[api]'
streamcatcher serve                                   # binds 127.0.0.1:8000
streamcatcher serve --host 0.0.0.0 --port 9000 --token changeme

Interactive OpenAPI docs are served at /docs. Key endpoints:

Endpoint Purpose
POST /session Open a session for a stream URL; returns an id (the URL is never echoed back).
GET /session/{id}/frame Current look-around viewport as a JPEG — how an agent "sees" now.
GET /session/{id}/panorama Raw, full-frame JPEG (before reprojection).
GET /session/{id}/stream.mjpg MJPEG stream of the viewport.
POST /session/{id}/look Pan/tilt/zoom by {pan, tilt, zoom} degree deltas.
POST /session/{id}/look/{pan_left…zoom_out} Discrete look steps.
GET /session/{id}/state Current projection and orientation.
DELETE /session/{id} Close the session.

The server binds 127.0.0.1 by default. Set --token (or STREAMCATCHER_API_TOKEN) to require an Authorization: Bearer <token> header on every request. Stream URLs and their credentials are never returned in any response.

Documentation

Full docs — CLI usage, the 360°/camera guide, the Python and HTTP APIs, architecture, and an API reference generated from the source — are built with mkdocs-material under docs/. Build them locally with uv run mkdocs serve (see Contributing). See the changelog for what has shipped so far.

Contributing

See CONTRIBUTING.md for the full development workflow. The short version, using uv:

uv sync --extra api           # create the environment (incl. the API extra)
uv run pytest                 # tests (offline, no credentials)
uv run ruff check .           # lint
uv run ruff format --check .  # format check
uv run mkdocs serve           # preview the docs (needs: uv sync --group docs)
pre-commit install            # enable local hooks

Security

  • CI runs gitleaks (secret scanning) and osv-scanner (dependency vulnerabilities) on every pull request.
  • Pre-commit hooks scan for secrets and private keys before anything is committed.
  • Stream URLs and their embedded credentials are never written to logs.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

streamcatcher-0.1.0.tar.gz (108.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

streamcatcher-0.1.0-py3-none-any.whl (33.9 kB view details)

Uploaded Python 3

File details

Details for the file streamcatcher-0.1.0.tar.gz.

File metadata

  • Download URL: streamcatcher-0.1.0.tar.gz
  • Upload date:
  • Size: 108.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for streamcatcher-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3e0802558349783530a0a929e899aa4d9a7c1635efb03e598ae38c67f76ed7a1
MD5 f87b8dc8e7d24428f6c2dbf3eae4b6bc
BLAKE2b-256 354911fa2e5e57d83915417150ad14bf9bb920ee3f377cafad856bcb1f6e15a6

See more details on using hashes here.

Provenance

The following attestation bundles were made for streamcatcher-0.1.0.tar.gz:

Publisher: release.yml on ThugipanSivanesan/Streamcatcher

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file streamcatcher-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: streamcatcher-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 33.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for streamcatcher-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9e215752d4fe604bd5fad7573dbe875ec4ad813e36a237a71ac1a9871ae08c88
MD5 5ee3721e647135a79ca4604327435209
BLAKE2b-256 5fb9cf399f091d078f21e8474e618b6c8b3ce3feb691ff0578a36f539310c67f

See more details on using hashes here.

Provenance

The following attestation bundles were made for streamcatcher-0.1.0-py3-none-any.whl:

Publisher: release.yml on ThugipanSivanesan/Streamcatcher

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page