capture_helper.preview module
capture_helper.preview
Live-preview helpers for the scene configurator GUI. Two flavours, both built on the existing iterators so no new capture path is introduced:
Camera → JPEG.
frame_to_jpeg()encodes one(H, W, 3)BGR uint8 frame (the exact arraycapture_helper.iter_camera_frames()yields) to a JPEG byte string via a one-shot ffmpeg call.snapshot_jpeg()grabs a single live frame and returns it as JPEG, anditer_camera_jpeg()yields a stream of JPEGs suitable for anmultipart/x-mixed-replaceMJPEG response in the browser.Microphone → level.
mic_level()captures a short slice of live audio throughcapture_helper.iter_mic_audio()and reduces it to an RMS / peak level (linear and dBFS) so the GUI can draw a live VU meter.
Why ffmpeg for JPEG (and not Pillow / OpenCV)
ffmpeg is already a hard runtime requirement of capture-helper. Encoding the raw
BGR frame through a tiny ffmpeg -f rawvideo … -f mjpeg - call keeps the
dependency surface flat — no Pillow, no OpenCV — at the cost of one subprocess
per encode, which is negligible for preview-rate frames.
- capture_helper.preview.frame_to_jpeg(frame, *, quality=5)[source]
Encode a single BGR frame to a JPEG byte string via ffmpeg.
- Parameters:
frame (numpy.ndarray) – A
(H, W, 3)uint8array in OpenCV BGR channel order — exactly whatcapture_helper.iter_camera_frames()yields.quality (int, default 5) – ffmpeg
-q:vvalue (2best …31worst). Lower = larger file, better image.5is a good preview trade-off.
- Returns:
The JPEG-encoded image.
- Return type:
- Raises:
ValueError – If
frameis not a(H, W, 3)uint8 array.FileNotFoundError – If ffmpeg is not on PATH.
RuntimeError – If ffmpeg fails to encode the frame.
Examples
>>> import numpy as np >>> jpg = frame_to_jpeg(np.zeros((16, 16, 3), dtype=np.uint8)) >>> jpg[:2] == b"\xff\xd8" # JPEG SOI marker True
- capture_helper.preview.iter_camera_jpeg(source, *, output_width=480, output_height=270, fps=10.0, quality=5, max_frames=None)[source]
Yield a stream of JPEG-encoded frames from a live camera.
Each yielded item is a complete JPEG suitable for concatenation into an
multipart/x-mixed-replaceMJPEG HTTP response (seecapture_helper.api()).- Parameters:
source (Source) – A
"camera"device.output_width (int) – Preview size per frame.
output_height (int) – Preview size per frame.
fps (float, default 10.0) – Capture-side frame rate — kept low so the preview is cheap.
quality (int, default 5) – JPEG quality per frame.
max_frames (int, optional) – Stop after this many frames.
None= until the consumer disconnects.
- Yields:
bytes – Successive JPEG images.
- Raises:
ValueError – If
sourceis not a camera.- Return type:
Examples
>>> cam = ... >>> for jpg in iter_camera_jpeg(cam, max_frames=3): ... handle(jpg)
- async capture_helper.preview.mic_level(source, *, target_sample_rate=16000, frame_ms=20, window_ms=200)[source]
Capture a short slice of live audio and reduce it to a level reading.
Drives
capture_helper.iter_mic_audio()for roughlywindow_msof audio, then returns RMS / peak levels — the GUI polls this to animate a VU meter without holding a long-lived stream open.- Parameters:
- Returns:
{"rms": …, "rms_dbfs": …, "peak": …, "peak_dbfs": …}.- Return type:
- Raises:
ValueError – If
sourceis not a microphone.
Examples
>>> import asyncio >>> mic = ... >>> asyncio.run(mic_level(mic))
- capture_helper.preview.rms_dbfs(pcm)[source]
Compute linear RMS and its dBFS equivalent for a PCM block.
- Parameters:
pcm (numpy.ndarray) – Float32 samples in
[-1, 1](any shape; flattened internally).- Returns:
(rms_linear, rms_dbfs).rms_dbfsis clamped at-120.0for digital silence to avoid-inf.- Return type:
Examples
>>> import numpy as np >>> lin, db = rms_dbfs(np.zeros(100, dtype=np.float32)) >>> lin == 0.0 and db == -120.0 True
- capture_helper.preview.snapshot_jpeg(source, *, output_width=480, output_height=270, quality=5)[source]
Grab one live frame from a camera and return it as JPEG bytes.
- Parameters:
source (Source) – A
"camera"device fromcapture_helper.pick_source()/list_sources().output_width (int) – Preview size (aspect-preserving fit-and-pad, per the camera iterator).
output_height (int) – Preview size (aspect-preserving fit-and-pad, per the camera iterator).
quality (int, default 5) – JPEG quality passed to
frame_to_jpeg().
- Returns:
A single JPEG image.
- Return type:
- Raises:
ValueError – If
sourceis not a camera.RuntimeError – If no frame could be captured (permission denied / device busy).
Examples
>>> cam = ... >>> jpg = snapshot_jpeg(cam)