从 Windows Threshold 开始,我们将暴露一个新的 WinRT 灯 API,它允许对 相机闪光灯进行编程 ,而无需创建 Windows.Media.Capture.MediaCapture 实例。 通过这样做,开发人员可以通过使用最少的资源(包括电源)来编写 手电筒 应用程序(仅用于照明目的),从而优化计算设备的电池寿命和性能。
为此,IHV/OEM 应实现支持以下功能的 WDM 驱动程序:
允许系统枚举所有闪存设备。
可根据不同设备打开/关闭手电筒。
如果适用,请根据设备调整光强度(类似于 PowerPercent)。
如果适用,请根据设备指定浅色。
就功能而言,上述列表与 MediaCapture(例如 FlashControl 和 TorchControl)的重叠显著。 此外,相同的闪光灯硬件用于 灯 和 拍摄时的闪光。 因此,推荐 IHV/OEM 使用单个 WDM 驱动程序来支持这两种类型的操作,以独占方式控制闪存。 下图说明了概念:
在上面的示例中,只有一个闪存硬件实例(如图所示),它由单个 KMDF 闪存驱动程序管理。 闪存驱动程序公开两个设备接口,每个接口都针对特定类型的客户端(或 WinRT API)。 例如,假设上图所示:
WinRT 媒体捕获 API 和 AVStream 微型驱动程序始终通过GUID_DEVINTERFACE_CAMERA_FLASH接口与闪存驱动程序通信,而
WinRT 灯 API 始终通过GUID_DEVINTERFACE_LAMP接口与闪光灯驱动程序通信。
由于GUID_DEVINTERFACE_CAMERA_FLASH接口由供应商特定的 AVStream 微型驱动程序使用,因此 IHV/OEM 可以随意定义其功能 -Windows 不会施加任何限制。
但是,Microsoft 将标准化接口 GUID_DEVINTERFACE_LAMP,因为它会由 WinRT Lamp API 使用。 有关GUID_DEVINTERFACE_LAMP的详细信息,请参阅 设备接口类 GUID
并发用例
在相机和手电筒应用程序之间共享闪存
相机闪存通常被视为捕获设备的 从属 外围设备。 捕获正在运行时,它不应与非相机方案共享。 为了进一步复杂化,底盘上的闪存设备数量极其有限,因此,在实践中,不会有专用于手电筒目的的备用闪存。
从软件的角度来看,上述情况带来了挑战,即相机应用程序和手电筒应用程序可以同时共存和访问闪存。 例如,从理论上讲,用户可以在相机取景器运行时通过手电筒应用程序切换 LED 状态。
由于相机需要精确控制闪光来支持焦点和捕获,因此驱动程序在确保图像质量的同时解决冲突利益的闪光请求可能很困难。 若要解决此问题,以下策略在系统级别作为协定强制执行:
如果先启动捕捉会话,则手电筒应用程序必须等待捕捉会话结束后,才能控制闪光灯。
手电筒应用程序仍然可以获取闪光灯驱动程序的句柄,但是任何修改闪光灯状态的操作都会立即出现错误。
当捕获停止以便 AVStream 微型驱动程序释放闪存时,需要闪存驱动程序发布 PnP 通知(请参阅 异步通知中的GUID_LAMP_RESOURCES_AVAILABLE),指示基础硬件现已可用。 收到此类通知后,手电筒应用程序被允许相应地控制闪光灯。
如果手电筒应用程序首先启动,则捕获会话可以自由地在不明确同意的情况下劫持闪存硬件。
通过“劫持”,我们的意思是 IHV/OEM 可以实现任意协议(可能通过GUID_DEVINTERFACE_CAMERA_FLASH接口),以便允许 AVStream 微型驱动程序获取闪存,就好像硬件根本不使用一样。
发生劫持时,闪光灯驱动程序需要发布另一个 PnP 通知(请参阅 异步通知中的 GUID_LAMP_RESOURCES_LOST),指示闪光灯已被非自愿重新分配,以便手电筒应用程序可以相应地做出反应(例如更新 UI)。
在多个手电筒应用程序之间共享闪存
如果未涉及相机,并且两个手电筒应用程序连续运行,驱动程序应继续为已获取GUID_DEVINTERFACE_LAMP接口的第一个客户端提供服务,并拒绝所有其他客户端,直到第一个客户端最终释放接口。
换句话说,GUID_DEVINTERFACE_LAMP接口一次只允许一个手电筒客户端,第一个获取接口的客户端会阻止其他人运行(不包括相机/AVStream)。
设备接口类 GUID
支持独立于 MediaCapture 手电筒功能的 IHV/OEM 闪光灯驱动程序必须通过 设备接口类 GUID 注册自身,GUID_DEVINTERFACE_LAMP。
| 特征 | 设置 |
|---|---|
| 标识符 | GUID_DEVINTERFACE_LAMP |
| 类 GUID | {6C11E9E3-8232-4F0A-AD19-AAEC26CA5E98} |
GUID_DEVINTERFACE_CAMERA_FLASH 的设备接口类 GUID 可由 IHV(独立硬件供应商)/OEM(原始设备制造商)自定义。 但是,GUID_DEVINTERFACE_LAMP的设备接口类 GUID 由 Windows 定义。
根据协定,需要公开设备接口的驱动程序GUID_DEVINTERFACE_LAMP才能支持以下功能(有关详细信息,请参阅后面的部分):
IOCTL_LAMP_GET_CAPABILITIES_{WHITE|COLOR} - 列出基础硬件支持的所有模式(例如,纯白模式与彩色模式)
IOCTL_LAMP_{GET|SET}_MODE – 获取或设置当前模式
IOCTL_LAMP_{GET|SET}_INTENSITY_{WHITE|COLOR} - 获取或设置光强度
IOCTL_LAMP_{GET|SET}_EMITTING_LIGHT – 获取或设置闪烁状态(例如 ON/OFF)
如果设备有多个不同类型的闪存硬件(例如 ,白色 LED 和 Xenon 闪存),并且这些硬件由不同的闪存驱动程序控制,则每个驱动程序应公开具有唯一实例 ID 的相同GUID_DEVINTERFACE_LAMP接口。
设备接口属性
由于计算设备在不同面板上可以有零个或多个闪存设备,因此 WinRT Lamp API 需要一种机制来枚举所有闪存硬件,以便应用程序可以编程特定实例。
若要支持设备枚举(类似于相机驱动程序),需要闪光灯驱动程序将 ACPI _PLD v2 结构与每个 GUID_DEVINTERFACE_LAMP 接口关联起来,作为接口属性数据。
IOCTL_LAMP_GET_CAPABILITIES_WHITE
当设备配置为发出白光时,IOCTL_LAMP_GET_CAPABILITIES_WHITE I/O 请求会查询闪光的功能。
定义
#define IOCTL_LAMP_BASE FILE_DEVICE_UNKNOWN
#define IOCTL_LAMP_GET_CAPABILITIES_WHITE \
CTL_CODE(IOCTL_LAMP_BASE, 0x0000, METHOD_BUFFERED, FILE_ANY_ACCESS)
输入参数
Irp-AssociatedIrp.SystemBuffer> 指向一个LAMP_CAPABILITIES_WHITE类型的缓冲区。 有关详细信息,请参阅 备注。
IO_STACK_LOCATION。Parameters.DeviceIoControl.OutputBufferLength 是在 Irp-AssociatedIrp.SystemBuffer> 字段中传递的缓冲区(以字节为单位)的长度。
输出参数
Irp->AssociatedIrp.SystemBuffer 包含了闪存硬件支持的所有功能。
I/O 状态块
驱动程序将 Irp-IoStatus.Status> 设置为STATUS_SUCCESS或相应的错误状态。 它将 Irp-IoStatus.Information> 设置为保存缓冲区所需的字节数。
注解
根据要求,驱动程序支持GUID_DEVINTERFACE_LAMP接口的闪存需要支持发出白光。 此 IOCTL 的有效负载定义如下:
// The output parameter type of IOCTL_LAMP_GET_CAPABILITIES_WHITE.
typedef struct LAMP_CAPABILITIES_WHITE
{
BOOLEAN IsLightIntensityAdjustable;
} LAMP_CAPABILITIES_WHITE;
IsLightIntensityAdjustable 字段指示是否可以编程亮度级别。 如果对此字段的判断为 false,则表示底层设备仅支持开关功能,并且无法调整光强度。
IOCTL_LAMP_GET_CAPABILITIES_COLOR
当设备配置为发出彩色光时,IOCTL_LAMP_GET_CAPABILITIES_COLOR 的 I/O 请求会查询闪光灯的能力。
定义
#define IOCTL_LAMP_GET_CAPABILITIES_COLOR \
CTL_CODE(IOCTL_LAMP_BASE, 0x0001, METHOD_BUFFERED, FILE_ANY_ACCESS)
输入参数
Irp->AssociatedIrp.SystemBuffer 指向一个 LAMP_CAPABILITIES_COLOR 类型的缓冲区。 有关详细信息,请参阅 备注。
IO_STACK_LOCATION。Parameters.DeviceIoControl.OutputBufferLength 是在 Irp-AssociatedIrp.SystemBuffer> 字段中传递的缓冲区(以字节为单位)的长度。
输出参数
Irp-AssociatedIrp.SystemBuffer> 充满了闪存硬件支持的所有功能。
I/O 状态块
驱动程序将 Irp-IoStatus.Status> 设置为STATUS_SUCCESS或相应的错误状态。 它将 Irp-IoStatus.Information> 设置为保存缓冲区所需的字节数。
注解
此 IOCTL 的有效负载定义如下:
// The output parameter type of IOCTL_LAMP_GET_CAPABILITIES_COLOR.
typedef struct LAMP_CAPABILITIES_COLOR
{
BOOLEAN IsSupported;
BOOLEAN IsLightIntensityAdjustable;
} LAMP_CAPABILITIES_COLOR;
第一个字段 IsSupported 指示闪光灯是否能够发出彩色光。 如果硬件不支持浅色,驱动程序应将此字段设置为 false。
第二个字段 IsLightIntensityAdjustable 指示是否可以对亮度级别进行编程。 如果闪光灯不支持色光(例如 IsSupported 被评估为 false),客户端应放弃 IsLightIntensityAdjustable 的值。
IOCTL_LAMP_GET_MODE
IOCTL_LAMP_GET_MODE I/O 请求查询当前闪光灯的配置模式。
定义
#define IOCTL_LAMP_GET_MODE \
CTL_CODE(IOCTL_LAMP_BASE, 0x0002, METHOD_BUFFERED, FILE_ANY_ACCESS)
输入参数
Irp-AssociatedIrp.SystemBuffer> 指向LAMP_MODE类型的缓冲区,如下所示:
typedef enum LAMP_MODE
{
LAMP_MODE_WHITE = 0,
LAMP_MODE_COLOR
} LAMP_MODE;
IO_STACK_LOCATION。Parameters.DeviceIoControl.OutputBufferLength 是在 Irp-AssociatedIrp.SystemBuffer> 字段中传递的缓冲区(以字节为单位)的长度。
输出参数
Irp->AssociatedIrp.SystemBuffer 被填充了 LAMP_MODE 值。
I/O 状态块
驱动程序将 Irp-IoStatus.Status> 设置为STATUS_SUCCESS或相应的错误状态。 它将 Irp-IoStatus.Information> 设置为保存 DWORD 值所需的字节数。
如果 MediaCapture 会话在发出此请求时正在流式传输数据,驱动程序应通过 Irp->IoStatus.Status 返回错误(STATUS_RESOURCE_IN_USE)。
IOCTL_LAMP_SET_MODE
IOCTL_LAMP_SET_MODE I/O 请求设置闪光灯的工作模式。
定义
#define IOCTL_LAMP_SET_MODE \
CTL_CODE(IOCTL_LAMP_BASE, 0x0003, METHOD_BUFFERED, FILE_ANY_ACCESS)
输入参数
Irp-AssociatedIrp.SystemBuffer> 指向LAMP_MODE类型的缓冲区。
输出参数
没有。
I/O 状态块
驱动程序将 Irp-IoStatus.Status> 设置为STATUS_SUCCESS或相应的错误状态。
如果 MediaCapture 会话在发出此请求时正在流式传输数据,驱动程序应通过 Irp->IoStatus.Status 返回错误(STATUS_RESOURCE_IN_USE)。
IOCTL_LAMP_GET_INTENSITY_WHITE(用于获取白光亮度的控制代码)
IOCTL_LAMP_GET_INTENSITY_WHITE I/O 请求是用于在将闪光灯配置为发出白光时查询光强度的请求。
定义
#define IOCTL_LAMP_GET_INTENSITY_WHITE \
CTL_CODE(IOCTL_LAMP_BASE, 0x0004, METHOD_BUFFERED, FILE_ANY_ACCESS)
输入参数
Irp-AssociatedIrp.SystemBuffer 指向>LAMP_INTENSITY_WHITE结构。 有关详细信息,请参阅 备注。
IO_STACK_LOCATION。Parameters.DeviceIoControl.OutputBufferLength 是在 Irp-AssociatedIrp.SystemBuffer> 字段中传递的缓冲区(以字节为单位)的长度。
输出参数
Irp->AssociatedIrp.SystemBuffer被填充了光强度信息。
I/O 状态块
驱动程序将 Irp-IoStatus.Status> 设置为STATUS_SUCCESS或相应的错误状态。
如果 MediaCapture 会话在发出此请求时正在流式传输数据,驱动程序应通过 Irp->IoStatus.Status 返回错误(STATUS_RESOURCE_IN_USE)。
注解
此 IOCTL 的有效负载类型定义如下:
// The I/O parameter type of IOCTL_LAMP_{GET|SET}_INTENSITY_WHITE.
typedef struct LAMP_INTENSITY_WHITE
{
BYTE Value;
} LAMP_INTENSITY_WHITE;
“值”字段表示白色光强度,以百分比计算,在 0 到 100 之间(包括0和100)。
IOCTL_LAMP_SET_INTENSITY_WHITE
IOCTL_LAMP_SET_INTENSITY_WHITE I/O 请求将闪光设置为指定的光强度。
定义
#define IOCTL_LAMP_SET_INTENSITY_WHITE \
CTL_CODE(IOCTL_LAMP_BASE, 0x0005, METHOD_BUFFERED, FILE_ANY_ACCESS)
输入参数
Irp->AssociatedIrp.SystemBuffer 指向一个 LAMP_INTENSITY_WHITE 结构(详见 IOCTL_LAMP_GET_INTENSITY_WHITE)。
输出参数
没有。
I/O 状态块
驱动程序将 Irp-IoStatus.Status> 设置为STATUS_SUCCESS或相应的错误状态。
如果在发出此请求时,MediaCapture 会话正在流式传输数据,驱动程序应通过 Irp->IoStatus.Status 返回错误(STATUS_RESOURCE_IN_USE)。
IOCTL_LAMP_GET_INTENSITY_COLOR
IOCTL_LAMP_GET_INTENSITY_COLOR I/O 请求在将闪光灯配置为发出彩色光时查询光强度。
定义
#define IOCTL_LAMP_GET_INTENSITY_COLOR \
CTL_CODE(IOCTL_LAMP_BASE, 0x0006, METHOD_BUFFERED, FILE_ANY_ACCESS)
输入参数
Irp->AssociatedIrp.SystemBuffer 指向一个 LAMP_INTENSITY_COLOR 结构。 有关详细信息,请参阅 备注。
IO_STACK_LOCATION.Parameters.DeviceIoControl.OutputBufferLength 是在 Irp->AssociatedIrp.SystemBuffer 字段中传递的缓冲区(以字节为单位)的长度。
输出参数
Irp->AssociatedIrp.SystemBuffer被填充了光强度信息。
I/O 状态块
驱动程序将 Irp-IoStatus.Status> 设置为STATUS_SUCCESS或相应的错误状态。
如果 MediaCapture 会话在发出此请求时正在流传输数据,驱动程序应通过 Irp->IoStatus.Status 返回错误(STATUS_RESOURCE_IN_USE)。
注解
此 IOCTL 的有效负载类型定义如下:
// The I/O parameter type of IOCTL_LAMP_{GET|SET}_INTENSITY_COLOR.
typedef struct LAMP_INTENSITY_COLOR
{
BYTE Red; // Red light intensity in percentage (0-100)
BYTE Green; // Green light intensity in percentage (0-100)
BYTE Blue; // Blue light intensity in percentage (0-100)
} LAMP_INTENSITY_COLOR;
IOCTL_LAMP_SET_INTENSITY_COLOR
IOCTL_LAMP_SET_INTENSITY_COLOR I/O 请求将闪光设置为指定的光强度。
定义
#define IOCTL_LAMP_SET_INTENSITY_COLOR \
CTL_CODE(IOCTL_LAMP_BASE, 0x0007, METHOD_BUFFERED, FILE_ANY_ACCESS)
输入参数
Irp->AssociatedIrp.SystemBuffer 指向一个 LAMP_INTENSITY_COLOR 的结构体(有关详细信息,请参阅 IOCTL_LAMP_GET_INTENSITY_COLOR)。
输出参数
没有。
I/O 状态块
驱动程序将 Irp-IoStatus.Status> 设置为STATUS_SUCCESS或相应的错误状态。
如果 MediaCapture 会话在发出此请求时正在流式传输数据,驱动程序应通过 Irp->IoStatus.Status 返回错误(STATUS_RESOURCE_IN_USE)。
IOCTL_LAMP_GET_EMITTING_LIGHT (获取灯光发射状态)
IOCTL_LAMP_GET_EMITTING_LIGHT I/O 请求用于查询(闪光)灯是否已打开。
定义
#define IOCTL_LAMP_GET_EMITTING_LIGHT
CTL_CODE(IOCTL_LAMP_BASE, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS)
输入参数
Irp-AssociatedIrp.SystemBuffer> 指向布尔类型的缓冲区。
IO_STACK_LOCATION。Parameters.DeviceIoControl.OutputBufferLength 是在 Irp-AssociatedIrp.SystemBuffer> 字段中传递的缓冲区(以字节为单位)的长度。
输出参数
Irp->AssociatedIrp.SystemBuffer 被填充为表示闪存状态,其中 TRUE 表示闪存已开启(例如,正在发光);否则为 FALSE。
I/O 状态块
驱动程序将 Irp-IoStatus.Status> 设置为STATUS_SUCCESS或相应的错误状态。 它将 Irp-IoStatus.Information> 设置为保存 DWORD 值所需的字节数。
如果 MediaCapture 会话是在发出此请求时流式传输数据,驱动程序应通过 Irp-IoStatus.Status> 返回错误(STATUS_RESOURCE_IN_USE)。
IOCTL_LAMP_SET_EMITTING_LIGHT (设置灯具发光)
IOCTL_LAMP_SET_EMITTING_LIGHT I/O 请求打开/关闭(闪光灯)光。
定义
#define IOCTL_LAMP_SET_EMITTING_LIGHT
CTL_CODE(IOCTL_LAMP_BASE, 0x0009, METHOD_BUFFERED, FILE_ANY_ACCESS)
输入参数
Irp-AssociatedIrp.SystemBuffer> 指向布尔类型的缓冲区,其值为 TRUE,指示 ON;否则为 FALSE。
输出参数
没有。
I/O 状态块
驱动程序将 Irp-IoStatus.Status> 设置为STATUS_SUCCESS或相应的错误状态。
如果 MediaCapture 会话在发出此请求时正在流式传输数据,驱动程序应通过 Irp->IoStatus.Status 返回错误(STATUS_RESOURCE_IN_USE)。
异步通知
如 并发用例中所述,需要闪存驱动程序才能发送 PnP 通知来报告资源可用性。 为此,可以根据具体情况使用以下 GUID 调用 IoReportTargetDeviceChange(或 IoReportTargetDeviceChangeAsynchronous):
由于捕获会话(或其他手电筒应用程序)启动,因此已逐出闪存资源:
特征 设置 标识符 GUID_LAMP_RESOURCES_LOST 类 GUID {F770E98C-4403-48C9-B1D2-4EEC3302E41F} 闪存资源现已可用:
特征 设置 标识符 GUID_LAMP_RESOURCES_AVAILABLE 类 GUID {185FE7CE-2616-481B-9094-20BB893ACD81}