在Android中,Camera2 API提供了对相机硬件的底层访问,包括对焦功能。以下是Camera2对焦原理和框架的简要概述,以及代码实现流程:
对焦原理和框架:
预览: 在开始对焦之前,通常需要先启动相机的预览。预览不仅允许用户看到实时视频流,还可以提供关于相机状态的信息,如对焦模式和当前的对焦区域。
对焦模式: Android支持多种对焦模式,如连续自动对焦(AF-C)、单次自动对焦(AF-S)和手动对焦。每种模式都有不同的应用场景和行为。
对焦区域: 相机可以设置多个对焦区域,每个区域可以独立地对焦。这允许用户选择特定的焦点或自动选择焦点。
触发对焦: 通过API可以手动触发对焦操作,也可以让系统自动触发。一旦触发对焦,相机会尝试调整镜头焦距以实现对焦。
对焦回调: 当对焦完成或发生变化时,系统会发出回调通知。应用程序可以监听这些回调,以便在需要时更新UI或执行其他任务。
代码实现流程:
打开相机: 使用CameraManager获取相机的列表,并选择一个相机打开。
设置预览: 创建一个Surface,用于接收相机的预览输出。将这个Surface与相机预览会话关联起来。
配置相机参数: 通过CameraCharacteristics获取相机的详细信息,并配置必要的参数,如对焦模式和区域。
触发对焦: 使用Camera2 API的方法来触发对焦操作。这通常涉及调用takePicture或startAutofocus方法。
处理回调: 注册一个回调来监听对焦事件。当对焦完成或失败时,可以在这个回调中处理后续逻辑,例如重新触发对焦或显示对焦结果给用户。
清理资源: 在不再需要相机时,确保释放资源并关闭相机连接。
请注意,Camera2 API是一个相对高级的API,需要对Android系统和相机硬件有深入的了解才能有效地使用。此外,由于Android设备众多,不同设备的Camera2实现可能会有所不同。因此,在开发过程中可能需要进行一些特定设备的适配工作。
在Android中,使用原生Camera2 API实现对焦功能需要遵循一系列步骤。下面是一个简化的代码实现过程:
// 导入必要的Camera2 API类
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
// 获取CameraManager实例
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
// 获取相机列表和默认相机ID
String cameraId = manager.getCameraIdList()[0]; // 假设使用默认相机
// 打开相机并获取CameraCharacteristics
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
// 创建CaptureRequest.Builder
CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
// 设置对焦模式和区域(根据需要配置)
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
captureBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, regions); // regions是定义的对焦区域
// 开始预览并触发对焦
try {
cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
try {
session.setRepeatingRequest(captureBuilder.build(), null, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
// 处理配置失败的情况
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
这段代码提供了一个基本的框架,用于打开相机、设置预览、配置对焦模式和区域,并开始预览和触发对焦。请注意,这是一个简化的示例,实际应用中可能需要处理更多的异常情况、权限请求,以及根据具体需求进行更详细的配置。
现在继续分析原生Camera2对焦代码的实现过程:
首先,在packages\apps\Camera2\src\com\android\camera\one\v2\common\BasicCameraFactory.java文件中构建BasicCameraFactory时会创建初始化自动对焦:
ManualAutoFocusFactory manualAutoFocusFactory = ManualAutoFocusFactory.create(new
Lifetime(lifetime), frameServer, cameraCommandExecutor, cropRegion,
sensorOrientation, mPreviewUpdater, requestTemplate,
templateType, new Settings3A(), Executors.newScheduledThreadPool(1),
3 /* afHoldSeconds */, cameraCharacteristics.isAutoExposureSupported(),
cameraCharacteristics.isAutoFocusSupported());
mManualAutoFocus = manualAutoFocusFactory.provideManualAutoFocus();
Supplier<MeteringRectangle[]> aeRegions =
manualAutoFocusFactory.provideAEMeteringRegion();
Supplier<MeteringRectangle[]> afRegions =
manualAutoFocusFactory.provideAFMeteringRegion();
requestTemplate.setParam(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
requestTemplate.setParam(CaptureRequest.CONTROL_AF_REGIONS, afRegions);
在看重点,packages\apps\Camera2\src\com\android\camera\one\v2\autofocus\ManualAutoFocusFactory.java
public static ManualAutoFocusFactory create(Lifetime lifetime, FrameServer frameServer,
CameraCommandExecutor commandExecutor, Supplier<Rect> cropRegion,
int sensorOrientation,
Runnable previewRunner, RequestBuilder.Factory rootBuilder,
int templateType, Settings3A settings3A,
ScheduledExecutorService threadPool,
int afHoldSeconds, boolean aeSupport, boolean afSupport) {
ConcurrentState<MeteringParameters> currentMeteringParameters = new ConcurrentState<>(
GlobalMeteringParameters.create());
AEMeteringRegion aeMeteringRegion = new AEMeteringRegion(currentMeteringParameters,
cropRegion);
AFMeteringRegion afMeteringRegion = new AFMeteringRegion(currentMeteringParameters,
cropRegion);
RequestTemplate afScanRequestBuilder = new RequestTemplate(rootBuilder);
if (aeSupport) {
afScanRequestBuilder.setParam(CaptureRequest.CONTROL_AE_REGIONS, aeMeteringRegion);
}
if (afSupport) {
afScanRequestBuilder.setParam(CaptureRequest.CONTROL_AF_REGIONS, afMeteringRegion);
}
CameraCommand initialCommand;
if (afSupport) {
initialCommand = new FullAFScanCommand(frameServer, afScanRequestBuilder,
templateType);
} else {
initialCommand = new UpdateRequestCommand(frameServer, afScanRequestBuilder,
templateType);
}
ResettingDelayedExecutor afHoldDelayedExecutor = new ResettingDelayedExecutor(
threadPool, afHoldSeconds, TimeUnit.SECONDS);
lifetime.add(afHoldDelayedExecutor);
CameraCommand afScanHoldResetCommand = new AFScanHoldResetCommand(initialCommand,
afHoldDelayedExecutor, previewRunner, currentMeteringParameters);
Runnable afRunner = new ResettingRunnableCameraCommand(commandExecutor,
afScanHoldResetCommand);
ManualAutoFocusImpl manualAutoFocus = new ManualAutoFocusImpl(currentMeteringParameters,
afRunner, sensorOrientation, settings3A);
return new ManualAutoFocusFactory(manualAutoFocus, aeMeteringRegion, afMeteringRegion);
}
在这个地方的重点看FullAFScanCommand,packages\apps\Camera2\src\com\android\camera\one\v2\autofocus\FullAFScanCommand.java,这个类里面的run线程里实现对焦的请求。
// Build a request to send a single AF_TRIGGER
RequestBuilder triggerBuilder = createAFTriggerRequest(afScanResult);
session.submitRequest(Arrays.asList(triggerBuilder.build()),
FrameServer.RequestType.NON_REPEATING);
private RequestBuilder createAFTriggerRequest(AFTriggerResult afScanResult) throws
CameraAccessException {
RequestBuilder triggerBuilder = mBuilderFactory.create(mTemplateType);
triggerBuilder.addResponseListener(forPartialMetadata(afScanResult));
triggerBuilder.setParam(CaptureRequest.CONTROL_MODE, CaptureRequest
.CONTROL_MODE_AUTO);
triggerBuilder.setParam(CaptureRequest.CONTROL_AF_MODE, CaptureRequest
.CONTROL_AF_MODE_AUTO);
triggerBuilder.setParam(CaptureRequest.CONTROL_AF_TRIGGER,
CaptureRequest.CONTROL_AF_TRIGGER_START);
return triggerBuilder;
}
这里直接把request下发到cameraservice里实现HAL的调用,实现对焦。
继续看如何实现触摸对焦,在packages\apps\Camera2\src\com\android\camera\CaptureModule.java这里实现触摸对焦的调用:
private void startActiveFocusAt(int viewX, int viewY) {
if (mCamera == null) {
// If we receive this after the camera is closed, do nothing.
return;
}
// TODO: make mFocusController final and remove null check.
if (mFocusController == null) {
Log.v(TAG, "CaptureModule mFocusController is null!");
return;
}
mFocusController.showActiveFocusAt(viewX, viewY);
// Normalize coordinates to [0,1] per CameraOne API.
float points[] = new float[2];
points[0] = (viewX - mPreviewArea.left) / mPreviewArea.width();
points[1] = (viewY - mPreviewArea.top) / mPreviewArea.height();
// Rotate coordinates to portrait orientation per CameraOne API.
Matrix rotationMatrix = new Matrix();
rotationMatrix.setRotate(mDisplayRotation, 0.5f, 0.5f);
rotationMatrix.mapPoints(points);
// Invert X coordinate on front camera since the display is mirrored.
if (mCameraCharacteristics.getCameraDirection() == Facing.FRONT) {
points[0] = 1 - points[0];
}
mCamera.triggerFocusAndMeterAtPoint(points[0], points[1]);
// Log touch (screen coordinates).
if (mZoomValue == 1f) {
TouchCoordinate touchCoordinate = new TouchCoordinate(
viewX - mPreviewArea.left,
viewY - mPreviewArea.top,
mPreviewArea.width(),
mPreviewArea.height());
// TODO: Add to logging: duration, rotation.
UsageStatistics.instance().tapToFocus(touchCoordinate, null);
}
}
这个的重点看mCamera.triggerFocusAndMeterAtPoint,最终调用到packages\apps\Camera2\src\com\android\camera\one\v2\autofocus\ManualAutoFocusImpl.java
public void triggerFocusAndMeterAtPoint(float nx, float ny) {
PointF point = new PointF(nx, ny);
mMeteringParameters.update(PointMeteringParameters.createForNormalizedCoordinates(
point /* afPoint */, point /* aePoint */, mSensorOrientation, mSettings3A));
mAFScanRunnable.run();
}
这里就可以看到调用到前面讲的自动对焦里去了。
最后,总结一下具体的框图逻辑: