记录一下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()去通知进行开启预览的操作:
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: