Camera2Basic 例程(I)
感觉Android例程不是很友好= =(与AVCam相比缺少一篇完整的文章解释)github地址
截图

拍摄管道(概览)
按下”Picture”之后发生了什么?
首先调用Camera2BasicFragment::onClick(View)方法,这里调用了takePicture()。显然,是要去拍照。
TakePicture()只有一行,调用了lockFocus()。拍摄前,需要锁定对焦。
lockFocus()首先要求对焦锁定:
//CaptureRequest.set(Key<T> key, T value)方法可以设置多个跟capture request相关的参数
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetaData.CONTROL_AF_TRIGGER_START);
自动对焦状态:afMode有以下几个状态:INACTIVE, ACTIVE_SCAN, FOCUSED_LOCKED, NOT_FOCUSED_LOCKED。不管在哪个状态下,只要接受了AF_TRIGGER_START命令,都会进入ACTIVE_SCAN(寻焦状态)。Scan之后的结果必定是FOCUSED_LOCKED或NOT_FOCUSED_LOCKED其中之一,这两个状态都是AFLock状态。
之后,置mState为STATE_WAITING_LOCK。mState是本程序控制CaptureCallback执行块的状态参数。在STATE_WAITING_LOCK状态下,CaptureCallback会检查当前的AF和AE状态,当AF/AE都结束之后调用captureStillPicture()
lockFocus()最后调用CameraCaptureSession.capture()让自动对焦命令生效。
captureStillImage():
- 构建拍摄请求
CaptureRequest,加入图像输出端ImageReader。 - 在相机端设置AE/AF,在输出端设置JPG的旋转。
- 开启自动闪光
- 设置了一个
onCaptureCompleted的回调,并在拍摄结束的最后调用unlockFocus()。 - 最后通过
CaptureSession.capture()让请求生效。
unlockFocus():
- 重置
afMode为INACTIVE - 开启自动闪光
- 重置
mState为STATE_PREVIEW,通过CaptureSession.setRepeatingRequest启动preview
到这一步拍摄流程结束。
CaptureCallback()执行块
上面已经说到mState是Preview和Waiting Lock状态时的动作,其中在Waiting Lock状态时可能会出现AF完成而AE没完成的情况,这时会调用runPrecaptureSequence()方法,mState会进入Waiting Precapture状态。
Precapture方法其实就是进行一次AE。AE算法有这些状态INACTIVE,SEARCHING,CONVERGED,FLASH_REQUIRED,LOCKED,PRECAPTURE。AE序列可以通过相机本身或者用户来启动。用户启动的方法是触发CONTROL_AE_PRECAPTURE_TRIGGER。如果当前状态不是LOCKED,触发之后会进入PRECAPTURE状态,相机会进入PRECAPTURE序列,完成之后会进入CONVERGED或者LOCKED状态。
因此,在Waiting Precapture执行块中,当检测到PRECAPTURE或者是FLASH_REQUIRED状态时,说明此时相机已经启动(过)AE序列,但是还没完成,因此需要继续检测下一个状态,这是将mState设置为Waiting Non PreCapture。
因为AEMode是设置为control_ae_mode_on_auto_flash的,在PreCapture序列里如果光照不足闪光会自动启动。下一个状态可能是:
PRECAPTURE->CONVERGED当然也有可能开了闪光之后场景还是太暗,于是进入FLASH_REQUIRED状态,但这时其实没有办法,只能force progress。于是这里处理的方法是,只要当前CONTROL_AE_STATE_PRECAPTURE状态不是PRECAPTURE就启动拍摄序列。
在`Waiting Non PreCaputure`中,Basic应用用了比较简略的处理方法。理论上,这时AE状态有这些可能性: - `PRECAPTURE` -> `CONVERGED` - `PRECAPTURE` -> `LOCKED` (没有AE_Lock的UI,实际不可能进入这个状态) - `FLASH_REQUIRED` -> `SEARCHING` -> `CONVERGED` - `FLASH_REQUIRED` -> `SEARCHING` -> `LOCKED` (没有AE_Lock的UI,实际不可能进入这个状态) - `FLASH_REQUIRED` -> `SEARCHING` -> `FLASH_REQUIRED` -> ... 但这里是一股脑地只要状态不是`PRECAPTURE`就马上宣布进入拍摄序列。问题主要在`FLASH_REQUIRED`状态中,这里的逻辑允许了在`FLASH_REQUIRED`状态下也进入拍摄序列,可能导致最后的图像结果过暗。