Linux&UVC驱动
+ -

LINUX&UVC输入终端描述符解析

2024-03-19 92 0

UVC输入终端是UVC设备拓扑结构中数据流的起始节点。UVC输入终端使用UVC输入终端描述符来描述.
关于该描述符详细的字段描述详见:https://www.usbzh.com/article/detail-95.html
关于相机终端描述符详见:https://www.usbzh.com/article/detail-47.html

根据前文可知,输入终端按其类型可分为:

wTerminalType 描述
ITT_VENDOR_SPECIFIC 0x200 厂商用自定义
ITT_CAMERA 0x201 相机
ITT_MEDIA_TRANSPORT_INPUT 0x202 序列媒介

一般最常见的UVC相机就是ITT_CAMERA类型,值为0x201。

uvc_parse_standard_control函数中关于输入终端的代码解析如下:

case UVC_VC_INPUT_TERMINAL:
        if (buflen < 8) {
            uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
                "interface %d INPUT_TERMINAL error\n",
                udev->devnum, alts->desc.bInterfaceNumber);
            return -EINVAL;
        }

        /*
         * Reject invalid terminal types that would cause issues:
         *
         * - The high byte must be non-zero, otherwise it would be
         *   confused with a unit.
         *
         * - Bit 15 must be 0, as we use it internally as a terminal
         *   direction flag.
         *
         * Other unknown types are accepted.
         */
        type = get_unaligned_le16(&buffer[4]);
        if ((type & 0x7f00) == 0 || (type & 0x8000) != 0) {
            uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
                "interface %d INPUT_TERMINAL %d has invalid "
                "type 0x%04x, skipping\n", udev->devnum,
                alts->desc.bInterfaceNumber,
                buffer[3], type);
            return 0;
        }

        n = 0;
        p = 0;
        len = 8;

        if (type == UVC_ITT_CAMERA) {
            n = buflen >= 15 ? buffer[14] : 0;
            len = 15;

        } else if (type == UVC_ITT_MEDIA_TRANSPORT_INPUT) {
            n = buflen >= 9 ? buffer[8] : 0;
            p = buflen >= 10 + n ? buffer[9+n] : 0;
            len = 10;
        }

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

        term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3],
                    1, n + p);
        if (term == NULL)
            return -ENOMEM;

        if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) {
            term->camera.bControlSize = n;
            term->camera.bmControls = (u8 *)term + sizeof(*term);
            term->camera.wObjectiveFocalLengthMin =    get_unaligned_le16(&buffer[8]);
            term->camera.wObjectiveFocalLengthMax =    get_unaligned_le16(&buffer[10]);
            term->camera.wOcularFocalLength = get_unaligned_le16(&buffer[12]);
            memcpy(term->camera.bmControls, &buffer[15], n);
        } else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT) {
            term->media.bControlSize = n;
            term->media.bmControls = (u8 *)term + sizeof(*term);
            term->media.bTransportModeSize = p;
            term->media.bmTransportModes = (u8 *)term + sizeof(*term) + n;
            memcpy(term->media.bmControls, &buffer[9], n);
            memcpy(term->media.bmTransportModes, &buffer[10+n], p);
        }

        if (buffer[7] != 0)
            usb_string(udev, buffer[7], term->name,sizeof(term->name));
        else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
            sprintf(term->name, "Camera %u", buffer[3]);
        else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT)
            sprintf(term->name, "Media %u", buffer[3]);
        else
            sprintf(term->name, "Input %u", buffer[3]);

        list_add_tail(&term->list, &dev->entities);
        break;

代码看着其实挺乱的,不过如果对代码整理,我相信大部分都会很看地很清楚的:
先定义3个结构体,分别为输入终端描述符,相机终端描述符和序列媒体描述符。

// Input Terminal Descriptor
typedef struct _USB_IT_DESCRIPTOR
{
   UINT8  bLength;
   UINT8  bDescriptorType;
   UINT8  bDescriptorSubtype;
   UINT8  bTerminalID;
   UINT16 wTerminalType;
   UINT8  bAssocTerminal;
   UINT8  iTerminal;
   UINT8  reserved[0];
} USB_IT_DESCRIPTOR;

