Linux&UVC驱动
+ -

LINUX&UVC控制接口头描述符解析

2024-03-19 25 0

UVC控制接口头描述符(Video Control Interface Header Descriptor )这里又称作UVC类特定视频控制接口头描述符(class-specific video control header)。无论叫什么名字,不过简称好像都叫USB_VC_HEADER。

关于该描述符各字段的具体介绍可详见:https://www.usbzh.com/article/detail-4.html
对照着LINUX&UVC驱动源代码,我们这里可以进行更加深刻地理解。

switch (buffer[2]) {
    case UVC_VC_HEADER:
        n = buflen >= 12 ? buffer[11] : 0;

        if (buflen < 12 + n) {
            uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
                "interface %d HEADER error\n", udev->devnum,
                alts->desc.bInterfaceNumber);
            return -EINVAL;
        }

        dev->uvc_version = get_unaligned_le16(&buffer[3]);
        dev->clock_frequency = get_unaligned_le32(&buffer[7]);

        /* Parse all USB Video Streaming interfaces. */
        for (i = 0; i < n; ++i) {
            intf = usb_ifnum_to_if(udev, buffer[12+i]);
            if (intf == NULL) {
                uvc_trace(UVC_TRACE_DESCR, "device %d "
                    "interface %d doesn't exists\n",
                    udev->devnum, i);
                continue;
            }

            uvc_parse_streaming(dev, intf);
        }
        break;

从代码分析来看,这里比较关键的三个字段分别为:

uvc_version

以BCD代码的形式表示了该设备所支持的UVC规范版本。

版本 BCD
V1.0 0x0100
V1.1 0x0110
V1.5 0x0150

因UVC版本的差异,导致对一些描述符的解析或者控制请求的数据长度有所不同。具体表现在以下几个方面:

1.对于UVC处理单元,其UVC1.0与UVC1.1、UVC1.5长度不一致。
2.UVC视频控制请求的字节数。

static size_t uvc_video_ctrl_size(struct uvc_streaming *stream)
{
    /*
     * Return the size of the video probe and commit controls, which depends
     * on the protocol version.
     */
    if (stream->dev->uvc_version < 0x0110)
        return 26;
    else if (stream->dev->uvc_version < 0x0150)
        return 34;
    else
        return 48;
}
  • clock_frequency:时钟频率HZ。
    当进行UVC控制请求时,UVC1.0直接使用的是clock_frequency时钟频率,而UVC1.1和UVC1.5可以支持其它时钟频率。

    ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]);
      ctrl->bFormatIndex = data[2];
      ctrl->bFrameIndex = data[3];
      ctrl->dwFrameInterval = le32_to_cpup((__le32 *)&data[4]);
      ctrl->wKeyFrameRate = le16_to_cpup((__le16 *)&data[8]);
      ctrl->wPFrameRate = le16_to_cpup((__le16 *)&data[10]);
      ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]);
      ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]);
      ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]);
      ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]);
      ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]);
    
      if (size >= 34) {
          ctrl->dwClockFrequency = get_unaligned_le32(&data[26]);
          ctrl->bmFramingInfo = data[30];
          ctrl->bPreferedVersion = data[31];
          ctrl->bMinVersion = data[32];
          ctrl->bMaxVersion = data[33];
      } else {
          ctrl->dwClockFrequency = stream->dev->clock_frequency;
          ctrl->bmFramingInfo = 0;
          ctrl->bPreferedVersion = 0;
          ctrl->bMinVersion = 0;
          ctrl->bMaxVersion = 0;
      }
    

    这里可以在https://www.usbzh.com/tool/uvc.html 使用默认的示例dwClockFrequency也可以看到:


