[译] 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 的多摄像头支持的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大陆第二家迪士尼乐园要落户长沙?官方最新
- 下一篇: 马斯克新传记上架亚马逊网站,作者评价其“