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

截图

Screenshot

拍摄管道(概览)

按下”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_LOCKEDNOT_FOCUSED_LOCKED其中之一,这两个状态都是AFLock状态。

之后,置mStateSTATE_WAITING_LOCKmState是本程序控制CaptureCallback执行块的状态参数。在STATE_WAITING_LOCK状态下,CaptureCallback会检查当前的AF和AE状态,当AF/AE都结束之后调用captureStillPicture()

lockFocus()最后调用CameraCaptureSession.capture()让自动对焦命令生效。

captureStillImage()

  1. 构建拍摄请求CaptureRequest,加入图像输出端ImageReader
  2. 在相机端设置AE/AF,在输出端设置JPG的旋转。
  3. 开启自动闪光
  4. 设置了一个onCaptureCompleted的回调,并在拍摄结束的最后调用unlockFocus()
  5. 最后通过CaptureSession.capture()让请求生效。

unlockFocus()

  1. 重置afModeINACTIVE
  2. 开启自动闪光
  3. 重置mStateSTATE_PREVIEW,通过CaptureSession.setRepeatingRequest启动preview

到这一步拍摄流程结束。

CaptureCallback()执行块

上面已经说到mState是PreviewWaiting 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就启动拍摄序列。