Skip to content

fix(server): initialize COM for Windows camera discovery - #99

Open
amrltqt wants to merge 1 commit into
huggingface:mainfrom
amrltqt:fix/windows-camera-com-initialization
Open

fix(server): initialize COM for Windows camera discovery#99
amrltqt wants to merge 1 commit into
huggingface:mainfrom
amrltqt:fix/windows-camera-com-initialization

Conversation

@amrltqt

@amrltqt amrltqt commented Aug 10, 2026

Copy link
Copy Markdown

Context

I use LeLab to test and iterate on my robot configurations. While setting it up on Windows, I ran into this issue when trying to use the camera configuration flow in the web interface.

The problem was reproducible with two USB webcams and occurred during camera discovery, before recording started. After initializing COM in the worker thread, the cameras were detected normally and their DirectShow names were returned correctly.

I hope this makes the Windows setup experience a little smoother for other LeLab users as well.

Background

On Windows, LeLab鈥檚 /available-cameras endpoint runs _windows_cameras() as a synchronous FastAPI route. Starlette executes synchronous routes in a worker thread.

The Windows implementation uses pygrabber to enumerate DirectShow devices and return their real friendly names. These names are required by the frontend to match the server-side camera index with the browser鈥檚 MediaDeviceInfo.deviceId.

Root cause

COM initialization is apartment/thread-local on Windows. Initializing COM in the main Python thread does not initialize it in a FastAPI worker thread.

pygrabber calls DirectShow from that worker thread without first initializing COM, which raises:

WinError -2147221008: CoInitialize has not been called

LeLab then falls back to probing camera indices with OpenCV using the DirectShow backend (CAP_DSHOW). That fallback runs in the same uninitialized thread, so OpenCV also fails with warnings such as:

VIDEOIO(DSHOW): backend is generally available but can't be used to capture by index

This caused LeLab to lose the real camera names and prevented reliable camera discovery from the web UI.

Fix

Initialize COM for the current worker thread before calling pygrabber or probing DirectShow cameras, and always call CoUninitialize() when the operation finishes.

The initialization is kept in a small context manager so that:

  • COM is initialized in the thread that actually uses DirectShow;
  • cleanup is guaranteed through finally;
  • the existing graceful fallback remains available if comtypes is not installed or COM initialization fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant