Skip to content

UVC User Guide


1. Overview

This article will introduce the method of configuring UVC on the device side and the implementation method of related applications on the device side.

2. Introduction to Keywords

  • EP

    EP stands for Endpoint, an important concept in the USB transmission protocol. In USB communication, data transmission is done through endpoints. A USB device can contain one or more endpoints, each with a unique endpoint address for data transmission between the device and the host. The transmission modes of the endpoint are mainly Control Transfer (Control), Bulk Transfer (Bulk), Interrupt Transfer (Interrupt), and Isochronous Transfer (Isochronous).

  • interval

    In USB transmission, data transmission is carried out in frames. Interval, also known as frame interval, is a parameter used to describe the time interval between two consecutive data transmissions.

  • maxpacket

    USB devices transmit data through endpoints, and when endpoints transmit data, they do so in packets. Maxpacket defines the maximum packet size of the corresponding endpoint in bytes.

  • burst

    In USB communication, data transmission is divided into frames, each frame containing a specific number of packets. Burst is the process of sending or receiving multiple packets within a frame period by a USB host or device. Since the bandwidth of USB is limited, using Burst can improve the speed of data transmission and thus improve the performance of the device.

  • mult

    Represents how many maxpackets can be sent in one transmission, depending on the hardware FIFO depth under its EP.

  • isoc

    Isoc transmission is a time-based transmission method that provides a real-time transmission mechanism for transmitting real-time data such as audio and video. The characteristics of isoc transmission are fixed bandwidth and data transmission rate, but no processing is done for retransmission and loss of packets, so it is not suitable for transmitting data with high requirements for data transmission delay and data integrity.

  • bulk

    Bulk transfer is a transfer-oriented transfer method that provides an efficient mechanism for transmitting large amounts of data. The characteristic of bulk transfer is that it does not guarantee the data transfer rate, but it has processed the retransmission and loss of packets, so it is suitable for transmitting data with low requirements for data transfer delay and data integrity.

  • PU

    PU (Processing Unit) is a descriptor used to describe video processing units. It contains various attributes and control options of video processing units.

  • XU

    XU (Extension Unit) is a descriptor used to describe extension units. It allows device manufacturers to define and support custom functions and control options to extend device functionality.

  • ConfigFs

    ConfigFs (Configuration Filesystem) is a virtual filesystem implemented in the Linux kernel for configuring and managing runtime parameters of devices and drivers. By representing configuration parameters of devices and drivers as files and directories, users can configure and control device behavior by modifying these files and directories.


3. Hardware Endpoint Description

As the only entity in USB transmission, endpoints complete communication between devices and hosts. Different endpoint configurations will affect the transmission rate of devices. Therefore, this article will introduce how endpoint configuration affects transmission rate. In addition, when using UVC devices at the same time may compound other functions such as RNDIS and DFU because each hardware endpoint has limited resources if endpoint parameter configuration is unreasonable may cause EP endpoint allocation failure.

3.1 Bandwidth Speed Description

Explanation: 8000 represents the maximum number of times USB can transmit per second. The USB2.0 protocol defines frames and microframes. Each frame has a length of 1ms. In high-speed mode, each frame is divided into 8 microframes with a length of 125us each. Therefore theoretically USB can send up to 8000 times per second.

3.1.1 bulk mode

Interval: 1-16

maxpacketsize: The maximum value can be set to 512 in USB2.0 protocol and 1024 in USB3.0 protocol.

burst: 1-13 The maximum value changes depending on hardware conditions.

Since bulk's actual bandwidth will vary depending on factors such as video stream resolution, specific transmission rates will depend on actual Device-side endpoint configuration and Host-side idle bandwidth.

3.1.2 isoc mode

  • usb2.0

    max_loadsize = 8000 / (2^(Interval-1)) * maxpacketsize * mult

  • usb3.0

    max_loadsize = 8000 / (2^(Interval-1)) * maxpacketsize * mult * burst

  • Range

    Interval: 1-16

    maxpacketsize: Maximum set to 1024

    mult: 1-3

    burst: 1-13 Maximum value changes depending on hardware conditions.

    Example: Interval=1, maxpacketsize=1024, mult=3, burst=5

    The EP rate used under USB2.0 is: 23.4MB/s

    The EP rate used under USB3.0 is: 117.1MB/s

3.2 EP Endpoint Allocation Description

3.2.1 Common Device EP Occupancy

Direction of Use EP Occupancy
RNDIS INT-in+BULK-in+BULK-out
UVC ISOC-in+INT-in OR BULK-in+INT-in
UAC ISOC-in OR ISOC-out
CDC (serial) INT-in+BULK-in+BULK-out
USB Mass Storage BULK-in+BULK-out
Human Interface Device (HID) INT-in+INT-out

3.2.2 EP Endpoint Allocation Example

If the current USB2.0 hardware EP situation is as follows:

(Scenario assessment should be based on the actual platform)

EP.NO Maxpacksize(Byte)
EP0 (fixed as CONTROL-mode, not assignable) 512
EP1 1024
EP2 128
EP3 512
EP4 1024
EP5 128
EP6 512

If using UVC (IN) + UAC (IN) + RNDIS (bulk-IN + bulk-OUT + int-IN), it will occupy five EPs. If the set maxpacketsize is 512, there are only four EPs that can support maxpacketsize greater than or equal to 512, so it cannot meet the allocation situation.


4. Environment Setup

The UVC environment is built on top of the basic environment setup. Device attributes can be completed by loading drivers and configuring scripts (ConfigFS). Script configuration is convenient for debugging. Loading driver configuration can be fixed and compiled into the kernel.

Note: The difference between the two configuration methods is whether g_sgs_gadget is loaded. The script configuration method only does not need to load g_sgs_gadget, and other UVC dependent modules still need to be loaded.

4.1 Basic Environment Setup

4.1.1 Hardware Driver Configuration

Please refer Doc:BSP Reference → 《USB Host/Device User Guide》.

4.1.2 Protocol Driver Configuration

Device Drivers --->
    <M> Multimedia support --->
        Media device types --->
            [*] Cameras and video grabbers
        Media core support --->
            <M> Video4linux core
            [*] Media Controller API

Device Drivers
    [*]USB support
        <M> USB Gadget Support  --->
            USB Gadget precomposed configurations ->
                <M> USB Sgs Gadget
                    [*] Include configuration with UVC (video)

The following ko files will be generated:
1, USB basic driver
  usb-common.ko
  usbcore.ko
2, UVC related dependent drivers
  videodev.ko
  videobuf2-common.ko
  videobuf2-v4l2.ko
  videobuf2-memops.ko
  videobuf2-vmalloc.ko
  videobuf2-dma-sg.ko
3, Gadget UVC driver
  udc-core.ko
  libcomposite.ko
  usb_f_uvc.ko

4.1.2 Configuration under USB3.0

Device Drivers  --->
        Sgs SOC platform drivers
                [*] Sgs USB support
                        <M>Sgs USB3 PHY drivers
                        <M>Simple Glue Layer of Sgs For DWC3
Device Drivers --->
    <M> Multimedia support --->
        Media device types --->
            [*] Cameras and video grabbers
        Media core support --->
            <M> Video4linux core
            [*] Media Controller API
    [*] USB support --->
        <M> Support for Host-side USB
        <M> DesignWare USB3 DRD Core Support
             DWC3 mode Selection (Gadget only mode)->
        <M> USB Gadget Support --->
            USB Peripheral Controller --->
                < > Sgs USB 2.0 Dvice Controller
            USB Gadget precomposed configurations ->
                <M> USB Sgs Gadget
                    [*] Include configuration with UVC (video)

The following ko files will be generated:
/**************/
USB basic driver
usb-common.ko
usbcore.ko
udc-core.ko
/**************/
UVC related dependent drivers
mc.ko
videodev.ko
videobuf2-common.ko
videobuf2-v4l2.ko
videobuf2-memops.ko
videobuf2-vmalloc.ko
videobuf2-dma-sg.ko
/**************/
USB3.0 driver
usbpll.ko
usb3-phy.ko
dwc3.ko
sgs-dwc3-of-simple.ko
libcomposite.ko
/**************/
UVC driver
usb_f_uvc.ko

4.1.3 Module Parameter Description

usb_f_uvc.ko

interrupt_ep_enable:

  • Parameter Description

    Indicates whether to enable the interrupt endpoint (Interrupt Endpoint).

  • Configuration

    insmod usb_f_uvc.ko interrupt_ep_enable=0
    

    Disable the interrupt EP endpoint.

4.2 UVC Device Attribute Configuration

4.2.1 Driver Configuration Description

To configure UVC through loading drivers, additional options need to be enabled in the kernel's menuconfig.

[*] USB support --->
    <M> USB Gadget Support --->
        <M> USB Sgs Gadget
         [*] Include configuration with UVC (video)

g_sgs_gadget.ko is generated.

g_sgs_gadget parameter description

bcdDevice:

  • Parameter Description

    bcdDevice is a field in the USB device descriptor used to indicate the firmware version of the device. It is a 16-bit field, usually composed of three bytes, in BCD (Binary-Coded Decimal) format.

  • Configuration

    insmod g_sgs_gadget.ko bcdDevice=0x0201
    

    If the value of bcdDevice is 0x0201, it means that the firmware version of the device is 2.01.

