为什么打开闪光灯会改变相机的对焦模式?

Why turning on flash change the focus mode of the camera?

我有 2 个可以通过按钮控制的 AF 焦距和一个用于闪光灯的开关。

为什么if ELSE for flashligh in updatePreview() 会影响对焦模式为auto?当我注释掉该部分时(IF ELSE for flashligh),自动对焦模式和焦距与 btnFocus 配合良好。

如何解决这个问题,同时仍然允许用户打开和关闭手电筒?

    private float focusDistance = 0;
    private int flashSwitch = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textureView = (TextureView)findViewById(R.id.textureView);
        //From Java 1.4 , you can use keyword 'assert' to check expression true or false
        assert textureView != null;
        textureView.setSurfaceTextureListener(textureListener);
        btnFocus = (Button)findViewById(R.id.btnFocus);
        btnFlash = (Button)findViewById(R.id.btnFlash);
        btnFocus.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                changeFocus();
            }
        });
        btnFlash.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                Flash();
            }
        });
    }

    private void Flash() {
        if(cameraDevice == null)
            return;
        if(flashSwitch == 0 ) {
            Toast.makeText(MainActivity.this, "Flash Turn On ", Toast.LENGTH_SHORT).show();
            flashSwitch = 1;
        }
        else{
            Toast.makeText(MainActivity.this, "Flash Turn Off ", Toast.LENGTH_SHORT).show();
            flashSwitch = 0;
        }
        createCameraPreview();
    }


    private void changeFocus() {
        if(cameraDevice == null)
            return;
        if(focusDistance == 0 )
            focusDistance = 10;
        else
            focusDistance = 0;
        Toast.makeText(MainActivity.this, "Focus Change "+ focusDistance, Toast.LENGTH_SHORT).show();
        createCameraPreview();
    }

    private void createCameraPreview() {
        try{
            SurfaceTexture texture = textureView.getSurfaceTexture();
            assert  texture != null;
            texture.setDefaultBufferSize(imageDimension.getWidth(),imageDimension.getHeight());
            Surface surface = new Surface(texture);
            captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            captureRequestBuilder.addTarget(surface);
            cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                    if(cameraDevice == null)
                        return;
                    cameraCaptureSessions = cameraCaptureSession;
                    updatePreview();
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                    Toast.makeText(MainActivity.this, "Changed", Toast.LENGTH_SHORT).show();
                }
            },null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

如果您取消注释部分,问题将在打开闪光灯和更改焦点时出现。

    private void updatePreview() {
        if(cameraDevice == null)
            Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
        try{
//            if you uncomment this part the problem will come out 
//            if(flashSwitch == 0){
//                captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
//            }
//            else{
//                captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
//            }
            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_OFF);
            captureRequestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, focusDistance);
            cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(),null,mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

预期输出

可以在不影响对焦模式的情况下手动打开和关闭闪光灯。

updatePreview() 中,您在 captureRequestBuilder 中解决所有密钥之前向 cameraCaptureSessions 发送了多个捕获请求。尝试先设置所有键,然后发送一个重复的捕获请求。

private void updatePreview() {
        if(cameraDevice == null)
            Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
        try{
            if(flashSwitch == 0){
                captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
            }
            else{
                captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
            }
            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_OFF);
            captureRequestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, focusDistance);

            cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(),null,mBackgroundHandler);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

我认为您的问题可能出在您设置请求的方式上。 您应该首先创建预览,并且只创建一次,按照您的方式,每次切换 flash and/or 焦点时都在创建预览。 我建议使用一些默认设置在 onStart 中创建预览:

focusDistance = 0;
flashSwitch = CaptureRequest.FLASH_MODE_OFF;

然后在 Flash() 和 changeFocus() 中调用 updatePreview() 而不是调用 createCameraPreview(),您的更新预览将如下所示:

private void updatePreview() {
        if(cameraDevice == null)
            Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
        try{
            captureRequestBuilder.set(CaptureRequest.FLASH_MODE, flashSwitch);
            captureRequestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, focusDistance);    
            cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(),null,mBackgroundHandler);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }