Note

This is the documentation for the latest development branch and may refer to features that are not available in released versions. If you are looking for the documentation for a specific release, use the drop-down menu on the left and select the desired version.

RTOS UVC Host Guide#

Overview#

The RT-Smart user-space UVC host APIs use the uvc_host_* prefix, and image formats are described with FOURCC.

Related sample directories:

  • src/rtsmart/examples/mpp/sample_uvc_host

  • src/rtsmart/examples/mpp/sample_uvc_dev_picture

  • src/rtsmart/examples/mpp/sample_uvc_dev_vicap

Currently supported input formats:

  • USBH_VIDEO_FOURCC_YUY2

  • USBH_VIDEO_FOURCC_UYVY

  • USBH_VIDEO_FOURCC_NV12

  • USBH_VIDEO_FOURCC_I420

  • USBH_VIDEO_FOURCC_MJPEG

Among them:

  • MJPEG is a compressed stream format

  • YUY2, UYVY, NV12, and I420 are raw pixel formats

Data Structures#

User-space header:

src/rtsmart/mpp/userapps/api/mpi_uvc_api.h

struct uvc_format#

struct uvc_format {
    unsigned int width;
    unsigned int height;
    unsigned int fourcc;
    unsigned int frameinterval;
};

Field description:

Field

Description

width

Requested or negotiated image width

height

Requested or negotiated image height

fourcc

Image format, using USBH_VIDEO_FOURCC_*

frameinterval

Frame interval in 100ns, for example 10000000 / 30 for 30fps

Notes:

  • uvc_host_init() uses this structure both for user input and for returning the final negotiated mode.

  • If the requested width, height, or frame rate cannot be matched exactly, the lower layer returns the actual negotiated result.

struct uvc_frame#

struct uvc_frame {
    unsigned int index;
    unsigned int bytesused;
    char *userptr;
    union {
        k_video_frame_info v_info;
        k_vdec_stream v_stream;
    };
};

Field description:

Field

Description

index

UVC buffer index for the current frame

bytesused

Valid data length in bytes

userptr

User-space virtual address of the current frame

v_info

Video-frame info for raw image data

v_stream

VDEC input info for MJPEG stream data

Notes:

  • Internal mapping fields such as length and offset are not exposed in the user-space structure.

  • userptr is valid only while the frame is held by the application.

  • After uvc_host_put_frame() is called, userptr must not be used again.

  • For MJPEG, bytesused is typically used when writing the compressed data directly to a file.

FOURCC Definitions#

#define USBH_VIDEO_FOURCC(a, b, c, d) \
    ((uint32_t)(uint8_t)(a) | ((uint32_t)(uint8_t)(b) << 8) | \
     ((uint32_t)(uint8_t)(c) << 16) | ((uint32_t)(uint8_t)(d) << 24))

#define USBH_VIDEO_FOURCC_YUY2  USBH_VIDEO_FOURCC('Y', 'U', 'Y', '2')
#define USBH_VIDEO_FOURCC_UYVY  USBH_VIDEO_FOURCC('U', 'Y', 'V', 'Y')
#define USBH_VIDEO_FOURCC_NV12  USBH_VIDEO_FOURCC('N', 'V', '1', '2')
#define USBH_VIDEO_FOURCC_I420  USBH_VIDEO_FOURCC('I', '4', '2', '0')
#define USBH_VIDEO_FOURCC_MJPEG USBH_VIDEO_FOURCC('M', 'J', 'P', 'G')

API Reference#

int uvc_host_init(struct uvc_format *fmt);#

Initialize the UVC host device.

int uvc_host_init(struct uvc_format *fmt);

Notes:

  • fmt carries the requested width, height, fourcc, and frameinterval.

  • After successful initialization, fmt is updated with the negotiated mode.

  • It is recommended to complete VB initialization before using this API.

Return value:

  • 0 on success

  • negative value on failure

int uvc_host_start_stream(void);#

Start the UVC video stream.

int uvc_host_start_stream(void);

Return value:

  • 0 on success

  • negative value on failure

int uvc_host_get_frame(struct uvc_frame *frame, unsigned int timeout_ms);#

Get one UVC frame.

int uvc_host_get_frame(struct uvc_frame *frame, unsigned int timeout_ms);

Notes:

  • The call blocks until a frame is received or the timeout expires.

  • On success, frame is filled with the buffer info and userptr.

  • Every successful uvc_host_get_frame() must be paired with uvc_host_put_frame().

Return value:

  • 0 on success

  • negative value on failure

int uvc_host_put_frame(struct uvc_frame *frame);#

Return one frame buffer to the driver.

int uvc_host_put_frame(struct uvc_frame *frame);

Notes:

  • After the buffer is returned, the driver may reuse it.

  • userptr must not be accessed after this call.

void uvc_host_exit(void);#

Close the UVC device and release resources.

void uvc_host_exit(void);

Notes:

  • If streaming has already started, uvc_host_exit() performs the stream cleanup.

  • There is currently no separate uvc_host_stop_stream() API.

int uvc_host_get_devinfo(char *info, int len);#

Query device vendor and product information.

int uvc_host_get_devinfo(char *info, int len);

Notes:

  • On success, the returned string is typically in the form vendor#product.

  • The API can open the device temporarily even if uvc_host_init() has not been called yet.

int uvc_host_get_formats(struct uvc_format **fmts);#

Enumerate all supported device modes.

int uvc_host_get_formats(struct uvc_format **fmts);

Notes:

  • The return value is the number of formats.

  • *fmts is allocated internally and must be released with uvc_host_free_formats().

  • Each uvc_format entry corresponds to one concrete width + height + fourcc + frameinterval combination.

void uvc_host_free_formats(struct uvc_format **fmts);#

