USB Host UVC Camera

Browse source code on GitHub

Overview

This sample demonstrates how to use the USB Host UVC (USB Video Class) driver to capture video frames from a USB camera connected to a Zephyr device acting as a USB host.

Upon connection, the USB camera is detected and configured automatically. The sample captures video frames and logs frame statistics.

Requirements

This sample uses the USB host stack and requires the USB host controller driver.

A USB camera supporting UVC (USB Video Class) specification is required.

Building and Running

The sample can be built and flashed as follows:

west build -b rd_rw612_bga/rw612 samples/subsys/usb/host_uvc
west flash

The device is expected to detect the USB camera automatically when connected.

Sample Output

When a USB camera is connected, you should see:

*** Booting Zephyr OS build v4.3.0-8828-g14f382c2002c ***
<inf> main: USB host video device usbh_uvc_0 is ready
<inf> usbh_dev: New device with address 1 state 2
<inf> usbh_dev: Configuration 1 bNumInterfaces 4
<inf> usbh_uvc: UVC device connected
<inf> usbh_uvc: Interface 0 associated with UVC class
<inf> usbh_dev: Set Interfaces 0, alternate 0 -> 0
<inf> usbh_dev: Set Interfaces 1, alternate 0 -> 0
<inf> usbh_uvc: Device configured successfully: control interface 0, streaming interface 1
<wrn> usbh_uvc: Control cid 134217729 not supported by device
<wrn> usbh_uvc: Control cid 134217730 not supported by device
<inf> usbh_uvc: Successfully initialized 8 UVC controls
<inf> usbh_uvc: UVC device (addr=1) initialization completed
<inf> usbh_class: Class 'uvc_host_c_data_0' matches interface 0
<inf> main: Video device connected!

Viewing Supported Formats

The sample will enumerate and display all supported video formats:

<inf> usbh_uvc: Created 36 format capabilities based on UVC descriptors
<inf> main: - Capabilities:
<inf> main:   YUYV width [640; 640; 1] height [480; 480; 1]
<inf> main:   YUYV width [160; 160; 1] height [90; 90; 1]
<inf> main:   YUYV width [160; 160; 1] height [120; 120; 1]
<inf> main:   YUYV width [176; 176; 1] height [144; 144; 1]
<inf> main:   YUYV width [320; 320; 1] height [180; 180; 1]
<inf> main:   YUYV width [320; 320; 1] height [240; 240; 1]
<inf> main:   YUYV width [352; 352; 1] height [288; 288; 1]
<inf> main:   YUYV width [432; 432; 1] height [240; 240; 1]
<inf> main:   YUYV width [640; 640; 1] height [360; 360; 1]
<inf> main:   YUYV width [800; 800; 1] height [448; 448; 1]
<inf> main:   YUYV width [800; 800; 1] height [600; 600; 1]
<inf> main:   YUYV width [864; 864; 1] height [480; 480; 1]
<inf> main:   YUYV width [960; 960; 1] height [720; 720; 1]
<inf> main:   YUYV width [1024; 1024; 1] height [576; 576; 1]
<inf> main:   YUYV width [1280; 1280; 1] height [720; 720; 1]
<inf> main:   YUYV width [1600; 1600; 1] height [896; 896; 1]
<inf> main:   YUYV width [1920; 1920; 1] height [1080; 1080; 1]
<inf> main:   YUYV width [2304; 2304; 1] height [1296; 1296; 1]
<inf> main:   YUYV width [2304; 2304; 1] height [1536; 1536; 1]
<inf> main:   JPEG width [640; 640; 1] height [480; 480; 1]
<inf> main:   JPEG width [160; 160; 1] height [90; 90; 1]
<inf> main:   JPEG width [160; 160; 1] height [120; 120; 1]
<inf> main:   JPEG width [176; 176; 1] height [144; 144; 1]
<inf> main:   JPEG width [320; 320; 1] height [180; 180; 1]
<inf> main:   JPEG width [320; 320; 1] height [240; 240; 1]
<inf> main:   JPEG width [352; 352; 1] height [288; 288; 1]
<inf> main:   JPEG width [432; 432; 1] height [240; 240; 1]
<inf> main:   JPEG width [640; 640; 1] height [360; 360; 1]
<inf> main:   JPEG width [800; 800; 1] height [448; 448; 1]
<inf> main:   JPEG width [800; 800; 1] height [600; 600; 1]
<inf> main:   JPEG width [864; 864; 1] height [480; 480; 1]
<inf> main:   JPEG width [960; 960; 1] height [720; 720; 1]
<inf> main:   JPEG width [1024; 1024; 1] height [576; 576; 1]
<inf> main:   JPEG width [1280; 1280; 1] height [720; 720; 1]
<inf> main:   JPEG width [1600; 1600; 1] height [896; 896; 1]
<inf> main:   JPEG width [1920; 1920; 1] height [1080; 1080; 1]

