Skip to content

feat: add cross-platform libuvc UVC camera support (Linux + Windows) - #83

Open
mathieucarbou wants to merge 6 commits into
mainfrom
feature/libuvc
Open

feat: add cross-platform libuvc UVC camera support (Linux + Windows)#83
mathieucarbou wants to merge 6 commits into
mainfrom
feature/libuvc

Conversation

@mathieucarbou

@mathieucarbou mathieucarbou commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes #78.

This PR adds support using cameras with libuvc for streaming and control on all platforms.

This PR does not yet remove the existing libvlc (V4L2) camera detect code but just adds on top of it camera support through libuvc so that features can be compared.

So all UVC cameras should be seen several times in the list, and even maybe 3 times on Windows with DxShow.

Example on macOS: UVC camera is discovered through the avcapture (QT) system and through libuvc, but the controls are different.

image

with macOS AVFoundation:

image

with libuvc:

image

@mathieucarbou

Copy link
Copy Markdown
Collaborator Author

Tested on macos ✅

Introduce libuvc-based UVC camera detection and control on Linux and
Windows, alongside the existing V4l2 and DShow paths (kept for testing).

New files:
- Services/LinuxCameraDetect.cs — scans /sys/class/video4linux/, walks
  sysfs to find USB idVendor/idProduct, returns APIType.Uvc cameras
- Services/WindowsUvcCameraDetect.cs — uses SetupAPI to enumerate USB
  Video Class (CC_VIDEO=0x0E) devices, extracts VID/PID from hardware IDs
- Libraries/libusb/win/{x64,arm64}/build.sh — download libusb-1.0.dll
  via vcpkg at build time

Changes:
- CameraControlService: dispatch Set/SetAuto/GetCameraList to the new
  LinuxCameraDetect or WindowsUvcCameraDetect for APIType.Uvc cameras
- UvcFrameSource.OpenDevice: guard macOS IOKit kernel driver detach
  with OperatingSystem.IsMacOS(); skip it on Linux/Windows
- UvcFrameSource.CloseDevice, TryRecoverUvcDevice: macOS-only kernel
  driver restore
- CollimationCircles.csproj: add CopyLibUsbWin, CopyLibUvcWin,
  CopyLibUvcLinux MSBuild targets
- .github/workflows/build-and-release.yml: copy libusb + libuvc
  binaries on Windows and Linux during publish

refactor: standardize UVC file naming and extract macOS UVC detection

- Rename LinuxCameraDetect.cs → UvcCameraDetectLinux.cs
- Rename WindowsUvcCameraDetect.cs → UvcCameraDetectWindows.cs
- Create UvcCameraDetectMac.cs in Services/Uvc/ with UVC-specific
  detection (system_profiler VID/PID parsing) and control routing
- Update MacOSCameraDetect.cs to only handle QTCapture cameras
  (UVC cameras now detected by UvcCameraDetectMac)
- Update CameraControlService.cs to use new class names and add
  macOS UVC detection via UvcCameraDetectMac
@mathieucarbou

Copy link
Copy Markdown
Collaborator Author

@sajmons : this PR is in draft because still a work in progress (need to remove V4L2 code and libvlc), but would you be able to test on your end before the removal?

@sajmons

sajmons commented Jul 4, 2026

Copy link
Copy Markdown
Owner

@mathieucarbou I have made a small fix for detecting UVC cameras on Windows with libusb.
But streaming is not working; I guess libuvc.dll is not properly compiled. There are missing csproj targets for making libuvc available at runtime. I don't have enough experience with native libraries to fix this.

@mathieucarbou

mathieucarbou commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator Author

@mathieucarbou I have made a small fix for detecting UVC cameras on Windows with libusb. But streaming is not working; I guess libuvc.dll is not properly compiled. There are missing csproj targets for making libuvc available at runtime. I don't have enough experience with native libraries to fix this.

Ok! I will do some deeper testing with VMs.

The problem is that libuvc compilation for windows produces a small dll of about 11ko which is just a stub and exports nothing. So there is something wrong in the compilation.

