12. Complete Property Reference & Details#

12.1 Video Properties Reference#

All 14 DirectShow video (image) properties with technical ranges, device-specific behaviors, and range query details. Typically adjust capture appearance without hardware reconfiguration.

Reference table:

Property

Range

Typical Default

Dynamic Query

Device Notes

Brightness

0–255

127

Yes

Most cameras support. Value $0$ = black, $255$ = full white.

Contrast

0–127

64

Yes

Scaling factor for luminance. Some cameras fix at 64.

Saturation

0–127

64

Yes

Color intensity. Set $0$ for grayscale, $127$ for maximum color.

Gamma

40–500

220

Yes

Nonlinear tone curve. Measured in 1/100 increments. Lower = darker midtones.

Hue

−180 to +180

0

Yes

Color rotation in degrees. Useless on grayscale cameras.

Sharpness

0–100

50

Yes

Edge enhancement strength. Low = soft, High = crisp but noisy.

Backlight Compensation

0–127

0

Yes

Brightens foreground when backlit. Rarely exceeds 64.

Gain (Master)

0–255

128

Yes

Analog amplification. Higher = more noise, but captures low-light detail.

Whitebalance (Color Temp)

2700–6500 K

4000

Varies

Some cameras only report temperature in auto mode.

Color Effects

0–6

0

Manual

0=Normal, 1=Sepia, 2=Monochrome, 3=Negative, 4=Posterize, 5=Solarize, 6=Vivid. Not all modes available on all devices.

Digital Multiplier

1–4× (device)

1

Yes

Post-sensor digital magnification. Higher values reduce effective resolution but increase perceived zoom.

Digital Multiplier Limit

Device-dependent

Device

Yes

Maximum allowed value for Digital Multiplier property on this device.

White Balance Component

Device-dependent

0

Yes

White balance adjustment per color component (Red, Green, Blue). Device-specific implementation varies.

Power Line Frequency

0=Disabled, 1=50Hz, 2=60Hz

60 Hz

Manual

AC mains flicker elimination. Set to match your local power line frequency (US/Americas=60Hz, EU/Asia=50Hz).


Dynamic range query details#

Query via get_property_range():

import duvc_ctl as duvc

device = duvc.devices()[^0]
cam = duvc.Camera(device)

# Get brightness range
result = cam.get_property_range(duvc.VidProp.Brightness)
if result.is_ok():
    range_info = result.value()
    print(f"Min: {range_info.min}, Max: {range_info.max}, Step: {range_info.step}")
    print(f"Default: {range_info.default_val}")

Returns {min: int, max: int, step: int, default: int, default_mode: str}.

Device-specific variations:

Some devices report hardcoded ranges instead of querying hardware:

  • USB 1.1 cameras often max brightness at 128 (8-bit value)

  • Built-in webcams may not support Hue adjustment

Query fallback mechanism:

If device doesn’t report range, library uses UVC defaults:

static constexpr PropRange DefaultBrightness{0, 255, 1, 127, CamMode::Auto};
static constexpr PropRange DefaultContrast{0, 127, 1, 64, CamMode::Auto};
// ... etc

Device-specific behaviors#

Logitech cameras may not support all video properties through standard UVC. Use supports_logitech_properties() to check, then access via get_logitech_property().

Built-in laptop cameras often:

  • Lock saturation and gamma to fixed values

  • Report incorrect ranges (e.g., claim range but return error on out-of-range set)

  • Skip color effects entirely

Professional USB cameras (FLIR, industrial):

  • Gamma may require absolute calibration (values $$ represent specific curves)

  • Whitebalance in Kelvin only available in manual mode; auto mode returns current effective temperature


Querying video properties in bulk#

import duvc_ctl as duvc

device = duvc.devices()[^0]
cam = duvc.Camera(device)

supported = cam.get_supported_properties()
video_props = supported.get('video', [])

for prop_name in video_props:
    prop_enum = duvc.VidProp[prop_name]  # String → enum
    result = cam.get_property(prop_enum)
    if result.is_ok():
        value = result.value()
        print(f"{prop_name}: {value.value} (mode: {value.mode})")

12.2 Camera Properties Reference#

