相机方向的驱动程序支持

重要

本主题后面讨论的自动更正方法是相机传感器的非参考方向安装 的建议 解决方案。 这是为了确保应用兼容性,因为大多数已写入使用相机源的应用程序不知道检查,也不知道旋转信息的正确性。 请仔细查看以下自动更正部分中的信息。

随着不同的外形规格计算设备的引入,一些物理约束导致相机传感器以非传统方向安装。 因此,有必要向 OS 和应用程序正确描述传感器的安装方式,以便正确呈现/录制生成的视频。

从 Window 10 版本 1607 开始,所有相机驱动程序都需要显式指定相机方向,无论相机是否按照 最低硬件要求安装。 具体而言,相机驱动程序必须在与捕获设备接口关联的 ACPI _PLD结构中设置新引入的字段 “旋转”:

typedef struct _ACPI_PLD_V2_BUFFER {

    UINT32 Revision:7;
    UINT32 IgnoreColor:1;
    UINT32 Color:24;
    // …
    UINT32 Panel:3;         // Already supported by camera.
    // …
    UINT32 CardCageNumber:8;
    UINT32 Reference:1;
    UINT32 Rotation:4;      // 0 – Rotate by 0° clockwise
                            // 1 – Rotate by 45° clockwise (N/A to camera)
                            // 2 – Rotate by 90° clockwise
                            // 3 – Rotate by 135° clockwise (N/A to camera)
                            // 4 – Rotate by 180° clockwise
                            // 5 – Rotate by 225° clockwise (N/A to camera)
                            // 6 – Rotate by 270° clockwise
    UINT32 Order:5;
    UINT32 Reserved:4;

    //
    // _PLD v2 definition fields.
    //

    USHORT VerticalOffset;
    USHORT HorizontalOffset;
} ACPI_PLD_V2_BUFFER, *PACPI_PLD_V2_BUFFER;

对于相机,ACPI _PLD结构中的 “旋转 ”字段指定 0° (“0”、90°的“2”、180°的“4”和“6”(270°)) 捕获的帧相对于屏幕旋转的度数。

根据“ 旋转 ”字段中的值,应用程序可以根据需要执行其他旋转,以便正确呈现捕获的帧。

旋转值

对于相机和显示器共享相同外壳 (或 机箱/外壳) 的设备,可以将这些外设安装在不同的表面上,每个外围设备在其各自的平面上按固定但任意度旋转。 因此,应用程序需要一种机制来描述两个外围设备之间的空间关系,以便捕获的帧可以以正确的方向转置到呈现图面上。

解决此问题的一种方法是使用 ACPI _PLD结构,该结构已定义了 表面旋转度 的概念。 例如,_PLD结构已具有 面板 字段,该字段指定外围设备所在的图面:

ACPI PLD 面板字段。

ACPI _PLD Panel 字段的定义 (Rev. 5.0a)

接下来的两个关系图直观地说明了每个面板的定义:

台式电脑和大多数设备的面板定义

面板定义 - 桌面。

可折叠设备的面板定义

面板定义 - 可折叠设备。

事实上,WINDOWS 已采用 ACPI“面板”的概念,其中:

ACPI _PLD 结构还具有定义如下的“旋转”字段:

ACPI _PLD 旋转字段的定义 (Rev 5.0a)

ACPI _PLD旋转字段定义。

我们不再按原样使用上述定义,而是进一步对其进行优化以避免歧义:

  • 对于相机,ACPI _PLD 结构中的“旋转”字段指定 (“0”表示 0°,“2”表示 90°,“4”表示 180°,“6”表示 270°,) 捕获的帧相对于屏幕旋转,而显示器处于其本机方向。

横向主副本与纵向主数据库

在 Windows 中,可以通过调用 属性 Windows.Graphics.Display.DisplayInformation.NativeOrientation 来查询本机显示方向,该属性返回 横向纵向

显示本机方向扫描模式。

