写点什么

[译] Android 的多摄像头支持 (1)

用户头像
Android架构
关注
发布于: 21 小时前

}, null)

第一个并不是最好的选择

上述代码目前看起来没什么问题。如果我们所需要的只是一个能够打开第一个存在的摄像头的应用程序,那么它在大部分的 Android 手机上都有效。但是考虑到以下场景:


  • 如果设备没有摄像头,那么应用程序会崩溃。这看起来似乎不太可能,但是要知道 Android 运用在各种设备上,包括 Android Things、Android Wear 和 Android TV 等这些有数百万用户的设备。

  • 如果设备至少有一个后置摄像头,它将会映射到列表中的第一个摄像头。但是当应用程序运行在没有后置摄像头的设备上,比如 PixelBooks 或者其他一些 ChromeOS 的笔记本电脑,将会打开唯一一个前置摄像头。


那么我们应该怎么做?检查摄像头列表和摄像头特性:


val cameraIdList = cameraManager.cameraIdList // may be emptyval characteristics = cameraManager.getCameraCharacteristics(cameraId)val cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)


变量 cameraLensFacing 有以下取值:



更多有关摄像头配置的信息,请查看文档.

合理的默认设置

根据应用程序的使用情况,我们希望默认打开特定的相机镜头配置(如果可以提供这样的功能)。比如,自拍应用程序很可能想要打开前置摄像头,而一款增强现实类的应用程序应该希望打开后置摄像头。我们可以将这样的一个逻辑包装成一个函数,它可以正确地处理上面提到的情况:


fun getFirstCameraIdFacing(cameraManager: CameraManager,facing: Int = CameraMetadata.LENS_FACING_BACK): String? {val cameraIds = cameraManager.cameraIdList// Iterate over the list of cameras and return the first one matching desired// lens-facing configurationcameraIds.forEach {val characteristics = cameraManager.getCameraCharacteristics(it)if (characteristics.get(CameraCharacteristics.LENS_FACING) == facing) {return it}}// If no camera matched desired orientation, return the first one from the listreturn cameraIds.firstOrNull()}

切换摄像头

目前为止,我们讨论了如何基于应用程序的用途选择默认摄像头。很多相机应用程序还为用户提供切换摄像头的功能:



Google 相机应用中切换摄像头按钮


要实现这个功能,尝试从CameraManager.getCameraIdList()提供的列表中选择下一个摄像头,但是这并不是个好的方式。因为从 Android P 开始,我们将会看到在同样的情况下更多的设备有多个摄像头,甚至有通过 USB 连接的外部摄像头。如果我们想要提供给用户切换不同摄像头的 UI,建议(按照文档)是为每个可能的镜头配置选择第一个可用的摄像头。


尽管没有一个通用的逻辑可以用来选择下一个摄像头,但是下述代码适用于大部分情况:


fun filterCameraIdsFacing(cameraIds: Array<String>, cameraManager: CameraManager,facing: Int): List<String> {return cameraIds.filter {val characteristics = cameraManager.getCameraCharacteristics(it)characteristics.get(CameraCharacteristics.LENS_FACING) == facing}}


fun getNextCameraId(cameraManager: CameraManager, currCameraId: String? = null): String? {// Get all front, back and external cameras in 3 separate listsval cameraIds = cameraManager.cameraIdListval backCameras = filterCameraIdsFacing(cameraIds, cameraManager, CameraMetadata.LENS_FACING_BACK)val frontCameras = filterCameraIdsFacing(cameraIds, cameraManager, CameraMetadata.LENS_FACING_FRONT)val externalCameras = filterCameraIdsFacing(cameraIds, cameraManager, CameraMetadata.LENS_FACING_EXTERNAL)


// The recommended order of iteration is: all external, first back, first frontval allCameras = (externalCameras + listOf(backCameras.firstOrNull(), frontCameras.firstOrNull())).filterNotNull()


// Get the index of the currently selected camera in the listval cameraIndex = allCameras.indexOf(currCameraId)


// The selected camera may not be on the list, for example it could be an// external camera that has been removed by the userreturn if (cameraIndex == -1) {// Return the first camera from the listallCameras.getOrNull(0)} else {// Return the next camera from the list, wrap around if necessaryallCameras.getOrNull((cameraIndex + 1) % allCameras.size)}}


这看起来可能有点复杂,但是我们需要考虑到大量的有不同配置的设备。

兼容性行为

对于那些仍然在使用已经废弃的 Camera API 的应用程序,通过 Camera.getNumberOfCameras() 得到的摄像头的数量取决于 OEM 的实现。文档上是这样描述的:


如果系统中有逻辑多摄像头,为了保持应用程序的向后兼容性,这个方法仅为每个逻辑摄像头和底层的物理摄像头组公开一个摄像头。使用 camera2 API 去查看所有摄像头。

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
[译] Android 的多摄像头支持(1)