All 22 UVC camera control properties. These affect lens and sensor behavior: focus, pan/tilt, exposure, zoom. Typically require longer I/O than video properties and may lock during automatic operation.

Reference table:

Property

Range

Typical Default

Mode Support

Hardware Dependent

Pan

±180°

0

Both

PTZ cameras only; non-PTZ ignored

Tilt

±90°

0

Both

PTZ cameras only

Roll

±180°

0

Both

Very rare; built-in cameras unsupported

Zoom

1–10× or 1–50

1

Both

USB 3.0+ cameras common; USB 2 rare

Exposure (Auto)

0–128

0

Auto only

Shutter time in $\log_2$ increments. Negative = faster.

Exposure (Manual)

−10 to +10

0

Manual only

Set mode to Manual first before changing.

Iris/Aperture

0–128

N/A

Both

Motorized iris only; fixed aperture cameras unsupported

Focus (Auto)

N/A

Enabled

Auto only

Affects focus distance automatically.

Focus (Manual)

0–255

128

Manual only

Distance: 0=Near, 255=Infinity. Set Focus to Manual first.

Focus Relative

±10

0

Manual only

Incremental focus adjustment for video.

Privacy

On/Off (0/1)

Off

Manual

Disables lens physically (mechanical shutter). Not all cameras support.

Backlight Comp

0–127

0

Both

Brightens subject against bright background.

Brightness Comp

−50 to +50

0

Both

Brightness delta applied over video brightness.

Power Line Freq

50/60 Hz

60

Manual

Flicker elimination. Match your AC mains (US=60, EU=50).

Scene Mode

0–8

0

Manual

Scene presets: Auto(0), Portrait(1), Landscape(2), etc. Device-specific.

Scanning Mode

0–1

0

Manual

Interlaced(0) or Progressive(1). Modern cameras use Progressive.

Contrast Enhancement

0–127

0

Manual

Adaptive contrast. Higher = more aggressive.

Saturation Boost

0–127

0

Manual

Post-processing color intensification.

Sharpening

0–100

50

Manual

Edge enhancement; tradeoff with noise.

Zoom Relative

±10

0

Manual

Incremental zoom (video mode, not absolute setting).

Digital Multiplier

1–4×

1

Manual

Post-sensor digital magnification. Reduces effective resolution.

White Balance Comp

−127 to +127

0

Manual

Temporary offset to white balance temperature.

These ranges are just fallbacks and are not definitive, ranges vary device to device


Relative vs absolute guide#

Absolute properties set exact values (Pan, Tilt, Zoom, Focus):

cam.pan = 45  # Set pan to exactly 45 degrees
cam.zoom = 2  # Set zoom to exactly 2x (if supported)

Relative properties apply incremental changes (Pan Relative, Tilt Relative, Zoom Relative, Focus Relative):

cam.pan_relative(15)  # Move 15 degrees from current position
cam.zoom_relative(-1)  # Zoom out incrementally
cam.focus_relative(5)  # Move focus closer

Relative operations are useful for real-time adjustments during video capture without querying current state.


Device-specific configuration notes#

Auto-focus behavior:

On cameras with motorized autofocus, set Focus to Auto mode:

cam.focus_mode = "auto"  # Or CamMode.Auto

Then leave Focus value unchanged. Do not set Focus value manually while in Auto mode; instead use relative adjustments or switch to Manual mode.

Pan/Tilt on PTZ cameras:

Professional PTZ (Pan-Tilt-Zoom) cameras support full 3-axis movement. Consumer USB cameras typically do not support Pan/Tilt (values are accepted but ignored by hardware).

Check capability before use:

caps = cam.get_capabilities()
if "Pan" in caps.supported_camera_properties:
    cam.pan = 30
else:
    print("Camera does not support Pan")

Zoom on USB 3.0+ cameras:

USB 3 cameras common support hardware zoom (1–10×). USB 2 cameras typically support digital zoom only (Digital Multiplier, 1–4×). Query range to distinguish:

zoom_range = cam.get_property_range(CamProp.Zoom)
if zoom_range.max > 4:
    print(f"Hardware zoom: {zoom_range.max}x")
else:
    print(f"Digital zoom: {zoom_range.max}x")

Iris/Aperture (motorized):

