Android Camera原理之openCamera模塊(二)

在上一篇文章《Android Camera原理之openCamera模塊(一)》咱們主要介紹了openCamera的調用流程以及camera模塊涉及到的4個層次之間的調用關係,可是一些細節問題並無闡釋到,本文咱們補充一下細節問題,力求豐滿整個openCamera模塊的知識體系。
《Android Camera模塊解析之拍照》一文中談到了調用openCamera方法:android

manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);

這個manager就是CameraManager實例,openCamera方法上一篇文章已經介紹地比較清楚了,可是第二個參數mStateCallback沒有深刻講解,你們只知道是一個相機狀態的回調,可是這個狀態很重要。這個狀態回調會告知開發者當前的camera處於什麼狀態,在確切得到這個狀態以後,才能進行下一步的操做。例如我打開camera是成功仍是失敗了,若是不知道的話是不能進行下一步的操做的。安全

private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {

        @Override
        public void onOpened(@NonNull CameraDevice cameraDevice) {
            // This method is called when the camera is opened.  We start camera preview here.
            mCameraOpenCloseLock.release();
            mCameraDevice = cameraDevice;
            createCameraPreviewSession();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {
            mCameraOpenCloseLock.release();
            cameraDevice.close();
            mCameraDevice = null;
        }

        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int error) {
            mCameraOpenCloseLock.release();
            cameraDevice.close();
            mCameraDevice = null;
            Activity activity = getActivity();
            if (null != activity) {
                activity.finish();
            }
        }

    };

本文想搞清楚的一點是:Camera狀態是如何回調的?
因爲上一篇openCamera的文章已經談到了詳細的調用流程,這裏不會贅述了。session

1.openCameraDeviceUserAsync中StateCallback

openCamera會調用到openCameraDeviceUserAsync(...)中,固然也會把它的StateCallback參數傳進來,這個參數和獲取到的CameraCharacteristics一塊兒傳入CameraDeviceImpl的構造函數中。app

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

可是傳入cameraService的回調參數卻不是這個回調,看一下代碼:ide

ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
//......
cameraUser = cameraService.connectDevice(callbacks, cameraId,
                            mContext.getOpPackageName(), uid);

這個callbacks是CameraDeviceImpl實例中的參數,那麼這個callbacks和咱們傳入的StateCallback有什麼關係了,仍是要去CameraDeviceImpl看一下。函數

public CameraDeviceImpl(String cameraId, StateCallback callback, Executor executor,
                        CameraCharacteristics characteristics, int appTargetSdkVersion) {
        if (cameraId == null || callback == null || executor == null || characteristics == null) {
            throw new IllegalArgumentException("Null argument given");
        }
        mCameraId = cameraId;
        mDeviceCallback = callback;
        mDeviceExecutor = executor;
        mCharacteristics = characteristics;
        mAppTargetSdkVersion = appTargetSdkVersion;

        final int MAX_TAG_LEN = 23;
        String tag = String.format("CameraDevice-JV-%s", mCameraId);
        if (tag.length() > MAX_TAG_LEN) {
            tag = tag.substring(0, MAX_TAG_LEN);
        }
        TAG = tag;

        Integer partialCount =
                mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
        if (partialCount == null) {
            // 1 means partial result is not supported.
            mTotalPartialCount = 1;
        } else {
            mTotalPartialCount = partialCount;
        }
    }
  • 構造函數中傳入的StateCallback賦給了CameraDeviceImpl中的mDeviceCallback
private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
    public CameraDeviceCallbacks getCallbacks() {
        return mCallbacks;
    }
    public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
    //......
    }
  • CameraDeviceCallbacks繼承ICameraDeviceCallbacks.Stub,而ICameraDeviceCallbacks.Stub是能夠在Binder IPC中傳輸的對象,很顯然這個纔是應用程序與CameraService通訊的回調,在這個回調中的執行方法標識當前的camera的執行狀態

2.CameraDeviceCallbacks回調

ICameraDeviceCallbacks.aidl自動生成的android/hardware/camera2/ICameraDeviceCallbacks.h文件post

class ICameraDeviceCallbacksDefault : public ICameraDeviceCallbacks {
public:
  ::android::IBinder* onAsBinder() override;
  ::android::binder::Status onDeviceError(int32_t errorCode, const ::android::hardware::camera2::impl::CaptureResultExtras& resultExtras) override;
  ::android::binder::Status onDeviceIdle() override;
  ::android::binder::Status onCaptureStarted(const ::android::hardware::camera2::impl::CaptureResultExtras& resultExtras, int64_t timestamp) override;
  ::android::binder::Status onResultReceived(const ::android::hardware::camera2::impl::CameraMetadataNative& result, const ::android::hardware::camera2::impl::CaptureResultExtras& resultExtras, const ::std::vector<::android::hardware::camera2::impl::PhysicalCaptureResultInfo>& physicalCaptureResultInfos) override;
  ::android::binder::Status onPrepared(int32_t streamId) override;
  ::android::binder::Status onRepeatingRequestError(int64_t lastFrameNumber, int32_t repeatingRequestId) override;
  ::android::binder::Status onRequestQueueEmpty() override;

};

這個回調函數是從CameraService中調上來的。下面的回調包含了Camera執行過程當中的各類狀態,執行成功、執行失敗、數據接收成功等等。這兒暫時不展開描述,等後面capture image的時候會詳細闡釋。學習

  • onDeviceError
  • onDeviceIdle
  • onCaptureStarted
  • onResultReceived
  • onPrepared
  • onRepeatingRequestError
  • onRequestQueueEmpty

3.StateCallback回調

StateCallback是openCamera傳入的3個參數中的一個,這是一個標識當前camera鏈接狀態的回調。ui

public static abstract class StateCallback {
        public static final int ERROR_CAMERA_IN_USE = 1;
        public static final int ERROR_MAX_CAMERAS_IN_USE = 2;
        public static final int ERROR_CAMERA_DISABLED = 3;
        public static final int ERROR_CAMERA_DEVICE = 4;
        public static final int ERROR_CAMERA_SERVICE = 5;

        /** @hide */
        @Retention(RetentionPolicy.SOURCE)
        @IntDef(prefix = {"ERROR_"}, value =
            {ERROR_CAMERA_IN_USE,
             ERROR_MAX_CAMERAS_IN_USE,
             ERROR_CAMERA_DISABLED,
             ERROR_CAMERA_DEVICE,
             ERROR_CAMERA_SERVICE })
        public @interface ErrorCode {};
        public abstract void onOpened(@NonNull CameraDevice camera); // Must implement
        public void onClosed(@NonNull CameraDevice camera) {
            // Default empty implementation
        }
        public abstract void onDisconnected(@NonNull CameraDevice camera); // Must implement
        public abstract void onError(@NonNull CameraDevice camera,
                @ErrorCode int error); // Must implement
    }
  • onOpened回調:
    當前camera device已經被打開了,會觸發這個回調。探明camera的狀態是opened了,這是能夠開始createCaptureSession開始使用camera 捕捉圖片或者視頻了。

觸發onOpened回調的地方在setRemoteDevice(...),這個函數在connectDevice(...)鏈接成功以後執行,代表當前的camera device已經鏈接成功了,觸發camera 可以打開的回調。this

public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {
        synchronized(mInterfaceLock) {
            // TODO: Move from decorator to direct binder-mediated exceptions
            // If setRemoteFailure already called, do nothing
            if (mInError) return;

            mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);

            IBinder remoteDeviceBinder = remoteDevice.asBinder();
            // For legacy camera device, remoteDevice is in the same process, and
            // asBinder returns NULL.
            if (remoteDeviceBinder != null) {
                try {
                    remoteDeviceBinder.linkToDeath(this, /*flag*/ 0);
                } catch (RemoteException e) {
                    CameraDeviceImpl.this.mDeviceExecutor.execute(mCallOnDisconnected);

                    throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
                            "The camera device has encountered a serious error");
                }
            }

            mDeviceExecutor.execute(mCallOnOpened);
            mDeviceExecutor.execute(mCallOnUnconfigured);
        }
    }

    private final Runnable mCallOnOpened = new Runnable() {
        @Override
        public void run() {
            StateCallbackKK sessionCallback = null;
            synchronized(mInterfaceLock) {
                if (mRemoteDevice == null) return; // Camera already closed

                sessionCallback = mSessionStateCallback;
            }
            if (sessionCallback != null) {
                sessionCallback.onOpened(CameraDeviceImpl.this);
            }
            mDeviceCallback.onOpened(CameraDeviceImpl.this);
        }
    };

  • onClosed回調:
    camera device已經被關閉,這個回調被觸發。通常是終端開發者closeCamera的時候會釋放當前持有的camera device,這是正常的現象。
public void close() {
        synchronized (mInterfaceLock) {
            if (mClosing.getAndSet(true)) {
                return;
            }

            if (mRemoteDevice != null) {
                mRemoteDevice.disconnect();
                mRemoteDevice.unlinkToDeath(this, /*flags*/0);
            }
            if (mRemoteDevice != null || mInError) {
                mDeviceExecutor.execute(mCallOnClosed);
            }

            mRemoteDevice = null;
        }
    }
    private final Runnable mCallOnClosed = new Runnable() {
        private boolean mClosedOnce = false;

        @Override
        public void run() {
            if (mClosedOnce) {
                throw new AssertionError("Don't post #onClosed more than once");
            }
            StateCallbackKK sessionCallback = null;
            synchronized(mInterfaceLock) {
                sessionCallback = mSessionStateCallback;
            }
            if (sessionCallback != null) {
                sessionCallback.onClosed(CameraDeviceImpl.this);
            }
            mDeviceCallback.onClosed(CameraDeviceImpl.this);
            mClosedOnce = true;
        }
    };
  • onDisconnected回調:
    camera device再也不可用,打開camera device失敗了,通常是由於權限或者安全策略問題致使camera device打不開。一旦鏈接camera device出現ERROR_CAMERA_DISCONNECTED問題了,這是函數就會被回調,表示當前camera device處於斷開的狀態。
  • onError回調:
    調用camera device的時候出現了嚴重的問題。執行CameraService-->connectDevice 出現異常了
} 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 onError 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);
            }

deviceImpl.setRemoteFailure(e);是執行onError回調的函數。

小結

Camera的知識點很是多,咱們從openCamera講起,也是但願從代碼實踐中真正瞭解camera的調用流程,由淺入深的學習camera知識。下面咱們會繼續講解鏈接成功以後,也就是StateCallback-->onOpened回調中camera會如何操做。敬請期待,不足之處,敬請諒解。

相關文章
相關標籤/搜索