Android 支持将搭载 Android 14-QPR1 或更高版本的设备用作 USB 摄像头。系统会将支持此功能的 Android 设备通告为 UVC 设备,这使得多种搭载不同操作系统(例如 Linux、macOS、Windows 和 ChromeOS)的 USB 主机可以将此类设备的摄像头用作网络摄像头。DeviceAsWebcam
服务支持此功能,可将此类设备用作摄像头。
DeviceAsWebcam 服务
AOSP 中的 DeviceAsWebcam
服务包括可以让用户取景的预览 activity (DeviceAsWebcamPreview.java
)。预览 activity 让用户能够执行以下操作:
在串流开始之前,预览摄像头 Feed 在主机上的显示效果。
通过以下方式自定义发送到主机的摄像头 Feed:
- 选择要串流前置还是后置摄像头 Feed。
- 使用滑块或按钮选择缩放级别。
- 点按预览画面的某个区域,以便聚焦于或取消聚焦于该区域。
预览 activity 可与 Android 上的常规无障碍功能(例如 TalkBack、开关控制和 Voice Access)配合使用。
图 1. 摄像头 Feed 串流到主机,预览可用于控制 Feed。
架构
图 2 中展示了支持将设备用作摄像头的架构。下文介绍了 DeviceAsWebcam
服务与 Android 框架其他部分的交互流程:
- 用户在“设置”应用中选择 USB 摄像头选项。
- “设置”应用通过
UsbManager
类向system_server
发送一个 binder 调用,通知对方已选择FUNCTION_UVC
。 - 系统服务器会执行以下操作:
- 通过
setUsbFunctions
HAL 接口调用通知 USB Gadget HAL 检索 UVC Gadget 函数。 - 通知 USB Gadget HAL 使用 ConfigFs 配置 UVC Gadget 驱动程序。
- 通过
- 收到来自 Gadget HAL 的回调后,
system_server
向框架发送广播,以供DeviceAsWebcam
服务接收。 - USB Gadget 驱动程序通过
/dev/video*
处的 V4L2 节点从主机接收到配置命令后,启动摄像头 Feed 串流。
图 2. DeviceAsWebcam 架构。
实现
本部分介绍了如何支持将 Android 设备用作摄像头。
内核支持
对于 Android 14 或更高版本,通用内核映像 (GKI) 会默认启用 UVC Gadget 驱动程序(请参阅 AOSP 补丁中的详细信息)。
在 Gadget HAL 中支持 UVC
从 Android 14 开始,UVC 函数包含在 GadgetFunction.aidl
HAL 接口中。对于 Gadget HAL,UVC Gadget 会装载到 ConfigFS,具体方式与装载其他 ConfigFS 函数(例如 MTP 或 ADB)的方式相同。
如要实现 Gadget HAL,请进行相应修改,将 UVC 函数装载到 ConfigFS。下面是支持 UVC 函数的 Gadget HAL 实现的示例代码段:
UsbGadget::setCurrentUsbFunctions(long functions) {
...
// Existing functions
if ((functions & GadgetFunction::MTP) != 0) {
...
linkFunction("ffs.mtp"); // Mount to ConfigFS
...
}
...
// UVC function follows the same pattern!
if ((functions & GadgetFunction::UVC) != 0) {
...
linkFunction("uvc.0"); // Mount to ConfigFS
...
}
...
}
当设备用作摄像头时,请确保 USB Gadget HAL 会通告正确的 VID/PID 组合。
由于所有 UVC 逻辑都在供应商 init 或 DeviceAsWebcam
服务中,因此除了将 UVC 函数以符号链接方式链接到 ConfigFS 之外,Gadget HAL 中不需要任何其他 UVC 专用逻辑。
如需有关实现的进一步指导,请参阅 AOSP 中的以下示例代码:
使用 UVC 配置设置 ConfigFS
如需将 Android 摄像头支持的格式、大小和帧速率通知 UVC Gadget 驱动程序,请使用 UVC 配置设置 ConfigFS。如需了解详情,请参阅关于 ConfigFS UVC Gadget ABI 的上游 Linux 文档。
以下是关于供应商 init 如何设置 UVC Gadget 驱动程序的示例(AOSP 中的代码段):
# uvc function
mkdir /configfs_path/functions/uvc.0
write /configfs_path/functions/uvc.0/function_name "Android Webcam"
write /configfs_path/functions/uvc.0/streaming_maxpacket 3072
# setup control params
mkdir /configfs_path/functions/uvc.0/control/header/h
symlink /configfs_path/functions/uvc.0/control/header/h \
/configfs_path/functions/uvc.0/control/class/fs/h
symlink /configfs_path/functions/uvc.0/control/header/h \
/configfs_path/functions/uvc.0/control/class/ss/h
# advertise 1080p resolution for webcam encoded as mjpeg
mkdir /configfs_path/functions/uvc.0/streaming/mjpeg/m/1080p
write /configfs_path/functions/uvc.0/streaming/mjpeg/m/1080p/wHeight 1080
write /configfs_path/functions/uvc.0/streaming/mjpeg/m/1080p/wWidth 1920
write /configfs_path/functions/uvc.0/streaming/mjpeg/m/1080p/dwMaxVideoFrameBufferSize 4147200
# advertise 30 fps support for 1080p.
write /configfs_path/functions/uvc.0/streaming/mjpeg/m/1080p/dwDefaultFrameInterval 333333
write /configfs_path/functions/uvc.0/streaming/mjpeg/m/1080p/dwFrameInterval "333333"
# setup streaming params
mkdir /configfs_path/functions/uvc.0/streaming/header/h
symlink /configfs_path/functions/uvc.0/streaming/mjpeg/m \
/configfs_path/functions/uvc.0/streaming/header/h/m
symlink /configfs_path/functions/uvc.0/streaming/header/h \
/configfs_path/functions/uvc.0/streaming/class/fs/h
symlink /configfs_path/functions/uvc.0/streaming/header/h \
/configfs_path/functions/uvc.0/streaming/class/hs/h
symlink /configfs_path/functions/uvc.0/streaming/header/h \
/config/usb_gadget/g1/functions/uvc.0/streaming/class/ss/h
# ...
此代码段用于将 UVC Gadget 驱动程序设置为以 30 fps 的帧速率通告 1080p MJPEG 串流。当 USB 主机查询受支持的分辨率和帧速率时,系统会将这些功能传达给 USB 主机。
以下是选择摄像头通告的配置时遵从的一般准则:
DeviceAsWebcam
服务支持的两种串流格式是 MJPEG 和未压缩的 YUYV。- USB 2.0 支持 480 Mbps (60 MBps) 数据传输。这意味着,当帧速率为 30 fps 时,每帧的大小不得超过 2 MB;当帧速率为 60 fps 时,每帧的大小不得超过 1 MB。
- 未压缩的串流 (YUYV):当帧速率为 30 fps 时,支持的最大帧大小为 720p,因为 YUYV 为每像素 2 个字节。
- 压缩的 MJPEG 串流:假设 YUV 的压缩率为 1:10,USB 2.0 可以支持 4K(每帧 1.18 MB)。
- 主要前置和后置摄像头设备必须支持所通告的所有帧大小。这是因为用户可以通过预览界面在摄像头 ID 之间切换。对于 MJPEG 串流,我们建议供应商通告 480p (640 x 480)、720p (1280 x 820) 和 1080p (1920 x 1080) 帧大小,因为这些是主机应用常用的大小。
- 主要前置和后置摄像头设备必须支持所通告的所有帧速率。我们强烈建议供应商支持 30 fps。
如需关于添加摄像头串流配置 (ConfigFS) 的示例,请参阅 AOSP 示例补丁。
在 build 中启用摄像头
如需启用 DeviceAsWebcam
服务,您必须在 device.mk
文件中将 ro.usb.uvc.enabled
系统属性设置为 true
。
# Enable UVC support
PRODUCT_VENDOR_PROPERTIES += \
ro.usb.uvc.enabled=true
此系统属性处于启用状态时,“设置”应用中的 USB 偏好设置下方会显示摄像头选项,如图 3 所示。如果您选择了此选项,Android 设备会向主机设备显示为 USB 摄像头。
图 3. “设置”应用中的 USB 偏好设置。
您还可以使用以下命令通过 ADB 将设备设置为 USB 摄像头:
adb shell svc usb setFunctions uvc
考虑功耗和发热问题
摄像头操作意味着设备的摄像头在一天中可能开启数小时,因此我们建议采取措施来确保设备的功耗和发热不超过一定限度。下面建议了一些解决方案,这些方案有助于使功耗不超过一定限度:
- 为了提升相机 HAL 的功耗性能,请在
DeviceAsWebcam
服务中启用STREAM_USE_CASE_VIDEO_CALL
。 如果启用
STREAM_USE_CASE_VIDEO_CALL
后仍然存在功耗问题,DeviceAsWebcam
服务提供了一个选项,即使用物理串流进一步降低功耗。您可以使用运行时资源叠加层 (RRO) 来指定要使用的物理摄像头。物理串流会显著降低视频质量并导致用户体验混乱,因此请仅在万不得已的情况下使用此解决方案。优化STREAM_USE_CASE_VIDEO_CALL
是解决功耗问题的首选方案。如需详细了解DeviceAsWebcam
服务支持的 RRO,请参阅 readme.md。下面是一个设置为使用物理摄像头 ID 3(而非逻辑摄像头 ID 0)的 RRO 示例。如需查看 AOSP 中的示例,请参阅 DeviceAsWebcamRaven。
// For logical camera id 0 - use physical camera id 3 {"0": {"3" : "UW"}}
验证
如需测试您设备上的 DeviceAsWebcam
服务实现,请使用以下测试:
- CTS 验证程序测试摄像头:测试设备支持的格式、大小和帧速率。
- 手动测试:测试摄像头功能能否与各种主机操作系统上的各种主机应用配合使用。
已知问题
以下是 DeviceAsWebcam
服务的已知问题:
UVC Gadget 驱动程序的串流有时会抖动并显示类似损坏的帧。此问题已修复,并且修复程序已合并至上游和 GKI。
由于 Apple 的 UVC 驱动程序存在 bug,因此处于摄像头模式的 Android 设备无法与 macOS 主机上的 USB 3.0+ 一起使用。