iSerialNumber:

  • Parameter Description

    iSerialNumber is a field in the USB device descriptor used to indicate the serial number of the device. It is an index value that points to an entry in the String Descriptor Table that contains the serial number string of the device.

  • Configuration

    insmod g_sgs_gadget.ko iSerialNumber=0
    

    The value of the iSerialNumber field is either zero or a non-zero index value. If it is zero, it means that the device does not provide serial number information.

streaming_maxburst:

  • Parameter Description

    streaming_maxburst is a parameter in UVC used to specify the maximum continuous transmission burst packet count (burst) allowed when transmitting video data. It defines the maximum number of packets that can be sent continuously in one transmission.

  • Configuration Description

    insmod g_sgs_gadget.ko streaming_maxburst=13,13 (two-way configuration)
    

    streaming_maxburst specifies the size of uvc transmission ep maxburst and supports multi-way configuration (separated by commas)

bulk_streaming_ep:

  • Parameter Description

    bulk_streaming_ep refers to the bulk transfer (Bulk Transfer) endpoint used for transmitting video data in UVC devices.

  • Configuration Description

    insmod g_sgs_gadget.ko bulk_streaming_ep=0
    

    bulk_streaming_ep = 0: use isoc mode

    bulk_streaming_ep = 1: use bulk mode

idProduct:

  • Parameter Description

    idProduct is a field in the USB device descriptor used to identify the product ID of the device. Each USB device has a unique product ID.

  • Configuration

    insmod g_sgs_gadget.ko idProduct=0x3311
    

    Product ID (idProduct) is a 16-bit integer value used to represent the specific product model or version of a device. It is assigned by the manufacturer of the device and set during the manufacturing process of the device. The host system can identify and distinguish different USB devices by reading the product ID in the device descriptor.

iManufacturer:

  • Parameter Description

    iManufacturer is a field in the USB device descriptor used to identify the manufacturer name of the device. It is an index pointing to a string descriptor that contains manufacturer name information for the device.

  • Configuration

    insmod g_sgs_gadget.ko iManufacturer=0
    

    The manufacturer name string descriptor is a string containing the actual manufacturer name, usually provided by the manufacturer of the device and set during the manufacturing process of the device. The host system can obtain the manufacturer name of the device by reading the value of the iManufacturer field in the device descriptor and then looking up the corresponding string descriptor in the string descriptor list.

streaming_interval:

  • Parameter Description

    A parameter in the UVC (USB Video Class) protocol used to represent the interval time for video stream transmission. In UVC, video streams are transmitted in frames, each frame containing a complete image. streaming_interval represents the time interval between two consecutive video frames, usually in milliseconds. It is used to determine the rate and stability of video frame transmission.

  • Configuration Description

    insmod g_sgs_gadget.ko streaming_interval=1,1 (two-way configuration)
    

    streaming_interval range is 1-16.

streaming_name:

  • Parameter Description

    It is used to identify the unique name or identifier of a video stream.

  • Configuration Description

    insmod g_sgs_gadget.ko streaming_name=vide0,video1 (two-channel configuration)
    

uvc_function_enable:

  • Parameter Description

    Used to configure multi-channels Functions. The number of channels can also be selected when configuring g_sgs_gadget in menuconfig.

    Device Drivers
        [*]USB support
            <M> USB Gadget Support  --->
            USB Gadget precomposed configurations ->
                    <M> USB Sgs Gadget
                        [*] Include configuration with UVC (video)
                    (1) Muti Stream Under One Function
    //This can be set to other values. If set to 2, one UVC will share one control interface.
    
  • Configuration Description

    insmod g_sgs_gadget.ko uvc_function_enable=2 (configure two-channel UVC)
    

rndis_function_enable:

  • Parameter Description

    Used to configure uvc's composite device configuration and enable rndis at the same time.

    Device Drivers
        [*]USB support
            <M> USB Gadget Support  --->
            USB Gadget precomposed configurations ->
                    <M> USB Sgs Gadget
                        [*] Include configuration with UVC (video)
                       (1) Muti Stream Under One Function
                        [*] Include configuration with RNDSI
    
  • Configuration Description

    insmod g_sgs_gadget.ko rndis_function_enable=1
    
  • Note

    If you find that there is no rndis device after configuring the above composite configuration, it is because at this time the board side is a usb composite device. Only after the uvc application is running will the rndis device be recognized by the host side.

4.2.2 Script Configuration Description

4.2.2.1 Script Example
#!/bin/sh

USB_DEVICE_DIR=/sys/kernel/config/usb_gadget/s-star
USB_CONFIGS_DIR=/sys/kernel/config/usb_gadget/s-star/configs/default.1
USB_FUNCTIONS_DIR=/sys/kernel/config/usb_gadget/s-star/functions

FUNCTION_ENALBE=0
# stream number
UVC_FUNCTION_ENABLE=0
RNDIS_FUNCTION_ENABLE=0

#uvc
UVC_STREAM_INDEX=0
UVC_STREAMING_MAX_PACKET_ARRAY="3072,1024"
UVC_STREAMING_MAX_BURST_ARRAY="13,13"
UVC_STREAMING_INTERVAL_ARRAY="1,1,1,1,1,1"
UVC_STREAMING_NAME_ARRAY="UVC Camera 0,UVC Camera 1"
UVC_STREAMING_FORMAT_YUV_ENABLE=0
UVC_STREAMING_FORMAT_NV12_ENABLE=0
UVC_STREAMING_FORMAT_MJPEG_ENABLE=1
UVC_STREAMING_FORMAT_H264_ENABLE=1
UVC_STREAMING_FORMAT_H265_ENABLE=1
UVC_VERSION=0x0100  #uvc1.5: 0x0150  uvc1.0:0x0100
UVC_MODE=0x1        #0x0 :isoc mode  o0x1:bulk mode



USB_DEVICE_PID=0x0102
USB_DEVICE_VID=0x1d6b
MANUFACTURER="Linux Foundation"
PRODUCT="USB GADGET"
SERIAL_NUM="0123"
CONFIGURATION="composite device"
###########################################UVC CONFIG######################################################
# bBitsPerPixel(uncompressed/framebase)/bDefaultFrameIndex/bmaControls/guidFormat(uncompressed/framebase)
config_uvc_format_yuyv()
{
    mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv
    echo 0x10 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv/bBitsPerPixel
    echo 0x01 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv/bDefaultFrameIndex
    echo 0x00 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv/bmaControls
    echo -ne \\x59\\x55\\x59\\x32\\x00\\x00\\x10\\x00\\x80\\x00\\x00\\xaa\\x00\\x38\\x9b\\x71 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv/guidFormat
}

config_uvc_format_nv12()
{
    mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12
    echo 0x0C > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/bBitsPerPixel
    echo 0x01 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/bDefaultFrameIndex
    echo 0x04 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/bmaControls
    echo -ne \\x4e\\x56\\x31\\x32\\x00\\x00\\x10\\x00\\x80\\x00\\x00\\xaa\\x00\\x38\\x9b\\x71 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/guidFormat
}

config_uvc_format_mjpeg()
{
    mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/mjpeg/default
    echo 0x01 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/mjpeg/default/bDefaultFrameIndex
    echo 0x04 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/mjpeg/default/bmaControls
}

config_uvc_format_h264()
{
    mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264
    echo 0x10 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/bBitsPerPixel
    echo 0x01 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/bDefaultFrameIndex
    echo 0x04 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/bmaControls
    echo -ne \\x48\\x32\\x36\\x34\\x00\\x00\\x10\\x00\\x80\\x00\\x00\\xaa\\x00\\x38\\x9b\\x71 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/guidFormat
}

config_uvc_format_h265()
{
    mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265
    echo 0x10 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265/bBitsPerPixel
    echo 0x01 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265/bDefaultFrameIndex
    echo 0x00 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265/bmaControls
    echo -ne \\x48\\x32\\x36\\x35\\x00\\x00\\x10\\x00\\x80\\x00\\x00\\xaa\\x00\\x38\\x9b\\x71 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265/guidFormat
}

# bmCapabilities/dwDefaultFrameInterval/dwFrameInterval/dwMaxBitRate/dwMaxVideoFrameBufferSize(uncompressed/mjpeg)/dwMinBitRate/wHeight/wWidth
config_uvc_frame_yuyv()
{
    UVC_FRAME_WIDTH=$1
    UVC_FRAME_HEIGHT=$2
    UVC_FRAME_INTERVAL=$3

    mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv/${UVC_FRAME_HEIGHT}p
    echo 0x00 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv/${UVC_FRAME_HEIGHT}p/bmCapabilities
    echo $UVC_FRAME_INTERVAL > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv/${UVC_FRAME_HEIGHT}p/dwDefaultFrameInterval
    echo -e "333333\n666666\n1000000" > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv/${UVC_FRAME_HEIGHT}p/dwFrameInterval
    echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*16*30)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv/${UVC_FRAME_HEIGHT}p/dwMaxBitRate
    echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*2)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv/${UVC_FRAME_HEIGHT}p/dwMaxVideoFrameBufferSize
    echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*16*10)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv/${UVC_FRAME_HEIGHT}p/dwMinBitRate
    echo $UVC_FRAME_HEIGHT > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv/${UVC_FRAME_HEIGHT}p/wHeight
    echo $UVC_FRAME_WIDTH > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv/${UVC_FRAME_HEIGHT}p/wWidth
}

