[译] Android 的多摄像头支持
- 原文地址:Camera Enumeration on Android
- 原文作者:Oscar Wahltinez
- 译文出自:掘金翻译计划
- 本文永久链接:github.com/xitu/gold-m…
- 译者:luoqiuyu
- 校对者:hanliuxin5
从 Android P 开始,添加了对逻辑多摄像头和 USB 摄像头的支持。这对 Android 开发者来说意味着什么?
多摄像头
一台设备有多个摄像头没什么新鲜的,但是直到现在,Android 设备仍然最多只有前后两个摄像头。如果你想要打开第一个摄像头,需要进行以下操作:
val cameraDevice = Camera.open(0)
复制代码
但是这些是比较简单的操作。如今多摄像头意味着前置或者后置有两个及两个以上的摄像头。有很多镜头可供选择!
Camera2 API
由于兼容性问题,尽管旧的 Camera API 已经被废弃很长时间,上述的代码仍然有效。但是随着生态系统的发展,需要更先进的相机功能。因此,Android 5.0(Lollipop)引进了 Camera2,适用于 API 21 及以上。用 Camera2 API 来打开第一个存在的摄像头代码如下所示:
val cameraManager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
val cameraId = cameraManager.cameraIdList[0]
cameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() {override fun onOpened(device: CameraDevice) {// Do something with `device`}override fun onDisconnected(device: CameraDevice) {device.close()}override fun onError(device: CameraDevice, error: Int) {onDisconnected(device)}
}, null)
复制代码
第一个并不是最好的选择
上述代码目前看起来没什么问题。如果我们所需要的只是一个能够打开第一个存在的摄像头的应用程序,那么它在大部分的 Android 手机上都有效。但是考虑到以下场景:
- 如果设备没有摄像头,那么应用程序会崩溃。这看起来似乎不太可能,但是要知道 Android 运用在各种设备上,包括 Android Things、Android Wear 和 Android TV 等这些有数百万用户的设备。
- 如果设备至少有一个后置摄像头,它将会映射到列表中的第一个摄像头。但是当应用程序运行在没有后置摄像头的设备上,比如 PixelBooks 或者其他一些 ChromeOS 的笔记本电脑,将会打开唯一一个前置摄像头。
那么我们应该怎么做?检查摄像头列表和摄像头特性:
val cameraIdList = cameraManager.cameraIdList // may be empty
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)
复制代码
变量 cameraLensFacing
有以下取值:
- CameraMetadata.LENS_FACING_FRONT
- CameraMetadata.LENS_FACING_BACK
- CameraMetadata.LENS_FACING_EXTERNAL
更多有关摄像头配置的信息,请查看文档.
合理的默认设置
根据应用程序的使用情况,我们希望默认打开特定的相机镜头配置(如果可以提供这样的功能)。比如,自拍应用程序很可能想要打开前置摄像头,而一款增强现实类的应用程序应该希望打开后置摄像头。我们可以将这样的一个逻辑包装成一个函数,它可以正确地处理上面提到的情况:
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 去查看所有摄像头。
请仔细阅读 其余文档 获得更多信息。通常来说,类似的建议适用于:使用 Camera.getCameraInfo() API 查询所有的摄像头方向, 在用户切换摄像头时,仅仅只为每个可用的方向提供一个摄像头。
最佳实践
Android 运行在许多不同的设备上。你不应该假设你的应用程序总是在有一两个摄像头的传统的手持设备上运行,而是应该为你的应用程序选择最适合的摄像头。如果你不需要特定的摄像头,选择有所需默认配置的第一个摄像头。如果设备连接了外部摄像头,则可以合理的假设用户希望首先看到这些外部摄像头中的第一个。
如果发现译文存在错误或其他需要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 本文永久链接 即为本文在 GitHub 上的 MarkDown 链接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。
[译] Android 的多摄像头支持相关推荐
- android camera2获取摄像头支持的分辨率
android camera2 获取摄像头支持的分辨率 41的for循环我注释了,代码是获取最匹配的分辨率. private Size getMatchingSize2(){Size selectSi ...
- Android 双usb 摄像头支持
公司有一款产品需要支持双USB摄像头,标准的Android设备只支持同时打开一个camera,若要支持两个显示需要修改rk3288 源码, hardware/rockchip/camera/Camer ...
- android高仿微信拍摄,Android 仿微信视频拍摄 支持触摸拍摄 长按拍摄
JCamera This is Android CameraActivity,Imitation WeChat Camera Android 仿微信视频拍摄 支持触摸拍摄 长按拍摄,采用camera2 ...
- Android 开发多摄像头 API
这篇博客是对我们的 Android 开发者峰会 2018 演讲 的补充,是与来自合作伙伴开发者团队中的 Vinit Modi.Android Camera PM 和 Emilie Roberts 合作 ...
- java 检测网络图片大小_java – 网络摄像头支持的图片大小
我正在尝试检索我的网络摄像头支持的可用图片尺寸分辨率;使用OpenCV库.我已经尝试使用类似的 Android问题/答案,但无济于事. (例如 Android camera supported pic ...
- 终于搞定android驱动USB摄像头了!
终于搞定android驱动USB摄像头了! 多亏了stackoverflow看到的一篇帖子,其中有几句关键的话,然后顺藤摸瓜解决了问题. 帖子大意: 讨论的前提是你的USB摄像头是UVC兼容的(如今大 ...
- android usb 摄像头 分辨率,Android 驱动USB摄像头
最近有个需求,要用android 来驱动外部usb摄像头.emmmmmmm...... 港真,突然听到这么个需求,有点蒙~~于是google github转有没有类似需求的文章.诶嘿 还真有. 还有 ...
- Android RK3399 UVC摄像头格式异常
Android RK3399 UVC摄像头格式异常 前言 分析 处理方式 结论 前言 厂商提供了一个摄像头,接入后dev/video节点已生成,打开也成功了,但是黑屏,无法预览.最终查了HAL层代码才 ...
- android 打开外置摄像头驱动程序,嵌入式er日常系列!终于搞定android驱动USB摄像头了!...
原标题:嵌入式er日常系列!终于搞定android驱动USB摄像头了! 感谢网上的大神分享经验,终于解决了让我头疼好久的USB摄像头问题,讨论的前提是你的USB摄像头是UVC兼容的(如今大部分摄像头兼 ...
最新文章
- Codeforces Round #658 (Div. 2)部分题解
- 拥抱AI大趋势,ARM发布两款AI芯片架构
- 根据location地址,在导航栏高亮显示当前页面
- 前端学习(2458):评论模块
- python 网格_Python | 网格到情节
- 开博1个月不到,照样可以申请到text-link-ads
- sql组合键设置外键_学习SQL:外键
- 递归法:走楼梯; 旋转数组的最小数字(递归法和改进二分法)
- Android 资源和国际化
- 如何区别文本是BIG5还是GB
- 语音计算机在线算使用方法,计算器在线计算
- 修改Centos服务器主机名称
- 【用积分求不规则面积+抛物线方程】HDU-1071 The area
- 基于ECS构建微信公众号管理系统
- python 编程基础案例
- destoon首页底部加产品分类拼音索引
- AVR单片机熔丝和解锁
- 全球及中国咳嗽和感冒药行业竞争趋势及需求规模预测报告(2022-2027)
- Java日志——Logback的使用及原理
- rasa填槽slot