1. Quick Start & Installation¶
1.1 Installation¶
System requirements¶
duvc-ctl is a Windows-only library that relies on the DirectShow multimedia framework. It requires:
Windows: Windows 7 SP1 or later. DirectShow is included with all modern Windows versions.
Python: 3.8 or later (binary wheels support 3.8–3.12).
C++ toolchain (for building from source): Visual Studio 2019+ or Build Tools, CMake 3.16+, and a C++17-compatible compiler.
Installation from PyPI¶
The easiest way to get started is to install the prebuilt binary wheel:
pip install duvc-ctl
Verify the installation:
python -c "import duvcctl; print(duvcctl.__version__)"
Binary wheels are available for Windows on Python 3.8–3.12 (64-bit). If your Python version or architecture differs, you’ll need to build from source.
Building from source¶
If a prebuilt wheel is not available for your configuration, or if you want to build with custom flags, build from source using CMake.
Prerequisites:
Python development headers (included with most Python distributions).
CMake 3.16 or later.
A C++ compiler: Visual Studio 2019 or later, or Build Tools for Visual Studio.
Git.
Build steps:
git clone https://github.com/allanhanan/duvc-ctl.git
cd duvc-ctl
cmake -B build -G "Visual Studio 17 2022" -A x64 -DDUVCBUILDPYTHON=ON
cmake --build build --config Release
cmake --install build --config Release
Replace “Visual Studio 17 2022” with your Visual Studio version if different (e.g., “Visual Studio 16 2019”).
CMake configuration options:
Common options to pass to the first cmake command:
DUVCBUILDSHARED(ON/OFF): Build a shared core library. Default: ON.DUVCBUILDSTATIC(ON/OFF): Build a static core library. Default: ON.DUVCBUILDCAPI(ON/OFF): Build the C API for bindings. Default: ON.DUVCBUILDCLI(ON/OFF): Build the command-line tool. Default: ON.DUVCBUILDPYTHON(ON/OFF): Build Python bindings. Default: ON.DUVCBUILDTESTS(ON/OFF): Build tests. Default: OFF.DUVCBUILDEXAMPLES(ON/OFF): Build examples. Default: OFF.
For example, to build only the Python bindings:
cmake -B build -G "Visual Studio 17 2022" -A x64 \
-DDUVCBUILDSHARED=ON \
-DDUVCBUILDSTATIC=OFF \
-DDUVCBUILDCAPI=OFF \
-DDUVCBUILDCLI=OFF \
-DDUVCBUILDPYTHON=ON
Editable installation (development)¶
For development work on the source code, install in editable mode:
pip install -e .
This compiles the extension in place and allows you to edit Python files without reinstalling. The underlying C++ code is compiled using scikit-build-core with pybind11. Ensure your toolchain is installed and on PATH before running this command.
Wheel repair and distribution¶
Binary wheels are built in CI and repaired on Windows using delvewheel to ensure all runtime dependencies (including required DLLs) are packaged correctly. This minimizes end-user setup complexity when installing from PyPI.
Using cibuildwheel¶
cibuildwheel uses the configured pyproject.toml that takes care of the cmake config, building and repairing wheel automatically
python -m cibuildwheel --output-dir dist
Verification¶
After installation, confirm that the library can enumerate devices:
import duvcctl as duvc
print("duvc-ctl version:", duvc.__version__)
devices = duvc.list_devices()
print("Devices found:", len(devices))
for device in devices:
print(f" - {device.name}")
If no devices are found, verify that:
A camera is physically connected.
The camera appears in Device Manager (devmgmt.msc).
The camera works in the built-in Windows Camera app.
Troubleshooting¶
ImportError or missing DLLs:
Install the Microsoft Visual C++ Redistributable for your Visual Studio version.
Verify that your Python is 64-bit if your Windows is 64-bit (or both 32-bit).
Build errors during pip install -e .:
Confirm that CMake is installed and visible in PATH:
cmake --version.Confirm your C++ toolchain is on PATH. For Visual Studio, run the build in a Visual Studio Developer Command Prompt.
Delete the build/ directory and try again:
rmdir /s /q build && pip install -e ..
CMake not found:
Add CMake to your system PATH, or specify the full path:
pip install -e . --config-settings=cmake.cmake-executable=C:\path\to\cmake.exe.
No devices appear:
Check the device is recognized by Windows:
wmic logicaldisk get nameor open Device Manager (devmgmt.msc).Test the camera with the Windows Camera app to rule out driver issues.
Enable debug logging to see what the library detects.
Platform detection warnings:
The module checks for Windows at import time. Non-Windows platforms will raise an ImportError or warning. duvc-ctl is Windows-only.
1.2 Your First Program¶
duvc-ctl offers two distinct APIs for different needs. The Pythonic API is simpler and better for quick scripts and beginners. The Result-Based API provides explicit error handling without exceptions and is suited for production systems. Both work on the same underlying C++ engine, so you can mix them as needed.
Choosing your approach¶
Use Case |
API |
Why |
|---|---|---|
Quick script, single camera |
Pythonic |
Automatic device selection, exceptions, minimal code |
Production application |
Result-based |
Explicit error handling, detailed diagnostics, no exceptions |
Learning the library |
Pythonic |
Simpler syntax, clearer intent, beginner-friendly |
Detailed error recovery |
Result-based |
Access error codes and recovery suggestions |
Concurrent camera access |
Either |
Both are thread-safe; Result-based gives better control |
Pythonic API - Quick Start¶
The Pythonic API uses property-based access and automatic device management:
import duvc_ctl as duvc
# Connect to first available camera
with duvc.CameraController() as cam:
# Simple property read/write
cam.brightness = 75
print(f"Brightness: {cam.brightness}")
# Direct method calls
cam.pan = 0 # Center camera
cam.tilt = -10 # Tilt down
print(f"Pan: {cam.pan}°, Tilt: {cam.tilt}°")
# Relative movement
cam.pan_relative(15) # Move 15° right
cam.zoom_relative(1) # Zoom in
Find a specific camera:
import duvc_ctl as duvc
try:
# Find by name pattern (case-insensitive substring)
cam = duvc.find_camera("Logitech")
cam.brightness = 80
cam.close()
except duvc.DeviceNotFoundError:
print("Camera not found")
Connect using Device object
The most explicit and reliable method:
import duvc_ctl as duvc
#Enumerate all devices
devices = duvc.list_devices()
if devices:
# Show available cameras
for i, device in enumerate(devices):
print(f"[{i}] {device.name} - {device.path}")
# Connect to first device
with duvc.CameraController(device=devices) as cam:
cam.brightness = 75
print(f"Connected to: {cam.device_name}")
else:
print("No cameras found")
Why use Device objects?
Full control over which camera to use
Access to device metadata (name, path, ID)
Works seamlessly with
list_devices()enumerationRequired for advanced scenarios (multi-camera, reconnection)
List available properties:
import duvc_ctl as duvc
with duvc.CameraController() as cam:
# Enumerate properties
supported = cam.get_supported_properties()
print("Video properties:")
for prop in supported['video']:
value = cam.get(prop)
print(f" {prop}: {value}")
print("Camera properties:")
for prop in supported['camera']:
value = cam.get(prop)
print(f" {prop}: {value}")
Batch operations:
import duvc_ctl as duvc
with duvc.CameraController() as cam:
# Set multiple properties at once
settings = {
'brightness': 75,
'contrast': 65,
'saturation': 80
}
results = cam.set_multiple(settings)
# Get multiple properties
values = cam.get_multiple(['brightness', 'contrast', 'saturation'])
Handle errors:
import duvc_ctl as duvc
with duvc.CameraController() as cam:
try:
cam.brightness = 999 # Out of range
except duvc.InvalidValueError as e:
print(f"Invalid value: {e}")
except duvc.PropertyNotSupportedError:
print("Brightness not supported on this camera")
Result-Based API - Production Use¶
The Result-Based API returns Result types instead of raising exceptions:
import duvc_ctl as duvc
# List devices
devices = duvc.list_devices()
if not devices:
print("No cameras found")
exit(1)
device = devices[^0]
# Open camera with explicit error handling
camera_result = duvc.open_camera(device)
if camera_result.is_ok():
camera = camera_result.value()
# Get property - returns Result
pan_result = camera.get(duvc.CamProp.Pan)
if pan_result.is_ok():
setting = pan_result.value()
print(f"Pan: {setting.value} ({setting.mode})")
else:
print(f"Error: {pan_result.error().description()}")
else:
print(f"Failed to open camera: {camera_result.error().description()}")
Set properties with range checking:
import duvc_ctl as duvc
devices = duvc.list_devices()
if devices:
device = devices[^0]
camera_result = duvc.open_camera(device)
if camera_result.is_ok():
camera = camera_result.value()
# Get range before setting
range_result = camera.get_range(duvc.CamProp.Pan)
if range_result.is_ok():
prop_range = range_result.value()
print(f"Pan range: {prop_range.min} to {prop_range.max}")
# Set to center
center = duvc.PropSetting(0, duvc.CamMode.Manual)
set_result = camera.set(duvc.CamProp.Pan, center)
if set_result.is_ok():
print("Pan centered successfully")
else:
print(f"Failed to set Pan: {set_result.error().description()}")
Get device capabilities:
import duvc_ctl as duvc
devices = duvc.list_devices()
if devices:
caps_result = duvc.get_device_capabilities(devices[^0])
if caps_result.is_ok():
capabilities = caps_result.value()
print("Supported camera properties:")
for prop in capabilities.supported_camera_properties():
print(f" - {duvc.to_string(prop)}")
print("Supported video properties:")
for prop in capabilities.supported_video_properties():
print(f" - {duvc.to_string(prop)}")
API Comparison Table¶
Feature |
Pythonic |
Result-Based |
|---|---|---|
Device selection |
Automatic (first device or by name) |
Manual (explicit Device passed) |
Error handling |
Standard Python exceptions |
Result types without exceptions |
Code verbosity |
Minimal |
Explicit |
Learning curve |
Easy |
Moderate |
Production ready |
Yes |
Yes |
Error diagnostics |
Basic error message |
Detailed error codes and descriptions |
Thread-safe |
Yes |
Yes |
Performance |
Slightly lower (exception handling) |
Slightly higher (no exception overhead) |
Next Steps¶
For simple scripts or learning, start with the Pythonic API above.
For production systems that need detailed error recovery, migrate to the Result-Based API.
See the Architecture section for a detailed comparison of both APIs and their design rationale.
Check Common Patterns & Recipes for multi-camera control, bulk operations, and advanced scenarios.
1.3 Platform Requirements & Compatibility¶
Windows support¶
duvc-ctl is designed for Windows only. It does not run on Linux, macOS, or other operating systems.
Supported Windows versions:
Windows 7 SP1 and later (Windows 7, 8, 8.1, 10, 11, and Server editions)
DirectShow, the multimedia framework used by duvc-ctl, is a standard component of all supported Windows versions
Attempting to import duvc-ctl on non-Windows platforms will raise an ImportError at module load time:
# On Linux or macOS:
import duvc_ctl
# ImportError: duvc-ctl is only supported on Windows
Python version requirements¶
Minimum: Python 3.8
Recommended: Python 3.9 or later
Maximum tested: Python 3.12
The library uses pybind11 for C++ bindings and has no external Python dependencies beyond the standard library. Binary wheels are built for Python 3.8, 3.9, 3.10, 3.11, and 3.12 on Windows (64-bit).
Check your Python version:
python --version
python -c "import struct; print('64-bit' if struct.calcsize('P') == 8 else '32-bit')"
Architecture compatibility¶
The library is built for 64-bit (x64) Windows only.
Architecture |
Status |
Notes |
|---|---|---|
x64 (64-bit) |
Supported |
Recommended; all wheels use this |
x86 (32-bit) |
Partially Supported |
No wheels built; compilation required |
ARM64 |
Not supported |
Windows on ARM is not targeted |
If you are on 64-bit Windows and have 32-bit Python, install 64-bit Python instead. Mixing 32-bit Python with 64-bit Windows is not recommended for this library.
Verify your Python architecture:
import platform
print(platform.architecture()) # Should show ('64bit', 'WindowsPE')
Runtime dependencies¶
Beyond Windows and Python, duvc-ctl requires:
DirectShow: Built into all supported Windows versions; no installation needed.
Visual C++ Redistributable: If installing from a prebuilt wheel, the matching MSVC runtime may be required. Modern wheels use delvewheel to bundle necessary DLLs, reducing this requirement. If you get a DLL error at runtime, install the Microsoft Visual C++ Redistributable for your Visual Studio version.
USB driver support: Windows manages UVC camera drivers automatically for standard webcams. Vendor-specific cameras may require additional drivers (check Device Manager).
Behavior differences by Windows version¶
Most behavior is consistent across supported Windows versions. However, there are minor differences:
Feature |
Win7 SP1 |
Win8+ |
Notes |
|---|---|---|---|
Device enumeration |
Yes |
Yes |
DirectShow device discovery works identically |
Property access |
Yes |
Yes |
IAMCameraControl and IAMVideoProcAmp interfaces available |
Hotplug detection |
Yes |
Yes |
Device change notifications supported |
DLL loading |
Yes |
Yes |
DirectShow is present on all versions |
32-bit Python on 64-bit Windows¶
While possible, running 32-bit Python on 64-bit Windows with duvc-ctl is not officially supported. If you must use 32-bit Python:
Build the extension from source (no prebuilt 32-bit wheel exists).
Ensure your C++ toolchain is configured for 32-bit builds.
Expect potential compatibility issues with device drivers and DirectShow.
We recommend using 64-bit Python on 64-bit Windows.
Import-time checks¶
When imported, duvc-ctl performs platform detection and will warn or error if:
You are not on Windows (raises
ImportError)Your Python architecture does not match your Windows architecture (warning)
DirectShow cannot be detected or accessed (warning, but import succeeds)
These checks help catch configuration issues early:
# Successful import (on Windows 64-bit with Python 3.8+):
import duvc_ctl as duvc
print(f"Module loaded: {duvc.__version__}")
# Failed import (on Linux):
import duvc_ctl
# ImportError: duvc-ctl is only supported on Windows
Forward compatibility¶
duvc-ctl targets stability across Windows versions. However:
Future Windows releases may deprecate or alter DirectShow APIs, which could affect the library. However MediaFoundation support is planned to be added in the future.
Binary wheels are tested on Windows 10 and 11; older versions (Windows 7, 8) are supported but receive less frequent testing.
Python 3.13+ has been tested, However due do CI/CD limitations, prebuilt wheels are not available; if you need it, build from source.
For the latest supported configurations, check the project README or CI/CD matrix on GitHub.