Only professional cameras with motorized iris. Most USB cameras have fixed aperture. Setting fails silently on unsupported hardware; query range first:

iris_range = cam.get_property_range(CamProp.Iris)
if iris_range.max > 0:
    cam.iris = iris_range.max  # Open iris wide

Exposure modes and temperature:

Auto exposure adjusts shutter time automatically in low light. Manual exposure fixes shutter for consistent brightness. Switching modes:

# Auto exposure
cam.exposure_mode = "auto"

# Manual exposure (set specific shutter)
cam.exposure_mode = "manual"
cam.exposure = -5  # Faster shutter (brighter in dark, less motion blur)

Negative exposure values = faster shutter (darker in daylight, clearer motion).


Device-specific workarounds#

Issue: Focus locks after setting manual value

Some cameras lock focus after manual setting and ignore relative adjustments. Workaround: Switch to Auto mode, wait 2 seconds, then set manual value if needed:

cam.focus_mode = "auto"
time.sleep(2)
cam.focus_mode = "manual"
cam.focus = 100

Issue: Pan/Tilt not moving despite no error

Non-PTZ cameras silently ignore Pan/Tilt commands. Workaround: Check device name or query property range (returns [^0][^0] if unsupported):

range_result = cam.get_property_range(CamProp.Pan)
if range_result.value().max == 0:
    print("Camera does not support Pan (not a PTZ model)")

Issue: Zoom changes resolution unexpectedly

Some cameras apply digital zoom, reducing output resolution. Workaround: Use Digital Multiplier for magnification without resolution loss (if supported), or apply software zoom post-capture.

Issue: Autofocus too slow or hunts constantly

Hardware autofocus may oscillate or take seconds to settle. Workaround: Use manual focus for fixed subjects:

cam.focus_mode = "manual"
cam.focus = 200  # Far field (landscape)

Or apply focus lock (if camera supports):

# Set autofocus, wait for convergence, switch to manual
cam.focus_mode = "auto"
time.sleep(3)
current_focus = cam.focus
cam.focus_mode = "manual"
cam.focus = current_focus  # Lock at current position

Issue: Exposure flickers in low light

Auto exposure may hunt when ambient light is marginal. Workaround: Lock to manual mode with fixed value:

cam.exposure_mode = "manual"
cam.exposure = -3  # Slow shutter (gather more light)

Or disable power line frequency cancellation if causing 50/60 Hz flicker:

cam.power_line_frequency = 0  # Disabled (not always supported)

12.3 Auto vs Manual Modes#

Camera properties support automatic and manual operation modes via CamMode enum. Auto mode delegates control to hardware algorithms; manual mode locks to specified values. Some properties only support one mode.


CamMode enum#

import duvc_ctl as duvc

duvc.CamMode.Auto      # Hardware automatic control
duvc.CamMode.Manual    # User-locked value

Property-specific mode support#

Property

Auto

Manual

Notes

Exposure

Auto adjusts shutter; Manual locks.

Focus

Auto seeks; Manual is fixed distance.

Iris/Aperture

Auto for varying light; Manual for fixed depth.

Whitebalance

Auto calibrates; Manual sets Kelvin.

Brightness (Video)

Both modes typically available.

Pan/Tilt

Auto returns to center; Manual stays put.

Zoom

Auto optical tracking; Manual user control.

Privacy

Manual only

Hardware toggle; no auto mode.

Gain

Auto normalizes; Manual fixes amplification.


Mode persistence#

Mode setting persists until changed explicitly. Setting a property value does not reset mode:

import duvc_ctl as duvc

cam = duvc.CameraController(0)

# Focus in auto mode
cam.focus_mode = "auto"

# Set value (mode remains auto; value ignored)
cam.focus = 100

# Switch to manual—previous value retained
cam.focus_mode = "manual"
print(cam.focus)  # Returns 100 (retained)

Mode string parsing#

User-friendly string input supports multiple aliases:

Input String

Equivalent Enum

Variations

"manual"

CamMode.Manual

"m"

"auto"

CamMode.Auto

"a", "automatic"

Parsing implementation (case-insensitive):

cam.focus_mode = "auto"        # Valid
cam.exposure_mode = "Manual"   # Case-insensitive
cam.iris_mode = "a"            # Short form
cam.pan_mode = "automatic"     # Alternative spelling

