【问题标题】:How to switch to front camera on CameraX?如何在 CameraX 上切换到前置摄像头?
【发布时间】:2021-08-12 09:51:49
【问题描述】:

我已按照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)
    }
}

但是,这不会切换到前置摄像头。我错过了什么?

【问题讨论】:

  • 既然您正在创建一个新的Preview 实例,您是否不需要在这个新的Preview 上运行第一个代码sn-p 中的setOnPreviewOutputUpdateListenerbindToLifecycle() 位? (除了清理旧的Preview 实例,如果这还没有完成的话)我还没有使用过 CameraX,所以我可能不正常——这只是比较和对比你的两个代码 sn-ps .
  • 刚刚找到了一个示例,github.com/android/camera/blob/master/CameraXBasic/app/src/main/…,看起来您需要再次致电bindToLifecycle。当我找到一个干净的解决方案时,我会更新答案!

标签: android android-camerax


【解决方案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()));
    }

【讨论】:

    【解决方案2】:

    看来recommended way的实现方式是将LensFacing位置存储为实例变量,然后调用bindToLifecycle()切换摄像头。

    这是一个对我有用的代码 sn-p:

    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)
    }
    

    【讨论】:

    • 我怎样才能在 java 中达到同样的效果
    • 没有CameraX.LensFacing.BACK 常量。应该是CameraSelector.LENS_FACING_BACK
    【解决方案3】:
    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 版本

    【讨论】:

    • 没有CameraX.LensFacing.BACK 常量。应该是CameraSelector.LENS_FACING_BACK
    【解决方案4】:

    这是我的做法

    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))
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多