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`状态下也进入拍摄序列,可能导致最后的图像结果过暗。