如何在CameraX上切换到前置摄像头?

时间:2019-05-16 23:08:49

标签: android android-camerax

我已经按照here to get CameraX setup的步骤进行操作,现在我正在尝试使前置摄像头按钮正常工作。

这是我的设置代码:

private lateinit var preview: Preview

private fun startCamera() {

    // Create configuration object for the viewfinder use case
    val previewConfig = PreviewConfig.Builder().apply {
        setLensFacing(CameraX.LensFacing.BACK)
    }.build()

    // Build the viewfinder use case
    preview = Preview(previewConfig)

    // Every time the viewfinder is updated, recompute layout
    preview.setOnPreviewOutputUpdateListener {

        // To update the SurfaceTexture, we have to remove it and re-add it
        val parent = viewFinder.parent as ViewGroup
        parent.removeView(viewFinder)
        parent.addView(viewFinder, 0)

        viewFinder.surfaceTexture = it.surfaceTexture
        updateTransform()
    }

    // Bind use cases to lifecycle
    CameraX.bindToLifecycle(this, preview)
}

当用户单击“切换”按钮时,我将预览重新配置为使用前置摄像头,然后重新初始化预览。

private fun initSwitchButton(view: View) {
    switchButton = view.findViewById(R.id.switch_button)
    switchButton.setOnClickListener {
        val previewConfig = PreviewConfig.Builder().apply { setLensFacing(CameraX.LensFacing.FRONT) }.build()
        preview = Preview(previewConfig)
    }
}

但是,这不会切换到前置摄像头。我想念什么?

4 个答案:

答案 0 :(得分:1)

自 2021 年以来,CameraX 的更新导致 CameraX.LensFacing 无法使用。改用 CameraSelector

    private CameraSelector lensFacing = CameraSelector.DEFAULT_FRONT_CAMERA;

    private void flipCamera() {
        if (lensFacing == CameraSelector.DEFAULT_FRONT_CAMERA) lensFacing = CameraSelector.DEFAULT_BACK_CAMERA;
        else if (lensFacing == CameraSelector.DEFAULT_BACK_CAMERA) lensFacing = CameraSelector.DEFAULT_FRONT_CAMERA;
        startCamera();
    }

    private void startCamera() {
        ListenableFuture<ProcessCameraProvider> cameraFuture = ProcessCameraProvider.getInstance(requireContext());

        cameraFuture.addListener(() -> {
            imageCapture = new ImageCapture.Builder()
                .setTargetRotation(cameraPreview.getDisplay().getRotation())
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                .build();
            videoCapture = new VideoCapture.Builder().build();

        try {
            ProcessCameraProvider processCameraProvider = cameraFuture.get();
            Preview preview = new Preview.Builder().build();
            preview.setSurfaceProvider(cameraPreview.getSurfaceProvider());
            processCameraProvider.unbindAll(); 

            // lensFacing is used here
            processCameraProvider.bindToLifecycle(getViewLifecycleOwner(), lensFacing, imageCapture, videoCapture, preview);
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        }, ContextCompat.getMainExecutor(requireContext()));
    }

答案 1 :(得分:0)

看来recommended way是通过将LensFacing位置存储为实例变量,然后调用bindToLifecycle()来切换相机来实现的。

以下是对我有用的代码段:

private var lensFacing = CameraX.LensFacing.BACK
private var imageCapture: ImageCapture? = null

@SuppressLint("RestrictedApi")
private fun startCamera() {
    bindCameraUseCases()

    // Listener for button used to switch cameras
    switchButton = view.findViewById(R.id.switch_button)
    switchButton.setOnClickListener {
        lensFacing = if (CameraX.LensFacing.FRONT == lensFacing) {
            CameraX.LensFacing.BACK
        } else {
            CameraX.LensFacing.FRONT
        }
        try {
            // Only bind use cases if we can query a camera with this orientation
            CameraX.getCameraWithLensFacing(lensFacing)
            bindCameraUseCases()
        } catch (exc: Exception) {
            // Do nothing
        }
    }
}

private fun bindCameraUseCases() {
    // Make sure that there are no other use cases bound to CameraX
    CameraX.unbindAll()

    val previewConfig = PreviewConfig.Builder().apply {
        setLensFacing(lensFacing)
    }.build()
    val preview = Preview(previewConfig)

    val imageCaptureConfig = ImageCaptureConfig.Builder().apply {
        setLensFacing(lensFacing)
    }.build()
    imageCapture = ImageCapture(imageCaptureConfig)

    // Apply declared configs to CameraX using the same lifecycle owner
    CameraX.bindToLifecycle(this, preview, imageCapture)
}

答案 2 :(得分:0)

private LensFacing lensFacing = CameraX.LensFacing.BACK;
private ImageCapture imageCapture = null;
private Button switchButton;


@SuppressLint("RestrictedApi")
private void startCamera() {
    bindCameraUseCases();

    // Listener for button used to switch cameras
    switchButton = view.findViewById(R.id.switch_button);
    switchButton.setOnClickListener(v -> {
        lensFacing = lensFacing == LensFacing.FRONT ? LensFacing.BACK : LensFacing.FRONT;
        try {
            // Only bind use cases if we can query a camera with this orientation
            CameraX.getCameraWithLensFacing(lensFacing);
            bindCameraUseCases();
        } catch (CameraInfoUnavailableException e) {
            // Do nothing
        }
    });
}

private void bindCameraUseCases() {
    // Make sure that there are no other use cases bound to CameraX
    CameraX.unbindAll();

    PreviewConfig previewConfig = new PreviewConfig.Builder().
            setLensFacing(lensFacing)
            .build();
    Preview preview = new Preview(previewConfig);

    ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
            .setLensFacing(lensFacing)
            .build();
    imageCapture = new ImageCapture(imageCaptureConfig);

    // Apply declared configs to CameraX using the same lifecycle owner
    CameraX.bindToLifecycle(this, preview, imageCapture);
}

Java版本

答案 3 :(得分:0)

这是我的做法

private var defaultCameraFacing = CameraSelector.DEFAULT_BACK_CAMERA

   btnFlipCamera.setOnClickListener {
        Log.d("CameraFacing", defaultCameraFacing.toString())
        defaultCameraFacing = if(defaultCameraFacing == CameraSelector.DEFAULT_FRONT_CAMERA){
            CameraSelector.DEFAULT_BACK_CAMERA
        }else{
            CameraSelector.DEFAULT_FRONT_CAMERA
        }

        try {
            // Only bind use cases if we can query a camera with this orientation
            startCamera(defaultCameraFacing)
        } catch (exc: Exception) {
            // Do nothing
        }
    }

private fun startCamera(defaultCameraFacing: CameraSelector) {
    llPictureCaptured.visibility = View.GONE
    tvLocationLabel.visibility= View.GONE
    pgLoadingLocation.visibility = View.GONE
    openCamera.visibility = View.GONE
    llCameraControl.visibility = View.VISIBLE
    viewFinder.visibility = View.VISIBLE


    val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

    cameraProviderFuture.addListener({
        // Used to bind the lifecycle of cameras to the lifecycle owner
        val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

        // Preview
        val preview = Preview.Builder()
            .build()
            .also {
                it.setSurfaceProvider(viewFinder.surfaceProvider)
            }

        imageCapture = ImageCapture.Builder()
            .build()

        //set image analysis, i.e luminosity analysis
        val imageAnalyzer = ImageAnalysis.Builder()
            .build()
            .also {
                it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
                    Log.d(TAG, "Average luminosity: $luma")
                })
            }

        // Set camera facing
        val cameraSelector = defaultCameraFacing

        try {
            // Unbind use cases before rebinding
            cameraProvider.unbindAll()

            // Bind use cases to camera
            cameraProvider.bindToLifecycle(
                this, cameraSelector, preview, imageCapture, imageAnalyzer)

        } catch (exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
        }

    }, ContextCompat.getMainExecutor(this))
}