capture_helper.sources module
capture_helper.sources
Cross-platform capture-device enumeration via ffmpeg’s
-list_devices mode. We shell out and parse stderr because there is
no clean cross-platform Python API for this — the per-OS alternatives
(pyobjc-AVFoundation on macOS, v4l2-python on Linux,
pywin32 / dshow on Windows) are heavier, harder to install, and
less consistent than just asking ffmpeg.
Limitations
ffmpeg -list_devicesis stderr-based and the line format drifts between ffmpeg versions and platforms. We parse defensively and return[]rather than raising when the format surprises us.Returns devices with the names ffmpeg reports, including any trailing platform-specific bracketed metadata.
Screen / window sources are NOT exposed in v0.0.1 — they need a different ffmpeg input format per OS (
avfoundationscreen index on macOS,x11grab/waylandon Linux,gdigrabon Windows) and the abstraction is best designed once we have a real iter function consuming them. v0.2.0 target.
Usage Example
>>> from capture_helper.sources import list_sources, pick_source, ffmpeg_input_args
>>> for s in list_sources():
... print(s["kind"], s["index"], s["name"], s["driver"])
>>> cam = pick_source("camera", name_substring="FaceTime")
>>> ffmpeg_input_args(cam)
['-f', 'avfoundation', '-i', '0:none']
- class capture_helper.sources.Source[source]
Bases:
TypedDictOne capture device, normalised across platforms.
Keys
- kind
"camera"|"microphone" Audio / video distinction.
- namestr
Human-readable name as reported by the OS driver. Use this when passing to a future
iter_camera_frames/iter_mic_audio— the per-OS ffmpeg input string is built internally.- indexint
Numeric device index in ffmpeg’s listing (0-based). Some OS backends only accept the index; others accept name OR index.
- platformstr
"darwin"/"linux"/"windows"— useful for callers that branch on the underlying driver (avfoundation / v4l2 / dshow / pulse).- driverstr
ffmpeg input format flag —
"avfoundation"/"v4l2"/"dshow"/"pulse"/"alsa".
- kind
- capture_helper.sources.ffmpeg_input_args(source)[source]
Build the ffmpeg
-f <driver> -i <spec>argument pair forsource.Encapsulates the per-OS quirks so
capture_helper.cameraandcapture_helper.micdon’t have to know about them:avfoundation(macOS) addresses devices as"<video_idx>:<audio_idx>"where"none"opts out of the other track.v4l2(Linux) uses the device path (/dev/videoN) reported bylist_sources().pulse(Linux) andalsa(Linux) take the source/device name.dshow(Windows) prefixes the device name withvideo=oraudio=.
- Parameters:
source (Source) – A device dict returned by
list_sources()/pick_source().- Returns:
Two elements:
["-f", "<driver>"]followed by["-i", "<spec>"]— ready to splice into an ffmpeg command line.- Return type:
- Raises:
ValueError – If the source’s driver is unknown to this helper.
- capture_helper.sources.list_sources(kind=None)[source]
Enumerate available capture devices on the current OS.
- Parameters:
kind (
"camera"|"microphone"| None) – Filter to one kind.None(default) returns both.- Returns:
Possibly empty if ffmpeg is missing or the OS driver returns nothing parseable. Never raises.
- Return type:
Examples
>>> from capture_helper import list_sources >>> for s in list_sources("microphone"): ... print(f"[{s['index']}] {s['name']} (driver={s['driver']})")
- capture_helper.sources.pick_source(kind, *, name_substring=None, index=None)[source]
Pick a single capture device matching the given constraints.
Runs
list_sources()forkindand applies each non-None filter as a hard predicate. Returns the first remaining candidate (OS-listing order — usually “built-in first, peripherals after”). RaisesValueErrorif nothing matches.- Parameters:
kind (
"camera"|"microphone") – Which kind of device to pick.name_substring (str, optional) – Case-insensitive substring filter against
Source["name"]. Useful to disambiguate when several devices of the same kind are present ("BlackHole","USB","FaceTime", …).index (int, optional) – Exact match against
Source["index"]. When the OS reports stable indices (avfoundation, dshow), this picks a specific device unambiguously.
- Returns:
The chosen device.
- Return type:
- Raises:
ValueError – If no device matches (either the catalog is empty, or every candidate is filtered out by the constraints).
Examples
>>> from capture_helper import pick_source >>> cam = pick_source("camera") # first available camera >>> mic = pick_source("microphone", name_substring="BlackHole") >>> usb_cam = pick_source("camera", index=1)