UVC使用指南
REVISION HISTORY¶
Revision No. | Description |
Date |
---|---|---|
1.0 | 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
参数结构体的unit
,selector
参数和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 }