无论 NativeOrientation 返回哪个值,逻辑显示扫描模式从屏幕左上角开始,从左向右向下移动 (见图 5) 。 对于默认物理方向不明的设备,此属性不仅意味着 ACPI 顶部 面板的位置,而且还提供相机输出缓冲区与呈现图面之间的空间关系。

请注意,与相机不同, NativeOrientation 属性不基于 ACPI,因此没有_PLD结构。 即使显示器静态装载到设备,也是如此。

在纵向主设备上安装时,相机驱动程序必须知道,无论实际相机输出缓冲区方向如何,大多数应用程序都会将设备视为输出横向相机输出缓冲区。 因此,我们建议相机驱动程序在纵向主设备上输出与 NativeOrientation 纵向偏移量为 90 度的相机缓冲区。 然后,这将允许在纵向设备上执行此额外旋转的应用程序将旋转更正为预期方向。 这可以使用 带旋转示例的相机应用程序进行验证。

偏移装载

强烈建议 IHV/OEM 避免在非 0 度偏移量内安装传感器,以保持应用兼容性。 许多现有和旧版应用不知道要查找 ACPI 的 PLD 表,也不会尝试更正非 0 度偏移量。 因此,对于此类应用,生成的视频将错误地呈现。

如果 IHV/OEM 无法按上述 0 度方向安装传感器,建议按优先顺序执行以下缓解步骤:

  1. 自动更正相机驱动程序中的非 0 度方向 (在内核模式下使用 AV 流微型端口驱动程序或在用户模式下使用插件(如设备 MFT 或 MFT0) ),以便生成的输出帧处于 0 度方向。

  2. 通过 FSSensorOrientation 标记声明非 0 度方向,以便相机管道可以更正捕获的图像。

  3. 如上所述,在 ACPI 的 PLD 表中声明非 0 度方向。

压缩/编码媒体类型

对于压缩和/或编码媒体类型 (,如 MJPG、JPEG、H264、HEVC) ,无法使用管道更正。 因此,如果 FSSensorOrientation 设置为非零值,则将筛选出压缩/编码媒体类型。

对于 MJPG 媒体类型 ((例如来自 UVC 相机) 的媒体类型),帧服务器管道为基于 DShow 的应用程序提供自动解码媒体类型 (NV12 或 YUY2) 。 将显示自动解码和更正的媒体类型,但不会显示原始 MJPG 格式。

[!注意!] 如果必须向应用程序公开压缩/编码的媒体类型,则 IHV/ODM 不得利用 FSSensorOrientation 更正。 相反,必须由相机驱动程序 (通过 AV Stream驱动程序在内核模式下或通过 DMFT/MFT0) 在用户模式下完成更正。

通过 AV Stream微型端口/设备 MFT/MFT0 自动更正

如果传感器无法安装 0 度偏移量,则建议的方案是将 AV Stream微型端口驱动程序 (或用户模式插件以 DMFT 或 MFT0 的形式插入,) 更正生成的捕获帧,以便以 0 度偏移量将其公开给管道。

从 AV Stream微型端口和/或设备 MFT/MFT0 插件更正视频帧时,生成的媒体类型声明必须基于更正的帧。 如果传感器的安装偏移量为 90 度,因此生成的视频与传感器的纵横比为 9:16,但更正后的视频为 16:9,则媒体类型必须声明 16:9 纵横比。

这包括生成的步幅信息。 这是必需的,因为负责进行更正的组件由 IHV/OEM 控制,并且相机管道无法查看视频帧,除非经过更正。