typedef struct _CAMERA_TERMINAL_DESCRIPTOR
   UINT8  bLength;
   UINT8  bDescriptorType;
   UINT8  bDescriptorSubtype;
   UINT8  bTerminalID;
   UINT16 wTerminalType;
   UINT8  bAssocTerminal;
   UINT8  iTerminal;
   UINT16 wObjectiveFocalLengthMin;
   UIN16 wObjectiveFocalLengthMax;
   UIN16 wOcularFocalLength;
   UINT8 bControlSize;
   UINT8  bmControls[3];
 }CAMERA_TERMINAL_DESCRIPTOR;

然后根据不同的bTerminalID,使用不同的结构体处理:

 if (UVC_ENTITY_TYPE(term) == UVC_TERM_INPUT) {
 ...
 }
else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA){
...
}
else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT){
...
}

至于申请的通用结构体uvc_entity,内部根据类型的不同,其用不同的结构体而已。这种情况在windows内核中太常见了,Linux中我也是第一次见。

struct uvc_entity {
...
    u8 id;
    u16 type;
...
union {
        struct {
            u16 wObjectiveFocalLengthMin;
            u16 wObjectiveFocalLengthMax;
            u16 wOcularFocalLength;
            u8  bControlSize;
            u8  *bmControls;
        } camera;

        struct {
            u8  bControlSize;
            u8  *bmControls;
            u8  bTransportModeSize;
            u8  *bmTransportModes;
        } media;

        struct {
        } output;

        struct {
            u16 wMaxMultiplier;
            u8  bControlSize;
            u8  *bmControls;
            u8  bmVideoStandards;
        } processing;

        struct {
        } selector;

        struct {
            u8  guidExtensionCode[16];
            u8  bNumControls;
            u8  bControlSize;
            u8  *bmControls;
            u8  *bmControlsType;
        } extension;
    };
}

0 篇笔记 写笔记

UVC 输入终端描述符
输入终端描述符用于向主机报告视频数据输入终端的相关信息。输入终端描述符使用bTerminalID描述输入终端的ID,且这个ID是惟一的。输入终端描述符位于视频控制接口中。输入终端描述符结构体定义如下:// Input Terminal Descriptortypedef struct _USB......
UAC 输入终端描述符
UAC输入终端描述符全称:Input Terminal Descriptor,简称ITD.输入终端描述符用于向主机提供输入终端的相关信息,这个概念和UVC摄像头的输入终端描述符类似。UAC输入终端描述符定义-UAC1.0typedef struct _USB_AC_IT_DESCRIPTOR{......
UAC麦克风输入终端描述符
输入终端描述符在拓扑结构中表示数据的来源端。该UAC麦克风输入终端描述符的数据配置如下:关于输入终端描述符的解释见:http://www.usbzh.com/article/detail-180.html输入终端描述符结构体和数据初始化代码如下:/* 4.3.2.1 Input Termina......
LINUX&UVC输入终端描述符解析
UVC输入终端是UVC设备拓扑结构中数据流的起始节点。UVC输入终端使用UVC输入终端描述符来描述.关于该描述符详细的字段描述详见:https://www.usbzh.com/article/detail-95.html关于相机终端描述符详见:https://www.usbzh.com/articl......
UAC双向终端类型Bidirectional Terminal Types
UAC无论是输入终端还是输出终端,都会有一个wTerminalType字段表示其类型。对于麦克风设备,一般是输入终端->其它->输出终端(0x0101 usb-stream)->USB总线对于扬声器设备,一般是USB总线->输出终端(0x0101 usb-stream)-&g......
关注公众号
  • HID人机交互
  • Linux&USB
  • UAC音频
  • TYPE-C
  • USB规范
  • USB大容量存储
  • USB百科
  • USB周边
  • UVC摄像头
  • Windows系统USB
  • 音视频博客
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

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

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