SnapdragonCamera驍龍相機源碼解析

驍龍相機是高通開發的一個測試系統攝像頭的demo,代碼完善,功能強大。可以配合Camera驅動進行功能聯調。

很多邏輯代碼在CaptureModule.java里。

CaptureModule有8000多行,包羅萬象。

涉及到界面顯示要結合CaptureUI.java? 一起來實現。

CaptureActivity持有了?CaptureModule 和 CaptureUI 。

以上是主要的引用關系。

CameraActivity 中調用了以下代碼

case ModuleSwitcher.CAPTURE_MODULE_INDEX:if(mCaptureModule == null) {mCaptureModule = new CaptureModule();//核心代碼!!!mCaptureModule.init(this, mCameraCaptureModuleRootView);} else {mCaptureModule.reinit();}mCurrentModule = mCaptureModule;mCameraCaptureModuleRootView.setVisibility(View.VISIBLE);Log.e("CameraActity"," setModuleFromIndex =================== CAPTURE_MODULE_INDEX");break;

?CaptureModule 里初始化代碼:

@Overridepublic void init(CameraActivity activity, View parent) {mActivity = activity;mRootView = parent;mSettingsManager = SettingsManager.getInstance();mSettingsManager.createCaptureModule(this);mSettingsManager.registerListener(this);if (mSettingsManager.mIsHasOneCamera) {CURRENT_ID = 0;} else {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 + 2; 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);}

通過以下代碼初始化CaptureUI

 mUI = new CaptureUI(activity, this, parent);mUI.initializeControlByIntent();

介紹一個核心操作來,了解是如何切換拍照模式的。

首先,通過CaptureUI ,來對組件賦予監聽回調。

mFlashButton = (FlashToggleButton) mRootView.findViewById(R.id.flash_button);mModeSelectLayout = (RecyclerView) mRootView.findViewById(R.id.mode_select_layout);mModeSelectLayout.setLayoutManager(new LinearLayoutManager(mActivity,LinearLayoutManager.HORIZONTAL, false));mCameraModeAdapter = new Camera2ModeAdapter(mModule.getCameraModeList());//設置單擊回調 mCameraModeAdapter.setOnItemClickListener(mModule.getModeItemClickListener());mModeSelectLayout.setAdapter(mCameraModeAdapter);mSettingsIcon = (ImageView) mRootView.findViewById(R.id.settings);mSettingsIcon.setImageResource(R.drawable.settings);mSettingsIcon.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {openSettingsMenu();}});

對應CaptureModule的處理。

 public OnItemClickListener getModeItemClickListener() {return new OnItemClickListener() {@Overridepublic int onItemClick(int mode) {if (showLog) Log.e(TAG, "mode >>> " + mode);if (!getCameraModeSwitcherAllowed()) {return -1;}if (mode == CameraMode.VIDEO.ordinal()) {videoCameraId = -1;videoType = VIDEO_DEFAULT;} else {if (mode == CameraMode.MACRO.ordinal() || mode == CameraMode.NIGHT.ordinal()) {videoCameraId = -1;videoType = -1;}}return selectCameraMode(mode);}};}

CaptureModule 核心代碼處理:

public int selectCameraMode(int mode) {if (showLog) Log.e("CaptureModule", "  mode:: ============== " + mode);if (showLog)Log.e("CaptureModule", "  mCurrentSceneMode.mode:: =================== " + mCurrentSceneMode.mode);for (SceneModule sceneModule : mSceneCameraIds) {if (showLog) Log.e(TAG, " secenmode:: >> " + sceneModule.mode);}if (showLog)Log.e("CaptureModule", "  mSceneCameraIds.get(mode).mode:: =================== " + mSceneCameraIds.get(mode).mode);if (showLog) Log.e("CaptureModule", "  videoType:: =================== " + videoType);if (showLog)Log.e("CaptureModule", "  videoCameraId:: =================== " + videoCameraId);showCameraDevice();String value = mSettingsManager.getValue(SettingsManager.KEY_FRONT_REAR_SWITCHER_VALUE);boolean post = false;if (mode == CameraMode.VIDEO.ordinal()) {videoType = VIDEO_DEFAULT;videoCameraId = 0;} else if (mode == CameraMode.MACRO.ordinal()) {if (value != null && value.equals("front")) {post = true;if (!isBackCamera()) {mUI.performCameraSwitchClick();}}} else if (mode == CameraMode.DEFAULT.ordinal()) {videoType = -1;videoCameraId = -1;} else if (mode == CameraMode.NIGHT.ordinal()) {if (value != null && value.equals("front")) {if (!isBackCamera()) {post = true;mUI.performCameraSwitchClick();}}if (showLog)Log.e("xxx", " mPreviewRequestBuilder.length ===========> " + mPreviewRequestBuilder.length);if (showLog)Log.e("xxx", " mPreviewRequestBuilder.length ===========> " + mPreviewRequestBuilder.length);} else if (mode == CameraMode.PRO_MODE.ordinal()) {
//            if (value != null && value.equals("front")) {
//                if (!isBackCamera()) {
//                    post = true;
//                    mUI.performCameraSwitchClick();
//                }
//            }} else if (mode == CameraMode.HFR.ordinal()) {if (value != null && value.equals("front")) {if (!isBackCamera()) {post = true;mUI.performCameraSwitchClick();}}}if (showLog)Log.e("CaptureModule", "  mode2:: ============== " + mode);if (showLog)Log.e("CaptureModule", "  mCurrentSceneMode.mode2 :: =================== " + mCurrentSceneMode.mode);if (showLog)Log.e("CaptureModule", "  mSceneCameraIds.get(mode).mode2 :: =================== " + mSceneCameraIds.get(mode).mode);showCameraDevice();nmode = mode;if (post) {mHandler.postDelayed(new Runnable() {@Overridepublic void run() {selectModle(nmode);}}, 1000);} else {selectModle(mode);}return 1;}

以上經過定制后的代碼。代碼邏輯更加復雜。因為要支持,夜視和微距攝像頭效果。還要支持前攝。

再調用selectModle方法

selectModle(int mode) 
private int selectModle(int mode) {
//        if (!isVideoModel) {
//            if (mCurrentSceneMode.mode == mSceneCameraIds.get(mode).mode) {
//                return -1;
//            }
//        }showCameraDevice();setCameraModeSwitcherAllowed(false);setNextSceneMode(mode);SceneModule nextSceneMode = mSceneCameraIds.get(mode);String value = mSettingsManager.getValue(SettingsManager.KEY_FRONT_REAR_SWITCHER_VALUE);if (showLog)Log.e(TAG, " =============== current Mode is :::  " + mCurrentSceneMode.mode.ordinal());if (value != null && value.equals("front") &&(nextSceneMode.mode == CameraMode.RTB|| nextSceneMode.mode == CameraMode.SAT|| nextSceneMode.mode == CameraMode.PRO_MODE)) {if (showLog)Log.e(TAG, " selectModle begin set value KEY_FRONT_REAR_SWITCHER_VALUE  rear ==========   mode:: " + mode);mSettingsManager.setValue(SettingsManager.KEY_FRONT_REAR_SWITCHER_VALUE, "rear");} else {if (showLog) Log.e(TAG, " restartAll ==========   mode:: " + mode);restartAll();}updateZoomSeekBarVisible();return 1;}

再調用?restartAll方法

 public void restartAll() {showCameraDevice();int nextCameraId = getNextScreneModeId(mNextModeIndex);CURRENT_ID = getMainCameraId();Log.d(TAG, "restart all CURRENT_ID :" + CURRENT_ID + " nextCameraId :" + nextCameraId);if (CURRENT_ID == nextCameraId && mCameraDevice[nextCameraId] != null) {mIsCloseCamera = false;} else {mIsCloseCamera = true;}SceneModule nextSceneModule = mSceneCameraIds.get(mNextModeIndex);if (nextSceneModule.mode == CameraMode.DEFAULT|| nextSceneModule.mode == CameraMode.PRO_MODE|| nextSceneModule.mode == CameraMode.HFR) {mIsCloseCamera = true;}if (mCameraDevice[nextCameraId] == null) {if (showLog) Log.e(TAG, "  mCameraDevice[nextCameraId] is null " + nextCameraId);} else {if (showLog) Log.e(TAG, "  mCameraDevice[nextCameraId] is not null " + nextCameraId);}

在restartAll中執行各種Camera的初始化操作。首先要關閉原來的攝像頭資源,再打開新的攝像頭資源。各種操作都封裝在以下幾個方法。

onPauseBeforeSuper();
if (showLog) Log.e(TAG, " do onPauseBeforeSuper");
onPauseAfterSuper(false);
if (showLog) Log.e(TAG, " do onPauseAfterSuper false");
reinitSceneMode();
if (showLog) Log.e(TAG, " do reinitSceneMode ");
onResumeBeforeSuper(true);
if (showLog) Log.e(TAG, " do onResumeBeforeSuper ");
onResumeAfterSuper(true);
if (showLog) Log.e(TAG, " do onResumeAfterSuper ");
setRefocusLastTaken(false);
if (showLog) Log.e(TAG, " do setRefocusLastTaken ");

打開攝像頭的操作。

onResumeAfterSuper 方法里的
 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);}}

對應Handle的操作

private class MyCameraHandler extends Handler {public MyCameraHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message msg) {int id = msg.arg1;switch (msg.what) {case OPEN_CAMERA:openCamera(id);break;case CANCEL_TOUCH_FOCUS:cancelTouchFocus(id);break;}}}

執行openCamra操作:

private void openCamera(int id) {if (mPaused) {return;}if (showLog) Log.e(TAG, "openCamera  1111 " + 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();if (showLog) Log.d(TAG, "openCamera CameraAccessException  2222" + id);} catch (InterruptedException e) {e.printStackTrace();if (showLog) Log.d(TAG, "openCamera InterruptedException  3333 " + id);} catch (Exception e) {e.printStackTrace();if (showLog) Log.d(TAG, "openCamera Exception  44444 " + id);}if (showLog) Log.d(TAG, "openCamera  end  55555 " + id);}

回調mStateCallback 操作。

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;}showCameraDevice();if (showLog)Log.e(TAG, "mStateCallback  onOpened  ========== id:: " + id);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;if (showLog)Log.e(TAG, "mStateCallback  onOpened  ========== mCamerasOpened:: " + mCamerasOpened);mActivity.runOnUiThread(new Runnable() {@Overridepublic void run() {if (showLog)Log.e(TAG, "mStateCallback  onOpened  ========== mUI.onCameraOpened:: ");mUI.onCameraOpened(mCurrentSceneMode.getCurrentId());if (showLog)Log.e(TAG, "mStateCallback  onOpened  ========== mUI.onCameraOpened:: end ");}});showCameraDevice();createSessions();}}

注意?mCameraDevice[id] = cameraDevice; 和?? mCameraOpened[id] = true;? 有幾個攝像頭就有幾個mCameraDevice。id就是CameraId,一般就是其下標。

同樣會有一個非常重要的函數?createSessions() ,有了 CameraDevice就要創建 CaptureSeesion。

private void createSessions() {if (PersistUtil.isTraceEnable())Trace.beginSection("createSessions");if (mPaused || !mCamerasOpened || mTempHoldVideoInVideoIntent) return;int cameraId = mCurrentSceneMode.getCurrentId();if (showLog)Log.e(TAG, "createSessions : Current SceneMode is ==== " + mCurrentSceneMode.mode);Log.e(TAG, "createSessions : Current cameraId is ===== " + cameraId);showCameraDevice();switch (mCurrentSceneMode.mode) {case VIDEO:case VIDEO_NIGHT:case VIDEO_MACRO:case NIGHT:createSessionForVideo(cameraId);break;case HFR:if (!HFR_RATE.equals("")) {mSettingsManager.setValue(SettingsManager.KEY_VIDEO_HIGH_FRAME_RATE, HFR_RATE);}createSessionForVideo(cameraId);break;default:createSession(cameraId);}if (PersistUtil.isTraceEnable())Trace.endSection();}

