将设备用作网络摄像头

对于运行 Android 14-QPR1 或更高版本的设备,Android 支持将设备用作 USB 网络摄像头。支持此功能的 Android 设备被宣传为 UVC 设备,这使各种具有不同操作系统的 USB 主机(例如,Linux、macOS、Windows 和 ChromeOS)可以使用设备的摄像头作为网络摄像头。DeviceAsWebcam 服务支持此功能,以将设备用作网络摄像头。

DeviceAsWebcam 服务

AOSP 中的 DeviceAsWebcam 服务包含一个预览 Activity (DeviceAsWebcamPreview.java),用户可以使用它来构图。用户可以使用预览 Activity 执行以下操作

  • 在开始流式传输之前,预览网络摄像头馈送到主机上的外观。

  • 通过以下方式自定义发送到主机的网络摄像头馈送

    • 选择要流式传输的摄像头,前置或后置。
    • 使用滑块或按钮选择缩放级别。
    • 点按预览的特定区域以对焦或移除区域的焦点。

预览 Activity 适用于 Android 上的通用无障碍功能,例如 TalkBackSwitch AccessVoice Access

webcam feed streamed to host

图 1. 网络摄像头馈送被流式传输到主机,预览控制馈送。

架构

图 2 说明了支持将设备用作网络摄像头的架构。以下描述了 DeviceAsWebcam 服务与 Android 框架其余部分的交互流程

  1. 用户在“设置”应用中选择 USB 网络摄像头选项。
  2. “设置”应用通过 UsbManager 类向 system_server 发送 Binder 调用,告知其已选择 FUNCTION_UVC
  3. 系统服务器执行以下操作
    1. 通过 setUsbFunctions HAL 接口调用,通知 USB gadget HAL 检索 UVC gadget 功能。
    2. 通知 USB gadget HAL 使用 ConfigFs 配置 UVC gadget 驱动程序。
  4. 收到来自 gadget HAL 的回调后,system_server 向框架发送广播,以供 DeviceAsWebcam 服务接收。
  5. USB gadget 驱动程序在通过 /dev/video* 上的 V4L2 节点接收到来自主机的配置命令后,启动网络摄像头流。

device as webcam architecture

图 2. DeviceAsWebcam 架构。

实现

本节介绍如何支持将 Android 设备用作网络摄像头。

内核支持

对于 Android 14 或更高版本,通用内核映像 (GKI) 默认启用 UVC gadget 驱动程序(详细信息请参阅 AOSP 补丁)。

在 Gadget HAL 中支持 UVC

从 Android 14 开始,UVC 功能包含在 GadgetFunction.aidl HAL 接口中。对于 Gadget HAL,UVC gadget 以与其他 ConfigFS 功能(例如 MTP 或 ADB)相同的方式挂载到 ConfigFS。

要实现 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 逻辑都在 vendor init 或 DeviceAsWebcam 服务中,因此 Gadget HAL 中不需要任何特定于 UVC 的逻辑,只需将 UVC 功能符号链接到 ConfigFS 即可。

有关实现的更多指导,请参阅 AOSP 中的以下示例代码

使用 UVC 配置设置 ConfigFS

要告知 UVC gadget 驱动程序 Android 网络摄像头支持哪些格式、大小和帧速率,请使用 UVC 配置设置 ConfigFS。有关更多信息,请参阅有关 ConfigFS UVC gadget ABI 的上游 Linux 文档。

以下是 vendor 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)。
  • 主前置和后置摄像头设备必须支持通告的所有帧大小。这是因为用户可以使用预览 UI 在摄像头 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 网络摄像头显示在主机设备上。

USB preferences in Settings app

图 3. “设置”应用中的 USB 偏好设置。

您还可以通过 ADB 使用以下命令将设备设置为 USB 网络摄像头功能

adb shell svc usb setFunctions uvc

考虑功耗和散热问题

网络摄像头操作意味着设备的摄像头可能每天开启数小时,因此我们建议采取措施以确保设备的功耗和散热保持在一定限制范围内。以下是将功耗保持在限制范围内的建议解决方案

  • 为了从摄像头 HAL 获得更好的电源性能,请在 DeviceAsWebcam 服务中启用 STREAM_USE_CASE_VIDEO_CALL
  • 如果即使启用了 STREAM_USE_CASE_VIDEO_CALL,功耗仍然是一个问题,则 DeviceAsWebcam 服务提供了一个选项,可以通过使用物理流来进一步降低功耗。您可以使用运行时资源叠加 (RRO) 来指定要使用的物理摄像头。物理流会显着降低视频质量并导致令人困惑的 UX,因此仅在万不得已的情况下才使用此解决方案。优化 STREAM_USE_CASE_VIDEO_CALL 是解决功耗问题的首选解决方案。有关 DeviceAsWebcam 服务支持的 RRO 的更多信息,请参阅 readme.md

    以下是设置 RRO 以使用物理摄像头 ID 3 而不是逻辑摄像头 ID 0 的示例。有关 AOSP 中的示例,请参阅 DeviceAsWebcamRaven

    // For logical camera id 0 - use physical camera id 3
    {"0": {"3" : "UW"}}
    

验证

要在您的设备上测试您对 DeviceAsWebcam 服务的实现,请使用以下测试

  • CTS 验证程序测试 webcam:测试设备是否支持格式、大小和帧速率。
  • 手动测试:测试网络摄像头功能是否适用于各种主机操作系统上的各种主机应用。

已知问题

以下是 DeviceAsWebcam 服务的已知问题