Release the array returned by uvc_host_get_formats().

void uvc_host_free_formats(struct uvc_format **fmts);

Raw-Format Conversion Helpers#

Besides direct frame access, three helper conversion APIs are provided:

int uvc_host_raw_to_nv12(const struct uvc_frame *frame, void *dst, size_t dst_len);
int uvc_host_raw_to_rgb565(const struct uvc_frame *frame, void *dst, size_t dst_len);
int uvc_host_raw_to_yuyv(const struct uvc_frame *frame, void *dst, size_t dst_len);

These helpers:

  • do not need an extra struct uvc_format

  • use the format negotiated by the most recent uvc_host_init()

  • apply only to raw pixel formats, not to MJPEG

uvc_host_raw_to_nv12#

Supported input formats:

  • YUY2

  • UYVY

  • NV12

  • I420

Required destination buffer size:

dst_len >= width * height * 3 / 2

Notes:

  • NV12 -> NV12 is a direct copy path.

  • If dst == frame->userptr and the current format is already NV12, the helper does not duplicate the copy.

uvc_host_raw_to_rgb565#

Supported input formats:

  • YUY2

  • UYVY

Required destination buffer size:

dst_len >= width * height * 2

uvc_host_raw_to_yuyv#

Supported input formats:

  • YUY2

  • UYVY

Required destination buffer size:

dst_len >= width * height * 2

Notes:

  • YUY2 is already in YUYV byte order.

  • If the current format is YUY2 and dst == frame->userptr, the helper avoids a duplicate copy.

  • If the current format is UYVY, the helper converts it to YUYV order.

Basic Usage Flow#

The typical call order is:

  1. Initialize VB.

  2. Optionally call uvc_host_get_devinfo() or uvc_host_get_formats().

  3. Call uvc_host_init().

  4. Call uvc_host_start_stream().

  5. Repeatedly call uvc_host_get_frame() and uvc_host_put_frame().

  6. Call uvc_host_exit() before exit.

Example 1: Write MJPEG Data to a File#

struct uvc_format fmt = {
    .width = 640,
    .height = 480,
    .fourcc = USBH_VIDEO_FOURCC_MJPEG,
    .frameinterval = 10000000 / 30,
};
struct uvc_frame frame;

kd_mpi_vb_set_config(&config);
kd_mpi_vb_init();

if (uvc_host_init(&fmt) != 0) {
    return -1;
}

if (uvc_host_start_stream() != 0) {
    uvc_host_exit();
    return -1;
}

if (uvc_host_get_frame(&frame, 3000) == 0) {
    FILE *file = fopen("/sdcard/test.jpg", "wb");
    if (file) {
        fwrite(frame.userptr, 1, frame.bytesused, file);
        fclose(file);
    }
    uvc_host_put_frame(&frame);
}

uvc_host_exit();

Example 2: Convert Raw Format to NV12 and Send It to VO#

struct uvc_format fmt = {
    .width = 640,
    .height = 480,
    .fourcc = USBH_VIDEO_FOURCC_YUY2,
    .frameinterval = 10000000 / 30,
};
struct uvc_frame frame;

if (uvc_host_init(&fmt) != 0) {
    return -1;
}

if (uvc_host_start_stream() != 0) {
    uvc_host_exit();
    return -1;
}

while (uvc_host_get_frame(&frame, 5000) == 0) {
    if (uvc_host_raw_to_nv12(&frame, vo_vaddr, vo_size) == 0) {
        kd_mpi_vo_insert_frame(K_VO_LAYER_VIDEO1, &vf_info);
    }
    uvc_host_put_frame(&frame);
}

uvc_host_exit();

Sample Program#

The current host-side sample is:

src/rtsmart/examples/mpp/sample_uvc_host/uvc_test.c

Command line:

Usage: ./sample_uvc_host [connector_type] [rotation] [fourcc] [width] [height] [total_frame]

Parameter description:

Parameter

Description

connector_type

Display type enum value

rotation

Whether to rotate, 0 or 1

fourcc

YUY2, UYVY, NV12, I420, MJPEG, or a numeric value

width

Target width

height

Target height

total_frame

Number of frames to process

Run examples:

/sdcard/app/examples/mpp/sample_uvc_host.elf 20 1 MJPEG 640 480 1000000
/sdcard/app/examples/mpp/sample_uvc_host.elf 20 1 YUY2 640 480 1000000

Notes:

  • The program prints both the input fourcc and the final negotiated fourcc.

  • The MJPEG path uses VDEC internally before display.

  • The non-MJPEG path converts the raw frame through uvc_host_raw_to_nv12() and then sends it to VO.

  • The sample periodically prints FPS.

Get connector_type#

Use:

list_connector

Configuration Options#

make menuconfig#

RT-Smart UserSpace Examples Configuration
-> Enable MPP examples
-> Enable Build sample_uvc_host

make rtsmart-menuconfig#

Components Configuration
-> Enable CherryUSB
-> Enable CherryUSB Host
-> CherryUSB Host Controller Driver (Using DesignWare Driver)

Components Configuration
-> Enable CherryUSB
-> Enable CherryUSB Host
-> Enable CherryUSB Host Class Driver
-> Enable UVC

Notes#

  1. Every successful uvc_host_get_frame() must be paired with uvc_host_put_frame().

  2. userptr must not be saved or reused after uvc_host_put_frame().

  3. If you only need device info or format enumeration, you can call uvc_host_get_devinfo() or uvc_host_get_formats() without calling uvc_host_init() first.

  4. For the VO display path, converting the raw format to NV12 first is the more common approach.

  5. It is not recommended to keep a UVC camera and other long-running high-bandwidth bulk devices on the same USB hub, because USB bandwidth may become insufficient.

Comments list
Comments
Log in