Configuring Video Format

The sample configures the video format based on prj.conf settings:

<inf> main: - Expected video format: YUYV 320x180
<inf> usbh_uvc: Setting format: YUYV 320x180 (format_index=1, frame_index=5, interval=333333)
<wrn> usbh_uvc: VS GET: expected 48 bytes, got 26 bytes
<inf> usbh_dev: Set Interfaces 1, alternate 0 -> 3
<inf> usbh_dev: Modify interface 1 ep 0x81 by op 0
<inf> usbh_dev: Modify interface 1 ep 0x81 by op 1
<inf> usbh_uvc: Set streaming interface 1 alternate 3 successfully
<inf> usbh_uvc: UVC format set successfully: YUYV 320x180@30fps

Adjusting Frame Rate

The sample displays supported frame intervals and sets the target frame rate:

<inf> main: - Default frame rate : 30.000000 fps
<inf> main: - Supported frame intervals for the default format:
<inf> main:    333333/10000000
<inf> main:    416666/10000000
<inf> main:    500000/10000000
<inf> main:    666666/10000000
<inf> main:    1000000/10000000
<inf> main:    1333333/10000000
<inf> main:    2000000/10000000
<inf> usbh_uvc: Setting frame rate: 15 fps -> 15 fps
<wrn> usbh_uvc: VS GET: expected 48 bytes, got 26 bytes
<inf> usbh_uvc: Frame rate successfully set to 15 fps
<inf> usbh_dev: Set Interfaces 1, alternate 3 -> 2
<inf> usbh_dev: Modify interface 1 ep 0x81 by op 0
<inf> usbh_dev: Modify interface 1 ep 0x81 by op 2
<inf> usbh_dev: Modify interface 1 ep 0x81 by op 1
<inf> usbh_uvc: Set streaming interface 1 alternate 2 successfully
<inf> main: - Target frame rate set to: 15.000000 fps

Accessing the Video Controls

The sample enumerates available camera controls:

<inf> main: - Supported controls:
<inf> main:          device: usbh_uvc_0
<inf> video_ctrls:                       Brightness 0x00980900 (int)      (flags=0x00) : min=0 max=255 step=1 default=128 value=128
<inf> video_ctrls:                         Contrast 0x00980901 (int)      (flags=0x00) : min=0 max=255 step=1 default=128 value=128
<inf> video_ctrls:                       Saturation 0x00980902 (int)      (flags=0x00) : min=0 max=255 step=1 default=128 value=128
<inf> video_ctrls:                         Exposure 0x00980911 (int)      (flags=0x00) : min=3 max=2047 step=1 default=250 value=250
<inf> video_ctrls:                             Gain 0x00980913 (int)      (flags=0x00) : min=0 max=255 step=1 default=0 value=0
<inf> video_ctrls:        White Balance Temperature 0x0098091a (int)      (flags=0x00) : min=2000 max=6500 step=1 default=4000 value=4000
<inf> video_ctrls:                  Focus, Absolute 0x009a090a (int)      (flags=0x00) : min=0 max=250 step=5 default=0 value=0
<inf> video_ctrls:                   Zoom, Absolute 0x009a090d (int)      (flags=0x00) : min=100 max=500 step=1 default=100 value=100

Frame Statistics

The sample logs frame statistics every 100 frames:

<inf> main: Allocating 6 video buffers, size=115200
<inf> usbh_dev: Set Interfaces 1, alternate 2 -> 2
<inf> main: Capture started
<inf> main: Received 100 frames
<inf> main: Received 200 frames
<inf> main: Received 300 frames

Configuration Options

The sample can be configured through prj.conf:

Video Format

  • CONFIG_APP_VIDEO_PIXEL_FORMAT - Pixel format (YUYV, MJPEG, etc.)

  • CONFIG_APP_VIDEO_FRAME_WIDTH - Frame width

  • CONFIG_APP_VIDEO_FRAME_HEIGHT - Frame height

  • CONFIG_APP_VIDEO_TARGET_FPS - Target frame rate

Memory Configuration

USB Transfer Configuration

Logging Configuration

Troubleshooting

Memory Allocation Failures

If you see memory allocation errors, increase heap size or reduce buffer count:

Dropped or Corrupted Frames

If frames are dropped or corrupted, increase buffer resources or reduce data rate:

Performance Issues

If video capture is slow or choppy, you can try to reduce the data rate or logging, or enable optimizations:

UVC buffer allocation is configured from the USB Host and Video areas, which can be useful in case of memory allocation issues or to sustain higher FPS:

See also

Video
USB Host Core API