简体   繁体   English

Android Camera2-变得不可用时回调到拦截E / Camera错误(即,用户使用自拍照)

[英]Android Camera2 - Callback to Intercept E/Camera Error When It Becomes Unavailable (i.e. User Takes Selfie)

In my application I am using the Camera2 API to do some processing in the background. 在我的应用程序中,我正在使用Camera2 API在后台进行一些处理。 I am using the well known Camera2Basic (albeit now heavily modified). 我正在使用众所周知的Camera2Basic(尽管现在已进行了大量修改)。 Everything runs great, but there is an obvious issue - when the user requests the camera for something (like launching a camera app to take a photo), my Camera2 quits, please see the LOGCAT: 一切运行良好,但是存在一个明显的问题-当用户向相机请求某些东西(例如启动相机应用以拍照)时,我的Camera2退出了,请参阅LOGCAT:

E/Camera: Error 2
I/RequestThread-1: Flushing all pending requests.
I/RequestQueue: Repeating capture request cancelled.
I/CameraDeviceState: Legacy camera service transitioning to state ERROR
E/RequestQueue: cancel failed: no repeating request exists for request id: 0
E/CameraDeviceState: Cannot receive result while in state: 0
W/CaptureCollector: previewProduced called with no preview request on queue!
W/MessageQueue: Handler (android.os.Handler) {32bb202} sending message to a Handler on a dead thread
                                                                  java.lang.IllegalStateException: Handler (android.os.Handler) {32bb202} sending message to a Handler on a dead thread
                                                                  ... (irrelevant) ...
                                                                      at android.os.Looper.loop(Looper.java:154)
                                                                      at android.os.HandlerThread.run(HandlerThread.java:61)
E/MyApp: disconnected
D/gralloc: gralloc_lock_ycbcr success. format : 11, usage: 3, ycbcr.y: 0x66903000, .cb: 0x66afd401, .cr: 0x66afd400, .ystride: 1920 , .cstride: 1920, .chroma_step: 2
E/BufferItemConsumer: [ImageReader-1920x1080f23m1-19683-0] Failed to release buffer: Unknown error -1 (1)
E/MyApp: closed

Now... in Camera1 API I was able to intercept and act precisely at the moment the E/Camera Error 2 was reported, using this: 现在...在Camera1 API中,我可以在报告E / Camera Error 2时进行拦截并采取以下行动:

mCamera.setErrorCallback(errorCallback);

But in Camera2 API the situation is funny because even though I have configured my StateCallback (please notice the Log.e() correspond to the above LOGCAT output), the onError() doesn't fire at all and onClosed() and onDisconnected() trigger too late (!): 但是在Camera2 API中,这种情况很有趣,因为即使我已经配置了StateCallback(请注意Log.e()对应于上述LOGCAT输出),onError()也不触发,并且onClosed()和onDisconnected( )触发得太晚(!):

private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice cameraDevice) {
        mCameraOpenCloseLock.release();
        mCameraDevice = cameraDevice;
        createCameraPreviewSession();
    }
    @Override
    public void onDisconnected(@NonNull CameraDevice cameraDevice) {
        mCameraOpenCloseLock.release();
        cameraDevice.close();
        mCameraDevice = null;
        Log.e("MyApp", "disconnected");
    }
    @Override
    public void onClosed(@NonNull CameraDevice cameraDevice) {
        super.onClosed(cameraDevice);
        Log.e("MyApp", "closed");
    }

    @Override
    public void onError(@NonNull CameraDevice cameraDevice, int error) {
        Log.e("MyApp", "Here we are "+error);
        mCameraOpenCloseLock.release();
        cameraDevice.close();
        mCameraDevice = null;
    }
};

Why wouldn't onError() trigger in case the camera becomes taken over by a user's request? 如果摄像机被用户的请求接管,为什么onError()不会触发? How can I detect such a condition? 如何检测到这种情况? I think that being able to "tap into" any of the following events would do the trick: 我认为能够“利用”以下任何事件都可以解决问题:

I/CameraDeviceState: Legacy camera service transitioning to state ERROR
E/RequestQueue: cancel failed: no repeating request exists for request id: 0
E/CameraDeviceState: Cannot receive result while in state: 0

Thank you kindly for any feedback. 谢谢您的任何反馈。 M. M.

Okay, so investigating this further I have arrived at a solution. 好的,进一步研究这个问题,我得出了一个解决方案。 The problem is that "Legacy" devices, which natively support Camera 1 API, although they "work" with Camera 2 API, behave differently than "Limited" / "Full" devices that natively support Camera 2 API. 问题是,虽然本机支持Camera 1 API的“旧版”设备“与Camera 2 API一起工作”,但其行为与本机支持Camera 2 API的“有限” /“完全”设备不同。

To detect the type of device you can use this snippet: 要检测设备的类型,可以使用以下代码段:

CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
Integer deviceLevel = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); // 0 - limited, 1 - full, 2 - legacy, 3 - uber full

Now, "Limited" an "Full" devices will behave as expected and upon the camera becoming unavailable, the onDisconnect() event of the StateCallback triggers, so you can react. 现在,“受限”和“完全”设备将按预期方式运行,并且当摄像机不可用时,将触发StateCallback的onDisconnect()事件,因此您可以做出反应。 For "Legacy" devices, at least according to my tests, this happens too late (as per the LOGCAT in the original question). 对于“传统”设备,至少根据我的测试,这种情况为时已晚(根据原始问题中的LOGCAT)。

The solution seems to be to switch between Camera API's depending on the hardware level, and then use the mCamera.setErrorCallback(errorCallback); 解决方案似乎是根据硬件级别在Camera API之间切换,然后使用mCamera.setErrorCallback(errorCallback); to catch the error on Camera 1 API devices. 在Camera 1 API设备上捕获错误。 Like so: 像这样:

CameraErrorCallback errorCallback = new CameraErrorCallback();
@SuppressWarnings("deprecation")
public class CameraErrorCallback implements android.hardware.Camera.ErrorCallback {
    @Override
    public void onError(int error, android.hardware.Camera camera) {
    // Do something.
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM