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。但是您可以将它用于内部应用程序,您可以在其中知道您的用户使用哪些设备