SnapdragonCamera源码分析(二)OpenCamera流程

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

CaptureModule#init():

    @Override
    public 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() {
    
    
            @Override
            public 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 view
        mSurfaceView = (AutoFitSurfaceView) mRootView.findViewById(R.id.mdp_preview_content);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(callback);
        mSurfaceView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
    
    
            @Override
            public 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
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    
    
            Log.v(TAG, "surfaceChanged: width =" + width + ", height = " + height);
        }

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

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
    
    
            Log.v(TAG, "surfaceDestroyed");
            mSurfaceHolder = null;
            if (mDeepZoomModeRect != null) {
    
    
                mDeepZoomModeRect.setVisibility(View.GONE);
            }
            previewUIDestroyed();
        }
    };

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

扫描二维码关注公众号,回复: 12538925 查看本文章
    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():

    @Override
    public void onPreviewUIReady() {
    
    
        updatePreviewSurfaceReadyState(true);

        if (mPaused || mIsRecordingVideo) {
    
    
            return;
        }
    }
    private void
    updatePreviewSurfaceReadyState(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 void
    updatePreviewSurfaceReadyState(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()

    @Override
    public 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 = 60000ms
            mMaxVideoDurationInMs = 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 stop
        if (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());
    }

初始化帧数据处理等:

        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() {
    
    

        @Override
        public 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() {
    
    
                    @Override
                    public void run() {
    
    
                        mUI.onCameraOpened(mCurrentSceneMode.getCurrentId());
                    }
                });
                createSessions();
            }
        }

        @Override
        public 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;
        }

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

        @Override
        public 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:

猜你喜欢

转载自blog.csdn.net/Otaku_627/article/details/113996114