A Pythonic library for controlling Sony cameras over USB using PTP (Picture Transfer Protocol) with Sony's proprietary SDIO extensions.
Built from the Sony Camera Remote Command SDK C/C++ reference implementation, this library provides the same functionality in a clean, easy-to-use Python package.
- Connect to Sony cameras via USB (auto-detects Sony PTP devices)
- Authenticate using the Sony SDIO handshake (v2 and v3 protocols)
- Read all camera properties — exposure mode, ISO, aperture, shutter speed, white balance, battery level, and 50+ more
- Change settings — set exposure mode, ISO, aperture, shutter speed, white balance, image quality, save media, and more
- Capture photos — full shutter control with image download to host
- LiveView streaming — get real-time JPEG preview frames
- Zoom and focus control — optical zoom in/out, manual focus near/far
- Movie recording — start/stop video recording
- Context manager support for safe connection handling
- Comprehensive enums — human-readable constants for all settings
- Python 3.10+
- libusb 1.0 — USB backend
- A Sony camera with USB connection in PC Remote mode
pip install -e .pip install git+https://github.com/olkham/pysonycam.gitLinux / macOS:
chmod +x install.sh
./install.shWindows:
install.batsudo apt install libusb-1.0-0 libusb-1.0-0-devTo use without root, add a udev rule:
echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="054c", MODE="0666"' | \
sudo tee /etc/udev/rules.d/99-sony-camera.rules
sudo udevadm control --reload-rules && sudo udevadm triggerbrew install libusbYou must replace the camera's driver with WinUSB using Zadig.
Use Zadig v2.7 — newer versions may fail to install the driver. Download v2.7 from here.
- Connect your Sony camera and set it to PC Remote mode
- Right-click
zadig.exe→ Run as administrator - In Zadig, go to Options → List All Devices
- Select your Sony camera from the dropdown (vendor ID
054C) - Set the target driver to WinUSB and click Replace Driver
Note: This replaces the MTP driver. To restore it later:
Device Manager → right-click your camera → Update Driver → Search Automatically
from pysonycam import SonyCamera
# Connect and authenticate
with SonyCamera() as camera:
camera.authenticate()
# Read all properties
props = camera.get_all_properties()
for code, info in sorted(props.items()):
print(f"0x{code:04X}: {info}")from pysonycam import SonyCamera
with SonyCamera() as camera:
camera.authenticate()
camera.set_mode("still")
camera.capture("photo.jpg")from pysonycam import SonyCamera, ExposureMode, WhiteBalance
with SonyCamera() as camera:
camera.authenticate()
camera.set_mode("still")
# Set to Aperture Priority
camera.set_exposure_mode(ExposureMode.APERTURE_PRIORITY)
# Set ISO to 400
camera.set_iso(0x00000190)
# Set aperture to F2.8
camera.set_aperture(0x0118)
# Set white balance to Daylight
camera.set_white_balance(WhiteBalance.DAYLIGHT)from pysonycam import SonyCamera
with SonyCamera() as camera:
camera.authenticate()
camera.set_mode("still")
# Get 100 LiveView frames
for i, frame in enumerate(camera.liveview_stream(count=100)):
with open(f"frame_{i:04d}.jpg", "wb") as f:
f.write(frame)import time
from pysonycam import SonyCamera
with SonyCamera() as camera:
camera.authenticate()
camera.set_mode("still")
camera.zoom_in(speed=3) # speed: 1=slow, 3=medium, 7=fast
time.sleep(2)
camera.zoom_stop()import time
from pysonycam import SonyCamera
with SonyCamera() as camera:
camera.authenticate()
camera.set_mode("movie")
camera.start_movie()
time.sleep(10) # Record for 10 seconds
camera.stop_movie()from pysonycam import SonyCamera
from pysonycam.constants import DeviceProperty, ISO_TABLE
with SonyCamera() as camera:
camera.authenticate()
camera.set_mode("still")
info = camera.get_property(DeviceProperty.ISO)
print(f"ISO: {ISO_TABLE.get(info.current_value, 'Unknown')}")
print(f"Writable: {info.is_writable}")
print(f"Supported values: {[ISO_TABLE.get(v) for v in info.supported_values]}")| Method | Description |
|---|---|
connect() |
Open USB connection and PTP session |
disconnect() |
Close session and USB connection |
authenticate() |
Perform Sony SDIO authentication handshake |
get_all_properties() |
Read all device properties → dict[int, DevicePropInfo] |
get_property(code) |
Read a single property → DevicePropInfo |
set_property(code, value) |
Write a property value |
set_mode(mode) |
Set operating mode: "still", "movie", "transfer", "standby" |
set_exposure_mode(mode) |
Set exposure mode (M, P, A, S, Auto...) |
set_iso(value) |
Set ISO (use 0x00FFFFFF for AUTO) |
set_aperture(code) |
Set F-number |
set_shutter_speed(code) |
Set shutter speed |
set_white_balance(wb) |
Set white balance mode |
set_exposure_compensation(value) |
Set EV compensation |
set_save_media(media) |
Set save destination (host/camera/both) |
capture(path=None) |
Capture a photo, optionally save to file → bytes |
get_liveview_frame() |
Get one LiveView JPEG frame → bytes |
liveview_stream(count) |
Yield LiveView frames as a generator |
zoom_in(speed) / zoom_out(speed) / zoom_stop() |
Zoom control |
focus_near(step) / focus_far(step) |
Manual focus control |
start_movie() / stop_movie() |
Movie recording control |
battery_level (property) |
Read battery level → DevicePropInfo or None |
Returned by get_property() and get_all_properties():
| Attribute | Type | Description |
|---|---|---|
property_code |
int |
Property code (hex) |
data_type |
int |
PTP data type code |
is_writable |
bool |
True if read-write |
is_valid |
bool |
True if property is currently valid |
current_value |
int|str|list |
Current value |
default_value |
int|str|list |
Factory default value |
supported_values |
list |
Enumeration of supported values (if applicable) |
minimum_value |
int |
Min of range (if applicable) |
maximum_value |
int |
Max of range (if applicable) |
step_size |
int |
Step size (if applicable) |
All constants are importable from pysonycam.constants:
DeviceProperty— all property codes (EXPOSURE_MODE, ISO, F_NUMBER, etc.)ExposureMode— Manual, Program Auto, Aperture Priority, Shutter Priority, Auto, etc.OperatingMode— Standby, Still Rec, Movie Rec, Contents TransferWhiteBalance— AWB, Daylight, Cloudy, Tungsten, Flash, Custom, etc.FocusMode— Manual, AF-S, AF-C, AF-Auto, DMFFocusArea— Wide, Zone, Center, Flexible Spot, Lock-On AFImageSize— Large, Medium, SmallJpegQuality— Extra Fine, Fine, Standard, LightFileFormat— RAW, RAW+JPEG, JPEGAspectRatio— 3:2, 16:9, 4:3, 1:1SaveMedia— Host, Camera, Host and CameraSHUTTER_SPEED_TABLE— hex code → human-readable stringF_NUMBER_TABLE— hex code → "F2.8" etc.ISO_TABLE— hex code → "100", "200", "AUTO" etc.
Enable detailed protocol logging:
import logging
logging.basicConfig(level=logging.DEBUG)Log levels:
INFO— connection events, authentication, mode changesDEBUG— every PTP command, response, and data transfer
├── pysonycam/ # Python package
│ ├── __init__.py # Package exports
│ ├── camera.py # High-level SonyCamera API
│ ├── ptp.py # PTP/USB transport layer
│ ├── parser.py # Binary protocol parser
│ ├── constants.py # All opcodes, property codes, enums
│ ├── format.py # Human-readable value formatting
│ └── exceptions.py # Custom exception hierarchy
├── examples/ # Python usage examples
│ ├── README.md # Full example index with descriptions and dependency notes
│ ├── requirements.txt # Optional deps for OpenCV-based examples (cv2, numpy)
│ ├── basic_usage.py # Read and display all device properties
│ ├── capture_photo.py # Take a single photo
│ ├── burst_capture.py # Multi-shot burst (pulse S2 per shot)
│ ├── continuous_burst.py # Hardware-rate continuous burst (hold S2)
│ ├── rapid_fire.py # Rapid single-shot with full S1→S2 cycle
│ ├── interactive_shutter.py # Keyboard-driven AF+AE lock and shutter
│ ├── live_viewfinder.py # OpenCV LiveView window with capture controls
│ ├── change_settings.py # Read and modify exposure settings
│ ├── zoom_control.py # Optical zoom in/out
│ ├── advanced_focus.py # Focus point, magnifier, continuous drive, AF settings
│ ├── astrophotography.py # Long-exposure, bulb mode, and live astrophotography HUD
│ ├── timelapse.py # Fixed-interval timelapse with optional video assembly
│ ├── hfr_slow_motion.py # HFR slow-motion recording (auto-loop or interactive)
│ ├── sq_mode_capture.py # S&Q movie recording with event confirmation
│ ├── custom_white_balance.py # Custom WB measurement sequence with event feedback
│ ├── creative_look_recipes.py # Apply film-simulation recipes (16 built-in looks)
│ ├── browse_and_download.py # Browse card content, download full or proxy, delete
│ ├── download_videos.py # Download MP4s via bare PTP / SDIO fallback strategies
│ ├── camera_status.py # Full diagnostic report (firmware, lens, battery, slots)
│ └── event_listener.py # Register event callbacks and listen for 30 s
├── CameraRemoteCommadExamples/ # Sony C/C++ SDK reference examples
│ ├── example-v2-linux/ # v2 protocol — Linux (libusb)
│ ├── example-v2-windows/ # v2 protocol — Windows (MFC)
│ ├── example-v3-linux/ # v3 protocol — Linux (libusb)
│ └── example-v3-windows/ # v3 protocol — Windows (MFC)
├── pyproject.toml # Package metadata & build config
├── requirements.txt # Dependencies
├── install.sh # Linux/macOS setup script
├── install.bat # Windows setup script
└── README.md # This file
This library should work with Sony cameras that support the Camera Remote Command SDK via PTP/USB.
Tested configuration: Windows 11 with a Sony RX100 VII (DSC-RX100M7), using the v3 protocol.
Behaviour on other cameras, operating systems, or protocol versions is untested — feedback welcome.
Supported protocol versions:
- v2 (SDK version 0x00C8 / 200) — parser support only, not tested on real hardware
- v3 (SDK version 0x012C / 300) — tested on RX100 VII / Windows 11
To use v2, pass version=0x00C8 when creating the camera:
from pysonycam.constants import SDI_VERSION_V2
camera = SonyCamera(version=SDI_VERSION_V2)The Sony SDIO extension to PTP comes in two versions. This library defaults to v3 — it is both feature-complete and backward-negotiated at connect time. Older cameras that only support v2 will fail the version handshake and you should pass version=SDI_VERSION_V2 explicitly.
| Feature | v2 (0x00C8) | v3 (0x012C) |
|---|---|---|
| Enumeration sets | Single set of supported values per property | Dual enumeration sets — properties can expose a second group of valid values |
| Storage management | Not supported | Full storage API: GetStorageID, GetStorageInfo, GetObjectHandles, DeleteObject |
| Zoom | ZOOM_SETTING only |
Enhanced: ZOOM_SCALE (0xD25C), ZOOM_OPTIC (0xD25D), ZOOM control (0xD2DD) |
| Focus magnify | 8 separate directional commands | Single consolidated command (FOCUS_MAGNIFY = 0xD254) |
| Image format | Basic COMPRESSION_SETTING |
JPEG_QUALITY (0xD252), FILE_FORMAT (0xD253), IMAGE_FILE_FORMAT (0x5004) |
| Creative controls | Not available | PICTURE_PROFILE (0xD23F), CREATIVE_STYLE (0xD240) |
| Focus area | Basic modes (Wide, Zone, Center, Flex) | Adds FOCUS_AREA_XY (0xD2DC) for coordinate-based placement |
| Movie format code | 0xD219 | Changed to 0xD241 |
| Battery | BATTERY_CHARGE + BATTERY_LEVEL |
BATTERY_LEVEL only |
| Contents transfer mode | Not supported | SDIOSetContentsTransferMode (0x9212) |
The most impactful protocol change is in how Enumeration-Form device property datasets are structured. In v2 each property has a single list of supported values. In v3, every Enumeration-Form property includes a second count field followed by a second list — even if that second list is empty (count = 0). Parsers that don't consume this second block will misalign the byte stream and fail to parse subsequent properties.
Our parser handles this correctly by always reading and consuming the second enumeration block regardless of the negotiated version:
# parse_device_prop_info() in parser.py — excerpt
elif info.form_flag == 2:
num_values = struct.unpack_from("<H", data, offset)[0]; offset += 2
for _ in range(num_values):
val, sz = _read_scalar(data, offset, scalar_dt)
info.supported_values.append(val)
offset += sz
# v3: always has a second enumeration set (may be count=0)
num_values_2nd = struct.unpack_from("<H", data, offset)[0]; offset += 2
for _ in range(num_values_2nd):
val, sz = _read_scalar(data, offset, scalar_dt)
offset += sz # consumed but not exposedThis Python library is a clean-room reimplementation of the protocol used in Sony's Camera Remote Command SDK examples (located in CameraRemoteCommadExamples/):
example-v2-linux/andexample-v3-linux/— C++ with libusbexample-v2-windows/andexample-v3-windows/— C++ MFC application
The Python version provides the same functionality with a simpler API.
MIT License. See LICENSE for details.