Introduce libuvc-based UVC camera detection and control on Linux and
Windows, alongside the existing V4l2 and DShow paths (kept for testing).

New files:
- Services/LinuxCameraDetect.cs — scans /sys/class/video4linux/, walks
  sysfs to find USB idVendor/idProduct, returns APIType.Uvc cameras
- Services/WindowsUvcCameraDetect.cs — uses SetupAPI to enumerate USB
  Video Class (CC_VIDEO=0x0E) devices, extracts VID/PID from hardware IDs
- Libraries/libusb/win/{x64,arm64}/build.sh — download libusb-1.0.dll
  via vcpkg at build time

Changes:
- CameraControlService: dispatch Set/SetAuto/GetCameraList to the new
  LinuxCameraDetect or WindowsUvcCameraDetect for APIType.Uvc cameras
- UvcFrameSource.OpenDevice: guard macOS IOKit kernel driver detach
  with OperatingSystem.IsMacOS(); skip it on Linux/Windows
- UvcFrameSource.CloseDevice, TryRecoverUvcDevice: macOS-only kernel
  driver restore
- CollimationCircles.csproj: add CopyLibUsbWin, CopyLibUvcWin,
  CopyLibUvcLinux MSBuild targets
- .github/workflows/build-and-release.yml: copy libusb + libuvc
  binaries on Windows and Linux during publish

refactor: standardize UVC file naming and extract macOS UVC detection

- Rename LinuxCameraDetect.cs → UvcCameraDetectLinux.cs
- Rename WindowsUvcCameraDetect.cs → UvcCameraDetectWindows.cs
- Create UvcCameraDetectMac.cs in Services/Uvc/ with UVC-specific
  detection (system_profiler VID/PID parsing) and control routing
- Update MacOSCameraDetect.cs to only handle QTCapture cameras
  (UVC cameras now detected by UvcCameraDetectMac)
- Update CameraControlService.cs to use new class names and add
  macOS UVC detection via UvcCameraDetectMac
@mathieucarbou

mathieucarbou commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator Author

@mathieucarbou I have made a small fix for detecting UVC cameras on Windows with libusb.

@SimonSander : where is your fix btw ? I don't see any commit on main or in this branch ?

@mathieucarbou

Copy link
Copy Markdown
Collaborator Author

@SimonSander FYI, I am currently working on fixing the libuvc github workflow for windows thanks to these refs:

Apparently people have succeeded with MingW.

@mathieucarbou

Copy link
Copy Markdown
Collaborator Author

@SimonSander CI tasks now can build libuvc for win correctly with MingW.

See: https://github.com/sajmons/CollimationCircles/actions/workflows/build-libuvc.yml

I have updated the libs in main branch.

@mathieucarbou
mathieucarbou force-pushed the feature/libuvc branch 2 times, most recently from 2fc220d to ef6d438 Compare July 6, 2026 15:08
Introduce libuvc-based UVC camera detection and control on Linux and
Windows, alongside the existing V4l2 and DShow paths (kept for testing).

New files:
- Services/LinuxCameraDetect.cs — scans /sys/class/video4linux/, walks
  sysfs to find USB idVendor/idProduct, returns APIType.Uvc cameras
- Services/WindowsUvcCameraDetect.cs — uses SetupAPI to enumerate USB
  Video Class (CC_VIDEO=0x0E) devices, extracts VID/PID from hardware IDs
- Libraries/libusb/win/{x64,arm64}/build.sh — download libusb-1.0.dll
  via vcpkg at build time

Changes:
- CameraControlService: dispatch Set/SetAuto/GetCameraList to the new
  LinuxCameraDetect or WindowsUvcCameraDetect for APIType.Uvc cameras
- UvcFrameSource.OpenDevice: guard macOS IOKit kernel driver detach
  with OperatingSystem.IsMacOS(); skip it on Linux/Windows
- UvcFrameSource.CloseDevice, TryRecoverUvcDevice: macOS-only kernel
  driver restore
- CollimationCircles.csproj: add CopyLibUsbWin, CopyLibUvcWin,
  CopyLibUvcLinux MSBuild targets