config_uvc_frame_nv12()
{
    UVC_FRAME_WIDTH=$1
    UVC_FRAME_HEIGHT=$2
    UVC_FRAME_INTERVAL=$3

    mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/${UVC_FRAME_HEIGHT}p
    echo 0x00 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/${UVC_FRAME_HEIGHT}p/bmCapabilities
    echo $UVC_FRAME_INTERVAL > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/${UVC_FRAME_HEIGHT}p/dwDefaultFrameInterval
    echo -e "333333\n666666\n1000000" > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/${UVC_FRAME_HEIGHT}p/dwFrameInterval
    echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*12*30)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/${UVC_FRAME_HEIGHT}p/dwMaxBitRate
    echo | awk "{print $UVC_FRAME_WIDTH*$UVC_FRAME_HEIGHT*3/2}" > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/${UVC_FRAME_HEIGHT}p/dwMaxVideoFrameBufferSize
    echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*12*10)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/${UVC_FRAME_HEIGHT}p/dwMinBitRate
    echo $UVC_FRAME_HEIGHT > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/${UVC_FRAME_HEIGHT}p/wHeight
    echo $UVC_FRAME_WIDTH > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/${UVC_FRAME_HEIGHT}p/wWidth
}

config_uvc_frame_mjpeg()
{
    UVC_FRAME_WIDTH=$1
    UVC_FRAME_HEIGHT=$2
    UVC_FRAME_INTERVAL=$3

    mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/mjpeg/default/${UVC_FRAME_HEIGHT}p
    echo 0x00 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/mjpeg/default/${UVC_FRAME_HEIGHT}p/bmCapabilities
    echo $UVC_FRAME_INTERVAL > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/mjpeg/default/${UVC_FRAME_HEIGHT}p/dwDefaultFrameInterval
    echo -e "333333\n666666\n1000000" > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/mjpeg/default/${UVC_FRAME_HEIGHT}p/dwFrameInterval
    echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*16*30)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/mjpeg/default/${UVC_FRAME_HEIGHT}p/dwMaxBitRate
    echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*2)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/mjpeg/default/${UVC_FRAME_HEIGHT}p/dwMaxVideoFrameBufferSize
    echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*16*10)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/mjpeg/default/${UVC_FRAME_HEIGHT}p/dwMinBitRate
    echo $UVC_FRAME_HEIGHT > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/mjpeg/default/${UVC_FRAME_HEIGHT}p/wHeight
    echo $UVC_FRAME_WIDTH > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/mjpeg/default/${UVC_FRAME_HEIGHT}p/wWidth
}

config_uvc_frame_h264()
{
    UVC_FRAME_WIDTH=$1
    UVC_FRAME_HEIGHT=$2
    UVC_FRAME_INTERVAL=$3

    mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p
    echo 0x00 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/bmCapabilities
    echo $UVC_FRAME_INTERVAL > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/dwDefaultFrameInterval
    echo -e "333333\n666666\n1000000" > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/dwFrameInterval
    echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*16*30)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/dwMaxBitRate
    echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*16*10)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/dwMinBitRate
    echo $UVC_FRAME_HEIGHT > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/wHeight
    echo $UVC_FRAME_WIDTH > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/wWidth
}

config_uvc_frame_h265()
{
    UVC_FRAME_WIDTH=$1
    UVC_FRAME_HEIGHT=$2
    UVC_FRAME_INTERVAL=$3

    mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265/${UVC_FRAME_HEIGHT}p
    echo 0x00 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265/${UVC_FRAME_HEIGHT}p/bmCapabilities
    echo $UVC_FRAME_INTERVAL > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265/${UVC_FRAME_HEIGHT}p/dwDefaultFrameInterval
    echo -e "333333\n666666\n1000000" > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265/${UVC_FRAME_HEIGHT}p/dwFrameInterval
    echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*16*30)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265/${UVC_FRAME_HEIGHT}p/dwMaxBitRate
    echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*16*10)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265/${UVC_FRAME_HEIGHT}p/dwMinBitRate
    echo $UVC_FRAME_HEIGHT > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265/${UVC_FRAME_HEIGHT}p/wHeight
    echo $UVC_FRAME_WIDTH > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265/${UVC_FRAME_HEIGHT}p/wWidth
}

config_uvc_yuv()
{
    config_uvc_format_yuyv
    config_uvc_frame_yuyv 320 240 333333
    config_uvc_frame_yuyv 640 480 333333
    config_uvc_frame_yuyv 1280 720 333333
    config_uvc_frame_yuyv 1920 1080 333333
    config_uvc_frame_yuyv 2560 1440 333333
    config_uvc_frame_yuyv 3840 2160 666666
    ln -s ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/yuyv ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/header/default/yuyv
}

config_uvc_nv12()
{
    config_uvc_format_nv12
    config_uvc_frame_nv12 320 240 333333
    config_uvc_frame_nv12 640 480 333333
    config_uvc_frame_nv12 1280 720 333333
    config_uvc_frame_nv12 1920 1080 333333
    config_uvc_frame_nv12 2560 1440 333333
    config_uvc_frame_nv12 3840 2160 666666
    ln -s ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12 ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/header/default/nv12
}

config_uvc_mjpeg()
{
    config_uvc_format_mjpeg
    config_uvc_frame_mjpeg 320 240 333333
    config_uvc_frame_mjpeg 640 480 333333
    config_uvc_frame_mjpeg 1280 720 333333
    config_uvc_frame_mjpeg 1920 1080 333333
    config_uvc_frame_mjpeg 2560 1440 333333
    config_uvc_frame_mjpeg 3840 2160 333333
    ln -s ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/mjpeg/default ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/header/default/mjpeg
}

config_uvc_h264()
{
    config_uvc_format_h264
    config_uvc_frame_h264 320 240 333333
    config_uvc_frame_h264 640 480 333333
    config_uvc_frame_h264 1280 720 333333
    config_uvc_frame_h264 1920 1080 333333
    config_uvc_frame_h264 2560 1440 333333
    config_uvc_frame_h264 3840 2160 333333
    ln -s ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264 ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/header/default/h264
}

config_uvc_h265()
{
    config_uvc_format_h265
    config_uvc_frame_h265 320 240 333333
    config_uvc_frame_h265 640 480 333333
    config_uvc_frame_h265 1280 720 333333
    config_uvc_frame_h265 1920 1080 333333
    config_uvc_frame_h265 2560 1440 333333
    config_uvc_frame_h265 3840 2160 333333
    ln -s ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h265 ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/header/default/h265
}


config_uvc()
{
    UVC_STREAMING_MAX_PACKET=`echo $UVC_STREAMING_MAX_PACKET_ARRAY | awk -F ',' '{print $'$((UVC_STREAM_INDEX+1))'}'`
    UVC_STREAMING_MAX_BURST=`echo $UVC_STREAMING_MAX_BURST_ARRAY | awk -F ',' '{print $'$((UVC_STREAM_INDEX+1))'}'`
    UVC_STREAMING_INTERVAL=`echo $UVC_STREAMING_INTERVAL_ARRAY | awk -F ',' '{print $'$((UVC_STREAM_INDEX+1))'}'`
    UVC_STREAMING_NAME=`echo $UVC_STREAMING_NAME_ARRAY | awk -F ',' '{print $'$((UVC_STREAM_INDEX+1))'}'`

    # Configure speed/name
    # streaming_maxpacket/streaming_maxburst/streaming_interval/bulk_streaming_ep
    mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}
    echo $UVC_STREAMING_MAX_PACKET > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming_maxpacket
    echo $UVC_STREAMING_MAX_BURST > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming_maxburst
    echo $UVC_STREAMING_INTERVAL > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming_interval
    echo -n $UVC_STREAMING_NAME > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming_name
    echo $UVC_MODE > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/bulk_streaming_ep

    # Configure control
    # bcdUVC/dwClockFrequency
    mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/control/header/default
    echo $UVC_VERSION > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/control/header/default/bcdUVC
    echo 0x02DC6C00 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/control/header/default/dwClockFrequency
    ln -s ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/control/header/default ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/control/class/fs/default
    ln -s ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/control/header/default ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/control/class/ss/default

    # Configure streaming
    mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/header/default

    if [ $UVC_STREAMING_FORMAT_YUV_ENABLE -gt 0 ]; then
        config_uvc_yuv
    fi
    if [ $UVC_STREAMING_FORMAT_NV12_ENABLE -gt 0 ]; then
        config_uvc_nv12
    fi
    if [ $UVC_STREAMING_FORMAT_MJPEG_ENABLE -gt 0 ]; then
        config_uvc_mjpeg
    fi
    if [ $UVC_STREAMING_FORMAT_H264_ENABLE -gt 0 ]; then
        config_uvc_h264
    fi
    if [ $UVC_STREAMING_FORMAT_H265_ENABLE -gt 0 ]; then
        config_uvc_h265
    fi

    ln -s ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/header/default ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/class/fs/default
    ln -s ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/header/default ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/class/hs/default
    ln -s ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/header/default ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/class/ss/default
}

###########################################RNDIS CONFIG####################################################
config_rndis()
{
    # dev_addr/host_addr/qmult/class/subclass/protocol
    mkdir ${USB_FUNCTIONS_DIR}/rndis.instance0
}

