Post

UVC (USB Video Class) Camera

UVC (USB Video Class) Camera

This post was migrated from Tistory. You can find the original here.

Most USB cameras sold on the market follow the UVC (USB Video Class) standard.

There are cases where the descriptor response doesn’t quite match the actual behavior,

but overall, the general structure and behavior still tend to follow the UVC spec.

Let’s take a look at UVC.

Overall UVC Operation Structure

System Layer Perspective

1
2
3
4
5
6
7
8
9
10
11
12
13
[Application]  
↓  
[UVC Handling Layer]  
↓  
[USB Transport Layer]  
↓  
================ USB =================  
↓  
[UVC Device Firmware]  
├─ Control Interface  
└─ Streaming Interface (video)  
↓  
[Sensor + ISP + Image Processing]

Device-Internal Perspective

1
2
3
4
5
6
7
8
9
10
11
[Image Sensor]                     ← HW
   ↓
[ISP / Image Processing]           ← HW + FW
   ↓
[CT / PU]                          ← FW (handles UVC control)
   ↓
[Encoder]                          ← FW
   ↓
[Frame Buffer]                     ← FW
   ↓
[USB Endpoint]                     ← HW + FW

UVC Structure

Control Interface (control channel)

Host → Device (Control Transfer)

  • Low speed (control transfer)

  • Descriptor-based

CT (Camera Terminal)

Control items: Exposure, Focus, Zoom, Tilt, …., optical-related settings

PU (Processing Unit)

Control items: Brightness, Contrast, White Balance, Gain, …., ISP (image signal processing) related settings

XU (Extension Unit)

Vendor-specific custom features

VS (Video Streaming) Interface

Through streaming-related information such as format (MJPEG, YUV, etc.), resolution, and FPS, you can determine which streaming modes the device supports.

Device → Host (Isochronous / Bulk Transfer)

High speed, continuous streaming, bandwidth matters

Format Descriptor: MJPEG / YUY2 / H264

Frame Descriptor: resolution / FPS

Endpoint: data transfer channel

1
2
3
4
5
6
7
8
9
10
11
12
VideoStreaming Interface
 ├─ VS_INPUT_HEADER
 ├─ VS_FORMAT_MJPEG (bFormatIndex = 1)
 │    ├─ VS_FRAME_MJPEG (bFrameIndex = 1) → 640x480 + fps list
 │    ├─ VS_FRAME_MJPEG (bFrameIndex = 2) → 1280x720 + fps list
 │    ├─ VS_FRAME_MJPEG (bFrameIndex = 3) → 1920x1080 + fps list
 │
 ├─ VS_FORMAT_UNCOMPRESSED (bFormatIndex = 2)
 │    ├─ VS_FRAME_UNCOMPRESSED (bFrameIndex = 1)
 │    ├─ VS_FRAME_UNCOMPRESSED (bFrameIndex = 2)
 └─ Endpoint Descriptor
     └─ bmAttributes → determines Iso / Bulk

(Transfer methods)

Isochronous

Guarantees real-time delivery, data loss possible, used by most cameras

Bulk

Higher reliability, has latency, used by some specialized cameras

VS_FRAME_MJPEG (Descriptor) example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bLength                0x1E
bDescriptorType        0x24   (CS_INTERFACE)
bDescriptorSubType     0x07   (VS_FRAME_MJPEG)

bFrameIndex            0x01
bmCapabilities         0x00

wWidth                 0x0280  (640)
wHeight                0x01E0  (480)

dwMinBitRate           0x000E1000
dwMaxBitRate           0x002DC6C0

dwMaxVideoFrameBufferSize 0x0004B000

dwDefaultFrameInterval 0x00051615  (333333 → 30fps)

bFrameIntervalType     0x03   (3 fps values)

dwFrameInterval[0]     0x00051615  (333333 → 30fps)
dwFrameInterval[1]     0x000A2C2A  (666666 → 15fps)
dwFrameInterval[2]     0x000F4240  (1000000 → 10fps)

USB Device Structure

1
2
3
4
5
6
7
8
9
10
Device
 ├─ Configuration
 │    ├─ Interface
 │    │    ├─ Endpoint
 │    │    ├─ Endpoint
 │    │
 │    ├─ Interface
 │         ├─ Endpoint
 │
 └─ Endpoint 0 (Control)  ← exception (device-level)

The USB spec defines that Control Transfers go through Endpoint 0.

The UVC spec also uses Control Transfers for negotiation and control.

So CT/PU control is carried out over Control Transfer (EP0),

while video streaming, such as MJPEG, goes through a separate Endpoint.

Endpoint 0 (Control)

Used for initial device communication, UVC control (CT/PU)

Other Endpoints

Used for specific functions (video streaming, audio, HID, …)

UVC Control Flow

CT/PU Descriptor

The GET/SET control request flow based on the CT/PU Descriptor (other descriptors follow the same flow)

1
2
3
4
5
6
7
8
9
10
11
Host (libuvc / libusb)
   ↓
Read descriptor
   ↓
Check bmControls
   ↓
"Ah, brightness is supported"
   ↓
UVC control request (GET/SET)
   ↓
Handled by firmware

Check support for a given control by looking at the bmControls value bit by bit

1
2
3
4
5
6
7
8
9
10
11
12
bmControls: 0x17 0x00 (2bytes little Endian)
 ↓
0x0017 = 23 (decimal)
 ↓
23 = 0000 0000 0001 0111 (binary)

bit |    Feature     | Value
0   |   Brightness   |  1
1   |   Contrast     |  1
2   |    Hue         |  1
3   |   Saturation   |  0
4   |   Sharpness    |  1

PU Descriptor example

1
2
3
4
5
6
7
8
bLength            0x0B
bDescriptorType    0x24
bDescriptorSubType 0x05 (PROCESSING_UNIT)
bUnitID            0x02
bSourceID          0x01
wMaxMultiplier     0x0000
bmControls         0x17 0x00
iProcessing        0x00

CT Descriptor example

1
2
3
4
5
6
7
8
9
10
11
12
bLength            0x12
bDescriptorType    0x24
bDescriptorSubType 0x02 (CAMERA_TERMINAL)
bTerminalID        0x01
wTerminalType      0x0201 (Camera)
bAssocTerminal     0x00
iTerminal          0x00
wObjectiveFocalLengthMin 0x0000
wObjectiveFocalLengthMax 0x0000
wOcularFocalLength       0x0000
bControlSize       0x03
bmControls         0x0F 0x00 0x00

Bulguksa Temple, Gyeongju

This post is licensed under CC BY-NC 4.0 by the author.