36 KiB
Insta360 Link / Link 2 / Link 2C USB & UVC Protocol Specification
This document provides the complete, byte-accurate hardware control protocol specification for the Insta360 Link, Insta360 Link 2, Insta360 Link 2C, and Insta360 Link 2 Pro (PUC3) webcam family.
All protocol structures, USB descriptors, UVC Extension Unit GUIDs, control selectors, sub-opcodes, payload layouts, and state machines documented here were reverse-engineered directly from the official macOS binary:
- Binary Path:
/Applications/Insta360 Link Controller.app/Contents/MacOS/Webcam-desktop - Application Version:
2.0.2(arm64Mach-O executable) - SHA-256 Digest:
41db6e352223f06fa2fd70989a4d2faf622fd9c14b16a84da2aff39c0dcff22e
1. USB Device Identification & Firmware Images
All Insta360 Link family cameras enumerate under Arashi Vision's USB Vendor ID (0x2e1a). Device discovery is implemented in MacUVCCameraControlImp::GetUVCCameraList (0x100191478) and UVCCameraDeviceWatcherImp::StartWatch (0x10019e29c).
- USB Vendor ID (
idVendor):0x2e1a(11802decimal — Arashi Vision Inc. / Insta360)
1.1 Product IDs (idProduct) and Firmware Targets
Verified at 0x100191480 (0x4c01..=0x4c06), 0x100191664 (0x00c2), Webcam::CameraInsta::GetCameraModel() (0x10005f92c), UVCCameraExtendControllerImp::FirmwareUpgrade jump table (0x10286f37d), and firmware path table (0x1001a0a0c):
PID (idProduct) |
Camera Model | Internal Code | Physical Gimbal | SetVideoMode Payload |
Virtual MSC Firmware Target Path |
|---|---|---|---|---|---|
0x4c01 |
Insta360 Link (1st Gen) | link1 |
Yes (3-axis) | 8 bytes | a:\Insta360WebCamFW.bin |
0x4c02 |
Insta360 Link 2 Pro (PUC3 Gimbal A) | link2_gimbal |
Yes (2-axis) | 8 bytes | a:\Insta360PUC3FW_GIMBAL.bin |
0x4c03 |
Insta360 Link 2C (Fixed-Lens 4K) | link2_main |
No | 36 bytes | a:\Insta360LINK2CFW_HOST.bin |
0x4c04 |
Insta360 Link 2 (2-Axis Gimbal 4K) | link2_gimbal |
Yes (2-axis) | 8 bytes | a:\Insta360LINK2FW_GIMBAL.bin |
0x4c05 |
Insta360 Link 2C Pro (PUC3 Host) | link2_main |
No | 36 bytes | a:\Insta360PUC3FW_HOST.bin |
0x4c06 |
Insta360 Link 2 Pro (PUC3 Gimbal B) | link2_gimbal |
Yes (2-axis) | 8 bytes | a:\Insta360PUC3FW_GIMBAL.bin |
0x00c2 |
Insta360 Link Simple-Class / DFU | link1 |
— | 36 bytes | a:\Insta360WebCamFW.bin |
SetVideoModePayload Length Note (0x1001970f4): InMacUVCCameraExtendController::SetVideoMode, when a 36-byte (0x24)VideoModeAuxiliaryDatastructure is supplied andpidis in0x4c01..=0x4c06, the binary tests bit(pid - 0x4c01)against the bitmask0x2b(0b101011, matching PIDs0x4c01,0x4c02,0x4c04,0x4c06). If the bit is set, the transfer length is truncated to 8 bytes (w4 = 8). For gimbal-less models (0x4c03Link 2C and0x4c05PUC3 Host), the full 36-byte (0x24) buffer is transmitted.
2. Per-Model Hardware Capability Matrix
Derived from Webcam::CameraDeviceSupporter::UpdateUIStatus (0x10004a8b8), the controller determines per-device feature support directly from the USB Product ID:
| Capability Flag | Condition in Binary (0x10004a8b8) |
0x4c01 Link |
0x4c02 PUC3 Gimbal A |
0x4c03 Link 2C |
0x4c04 Link 2 |
0x4c05 PUC3 Host |
0x4c06 PUC3 Gimbal B |
|---|---|---|---|---|---|---|---|
has_physical_gimbal |
pid != 0x4c03 && pid != 0x4c05 |
Yes | Yes | No | Yes | No | Yes |
support_ptz_drag |
pid != 0x4c03 && pid != 0x4c05 |
Yes | Yes | No | Yes | No | Yes |
support_auto_framing |
pid != 0x4c01 |
No | Yes | Yes | Yes | Yes | Yes |
support_highlighting |
pid != 0x4c01 |
No | Yes | Yes | Yes | Yes | Yes |
support_mirror_vertically |
pid != 0x4c01 |
No | Yes | Yes | Yes | Yes | Yes |
support_track_speed |
pid != 0x4c03 && pid != 0x4c05 |
Yes | Yes | No | Yes | No | Yes |
support_image_template |
pid != 0x4c01 |
No | Yes | Yes | Yes | Yes | Yes |
support_privacy_mode |
pid != 0x4c01 |
No | Yes | Yes | Yes | Yes | Yes |
support_area_track |
(pid & 0xfffd) == 0x4c04 |
No | No | No | Yes | No | Yes |
support_roll_adjustment |
pid == 0x4c01 |
Yes | No | No | No | No | No |
support_ai_denoise |
pid != 0x4c01 |
No | Yes | Yes | Yes | Yes | Yes |
support_sound_wall |
pid == 0x4c05 || pid == 0x4c06 |
No | No | No | No | Yes | Yes |
support_speak_tracking |
(pid & 0xfffd) == 0x4c04 |
No | No | No | Yes | No | Yes |
support_auto_track |
pid != 0x4c03 && pid != 0x4c05 |
Yes | Yes | No | Yes | No | Yes |
support_smart_adjustment |
pid != 0x4c03 && pid != 0x4c05 |
Yes | Yes | No | Yes | No | Yes |
support_audio_capture_mode |
pid != 0x4c01 |
No | Yes | Yes | Yes | Yes | Yes |
support_horizontal_correction |
pid == 0x4c04 |
No | No | No | Yes | No | No |
3. UVC Descriptor Discovery & Extension Unit GUIDs
In FindControllerInterfaceForServiceObject (0x100190fe0), the host walks the USB Configuration Descriptor (bDescriptorType = 0x04 Interface Descriptor) looking for the UVC VideoControl interface:
bInterfaceClass = 0x0e(CC_VIDEO)bInterfaceSubclass = 0x01(SC_VIDEOCONTROL)
Within the VideoControl interface, class-specific interface descriptors (bDescriptorType = 0x24, CS_INTERFACE) are parsed by bDescriptorSubtype:
VC_INPUT_TERMINAL(0x02):- Checks
wTerminalType == 0x0201(ITT_CAMERAat byte offset4..6) and recordsbTerminalID(desc[3]).
- Checks
VC_PROCESSING_UNIT(0x05):- Records
bUnitID(desc[3]).
- Records
VC_EXTENSION_UNIT(0x06):- Compares the 16-byte
guidExtensionCode(desc[4..20]) against two proprietary Insta360 Extension Unit GUIDs.
- Compares the 16-byte
3.1 Proprietary Extension Unit GUIDs
| Extension Unit | Canonical UUID String (0x102a9d098 / 0x102a9d0b8) |
Mixed-Endian 16-Byte USB guidExtensionCode (desc[4..20]) |
Default bUnitID |
|---|---|---|---|
Extension Unit 1 (XU1) |
FAF1672D-B71B-4793-8C91-7B1C9B7F95F8 |
2d 67 f1 fa 1b b7 93 47 8c 91 7b 1c 9b 7f 95 f8 |
9 (0x09) |
Extension Unit 2 (XU2) |
E307E649-4618-A3FF-82FC-2D8B5F216773 |
49 e6 07 e3 18 46 ff a3 82 fc 2d 8b 5f 21 67 73 |
10 (0x0a) |
Mixed-Endian UUID Conversion (
0x100191140&0x100191168): Per the USB Video Class specification, the first three fields ofguidExtensionCode(Data1: u32,Data2: u16,Data3: u16) are encoded in little-endian byte order, whileData4: [u8; 8]is encoded in big-endian (network) byte order:
FAF1672D-B71B-4793-8C91-7B1C9B7F95F8→2D 67 F1 FA|1B B7|93 47|8C 91|7B 1C 9B 7F 95 F8E307E649-4618-A3FF-82FC-2D8B5F216773→49 E6 07 E3|18 46|FF A3|82 FC|2D 8B 5F 21 67 73
3.2 Default UVC Unit IDs
When UVC descriptors are not overridden, Insta360 Link family cameras use the following standard unit IDs:
| Unit / Interface | Constant | Default ID |
|---|---|---|
| UVC VideoControl Interface | DEFAULT_CONTROL_INTERFACE |
0 (0x00) |
Camera Input Terminal (CT) |
DEFAULT_INPUT_TERMINAL_ID |
1 (0x01) |
Processing Unit (PU) |
DEFAULT_PROCESSING_UNIT_ID |
2 (0x02) |
Insta360 Extension Unit 1 (XU1) |
DEFAULT_EXTENSION_UNIT_ID |
9 (0x09) |
Insta360 Extension Unit 2 (XU2) |
DEFAULT_EXTENSION_UNIT2_ID |
10 (0x0a) |
4. UVC Control Request Framing
All standard and extension unit commands are transmitted as USB Control Transfers to Endpoint 0 targeting the UVC VideoControl interface (MacUVCCameraControl::SetData at 0x100192880 and MacUVCCameraControl::GetData at 0x10019282c).
4.1 USB Setup Packet Layout
| Field | Size | Value / Formula | Description |
|---|---|---|---|
bmRequestType |
u8 |
0x21 (SET_CUR) or 0xa1 (GET_*) |
Class-specific (0x20), Interface recipient (0x01), Host-to-Device (0x00) or Device-to-Host (0x80) |
bRequest |
u8 |
0x01 or 0x81..0x87 |
UVC Request Code (see table below) |
wValue |
u16 (LE) |
(selector as u16) << 8 |
Control Selector (CS) in high byte, 0x00 in low byte |
wIndex |
u16 (LE) |
((unit_id as u16) << 8) | (interface_num as u16) |
Entity/Unit/Terminal ID in high byte, VideoControl bInterfaceNumber in low byte |
wLength |
u16 (LE) |
data.len() as u16 |
Payload length in bytes |
4.2 UVC Request Codes (bRequest)
| Request Name | bmRequestType |
bRequest |
Direction | Usage |
|---|---|---|---|---|
SET_CUR |
0x21 |
0x01 |
OUT (Host → Camera) | Write control value or execute command |
GET_CUR |
0xa1 |
0x81 |
IN (Camera → Host) | Read current control value or status |
GET_MIN |
0xa1 |
0x82 |
IN (Camera → Host) | Read minimum supported value |
GET_MAX |
0xa1 |
0x83 |
IN (Camera → Host) | Read maximum supported value |
GET_RES |
0xa1 |
0x84 |
IN (Camera → Host) | Read step resolution |
GET_LEN |
0xa1 |
0x85 |
IN (Camera → Host) | Read payload length (u16 LE, 2 bytes) for variable-length XU selectors |
GET_INFO |
0xa1 |
0x86 |
IN (Camera → Host) | Read control capability flags (1 byte) |
GET_DEF |
0xa1 |
0x87 |
IN (Camera → Host) | Read factory default value |
5. Standard UVC Camera Terminal (CT_*) & Processing Unit (PU_*) Controls
Implemented in MacUVCCameraController (0x100193694–0x100195800).
5.1 Camera Terminal Controls (unit_id = input_terminal_id, default 1)
| Selector | UVC Control Name | Size | Type (LE) | Description & Typical Values |
|---|---|---|---|---|
0x02 |
CT_AE_MODE_CONTROL |
1B | u8 |
Auto-Exposure mode bitmap: 1 = Manual, 2 = Auto, 4 = Shutter Priority, 8 = Aperture Priority |
0x04 |
CT_EXPOSURE_TIME_ABSOLUTE_CONTROL |
4B | u32 |
Shutter speed / exposure duration in 100 µs units (e.g. 10..1000, default 200) |
0x06 |
CT_FOCUS_ABSOLUTE_CONTROL |
2B | u16 |
Manual focus distance (0..100, step 1, default 50) |
0x08 |
CT_FOCUS_AUTO_CONTROL |
1B | u8 |
Auto-focus enable: 0 = Manual Focus, 1 = Auto Focus |
0x0b |
CT_ZOOM_ABSOLUTE_CONTROL |
2B | u16 |
Digital zoom multiplier (100 = 1.0x .. 400 = 4.0x, step 1, default 100) |
0x0d |
CT_PANTILT_ABSOLUTE_CONTROL |
8B | (i32, i32) |
[0..4] Pan angle in arcseconds (-468000..+468000), [4..8] Tilt angle in arcseconds (-324000..+324000); 1° = 3600 arcsec |
0x0e |
CT_PANTILT_RELATIVE_CONTROL |
4B | [i8, u8, i8, u8] |
[0] pan_dir (-1, 0, +1), [1] pan_speed, [2] tilt_dir (-1, 0, +1), [3] tilt_speed |
0x0f |
CT_ROLL_ABSOLUTE_CONTROL |
2B | i16 |
Gimbal roll angle in tenths of a degree (Link 1 0x4c01 only, e.g. -1800..+1800) |
5.2 Processing Unit Controls (unit_id = processing_unit_id, default 2)
| Selector | UVC Control Name | Size | Type (LE) | Description & Typical Values |
|---|---|---|---|---|
0x02 |
PU_BRIGHTNESS_CONTROL |
2B | i16 |
Image brightness (0..100, step 1, default 50) |
0x03 |
PU_CONTRAST_CONTROL |
2B | u16 |
Image contrast (0..100, step 1, default 50) |
0x05 |
PU_POWER_LINE_FREQUENCY_CONTROL |
1B | u8 |
Anti-flicker frequency: 0 = Disabled, 1 = 50 Hz, 2 = 60 Hz, 3 = Auto |
0x07 |
PU_SATURATION_CONTROL |
2B | u16 |
Color saturation (0..100, step 1, default 50) |
0x08 |
PU_SHARPNESS_CONTROL |
2B | u16 |
Image sharpness (0..100, step 1, default 50) |
0x0a |
PU_WHITE_BALANCE_TEMPERATURE_CONTROL |
2B | u16 |
Color temperature in Kelvin (2000..10000, step 50, default 5000) |
0x0c |
PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL |
1B | u8 |
Auto White Balance (AWB): 0 = Manual, 1 = Auto |
6. Proprietary Extension Unit 1 (XU1) Selectors (0x01 – 0x0f)
- GUID:
FAF1672D-B71B-4793-8C91-7B1C9B7F95F8 - Default Unit ID:
9(0x09) - Binary Implementation:
MacUVCCameraExtendController(0x100195a18–0x10019bd00)
Summary Table of XU1 Selectors
| Selector | Constant Name | Size | Requests | Primary Function |
|---|---|---|---|---|
0x01 |
SYSTEM_AND_PRESET_CMD |
4B / 5B | SET_CUR |
Preset recall/add/delete, Gimbal reset, Factory default, Composition bias, Forbidden area mode |
0x02 |
VIDEO_MODE |
8B / 36B | SET_CUR, GET_CUR |
Video mode (Normal, AutoTracking, WhiteBoard, OverheadShot, DeskView, AutoFraming, SmartWhiteBoard) & ROI/pitch/zoom |
0x03 |
TRACKING_AND_GESTURE |
6B / 16B | SET_CUR, GET_CUR |
Hand gesture enables, AI tracking speed, Composition style, Smart Whiteboard force |
0x04 |
AUDIO_CONTROL |
2B | SET_CUR, GET_CUR |
Audio AI noise reduction (0..1) & Audio capture mode (1..5) |
0x05 |
TRACK_OBJECT_SELECT |
10B | SET_CUR |
Select target person/object bounding box (UVCRect) for AI tracking |
0x06 |
TRACK_OBJECT_LIST_V1 |
N * 10B |
GET_LEN, GET_CUR |
Detected trackable objects bounding box array (Insta360 Link 1 0x4c01) |
0x07 |
EXPOSURE_CURVE_AND_ISO |
259B | SET_CUR, GET_CUR |
Auto/Manual exposure mode (u8), Manual ISO (u16), and 128-point tone curve ([u16; 128]) |
0x08 |
EXPOSURE_COMPENSATION |
4B | SET_CUR, GET_CUR |
Exposure compensation EV (f32 IEEE-754 little-endian) |
0x09 |
WHITE_BALANCE_EXT |
129B | SET_CUR, GET_CUR |
Extended white balance mode (u8) and 32-channel gain array ([u32; 32]) |
0x0a |
EXTEND_FUNC_BITMASK |
8B | SET_CUR, GET_CUR |
15-bit Extended Function bitmask (u32 mask, u32 values) |
0x0b |
PANTILT_RELATIVE_EXT |
4B | SET_CUR, GET_CUR |
Proprietary gimbal relative pan/tilt ([pan_speed, pan_dir, tilt_speed, tilt_dir]) |
0x0c |
DEVICE_STATUS |
4B | GET_CUR |
Runtime device status bitflags (u32) |
0x0d |
PTZ_VERSION_AND_ABS |
30B | GET_CUR |
Gimbal firmware version string ([0..20]) and current pan/tilt/zoom ([20..27]) |
0x0e |
PRESET_POSITION_FLAGS |
8B | GET_CUR |
Populated gimbal preset slot bitmask, active slot, and max slots |
0x0f |
USB_MODE_SWITCH |
4B | SET_CUR |
Switch to Read-Only Mass Storage Class ([2, 0, 0, 0]) or camera file download ([1, 0, 0, 0]) |
Detailed XU1 Selector Payloads
XU1 0x01 — SYSTEM_AND_PRESET_CMD (4 or 5 Bytes, SET_CUR)
Multiplexed command register dispatched by sub-opcode in byte[0]:
Sub-Opcode (byte[0]) |
Method in Binary | Address | Length | Wire Payload (Hex / Layout) | Description |
|---|---|---|---|---|---|
0x00 |
SetCurPresetPosition(u8 index) |
0x100199918 |
4B | [0x00, index, 0x00, 0x00] |
Recall gimbal preset slot index (0..=5) |
0x01 |
AddPresetPosition(u8 index) |
0x1001999b4 |
4B | [0x01, index, 0x00, 0x00] |
Save current gimbal PTZ to slot index (0..=5) |
0x02 |
DeletePresetPosition(u8 index) |
0x100199a54 |
4B | [0x02, index, 0x00, 0x00] |
Delete gimbal preset slot index (0..=5) |
0x03 |
ResetGimbal() |
0x100196fb0 |
4B | [0x03, 0x00, 0x00, 0x00] |
Center/home gimbal pan, tilt, roll, and zoom |
0x04 |
LoadFactoryDefault() |
0x10019701c |
4B | [0x04, 0x00, 0x00, 0x00] |
Reset image/camera parameters to factory defaults |
0x06 |
SetCompositionBias(i16 x, i16 y) |
0x10019933c |
5B | [0x06, x_lo, x_hi, y_lo, y_hi] |
Set AI tracking composition offset (x = 0x7fff, y = 0x7fff resets bias) |
0x07 |
EnterTrackForbiddenAreaSetting() |
0x10019bf74 |
4B | [0x07, 0x01, 0x00, 0x00] |
Enter interactive tracking forbidden-area calibration mode |
0x08 |
ExitTrackForbiddenAreaSetting() |
0x10019bfb4 |
4B | [0x08, 0x01, 0x00, 0x00] |
Exit tracking forbidden-area calibration mode |
XU1 0x02 — VIDEO_MODE (8 or 36 Bytes)
Verified in SetVideoMode (0x100197088) and GetVideoMode (0x1001978b8).
VideoMode Enum Values (byte[0], verified in CameraInsta at 0x1000601d4–0x100060234):
| Value | Variant | UI Display Name | Description |
|---|---|---|---|
0 |
Normal |
Normal | Standard webcam mode |
1 |
AutoTracking |
AI Tracking | Single-person gimbal/digital AI tracking |
4 |
WhiteBoard |
Whiteboard | Corner-marker whiteboard keystone enhancement |
5 |
OverheadShot |
Overhead | Gimbal pitched straight down (-90°) for top-down view |
6 |
DeskView |
DeskView | Tilted trapezoid perspective correction for desktop view |
7 |
AutoFraming |
Auto Framing | Multi-person group framing (Link 2 / Link 2C / PUC3) |
8 (or 10) |
SmartWhiteBoard |
Smart Whiteboard | Markerless AI whiteboard detection & perspective correction |
Wire Layout (36-Byte VideoModeAuxiliaryData):
| Byte Offset | Type | Field | Description |
|---|---|---|---|
0 |
u8 |
mode |
VideoMode enum value (0, 1, 4, 5, 6, 7, 8) |
1 |
u8 |
flags |
Auxiliary mode flags (0 by default) |
2..6 |
i32 LE |
rect[0] (x) |
ROI X or corner coordinate |
6..10 |
i32 LE |
rect[1] (y) |
ROI Y or corner coordinate |
10..14 |
i32 LE |
rect[2] (w) |
ROI Width or corner coordinate |
14..18 |
i32 LE |
rect[3] (h) |
ROI Height or corner coordinate |
18..20 |
i16 LE |
pitch |
DeskView / Host pitch angle (-900..0 or -61926 sentinel) |
20..22 |
u16 LE |
zoom |
Mode zoom percentage (default 100) |
22..36 |
[u8; 14] |
extra |
Mode-specific auxiliary bytes |
Note: On Link (0x4c01), Link 2 (0x4c04), and PUC3 Gimbal (0x4c02, 0x4c06), SET_CUR sends only the first 8 bytes ([0..8]). On Link 2C (0x4c03) and PUC3 Host (0x4c05), SET_CUR sends all 36 bytes. GET_CUR always reads 36 bytes.
XU1 0x03 — TRACKING_AND_GESTURE (6 or 16 Bytes)
Multiplexed control for hand gestures, tracking speed, composition style, and Smart Whiteboard:
-
SET_CUR(16 Bytes) — Dispatched bybyte[0]:byte[0] == 0x00(EnableAllGestureat0x100197b54):[0x00, enable_u8, 0x00, ...](also togglesExtendFunction::AllGesturesbit 4 inXU1 0x0a).byte[0] == 0x01(EnableGestureWorkat0x100197bc8): Reads 6 bytes[all, ok, palm, l, v, rock]fromGET_CUR, setsbuf[0] = 0x01andbuf[gesture_idx + 1] = enable_u8, padded with zeros to 16 bytes.byte[0] == 0x03(ForceSetSmatrWhiteBoardat0x1001980d0):[0x03, mode_u8, 0x00, ...].byte[0] == 0x05(SetTrackSpeedat0x1001975bc):[0x05, speed_u8, 0x00, ...].byte[0] == 0x06(SetCompositionStyleat0x100197498):[0x06, style_u8, 0x00, ...].
-
GET_CUR(6 or 16 Bytes):byte[0]: Master gesture enable (0or1)byte[1]:Gesture::Ok(0) enable (0or1)byte[2]:Gesture::Palm(1) enable (0or1)byte[3]:Gesture::LShape(2) enable (0or1)byte[4]:Gesture::VShape(3) enable (0or1)byte[5]:Gesture::Rock(4) enable (0or1)byte[6]:TrackSpeed(GetTrackSpeedat0x100197630:0=Slow,1=Normal,2=Fast)byte[7]:CompositionStyle(GetCompositionStyleat0x10019750c:0=Head,1=HalfBody,2=WholeBody,3=Custom)
Gesture Indices (0x100197bc8 & setUseGesture* at 0x100067f58–0x100068888):
| Index | Enum Variant | Hand Gesture | Default Action |
|---|---|---|---|
0 |
Gesture::Ok |
👌 OK Sign | Toggle AI Tracking / Auto Framing (byte[1]) |
1 |
Gesture::Palm |
✋ Open Palm | Toggle AI Tracking / Auto Framing (byte[2]) |
2 |
Gesture::LShape |
👆 L-Shape | Dynamic Zoom In/Out (byte[3]) |
3 |
Gesture::VShape |
✌️ V-Shape (Peace) | Toggle Whiteboard Mode (byte[4]) |
4 |
Gesture::Rock |
🤘 Rock Sign | Custom / Reserved (byte[5]) |
XU1 0x04 — AUDIO_CONTROL (2 Bytes)
Verified in EnableAudioNoiseReduction (0x100197798), GetAudioNoiseStatus (0x100197808), SetAudioCaptureMode (0x10019bf54), and GetAudioCaptureMode (0x10019bf64).
- Payload:
[value_u8, 0x00](2 bytes) - For Link 1 noise reduction:
value_u8is0(Disabled) or1(Enabled). - For Link 2 / Link 2C / PUC3
AudioCaptureMode(0x1000702a8):
| Value | Variant | UI Display Name | Description |
|---|---|---|---|
1 |
VoiceFocus |
Voice Focus | Directional beamforming microphone mode |
2 |
VoiceSuppression |
Noise Suppression | Wide-angle background noise cancellation |
3 |
MusicBalance |
Music Balance | Balanced voice and ambient music fidelity |
4 |
Original |
Original Sound | Unprocessed raw microphone audio |
5 |
SoundWall |
Sound Wall | Virtual audio fence (PUC3 0x4c05 / 0x4c06 only) |
XU1 0x05 & 0x06 — TRACK_OBJECT_SELECT & TRACK_OBJECT_LIST_V1 (10 Bytes per UVCRect)
Verified in SetTrackObj (0x100198a38) and GetTrackObjLists (0x100198adc).
Each UVCRect entry is 10 bytes (5 × i16 little-endian):
| Byte Offset | Type | Field | Description |
|---|---|---|---|
0..2 |
i16 LE |
x |
Normalized bounding box X coordinate |
2..4 |
i16 LE |
y |
Normalized bounding box Y coordinate |
4..6 |
i16 LE |
width |
Normalized bounding box width |
6..8 |
i16 LE |
height |
Normalized bounding box height |
8..10 |
i16 LE |
track_id |
Object tracking identifier |
XU1 0x07 — EXPOSURE_CURVE_AND_ISO (259 Bytes)
Verified in GetExpouseCurve (0x10019aaa0), SetExpouseCurve (0x10019ab74), EnableAutoExposure (0x10019ac90), GetAutoExposureStatus (0x10019ad98), SetISOValue (0x10019ae24), and GetISOValue (0x10019af50).
| Byte Offset | Type | Field | Description |
|---|---|---|---|
0 |
u8 |
mode |
Exposure mode: 0 = Manual Exposure, 1 = Auto Exposure |
1..3 |
u16 LE |
iso |
Manual ISO sensitivity (e.g. 100..=3200) |
3..259 |
[u16; 128] LE |
points |
128-point tone/exposure lookup curve (256 bytes) |
XU1 0x08 — EXPOSURE_COMPENSATION (4 Bytes)
Verified in SetExposureCompensation (0x100198f34) and GetExposureCompensation (0x100198fc0).
- Payload: 4-byte IEEE-754 single-precision float (
f32little-endian) representing EV compensation (e.g.,-3.0to+3.0).
XU1 0x09 — WHITE_BALANCE_EXT (129 Bytes)
Verified in SetWhiteBalanceParam (0x10019afe0) and GetWhiteBalanceParam (0x10019b264).
byte[0]:u8White balance modebyte[1..129]:[u32; 32]Little-endian channel calibration gains (128bytes).
XU1 0x0a — EXTEND_FUNC_BITMASK (8 Bytes)
Verified in EnableExtendFuncWork (0x100199afc), GetExtendFuncStatus (0x100199dd0), EnableVerticalScreen (0x10019b7d0), EnableLowResolution (0x10019b854), and the CameraInsta::Init jump table at 0x102864a20.
Wire Layout (8 Bytes):
| Byte Offset | Type | Field | Description |
|---|---|---|---|
0..4 |
u32 LE |
mask |
Bitmask of feature bit(s) being modified (1u32 << bit_index on SET_CUR) |
4..8 |
u32 LE |
values |
Full 32-bit state bitmask of all enabled extended functions |
Complete ExtendFunction Bit Definitions (0..14, verified at 0x102864a20):
| Bit Index | Bitmask (1 << bit) |
Enum Variant | Internal Field in CameraInsta |
Description |
|---|---|---|---|---|
0 |
0x0000_0001 |
AiZoom |
ai_zoom_checked_ |
Automatic AI Zoom during tracking |
1 |
0x0000_0002 |
Reserved1 |
— | Reserved |
2 |
0x0000_0004 |
Hdr |
enable_hdr_ |
Hardware HDR mode |
3 |
0x0000_0008 |
HorizontalMirror |
mirror_checked_ |
Horizontal image flip / mirror |
4 |
0x0000_0010 |
AllGestures |
enable_all_gestures_ |
Master hand-gesture recognition flag |
5 |
0x0000_0020 |
VerticalMode |
enable_vertical_mode_ |
9:16 Vertical output resolution |
6 |
0x0000_0040 |
StartupParams |
enable_startup_params_ |
Persist startup parameters in camera NVRAM |
7 |
0x0000_0080 |
SingleTapTracking |
enable_single_tap_tracking_ |
Single-click target selection tracking |
8 |
0x0000_0100 |
AutoTracking |
enable_auto_tracking_ |
Automatic human tracking enable |
9 |
0x0000_0200 |
SmartAdjustment |
smart_adjustment_checked_ |
Smart exposure/frame adjustment |
10 |
0x0000_0400 |
ForcedVertical |
forced_vertical_ |
Uncropped 9:16 portrait mode (physical 90° rotation) |
11 |
0x0000_0800 |
UltimatePrivacyMode |
enable_privacy_mode_ |
10-second inactivity sleep / gimbal tilt-down privacy |
12 |
0x0000_1000 |
VerticalMirror |
enable_vertically_mirror_ |
Vertical image flip (upside-down mount) |
13 |
0x0000_2000 |
LowResolution |
enable_low_resolution_ |
Low-resolution compatibility mode |
14 |
0x0000_4000 |
TrackForbiddenArea |
enable_track_forbidden_area_ |
Enforce tracking forbidden zones |
XU1 0x0b — PANTILT_RELATIVE_EXT (4 Bytes)
Verified in SetPanTiltRelative (0x1001990f4) and GetPanTiltRelative.
- Payload:
[pan_speed: u8, pan_dir: i8, tilt_speed: u8, tilt_dir: i8] - Note that the byte order (
speedthendir) is reversed compared to standard UVCCT_PANTILT_RELATIVE_CONTROL(0x0e, which usesdirthenspeed). dir:0= Stop,1= Positive (Right / Up),-1(0xff) = Negative (Left / Down).
XU1 0x0c — DEVICE_STATUS (4 Bytes, GET_CUR)
Verified in GetDeviceStatus (0x10019b8dc). Returns a 32-bit little-endian status bitmask (DeviceStatus):
- Bit 0 (
0x01):TRACKING_ACTIVE - Bit 1 (
0x02):WHITEBOARD_ACTIVE - Bit 2 (
0x04):GESTURE_DETECTED - Bit 3 (
0x08):PRIVACY_SLEEP - Bit 4 (
0x10):OVERHEAD_MODE - Bit 5 (
0x20):DESKVIEW_MODE - Bit 6 (
0x40):UPGRADING
XU1 0x0d — PTZ_VERSION_AND_ABS (30 Bytes, GET_CUR)
Verified in GetPTZVersionInfo (0x1001993bc) and GetPanTiltAbsoluteValue (0x1001996cc).
byte[0..20]: Null-terminated ASCII gimbal firmware version string (e.g."v1.3.1.0_build0").byte[20..22]:i16LE current Pan angle (in0.1°units,1° = 10units =3600 arcsec).byte[22..24]:i16LE current Tilt angle (in0.1°units).byte[24..26]:u16LE current Zoom ratio (100..400).byte[26]:u8Gimbal status byte.byte[27..30]: Reserved.
XU1 0x0e — PRESET_POSITION_FLAGS (8 Bytes, GET_CUR)
Verified in GetCurPresetPositionFlag (0x1001997c0).
byte[0]:slot_mask(u8bitmask of saved presets, bits0..5).byte[1]:current_slot(u8index of active preset).byte[2]:max_slots(u8, typically6).byte[3..8]: Reserved.
XU1 0x0f — USB_MODE_SWITCH (4 Bytes, SET_CUR)
Verified in SwitchMscReadOnlyClass (0x10019b998) and DownloadFileFromCamera (0x10019b928):
[0x01, 0x00, 0x00, 0x00]: Trigger diagnostic log / file download mode.[0x02, 0x00, 0x00, 0x00]: Switch camera USB personality to Read-Only Mass Storage Class (MSC) / Simple-Class mode for firmware upgrade.
7. Proprietary Extension Unit 2 (XU2) Selectors (0x01 – 0x0f)
- GUID:
E307E649-4618-A3FF-82FC-2D8B5F216773 - Default Unit ID:
10(0x0a) - Binary Implementation:
MacUVCCameraExtendController(0x100195a18–0x10019c478)
Summary Table of XU2 Selectors
| Selector | Constant Name | Size | Requests | Primary Function |
|---|---|---|---|---|
0x01 |
GESTURE_BINDING_MAP |
16B | SET_CUR, GET_CUR |
Map hand gestures (0..4) to GestureFunction actions (0..4) |
0x02 |
SYSTEM_TIME_AND_IQ |
10B | SET_CUR |
Sync host UTC timestamp, set IQ switches (D0/D1), or restore factory settings |
0x03 |
DEVICE_INFO |
150B | GET_CUR |
Read device name ([0..50]), firmware version ([50..100]), and serial number ([100..150]) |
0x04 |
IMAGE_TEMPLATE_INFO |
11B | SET_CUR, GET_CUR |
Image preset template save/apply/delete & populated 64-bit slot bitmask |
0x05 |
IMAGE_TEMPLATE_NAME |
65B | SET_CUR, GET_CUR |
Read/write 64-byte ASCII name for image template id (byte[0]) |
0x06 |
FILTER_MODE |
1B | SET_CUR, GET_CUR |
Hardware LUT color filter (0..=8) |
0x07 |
(Reserved) | — | — | Unused in v2.0.2 |
0x08 |
PRIVACY_AND_FILL_LIGHT |
4B | SET_CUR, GET_CUR |
Hardware privacy mode ([2, enable, 0, 0]) and fill light parameters |
0x09 |
HOST_PTZ |
8B | SET_CUR |
Digital crop box on gimbal-less cameras (u16 x, y, width, height, normalized 0..5140) |
0x0a |
TRACK_OBJECT_LIST_V2 |
N * 10B |
GET_LEN, GET_CUR |
Detected trackable objects bounding box array (GetNewTrackObjLists for Link 2 / 2C) |
0x0b |
TRACK_FORBIDDEN_AREA |
40B | SET_CUR, GET_CUR |
Configure/enable gimbal tracking exclusion zones (ForbiddenAreaInfo_s) |
0x0c |
DEFAULT_TRACK_MODE |
1B | SET_CUR, GET_CUR |
Default AI tracking mode (0 = Single Person, 1 = Group / Auto Framing) |
0x0d |
HORIZONTAL_CORRECTION |
1B | SET_CUR, GET_CUR |
Gimbal horizon leveling (0 = Off, 1 = On; Link 2 0x4c04) |
0x0e |
REAL_ZOOM_AND_UDISK |
4B | SET_CUR, GET_CUR |
Query real optical/digital zoom value (u16 LE) and UDisk open counter |
0x0f |
REPORT_DATA |
Variable | GET_LEN, GET_CUR |
Telemetry and diagnostic report buffer (GetReportData) |
Detailed XU2 Selector Payloads
XU2 0x01 — GESTURE_BINDING_MAP (16 Bytes)
Verified in GetGestureBindingMap (0x100198384) and SetGestureBindingFunc (0x10019874c).
Maps each Gesture (0..4) to a GestureFunction:
0=None1=AutoTracking2=Zoom3=WhiteBoard4=AutoFraming
XU2 0x02 — SYSTEM_TIME_AND_IQ (10 Bytes, SET_CUR)
Multiplexed system control dispatched by byte[0]:
Sub-Opcode (byte[0]) |
Method in Binary | Address | Wire Payload (10 Bytes) | Description |
|---|---|---|---|---|
0x01 |
SetTimestamp(u64 ms) |
0x10019be40 |
[0x01, ts_le[0..8], 0x00] |
Synchronize camera RTC with 64-bit host timestamp (ms) |
0x02 |
SetIQSwitch(int bit, bool en) |
0x100199ce0 |
[0x02, mask_u32_le[0..4], 0..] |
Toggle ISP Image Quality switch bit (0 = D0, 1 = D1) |
0x04 |
RestoreFactorySet(true) |
0x10019c1ac |
[0x04, 0x01, 0x00, ...] |
Full factory reset and reboot camera |
0x05 |
RestoreFactorySet(false) |
0x10019c1ac |
[0x05, 0x01, 0x00, ...] |
Restore factory settings without rebooting |
XU2 0x03 — DEVICE_INFO (150 Bytes, GET_CUR)
Verified in GetDeviceInfo (0x100196e74) and GetSerialNumber (0x100196d10).
Contains three fixed 50-byte null-terminated ASCII strings:
byte[0..50]:device_name(e.g."Insta360 Link 2")byte[50..100]:firmware_version(e.g."v2.5.8.8_build1")byte[100..150]:serial_number(e.g."INK2A240912345")
XU2 0x04 & 0x05 — IMAGE_TEMPLATE_INFO (11 Bytes) & IMAGE_TEMPLATE_NAME (65 Bytes)
Verified in GetImageTemplateInfo (0x10019ba4c), SetImageTemplate (0x10019bb08), DeleteTemplate (0x10019bbc8), GetImageTemplateName (0x10019bc74), and SetImageTemplateName (0x10019bd14).
XU2 0x04 (IMAGE_TEMPLATE_INFO, 11 Bytes):
| Byte Offset | Type | Field | Description |
|---|---|---|---|
0 |
i8 |
current_id |
Active template slot ID (0..63, or -1 if none active) |
1 |
u8 |
operation |
ImageOperation: 0 = None, 1 = SaveOrUpdate, 2 = Apply |
2..10 |
u64 LE |
bitmask |
64-bit mask of populated template slots (bit N = 1 if slot N exists) |
10 |
u8 |
max_templates |
Maximum supported templates (typically 10) |
XU2 0x05 (IMAGE_TEMPLATE_NAME, 65 Bytes):
byte[0]:i8template_id(0..63)byte[1..65]: 64-byte null-terminated UTF-8/ASCII template name.
XU2 0x06 — FILTER_MODE (1 Byte)
Verified in SetFilter (0x10019bdb0), GetFilter (0x10019bdf8), and UI mapping at 0x100096f94:
| Value | Variant | Filter Name |
|---|---|---|
0 |
FilterMode::None |
None (Original) |
1 |
FilterMode::Style1 |
Style 1 |
2 |
FilterMode::Style2 |
Style 2 |
3 |
FilterMode::Fresh |
Fresh |
4 |
FilterMode::Amber |
Amber |
5 |
FilterMode::Film1 |
Film 1 |
6 |
FilterMode::Film2 |
Film 2 |
7 |
FilterMode::Cool |
Cool |
8 |
FilterMode::Warm |
Warm |
XU2 0x08 — PRIVACY_AND_FILL_LIGHT (4 Bytes)
Verified in SetPrivacyMode (0x10019c108) and GetPrivacyMode (0x10019c168):
SET_CUR(4 Bytes):[0x02, enable_u8, 0x00, 0x00]whereenable_u8is1(Privacy On) or0(Privacy Off).GET_CUR(4 Bytes):byte[0]= status code (i8),byte[1]=1if privacy mode is enabled else0.
XU2 0x09 — HOST_PTZ (8 Bytes, SET_CUR)
Verified in SetHostPTZ (0x10019bec0). Used on gimbal-less models (Link 2C 0x4c03 and PUC3 Host 0x4c05) for digital pan/tilt/zoom cropping within a 5140 × 5140 coordinate space:
byte[0..2]:u16LEx(0..5140)byte[2..4]:u16LEy(0..5140)byte[4..6]:u16LEwidth(default5140)byte[6..8]:u16LEheight(default5140)
XU2 0x0b — TRACK_FORBIDDEN_AREA (40 Bytes)
Verified in SetTrackForbiddenArea (0x10019bff4), GetTrackForbiddenArea (0x10019c038), and EnableTrackForbiddenArea. Stores up to 4 ForbiddenAreaInfo_s entries (10 bytes each: u8 enabled, u8 index, i16 pan_min, i16 pan_max, i16 tilt_min, i16 tilt_max).
XU2 0x0c — DEFAULT_TRACK_MODE (1 Byte)
Verified in SetDefaultTrackMode (0x10019c220) and GetDefaultTrackMode (0x10019c268).
byte[0]:0= Single-person tracking,1= Multi-person / Group tracking.
XU2 0x0d — HORIZONTAL_CORRECTION (1 Byte)
Verified in EnableHorizontalCorrection (0x10019c2b0) and GetEnableHorizontalCorrection (0x10019c2f8).
byte[0]:0= Disabled,1= Enabled (supported on Insta360 Link 20x4c04).
XU2 0x0e — REAL_ZOOM_AND_UDISK (4 Bytes)
Verified in GetRealZoomValue (0x10019c340), GetUDiskOpenCount, and SetUDiskOpenCount.
byte[0..2]:u16LE real zoom factor (100..400).
8. Firmware Upgrade Protocol (UVCCameraExtendControllerImp::FirmwareUpgrade)
Verified in UVCCameraExtendControllerImp::FirmwareUpgrade (0x10019fc88) and MacSimpleClassControlImp (0x1001a0a0c).
Insta360 cameras support two firmware delivery paths depending on the active USB mode:
- Read-Only Mass Storage Class (MSC) Mode: Triggered via
XU1selector0x0f([0x02, 0x00, 0x00, 0x00]). - USB Vendor Simple-Class Mode (
PID 0x00c2or vendor interface): Transfers the firmware image over raw USB Vendor Control + Bulk OUT transfers.
8.1 Step-by-Step USB Simple-Class Upgrade Sequence (0x10019fc88)
-
Initiate Firmware Transfer (Vendor Control Transfer OUT):
bmRequestType = 0x41(Host-to-Device, Vendor, Interface)bRequest = 0x01wValue = 0x0004wIndex = 0x0000wLength = 137(0x0089bytes)- 137-Byte Header Payload:
byte[0..8]:u64LE total firmware file size in bytesbyte[8]:0x5c('\\'path separator sentinel)byte[9..137]: 128-byte null-padded ASCII target path on camera flash (from0x1001a0a0c, e.g.a:\Insta360WebCamFW.bin,a:\Insta360LINK2FW_GIMBAL.bin,a:\Insta360LINK2CFW_HOST.bin,a:\Insta360PUC3FW_GIMBAL.bin, ora:\Insta360PUC3FW_HOST.bin).
-
Stream Firmware Image in 512 KB Bulk Chunks:
- Endpoint: Bulk OUT Endpoint
0x01 - Chunk Size:
0x80000bytes (524,288bytes = 512 KB) per bulk transfer until the entire firmware binary is transmitted.
- Endpoint: Bulk OUT Endpoint
-
Verify Firmware Reception (Vendor Control Transfer IN):
bmRequestType = 0xc1(Device-to-Host, Vendor, Interface)bRequest = 0x81wValue = 0x0004wIndex = 0x0000wLength = 1- Response: 1 byte (
0x00indicates checksum/transfer verification succeeded).
-
Reboot into Normal UVC Mode (Vendor Control Transfer OUT):
bmRequestType = 0x41(Host-to-Device, Vendor, Interface)bRequest = 0x01wValue = 0x0002wIndex = 0x0000wLength = 1- Payload:
[0x01]