DirectShow UVC Camera Control Library
Project description
duvc-ctl
duvc-ctl is a lightweight Python library for controlling USB Video Class (UVC) camera properties on Windows using the native DirectShow API.
It exposes camera and video properties (PTZ, focus, exposure, brightness, etc.), supports device monitoring with hotplug detection, and provides access to vendor-specific property sets — all without vendor SDKs, extra drivers, or dependencies.
Key Features
- Simple Pythonic API: Property-based access (
cam.brightness = 80) with automatic device management and beginner-friendly error handling - Advanced Result-Based API: Explicit error handling with Result types for detailed control in production code
- Camera & Video Properties: Get/set PTZ controls, exposure, focus, white balance, gain, and other IAMCameraControl/IAMVideoProcAmp properties
- Device Monitoring: List devices, check connectivity, and handle hotplug events
- Vendor Extensions: Access custom property sets via GUID
- Multiple Error Handling: Simple exceptions, Result types, or safe tuple returns
- Thread-Safe: Safe for use in multi-threaded applications
Works on Windows 7+ with Python 3.8+. Suitable for computer vision, robotics, video streaming, and automation projects requiring precise USB camera control.
Installation
pip install duvc-ctl
Two APIs, One Library
duvc-ctl provides two complementary APIs for different use cases:
1. Pythonic API (Recommended for Most Users)
Use when: You want simple, readable code with automatic device selection and beginner-friendly errors.
Simple property-based control with context manager support:
import duvc_ctl as duvc
# Connect to first available camera
with duvc.CameraController() as cam:
cam.brightness = 80 # Simple assignment
cam.pan += 10 # Relative adjustment
print(f"Zoom: {cam.zoom}") # Simple property read
# Reset to defaults
cam.reset_to_defaults()
Or find a specific camera:
cam = duvc.find_camera("Logitech")
cam.brightness = 80
cam.close()
2. Result-Based API (Advanced)
Use when: You need explicit error handling, detailed diagnostics, or building production systems.
Result types provide detailed error information without exceptions:
import duvc_ctl as duvc
devices = duvc.list_devices()
if not devices:
print("No cameras found")
else:
device = devices[0]
camera_result = duvc.open_camera(device)
if camera_result.is_ok():
camera = camera_result.value()
# Set property with explicit error checking
setting = duvc.PropSetting(100, duvc.CamMode.Manual)
result = camera.set(duvc.CamProp.Pan, setting)
if result.is_ok():
print("Pan set successfully")
else:
error = result.error()
print(f"Error: {error.description()}")
else:
print(f"Failed to open camera: {camera_result.error().description()}")
API Comparison
| Feature | Pythonic | Result-Based |
|---|---|---|
| Device selection | Automatic | Manual |
| Error handling | Exceptions | Result types |
| Code verbosity | Minimal | Explicit |
| Learning curve | Easy | Moderate |
| Production ready | Yes | Yes |
| Diagnostics | Basic | Detailed |
Quick Start — Pythonic API
import duvc_ctl as duvc
# List cameras
cameras = duvc.list_cameras()
print(f"Found {len(cameras)} camera(s): {cameras}")
# Connect and control
with duvc.CameraController() as cam:
print(f"Connected to: {cam.device_name}")
# Check supported properties
supported = cam.get_supported_properties()
print(f"Camera properties: {supported['camera']}")
print(f"Video properties: {supported['video']}")
# Video properties
if 'brightness' in supported['video']:
cam.brightness = 75
cam.contrast = 60
print(f"Brightness: {cam.brightness}")
# PTZ properties
if 'pan' in supported['camera']:
cam.pan = 0 # Center
cam.zoom = 100 # 1x zoom
Quick Start — Result-Based API
import duvc_ctl as duvc
devices = duvc.list_devices()
if devices:
device = devices[0]
# Open camera with explicit error handling
result = duvc.open_camera(device)
if result.is_ok():
camera = result.value()
# Get property with range
range_result = camera.get_range(duvc.CamProp.Pan)
if range_result.is_ok():
pan_range = range_result.value()
print(f"Pan range: {pan_range.min} to {pan_range.max}")
# Set to center
center = duvc.PropSetting(0, duvc.CamMode.Manual)
result = camera.set(duvc.CamProp.Pan, center)
API Reference
Pythonic API — Classes
CameraController
High-level camera control with property-based access.
# Connect to first available camera
cam = duvc.CameraController()
# Connect to specific camera
cam = duvc.CameraController(device_index=1)
cam = duvc.CameraController(device_name="Logitech")
# Use as context manager (recommended)
with duvc.CameraController() as cam:
cam.brightness = 80
# Auto-closes camera
# Property access
cam.brightness = 75 # Set
value = cam.brightness # Get
range_info = cam.get_property_range('brightness')
# Device info
print(cam.device_name)
print(cam.is_connected)
# Cleanup
cam.close()
Pythonic API — Device Discovery
# List camera names
cameras = duvc.list_cameras()
# Find camera by name pattern
cam = duvc.find_camera("Logitech")
# Get camera info
info = duvc.get_camera_info(0)
Result-Based API — Classes
Device
Represents a connected USB camera.
device.name # Friendly name
device.path # System path
device.is_valid()
Camera
Opened camera connection with explicit error handling.
result = duvc.open_camera(device)
if result.is_ok():
camera = result.value()
# All operations return Result types
get_result = camera.get(duvc.CamProp.Pan)
set_result = camera.set(duvc.CamProp.Pan, setting)
range_result = camera.get_range(duvc.CamProp.Pan)
PropSetting
Property value and control mode.
setting = duvc.PropSetting(100, duvc.CamMode.Manual)
auto_setting = duvc.PropSetting(0, duvc.CamMode.Auto)
print(setting.value, setting.mode)
PropRange
Property constraints and defaults.
range_result = camera.get_range(duvc.CamProp.Pan)
if range_result.is_ok():
prop_range = range_result.value()
print(prop_range.min, prop_range.max, prop_range.step)
Result Types
# All Result types have the same pattern
result = camera.get(duvc.CamProp.Pan)
if result.is_ok():
value = result.value() # Get the value
else:
error = result.error() # Get the error
print(error.description())
Property Enums
CamProp (Camera Properties)
Pan, Tilt, Roll, Zoom, Exposure, Iris, Focus, Privacy,
ScanMode, Lamp, BacklightCompensation, DigitalZoom
VidProp (Video Properties)
Brightness, Contrast, Hue, Saturation, Sharpness, Gamma,
ColorEnable, WhiteBalance, BacklightCompensation, Gain
Control Modes
CamMode
Auto— Automatic adjustmentManual— Manual control with specific values
Error Types
Pythonic API
Standard Python exceptions:
try:
cam = duvc.CameraController()
except duvc.DeviceNotFoundError:
print("No cameras found")
except duvc.PropertyNotSupportedError:
print("Property not supported")
Result-Based API
Result type checking with no exceptions:
result = duvc.open_camera(device)
if result.is_ok():
camera = result.value()
else:
error = result.error()
code = error.code() # Get error code
description = error.description() # Get description
Exception Types (Both APIs)
DuvcError— Base exception for all errorsDeviceNotFoundError— Camera disconnected or not foundDeviceBusyError— Camera in use by another applicationPropertyNotSupportedError— Property not supported by cameraInvalidValueError— Property value out of rangePermissionDeniedError— Insufficient permissionsSystemError— Windows/DirectShow system error
Examples
Property Enumeration
with duvc.CameraController() as cam:
# Get supported properties
props = cam.get_supported_properties()
print("Camera properties:")
for prop in props['camera']:
print(f" - {prop}")
print("Video properties:")
for prop in props['video']:
print(f" - {prop}")
PTZ Control
with duvc.CameraController() as cam:
# Absolute positioning
cam.pan = 0 # Center
cam.tilt = 0
# Relative movement
cam.pan_relative(15) # Move 15 degrees right
cam.zoom_relative(2) # Zoom in 2 steps
# Get current values
print(f"Pan: {cam.pan}°, Tilt: {cam.tilt}°, Zoom: {cam.zoom}")
Preset Configuration
with duvc.CameraController() as cam:
# Apply built-in preset
cam.apply_preset('daylight')
# Create custom preset
config = {
'brightness': 75,
'contrast': 60,
'saturation': 80
}
cam.create_custom_preset('my_preset', config)
# Apply custom preset
cam.apply_preset('my_preset')
Batch Operations
with duvc.CameraController() as cam:
# Set multiple properties at once
settings = {
'brightness': 80,
'contrast': 65,
'saturation': 75
}
results = cam.set_multiple(settings)
# Get multiple properties at once
values = cam.get_multiple(['brightness', 'contrast', 'saturation'])
Vendor Properties
import uuid
import duvc_ctl as duvc
device = duvc.list_devices()[0]
# Read vendor property
vendor_guid = uuid.UUID('12345678-1234-5678-9abc-123456789abc')
success, data = duvc.read_vendor_property(device, vendor_guid, 1)
if success:
print(f"Property data: {data.hex()}")
# Write vendor property
success = duvc.write_vendor_property(device, vendor_guid, 1, b'\\x01\\x02\\x03')
Error Handling Patterns
# Pythonic API - with exceptions
try:
with duvc.CameraController() as cam:
cam.brightness = 999 # Out of range
except duvc.InvalidValueError as e:
print(f"Invalid value: {e}")
# Result-Based API - explicit checking
result = duvc.open_camera(device)
if result.is_ok():
camera = result.value()
set_result = camera.set(duvc.CamProp.Pan, setting)
if not set_result.is_ok():
print(f"Failed: {set_result.error().description()}")
Requirements
- Windows 10+ (x64)
- Python 3.8+
- No additional drivers or SDKs required
Performance
- Native C++ backend with DirectShow for optimal performance
- Thread-safe for concurrent access
- Minimal overhead — thin Python wrapper over C++ core
Other Interfaces
- C++ Library — Native API for C++ applications
- CLI Tool —
duvc-cli.exefor scripting and automation
Links
- Releases: https://github.com/allanhanan/duvc-ctl/releases
- Documentation: https://allanhanan.github.io/duvc-ctl/sphinx/api/python/index.html
- Source Code: https://github.com/allanhanan/duvc-ctl
- Issues: https://github.com/allanhanan/duvc-ctl/issues
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file duvc_ctl-2.0.1.tar.gz.
File metadata
- Download URL: duvc_ctl-2.0.1.tar.gz
- Upload date:
- Size: 54.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0017ebc3a819ad65d1774bbf0591ce295ada8ba8a8964b2d766da8f71946f308
|
|
| MD5 |
d1f1da8ad4dd915c2550dc884784160b
|
|
| BLAKE2b-256 |
d95f2a8cadc04519d508e0d34d750100217c24b990ab64ae13d5e442fac491c6
|
Provenance
The following attestation bundles were made for duvc_ctl-2.0.1.tar.gz:
Publisher:
build-and-publish.yml on allanhanan/duvc-ctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
duvc_ctl-2.0.1.tar.gz -
Subject digest:
0017ebc3a819ad65d1774bbf0591ce295ada8ba8a8964b2d766da8f71946f308 - Sigstore transparency entry: 804349565
- Sigstore integration time:
-
Permalink:
allanhanan/duvc-ctl@b93951ad0cf8194834fa276c69a95450372ee8a7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/allanhanan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build-and-publish.yml@b93951ad0cf8194834fa276c69a95450372ee8a7 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file duvc_ctl-2.0.1-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: duvc_ctl-2.0.1-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 1.2 MB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c9623b8f8bea31715df32ce9e4ceb19b8eff4abe931bbaf451096021f2d95755
|
|
| MD5 |
ddac720fb3626ca0e51279ef53d8bebd
|
|
| BLAKE2b-256 |
292ba30fcb33618813df1b2d5946205967d5c6fb974cafea201c7e68ba071209
|
Provenance
The following attestation bundles were made for duvc_ctl-2.0.1-cp312-cp312-win_amd64.whl:
Publisher:
build-and-publish.yml on allanhanan/duvc-ctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
duvc_ctl-2.0.1-cp312-cp312-win_amd64.whl -
Subject digest:
c9623b8f8bea31715df32ce9e4ceb19b8eff4abe931bbaf451096021f2d95755 - Sigstore transparency entry: 804349586
- Sigstore integration time:
-
Permalink:
allanhanan/duvc-ctl@b93951ad0cf8194834fa276c69a95450372ee8a7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/allanhanan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build-and-publish.yml@b93951ad0cf8194834fa276c69a95450372ee8a7 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file duvc_ctl-2.0.1-cp311-cp311-win_amd64.whl.
File metadata
- Download URL: duvc_ctl-2.0.1-cp311-cp311-win_amd64.whl
- Upload date:
- Size: 1.2 MB
- Tags: CPython 3.11, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
871cabcc00c40e1204ca33c2dc6436259d314fef1df2036deaa1505426a9a5d4
|
|
| MD5 |
03ea2ff7bac847c4ea25459793364639
|
|
| BLAKE2b-256 |
f4070aed5bfcb81ad0ddffc4b3eaac9f29a99683a0bf367f1ccbacc51d436ccc
|
Provenance
The following attestation bundles were made for duvc_ctl-2.0.1-cp311-cp311-win_amd64.whl:
Publisher:
build-and-publish.yml on allanhanan/duvc-ctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
duvc_ctl-2.0.1-cp311-cp311-win_amd64.whl -
Subject digest:
871cabcc00c40e1204ca33c2dc6436259d314fef1df2036deaa1505426a9a5d4 - Sigstore transparency entry: 804349575
- Sigstore integration time:
-
Permalink:
allanhanan/duvc-ctl@b93951ad0cf8194834fa276c69a95450372ee8a7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/allanhanan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build-and-publish.yml@b93951ad0cf8194834fa276c69a95450372ee8a7 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file duvc_ctl-2.0.1-cp310-cp310-win_amd64.whl.
File metadata
- Download URL: duvc_ctl-2.0.1-cp310-cp310-win_amd64.whl
- Upload date:
- Size: 1.2 MB
- Tags: CPython 3.10, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4afaf129694731c039dab25fded852b084d5570d6add1d3ebea80278ffc16e10
|
|
| MD5 |
d86d5f04bc1ac08264a159fa7a39198c
|
|
| BLAKE2b-256 |
daf13a4ec71be7ad8f891700af51a5c68ff0c9c15f7e2641b247a02d13968a65
|
Provenance
The following attestation bundles were made for duvc_ctl-2.0.1-cp310-cp310-win_amd64.whl:
Publisher:
build-and-publish.yml on allanhanan/duvc-ctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
duvc_ctl-2.0.1-cp310-cp310-win_amd64.whl -
Subject digest:
4afaf129694731c039dab25fded852b084d5570d6add1d3ebea80278ffc16e10 - Sigstore transparency entry: 804349601
- Sigstore integration time:
-
Permalink:
allanhanan/duvc-ctl@b93951ad0cf8194834fa276c69a95450372ee8a7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/allanhanan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build-and-publish.yml@b93951ad0cf8194834fa276c69a95450372ee8a7 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file duvc_ctl-2.0.1-cp39-cp39-win_amd64.whl.
File metadata
- Download URL: duvc_ctl-2.0.1-cp39-cp39-win_amd64.whl
- Upload date:
- Size: 1.3 MB
- Tags: CPython 3.9, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d245f4a39499ea9d932330bd66aff64e162d3bc5a798b35552c6f19f90fbb091
|
|
| MD5 |
ff2e8c9599a5954277bd729f515b1bf2
|
|
| BLAKE2b-256 |
bb0794e11a578cb7670723188b873a4d457bf04effc1525d89d84486d4a205ef
|
Provenance
The following attestation bundles were made for duvc_ctl-2.0.1-cp39-cp39-win_amd64.whl:
Publisher:
build-and-publish.yml on allanhanan/duvc-ctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
duvc_ctl-2.0.1-cp39-cp39-win_amd64.whl -
Subject digest:
d245f4a39499ea9d932330bd66aff64e162d3bc5a798b35552c6f19f90fbb091 - Sigstore transparency entry: 804349569
- Sigstore integration time:
-
Permalink:
allanhanan/duvc-ctl@b93951ad0cf8194834fa276c69a95450372ee8a7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/allanhanan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build-and-publish.yml@b93951ad0cf8194834fa276c69a95450372ee8a7 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file duvc_ctl-2.0.1-cp38-cp38-win_amd64.whl.
File metadata
- Download URL: duvc_ctl-2.0.1-cp38-cp38-win_amd64.whl
- Upload date:
- Size: 1.3 MB
- Tags: CPython 3.8, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63198433eb9b4bd9fd6fcc8e1e8568531da4f5d62427e2757eff3a1b29f3e57f
|
|
| MD5 |
c6cbb48090e4b465b86826a841e588c2
|
|
| BLAKE2b-256 |
765f74876aae7a333ade55f21c50d33981a88bebf89a7375cfbab19b9eb9d00a
|
Provenance
The following attestation bundles were made for duvc_ctl-2.0.1-cp38-cp38-win_amd64.whl:
Publisher:
build-and-publish.yml on allanhanan/duvc-ctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
duvc_ctl-2.0.1-cp38-cp38-win_amd64.whl -
Subject digest:
63198433eb9b4bd9fd6fcc8e1e8568531da4f5d62427e2757eff3a1b29f3e57f - Sigstore transparency entry: 804349588
- Sigstore integration time:
-
Permalink:
allanhanan/duvc-ctl@b93951ad0cf8194834fa276c69a95450372ee8a7 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/allanhanan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
build-and-publish.yml@b93951ad0cf8194834fa276c69a95450372ee8a7 -
Trigger Event:
workflow_dispatch
-
Statement type: