Skip to main content

pyezcams

v0.1.3 · PyPI

Minimal (stdlib-only) toolkit to run a node that captures USB webcams and streams them over RTSP/WebRTC via MediaMTX. A single command (pyezcams) starts MediaMTX and one ffmpeg per camera and keeps them alive.

No Python dependencies. Relies on three system binaries: ffmpeg, v4l2-ctl and mediamtx. Linux only (v4l2 capture).

Stateless: the library stores nothing and assumes no paths. All configuration is the match file, passed explicitly and required.

Prerequisites

Binary Install
ffmpeg sudo apt install ffmpeg
v4l2-ctl sudo apt install v4l-utils
mediamtx binary from releases onto the PATH

check_prerequisites() verifies them at startup and, if any is missing, says what to do.

Install

pip install pyezcams

Usage

pyezcams --config cameras.txt                       # defaults: 720p30
pyezcams --config cameras.txt --resolution 1920x1080 --fps 25

--config is required (no default path). The command checks prerequisites, detects the encoder, starts MediaMTX and launches one ffmpeg per camera, supervising them (relaunches any that die, clean shutdown on SIGINT/SIGTERM).

Defaults

720p30 surveillance standard; everything works with no flags. Only --config is required; --resolution and --fps are optional overrides.

Parameter Default Applies to
resolution 1280x720 (max) capture (both cases)
framerate 30 (max) capture (both cases)
bitrate 4M re-encode (MJPG) only
GOP 60 (2s @30fps) re-encode (MJPG) only
RTSP output rtsp://localhost:8554/<alias> both cases

--resolution and --fps are a ceiling, not a fixed value. Each camera is probed with v4l2-ctl and captures at the largest mode it actually offers at or below them; a camera that only does MJPG 640x480@30 gets exactly that, and the downgrade is logged as a warning. Asking for a size the camera does not have would make V4L2 silently fall back to YUYV at its smallest size — that is the bug this avoids.

Per case:

  • H264 (copy) — captures at the negotiated mode and copies the native stream (-c:v copy, ~0 CPU). Bitrate does not apply (nothing is re-encoded).
  • MJPG (re-encode) — captures at the negotiated mode and re-encodes with the detected encoder at the given bitrate.

Bitrate and RTSP base are module constants in command.py; build_command also takes video_size, framerate and bitrate keyword args for per-camera overrides.

Match file

One camera per line, path = alias (blank lines and # comments ignored):

/dev/v4l/by-path/...-video-index0 = laser20w
/dev/v4l/by-path/...-video-index0 = cnc_a

Get the paths with ls -l /dev/v4l/by-path/.

API

from pyezcams import (
    parse_match, check_prerequisites, detect_encoder,
    detect_mode, detect_format, build_command, run,
)
  • parse_match(path) -> dict — read the match file into {alias: usb_path}.
  • check_prerequisites() -> None — verify the three binaries; RuntimeError if any is missing.
  • detect_encoder() -> str | None — first H.264 encoder that passes a real 1-frame test (h264_nvenc > h264_qsv > h264_vaapi > h264_v4l2m2m > libx264). Hang-proof: each test is capped by ENCODER_TEST_TIMEOUT (10s). A hardware encoder that hangs (broken driver/firmware) is discarded on timeout and the detection falls through to the next candidate instead of blocking node startup; software libx264 always works as the final fallback.
  • detect_mode(usb_path, max_width, max_height, max_fps) -> Mode | None — the camera's best Mode(fmt, width, height, fps) at or below the ceiling: preferred format first (H264 > MJPG), then the largest frame size that fits, then the highest fps not above max_fps (or the lowest available if the camera only offers more). None if it has no usable format. Only Size: Discrete modes are parsed; a stepwise-only camera yields None.
  • detect_format(usb_path) -> str | None — "H264" (copy) or "MJPG" (re-encode), or None. Kept for back-compat; prefer detect_mode, since a format alone does not tell you at which sizes the camera offers it.
  • build_command(usb_path, alias, fmt, encoder, video_size=..., framerate=..., bitrate=...) -> list[str] — build (not run) the ffmpeg argv; the last three default to the 720p30/4M standard. ValueError if fmt is None. Pass a size/fps the camera really has (i.e. from detect_mode), not a wish.
  • run(config, video_size=..., framerate=...) -> None — orchestrate the node: prerequisites -> MediaMTX -> one ffmpeg per camera -> supervision -> clean shutdown. video_size/framerate are a ceiling.

License

MIT — see LICENSE.

Release files for pyezcams 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyezcams 0.1.3
File Size Uploaded
pyezcams-0.1.3.tar.gz 12.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyezcams 0.1.3
File Interpreter ABI Platform
pyezcams-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 26.5 kB

Release files / pyezcams-0.1.3.tar.gz

Download URL pyezcams-0.1.3.tar.gz
Size 12.1 kB
Tags Source
SHA-256 checksum
How to use checksums
9aa1777dc45ed5708df9b59df958c3d4243536ef6aa68e8a94d42081a2f701da
BLAKE2b-256 checksum
How to use checksums
1d9e780dc5e1efaefd4c02c41ccb7b9cde4d131d59f25c7e79a0a868b6c7e834
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.9

Release files / pyezcams-0.1.3-py3-none-any.whl

Download URL pyezcams-0.1.3-py3-none-any.whl
Size 14.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
12a3050b66fdbb0f90de18c8f984b1e6b41bbbae6ebe39e3b43b78eae36ab4e9
BLAKE2b-256 checksum
How to use checksums
2fb0fa338b303a0d6b0bf236571016eb069cc27d98764f055e2b328156468219
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.9

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page