Camera: MTK OpenCamera

        基于MTK Camera框架进行了App -> FrameWork -> CameraService的时序流程的整理,本篇对其中的一些细节进行一下梳理和重点突出。

1.MTK Open Camer时序图

Camera: MTK OpenCamera

 2.应用层OpenCamera需要check的点

        从应用层角度来讲,openCamera层层递进、下发的流程还是比较清晰的;应用层需要特别关注的是openCamera结束后,底层传给应用层的状态,去check Camera是否open成功。Camera2DeviceImpl传给FrameWork层的第二个参数mStateCallback,就可以用来接收底层的open回调状态。

private final StateCallback mStateCallback = new StateCallback() {
                @Override
                public void onOpened(CameraDevice camera) {
                    LogHelper.i(mRespondTag, "[onOpened] camera = " + camera);
                    mRetryCount = 0;
                    createHandlerAndProxy(camera);
                    notifyStateCallback();
                }

                @Override
                public void onClosed(CameraDevice camera) {
                    super.onClosed(camera);
                    if (mCameraDevice != null && mCameraDevice == camera) {
                        LogHelper.d(mRespondTag, "[onClosed] camera = " + camera);
                        mOpenStateCallback.onClosed(mCamera2Proxy);
                        mCameraDevice = null;
                        mCamera2Proxy = null;
                    }
                }

                @Override
                public void one rror(CameraDevice camera, final int error) {
                    LogHelper.e(mRespondTag, "[onError] camera = " + camera + " error = " + error);
                    notifyStateCallback();
                    mOpenStateCallback.onError(mCamera2Proxy, error);
                    if (mRequestHandler != null) {
                        mRequestHandler.closeCamera();
                    }
                    if (mCameraDevice != null) {
                        mCameraDevice.close();
                    }
                    mCameraDevice = null;
                    mCamera2Proxy = null;
                }

                @Override
                public void onDisconnected(CameraDevice camera) {
                    LogHelper.d(mRespondTag, "[onDisconnected] camera = " + camera);
                    if (mCameraDevice != null && mCameraDevice == camera) {
                        mOpenStateCallback.onDisconnected(mCamera2Proxy);
                        mCameraDevice = null;
                        mCamera2Proxy = null;
                    }

                }
            };
private void createHandlerAndProxy(CameraDevice camera) {
                if (camera != mCameraDevice) {
                    mCameraDevice = camera;
                    mThreadLock.lock();
                    mRequestHandler = new Camera2Handler(mCameraId, mRequestThread.getLooper(),
                            mRespondHandler, camera, mDeviceInfoListener);
                    mThreadLock.unlock();

                    //根据FrameWork层传上来的CameraDevice初始化应用层的代理Camera2Proxy
                    mCamera2Proxy = new Camera2Proxy(
                            mCameraId, camera, mRequestHandler, mRespondHandler);
                    mRequestHandler.updateCamera2Proxy(mCamera2Proxy);
                }
            }

        另外在应用层Device2Controller里面继承了Camera2Proxy.StateCallback,用于进行各个模块拿到需要的信息之后的管理。

public class DeviceStateCallback extends Camera2Proxy.StateCallback {

        @Override
        public void onOpened(@Nonnull Camera2Proxy camera2proxy) {
            mModeHandler.obtainMessage(MSG_DEVICE_ON_CAMERA_OPENED,
                    camera2proxy).sendToTarget();
        }

        @Override
        public void onClosed(@Nonnull Camera2Proxy camera2Proxy) {
            mModeHandler.obtainMessage(MSG_DEVICE_ON_CAMERA_CLOSED,
                    camera2Proxy).sendToTarget();
        }

        @Override
        public void onDisconnected(@Nonnull Camera2Proxy camera2proxy) {
            mModeHandler.obtainMessage(MSG_DEVICE_ON_CAMERA_DISCONNECTED,
                    camera2proxy).sendToTarget();
        }

        @Override
        public void one rror(@Nonnull Camera2Proxy camera2Proxy, int error) {
            mModeHandler.obtainMessage(MSG_DEVICE_ON_CAMERA_ERROR, error, 0,
                    camera2Proxy).sendToTarget();
        }

    }
private class ModeHandler extends Handler {

        public ModeHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_DEVICE_ON_CAMERA_OPENED:
                    //对应调用到各个Mode拿到open 成功的回调信息之后的处理
                    doCameraOpened((Camera2Proxy) msg.obj);
                    break;

                case MSG_DEVICE_ON_CAMERA_CLOSED:
                    doCameraClosed((Camera2Proxy) msg.obj);
                    break;

                case MSG_DEVICE_ON_CAMERA_DISCONNECTED:
                    doCameraDisconnected((Camera2Proxy) msg.obj);
                    break;

                case MSG_DEVICE_ON_CAMERA_ERROR:
                    doCameraError((Camera2Proxy) msg.obj, msg.arg1);
                    break;

                default:
                    break;
            }
        }
    }

         下面以Photo模块为例,分析一下拿到camera open成功的回调之后应用层会做些什么样的处理。

