Android-CameraX:在多个前置摄像头之间切换
Android-CameraX: Switch between multiple front cameras
我正在尝试编写我的第一个 Android 相机应用程序,但它总是选择变焦相机而不是主相机。 (我在华为P30 Pro上测试过)
并且代码基于官方的 camerax 示例应用程序 (https://github.com/android/camera-samples/tree/master/CameraXBasic)
相关代码:
/** Declare and bind preview, capture and analysis use cases */
private fun bindCameraUseCases() {
// Get screen metrics used to setup camera for full screen resolution
val metrics = DisplayMetrics().also { viewFinder.display.getRealMetrics(it) }
Log.d(TAG, "Screen metrics: ${metrics.widthPixels} x ${metrics.heightPixels}")
val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels)
Log.d(TAG, "Preview aspect ratio: $screenAspectRatio")
val rotation = viewFinder.display.rotation
// Bind the CameraProvider to the LifeCycleOwner
val cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
cameraProviderFuture.addListener(Runnable {
// CameraProvider
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview
preview = Preview.Builder()
// We request aspect ratio but no resolution
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation
.setTargetRotation(rotation)
.build()
// ImageCapture
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
// We request aspect ratio but no resolution to match preview config, but letting
// CameraX optimize for whatever specific resolution best fits our use cases
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation, we will have to call this again if rotation changes
// during the lifecycle of this use case
.setTargetRotation(rotation)
.build()
// Must unbind the use-cases before rebinding them
cameraProvider.unbindAll()
try {
// A variable number of use-cases can be passed here -
// camera provides access to CameraControl & CameraInfo
camera = cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture /**, imageAnalyzer*/)
// Attach the viewfinder's surface provider to preview use case
preview?.setSurfaceProvider(viewFinder.createSurfaceProvider(camera?.cameraInfo))
} catch(exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(requireContext()))
}
使用当前的 CameraX APIs,我不认为你可以选择使用哪个特定的相机,你只能 select 镜头朝向 (CameraSelector.Builder().requireLensFacing(int)
),这可以在前面或后面。当您绑定用例时,CameraX 会选择满足用例要求的第一台相机。例如,在启用或禁用扩展程序的情况下绑定预览用例时,可能会使用 2 个不同的后置摄像头。
CameraSelector
API 似乎还有成长的空间,所以在未来,您可能会更好地控制 select 的相机。如果您现在需要那种控制,您可能需要使用 Camera2。
我有类似的问题,但与后置摄像头有关。我检查了一些设备,发现在我所有测试过的设备上,我可以 select 相机 ID 并获得正确的相机:
- 相机 ID“0”-> Normal/default 后置相机
- 摄像头 ID“1”-> Normal/default 前置摄像头
所以我创建了一个自定义 CameraFilter,我在其中过滤相机 ID“0”:
class CameraIdFilter(private val cameraId: String) : CameraFilter {
override fun filterCameras(cameras: Set<CameraInternal>): Set<CameraInternal> {
val resultCameras: MutableSet<CameraInternal> = LinkedHashSet()
for (camera in cameras) {
val cameraId = camera.cameraInfoInternal.cameraId
if (cameraId == this.cameraId) {
resultCameras.add(camera)
}
}
return resultCameras
}
}
并将滤镜附加到相机select或:
val cameraSelectorBuilder = CameraSelector.Builder()
.requireLensFacing(lensFacing)
.appendFilter(CameraIdFilter("0"))
我不建议在生产应用中使用它,因为我确信有些设备不遵循这个 convention/pattern。但是您可以将它用于内部应用程序,您可以在其中知道您的用户使用哪些设备
我正在尝试编写我的第一个 Android 相机应用程序,但它总是选择变焦相机而不是主相机。 (我在华为P30 Pro上测试过)
并且代码基于官方的 camerax 示例应用程序 (https://github.com/android/camera-samples/tree/master/CameraXBasic)
相关代码:
/** Declare and bind preview, capture and analysis use cases */
private fun bindCameraUseCases() {
// Get screen metrics used to setup camera for full screen resolution
val metrics = DisplayMetrics().also { viewFinder.display.getRealMetrics(it) }
Log.d(TAG, "Screen metrics: ${metrics.widthPixels} x ${metrics.heightPixels}")
val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels)
Log.d(TAG, "Preview aspect ratio: $screenAspectRatio")
val rotation = viewFinder.display.rotation
// Bind the CameraProvider to the LifeCycleOwner
val cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
cameraProviderFuture.addListener(Runnable {
// CameraProvider
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview
preview = Preview.Builder()
// We request aspect ratio but no resolution
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation
.setTargetRotation(rotation)
.build()
// ImageCapture
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
// We request aspect ratio but no resolution to match preview config, but letting
// CameraX optimize for whatever specific resolution best fits our use cases
.setTargetAspectRatio(screenAspectRatio)
// Set initial target rotation, we will have to call this again if rotation changes
// during the lifecycle of this use case
.setTargetRotation(rotation)
.build()
// Must unbind the use-cases before rebinding them
cameraProvider.unbindAll()
try {
// A variable number of use-cases can be passed here -
// camera provides access to CameraControl & CameraInfo
camera = cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture /**, imageAnalyzer*/)
// Attach the viewfinder's surface provider to preview use case
preview?.setSurfaceProvider(viewFinder.createSurfaceProvider(camera?.cameraInfo))
} catch(exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(requireContext()))
}
使用当前的 CameraX APIs,我不认为你可以选择使用哪个特定的相机,你只能 select 镜头朝向 (CameraSelector.Builder().requireLensFacing(int)
),这可以在前面或后面。当您绑定用例时,CameraX 会选择满足用例要求的第一台相机。例如,在启用或禁用扩展程序的情况下绑定预览用例时,可能会使用 2 个不同的后置摄像头。
CameraSelector
API 似乎还有成长的空间,所以在未来,您可能会更好地控制 select 的相机。如果您现在需要那种控制,您可能需要使用 Camera2。
我有类似的问题,但与后置摄像头有关。我检查了一些设备,发现在我所有测试过的设备上,我可以 select 相机 ID 并获得正确的相机:
- 相机 ID“0”-> Normal/default 后置相机
- 摄像头 ID“1”-> Normal/default 前置摄像头
所以我创建了一个自定义 CameraFilter,我在其中过滤相机 ID“0”:
class CameraIdFilter(private val cameraId: String) : CameraFilter {
override fun filterCameras(cameras: Set<CameraInternal>): Set<CameraInternal> {
val resultCameras: MutableSet<CameraInternal> = LinkedHashSet()
for (camera in cameras) {
val cameraId = camera.cameraInfoInternal.cameraId
if (cameraId == this.cameraId) {
resultCameras.add(camera)
}
}
return resultCameras
}
}
并将滤镜附加到相机select或:
val cameraSelectorBuilder = CameraSelector.Builder()
.requireLensFacing(lensFacing)
.appendFilter(CameraIdFilter("0"))
我不建议在生产应用中使用它,因为我确信有些设备不遵循这个 convention/pattern。但是您可以将它用于内部应用程序,您可以在其中知道您的用户使用哪些设备