强烈建议在用户模式下进行更正,并且必须遵循管道和用户模式插件之间的 API 协定。 具体而言,在使用 DMFT 或 MFT0 时,当使用MFT_MESSAGE_SET_D3D_MANAGER消息调用 IMFDeviceTransform::P rocessMessage 或 IMFTransform::P rocessMessage 时,用户模式插件必须遵守以下准则:

  • 如果未提供 D3D 管理器 (消息的 ulParam 为 0) ,则用户模式插件不得调用任何 GPU 操作来处理旋转更正。 生成的帧必须在系统内存中提供。
  • 如果提供了 D3D 管理器 (消息的 ulParam 是 DXGI 管理器) 的 IUnknown,则必须使用该 DXGI 管理器进行旋转更正,并且生成的帧必须是 GPU 内存。
  • 用户模式插件还必须在运行时处理 D3D 管理器消息。 发出MFT_MESSAGE_SET_D3D_MANAGER消息时,插件生成的下一帧必须与请求的内存 (类型相对应,即 GPU(如果提供了 DXGI 管理器),否则 CPU) 。
  • 当 AV Stream驱动程序 (或用户模式插件) 处理旋转更正时,ACPI 的 PLD 结构的“旋转”字段必须设置为 0。

注意

使用自动更正时,OEM 和 IHV 不得通过“_PLD 旋转 ”字段播发传感器的实际方向。 在这种情况下, “旋转 ”字段必须指示更正后的方向:0 度。

通过 FSSensorOrientation 声明

; Defines the sensor mounting orientation offset angle in
; degrees clockwise.
FSSensorOrientation: REG_DWORD: 90, 180, 270

通过 FSSensorOrientation 注册表标记声明传感器的非 0 度方向,相机管道可以在将捕获的帧呈现给应用程序之前对其进行更正。

管道将基于用例和应用请求/方案利用 GPU 或 CPU 资源来优化旋转逻辑。

ACPI PLD 旋转

ACPI PLD 结构的“旋转”字段必须为 0。 这是为了避免混淆应用程序,这些应用程序可能会使用 PLD 信息来更正帧。

媒体类型信息

驱动程序提供的媒体类型必须是未更正的媒体类型。 使用 FSSensorOrientation 条目通知相机管道非 0 度偏移时,传感器提供的媒体类型信息必须是未更正的媒体类型。 例如,如果传感器装载了 90 度顺时针偏移量,因此,生成的视频为 9:16,而不是 16:9 纵横比,必须将 9:16 纵横比媒体类型呈现给相机管道。

这是确保管道可以正确配置计数器轮换过程所必需的:管道需要应用程序的输入媒体类型和所需的输出媒体类型。

这包括步幅信息。 必须将未更正的媒体类型的步幅信息提供给相机管道。

注册表子项

必须在“设备接口”节点上发布 FSSensorOrientation 注册表项。 建议的方法是在相机驱动程序的 INF 中的 AddInterface 指令声明期间将此声明为 AddReg 指令。

FSSensorOrientation 中显示的数据必须是REG_DWORD且接受的唯一有效值为 90、180 和 270。 任何其他值将被视为 0 度偏移量 (即忽略) 。

每个值表示传感器方向(以度为单位)顺时针。 相机管道将通过计数器将视频旋转相同数量的逆时针来更正生成的视频帧:即,90 度顺时针声明将导致 90 度逆时针旋转,使生成的视频帧回到 0 度偏移量。

MS OS 描述符 1.0

对于基于 USB 的相机,还可以通过 MSOS 描述符发布 FSSensorOrientation。

MS OS 描述符 1.0 有两个组件:

  • 固定长度标头部分
  • 一个或多个可变长度的自定义属性部分,它们遵循标头部分

MS OS 描述符 1.0 标头部分

