记录一下SnapdragonCamera的相关流程。
从上一篇 SnapdragonCamera源码分析(一)CameraActivity可以知道,桌面点击相机图标实质上启动的是CameraActivity,且根据启动的Intent信息及其使用的CameraAPI2来看,启动后默认相机模式为拍照模式,使用的Module为CaptureModule.java。
CaptureModule在CameraActivity的onCreate()方法内被init():

CaptureModule#init():

    @Overridepublic void init(CameraActivity activity, View parent) {mActivity = activity;mRootView = parent;mSettingsManager = SettingsManager.getInstance();mSettingsManager.createCaptureModule(this);mSettingsManager.registerListener(this);if (isBackCameraId()) {CURRENT_ID = BACK_MODE;} else {CURRENT_ID = FRONT_MODE;}mSettingsManager.init();mFirstPreviewLoaded = false;Log.d(TAG, "init");for (int i = 0; i < MAX_NUM_CAM; i++) {mCameraOpened[i] = false;mTakingPicture[i] = false;}for (int i = 0; i < MAX_NUM_CAM; i++) {mState[i] = STATE_PREVIEW;}SceneModule module;for (int i = 0; i < mSelectableModes.length; i++) {module = new SceneModule();module.mode = CameraMode.values()[i];mSceneCameraIds.add(module);}mPostProcessor = new PostProcessor(mActivity, this);mFrameProcessor = new FrameProcessor(mActivity, this);mContentResolver = mActivity.getContentResolver();initModeByIntent();initCameraIds();mUI = new CaptureUI(activity, this, parent);mUI.initializeControlByIntent();mFocusStateListener = new FocusStateListener(mUI);mLocationManager = new LocationManager(mActivity, this);}

1、初始化mSettingsManager,并注册相关设置项改变监听;顾名思义SettingsManager主要用来管理Camera设置项的管理,包括闪光灯状态、画质等设置项,当设置项改变时通过回调onSettingsChanged()方法处理。
2、判断当前前后摄模式,初始化CURRENT_ID;
3、默认设置所有可用Camera Devices的状态为非打开状态、非拍照状态、处于预览状态。
4、为每一种拍照模式初始化一个SceneModule对象,这个对象主要用于记录管理相应的Camera ID
六大模式:

private String[] mSelectableModes = {"Video", "HFR", "Photo", "Bokeh", "SAT", "ProMode"};
    public enum CameraMode {VIDEO,HFR,DEFAULT,RTB,SAT,PRO_MODE}

5、初始化mPostProcessor、mFrameProcessor,主要处理预览、拍照等由底层返回的帧数据;
6、根据Activity启动的Intent action初始化拍照模式mIntentMode、mQuickCapture等;
7、获取所有可用Camera Device的设备描述信息CameraCharacteristics,根据Camera Devices的设备类型、是否前后摄判断设置之前为每个拍照模式设置的SceneModule对象,并且此时会初始化mCurrentSceneMode为“photo”。
1>通过TAG "org.codeaurora.qcamera3.logicalCameraType.logical_camera_type"来判断设备类型:

    public static CameraCharacteristics.Key<Byte> logical_camera_type =new CameraCharacteristics.Key<>("org.codeaurora.qcamera3.logicalCameraType.logical_camera_type", Byte.class);

2>通过CameraCharacteristics.LENS_FACING判断是否前后摄:

        int facing = characteristics.get(CameraCharacteristics.LENS_FACING);

8、初始化CaptureUI,此主要用于管理当前拍照模式下所有UI方面的控制切换显示;

    public void initializeControlByIntent() {mThumbnail = (ImageView) mRootView.findViewById(R.id.preview_thumb);mThumbnail.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (!CameraControls.isAnimating() && !mModule.isTakingPicture() &&!mModule.isRecordingVideo())mActivity.gotoGallery();}});if (mModule.getCurrentIntentMode() != CaptureModule.INTENT_MODE_NORMAL) {mCameraControls.setIntentMode(mModule.getCurrentIntentMode());}}

初始化缩略图控件,并为其设置点击跳转到相册的事件。
9、初始化mFocusStateListener,用于处理Camera对焦状态,具体用作CaptureUI内:

        mFocusStateListener = new FocusStateListener(mUI);