- .github/workflows/build-and-release.yml: copy libusb + libuvc
  binaries on Windows and Linux during publish

refactor: standardize UVC file naming and extract macOS UVC detection

- Rename LinuxCameraDetect.cs → UvcCameraDetectLinux.cs
- Rename WindowsUvcCameraDetect.cs → UvcCameraDetectWindows.cs
- Create UvcCameraDetectMac.cs in Services/Uvc/ with UVC-specific
  detection (system_profiler VID/PID parsing) and control routing
- Update MacOSCameraDetect.cs to only handle QTCapture cameras
  (UVC cameras now detected by UvcCameraDetectMac)
- Update CameraControlService.cs to use new class names and add
  macOS UVC detection via UvcCameraDetectMac
@mathieucarbou

Copy link
Copy Markdown
Collaborator Author

@SimonSander : I have updated this branch.
you can get the latest version by doing:

# refresh git repo metadata
> git fetch
# set your local branch content to origin/feature/libuvc
> git reset --hard origin/feature/libuvc

The DLL is loading correctly but I get no stream:

2026-07-06 17:27:58.8890: INFO PlayPause clicked: camera='ocal4.1', APIType=Uvc, FullAddress='uvc-direct://60324:4867'
2026-07-06 17:27:58.8916: INFO Starting UVC direct stream for camera 'ocal4.1' (VID=60324 PID=4867)
2026-07-06 17:27:58.8916: INFO UvcFrameSource.StartAsync: begin for 'ocal4.1' (VID=60324 PID=4867)
2026-07-06 17:27:58.8916: DEBUG OpenDevice: begin VID=60324 PID=4867
2026-07-06 17:27:58.9412: DEBUG OpenDevice: uvc_init success, ctx=2172520619824
2026-07-06 17:27:58.9527: DEBUG OpenDevice: uvc_open attempt 0 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.0191: DEBUG OpenDevice: uvc_open attempt 1 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.0911: DEBUG OpenDevice: uvc_open attempt 2 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.1607: DEBUG OpenDevice: uvc_open attempt 3 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.2213: DEBUG OpenDevice: uvc_open attempt 4 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.2918: DEBUG OpenDevice: uvc_open attempt 5 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.3538: DEBUG OpenDevice: uvc_open attempt 6 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.4261: DEBUG OpenDevice: uvc_open attempt 7 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.4950: DEBUG OpenDevice: uvc_open attempt 8 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.5637: DEBUG OpenDevice: uvc_open attempt 9 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.6276: DEBUG OpenDevice: uvc_open attempt 10 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.6981: DEBUG OpenDevice: uvc_open attempt 11 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.7692: DEBUG OpenDevice: uvc_open attempt 12 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.8359: DEBUG OpenDevice: uvc_open attempt 13 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.9035: DEBUG OpenDevice: uvc_open attempt 14 failed: ERROR_NOT_FOUND
2026-07-06 17:27:59.9743: DEBUG OpenDevice: uvc_open attempt 15 failed: ERROR_NOT_FOUND
2026-07-06 17:28:00.0453: DEBUG OpenDevice: uvc_open attempt 16 failed: ERROR_NOT_FOUND
2026-07-06 17:28:00.1176: DEBUG OpenDevice: uvc_open attempt 17 failed: ERROR_NOT_FOUND
2026-07-06 17:28:00.1916: DEBUG OpenDevice: uvc_open attempt 18 failed: ERROR_NOT_FOUND
2026-07-06 17:28:00.2610: DEBUG OpenDevice: uvc_open attempt 19 failed: ERROR_NOT_FOUND
2026-07-06 17:28:00.3182: ERROR uvc_open failed after 20 attempts: ERROR_NOT_FOUND
2026-07-06 17:28:00.3182: ERROR Failed to open UVC device for 'ocal4.1' (VID=60324 PID=4867)
2026-07-06 17:28:00.3182: ERROR Failed to start UVC direct stream for camera 'ocal4.1'
2026-07-06 17:28:00.3182: TRACE MediaPlayer closed
2026-07-06 17:28:00.3182: TRACE Closed web camera stream window
2026-07-06 17:28:12.5841: INFO Saving application state to 'C:\Users\mat\AppData\Local\CollimationCircles\appstate.json'

