Skip to content

UVC User Guide


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 02/01/2024

    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:

    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_sstar_gadget is loaded. The script configuration method only does not need to load g_sstar_gadget, and other UVC dependent modules still need to be loaded.

    4.1 Basic Environment Setup

    4.1.1 Configuration under USB2.0

    Device Drivers --->
        <M> Multimedia support --->
            Media device types --->
                [*] Cameras and video grabbers
            Media core support --->
                <M> Video4linux core
                [*] Media Controller API
        [*] USB support --->
            <M> USB Gadget Support --->
                USB Peripheral Controller --->
                    <M> Sstar USB 2.0 Dvice Controller
                USB Gadget precomposed configurations ->
                    <M> USB Sigmastar 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 v
    videobuf2-vmalloc.ko
    videobuf2-dma-sg.ko
    /**************/
    USB2.0 driver
    udc-msb250x.ko
    libcomposite.ko
    /**************/
    UVC driver
    usb_f_uvc.ko
    /**************/
    UVC config driver
    g_sstar_gadget.ko
    

    4.1.2 Configuration under USB3.0(IFORD not supported)

    Device Drivers  --->
            SStar SOC platform drivers
                    [*] SStar USB support
                            <M>Sigmastar USB3 PHY drivers
                            <M>Simple Glue Layer of SStar 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 --->
                    <空> Sstar USB 2.0 Dvice Controller
                USB Gadget precomposed configurations ->
                    <M> USB Sigmastar 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
    sstar-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.

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

    g_sstar_gadget.ko is generated.

    g_sstar_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_sstar_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_sstar_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_sstar_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_sstar_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_sstar_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_sstar_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_sstar_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_sstar_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_sstar_gadget in menuconfig.

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

      insmod g_sstar_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_sstar_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\sstar\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/common/ss_uvc/ss_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\sstar\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/common/ss_uvc/ss_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/sstar/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/sstar/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/common/ss_uvc/ss_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/sstar/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/common/ss_uvc/ss_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/sstar/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/common/ss_uvc/ss_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
      }