标头部分描述人脸身份验证配置文件) (单个自定义属性。

Offset 字段 大小(字节) 说明
0 dwLength 4 <>
4 bcdVersion 2 0x0100 版本 1.0
6 wIndex 2 0x0005 扩展属性 OS 描述符
8 wCount 2 0x0001 一个自定义属性

自定义 MS OS 描述符 1.0 属性部分

Offset 字段 大小(字节) 说明
0 dwSize 4 0x00000036 (54) 此属性的总大小 (,以字节为单位) 。
4 dwPropertyDataType 4 0x00000004 REG_DWORD_LITTLE_ENDIAN
8 wPropertyNameLength 2 0x00000024 (36) 属性名称) 大小 (字节数。
10 bPropertyName 50 UVC-FSSensorOrientation Unicode 中的“UVC-FSSensorOrientation”字符串。
60 dwPropertyDataLength 4 0x00000004 属性数据的 4 个字节, (size 为 (DWORD) ) 。
64 bPropertyData 4 偏移角度(以度为单位)顺时针。 有效值为 90、180 和 270。

MS OS 描述符 2.0

MSOS 扩展描述符 2.0 可用于定义注册表值以添加 FSSensorOrientation 支持。 这是使用 Microsoft OS 2.0 注册表属性描述符完成的

对于 UVC-FSSensorOrientation 注册表项,下面显示了一个示例 MSOS 2.0 描述符集:

UCHAR Example2_MSOS20DescriptorSet_UVCFSSensorOrientationForFutureWindows[0x3C] =
{
    //
    // Microsoft OS 2.0 Descriptor Set Header
    //
    0x0A, 0x00,                 // wLength - 10 bytes
    0x00, 0x00,                 // MSOS20_SET_HEADER_DESCRIPTOR
    0x00, 0x00, 0x0?, 0x06,     // dwWindowsVersion – 0x060?0000 for future Windows version
    0x4A, 0x00,                 // wTotalLength – 74 bytes

    //
    // Microsoft OS 2.0 Registry Value Feature Descriptor
    //
    0x40, 0x00,                 // wLength - 64 bytes
    0x04, 0x00,                 // wDescriptorType – 4 for Registry Property
    0x04, 0x00,                 // wPropertyDataType - 4 for REG_DWORD_LITTLE_ENDIAN
    0x32, 0x00,                 // wPropertyNameLength – 50 bytes
    0x55, 0x00, 0x56, 0x00,     // Property Name - "UVC-FSSensorOrientation"
    0x43, 0x00, 0x2D, 0x00,
    0x46, 0x00, 0x53, 0x00,
    0x53, 0x00, 0x65, 0x00,
    0x6E, 0x00, 0x73, 0x00,
    0x6F, 0x00, 0x72, 0x00,
    0x4F, 0x00, 0x72, 0x00,
    0x69, 0x00, 0x65, 0x00,
    0x6E, 0x00, 0x74, 0x00,
    0x61, 0x00, 0x74, 0x00,
    0x69, 0x00, 0x6F, 0x00,
    0x6E, 0x00, 0x00, 0x00,
    0x00, 0x00,
    0x04, 0x00,                 // wPropertyDataLength – 4 bytes
    0x5A, 0x00, 0x00, 0x00      // PropertyData – 0x0000005A (90 degrees offset)
}

通过 ACPI PLD 信息声明

作为最后的选择,可以如上所述利用 PLD 信息向应用程序指示必须在呈现/编码之前更正视频帧。 但是,如前所述,许多现有应用程序不使用 PLD 信息,也不会处理帧旋转,因此在某些情况下,应用可能无法正确呈现生成的视频。

下图说明了每个硬件配置的“_PLD轮换”字段的值:

旋转:顺时针 0 度

0 度旋转图。

在上图中:

  • 左侧的图片演示了要捕获的场景。

  • 中间的图片描绘了一个CMOS传感器如何查看场景,该传感器的物理读出顺序从左下角开始向上移动。

  • 右侧的图片表示相机驱动程序的输出。 在此示例中,当显示器是其本机方向时,可以直接呈现媒体缓冲区的内容,而无需其他旋转。 因此,ACPI _PLD Rotation 字段的值为 0。

旋转:顺时针旋转 90 度

90 度旋转图。

在这种情况下,与原始场景相比,媒体缓冲区的内容顺时针旋转 90 度。 因此,ACPI _PLD Rotation 字段的值为 2。

旋转:顺时针旋转 180 度

180 度旋转图。

在这种情况下,媒体缓冲区的内容与原始场景相比,顺时针旋转 180 度。 因此,ACPI _PLD Rotation 字段的值为 4。

旋转:顺时针 270 度

270 度旋转图。

在这种情况下,与原始场景相比,媒体缓冲区的内容按顺时针旋转 270 度。 因此,ACPI _PLD Rotation 字段的值为 6。