如下内容方便有Camera2基础人查看,如不了解Camera2的人不建议查看。
拍照流程
先执行CaptureRequest.CONTROL_AF_TRIGGER_START锁定AF,然后根据回调不断判断AF状态,伪代码实现如下
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
if (afState == null) {
//--执行拍照`
} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
//--判断AE状态
}
判断AF状态是lock或者unlock之后还需要在进一步判断AE状态是否收敛,然后在执行拍照。AF状态lock或unlock后判断AE状态判断伪代码如下
if (afState == null) {
`//--执行拍照`
} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
//--执行拍照
} else {
//--AE未收敛,主动执行AE_trigger_start
}
}
如果AE未收敛则主动触发一次AE操作执行CONTROL_AE_PRECAPTURE_TRIGGER_START,然后根据Capture回调判断AE状态,伪代码如下:
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
//--锁定AE
}
AE收敛完成,为了确保场景亮度变化自动触发AE,这里需要锁定AE,伪代码如下
final CaptureRequest.Builder captureBuilder;
try {
captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureBuilder.addTarget(mPreviewSurface);
setAutoFlash(captureBuilder);
//--锁定AE
captureBuilder.set(CaptureRequest.CONTROL_AE_LOCK, Boolean.TRUE);
try {
mCaptureSession.setRepeatingRequest(captureBuilder.build(), mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
Log.d("ArMn", "--------STATE_WATTING_LOCK_AE--------Excepture" );
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
//---监听AE LOCK状态
if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_LOCKED) {
//--------执行拍照
}
在AF和AE都满足拍照条件后,执行拍照。如上是拍照中AF和AE状态处理流程,也是确保图片质量的关键点。
现在我们讨论下如何在每次拍照前触发一次闪光灯
在每次拍照前触发闪光灯需要遵循多个条件
- 条件一
AE_MODE需要设置成CONTROL_AE_MODE_ON_ALWAYS_FLASH - 条件二
FLASH_MODE需要设置成FLASH_MODE_SINGLE
完整代码实现如下:
按下拍照按钮
private void takePicture() {
lockFocus();
}
锁AF(如果在锁定AF之前设置了CONTROL_AE_REGIONS,则AF LOCK会触发打闪)
private void lockFocus() {
try {
// This is how to tell the camera to lock focus.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CaptureRequest.CONTROL_AF_TRIGGER_START);
// Tell #mCaptureCallback to wait for the lock.
mState = STATE_WAITING_LOCK;
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
判断AF状态
case STATE_WAITING_LOCK: {
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
Log.d("ArMn", "--------- STATE_WAITING_LOCK-------afState: " + afState);
if (afState == null) {
captureStillPicture();
} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
mState = STATE_PICTURE_TAKEN;
Log.d("ArMn", "--------captureStillPicture--------");
captureStillPicture();
} else {
Log.d("ArMn", "--------runPrecaptureSequence--------");
runPrecaptureSequence();
}
}
break;
}
执行AE打闪(如果AF没有触发打闪,则此处会触发打闪)
private void runPrecaptureSequence() {
try {
final CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
captureBuilder.addTarget(mImageReader.getSurface());
setAutoFlash(captureBuilder);
captureBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
// This is how to tell the camera to trigger.
// Tell #mCaptureCallback to wait for the precapture sequence to be set.
mState = STATE_WAITING_PRECAPTURE;
mCaptureSession.capture(captureBuilder.build(), mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
判断AE打闪状态
case STATE_WAITING_PRECAPTURE: {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
Log.d("ArMn", "--------STATE_WAITING_PRECAPTURE--------aeState: " + aeState);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
mState = STATE_WATTING_LOCK_AE;
}
break;
锁定AE状态
private void lockAe() {
mState = STATE_WAITING_NON_PRECAPTURE;
final CaptureRequest.Builder captureBuilder;
try {
captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureBuilder.addTarget(mPreviewSurface);
setAutoFlash(captureBuilder);
captureBuilder.set(CaptureRequest.CONTROL_AE_LOCK, Boolean.TRUE);
try {
mCaptureSession.setRepeatingRequest(captureBuilder.build(), mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
Log.d("ArMn", "--------STATE_WATTING_LOCK_AE--------Excepture" );
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
判断AE锁定状态
case STATE_WAITING_NON_PRECAPTURE: {
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
Log.d("ArMn", "--------captureStillPicture-- STATE_WAITING_NON_PRECAPTURE ------state: " + aeState);
if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_LOCKED) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
}
break;
}
执行拍照
private void captureStillPicture() {
try {
final Activity activity = getActivity();
if (null == activity || null == mCameraDevice) {
return;
}
// This is the CaptureRequest.Builder that we use to take a picture.
final CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
// Use the same AE and AF modes as the preview.
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
setAutoFlash(captureBuilder);
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
注意: 不要在锁定AE的时候下发CONTROL_AE_PRECAPTURE_TRIGGER,不然会导致闪光灯常亮。 建议每触发一次capture都重新创建一次CapureRequest对象。 如果在触发CONTROL_AE_PRECAPTURE_TRIGGER成功之后不锁定AE,闪光灯会很快关闭。如果执行了锁定AE会在AE状态lock后关闭
Flash常用的如下设置(摘抄高通Camera源码)
private void applyFlash(CaptureRequest.Builder request, String value) {
switch (value) {
case "on":
if (mLongshotActive) {
request.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
request.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
} else {
request.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
request.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
}
break;
case "auto":
if (mLongshotActive) {
// When long shot is active, turn off the flash in auto mode
request.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
request.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
} else {
request.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
request.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
}
break;
case "off":
request.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
request.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
break;
}
}