This is the classic Windows problem described in issues #12 and #136. The DLL works correctly (uvc_init succeeds, uvc_find_device finds the camera), but uvc_open fails with ERROR_NOT_FOUND because the default Windows UVC driver has exclusive access to the camera's USB interfaces.

On macOS we detach the kernel driver via IOKit, on Linux libusb detaches the driver automatically, but on Windows you must manually replace the driver using Zadig:

Download Zadig
Options → List All Devices
Select the camera (e.g. ocal4.1)
Replace the driver with WinUSB (or libusbK)
Click "Replace Driver"
After this, uvc_open should work (I said should because this procedure does not work on Windows ARM).

However, the camera will no longer be available in other Windows applications (OBS, Camera app, etc.) as long as the WinUSB driver is installed.

This is a fundamental limitation of Windows — not a code bug. It is documented in the pupil-labs/pyuvc WINDOWS_USER.md and in all the libuvc Windows issues.

This driver replacement is not possible on ARM64 since there is no arm drivers for that.

=> So I propose we leave this PR as draft, we leave the issue open, we only use UVC camera support throuhg libuvc on macOS since this is the only ways to have UVC cameras working on macOS.

Side note: on windoss arm64 I am not able to open cameras with DShow also:

2026-07-06 17:53:52.1376: INFO PlayPause clicked: camera='ocal4.1', APIType=Dshow, FullAddress='dshow://'
2026-07-06 17:53:58.1719: INFO LibVLC initialized.
2026-07-06 17:53:58.1719: INFO Playing web camera stream: 'dshow://'
2026-07-06 17:53:58.1871: TRACE MediaPlayer opening
2026-07-06 17:53:58.1871: TRACE MediaPlayer closed
2026-07-06 17:53:58.2800: INFO StreamView opened. MediaPlayer IsPlaying=False, CropGeometry='', Scale=0
2026-07-06 17:53:58.2800: INFO UpdateImageTransform: zoom<=1, reset VideoView to stretch (zoom=1,00).
2026-07-06 17:53:58.2800: TRACE Opened web camera stream window
2026-07-06 17:53:58.3647: TRACE Closed web camera stream window

That being done, my next step will be to tryout the new added features features in v5 during next time I will collimate.

@sajmons

sajmons commented Jul 6, 2026

Copy link
Copy Markdown
Owner

@mathieucarbou when referencing me, please use @sajmons not @SimonSander. Thank you!

@sajmons
sajmons marked this pull request as ready for review July 6, 2026 17:54

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

https://github.com/sajmons/CollimationCircles/blob/b638ae4a367cf5396a275170a258ed1f50c24d98/Services/Uvc/UvcCameraDetectWindows.cs#L160
P2 Badge Preserve distinct devices with the same VID/PID

When two physical UVC cameras of the same model are connected on Windows, they share the same vendor/product IDs, so this check drops every camera after the first even though instanceId was just collected as a per-device path. That leaves users unable to select the second camera from the UVC list; de-duplication should use the device instance/interface identity instead of only VID/PID.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

'linux-x64' {
Copy-Item -Force './CollimationCircles/Libraries/ASI_linux_mac_SDK_V1.41/lib/x64/libASICamera2.so*' $output
# Copy libuvc for UVC camera control and streaming via libuvc on Linux
Copy-Item -Force './CollimationCircles/Libraries/libuvc/linux/x64/libuvc.so' $output

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Bundle libusb with Linux libuvc artifacts

For the Linux release artifacts this copies only libuvc.so, but the checked-in Linux libuvc.so has a dynamic NEEDED dependency on libusb-1.0.so.0 (I verified with readelf -d, and ldd reports it as not found in this environment). On systems without a system libusb package, the first DllImport("libuvc") will fail before any UVC camera can open, so the self-contained Linux builds won't actually provide the new UVC path unless libusb is packaged or libuvc is linked statically.

Useful? React with 👍 / 👎.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace libvlc with libuvc for global camera streaming and support in the project.

2 participants