capture_helper.camera module

capture_helper.camera

Live camera-frame iterator that bridges capture_helper.list_sources() output with the same numpy BGR (H, W, 3) uint8 contract that video_helper.extract_frames() uses for file-based decoding. The intent is: if you can drop a video file path into a pipeline, you can drop a live camera in.

Implementation

  • Shells out to ffmpeg with the right per-OS input driver (-f avfoundation / -f v4l2 / -f dshow) built by capture_helper.sources.ffmpeg_input_args().

  • Asks ffmpeg to decode + scale + pad to the requested output size and emit raw bgr24 to stdout. We read fixed-size byte blocks and reshape into (H, W, 3).

  • Pure synchronous generator — matches the video_helper.extract_frames() API. Async wrapping is left to the caller (e.g. asyncio.to_thread).

Usage example

>>> import capture_helper as ch
>>> import cv2
>>> cam = ch.pick_source("camera")
>>> for frame in ch.iter_camera_frames(cam, output_width=640, output_height=360,
...                                    fps=30, max_frames=300):
...     cv2.imshow("preview", frame)
...     if cv2.waitKey(1) & 0xFF == ord("q"):
...         break

Author

Warith Harchaoui, Ph.D. — https://linkedin.com/in/warith-harchaoui/

capture_helper.camera.iter_camera_frames(source, *, width=None, height=None, fps=None, output_width=None, output_height=None, pad_color='black', max_frames=None)[source]

Yield live camera frames as numpy BGR uint8 arrays.

Wraps ffmpeg with the per-OS input driver picked up from source["driver"] and emits (H, W, 3) uint8 arrays in OpenCV’s BGR channel order — the same shape and dtype video_helper.extract_frames() yields. Consumers built for the file-based path therefore plug in unchanged.

Parameters:
  • source (Source) – Device dict returned by pick_source() / list_sources(). Its kind must be "camera".

  • width (int, optional) – Capture-side resolution request. Passed to ffmpeg as -video_size WxH before the input — the OS driver picks the closest supported mode if the exact value isn’t available. Leave None to use the driver’s default.

  • height (int, optional) – Capture-side resolution request. Passed to ffmpeg as -video_size WxH before the input — the OS driver picks the closest supported mode if the exact value isn’t available. Leave None to use the driver’s default.

  • fps (float, optional) – Capture-side frame rate request. Same caveat as width / height. Leave None for the driver default.

  • output_width (int, optional) –

    Post-decode output size. Behaviour mirrors video_helper.extract_frames():

    • both set → scale-fit (aspect preserved) then pad with pad_color to exactly output_width × output_height;

    • one set → scale that axis, preserve aspect on the other;

    • neither set → native camera frame size.

  • output_height (int, optional) –

    Post-decode output size. Behaviour mirrors video_helper.extract_frames():

    • both set → scale-fit (aspect preserved) then pad with pad_color to exactly output_width × output_height;

    • one set → scale that axis, preserve aspect on the other;

    • neither set → native camera frame size.

  • pad_color (str, optional) – Colour name ("black" / "white" / "#RRGGBB" / …) used when scale-fit-and-pad applies. Default "black".

  • max_frames (int, optional) – Stop after yielding this many frames. None (default) = unbounded — runs until the source disconnects or the consumer breaks.

Yields:

numpy.ndarray – Successive frames as (H, W, 3) BGR uint8 arrays. Same convention as OpenCV and video_helper.extract_frames().

Raises:
  • ValueError – If source["kind"] isn’t "camera".

  • FileNotFoundError – If ffmpeg isn’t on PATH.

  • RuntimeError – If ffmpeg exits before the first frame is decoded (typical when the OS denied camera permission or the device is in use by another process).

Return type:

Iterator[ndarray]

Examples

>>> cam = ch.pick_source("camera")
>>> for frame in ch.iter_camera_frames(cam,
...                                    output_width=224, output_height=224,
...                                    max_frames=10):
...     # frame.shape == (224, 224, 3), dtype uint8, BGR.
...     model(frame)