一、 app flow , qcom camera
/**
* Initiate a still image capture.
*/
private void takePicture() {
Log.d(TAG, "takePicture");
...
...
if (mUI.getCurrentProMode() == ProMode.MANUAL_MODE) {
captureStillPicture(cameraId);
} else {
if (mLongshotActive) {
parallelLockFocusExposure(cameraId);
} else {
if (mPreviewCaptureResult != null) {
Integer aeState = mPreviewCaptureResult.get(CaptureResult.CONTROL_AE_STATE);
//1.---- is need flash -----
isFlashRequiredInDriver = aeState != null && aeState == CameraMetadata.CONTROL_AE_STATE_FLASH_REQUIRED;
}
lockFocus(cameraId);
}
}
}
}
/**
* Lock the focus as the first step for a still image capture.
*/
private void lockFocus(int id) {
Log.d(TAG, "lockFocus " + id);
try {
......
......
mTakingPicture[id] = true;
//if touch focuing ?
if (mState[id] == STATE_WAITING_TOUCH_FOCUS) {
mCameraHandler.removeMessages(CANCEL_TOUCH_FOCUS, mCameraId[id]);
mState[id] = STATE_WAITING_AF_LOCK;
mLockRequestHashCode[id] = 0;
return;
}
try {
//2. ----- start af ---------------------
CaptureRequest.Builder builder = getRequestBuilder(id);
builder.setTag(id);
addPreviewSurface(builder, null, id);
applySettingsForLockFocus(builder, id);
/**private void applySettingsForLockFocus(CaptureRequest.Builder builder, int id) {
builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
applyAFRegions(builder, id);
applyAERegions(builder, id);
applyCommonSettings(builder, id);
}**/
CaptureRequest request = builder.build();
mLockRequestHashCode[id] = request.hashCode();
mState[id] = STATE_WAITING_AF_LOCK;
mCaptureSession[id].capture(request, mCaptureCallback, mCameraHandler);
} catch (CameraAccessException | IllegalStateException e) {
e.printStackTrace();
}
}
/**
* A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
*/
private CameraCaptureSession.CaptureCallback mCaptureCallback
= new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureProgressed(CameraCaptureSession session,
CaptureRequest request,
CaptureResult partialResult) {
....
}
@Override
public void onCaptureCompleted(CameraCaptureSession session,
CaptureRequest request,
TotalCaptureResult result) {
...
//3. ----- handle af ae -> up code -------
processCaptureResult(result);
...
}
private void processCaptureResult(CaptureResult result) {
int id = (int) result.getRequest().getTag();
.....
updateCaptureStateMachine(id, result);
....
};
private void updateCaptureStateMachine(int id, CaptureResult result) {
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
Log.d(TAG, "updateCaptureStateMachine state:"+ mState[id]
+" camera id: " + id + " afState:" + afState + " aeState:" + aeState);
switch (mState[id]) {
case STATE_PREVIEW: {
break;
}
case STATE_WAITING_AF_LOCK: {
//4. AF_PASSIVE is added for continous auto focus mode
if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED == afState ||
CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED == afState ||
(mLockRequestHashCode[id] == result.getRequest().hashCode() &&
afState == CaptureResult.CONTROL_AF_STATE_INACTIVE)) {
if(id == MONO_ID && getCameraMode() == DUAL_MODE && isBackCamera()) {
// in dual mode, mono AE dictated by bayer AE.
// if not already locked, wait for lock update from bayer
if(aeState == CaptureResult.CONTROL_AE_STATE_LOCKED)
checkAfAeStatesAndCapture(id);
else
mState[id] = STATE_WAITING_AE_LOCK;
} else {
if ((mLockRequestHashCode[id] == result.getRequest().hashCode()) || (mLockRequestHashCode[id] == 0)) {
// CONTROL_AE_STATE can be null on some devices
if(aeState == null || (aeState == CaptureResult
.CONTROL_AE_STATE_CONVERGED) && isFlashOff(id)) {
lockExposure(id);
} else {
//5.---- start Precapture Sequence ---------------
runPrecaptureSequence(id);
}
}
}
} else if (mLockRequestHashCode[id] == result.getRequest().hashCode()){
Log.i(TAG, "AF lock request result received, but not focused");
mLockRequestHashCode[id] = 0;
} else if (mSettingsManager.isFixedFocus(id)) {
// CONTROL_AE_STATE can be null on some devices
if(aeState == null || (aeState == CaptureResult
.CONTROL_AE_STATE_CONVERGED) && isFlashOff(id)) {
lockExposure(id);
} else {
runPrecaptureSequence(id);
}
}
break;
}
case STATE_WAITING_PRECAPTURE: {
// CONTROL_AE_STATE can be null on some devices
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED ||
aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
if ((mPrecaptureRequestHashCode[id] == result.getRequest().hashCode()) || (mPrecaptureRequestHashCode[id] == 0)) {
if (mLongshotActive && isFlashOn(id)) {
//---------------- capture -----------------------------
checkAfAeStatesAndCapture(id);
} else {
//6. ---------- lock exposure -------------------------
lockExposure(id);
}
}
} else if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_INACTIVE) {
// AE Mode is OFF, the AE state is always CONTROL_AE_STATE_INACTIVE
// then begain capture and ignore lock AE.
checkAfAeStatesAndCapture(id);
} else if (mPrecaptureRequestHashCode[id] == result.getRequest().hashCode()) {
Log.i(TAG, "AE trigger request result received, but not converged");
mPrecaptureRequestHashCode[id] = 0;
}
break;
}
case STATE_WAITING_AE_LOCK: {
// CONTROL_AE_STATE can be null on some devices
if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_LOCKED) {
//7. ------- capture -------------
checkAfAeStatesAndCapture(id);
}
break;
}
...
}
}
/**Precapture Sequence
* Run the precapture sequence for capturing a still image. This method should be called when
* we get a response in {@link #mCaptureCallback} from {@link #lockFocus()}.
*/
private void runPrecaptureSequence(int id) {
Log.d(TAG, "runPrecaptureSequence: " + id);
if (!checkSessionAndBuilder(mCaptureSession[id], mPreviewRequestBuilder[id])) {
return;
}
try {
CaptureRequest.Builder builder = getRequestBuilder(id);
builder.setTag(id);
addPreviewSurface(builder, null, id);
//----- apply precapture build -------------------
applySettingsForPrecapture(builder, id);
CaptureRequest request = builder.build();
mPrecaptureRequestHashCode[id] = request.hashCode();
mState[id] = STATE_WAITING_PRECAPTURE;
mCaptureSession[id].capture(request, mCaptureCallback, mCameraHandler);
isFlashRequiredInDriver = false;
} catch (CameraAccessException | IllegalStateException e) {
e.printStackTrace();
}
}
private void applySettingsForPrecapture(CaptureRequest.Builder builder, int id) {
String redeye = mSettingsManager.getValue(SettingsManager.KEY_REDEYE_REDUCTION);
if (redeye != null && redeye.equals("on") && !isFlashRequiredInDriver) {
if (DEBUG)
Log.d(TAG, "Red Eye Reduction is On. " +
"Don't set CONTROL_AE_PRECAPTURE_TRIGGER to Start");
} else {
builder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
}
// For long shot, torch mode is used
if (!mLongshotActive) {
// -------- flash mode -------------------------
applyFlash(builder, id);
/**private void applyFlash(CaptureRequest.Builder request, int id) {
if (mSettingsManager.isFlashSupported(id)) {
String value = mSettingsManager.getValue(mCurrentSceneMode.mode == CameraMode.PRO_MODE ?
SettingsManager.KEY_VIDEO_FLASH_MODE : SettingsManager.KEY_FLASH_MODE);
applySnapshotFlash(request, value);
} else {
request.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
}
}**/
}
applyCommonSettings(builder, id);
}
/**
* Lock the exposure for capture
*/
private void lockExposure(int id) {
if (!checkSessionAndBuilder(mCaptureSession[id], mPreviewRequestBuilder[id])) {
return;
}
Log.d(TAG, "lockExposure: " + id);
try {
applySettingsForLockExposure(mPreviewRequestBuilder[id], id);
/**private void applySettingsForLockExposure(CaptureRequest.Builder builder, int id) {
builder.set(CaptureRequest.CONTROL_AE_LOCK, Boolean.TRUE);
}**/
//change state
mState[id] = STATE_WAITING_AE_LOCK;
mCaptureSession[id].setRepeatingRequest(mPreviewRequestBuilder[id].build(),
mCaptureCallback, mCameraHandler);
} catch (CameraAccessException | IllegalStateException e) {
e.printStackTrace();
}
}
tuning flow
1. 先统计 ae 送给算法
2. 预闪 , 预闪结束后 ae 收敛完成 送给算法
3. 预闪前 ae 和 预闪后 ae 值都有了, 然后给 算法, 算出来 主闪需要打多少光
PS: 为了保护闪光灯不被烧坏, 所以需要 预闪 和 主闪之间的冷却时间