============UVC1.0============
0x01, 0x00, UINT16 bmHint;dwFrameInterval保持不变;
0x05, UINT8 bFormatIndex=5,
0x04, UINT8 bFrameIndex=4,
0x15, 0x16, 0x05, 0x00, UINT32 dwFrameInterval=333333,;33.3333,ms/帧
0x00, 0x00, UINT16 wKeyFrameRate=0,;缩格式中只有第1帧为关键帧;
0x00, 0x00, UINT16 wPFrameRate=0,;压缩格式P帧速率;
0x00, 0x00, UINT16 wCompQuality=0,,压缩质量1-10000;
0x00, 0x00, UINT16 wCompWindowSize;0,,平均比特率控制的窗口大小;
0x00, 0x00, UINT16 wDelay;0,,内部视频流接口延迟(毫秒);
0x00, 0x90, 0x7E, 0x00, UINT32 dwMaxVideoFrameSize;8294400,Bytes
0x0C, 0xC8, 0x00, 0x00, UINT32 dwMaxPayloadTransferSize;51212,Bytes

============UVC1.1============
0x00, 0x00, 0x00, 0x00, UINT32 dwClockFrequency=0,;指定格式的设备时钟频率HZ
0x03, UINT8 bmFramingInfo=3,负载信息位图
0x01, UINT8 bPreferedVersion=1,bFormatIndex预设版本
0x00, UINT8 bMinVersion=0,bFormatIndex最小版本
0x01, UINT8 bMaxVersion=1,bFormatIndex最大版本

// 34 bytes

bInCollection

第三个比较重要的参数就是bInCollection。其位直为buffer[11],其代表着视频流接口个数。
一般一个UVC视频设备只有一个视频流接口,本人也未曾见到过多个视频流的设备,但并不代表这种设备不存在。从LINUX源代码和UVC规范上来讲,人家是支持的。

    n = buflen >= 12 ? buffer[11] : 0;
    ...
    /* Parse all USB Video Streaming interfaces. */
    for (i = 0; i < n; ++i) {
        intf = usb_ifnum_to_if(udev, buffer[12+i]);
        if (intf == NULL) {
            uvc_trace(UVC_TRACE_DESCR, "device %d "
                "interface %d doesn't exists\n",
                udev->devnum, i);
            continue;
        }

        uvc_parse_streaming(dev, intf);
    }

bInCollection的为baInterfaceNr数组,其个数由bInCollection决定。UVC源代码使用usb_ifnum_to_if函数分别获取对应的接口描述符的指针,并使用uvc_parse_streaming解析该视频流接口描述符

struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
                      unsigned ifnum)
{
    struct usb_host_config *config = dev->actconfig;
    int i;

    if (!config)
        return NULL;
    for (i = 0; i < config->desc.bNumInterfaces; i++)
        if (config->interface[i]->altsetting[0]
                .desc.bInterfaceNumber == ifnum)
            return config->interface[i];

    return NULL;
}

0 篇笔记 写笔记

UVC特定类请求get cur返回长度是26或者是34的是什么?
从返回的长度来看,你应该是在应用打开摄像头,进行视频格式及图形分辨率协商返回的数据长度.UVC视频流接口这两个特别重要的选择子,分别用于协商过程和提交数据格式,让固件开始发送数据。ControlSelector ValueVS_PROBE_CONTROL0x01VS_COMMIT_CONTROL0x......
Windows对UVC规范的版本支持情况?
Windows从WindowsXP开始支持UVC1.0规范的驱动,这个驱动的名字叫USB视频类驱动程序。驱动程序文件为Usbvideo.sys。USB视频类(UVC)驱动程序是Microsoft提供的AVStream微型驱动程序,为USB视频类设备提供驱动程序支持。UVC 版本Windows Vis......
UVC 类特定视频控制接口头描述符
类特定视频控制接口头描述符总长度由控制接口类单元和端点和决定。类特定视频控制接口头描述符位于UVC 标准视频控制接口描述符之后,是控制单元和端点的描述符头。结构体定义如下:// class-specific video control headertypedef struct _USB_VC_......
LINUX&UVC控制接口头描述符解析
UVC控制接口头描述符(Video Control Interface Header Descriptor )这里又称作UVC类特定视频控制接口头描述符(class-specific video control header)。无论叫什么名字,不过简称好像都叫USB_VC_HEADER。关于该描述......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!