Invalid strings raise ValueError:

cam.zoom_mode = "invalid"  # ValueError: Invalid mode 'invalid' for zoom...

Mode string implementation details#

Parser implemented in CameraController.parse_mode_string():

def parse_mode_string(self, mode: str, property_name: str) -> CamMode:
    """Convert mode string to CamMode enum."""
    mode_lower = mode.lower().strip()
    mode_mapping = {
        "manual": CamMode.Manual,
        "auto": CamMode.Auto,
        "automatic": CamMode.Auto,
        "m": CamMode.Manual,
        "a": CamMode.Auto,
    }
    if mode_lower not in mode_mapping:
        available = list(mode_mapping.keys())
        raise ValueError(
            f"Invalid mode '{mode}' for {property_name}. "
            f"Available modes: {', '.join(available)}"
        )
    return mode_mapping[mode_lower]

12.4 Range Discovery & Clamping#

Property constraints vary by device. Query valid ranges before setting values. Library provides automatic validation and fallback defaults.


get_property_range() returns dict#

Returns dictionary with constraint metadata:

import duvc_ctl as duvc

cam = duvc.CameraController(0)

brightness_range = cam.get_property_range("brightness")
print(brightness_range)
# {'min': 0, 'max': 255, 'step': 1, 'default': 127}

Returns None if property unsupported:

unsupported = cam.get_property_range("pan")  # PTZ-only camera
if unsupported is None:
    print("Pan not supported on this device")

PropRange.clamp()#

Clamp value to valid range with optional stepping:

import duvc_ctl as duvc

cam = duvc.CameraController(0)
range_info = cam.get_property_range("zoom")

clamped = range_info["max"]  # Clamp to max
if clamped > range_info["max"]:
    clamped = range_info["max"]
if clamped < range_info["min"]:
    clamped = range_info["min"]

cam.zoom = clamped

Automatic clamping in setter:

cam.zoom = 999  # Out of range
# Library clamps to max and applies successfully

PropRange.contains#

Check if value in valid range:

range_info = cam.get_property_range("brightness")

if 128 in range_info:  # min <= 128 <= max
    cam.brightness = 128
else:
    print("Value out of range")

Automatic range validation#

Setters validate against device constraints before applying:

import duvc_ctl as duvc

cam = duvc.CameraController(0)

# Out-of-range raises InvalidValueError
try:
    cam.brightness = 999  # Device max is 255
except duvc.InvalidValueError as e:
    print(f"Error: {e}")  # brightness must be <= 255, got 999

Automatic validation applies bounds-checking:

zoom_range = cam.get_property_range("zoom")
if zoom_range:
    value = max(zoom_range["min"], min(value, zoom_range["max"]))
    # Value is now safe to apply

Default value recovery#

Retrieve hardware default from range:

expo_range = cam.get_property_range("exposure")

if expo_range:
    default = expo_range.get("default", 0)
    print(f"Hardware default: {default}")
    
    # Reset to hardware default
    cam.exposure = default
else:
    print("Exposure range unavailable")

Device-specific variations#

Different devices report different ranges:

# USB 2 camera
brightness_range_usb2 = {"min": 0, "max": 128, "step": 1, "default": 64}

# USB 3 camera
brightness_range_usb3 = {"min": 0, "max": 255, "step": 1, "default": 128}

# Check actual device range
actual = cam.get_property_range("brightness")
print(f"This camera: min={actual['min']}, max={actual['max']}")

Some devices report hardcoded ranges instead of querying hardware. Always use returned range, not UVC spec values.


Fallback mechanism documentation#

When device doesn’t report range, library uses safe defaults:

def get_dynamic_range(self, property_name, fallback_min, fallback_max):
    """Get device range with fallback."""
    try:
        prop_range = self.get_property_range(property_name)
        if prop_range:
            return prop_range["min"], prop_range["max"]
    except Exception:
        pass
    # Fallback to safe defaults
    return fallback_min, fallback_max

# Usage
min_val, max_val = self.get_dynamic_range("brightness", 0, 100)
# Returns actual device range if available, else (0, 100)

Fallback used by property setters to prevent out-of-range errors on devices without range reporting. Application can override by explicitly querying and clamping.