UVC使用指南


REVISION HISTORY

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

    1. 概述

    本文将介绍在设备端配置 UVC 的方法以及设备端相关应用的实现方法。

    2. 关键词介绍

    • EP

      EP代表Endpoint,即端点,usb 传输协议中重要的概念。在USB通信中,数据的传输是通过端点来进行的。一个USB设备可以包含一个或多个端点,每个端点都有唯一的端点地址,用于在设备和主机之间进行数据传输。其中端点的传输方式主要分为控制传输(Control)、批量传输(Bulk )、终端传输(Interrupt )、等时传输(Isochronous )。

    • interval

      在USB传输中,数据传输是以帧为单位进行传输的,interval 也就是帧间隔,是用来描述两个连续的数据传输之间时间间隔的一个参数。

    • maxpacket

      USB 设备是通过 endpoint 进行数据传输的,而 endpoint 进行传输的时候是以包(packet)的形式进行传输的,maxpacket 就定义了对应 endpoint 最大包的大小,单位为字节。

    • burst

      在 USB 通信中,数据传输被分为帧(frame),每个帧都包含一个特定数量的数据包(packet)。Burst 就是在一个帧周期内,USB 主机或设备发送或接收多个数据包的过程。由于 USB 的带宽是有限的,使用 Burst 可以提高数据传输的速度,从而提高设备的性能。

    • mult

      代表一次传输可以发送多少maxpacket的数量,取决于其EP下的硬件FIFO深度。

    • isoc

      isoc传输是一种基于时间的传输方式,它提供了一种实时传输的机制,用于传输音频和视频等实时数据。isoc传输的特点是固定带宽和数据传输速率,但是对数据包的重传和丢失不作任何处理,因此不适合传输对数据传输延迟和数据完整性要求较高的数据。

    • bulk

      bulk传输是一种面向传输的传输方式,它提供了一种高效的机制,用于传输大量数据。bulk传输的特点是不保证数据传输速率,但是对于数据包的重传和丢失进行了处理,因此适合传输对数据传输延迟和数据完整性要求不高的数据。

    • PU

      PU(Processing Unit)是用于描述视频处理单元的描述符,它包含了视频处理单元的各种属性和控制选项。

    • XU

      XU(Extension Unit)是用于描述扩展单元的描述符,它允许设备厂商定义和支持自定义的功能和控制选项,以扩展设备的功能。

    • ConfigFs

      ConfigFs(Configuration Filesystem)是一个在 Linux 内核中实现的虚拟文件系统,用于配置和管理设备和驱动程序的运行时参数。它通过将设备和驱动程序的配置参数表示为文件和目录的形式,使得用户可以通过修改这些文件和目录来配置和控制设备的行为。


    3. 硬件端点说明

    端点作为USB传输的唯一实体,设备和主机之间的通信都是由端点来完成,不同的端点配置会对设备的传输速率产生影响,所以下文会对端点配置如何对传输速率的影响有所介绍。此外在使用UVC设备同时可能会复合其他功能,例如RNDIS、DFU,因为每一个硬件端点的资源有限,如果端点参数配置不合理可能会造成EP端点分配不到的情况。

    3.1. 带宽速度说明

    说明:8000代表USB一秒内可以传输的最大次数,USB2.0协议中定义了帧和微帧的概念,每个帧长为1ms,USB高速模式下,每个帧又分为8个微帧,即每个微帧长度为125us。所以理论上1s内USB可以发送的最大次数是8000。

    3.1.1. bulk mode

    Interval:1-16

    maxpacketsize :USB2.0协议中最大值可设置为512,USB3.0协议中最大值可设置为1024

    burst:1-13 最大值视硬件情况有所改变

    因为bulk的实际带宽会根据视频流的分辨率等因素变化,所以具体传输速率要根据实际Device端的端点配置和Host端的空闲带宽决定。

    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

    • 取值范围

      Interval:1-16

      maxpacketsize :最大设置为1024

      mult:1-3

      burst:1-13 最大值视硬件情况有所改变

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

      USB2.0下对应其使用的EP速率为:23.4MB/s

      USB3.0下对应其使用的EP速率为:117.1MB/s

    3.2. EP端点分配说明

    3.2.1. 常用设备EP占用

    使用方向 EP占用情况
    RNDIS INT-in+BULK-in+BULK-out
    UVC ISOC-in+INT-in OR BULK-in+INT-in
    UAC ISOC-in OR ISOC-out
    CDC(串口) 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端点分配举例

    若目前的USB2.0硬件EP的情况为下表:

    EP.NO Maxpacksize(Byte)
    EP0(固定为CONTROL-mode,不可分配) 512
    EP1 1024
    EP2 128
    EP3 512
    EP4 1024
    EP5 128
    EP6 512

    如果使用UVC(IN)+UAC(IN)+RNDIS(bulk-IN+bulk-OUT+int-IN),会占用五个EP,如果设置的maxpacketsize为512,可以支持maxpacketsize大于等于512的EP只有四个,所以无法满足分配情况。


    4. 环境搭建

    UVC环境搭建在基础环境搭建之上,设备属性可以通过加载驱动和配置脚本(ConfigFS)的方式来完成。使用脚本配置,修改方便,适合调试使用。使用加载驱动配置可以固定加载,编译进kernel。

    注意:两种配置方式的区别在于g_sstar_gadget是否被加载,脚本配置的方式只是不需要加载g_sstar_gadget,其他的UVC依赖模块依然要加载。

    4.1. 基础环境搭建

    4.1.1. 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
    
    Device Drivers
        [*] SStar SoC platform drivers ->
            [*] SStar USB support ->
                <M> Sigmastar USB2 UTMI Transceiver Driver
    
    Device Drivers
        [*]USB support
            <M> Support for Host-side USB
            <M> USB Gadget Support  --->
                USB Gadget precomposed configurations ->
                    <M> USB Sigmastar Gadget
                        [*] Include configuration with UVC (video)
    将生成以下ko文件:
    /**************/
    USB基础驱动
    usb-common.ko
    usbcore.ko
    udc-core.ko
    /**************/
    UVC相关依赖驱动
    mc.ko
    videodev.ko
    videobuf2-common.ko
    videobuf2-v4l2.ko
    videobuf2-memops.ko v
    ideobuf2-vmalloc.ko
    videobuf2-dma-sg.ko
    /**************/
    USB2.0驱动
    udc-msb250x.ko
    libcomposite.ko
    /**************/
    UVC驱动
    usb_f_uvc.ko
    

    4.1.2. USB3.0下配置

    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)
    将生成以下ko文件:
    /**************/
    USB基础驱动
    usb-common.ko
    usbcore.ko
    udc-core.ko
    /**************/
    UVC相关依赖驱动
    mc.ko
    videodev.ko
    videobuf2-common.ko
    videobuf2-v4l2.ko
    videobuf2-memops.ko
    videobuf2-vmalloc.ko
    videobuf2-dma-sg.ko
    /**************/
    USB3.0驱动
    usbpll.ko
    usb3-phy.ko
    dwc3.ko
    sstar-dwc3-of-simple.ko
    libcomposite.ko
    /**************/
    UVC驱动
    usb_f_uvc.ko
    

    4.1.3. 模块参数说明

    usb_f_uvc.ko

    interrupt_ep_enable:

    • 参数说明

      表示是否启用中断端点(Interrupt Endpoint)

    • 配置

      insmod usb_f_uvc.ko interrupt_ep_enable=0
      

      关闭中断EP端点

    4.2. UVC设备属性配置

    4.2.1. 驱动配置说明

    要通过加载驱动配置UVC需要开启kernel下menuconfig的额外选项

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

    生成:g_sstar_gadget.ko

    g_sstar_gadget参数说明

    bcdDevice:

    • 参数说明

      bcdDevice是 USB 设备描述符中的一个字段,用于指示设备的固件版本号。它是一个16位的字段,通常由三个字节组成,格式为 BCD(Binary-Coded Decimal)。

    • 配置

      insmod g_sstar_gadget.ko bcdDevice=0x0201
      

      bcdDevice的值为 0x0201,则表示设备的固件版本为 2.01。

    iSerialNumber:

    • 参数说明

      iSerialNumber是 USB 设备描述符中的一个字段,用于指示设备的序列号。它是一个索引值,指向设备描述字符串描述符表(String Descriptor Table)中的一个条目,该条目包含设备的序列号字符串。

    • 配置

      insmod g_sstar_gadget.ko iSerialNumber=0
      

      iSerialNumber字段的值为零或非零的索引值,如果为零,则表示设备没有提供序列号信息。

    streaming_maxburst:

    • 参数说明

      streaming_maxburst是 UVC中的一个参数,用于指定在传输视频数据时允许的最大连续传输突发包数(burst)。它定义了在一次传输中可以连续发送的最大数据包数量。

    • 配置说明

      insmod g_sstar_gadget.ko streaming_maxburst=13,13   (两路配置)
      

      streaming_maxburst指定uvc传输ep maxburst的大小支持多路配置(使用逗号隔开)

    bulk_streaming_ep:

    • 参数说明

      bulk_streaming_ep是指在 UVC设备中用于传输视频数据的批量传输(Bulk Transfer)端点。

    • 配置说明

      insmod g_sstar_gadget.ko bulk_streaming_ep=0
      

      bulk_streaming_ep = 0:使用isoc mode

      bulk_streaming_ep = 1:使用bulk mode

    idProduct:

    • 参数说明

      idProduct是 USB 设备描述符中的一个字段,用于标识设备的产品ID。每个 USB 设备都有一个唯一的产品ID。

    • 配置

      insmod g_sstar_gadget.ko idProduct=0x3311
      

      产品ID(idProduct)是一个16位的整数值,用于表示设备的具体产品型号或版本。它由设备的制造商分配,并在设备制造过程中进行设置。主机系统可以通过读取设备描述符中的产品ID来识别和区分不同的 USB 设备。

    iManufacturer:

    • 参数说明

      iManufacturer是 USB 设备描述符中的一个字段,用于标识设备的制造商名称。它是一个指向字符串描述符的索引,该字符串描述符包含设备的制造商名称信息。

    • 配置

      insmod g_sstar_gadget.ko iManufacturer=0
      

      制造商名称字符串描述符是一个包含实际制造商名称的字符串,它通常由设备的制造商提供,并在设备制造过程中设置。主机系统可以通过读取设备描述符中的 iManufacturer 字段的值,然后在字符串描述符列表中查找相应的字符串描述符,以获取设备的制造商名称。

    streaming_interval:

    • 参数说明

      UVC(USB Video Class)协议中用于表示视频流传输的间隔时间的参数。在 UVC 中,视频流是以帧的形式传输的,每一帧包含一个完整的图像。streaming_interval表示两个连续视频帧之间的时间间隔,通常以毫秒为单位。它用于确定视频帧传输的速率和稳定性。

    • 配置说明

      insmod g_sstar_gadget.ko streaming_interval=1,1 (两路配置)
      

      streaming_interval 范围为1-16

    streaming_name:

    • 参数说明

      它是用于标识视频流的唯一名称或标识符。

    • 配置说明

      insmod g_sstar_gadget.ko streaming_name=vide0,video1    (两路配置)
      

    uvc_function_enable:

    • 参数说明

      用于配置几路Function,设置几路在menuconfig中配置g_sstar_gadget的时候也可以选择

      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
      //这里可以设置为其他数值,设置为2则一个UVC公用一个control interface
      
    • 配置说明

      insmod g_sstar_gadget.ko uvc_function_enable=2  (配置两路UVC)
      

    rndis_function_enable:

    • 参数说明

      用于配置uvc的复合设备配置,同时使能rndis

      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
      
    • 配置说明

      insmod g_sstar_gadget.ko rndis_function_enable=1
      
    • 注意

      如果配置了上述复合配置发现没有出现rndis设备,是因为此时板端为usb组合设备,只有uvc应用跑起来后rndis设备才会被host端一并识别。

    4.2.2. 脚本配置说明

    4.2.2.1. 脚本示例
    #!/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))'}'`
    
        # 配置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
    
        # 配置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
    
        # 配置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
    
        # 配置configs
        # MaxPower/bmAttributes
        echo 0x02 > ${USB_CONFIGS_DIR}/MaxPower
        echo 0xC0 > ${USB_CONFIGS_DIR}/bmAttributes
    
        # 配置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
    
        # 配置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. 脚本运行
    ./xxxx.sh  -a2
    

    开两路uvc设备节点,运行成功后在/dev下有video0和video1的设备节点。

    ./xxxx.sh  -z
    

    清除当前的所有配置项。

    注意:依靠configfs来配置uvc就不能加载g_sstar_gadget驱动,因为他们做的都是配置的动作。

    4.2.2.3. 脚本参数说明
    参数 说明 举例
    UVC_STREAMING_NAME_ARRAY 配置每一路UVC设备的名字 配置两路uvc的名字:UVC_STREAMING_NAME_ARRAY="UVC Camera 0,UVC Camera 1"
    UVC_STREAMING_MAX_PACKET_ARRAY 配置每一路uvc设备的maxpacket属性值 配置两路uvc的maxpacket为3072和1024:UVC_STREAMING_MAX_PACKET_ARRAY="3072,1024"
    UVC_STREAMING_MAX_BURST_ARRAY 配置每一路uvc设备的burst属性值 配置两路uvc的brust为13和13:UVC_STREAMING_MAX_BURST_ARRAY="13,13"
    UVC_STREAMING_INTERVAL_ARRAY 配置每一路uvc设备的interval属性值 配置两路uvc的interval为1:UVC_STREAMING_INTERVAL_ARRAY="1,1"
    UVC_MODE 配置uvc设备的传输模式 UVC_MODE = 0x0: isoc mode
    UVC_MODE = 0x1: bulk mode
    UVC_STREAMING_FORMAT_YUV_ENABLE 是否使能YUV数据格式 UVC_STREAMING_FORMAT_YUV_ENABLE =0:关闭
    UVC_STREAMING_FORMAT_YUV_ENABLE=1:打开
    UVC_STREAMING_FORMAT_NV12_ENABLE 是否使能NV12数据格式 UVC_STREAMING_FORMAT_NV12_ENABLE =0:关闭
    UVC_STREAMING_FORMAT_NV12_ENABLE=1:打开
    UVC_STREAMING_FORMAT_MJPEG_ENABLE 是否使能Mjpeg数据格式 UVC_STREAMING_FORMAT_MJPEG_ENABLE =0:关闭
    UVC_STREAMING_FORMAT_MJPEG_ENABLE=1:打开
    UVC_STREAMING_FORMAT_H264_ENABLE 是否使能H264数据格式 UVC_STREAMING_FORMAT_H264_ENABLE =0:关闭
    UVC_STREAMING_FORMAT_H264_ENABLE=1:打开
    UVC_STREAMING_FORMAT_H265_ENABLE 是否使能H265数据格式 UVC_STREAMING_FORMAT_H265_ENABLE =0:关闭
    UVC_STREAMING_FORMAT_H265_ENABLE=1:打开
    UVC_VERSION=0x0100 选择uvc版本 UVC_VERSION =0x0150:uvc1.5版本
    UVC_VERSION=0x0100:uvc1.0版本

    5. 编程指南

    5.1. V4L2相关API

    • StreamingBuf相关api

      控制码 描述
      VIDIOC_QBUF 用于将一个缓冲帧(buffer)加入到缓冲队列中,等待驱动程序进行处理或采集。它将一个空闲的缓冲帧传递给驱动程序,以便驱动程序可以将数据填充到该缓冲帧中
      VIDIOC_DQBUF 用于从视频缓冲队列中取出一个已经被填充好的视频帧
      VIDIOC_REQBUFS 用于请求分配V4L2驱动程序的视频缓冲区(buffers)
      VIDIOC_QUERYBUF 用于查询驱动程序中缓冲区的相关信息,比如缓冲区的大小和偏移地址等。其主要作用是为了能够在用户空间中访问和操作缓冲区。
      VIDIOC_STREAMON 用于启动视频流数据的传输。该命令通常在设备初始化后使用,以通知设备开始采集并传输视频数据
      VIDIOC_STREAMOFF 用于停止视频流的传输
    • 事件控制相关API

      控制码 描述
      VIDIOC_G_FMT 用于获取当前采集或输出视频的格式信息,例如分辨率、帧率、像素格式等
      VIDIOC_S_FMT 请求设置视频数据的格式(例如图像的宽、高、像素格式等)
      VIDIOC_DQEVENT 获取有关视频设备事件的信息,如数据溢出、视频流丢失等
      UVCIOC_SEND_RESPONSE 用于发送UVC请求的响应。该命令可用于在UVC控制器和USB设备之间进行通信
      VIDIOC_QUERYCAP 用于查询设备的功能和属性,如设备名称、驱动名称、能够支持的视频格式、支持的输入/输出格式等
      VIDIOC_SUBSCRIBE_EVENT 将V4L2设备的事件订阅到用户空间。V4L2设备可能会产生多种事件,例如摄像头模块的热插拔事件、帧率变化事件等

      API详细介绍或其他API说明请参考:https://www.kernel.org/doc/html/v4.11/media/uapi/v4l/

    5.2. PU事件添加

    • 说明

      Processing Unit(PU)通常是指视频采集设备中的处理单元,用于对图像进行处理和调整,以提供各种视频效果和增强功能。PU可以控制图像的属性,如亮度、对比度、饱和度、色调等,还可以应用图像增强算法,如锐化、降噪、自动曝光等。PU还可以控制设备的传输帧率、图像格式和分辨率等参数。

    • PU识别流程

      • USBCAM端

        kernel下增加PU可以支持的控制选项

      • UVC控制端

        如果确定控制选项可使用,发送控制项命令

      • USBCAM端

        APP下监听PU事件,并实际处理增加的控制选项的命令处理和数据处理

    5.2.1. 增加图像控制属性

    例:增加亮度调节指令

    5.2.1.1. KERNEL端
    • 说明

      驱动端主要是对于PU描述符结构体下bmControls的修改,bmControls是一个位图(Bitmap),用于表示UVC设备支持的不同控制选项。它的每一位对应于一个特定的控制选项,用于指示该选项是否可用或支持。

      以下是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
      

      UVC协议中关于PU选项的更多配置请参考:https://www.usb.org/document-library/video-class-v15-document-set

    • 修改示例:亮度调节对应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端
    • 说明

      demo端主要是对增加的PU指令完成指令处理和数据处理。

    • 修改示例

      注意:AppDemo中使用的是v4l2_event结构体来接受PU指令和数据

      APP端对于PU指令的具体控制说明,例:

      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];  //拿到的数据自行处理
                  pu_brightness_data[1] = data->data[1];  //拿到的数据自行处理
              }
              break;
      
          default:
              XU_Print(":: not support.\n");
              break;
          }
      
          return ST_UVC_SUCCESS;
      }
      add++++++++++++++++++++++++++++++++++++++++++++++
      

      UVC_SET_CUR请参考UVC协议4.2.2.3:https://www.usb.org/document-library/video-class-v15-document-set

    5.3. XU事件添加

    • 说明

      XU(Extension Unit)是一种用于扩展功能的机制。它允许摄像头设备提供自定义的控制功能,超出了 UVC 标准所定义的基本控制功能。

    • XU识别流程

      • USBCAM端

        kernel下增加XU的描述符定义以及可以支持的控制选项

        注意:XU的具体控制选项不需要像PU在kernel下具体定义每一条控制选项,但是bmControls 依然要使能对应的使用位。

      • UVC控制端

        如果确定控制选项可使用,发送控制项命令

      • USBCAM端

        APP下监听PU事件,并实际处理增加的控制选项的命令处理和数据处理

    5.3.1. 增加额外控制属性

    例:增加命令码为CUS_XU_SET_DOSAMETHING:0x1的自定义控制指令

    5.3.1.1. KERNEL端
    • 说明

      驱动端主要是对于XU描述符结构体下bmControls的修改,bmControls 是一个位图(Bitmap),用于表示UVC设备支持的不同控制选项。它的每一位对应于一个特定的控制选项,用于指示该选项是否可用或支持。

    • 注意

      XU的额外控制指令的定义不需要在kernel下定义,只需要USBCAM-APP和UVC控制端相一致即可。

    • 修改示例

      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,  //开启Bit0-Bit5的功能
      +++++
          .bmControls[1] = 0x00,
          .iExtension = 0x00,
      };
      

      注意:XU为自定义属性,所以bmControls每一位都由使用者来确定。

    5.3.1.2. APP端
    • 说明

      demo端主要是对增加的XU指令完成指令处理和数据处理

    • 修改示例

      注意:AppDemo中使用的是v4l2_event结构体来接受XU指令和其数据

      APP端对于XU指令的具体控制说明,例:

      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))  //控制指令处理函数,自行处理
              {
                  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++++++++++++++++++++++++++++++++++++++++++++++
      

      注意:

      在host端需要uvc_xu_control_query 参数结构体的unitselector参数和device端的参数相对应。

      unit 参数表示扩展单元的单元标识符(Unit ID)。每个扩展单元在 UVC 设备中都有一个唯一的标识符,用于区分不同的扩展单元。

      selector 参数表示控制选择器(Control Selector)。每个扩展单元可以支持多个控制,通过不同的选择器来区分。控制选择器定义了特定功能或属性的控制命令。

      UVC_SET_CUR请参考UVC协议4.2.2.5:https://www.usb.org/document-library/video-class-v15-document-set

    6. 视频流相关改示例

    6.1. 驱动中相关结构体说明

    /kernel/drivers/sstar/usb/gadget/legacy/bind_uvc.c 中一些结构体的说明

    • 整个可支持视频格式列表的定义结构体

      *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,
      },
      

      以上说明可以支持H264,H265,MJPEG,NV12,YUY2的视频格式。

    • 固定视频格式描述符的定义结构体

      以下是H264编码格式的说明:

      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:H264视频编码格式在整个视频格式中的位置

      *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:H264视频编码格式下有多少种分辨率格式

      bDefaultFrameIndex:H264视频编码格式下默认分辨率格式选择

      //    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
      
    • 固定视频格式分辨率描述符的定义结构体

      以下是H264编码格式下对于4K分辨率定义的说明:

      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:4K分辨率在H264视频格式中的排列顺序

      wWidth:4K分辨率的宽大小

      wHeight:4K分辨率的高大小

      dwDefaultFrameInterval:4K分辨率的默认帧率(此处为30fps)

      bFrameIntervalType:4K分辨率支持多少种帧率

      dwFrameInterval[x]:对应上面的每一张帧率设置

      #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. 视频格式修改示例

    6.2.1. 增加NV12是视频流格式

    • kernel驱动端

      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,
              },
      下面修改以此类推
      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端

      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+++++++++++++++++++++++++++++
      
    • 脚本端

      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. 视频分辨率修改示例

    6.3.1. 增加一组H264码流的分辨率640x360

    • kernel驱动端

      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,           //注意index要与下面的位置想对应
          .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端

      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, }, },
      };
      
    • 脚本端

      UVC_STREAMING_FORMAT_H264_ENABLE=1      //确保H264码流有Enable
      
      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. 视频帧率修改示例

    6.4.1. H264码流1920X1080分辨率下添加25FPS

    • kernel驱动端

      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端

      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, }, },
      };
      
    • 脚本端

      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
      }