config_clear()
{
    if [ ! -d $USB_DEVICE_DIR ];then
        return
    fi

    echo "" > ${USB_DEVICE_DIR}/UDC

    for i in `ls ${USB_CONFIGS_DIR}/ | grep ".instance"`
    do
        rm ${USB_CONFIGS_DIR}/$i
    done

    if [ -d $USB_CONFIGS_DIR/strings/0x409 ]; then
        rmdir  $USB_CONFIGS_DIR/strings/0x409
    fi
    if [ -d $USB_CONFIGS_DIR ]; then
        rmdir  $USB_CONFIGS_DIR
    fi

    for i in `ls $USB_FUNCTIONS_DIR | grep .instance`; do
        if [ -n `echo $i | grep uvc` ]; then
            rm -f $USB_FUNCTIONS_DIR/$i/control/class/fs/default
            rm -f $USB_FUNCTIONS_DIR/$i/control/class/ss/default
            rm -f $USB_FUNCTIONS_DIR/$i/streaming/class/fs/default
            rm -f $USB_FUNCTIONS_DIR/$i/streaming/class/hs/default
            rm -f $USB_FUNCTIONS_DIR/$i/streaming/class/ss/default
            rm -f $USB_FUNCTIONS_DIR/$i/streaming/header/default/yuyv
            rm -f $USB_FUNCTIONS_DIR/$i/streaming/header/default/nv12
            rm -f $USB_FUNCTIONS_DIR/$i/streaming/header/default/mjpeg
            rm -f $USB_FUNCTIONS_DIR/$i/streaming/header/default/h264
            rm -f $USB_FUNCTIONS_DIR/$i/streaming/header/default/h265

            if [ -d $USB_FUNCTIONS_DIR/$i/streaming/uncompressed/yuyv ]; then
                rmdir $USB_FUNCTIONS_DIR/$i/streaming/uncompressed/yuyv/*p
                rmdir $USB_FUNCTIONS_DIR/$i/streaming/uncompressed/yuyv
            fi
            if [ -d $USB_FUNCTIONS_DIR/$i/streaming/uncompressed/nv12 ]; then
                rmdir $USB_FUNCTIONS_DIR/$i/streaming/uncompressed/nv12/*p
                rmdir $USB_FUNCTIONS_DIR/$i/streaming/uncompressed/nv12
            fi
            if [ -d $USB_FUNCTIONS_DIR/$i/streaming/mjpeg/default ]; then
                rmdir $USB_FUNCTIONS_DIR/$i/streaming/mjpeg/default/*p
                rmdir $USB_FUNCTIONS_DIR/$i/streaming/mjpeg/default
            fi
            if [ -d $USB_FUNCTIONS_DIR/$i/streaming/framebase/h264 ]; then
                rmdir $USB_FUNCTIONS_DIR/$i/streaming/framebase/h264/*p
                rmdir $USB_FUNCTIONS_DIR/$i/streaming/framebase/h264
            fi
            if [ -d $USB_FUNCTIONS_DIR/$i/streaming/framebase/h265 ]; then
                rmdir $USB_FUNCTIONS_DIR/$i/streaming/framebase/h265/*p
                rmdir $USB_FUNCTIONS_DIR/$i/streaming/framebase/h265
            fi

            if [ -d $USB_FUNCTIONS_DIR/$i/control/header/default ]; then
                rmdir $USB_FUNCTIONS_DIR/$i/control/header/default
            fi
            if [ -d $USB_FUNCTIONS_DIR/$i/streaming/header/default ]; then
                rmdir $USB_FUNCTIONS_DIR/$i/streaming/header/default
            fi

        fi
        rmdir $USB_FUNCTIONS_DIR/$i
    done

    if [ -d $USB_DEVICE_DIR/strings/0x409 ]; then
        rmdir  $USB_DEVICE_DIR/strings/0x409
    fi
    rmdir $USB_DEVICE_DIR
}

usage()
{
    echo -e "Usage:./gadget-configfs.sh -x NUM\n"
    echo -e "\t -a        UVC"
    echo -e "\t -z        NO CLASS"
    echo -e "\t Examples: ./gadget-configfs.sh -a1        ---> one UVC device"
}

main()
{
    while getopts ":a:b:c:d:e:f:g:h:i:j:z" opt
    do
        case $opt in
        a)
            UVC_FUNCTION_ENABLE=$OPTARG
            ;;
        z)
            config_clear
            exit 0
            ;;
        ?)
            usage
            exit 1
            ;;
        esac
    done

    if [ $UVC_FUNCTION_ENABLE -eq 0 ] ; then
        usage
        exit 1
    fi


    config_clear
    echo "UVC:$UVC_FUNCTION_ENABLE"
    if [ -d /sys/kernel/config/usb_gadget ]
    then
    umount /sys/kernel/config
    fi

    mount -t configfs none /sys/kernel/config
    mkdir $USB_DEVICE_DIR
    mkdir $USB_CONFIGS_DIR
    mkdir ${USB_DEVICE_DIR}/strings/0x409
    mkdir ${USB_CONFIGS_DIR}/strings/0x409

    # Configure configs
    # MaxPower/bmAttributes
    echo 0x02 > ${USB_CONFIGS_DIR}/MaxPower
    echo 0xC0 > ${USB_CONFIGS_DIR}/bmAttributes

    # Configure strings
    # manufacturer/product/serialnumber/configuration
    echo "$MANUFACTURER" > ${USB_DEVICE_DIR}/strings/0x409/manufacturer
    echo "$PRODUCT" > ${USB_DEVICE_DIR}/strings/0x409/product
    echo "$SERIAL_NUM" > ${USB_DEVICE_DIR}/strings/0x409/serialnumber
    echo "$CONFIGURATION" > ${USB_CONFIGS_DIR}/strings/0x409/configuration

    # functions
    if [ $RNDIS_FUNCTION_ENABLE -gt 0 ]; then
        config_rndis
        ln -s ${USB_FUNCTIONS_DIR}/rndis.instance0 ${USB_CONFIGS_DIR}/rndis.instance0
    fi

    # functions
    while [ $UVC_STREAM_INDEX -lt $UVC_FUNCTION_ENABLE ]
    do
        config_uvc
        ln -s ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX} ${USB_CONFIGS_DIR}/uvc.instance${UVC_STREAM_INDEX}
        let UVC_STREAM_INDEX++
    done

    # Configure device
    # UDC/bDeviceClass/bDeviceProtocol/bDeviceSubClass/bMaxPacketSize0/bcdDevice/bcdUSB/idProduct/idVendor
    echo 0xef > ${USB_DEVICE_DIR}/bDeviceClass
    echo 0x01 > ${USB_DEVICE_DIR}/bDeviceProtocol
    echo 0x02 > ${USB_DEVICE_DIR}/bDeviceSubClass
    echo 0x00 > ${USB_DEVICE_DIR}/bMaxPacketSize0
    echo 0x0419 > ${USB_DEVICE_DIR}/bcdDevice
    echo 0x0200 > ${USB_DEVICE_DIR}/bcdUSB
    echo $USB_DEVICE_PID > ${USB_DEVICE_DIR}/idProduct
    echo $USB_DEVICE_VID > ${USB_DEVICE_DIR}/idVendor
    UDC=`ls /sys/class/udc/ | head -n 1`
    echo $UDC > ${USB_DEVICE_DIR}/UDC
}


main $@
4.2.2.2 Script Execution
./xxxx.sh -a2

Enable two-channel uvc device nodes. After successful execution, there are video0 and video1 device nodes under /dev.

./xxxx.sh -z

Clear all current configuration items.

Note: Relying on configfs to configure uvc cannot load the g_sgs_gadget driver because they are all doing configuration actions.

4.2.2.3 Script Parameter Description
Parameter Description Example
UVC_STREAMING_NAME_ARRAY Configure the name of each UVC device Configure the names of two uvc devices: UVC_STREAMING_NAME_ARRAY="UVC Camera 0,UVC Camera 1"
UVC_STREAMING_MAX_PACKET_ARRAY Configure the maxpacket attribute value of each uvc device Configure the maxpacket of two uvc devices to 3072 and 1024: UVC_STREAMING_MAX_PACKET_ARRAY="3072,1024"
UVC_STREAMING_MAX_BURST_ARRAY Configure the burst attribute value of each uvc device Configure the brust of two uvc devices to 13 and 13: UVC_STREAMING_MAX_BURST_ARRAY="13,13"
UVC_STREAMING_INTERVAL_ARRAY Configure the interval attribute value of each uvc device Configure the interval of two uvc devices to 1: UVC_STREAMING_INTERVAL_ARRAY="1,1"
UVC_MODE Configure the transmission mode of the uvc device UVC_MODE = 0x0: isoc mode
UVC_MODE = 0x1: bulk mode
UVC_STREAMING_FORMAT_YUV_ENABLE Whether to enable YUV data format UVC_STREAMING_FORMAT_YUV_ENABLE =0:Disable
UVC_STREAMING_FORMAT_YUV_ENABLE=1:Enable
UVC_STREAMING_FORMAT_NV12_ENABLE Whether to enable NV12 data format UVC_STREAMING_FORMAT_NV12_ENABLE =0:Disable
UVC_STREAMING_FORMAT_NV12_ENABLE=1:Enable
UVC_STREAMING_FORMAT_MJPEG_ENABLE Whether to enable Mjpeg data format UVC_STREAMING_FORMAT_MJPEG_ENABLE =0:Disable
UVC_STREAMING_FORMAT_MJPEG_ENABLE=1:Enable
UVC_STREAMING_FORMAT_H264_ENABLE Whether to enable H264 data format UVC_STREAMING_FORMAT_H264_ENABLE =0:Disable
UVC_STREAMING_FORMAT_H264_ENABLE=1:Enable
UVC_STREAMING_FORMAT_H265_ENABLE Whether to enable H265 data format UVC_STREAMING_FORMAT_H265_ENABLE =0:Disable
UVC_STREAMING_FORMAT_H265_ENABLE=1:Enable
UVC_VERSION=0x0100 Choose uvc version UVC_VERSION =0x0150:uvc1.5 version
UVC_VERSION=0x0100:uvc1.0 version

5. Programming Guide

  • StreamingBuf related api

    Control Code Description
    VIDIOC_QBUF Used to add a buffer frame to the buffer queue for processing or acquisition by the driver. It passes an idle buffer frame to the driver so that the driver can fill data into that buffer frame
    VIDIOC_DQBUF Used to retrieve a filled video frame from the video buffer queue
    VIDIOC_REQBUFS Used to request allocation of V4L2 driver's video buffers
    VIDIOC_QUERYBUF Used to query information about buffers in the driver, such as buffer size and offset address. Its main function is to be able to access and operate buffers in user space.
    VIDIOC_STREAMON Used to start transmission of video stream data. This command is usually used after device initialization to notify the device to start collecting and transmitting video data
    VIDIOC_STREAMOFF Used to stop transmission of video streams
  • Event control related API

    Control Code Description
    VIDIOC_G_FMT Used to obtain the current format information of the collected or output video, such as resolution, frame rate, pixel format, etc.
    VIDIOC_S_FMT Request to set the format of the video data (such as the width, height, pixel format of the image, etc.)
    VIDIOC_DQEVENT Get information about video device events, such as data overflow, video stream loss, etc.
    UVCIOC_SEND_RESPONSE Used to send a response to a UVC request. This command can be used for communication between the UVC controller and the USB device
    VIDIOC_QUERYCAP Used to query the capabilities and attributes of the device, such as device name, driver name, supported video formats, supported input/output formats, etc.
    VIDIOC_SUBSCRIBE_EVENT Subscribe V4L2 device events to user space. V4L2 devices may generate multiple events, such as hot-plug events for camera modules and frame rate change events

    For detailed introduction or explanation of other APIs, please refer to: https://www.kernel.org/doc/html/v4.11/media/uapi/v4l/

5.2 Adding PU Events

  • Description

    Processing Unit (PU) usually refers to the processing unit in a video capture device used for processing and adjusting images to provide various video effects and enhancement functions. PU can control image attributes such as brightness, contrast, saturation and hue. It can also apply image enhancement algorithms such as sharpening, noise reduction and auto exposure. PU can also control device transmission frame rate, image format and resolution parameters.

  • PU recognition process

    • USBCAM side

      Add control options that PU can support in kernel

    • UVC control side

      If it is determined that the control option can be used, send a control command

    • USBCAM side

      Listen for PU events under APP and actually handle command processing and data processing for added control options

5.2.1 Adding Image Control Attributes

Example: Add brightness adjustment instruction

5.2.1.1 KERNEL side
  • Description

    The driver side mainly modifies bmControls under the PU descriptor structure. bmControls is a bitmap (Bitmap) used to represent different control options supported by UVC devices. Each bit corresponds to a specific control option and is used to indicate whether that option is available or supported.

    The following are the control options supported by kernel:

    bmControls
    
    D00                     Brightness
    D01                     Contrast
    D02                     Hue
    D03                     Saturation
    D04                     Sharpness
    D05                     Gamma
    D06                     White Balance Temperature
    D07                     White Balance Component
    D08                     Backlight Compensation
    D09                     Gain
    D10                     Power Line Frequency
    D11                     Hue, Auto
    D12                     White Balance Temperature, Auto
    D13                     White Balance Component, Auto
    D14                     Digital Multiplier
    D15                     Digital Multiplier Limit
    

    For more configuration of PU options in UVC protocol, please refer to: https://www.usb.org/document-library/video-class-v15-document-set

  • Modification example: Brightness adjustment corresponds to UVC_PU_BACKLIGHT_COMPENSATION_CONTROL

    kernel\drivers\sgs\usb\gadget\legacy\bind_uvc.c
    
    static struct uvc_processing_unit_descriptor uvc_processing = {
    #if (USB_VIDEO_CLASS_VERSION == 0x150)
        .bLength = UVC_DT_PROCESSING_UNIT_SIZE(3),
        .bControlSize = 3,
    #else
        .bLength = UVC_DT_PROCESSING_UNIT_SIZE(2),
        .bControlSize = 2,
    #endif
        .bDescriptorType = USB_DT_CS_INTERFACE,
        .bDescriptorSubType = UVC_VC_PROCESSING_UNIT,
        .bUnitID = UVC_PU_ID,
        .bSourceID = UVC_IT_ID,
        .wMaxMultiplier = cpu_to_le16(16 * 1024),
    -----
        .bmControls[0] = 0,
    -----
    +++++
        .bmControls[0] = 0x01,
    +++++
        .bmControls[1] = 0,
    #if (USB_VIDEO_CLASS_VERSION == 0x150)
        .bmControls[2] = 0,
    #endif
        .iProcessing = 0,
    };
    
5.2.1.2 APP side
  • Description

    The demo side mainly completes command processing and data processing for the added PU instructions.

  • Modification example

    Note: The v4l2_event structure is used in the AppDemo to receive PU instructions and data

    Specific control description of PU instructions on the APP side, for example:

    sdk/verify/app_demo/intrnal/uvc/st_uvc.c
    
    modify one:
    
    static int8_t _UVC_Events_Process_Control(ST_UVC_Device_t *pdev,uint8_t req,uint8_t cs,uint8_t entity_id,uint8_t len,struct uvc_request_data *resp)
    {
    switch (entity_id)
        {
        /* Camera terminal */
        case UVC_VC_INPUT_TERMINAL_ID:
        break;
    add++++++++++++++++++++++++++++++++++++++++++++++
            /* Processing unit */
        case UVC_VC_PROCESSING_UNIT_ID:
            switch (cs)
            {
                case UVC_PU_BRIGHTNESS_CONTROL:
                    switch (req)
                    {
                    case UVC_SET_CUR:
                        resp->length = 2;
                        pdev->request_error_code.data[0] = 0x00;
                        pdev->request_error_code.length = 1;
                        break;
                    case UVC_GET_CUR:
                        resp->length = 2;
                        resp->data[0] = pu_brightness_data[0];
                        resp->data[1] = pu_brightness_data[1];
                        pdev->request_error_code.data[0] = 0x00;
                        pdev->request_error_code.length = 1;
                        break;
                    case UVC_GET_MIN:
                        resp->length = 2;
                        resp->data[0] = 0x00;
                        resp->data[1] = 0x00;
                        pdev->request_error_code.data[0] = 0x00;
                        pdev->request_error_code.length = 1;
                        break;
                    case UVC_GET_MAX:
                        resp->length = 2;
                        resp->data[0] = 0xFF;
                        resp->data[1] = 0x00;
                        pdev->request_error_code.data[0] = 0x00;
                        pdev->request_error_code.length = 1;
                        break;
                    case UVC_GET_RES:
                        resp->length = 2;
                        resp->data[0] = 0x01;
                        resp->data[1] = 0x00;
                        pdev->request_error_code.data[0] = 0x00;
                        pdev->request_error_code.length = 1;
                        break;
                    case UVC_GET_INFO:
                        resp->length = 1;
                        resp->data[0] = 0x03;
                        pdev->request_error_code.data[0] = 0x00;
                        pdev->request_error_code.length = 1;
                        break;
                    case UVC_GET_DEF:
                        resp->length = 2;
                        pu_brightness_data[0] = resp->data[0] = 0x00;
                        pu_brightness_data[1] = resp->data[1] = 0x00;
                        pdev->request_error_code.data[0] = 0x00;
                        pdev->request_error_code.length = 1;
                        break;
    
                    /* not support GET_LEN cmd */
                    case UVC_GET_LEN:
                    default:
                        /*
                        * We don't support this control, so STALL the
                        * default control ep.
                        */
                        resp->length = -EL2HLT;
                        /*
                        * For every unsupported control request
                        * set the request error code to appropriate
                        * code.
                        */
                        pdev->request_error_code.data[0] = 0x07;
                        pdev->request_error_code.length = 1;
                        break;
                }
                break;
    add++++++++++++++++++++++++++++++++++++++++++++++
    }
    
    modify two:
    
    static int8_t _UVC_Events_Process_Data(ST_UVC_Device_t * pdev, struct uvc_request_data *data)
    {
    if(UVC_CONTROL_INTERFACE == pdev->control.ctype)
    {
    add++++++++++++++++++++++++++++++++++++++++++++++
    return usb_vc_out_data(pdev, pdev->control.entity, pdev->control.control, pdev->control.length, data);
    add++++++++++++++++++++++++++++++++++++++++++++++
    }
    
    }
    add++++++++++++++++++++++++++++++++++++++++++++++
    // process PU, CT, XU job.
    int8_t usb_vc_out_data(ST_UVC_Device_t *pdev, uint8_t entity, uint8_t cs, uint32_t len, struct uvc_request_data * data)
    {
        switch (entity)
        {
    
        case UVC_VC_PROCESSING_UNIT_ID:
            return usb_vc_pu_cs_out(pdev, entity, cs, len, data);
            break;
    
        }
    
        return ST_UVC_SUCCESS;
    }
    add++++++++++++++++++++++++++++++++++++++++++++++
    
    modify three:
    
    add++++++++++++++++++++++++++++++++++++++++++++++
    int8_t usb_vc_pu_cs_out(ST_UVC_Device_t *pdev, uint8_t entity_id, uint8_t cs, uint32_t len, struct uvc_request_data *data)
    {
    unsigned char pu_brightness_data[2];
        switch (cs)
        {
        case UVC_PU_BRIGHTNESS_CONTROL:
            if(data->data[0] < 0x00 || data->data[0] > 0xFF || data->data[1] != 0x00)
            {
                pdev->request_error_code.data[0] = 0x04;
                pdev->request_error_code.length = 1;
                return -1;
            }
            if(2 == len)
            {
                pu_brightness_data[0] = data->data[0];  //Process the obtained data yourself
                pu_brightness_data[1] = data->data[1];  //Process the obtained data yourself
            }
            break;
    
        default:
            XU_Print(":: not support.\n");
            break;
        }
    
        return ST_UVC_SUCCESS;
    }
    add++++++++++++++++++++++++++++++++++++++++++++++
    

    For UVC_SET_CUR, please refer to UVC protocol 4.2.2.3: https://www.usb.org/document-library/video-class-v15-document-set

5.3 Adding XU Events

  • Description

    XU (Extension Unit) is a mechanism for extending functionality. It allows camera devices to provide custom control functions beyond the basic control functions defined by the UVC standard.

  • XU recognition process

    • USBCAM side

      Add descriptor definition and supported control options for XU in kernel

      Note: The specific control options of XU do not need to define each control option like PU in kernel, but bmControls still needs to enable the corresponding use bit.

    • UVC control side

      If it is determined that the control option can be used, send a control command

    • USBCAM side

      Listen for PU events under APP and actually handle command processing and data processing for added control options

5.3.1 Adding Additional Control Attributes

Example: Add custom control instruction with command code CUS_XU_SET_DOSAMETHING: 0x1

5.3.1.1 KERNEL side
  • Description

    The driver side mainly modifies bmControls under the XU descriptor structure. bmControls is a bitmap (Bitmap) used to represent different control options supported by UVC devices. Each bit corresponds to a specific control option and is used to indicate whether that option is available or supported.

  • Note

    The definition of additional control instructions for XU does not need to be defined in kernel, as long as USBCAM-APP and UVC control side are consistent.

  • Modification example

    kernel\drivers\sgs\usb\gadget\legacy\bind_uvc.c
    
    static struct UVC_EXTENSION_UNIT_DESCRIPTOR(1, 2) uvc_extension_unit2 = {
        .bLength = UVC_DT_EXTENSION_UNIT_SIZE(1, 2),
        .bDescriptorType = USB_DT_CS_INTERFACE,
        .bDescriptorSubType = UVC_VC_EXTENSION_UNIT,
        .bUnitID = UVC_EU2_ID,
        .guidExtensionCode = UVC_EU2_GUID,
        .bNumControls = 0x06,
        .bNrInPins = 0x01,
        .baSourceID[0] = UVC_EU1_ID,
        .bControlSize = 0x02,
    -----
        .bmControls[0] = 0,
    -----
    +++++
        .bmControls[0] = 0x3F,  //Enable Bit0-Bit5 function
    +++++
        .bmControls[1] = 0x00,
        .iExtension = 0x00,
    };
    

    Note: Since XU is a custom attribute, each bit of bmControls is determined by the user.

5.3.1.2 APP side
  • Description

    The demo side mainly completes command processing and data processing for the added XU instructions.

  • Modification example

    Note: The v4l2_event structure is used in the AppDemo to receive XU instructions and their data.

    Specific control description of XU instructions on the APP side, for example:

    sdk/verify/app_demo/intrnal/uvc/st_uvc.c
    
    static int8_t _UVC_Events_Process_Control(ST_UVC_Device_t *pdev,uint8_t req,uint8_t cs,uint8_t entity_id,uint8_t len,struct uvc_request_data *resp)
    {
    switch (entity_id)
        {
        /* Camera terminal */
        case UVC_VC_INPUT_TERMINAL_ID:
        break;
    add++++++++++++++++++++++++++++++++++++++++++++++
            /* Extension unit for customer */
        case UVC_VC_EXTENSION2_UNIT_ID:
            if (0 == usb_vc_eu2_cs(cs, req, resp))  //Control instruction processing function, process it yourself
            {
                resp->length = len;
                pdev->request_error_code.data[0] = 0x00;
                pdev->request_error_code.length = 1;
            }
            else
            {
                resp->length = -EL2HLT;
                pdev->request_error_code.data[0] = 0x06;
                pdev->request_error_code.length = 1;
            }
            break;
    add++++++++++++++++++++++++++++++++++++++++++++++
    }
    
    static int8_t _UVC_Events_Process_Data(ST_UVC_Device_t * pdev, struct uvc_request_data *data)
    {
    if(UVC_CONTROL_INTERFACE == pdev->control.ctype)
    {
    add++++++++++++++++++++++++++++++++++++++++++++++
    return usb_vc_out_data(pdev, pdev->control.entity, pdev->control.control, pdev->control.length, data);
    add++++++++++++++++++++++++++++++++++++++++++++++
    }
    
    }
    
    add++++++++++++++++++++++++++++++++++++++++++++++
    // process PU, CT, XU job.
    int8_t usb_vc_out_data(ST_UVC_Device_t *pdev, uint8_t entity, uint8_t cs, uint32_t len, struct uvc_request_data * data)
    {
        switch (entity)
        {
            case UVC_VC_EXTENSION2_UNIT_ID:
                usb_vc_eu2_cs_out(entity, cs, len, data);
                break;
        }
    
        return ST_UVC_SUCCESS;
    }
    add++++++++++++++++++++++++++++++++++++++++++++++
    
    add++++++++++++++++++++++++++++++++++++++++++++++
    // CUS XU
    #define UVC_XU_EU2_UNDEFINED    (0x0)
    #define CUS_XU_SET_DOSAMETHING      (0x1)   //command number
    #define CUS_XU_GET_DOSAMETHING      (0x2)   //command number
    int8_t usb_vc_eu2_cs_out(uint8_t entity_id, uint8_t cs, uint32_t len, struct uvc_request_data *data)
    {
    unsigned char pu_brightness_data[2];
        switch (cs)
        {
            case CUS_XU_SET_DOSAMETHING:
                //do samething
                break;
            case CUS_XU_GET_DOSAMETHING:
                //do samething
                break;
            default:
                XU_Print(":: not support.\n");
                break;
        }
        return ST_UVC_SUCCESS;
    }
    add++++++++++++++++++++++++++++++++++++++++++++++
    

    Note:

    The unit and selector parameters of the uvc_xu_control_query parameter structure on the host side must correspond to the parameters on the device side.

    The unit parameter represents the Unit ID of the extension unit. Each extension unit in a UVC device has a unique identifier to distinguish different extension units.

    The selector parameter represents the Control Selector. Each extension unit can support multiple controls and is distinguished by different selectors. The control selector defines control commands for specific functions or attributes.

    For UVC_SET_CUR, please refer to UVC protocol 4.2.2.5: https://www.usb.org/document-library/video-class-v15-document-set

Some structure descriptions in /kernel/drivers/sgs/usb/gadget/legacy/bind_uvc.c

  • Definition structure of the entire list of supported video formats

    *uvc_streaming_cls_std[MAX_STREAM_SUPPORT][MAX_FORMAT_COUNT] = {
        (struct uvc_descriptor_header *)&uvc_input_header[0],
        UVC_DESCRIPTOR_HEADERS_OF_H264_FRAME
        UVC_DESCRIPTOR_HEADERS_OF_NV12_FRAME
        UVC_DESCRIPTOR_HEADERS_OF_MJPG_FRAME
        UVC_DESCRIPTOR_HEADERS_OF_YUY2_FRAME
        UVC_DESCRIPTOR_HEADERS_OF_H265_FRAME
        NULL,
    },
    

    As shown above, H264, H265, MJPEG, NV12 and YUY2 video formats are supported.

  • Definition structure of fixed video format descriptor

    The following is an explanation of the H264 encoding format:

    static struct uvc_format_framebase uvc_format_h264 = {
        .bLength = UVC_DT_FORMAT_FRAMEBASE_SIZE,
        .bDescriptorType = USB_DT_CS_INTERFACE,
        .bDescriptorSubType = UVC_VS_FORMAT_FRAME_BASED,
        .bFormatIndex = 1,
        .bNumFrameDescriptors = 7,
        .guidFormat = { 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
                0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 },
        .bBitsPerPixel = 16,
        .bDefaultFrameIndex = 7,
        .bAspectRatioX = 0,
        .bAspectRatioY = 0,
        .bmInterfaceFlags = 0,
        .bCopyProtect = 0,
        .bVariableSize = 1
    };
    

    bFormatIndex: The position of the H264 video encoding format in the entire video format

    *uvc_streaming_cls_std[MAX_STREAM_SUPPORT][MAX_FORMAT_COUNT] = {
    {
    (struct uvc_descriptor_header *)&uvc_input_header[0],
    UVC_DESCRIPTOR_HEADERS_OF_H264_FRAME    bFormatIndex = 1
    UVC_DESCRIPTOR_HEADERS_OF_NV12_FRAME    bFormatIndex = 2
    UVC_DESCRIPTOR_HEADERS_OF_MJPG_FRAME    bFormatIndex = 3
    UVC_DESCRIPTOR_HEADERS_OF_YUY2_FRAME    bFormatIndex = 4
    UVC_DESCRIPTOR_HEADERS_OF_H265_FRAME    bFormatIndex = 5
    NULL,
    },
    

    bNumFrameDescriptors: How many resolution formats are there under the H264 video encoding format

    bDefaultFrameIndex: Default resolution format selection under H264 video encoding format

    //    bNumFrameDescriptors = 7
    #define UVC_DESCRIPTOR_HEADERS_OF_H264_FRAME
    (struct uvc_descriptor_header *)&uvc_format_h264,
    (struct uvc_descriptor_header *)&uvc_frame_h264_240p,// bDefaultFrameIndex = 1
    (struct uvc_descriptor_header *)&uvc_frame_h264_480p,//bDefaultFrameIndex = 2
    (struct uvc_descriptor_header *)&uvc_frame_h264_720p, //bDefaultFrameIndex = 3
    (struct uvc_descriptor_header *)&uvc_frame_h264_1080p,//bDefaultFrameIndex = 4
    (struct uvc_descriptor_header *)&uvc_frame_h264_2kp, //bDefaultFrameIndex = 5
    (struct uvc_descriptor_header *)&uvc_frame_h264_4kp,  //bDefaultFrameIndex = 6
    (struct uvc_descriptor_header *)&uvc_frame_h264_360p, //bDefaultFrameIndex = 7
    (struct uvc_descriptor_header *)&uvc_frame_h264_still_image,
    (struct uvc_descriptor_header *)&uvc_color_matching,
    #else
    
  • Definition structure of fixed video format resolution descriptor

    The following is an explanation of the definition of the H264 encoding format for the 4K resolution:

    static struct UVC_FRAME_FRAMEBASE(3) uvc_frame_h264_4kp = {
        .bLength = UVC_DT_FRAME_MJPEG_SIZE(3),
        .bDescriptorType = USB_DT_CS_INTERFACE,
        .bDescriptorSubType = UVC_VS_FRAME_FRAME_BASED,
        .bFrameIndex = 6,
        .bmCapabilities = 0,
        .wWidth = cpu_to_le16(3840),
        .wHeight = cpu_to_le16(2160),
        .dwMinBitRate = cpu_to_le32(3840 * 2160 * 2 * 8 * 10),
        .dwMaxBitRate = cpu_to_le32(3840 * 2160 * 2 * 8 * 10),
        .dwDefaultFrameInterval = cpu_to_le32(333333),
        .bFrameIntervalType = 3,
        .dwFrameInterval[0] = cpu_to_le32(333333),
        .dwFrameInterval[1] = cpu_to_le32(666666),
        .dwFrameInterval[2] = cpu_to_le32(1000000),
    };
    

    bFrameIndex: The order of the arrangement of the 4K resolution in the H264 video format

    wWidth: The width size of the 4K resolution

    wHeight: The height size of the 4K resolution

    dwDefaultFrameInterval: The default frame rate of the 4K resolution (here it is 30fps)

    bFrameIntervalType: How many frame rates are supported by the 4K resolution

    dwFrameInterval[x]: Set each frame rate corresponding to the above

    #define UVC_DESCRIPTOR_HEADERS_OF_H264_FRAME
    (struct uvc_descriptor_header *)&uvc_format_h264,
    (struct uvc_descriptor_header *)&uvc_frame_h264_240p,    bFrameIndex = 1
    (struct uvc_descriptor_header *)&uvc_frame_h264_480p,    bFrameIndex = 2
    (struct uvc_descriptor_header *)&uvc_frame_h264_720p,    bFrameIndex = 3
    (struct uvc_descriptor_header *)&uvc_frame_h264_1080p,   bFrameIndex = 4
    (struct uvc_descriptor_header *)&uvc_frame_h264_2kp,     bFrameIndex = 5
    (struct uvc_descriptor_header *)&uvc_frame_h264_4kp,     bFrameIndex = 6
    (struct uvc_descriptor_header *)&uvc_frame_h264_still_image,
    (struct uvc_descriptor_header *)&uvc_color_matching,
    #else
    

6.2 Video Format Modification Example

6.2.1 Add NV12 as a video stream format

  • kernel driver side

    kernel/drivers/sgs/usb/gadget/legacy/bind_uvc.c
    
    static struct uvc_descriptor_header
        *uvc_streaming_cls_std[MAX_STREAM_SUPPORT][MAX_FORMAT_COUNT] = {
            {
                (struct uvc_descriptor_header *)&uvc_input_header[0],
                UVC_DESCRIPTOR_HEADERS_OF_YUY2_FRAME
                add+++++++++++++++++++++++++++++
                    UVC_DESCRIPTOR_HEADERS_OF_NV12_FRAME
                add+++++++++++++++++++++++++++++
                        UVC_DESCRIPTOR_HEADERS_OF_MJPG_FRAME
                            UVC_DESCRIPTOR_HEADERS_OF_H264_FRAME
                                UVC_DESCRIPTOR_HEADERS_OF_H265_FRAME
                                    NULL,
            },
            {
                (struct uvc_descriptor_header *)&uvc_input_header[1],
    #ifdef CONFIG_WINDOWS_HELLO_SUPPORT
                UVC_DESCRIPTOR_HEADERS_OF_IR_FRAME
    #else
                UVC_DESCRIPTOR_HEADERS_OF_YUY2_FRAME
                add+++++++++++++++++++++++++++++
                    UVC_DESCRIPTOR_HEADERS_OF_NV12_FRAME
                add+++++++++++++++++++++++++++++
                        UVC_DESCRIPTOR_HEADERS_OF_MJPG_FRAME
                            UVC_DESCRIPTOR_HEADERS_OF_H264_FRAME
                                UVC_DESCRIPTOR_HEADERS_OF_H265_FRAME
    #endif
                    NULL,
            },
            {
                (struct uvc_descriptor_header *)&uvc_input_header[2],
                UVC_DESCRIPTOR_HEADERS_OF_YUY2_FRAME
                add+++++++++++++++++++++++++++++
                    UVC_DESCRIPTOR_HEADERS_OF_NV12_FRAME
                add+++++++++++++++++++++++++++++
                        UVC_DESCRIPTOR_HEADERS_OF_MJPG_FRAME
                            UVC_DESCRIPTOR_HEADERS_OF_H264_FRAME
                                UVC_DESCRIPTOR_HEADERS_OF_H265_FRAME
                                    NULL,
            },
    
    The following modifications are configured in the same way.
    add+++++++++++++++++++++++++++++
    #define UVC_DESCRIPTOR_HEADERS_OF_YUY2_FRAME
    #endif
    #ifdef SUPPORT_NV12
    static struct uvc_format_uncompressed uvc_format_nv12 = {
        .bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
        .bDescriptorType = USB_DT_CS_INTERFACE,
        .bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED,
        .bFormatIndex = 2,
        .bNumFrameDescriptors = 6,
        .guidFormat = { 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
                0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 },
        .bBitsPerPixel = 12,
        .bDefaultFrameIndex = 1,
        .bAspectRatioX = 0,
        .bAspectRatioY = 0,
        .bmInterfaceFlags = 0,
        .bCopyProtect = 0,
    };
    add+++++++++++++++++++++++++++++
    
    add+++++++++++++++++++++++++++++
    #define UVC_DESCRIPTOR_HEADERS_OF_NV12_FRAME                                   \
        (struct uvc_descriptor_header *)&uvc_format_nv12,                      \
            (struct uvc_descriptor_header *)&uvc_frame_nv12_240p,          \
            (struct uvc_descriptor_header *)&uvc_frame_nv12_480p,          \
            (struct uvc_descriptor_header *)&uvc_frame_nv12_720p,          \
            (struct uvc_descriptor_header *)&uvc_frame_nv12_1080p,         \
            (struct uvc_descriptor_header *)&uvc_frame_nv12_2kp,           \
            (struct uvc_descriptor_header *)&uvc_frame_nv12_4kp,           \
            (struct uvc_descriptor_header *)&uvc_frame_nv12_still_image,   \
            (struct uvc_descriptor_header *)&uvc_color_matching,
    #else
    add+++++++++++++++++++++++++++++
    
  • APP side

    sdk/verify/appdemo/internal/uvc/st_uvc_datatype.h
    
    static const struct uvc_format_info uvc_formats[] = {
        { V4L2_PIX_FMT_YUYV,  uvc_frames_yuyv },
        add+++++++++++++++++++++++++++++
        { V4L2_PIX_FMT_NV12,  uvc_frames_nv12 },
        add+++++++++++++++++++++++++++++
        { V4L2_PIX_FMT_MJPEG, uvc_frames_mjpg },
        { V4L2_PIX_FMT_H264,  uvc_frames_h264 },
        { V4L2_PIX_FMT_H265,  uvc_frames_h265 },
    };
    
    static const struct uvc_format_info uvc_still_formats[] = {
        { V4L2_PIX_FMT_YUYV,  uvc_still_frames_yuyv },
        add+++++++++++++++++++++++++++++
        { V4L2_PIX_FMT_NV12,  uvc_still_frames_nv12 },
        add+++++++++++++++++++++++++++++
        { V4L2_PIX_FMT_MJPEG, uvc_still_frames_mjpg },
        { V4L2_PIX_FMT_H264,  uvc_still_frames_h264 },
        { V4L2_PIX_FMT_H265,  uvc_still_frames_h265 },
    };
    
    add+++++++++++++++++++++++++++++
    static const struct uvc_frame_info uvc_frames_nv12[] = {
        {  320, 240, { 333333, 666666, 1000000, 0 }, },
        {  640, 480, { 333333, 666666, 1000000, 0 }, },
        { 1280, 720, { 333333, 666666, 1000000, 0 }, },
        { 1920, 1080,{ 333333, 666666, 1000000, 0 }, },
        { 2560, 1440,{ 333333, 666666, 1000000, 0 }, },
        { 3840, 2160,{ 333333, 666666, 1000000, 0 }, },
        { 0, 0, { 0, }, },
    };
    add+++++++++++++++++++++++++++++
    
  • Script side

    UVC_STREAMING_FORMAT_NV12_ENABLE=1
    
    add+++++++++++++++++++++++++++++
    config_uvc_nv12()
    {
        config_uvc_format_nv12
        config_uvc_frame_nv12 320 240 333333
        config_uvc_frame_nv12 640 480 333333
        config_uvc_frame_nv12 1280 720 333333
        config_uvc_frame_nv12 1920 1080 333333
        config_uvc_frame_nv12 2560 1440 333333
        config_uvc_frame_nv12 3840 2160 666666
        ln -s ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12 ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/header/default/nv12
    }
    add+++++++++++++++++++++++++++++
    
    add+++++++++++++++++++++++++++++
    config_uvc_format_nv12()
    {
        mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12
        echo 0x0C > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/bBitsPerPixel
        echo 0x01 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/bDefaultFrameIndex
        echo 0x04 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/bmaControls
        echo -ne \\x4e\\x56\\x31\\x32\\x00\\x00\\x10\\x00\\x80\\x00\\x00\\xaa\\x00\\x38\\x9b\\x71 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/uncompressed/nv12/guidFormat
    }
    add+++++++++++++++++++++++++++++
    

6.3 Video Resolution Modification Example

6.3.1 Add a set of H264 stream resolutions of 640x360

  • kernel driver side

    kernel/drivers/sgs/usb/gadget/legacy/bind_uvc.c
    
    add+++++++++++++++++++++++++++++
    static struct UVC_FRAME_FRAMEBASE(3) uvc_frame_h264_360p = {
        .bLength = UVC_DT_FRAME_MJPEG_SIZE(3),
        .bDescriptorType = USB_DT_CS_INTERFACE,
        .bDescriptorSubType = UVC_VS_FRAME_FRAME_BASED,
        .bFrameIndex = 7,           //Please note that the index must correspond to the position below.
        .bmCapabilities = 0,
        .wWidth = cpu_to_le16(640),
        .wHeight = cpu_to_le16(360),
        .dwMinBitRate = cpu_to_le32(640 * 360 * 2 * 8 * 10),
        .dwMaxBitRate = cpu_to_le32(640 * 360 * 2 * 8 * 30),
        .dwDefaultFrameInterval = cpu_to_le32(333333),
        .bFrameIntervalType = 3,
        .dwFrameInterval[0] = cpu_to_le32(333333),
        .dwFrameInterval[1] = cpu_to_le32(666666),
        .dwFrameInterval[2] = cpu_to_le32(1000000),
    };
    add+++++++++++++++++++++++++++++
    
    #define UVC_DESCRIPTOR_HEADERS_OF_H264_FRAME
    (struct uvc_descriptor_header *)&uvc_format_h264,
    (struct uvc_descriptor_header *)&uvc_frame_h264_240p,
    (struct uvc_descriptor_header *)&uvc_frame_h264_480p,
    (struct uvc_descriptor_header *)&uvc_frame_h264_720p,
    (struct uvc_descriptor_header *)&uvc_frame_h264_1080p,
    (struct uvc_descriptor_header *)&uvc_frame_h264_2kp,
    (struct uvc_descriptor_header *)&uvc_frame_h264_4kp,
    add+++++++++++++++++++++++++++++
    (struct uvc_descriptor_header *)&uvc_frame_h264_360p,
    add+++++++++++++++++++++++++++++
    (struct uvc_descriptor_header *)&uvc_frame_h264_still_image,
    (struct uvc_descriptor_header *)&uvc_color_matching,
    #else
    
  • APP side

    sdk/verify/appdemo/internal/uvc/st_uvc_datatype.h
    
    static const struct uvc_frame_info uvc_frames_h264[] = {
        {  320, 240, { 333333, 666666, 1000000,  0 }, },
        {  640, 480, { 333333, 666666, 1000000,  0 }, },
        { 1280, 720, { 333333, 666666, 1000000,  0 }, },
        { 1920,1080, { 333333, 666666, 1000000,  0 }, },
        { 2560,1440, { 333333, 666666, 1000000,  0 }, },
        { 3840,2160, { 333333, 666666, 1000000,  0 }, },
        add+++++++++++++++++++++++++++++++++
        { 640, 360, { 333333, 666666, 1000000,  0 }, },
        ++++++++++++++++++++++++++++++++++++
        { 0, 0, { 0, }, },
    };
    
  • Script side

    UVC_STREAMING_FORMAT_H264_ENABLE=1      //Make sure that H264 stream is enabled
    
    config_uvc_h264()
    {
        config_uvc_format_h264
        config_uvc_frame_h264 320 240 333333
        config_uvc_frame_h264 640 480 333333
        config_uvc_frame_h264 1280 720 333333
        config_uvc_frame_h264 1920 1080 333333
        config_uvc_frame_h264 2560 1440 333333
        config_uvc_frame_h264 3840 2160 333333
        add+++++++++++++++++++++++++++++++++
        config_uvc_frame_h264 640 360 333333
        ++++++++++++++++++++++++++++++++++++
        ln -s ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264 ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/header/default/h264
    }
    

6.4. Video Frame Rate Modification Example

6.4.1. Adding 25FPS under H264 stream with 1920X1080 resolution

  • Kernel driver side

    kernel/drivers/sgs/usb/gadget/legacy/bind_uvc.c
    
    static struct UVC_FRAME_FRAMEBASE(3) uvc_frame_h265_1080p = {
        .bLength = UVC_DT_FRAME_MJPEG_SIZE(3),
        .bDescriptorType = USB_DT_CS_INTERFACE,
        .bDescriptorSubType = UVC_VS_FRAME_FRAME_BASED,
        .bFrameIndex = 4,
        .bmCapabilities = 0,
        .wWidth = cpu_to_le16(1920),
        .wHeight = cpu_to_le16(1080),
        .dwMinBitRate = cpu_to_le32(1920 * 1080 * 2 * 8 * 10),
        .dwMaxBitRate = cpu_to_le32(1920 * 1080 * 2 * 8 * 30),
        .dwDefaultFrameInterval = cpu_to_le32(333333),
        .bFrameIntervalType = 3,
        .dwFrameInterval[0] = cpu_to_le32(333333),
        add+++++++++++++++++++++++++++++++++
        .dwFrameInterval[1] = cpu_to_le32(400000),
        add+++++++++++++++++++++++++++++++++
        .dwFrameInterval[2] = cpu_to_le32(1000000),
    };
    
  • App side

    sdk/verify/appdemo/internal/uvc/st_uvc_datatype.h
    
    static const struct uvc_frame_info uvc_frames_h264[] = {
        {  320, 240, { 333333, 666666, 1000000,  0 }, },
        {  640, 480, { 333333, 666666, 1000000,  0 }, },
        { 1280, 720, { 333333, 666666, 1000000,  0 }, },
        -----
        { 1920,1080, { 333333, 666666, 1000000,  0 }, },
        -----
        +++++
        { 1920,1080, { 333333, 400000, 1000000,  0 }, },
        +++++
        { 2560,1440, { 333333, 666666, 1000000,  0 }, },
        { 3840,2160, { 333333, 666666, 1000000,  0 }, },
        { 5472,3078, { 333333, 666666, 1000000,  0 }, },
        { 0, 0, { 0, }, },
    };
    
  • Script side

    config_uvc_frame_h264()
    {
        UVC_FRAME_WIDTH=$1
        UVC_FRAME_HEIGHT=$2
        UVC_FRAME_INTERVAL=$3
        UVC_FRAME_INDEX=$4
    
        mkdir ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p
        if [ $UVC_NEED_CONFIG_FRAME_INDEX == 1 ]; then
            echo $UVC_FRAME_INDEX >  ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/bFrameIndex
        fi
        echo 0x00 > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/bmCapabilities
        echo $UVC_FRAME_INTERVAL > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/dwDefaultFrameInterval
        -----
        echo -e "333333\n666666\n1000000" > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/dwFrameInterval
        -----
        +++++
        echo -e "333333\n400000\n1000000" > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/dwFrameInterval
        +++++
        echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*16*30)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/dwMaxBitRate
        echo $((UVC_FRAME_WIDTH*UVC_FRAME_HEIGHT*16*10)) > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/dwMinBitRate
        echo $UVC_FRAME_HEIGHT > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/wHeight
        echo $UVC_FRAME_WIDTH > ${USB_FUNCTIONS_DIR}/uvc.instance${UVC_STREAM_INDEX}/streaming/framebase/h264/${UVC_FRAME_HEIGHT}p/wWidth
    }