在不中断预览的情况下切换Camera2中的闪光灯



刚开始使用Camera2框架,因为它增加了对相机底层功能的控制。然而,我在快速打开和关闭手电筒时遇到了一些问题。使用旧的相机API,我可以切换闪光灯,同时提供预览通过:

try
{
    android.hardware.Camera.Parameters parameters = c.getParameters();
    if (parameters.getFlashMode().equals(Camera.Parameters.FLASH_MODE_OFF))
    {
        parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
        Log.i("HeartBeatAlgorithm", "LightOn");
    }
    else if (parameters.getFlashMode().equals(Camera.Parameters.FLASH_MODE_TORCH))
    {
        parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
        Log.i("HeartBeatAlgorithm", "LightOff");
    }
    c.setParameters(parameters);
}
catch (Exception exception)
{
    c.release();
    c = null;
}

手电筒会很快打开或关闭,不会有任何明显的中断。然而,对于Camera2,闪光模式似乎是CaptureSession的一个属性,这意味着需要创建一个全新的CaptureSession来更改闪光模式,即:

try
{
    SurfaceTexture texture = mTextureView.getSurfaceTexture();
    assert texture != null;
    texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
    Surface surface = new Surface(texture);
    mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    if (mLightNowOn == true)
    {
        mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
    }
    else
    {
        mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
    }
    mPreviewRequestBuilder.addTarget(surface);
    mPreviewRequest = mPreviewRequestBuilder.build();
    mCameraDevice.createCaptureSession(Arrays.asList(surface), mSessionStateCallback, null);
}
catch (CameraAccessException e)
{
    e.printStackTrace();
}

正如开发人员文档中所提到的,"创建会话是一项昂贵的操作,可能需要数百毫秒,因为它需要配置相机设备的内部管道,并为将图像发送到所需目标分配内存缓冲区。"确实如此,而且我的应用程序在切换闪光灯模式时会出现明显的延迟。

我真的需要能够快速切换闪光灯模式,而不会打断预览太多。有什么办法解决这个问题吗?还是由于新的API管道而不可避免?

并非每次都必须创建全新的捕获会话才能更改闪存模式。相反,您可以在现有的捕获会话上创建重复的预览请求,每次只设置NewRepeating请求,例如:

mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,CaptureRequest.fLASSH_MODE_TORCH);。。。mPreviewRequest=mPreviewRequestBuilder.build();。。。mCaptureSession.setReatingRequest(mPreviewRequest、captureCallBack、backgroundHandler);

您可以多次重复此序列。

这看起来有点古怪,但Ivan的输入对我有效…

如果不明显的话,变量名称看起来像类/接口名称。您必须在外部范围中声明它们。

captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
captureRequest = captureRequestBuilder.build();
cameraCaptureSession.setRepeatingRequest(captureRequest, null, backgroundHandler);
torchButton = findViewById(R.id.button);
torchButton.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
        if(!lightOn) {
            try {
                captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
                captureRequest = captureRequestBuilder.build();
                cameraCaptureSession.setRepeatingRequest(captureRequest, null, backgroundHandler);
                lightOn = true;
            } catch (CameraAccessException e) {}
        }
        else if(lightOn) {
            try {
                captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
                captureRequest = captureRequestBuilder.build();
                cameraCaptureSession.setRepeatingRequest(captureRequest, null, backgroundHandler);
                lightOn = false;
            } catch (CameraAccessException e) {}
        }
    }
});

这样,你可以在关闭手电筒的情况下开始预览,但这可以通过点击按钮来控制。

最新更新