3

刚刚开始使用 Camera2 框架,因为它提供了对相机低级功能的更多控制。但是,我在快速打开和关闭手电筒时遇到了一些麻烦。使用旧的 Camera 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,似乎 flash 模式是 CaptureSession 的一个属性,这意味着需要创建一个全新的 CaptureSession 来更改 flash 模式,即:

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

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

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

4

2 回答 2

2

每次都必须创建全新的捕获会话来更改 Flash 模式,这不是真的。相反,您可以在现有捕获会话上创建重复预览请求,并且每次只需 setNewRepeating 请求,如下所示:

mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); ... mPreviewRequest = mPreviewRequestBuilder.build(); ... mCaptureSession.setRepeatingRequest(mPreviewRequest, captureCallBack, backgroundHandler);

您可以多次重复此序列。

于 2017-11-16T07:55:19.053 回答
2

这似乎有点骇人听闻,但伊万的意见对我有用......

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

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

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

于 2018-04-17T04:46:38.277 回答