對應的會執行2個方法,一個是創建Camera的Session? createSession(cameraId)? 一個是創建Video的Session??createSessionForVideo(cameraId)

createSession()

if (mChosenImageFormat == ImageFormat.YUV_420_888 || mChosenImageFormat == ImageFormat.PRIVATE) {if (mPostProcessor.isZSLEnabled()) {mPreviewRequestBuilder[id].addTarget(mImageReader[id].getSurface());list.add(mPostProcessor.getZSLReprocessImageReader().getSurface());if (mSaveRaw) {mPreviewRequestBuilder[id].addTarget(mRawImageReader[id].getSurface());}mCameraDevice[id].createReprocessableCaptureSession(new InputConfiguration(mImageReader[id].getWidth(),mImageReader[id].getHeight(), mImageReader[id].getImageFormat()), list, captureSessionCallback, mCameraHandler);} else {if (mSettingsManager.isHeifWriterEncoding() && outputConfigurations != null) {mCameraDevice[id].createCaptureSessionByOutputConfigurations(outputConfigurations,captureSessionCallback, mCameraHandler);} else {mCameraDevice[id].createCaptureSession(list, captureSessionCallback, mCameraHandler);}}} else {outputConfigurations = null;if (ApiHelper.isAndroidPOrHigher() && outputConfigurations != null) {Log.i(TAG, "list size:" + list.size());Log.i(TAG, "create session 111 ");createCameraSessionWithSessionConfiguration(id, outputConfigurations,captureSessionCallback, mCameraHandler, mPreviewRequestBuilder[id]);//                        mCameraDevice[id].createCaptureSession(list, captureSessionCallback, mCameraHandler);} else {Log.i(TAG, "create session 222 ");mCameraDevice[id].createCaptureSession(list, captureSessionCallback, mCameraHandler);}

?captureSessionCallback 的操作

CameraCaptureSession.StateCallback captureSessionCallback =new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(CameraCaptureSession cameraCaptureSession) {if (mPaused || null == mCameraDevice[id] ||cameraCaptureSession == null) {return;}Log.i(TAG, "cameracapturesession - onConfigured " + id);setCameraModeSwitcherAllowed(true);// When the session is ready, we start displaying the preview.mCaptureSession[id] = cameraCaptureSession;if (id == getMainCameraId()) {mCurrentSession = cameraCaptureSession;}initializePreviewConfiguration(id);setDisplayOrientation();updateFaceDetection();mFirstPreviewLoaded = false;try {if (isBackCamera() && getCameraMode() == DUAL_MODE) {linkBayerMono(id);mIsLinked = true;}// Finally, we start displaying the camera preview.// for cases where we are in dual mode with mono preview off,// don't set repeating request for monoif (mCaptureSession[id] == null) {return;}
//                                if (id == NIGHT_CAMRA_ID) { //Night模式
//                                    mPreviewRequestBuilder[id].set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
//                                }if (id == MONO_ID && !canStartMonoPreview()&& getCameraMode() == DUAL_MODE) {mCaptureSession[id].capture(mPreviewRequestBuilder[id].build(), mCaptureCallback, mCameraHandler);} else {if (id == NIGHT_CAMRA_ID) { //Night模式mPreviewRequestBuilder[id].set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
//                                        mPreviewRequestBuilder[id].set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);Log.d(TAG, "createSession : mPreviewRequestBuilder FLASH_MODE_TORCH ===== ");}mCaptureSession[id].setRepeatingRequest(mPreviewRequestBuilder[id].build(), mCaptureCallback, mCameraHandler);}if (mIntentMode == INTENT_MODE_STILL_IMAGE_CAMERA &&mIsVoiceTakePhote) {mHandler.sendEmptyMessageDelayed(VOICE_INTERACTION_CAPTURE, 500);}if (isClearSightOn()) {ClearSightImageProcessor.getInstance().onCaptureSessionConfigured(id == BAYER_ID, cameraCaptureSession);} else if (mChosenImageFormat == ImageFormat.PRIVATE && id == getMainCameraId()) {mPostProcessor.onSessionConfigured(mCameraDevice[id], mCaptureSession[id]);}} catch (CameraAccessException e) {e.printStackTrace();} catch (IllegalStateException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();}mCurrentSessionClosed = false;}@Overridepublic void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {if (showLog)Log.e(TAG, "cameracapturesession - onConfigureFailed " + id);setCameraModeSwitcherAllowed(true);if (mActivity.isFinishing()) {return;}
//                            Toast.makeText(mActivity, "Camera Initialization Failed",
//                                    Toast.LENGTH_SHORT).show();}@Overridepublic void onClosed(CameraCaptureSession session) {Log.d(TAG, "cameracapturesession - onClosed");setCameraModeSwitcherAllowed(true);}};

createSessionForVideo()

 if (showLog)Log.e(TAG, "createSessionForVideo   66666666666666 ");if (isHighSpeedRateCapture()) {int optionMode = isSSMEnabled() ? STREAM_CONFIG_SSM : SESSION_HIGH_SPEED;if (showLog)Log.e("TAG", " buildConstrainedCameraSession in ");buildConstrainedCameraSession(mCameraDevice[cameraId], optionMode,surfaces, mSessionListener, mCameraHandler, mVideoRecordRequestBuilder);if (showLog)Log.e(TAG, "createSessionForVideo    77777777777777777");} else {if (showLog)Log.e("TAG", " configureCameraSessionWithParameters in  cameraId :: " + cameraId);configureCameraSessionWithParameters(cameraId, surfaces,mSessionListener, mCameraHandler, mVideoRecordRequestBuilder);if (showLog)Log.e(TAG, "createSessionForVideo    888888888888");}

創建CameraSession和VideoSession的主要區別。

CameraSession 使用了 mVideoRecordRequestBuilder 和  mPreviewRequestBuilder。
VideoSession 使用了 mVideoPreviewSurface 和 mMediaRecorderSurface。

CameraSession 通過拍照操作,來使用ImageReader獲取圖片數據。對應CameraSession有ImageReader實現的地方。

 mCurrentSession.setRepeatingRequest(mVideoRecordRequestBuilder.build(),mCaptureCallback, mCameraHandler);

執行以上操作后,就可以預覽看到的內容了。

對應的,還有關閉Camera的操作。

closeCamera()
/*** Closes the current {@link CameraDevice}.*/private void closeCamera() {Log.d(TAG, "closeCamera ============== begin");closeProcessors();/* no need to set this in the callback and handle asynchronously. This is the samereason as why we release the semaphore here, not in camera close callback functionas we don't have to protect the case where camera open() gets called during cameraclose(). The low level framework/HAL handles the synchronization for open()happens after close() */try {// Close camera starting with AUX firstfor (int i = MAX_NUM_CAM - 1; i >= 0; i--) {if (null != mCameraDevice[i]) {try {if (!mCameraOpenCloseLock.tryAcquire(2000, TimeUnit.MILLISECONDS)) {Log.d(TAG, "Time out waiting to lock camera closing.");
//                            throw new RuntimeException("Time out waiting to lock camera closing");}} catch (Exception e) {mCameraOpenCloseLock.release();e.printStackTrace();}Log.d(TAG, "Closing camera: " + mCameraDevice[i].getId());// session was closed here if intentMode is INTENT_MODE_VIDEOif (mIntentMode != INTENT_MODE_VIDEO) {try {if (isAbortCapturesEnable() && mCaptureSession[i] != null) {mCaptureSession[i].abortCaptures();Log.d(TAG, "Closing camera call abortCaptures ");}if (isSendRequestAfterFlushEnable() && mCaptureSession[i] != null) {Log.v(TAG, "Closing camera call setRepeatingRequest");mCaptureSession[i].setRepeatingRequest(mPreviewRequestBuilder[i].build(),mCaptureCallback, mCameraHandler);}} catch (IllegalStateException | CameraAccessException e) {e.printStackTrace();}}mCameraDevice[i].close();mCameraDevice[i] = null;mCameraOpened[i] = false;mCaptureSession[i] = null;}}mIsLinked = false;if (null != mMediaRecorder) {mMediaRecorder.release();mMediaRecorder = null;}} catch (RuntimeException e) {mCameraOpenCloseLock.release();
//            throw new RuntimeException("Interrupted while trying to lock camera closing.", e);e.printStackTrace();} catch (Exception e) {e.printStackTrace();} finally {mCurrentSessionClosed = true;mCameraOpenCloseLock.release();}Log.d(TAG, "closeCamera ============== end");}
closeImageReader()的操作
private void closeImageReader() {for (int i = MAX_NUM_CAM - 1; i >= 0; i--) {if (null != mImageReader[i]) {mImageReader[i].close();mImageReader[i] = null;}if (null != mRawImageReader[i]) {mRawImageReader[i].close();mRawImageReader[i] = null;}}for (int i = mYUVCount - 1; i >= 0; i--) {if (null != mYUVImageReader[i]) {mYUVImageReader[i].close();mYUVImageReader[i] = null;}}if (null != mVideoSnapshotImageReader) {mVideoSnapshotImageReader.close();mVideoSnapshotImageReader = null;}}

closeProcessors()

private void closeProcessors() {if (mPostProcessor != null) {mPostProcessor.onClose();}if (mFrameProcessor != null) {mFrameProcessor.onClose();}}

closeSessions()

private void closeSessions() {for (int i = MAX_NUM_CAM - 1; i >= 0; i--) {if (null != mCaptureSession[i]) {if (mCamerasOpened) {try {if (mCurrentSession instanceof CameraConstrainedHighSpeedCaptureSession) {List requestList = ((CameraConstrainedHighSpeedCaptureSession)mCurrentSession).createHighSpeedRequestList(mVideoRecordRequestBuilder.build());mCurrentSession.captureBurst(requestList, null, mCameraHandler);} else {mCaptureSession[i].capture(mPreviewRequestBuilder[i].build(), null,mCameraHandler);}} catch (CameraAccessException e) {e.printStackTrace();} catch (IllegalStateException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();}}mCaptureSession[i].close();mCaptureSession[i] = null;}}}

以上是Camera的初始化流程,很復雜。這里單純的是CaptureModule的邏輯。其中還要涉及到

CaptureUI的邏輯交互。

其中主要調用 showRelatedIcons(CaptureModule.CameraMode mode),根據顯示模式顯示不同的界面。

public void showRelatedIcons(CaptureModule.CameraMode mode) {//common settingsmShutterButton.setVisibility(View.VISIBLE);mFrontBackSwitcher.setVisibility(View.VISIBLE);photoVideoSwitcher.setVisibility(View.INVISIBLE);txt_macro_advice.setVisibility(View.INVISIBLE);mMakeupButton.setVisibility(View.INVISIBLE);mSceneModeSwitcher.setVisibility(View.INVISIBLE);//settings for each modeswitch (mode) {case DEFAULT:mFilterModeSwitcher.setVisibility(View.VISIBLE);mSceneModeSwitcher.setVisibility(View.VISIBLE);mVideoButton.setVisibility(View.INVISIBLE);mMuteButton.setVisibility(View.INVISIBLE);mPauseButton.setVisibility(View.INVISIBLE);break;case RTB:case SAT:mFilterModeSwitcher.setVisibility(View.VISIBLE);mSceneModeSwitcher.setVisibility(View.VISIBLE);mVideoButton.setVisibility(View.INVISIBLE);mFlashButton.setVisibility(View.INVISIBLE);mMuteButton.setVisibility(View.INVISIBLE);mPauseButton.setVisibility(View.INVISIBLE);if (!DEV_LEVEL_ALL) {mFrontBackSwitcher.setVisibility(View.INVISIBLE);}break;case VIDEO:case HFR:mFrontBackSwitcher.setVisibility(View.VISIBLE);photoVideoSwitcher.setVisibility(View.INVISIBLE);mVideoButton.setVisibility(View.VISIBLE);mFilterModeSwitcher.setVisibility(View.VISIBLE);if (mModule.isBackCamera()) {mFlashButton.setVisibility(View.INVISIBLE);} else {mFlashButton.setVisibility(View.VISIBLE);}mShutterButton.setVisibility(View.INVISIBLE);break;case PRO_MODE:mFilterModeSwitcher.setVisibility(View.INVISIBLE);mVideoButton.setVisibility(View.INVISIBLE);mFrontBackSwitcher.setVisibility(View.INVISIBLE);mMuteButton.setVisibility(View.INVISIBLE);mPauseButton.setVisibility(View.INVISIBLE);
//                if (mModule.isBackCamera()) {
//                    mFlashButton.setVisibility(View.VISIBLE);
//                } else {mFlashButton.setVisibility(View.INVISIBLE);
//                }break;case MACRO:mFrontBackSwitcher.setVisibility(View.INVISIBLE);photoVideoSwitcher.setVisibility(View.VISIBLE);((RotateImageView) photoVideoSwitcher).setImageResource(R.drawable.video_switch);mVideoButton.setVisibility(View.INVISIBLE);mFilterModeSwitcher.setVisibility(View.INVISIBLE);txt_macro_advice.setVisibility(View.VISIBLE);break;case VIDEO_MACRO:mFrontBackSwitcher.setVisibility(View.INVISIBLE);photoVideoSwitcher.setVisibility(View.VISIBLE);((RotateImageView) photoVideoSwitcher).setImageResource(R.drawable.photo_switch);mVideoButton.setVisibility(View.VISIBLE);mFilterModeSwitcher.setVisibility(View.INVISIBLE);mShutterButton.setVisibility(View.INVISIBLE);txt_macro_advice.setVisibility(View.VISIBLE);break;case VIDEO_NIGHT:mFlashButton.setVisibility(View.VISIBLE);mFrontBackSwitcher.setVisibility(View.INVISIBLE);photoVideoSwitcher.setVisibility(View.VISIBLE);((RotateImageView) photoVideoSwitcher).setImageResource(R.drawable.photo_switch);mFilterModeSwitcher.setVisibility(View.INVISIBLE);mShutterButton.setVisibility(View.INVISIBLE);mVideoButton.setVisibility(View.VISIBLE);break;case NIGHT:mFlashButton.setVisibility(View.INVISIBLE);mFrontBackSwitcher.setVisibility(View.INVISIBLE);photoVideoSwitcher.setVisibility(View.VISIBLE);((RotateImageView) photoVideoSwitcher).setImageResource(R.drawable.video_switch);mVideoButton.setVisibility(View.INVISIBLE);mFilterModeSwitcher.setVisibility(View.INVISIBLE);break;default:break;}String value = mSettingsManager.getValue(SettingsManager.KEY_FRONT_REAR_SWITCHER_VALUE);if (value == null) {mFrontBackSwitcher.setVisibility(View.INVISIBLE);}if (mModule.getVideoType() == CaptureModule.VIDEO_DEFAULT || mModule.getCurrenCameraMode() == CaptureModule.CameraMode.HFR) {photoVideoSwitcher.setVisibility(View.INVISIBLE);if (mModule.getCurrenCameraMode() == CaptureModule.CameraMode.HFR) {if (mModule.isBackCamera()) {mFlashButton.setVisibility(View.VISIBLE);} else {mFlashButton.setVisibility(View.INVISIBLE);}}}if (mModule.mMFNREnable && mModule.getMainCameraId() == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT) {mFilterModeSwitcher.setVisibility(View.INVISIBLE);}}

源碼多讀,多多比較思考和跟蹤代碼的流程。

如何編譯 在SnapdragonCamera工程呢?

執行

source? ./build/envsetup.sh

執行

lunch

選擇正確的配置

在SnapdragonCamera工程下,執行 ,

mm

編譯即可。

執行

adb install -r? ../../../../SnapdragonCamera.apk

安裝即可。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/76335.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/76335.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/76335.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

多線程猜數問題

題目&#xff1a;線程 A 生成隨機數&#xff0c;另外兩個線程來猜數&#xff0c;線程 A 可以告訴猜的結果是大還是小&#xff0c;兩個線程都猜對后&#xff0c;游戲結束&#xff0c;編寫代碼完成。 一、Semaphore 多個線程可以同時操作同一信號量&#xff0c;由此實現線程同步…

seq2seq

理解 transformer 中的 encoder decoder 詳細的 transformer 教程見&#xff1a;【極速版 – 大模型入門到進階】Transformer 文章目錄 &#x1f30a; Encoder: 給一排向量輸出另外一排向量&#x1f30a; Encoder vs. Decoder: multi-head attention vs. masked multi-head at…

Proxmox pct 部署ubuntu

pct 前言 PCT(Proxmox Container Tool)是 PVE 中用于管理 Linux 容器(LXC)的命令行工具。通過 PCT,用戶可以執行各種容器管理任務,例如創建新的容器、啟動和停止容器、更新容器、安裝軟件包、導出和導入容器等。PCT 提供了與 Web 界面相同的功能,但通過命令行進行操作,…

Google Play關鍵字優化:關鍵排名因素與實戰策略

如果您準備發布應用程序或開始專注于關鍵字優化&#xff0c;您可能想知道如何向Google Play上的應用程序添加關鍵字。Google Play上的搜索量和排名與App Store不同&#xff0c;而且被索引排名的關鍵字也不同。在此文中&#xff0c;我們將確定Google Play上的關鍵排名因素&#…

Kafka延遲隊列實現分級重試

技術方案 方案背景 Kafka隊列消息消費處理過程中&#xff0c;發生處理異常&#xff0c;需要實現重試機制&#xff0c;并基于重試次數實現不同延遲時間重試方案。 方案介紹 通過實現Kafka延遲隊列來實現消息重試機制。 目標&#xff1a; 支持所有業務場景的延遲重試支持多…

Maven核心配置文件深度解析:pom.xml完全指南

&#x1f9d1; 博主簡介&#xff1a;CSDN博客專家、全棧領域優質創作者、高級開發工程師、高級信息系統項目管理師、系統架構師&#xff0c;數學與應用數學專業&#xff0c;10年以上多種混合語言開發經驗&#xff0c;從事DICOM醫學影像開發領域多年&#xff0c;熟悉DICOM協議及…

MSTP多域生成樹

協議信息 MSTP 兼容 STP 和 RSTP&#xff0c;既可以快速收斂&#xff0c;又提供了數據轉發的多個冗余路徑&#xff0c;在數據轉發過程中實現 VLAN 數據的負載均衡。 MSTP 可以將一個或多個 VLAN 映射到一個 Instance&#xff08;實例&#xff09;&#xff08;一個或多個 VLAN…

MQTT 服務器(emqx)搭建及使用(一)

一. EMQX 服務器搭建 1.下載EMQX 下載鏈接&#xff1a;Windows | EMQX 文檔 官方手冊 2.下載內容解壓至盤符根目錄 3.進入bin文件夾&#xff0c;在地址欄輸入cmd 4.依次輸入下面命令安裝服務 .\emqx.cmd install .\emqx.cmd console 5.設置自啟動 創建批處理文件&#x…

在Thinkphp中使用JWT 包括JWT是什么,JWT的優勢

首先了解一下什么是JWT JWT 是一種開放標準&#xff08;RFC 7519&#xff09;&#xff0c;用于在各方之間以 JSON 對象形式安全傳輸信息4。其核心特點包括&#xff1a; 結構&#xff1a;由三部分組成&#xff08;Header、Payload、Signature&#xff09;&#xff0c;通過點號…

hackmyvn-casino

arp-scan -l nmap -sS -v 192.168.255.205 目錄掃描 dirsearch -u http://192.168.255.205/ -e * gobuster dir -u http://192.168.255.205 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php -b 301,401,403,404 80端口 隨便注冊一個賬號 玩游戲時的…

圖表配置表增加分析指標字段

在設計報表圖表配置表時&#xff0c;為存儲 同比、環比 這類分析指標&#xff0c;建議通過以下方式定義字段結構和命名&#xff1a; 一、字段設計方案 // 配置表示例結構 interface ChartConfig {id: string; // 唯一標識name: string; // 圖表…

廣州SMT貼片加工廠精密制造工藝解析

內容概要 在電子制造領域&#xff0c;SMT貼片加工技術已成為現代電子產品精密組裝的核心環節。廣州作為華南地區電子產業的重要樞紐&#xff0c;其SMT貼片加工廠通過融合自動化設備與嚴格工藝標準&#xff0c;構建起高效可靠的制造體系。 對于電子產品制造商而言&#xff0c;…

RK3568-適配ov5647攝像頭

硬件原理圖 CAM_GPIO是攝像頭電源控制引腳,連接芯片GPIO4_C2 CAM_LEDON是攝像頭led燈控制引腳,連接芯片GPIO4_C3編寫設備樹 / {ext_cam_clk: external-camera-clock {compatible = "fixed-clock";clock-frequency = <25000000>;clock-output-names = "…

關于 @Autowired 和 @Value 使用 private 字段的警告問題分析與解決方案

問題背景 在使用 Spring 框架進行開發時&#xff0c;我們經常會使用 Autowired 和 Value 注解來進行依賴注入和屬性值注入。然而&#xff0c;當我們將這些注解應用于 private 字段時&#xff0c;IDE&#xff08;如 IntelliJ IDEA&#xff09;可能會顯示警告信息&#xff0c;提…

Flutter 開發環境配置--宇宙級教學!

目錄 一、安裝環境&#xff08;Windows&#xff09;二、Android 創建Flutter項目三、VSCode 搭建環境四、補充 一、安裝環境&#xff08;Windows&#xff09; Flutter SDK 下載 推薦使用中國鏡像站點下載 Flutter SDK&#xff0c;速度更快&#xff1a;中國環境 或者從官網下載…

碰一碰發視頻網頁版本開發的源碼搭建指南

引言 在數字化信息快速傳播的時代&#xff0c;近場通信&#xff08;NFC&#xff09;技術為信息交互帶來了新的便捷方式。通過網頁版本實現碰一碰發視頻功能&#xff0c;能夠讓用戶在瀏覽器環境中輕松實現視頻分享&#xff0c;拓展了視頻傳播的途徑。本文將詳細介紹碰一碰發視頻…

OMNIWeb 數據介紹

網址&#xff1a;SPDF - OMNIWeb Service 注&#xff1a;OMNI并非特定縮寫&#xff0c;僅表示"多樣化"含義。 About the Data All the data to which this interface and its multiple underlying interfaces provide access have in common that they are relevan…

Python學習(二)操作列表

一、列表的遍歷 每個縮進的代碼行都是循環的一部分&#xff0c;且將針對列表中的每個值都執行一次。因此&#xff0c;可對列表中的每個值執行任意次數的操作。 magicians [alice, david, carolina] for magician in magicians:print(magician)注意&#xff1a; 1、遍歷的時…

淺析RAG技術:大語言模型的知識增強之道

淺析RAG技術&#xff1a;大語言模型的知識增強之道 &#x1f3e0; 引言&#xff1a;當生成遇到檢索 在人工智能領域&#xff0c;大型語言模型(LLMs)如GPT-4、Llama3等展現出了驚人的文本生成能力&#xff0c;但它們也面臨著知識滯后、事實性錯誤等挑戰。Retrieval-Augmented …

Linux Vim 編輯器的使用

Vim 編輯器的使用 一、安裝及介紹二、基礎操作三、高級功能四、配置與插件 一、安裝及介紹 Vim是一款強大且高度可定制的文本編輯器&#xff0c;相當于 Windows 中的記事本。具備命令、插入、底行等多種模式。它可通過簡單的鍵盤命令實現高效的文本編輯、查找替換、分屏操作等…