@Override
    public void doCameraOpened(@Nonnull Camera2Proxy camera2proxy) {
            try {
                if (CameraState.CAMERA_OPENING == getCameraState()
                        && camera2proxy != null && camera2proxy.getId().equals(mCurrentCameraId)) {
                    mCamera2Proxy = camera2proxy;
                    mFirstFrameArrived = false;

                    if (mModeDeviceCallback != null) {
                        mModeDeviceCallback.onCameraOpened(mCurrentCameraId);
                    }

                    //更新相关的标志位为打开Camera成功
                    updateCameraState(CameraState.CAMERA_OPENED);
                    //更新拍照按钮为可拍照状态
                    updateShutterState(true);
                
//更新setting里面的参数属性                   mSettingDevice2Configurator.setCameraCharacteristics(mCameraCharacteristics);
                   
           
                    //更新预览size
                    updatePreviewSize();
                    //更新拍照size
                    updatePictureSize();
                    
                    if (mPreviewSizeCallback != null) {
                        mPreviewSizeCallback.onPreviewSizeReady(new Size(mPreviewWidth,
                                mPreviewHeight));
                    }
                    if (mNeedSubSectionInitSetting) {
                        //创建Session通道
                        configureSession(true);
                    } else {
                        mSettingController.addViewEntry();
                        mSettingController.refreshViewEntry();
                    }
                }
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
    }

3.FrameWork层OpenCamera需要check的点

        FrameWork层用于接收HAL层CameraDeviceClient的接口为ICameraDeviceUser,而FrameWork层返回给应用层的接口为CameraDevice,而应用层用Camera2Proxy来接收。

        另外需要注意的是CameraManager里面的三方Camera apk,如Whatsapp、google Lens等走的openCamera的流程是一样的,通过cameraService.connectDevice后俩个参数mContext.getOpPackageName()和uid来进行区分处理。

private CameraDevice openCameraDeviceUserAsync(String cameraId,
            CameraDevice.StateCallback callback, Executor executor, final int uid)
            throws CameraAccessException {
        CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
        CameraDevice device = null;

        synchronized (mLock) {

            ICameraDeviceUser cameraUser = null;

            android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
                    new android.hardware.camera2.impl.CameraDeviceImpl(
                        cameraId,
                        callback,
                        executor,
                        characteristics,
                        mContext.getApplicationInfo().targetSdkVersion);

            ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();

            try {
                    // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
                    ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
                    if (cameraService == null) {
                        throw new ServiceSpecificException(
                            ICameraService.ERROR_DISCONNECTED,
                            "Camera service is currently unavailable");
                    }

                    //FrameWork层用于接收HAL层CameraDevice的接口
                    cameraUser = cameraService.connectDevice(callbacks, cameraId,
                            mContext.getOpPackageName(), uid);

            } catch (ServiceSpecificException e) {
                if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
                    throw new AssertionError("Should've gone down the shim path");
                } else if (e.errorCode == ICameraService.ERROR_CAMERA_IN_USE ||
                        e.errorCode == ICameraService.ERROR_MAX_CAMERAS_IN_USE ||
                        e.errorCode == ICameraService.ERROR_DISABLED ||
                        e.errorCode == ICameraService.ERROR_DISCONNECTED ||
                        e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {
                    // Received one of the known connection errors
                    // The remote camera device cannot be connected to, so
                    // set the local camera to the startup error state
                    deviceImpl.setRemoteFailure(e);

                    if (e.errorCode == ICameraService.ERROR_DISABLED ||
                            e.errorCode == ICameraService.ERROR_DISCONNECTED ||
                            e.errorCode == ICameraService.ERROR_CAMERA_IN_USE) {
                        // Per API docs, these failures call one rror and throw
                        throwAsPublicException(e);
                    }
                } else {
                    // Unexpected failure - rethrow
                    throwAsPublicException(e);
                }
            } catch (RemoteException e) {
                // Camera service died - act as if it's a CAMERA_DISCONNECTED case
                ServiceSpecificException sse = new ServiceSpecificException(
                    ICameraService.ERROR_DISCONNECTED,
                    "Camera service is currently unavailable");
                deviceImpl.setRemoteFailure(sse);
                throwAsPublicException(sse);
            }

            // TODO: factor out callback to be non-nested, then move setter to constructor
            // For now, calling setRemoteDevice will fire initial
            // onOpened/onUnconfigured callbacks.
            // This function call may post onDisconnected and throw CAMERA_DISCONNECTED if
            // cameraUser dies during setup.

            //将HAL层的返回与CameraDeviceImpl绑定起来,FrameWork层返回到应用层的接口为CameraDeviceImpl
            deviceImpl.setRemoteDevice(cameraUser);
            device = deviceImpl;
        }

        return device;
    }

小结:

        openCamera的流程看起来算是简单的,但是相机的应用场景却很复杂,很多模式切换需不需要closeCamera再openCamera等之类的问题在实际项目中是问题很多的。更重要的是需要配合Session流等一系列的操作,很可能open成功,因为一些其他原因又让你失败了,属实头疼。

上一篇:高通平台Camera调试移植入门


下一篇:使用ROS和AprilTags进行相机定位