public class FocusStateListener {private static final String TAG = "SnapCam_FocusStateListe";private CaptureUI mUI;public FocusStateListener(CaptureUI ui) {mUI = ui;}public void onFocusStatusUpdate(int focusState) {switch (focusState) {case CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN:Log.d(TAG, "CONTROL_AF_STATE_ACTIVE_SCAN onFocusStarted");mUI.onFocusStarted();break;case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED:Log.d(TAG, "CONTROL_AF_STATE_FOCUSED_LOCKED onFocusSucceeded");mUI.onFocusSucceeded(false);break;case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:Log.d(TAG, "CONTROL_AF_STATE_NOT_FOCUSED_LOCKED onFocusFailed");mUI.onFocusFailed(false);break;case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED:Log.d(TAG, "CONTROL_AF_STATE_PASSIVE_FOCUSED onFocusSucceeded");mUI.onFocusSucceeded(true);break;case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN:Log.d(TAG, "CONTROL_AF_STATE_PASSIVE_SCAN onFocusStarted");mUI.onFocusStarted();break;case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED:Log.d(TAG, "CONTROL_AF_STATE_PASSIVE_UNFOCUSED onFocusFailed");mUI.onFocusFailed(true);break;case CaptureResult.CONTROL_AF_STATE_INACTIVE:Log.d(TAG, "CONTROL_AF_STATE_INACTIVE clearFocus");mUI.clearFocus();break;}}
}

10、初始化mLocationManager,主要用于处理应用内所有关于定位相关的操作。
即完成mCurrentModule的初始化

CaptureUI()

再来看CaptureUI,由于此方法篇幅较长,通篇进行一些控件初始化设置,挑选对本篇内容的关键比较重要的部分进行记录:

        mSettingsManager = SettingsManager.getInstance();mSettingsManager.registerListener(this);

实例化mSettingsManager,并为其注册设置项改变的监听,实现onSettingsChanged()方法;

        mActivity.getLayoutInflater().inflate(R.layout.capture_module,(ViewGroup) mRootView, true);mPreviewCover = mRootView.findViewById(R.id.preview_cover);// display the viewmSurfaceView = (AutoFitSurfaceView) mRootView.findViewById(R.id.mdp_preview_content);mSurfaceHolder = mSurfaceView.getHolder();mSurfaceHolder.addCallback(callback);mSurfaceView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {@Overridepublic void onLayoutChange(View v, int left, int top, int right,int bottom, int oldLeft, int oldTop, int oldRight,int oldBottom) {int width = right - left;int height = bottom - top;if (mFaceView != null) {mFaceView.onSurfaceTextureSizeChanged(width, height);}if (mT2TFocusRenderer != null) {mT2TFocusRenderer.onSurfaceTextureSizeChanged(width, height);}}});mSurfaceViewMono = (AutoFitSurfaceView) mRootView.findViewById(R.id.mdp_preview_content_mono);mSurfaceViewMono.setZOrderMediaOverlay(true);mSurfaceHolderMono = mSurfaceViewMono.getHolder();mSurfaceHolderMono.addCallback(callbackMono);

初始化预览surfaceView,并为其设置状态回调callback;其中有两个surface,但我们只需要关注mSurfaceView即可:

    private SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {// SurfaceHolder callbacks@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {Log.v(TAG, "surfaceChanged: width =" + width + ", height = " + height);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {Log.v(TAG, "surfaceCreated");mSurfaceHolder = holder;previewUIReady();if(mTrackingFocusRenderer != null && mTrackingFocusRenderer.isVisible()) {mTrackingFocusRenderer.setSurfaceDim(mSurfaceView.getLeft(), mSurfaceView.getTop(), mSurfaceView.getRight(), mSurfaceView.getBottom());}if(mT2TFocusRenderer != null && mT2TFocusRenderer.isShown()) {mT2TFocusRenderer.setSurfaceDim(mSurfaceView.getLeft(), mSurfaceView.getTop(),mSurfaceView.getRight(), mSurfaceView.getBottom());}}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {Log.v(TAG, "surfaceDestroyed");mSurfaceHolder = null;if (mDeepZoomModeRect != null) {mDeepZoomModeRect.setVisibility(View.GONE);}previewUIDestroyed();}};

当SurfaceView成功创建时回调surfaceCreated(),通过调用previewUIReady()去通知进行开启预览的操作:

    private void previewUIReady() {if((mSurfaceHolder != null && mSurfaceHolder.getSurface().isValid())) {mModule.onPreviewUIReady();if ((mIsVideoUI || mModule.getCurrentIntentMode() != CaptureModule.INTENT_MODE_NORMAL)&& mThumbnail != null){mThumbnail.setVisibility(View.INVISIBLE);mThumbnail = null;mActivity.updateThumbnail(mThumbnail);} else if (!mIsVideoUI &&mModule.getCurrentIntentMode() == CaptureModule.INTENT_MODE_NORMAL){if (mThumbnail == null)mThumbnail = (ImageView) mRootView.findViewById(R.id.preview_thumb);mActivity.updateThumbnail(mThumbnail);}}}

当SurfaceView可用时,调用onPreviewUIReady()通知CaptureModule准备开始预览;更新界面缩略图。
CaptureModule#onPreviewUIReady():

    @Overridepublic void onPreviewUIReady() {updatePreviewSurfaceReadyState(true);if (mPaused || mIsRecordingVideo) {return;}}
    private voidupdatePreviewSurfaceReadyState(boolean rdy) {if (rdy != mSurfaceReady) {if (rdy) {Log.i(TAG, "Preview Surface is ready!");mSurfaceReadyLock.release();mSurfaceReady = true;} else {try {Log.i(TAG, "Preview Surface is not ready!");mSurfaceReady = false;mSurfaceReadyLock.acquire();} catch (InterruptedException e) {e.printStackTrace();}}}}

可以看到当SurfaceView创建完成并可用时,会通知CaptureModule释放mSurfaceReadyLock锁,此时表明可以开启预览了。

CaptureModule#onResumeBeforeSuper()

继续运行时,CameraActivity的onResume()方法,通知mCurrentModule继续进行Camera相关动作:

        mCurrentModule.onResumeBeforeSuper();...mCurrentModule.onResumeAfterSuper();

先来看onResumeBeforeSuper():

    public void onResumeBeforeSuper() {// must change cameraId before "mPaused = false;"int facingOfIntentExtras = CameraUtil.getFacingOfIntentExtras(mActivity);if (facingOfIntentExtras != -1) {mCurrentSceneMode.setSwithCameraId(facingOfIntentExtras);}mPaused = false;for (int i = 0; i < MAX_NUM_CAM; i++) {if(mIsCloseCamera) {mCameraOpened[i] = false;}mTakingPicture[i] = false;}for (int i = 0; i < MAX_NUM_CAM; i++) {mState[i] = STATE_PREVIEW;}mLongshotActive = false;if(mIsCloseCamera) {updatePreviewSurfaceReadyState(false);}}

1、第一次进入应用时,默认mCurrentSceneMode会被设置成"photo"模式,设置swithCameraId为FACING_BACK;
2、重置所有可用Camera Devices状态为非打开状态、非拍照状态、处于预览状态。
3、首次进入应用时,申请mSurfaceReadyLock锁等待surfaceView准备好:

        if(mIsCloseCamera) {updatePreviewSurfaceReadyState(false);}
    private voidupdatePreviewSurfaceReadyState(boolean rdy) {if (rdy != mSurfaceReady) {if (rdy) {Log.i(TAG, "Preview Surface is ready!");mSurfaceReadyLock.release();mSurfaceReady = true;} else {try {Log.i(TAG, "Preview Surface is not ready!");mSurfaceReady = false;mSurfaceReadyLock.acquire();} catch (InterruptedException e) {e.printStackTrace();}}}}

上面记录到当CaptureUI中SurfaceView创建完成并可用时,则会重新调用updatePreviewSurfaceReadyState()方法去释放锁。

CaptureModule#onResumeAfterSuper()

    @Overridepublic void onResumeAfterSuper() {onResumeAfterSuper(false);}

此方法篇幅较长,拆解记录:

        reinit();
    public void reinit() {CURRENT_ID = mCurrentSceneMode.getCurrentId();CURRENT_MODE = mCurrentSceneMode.mode;Log.d(TAG, "reinit: CURRENT_ID :" + CURRENT_ID);mSettingsManager.init();}

初始化CURRENT_ID、CURRENT_MODE,即当前需要使用的CameraID、模式等;
SettingsManager初始化操作:

    public void init() {Log.d(TAG, "SettingsManager init" + CaptureModule.CURRENT_ID);final int cameraId = getInitialCameraId();setLocalIdAndInitialize(cameraId);autoTestBroadcast(cameraId);reloadCharacteristics(cameraId);}

1、获取当前使用的CameraID;

    public int getInitialCameraId() {return CaptureModule.CURRENT_ID;}

2、初始化加载布局等:

    private void setLocalIdAndInitialize(int cameraId) {String facing = mPreferences.getGlobal().getString(KEY_FRONT_REAR_SWITCHER_VALUE, "rear");mPreferences.setLocalId(mContext, facing, String.valueOf(CaptureModule.CURRENT_MODE));mCameraId = cameraId;CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());PreferenceInflater inflater = new PreferenceInflater(mContext);mPreferenceGroup =(PreferenceGroup) inflater.inflate(R.xml.capture_preferences);mValuesMap = new HashMap<>();mDependendsOnMap = new HashMap<>();mFilteredKeys = new HashSet<>();try {if (mCharacteristics.size() > 0) {mExtendedHFRSize = mCharacteristics.get(cameraId).get(CaptureModule.hfrFpsTable);}} catch(IllegalArgumentException exception) {exception.printStackTrace();}filterPreferences(cameraId);initDependencyTable();initializeValueMap();filterChromaflashPictureSizeOptions();filterHeifSizeOptions();mVideoEisConfigs = getVideoEisConfigs(cameraId);}

1>为当前的使用Camera创建单独的Preferences管理相关设置项;
2>加载设置菜单布局R.xml.capture_preferences;
3>后续根据当前Camera Device的设备特性来过滤加载显示相关设置项;

回到onResumeAfterSuper()方法:
设置切换前后摄控件不可点击:

        setCameraModeSwitcherAllowed(false);
    public void setCameraModeSwitcherAllowed(boolean allow) {mCameraModeSwitcherAllowed = allow;mUI.updateCameraSwitchEnable(allow);}
    public void updateCameraSwitchEnable(boolean enable) {mActivity.runOnUiThread(new Runnable() {public void run() {if(mFrontBackSwitcher != null) {mFrontBackSwitcher.setEnabled(enable);}}});}

继续进行初始化设置:

        initializeValues();
    private void initializeValues() {initYUVCallbackParam();updatePictureSize();updateVideoSize();updateVideoSnapshotSize();updateTimeLapseSetting();estimateJpegFileSize();updateMaxVideoDuration();mSettingsManager.filterPictureFormatByIntent(mIntentMode);}

1、initYUVCallbackParam(),判断是否需要配置yuv流,初始化mYUVCallback:

    private void initYUVCallbackParam(){if (mCurrentSceneMode.mode == CameraMode.SAT){mYUVCount = 3;} else if(mCurrentSceneMode.mode == CameraMode.RTB){mYUVCount = 2;}Log.i(TAG,"init, callbackenable:" + PersistUtil.getYUVCallbackEnable() + ",mode:" +  mCurrentSceneMode.mode);mYUVCallback = PersistUtil.getYUVCallbackEnable() && (mCurrentSceneMode.mode == CameraMode.SAT || mCurrentSceneMode.mode == CameraMode.RTB);}

获取系统配置的system.prop属性"persist.sys.camera.yuvcallback"判断:

    public static boolean getYUVCallbackEnable() {return PERSIST_YUV_CALLBACK_ENABLE;}
    private static final boolean PERSIST_YUV_CALLBACK_ENABLE =getBoolean("persist.sys.camera.yuvcallback",false);

2、updatePictureSize(),根据设置项的pictureSize、Camera支持的预览size,设置最优mPreviewSize;设置初始化缩略图size mPictureThumbSize:

    private void updatePictureSize() {String pictureSize = mSettingsManager.getValue(SettingsManager.KEY_PICTURE_SIZE);mPictureSize = parsePictureSize(pictureSize);Size[] prevSizes = mSettingsManager.getSupportedOutputSize(getMainCameraId(),SurfaceHolder.class);List<Size> prevSizeList = Arrays.asList(prevSizes);prevSizeList.sort((o1,o2) -> o2.getWidth()*o2.getHeight() - o1.getWidth()*o1.getHeight());mSupportedMaxPreviewSize = prevSizeList.get(0);Size[] picSize = mSettingsManager.getSupportedOutputSize(getMainCameraId(), ImageFormat.JPEG);Size[] highResSizes = mSettingsManager.getHighResolutionOutputSize(getMainCameraId());Size[] allPicSizes = new Size[picSize.length + highResSizes.length];System.arraycopy(picSize, 0, allPicSizes, 0, picSize.length);System.arraycopy(highResSizes, 0, allPicSizes, picSize.length, highResSizes.length);List<Size> allPicSizesList = Arrays.asList(allPicSizes);allPicSizesList.sort((o1,o2) -> o2.getWidth()*o2.getHeight() - o1.getWidth()*o1.getHeight());mSupportedMaxPictureSize = allPicSizesList.get(0);Size[] yuvSizes = mSettingsManager.getSupportedOutputSize(getMainCameraId(), ImageFormat.PRIVATE);List<Size> yuvSizeList = Arrays.asList(yuvSizes);if(DEBUG)Log.i(TAG,"mSupportedMaxPreviewSize:" + mSupportedMaxPreviewSize + ",mSupportedMaxPictureSize:" + mSupportedMaxPictureSize);yuvSizeList.sort((o1,o2) -> o2.getWidth()*o2.getHeight() - o1.getWidth()*o1.getHeight());for (int i = 0; i< mYUVCount; i++) {mYUVsize[i] = yuvSizeList.get(0);}Size[] rawSize = mSettingsManager.getSupportedOutputSize(getMainCameraId(),ImageFormat.RAW10);if (rawSize == null || rawSize.length == 0) {mSupportedRawPictureSize = null;mSaveRaw = false;} else {mSupportedRawPictureSize = rawSize[0];}mPreviewSize = getOptimalPreviewSize(mPictureSize, prevSizes);Size[] thumbSizes = mSettingsManager.getSupportedThumbnailSizes(getMainCameraId());mPictureThumbSize = getOptimalPreviewSize(mPictureSize, thumbSizes); // get largest thumb size}

3、updateVideoSize();根据设置项的videoSize、Camera支持的预览size,设置最优mVideoPreviewSize;

    private void updateVideoSize() {String videoSize = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_QUALITY);if (videoSize == null) return;mVideoSize = parsePictureSize(videoSize);Point videoSize2 = PersistUtil.getCameraVideoSize();if (videoSize2 != null) {mVideoSize = new Size(videoSize2.x, videoSize2.y);}if (DEBUG) {Log.v(TAG, "updateVideoSize mVideoSize = " + mVideoSize + ", videoSize :" + videoSize);}Size[] prevSizes = mSettingsManager.getSupportedOutputSize(getMainCameraId(),MediaRecorder.class);mVideoPreviewSize = getOptimalVideoPreviewSize(mVideoSize, prevSizes);Point previewSize = PersistUtil.getCameraPreviewSize();if (previewSize != null) {mVideoPreviewSize = new Size(previewSize.x, previewSize.y);}Log.d(TAG, "updateVideoPreviewSize final video Preview size = " + mVideoPreviewSize.getWidth()+ ", " + mVideoPreviewSize.getHeight());}

4、updateVideoSnapshotSize();设置录像中拍照的图片size mVideoSnapshotSize及其图片缩略图size mVideoSnapshotThumbSize:

    private void updateVideoSnapshotSize() {mVideoSnapshotSize = mVideoSize;if (!is4kSize(mVideoSize) && (mHighSpeedCaptureRate == 0)) {mVideoSnapshotSize = getMaxPictureSizeLiveshot();}if(mSettingsManager.isLiveshotSizeSameAsVideoSize()){mVideoSnapshotSize = mVideoSize;}String videoSnapshot = PersistUtil.getVideoSnapshotSize();String[] sourceStrArray = videoSnapshot.split("x");if (sourceStrArray != null && sourceStrArray.length >= 2) {int width = Integer.parseInt(sourceStrArray[0]);int height = Integer.parseInt(sourceStrArray[1]);mVideoSnapshotSize = new Size(width, height);}Log.d(TAG, "updateVideoSnapshotSize final video snapShot size = " +mVideoSnapshotSize.getWidth() + ", " + mVideoSnapshotSize.getHeight());Size[] thumbSizes = mSettingsManager.getSupportedThumbnailSizes(getMainCameraId());mVideoSnapshotThumbSize = getOptimalPreviewSize(mVideoSnapshotSize, thumbSizes); // get largest thumb size}

5、updateTimeLapseSetting();初始化延时摄影时间mTimeBetweenTimeLapseFrameCaptureMs,是否延时摄影mCaptureTimeLapse:

    private void updateTimeLapseSetting() {String value = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL);if (value == null) return;int time = Integer.parseInt(value);mTimeBetweenTimeLapseFrameCaptureMs = time;mCaptureTimeLapse = mTimeBetweenTimeLapseFrameCaptureMs != 0;mUI.showTimeLapseUI(mCaptureTimeLapse);}

6、estimateJpegFileSize();预算当前设置画质下,拍摄每张图片所需的存储空间大小:

    private void estimateJpegFileSize() {String quality = mSettingsManager.getValue(SettingsManager.KEY_JPEG_QUALITY);int[] ratios = mActivity.getResources().getIntArray(R.array.jpegquality_compression_ratio);String[] qualities = mActivity.getResources().getStringArray(R.array.pref_camera_jpegquality_entryvalues);int ratio = 0;for (int i = ratios.length - 1; i >= 0; --i) {if (qualities[i].equals(quality)) {ratio = ratios[i];break;}}String pictureSize = mSettingsManager.getValue(SettingsManager.KEY_PICTURE_SIZE);Size size = parsePictureSize(pictureSize);if (ratio == 0) {Log.d(TAG, "mJpegFileSizeEstimation 0");} else {mJpegFileSizeEstimation =  size.getWidth() * size.getHeight() * 3 / ratio;Log.d(TAG, "mJpegFileSizeEstimation " + mJpegFileSizeEstimation);}}

7、updateMaxVideoDuration();初始化当前设置下录像时长mMaxVideoDurationInMs:

    private void updateMaxVideoDuration() {String minutesStr = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_DURATION);int minutes = Integer.parseInt(minutesStr);if (minutes == -1) {// User wants lowest, set 30s */mMaxVideoDurationInMs = 30000;} else {// 1 minute = 60000msmMaxVideoDurationInMs = 60000 * minutes;}}

8、filterPictureFormatByIntent();根据intent action设置的mIntentMode再次过滤一次设置项的显示,默认点击桌面图标的启动应该不用考虑执行此方法:

        mSettingsManager.filterPictureFormatByIntent(mIntentMode);
    public void filterPictureFormatByIntent(int captureMode){ListPreference pictureFormat = mPreferenceGroup.findPreference(KEY_PICTURE_FORMAT);if (pictureFormat != null){if (captureMode != CaptureModule.INTENT_MODE_NORMAL) {String[] formats = mContext.getResources().getStringArray(R.array.pref_camera2_picture_format_entryvalues);List<String> avaliableFormat = new ArrayList<String>();if (formats != null && formats[0] != null){avaliableFormat.add(formats[0]);if (filterUnsupportedOptions(pictureFormat,avaliableFormat)) {mFilteredKeys.add(pictureFormat.getKey());}}}}}

再次设置一次预览size:

        updatePreviewSize();
    private void updatePreviewSize() {int width = mPreviewSize.getWidth();int height = mPreviewSize.getHeight();String makeup = mSettingsManager.getValue(SettingsManager.KEY_MAKEUP);boolean makeupOn = makeup != null && !makeup.equals("0");if (makeupOn) {width = mVideoSize.getWidth();height = mVideoSize.getHeight();}Point previewSize = PersistUtil.getCameraPreviewSize();if (previewSize != null) {width = previewSize.x;height = previewSize.y;}mPreviewSize = new Size(width, height);if (mCurrentSceneMode.mode == CameraMode.VIDEO || mCurrentSceneMode.mode == CameraMode.HFR) {mUI.setPreviewSize(mVideoPreviewSize.getWidth(), mVideoPreviewSize.getHeight());} else if (!mDeepPortraitMode) {mUI.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());}}

并将其设置到CaptureUI内,方便界面UI设置;

初始化mSoundPlayer,便于设置播放拍照、录像提示音:

        // Set up sound playback for shutter button, video record and video stopif (mSoundPlayer == null) {mSoundPlayer = SoundClips.getPlayer(mActivity);}

设置存储路径,手机还是SD Card:

        updateSaveStorageState();
    private void updateSaveStorageState() {Storage.setSaveSDCard(mSettingsManager.getValue(SettingsManager.KEY_CAMERA_SAVEPATH).equals("1"));}

初始化设置屏幕显示方向,mDisplayOrientation:

        setDisplayOrientation();
    private void setDisplayOrientation() {mDisplayRotation = CameraUtil.getDisplayRotation(mActivity);mDisplayOrientation = CameraUtil.getDisplayOrientationForCamera2(mDisplayRotation, getMainCameraId());}

开启子线程,包括Camera操作相关子线程、流数据处理等:

        if (!resumeFromRestartAll) {startBackgroundThread();}
    /*** Starts a background thread and its {@link Handler}.*/private void startBackgroundThread() {mCameraThread = new HandlerThread("CameraBackground");mCameraThread.start();mImageAvailableThread = new HandlerThread("CameraImageAvailable");mImageAvailableThread.start();mCaptureCallbackThread = new HandlerThread("CameraCaptureCallback");mCaptureCallbackThread.start();mMpoSaveThread = new HandlerThread("MpoSaveHandler");mMpoSaveThread.start();mCameraHandler = new MyCameraHandler(mCameraThread.getLooper());mImageAvailableHandler = new Handler(mImageAvailableThread.getLooper());mCaptureCallbackHandler = new Handler(mCaptureCallbackThread.getLooper());mMpoSaveHandler = new MpoSaveHandler(mMpoSaveThread.getLooper());}

初始化帧数据处理、相关ImageReader等:

        openProcessors();

判断是否加载倒计时拍照布局:

        loadSoundPoolResource();
    private void loadSoundPoolResource() {String timer = mSettingsManager.getValue(SettingsManager.KEY_TIMER);int seconds = Integer.parseInt(timer);if (seconds > 0) {mUI.initCountDownView();}}

继续往下看onResumeAfterSuper(),打开Camera:

        if(mIsCloseCamera) {Message msg = Message.obtain();msg.what = OPEN_CAMERA;msg.arg1 = mCurrentSceneMode.getCurrentId();Log.d(TAG, "open is " + msg.arg1);if (mCameraHandler != null) {mCameraHandler.sendMessage(msg);}}

默认mIsCloseCamera为true,发送OPEN_CAMERA message到“CameraBackground”子线程内去开启摄像头;

                case OPEN_CAMERA:openCamera(id);break;
    private void openCamera(int id) {if (mPaused) {return;}Log.d(TAG, "openCamera " + id);CameraManager manager;try {manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);mCameraId[id] = manager.getCameraIdList()[id];if (!mCameraOpenCloseLock.tryAcquire(5000, TimeUnit.MILLISECONDS)) {Log.d(TAG, "Time out waiting to lock camera opening.");throw new RuntimeException("Time out waiting to lock camera opening");}manager.openCamera(mCameraId[id], mStateCallback, mCameraHandler);} catch (CameraAccessException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}

1、CameraActivity处于onPause()时不处理open camera的操作;
2、申请mCameraOpenCloseLock锁,设置超时时间为5s,主要用来确保执行closeCamera操作必须是在收到openCamera事件回调之后,确保时序。如果超过5s未收到底层openCamera的事件回调,抛出超时异常:

    /*** A {@link Semaphore} make sure the camera open callback happens first before closing the* camera.*/private Semaphore mCameraOpenCloseLock = new Semaphore(1);

3、使用系统服务CameraManager接口申请openCamera,id及为所需要打开的Camera Devices的id,设置相关Camera状态回调mStateCallback,主要执行在“CameraBackground”子线程内。

继续来看CameraDevice的状态回调CameraDevice.StateCallback:

    private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {@Overridepublic void onOpened(CameraDevice cameraDevice) {int id = Integer.parseInt(cameraDevice.getId());Log.d(TAG, "onOpened " + id);mCameraOpenCloseLock.release();if (mPaused) {return;}mCameraDevice[id] = cameraDevice;mCameraOpened[id] = true;if (isBackCamera() && getCameraMode() == DUAL_MODE && id == BAYER_ID) {Message msg = mCameraHandler.obtainMessage(OPEN_CAMERA, MONO_ID, 0);mCameraHandler.sendMessage(msg);} else {mCamerasOpened = true;mActivity.runOnUiThread(new Runnable() {@Overridepublic void run() {mUI.onCameraOpened(mCurrentSceneMode.getCurrentId());}});createSessions();}}@Overridepublic void onDisconnected(CameraDevice cameraDevice) {int id = Integer.parseInt(cameraDevice.getId());Log.d(TAG, "onDisconnected " + id);cameraDevice.close();mCameraDevice[id] = null;mCameraOpenCloseLock.release();mCamerasOpened = false;mIsCloseCamera = true;}@Overridepublic void onError(CameraDevice cameraDevice, int error) {int id = Integer.parseInt(cameraDevice.getId());Log.e(TAG, "onError " + id + " " + error);mCameraOpenCloseLock.release();mCamerasOpened = false;if (null != mActivity) {Toast.makeText(mActivity,"open camera error id =" + id,Toast.LENGTH_LONG).show();mActivity.finish();}}@Overridepublic void onClosed(CameraDevice cameraDevice) {int id = Integer.parseInt(cameraDevice.getId());Log.d(TAG, "onClosed " + id);mCameraDevice[id] = null;mCameraOpenCloseLock.release();mCamerasOpened = false;mIsCloseCamera = true;}};

1、当申请打开的Camera Device被成功打开时,回调onOpened();
1>释放mCameraOpenCloseLock锁,
2>初始化mCameraDevice[id]、mCameraOpened[id]开关状态;
3>如果当前处于后摄双摄美颜模式,再次发送OPEN_CAMERA Msg消息再去申请打开MONO_ID摄像头;
4>其他情况下,则初始化mCamerasOpened;调用CaprureUI的onCameraOpened方法更新界面;创建Camera会话操作的Session。

2、当CameraDevice与底层CameraService断开链接时,回调onDisconnected();断开cameraDevice,释放mCameraOpenCloseLock锁。

3、当open camera失败或者底层出现异常时,回调onError();重置状态,释放mCameraOpenCloseLock锁。

4、当相机关闭时,回调onClosed();重置状态,释放mCameraOpenCloseLock锁。

从上可以看到,只要接收到Camera Device的状态回调就会释放mCameraOpenCloseLock锁。开启成功后就会创建Session:

SnapdragonCamera源码分析(二)OpenCamera流程相关推荐

  1. SnapdragonCamera源码分析

    SnapdragonCamera源码分析 原文:https://blog.csdn.net/qingsheng33/article/details/84401223 SnapdragonCamera是 ...

  2. 【投屏】Scrcpy源码分析二(Client篇-连接阶段)

    Scrcpy源码分析系列 [投屏]Scrcpy源码分析一(编译篇) [投屏]Scrcpy源码分析二(Client篇-连接阶段) [投屏]Scrcpy源码分析三(Client篇-投屏阶段) [投屏]Sc ...

  3. ENS最新合约源码分析二

    ENS(以太坊域名服务)智能合约源码分析二 0.简介 ​ 本次分享直接使用线上实际注册流程来分析最新注册以太坊域名的相关代码.本次主要分析最新的关于普通域名注册合约和普通域名迁移合约,短域名竞拍合约不 ...

  4. 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 二 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  5. SpringBoot源码分析(二)之自动装配demo

    SpringBoot源码分析(二)之自动装配demo 文章目录 SpringBoot源码分析(二)之自动装配demo 前言 一.创建RedissonTemplate的Maven服务 二.创建测试服务 ...

  6. gSOAP 源码分析(二)

    gSOAP 源码分析(二) 2012-5-24 flyfish 一 gSOAP XML介绍 Xml的全称是EXtensible Markup Language.可扩展标记语言.仅仅是一个纯文本.适合用 ...

  7. Android Q 10.1 KeyMaster源码分析(二) - 各家方案的实现

    写在之前 这两篇文章是我2021年3月初看KeyMaster的笔记,本来打算等分析完KeyMaster和KeyStore以后再一起做成一系列贴出来,后来KeyStore的分析中断了,这一系列的文章就变 ...

  8. openxr runtime Monado 源码解析 源码分析:CreateInstance流程(设备系统和合成器系统)Compositor comp_main client compositor

    monado系列文章索引汇总: openxr runtime Monado 源码解析 源码分析:源码编译 准备工作说明 hello_xr解读 openxr runtime Monado 源码解析 源码 ...

  9. Nouveau源码分析(二):Nouveau结构体的基本框架

    Nouveau源码分析(二) 在讨论Nouveau对Nvidia设备的初始化前,我准备先说一下Nouveau结构体的基本框架 Nouveau的很多结构体都可以看作是C++中的类,之间有很多相似的东西, ...

最新文章

  1. 完全基于Transformer的目标检测器,ICLR匿名论文实现视觉、检测统一
  2. python输出文本-python;如何将输出写入文本文件
  3. Asp.net PageBase学习总结
  4. Java的三大结构理解
  5. python database ioerror_python – IOError:[Errno 2]没有这样的文件或...
  6. 数据库开发设计规范及表结构设计原则
  7. golang-context
  8. python 没有控件_PyQt自定义控件未显示
  9. Mysql8.0 15安装后怎么打开_mysql-8.0.15-winx64 解压版安装 图文详解
  10. AT:配置/禁用PSM模式和设置T3324/T3412
  11. curl返回常见错误码
  12. crf的实现 keras_keras 解决加载lstm+crf模型出错的问题
  13. 安踏2019上半年收益突破148亿元劲增超40%
  14. Google预训练语言模型T5
  15. 动态数据可视化图表制作
  16. 恶意软件隐身术:把可执行文件隐藏在注册表里
  17. 黄金票据的制作与使用
  18. 如何搭建nginx服务器?
  19. html5 摇骰子游戏,html5摇骰子游戏
  20. Think in automotive Ethernet Topology

热门文章

  1. 01 What Adaptive AUTOSAR?
  2. 【光学】基于matlab GUI菲涅尔系数计算【含Matlab源码 1165期】
  3. centos7使用命令行查看开机启动项和服务启动状态
  4. 设计模式系列之--忘备录模式
  5. Label Smoothing介绍及其代码实现
  6. 稳定状态模型 (一): 微分方程稳定性理论简介
  7. 2022-2028全球及中国先进和超高强度钢行业研究及十四五规划分析报告
  8. Android 报错处理:xxx is translated here but not found in default locale
  9. java osgi 模块热插拔_osgi记录
  10. 大模型 LLM 综述, A Survey of Large Language Models