Camera1 源码解析系列(二)—— Camera1 Open() 流程解析
2024-02-20 04:17:47
前言
Camera1 是 Android 平台上用于访问摄像头硬件的原始 API。它提供了对摄像头设备的直接控制,允许应用程序配置摄像头参数、捕获图像和视频数据。然而,Camera1 API 已经过时,Android 5.0(API 级别 21)之后就不再推荐使用。取而代之的是 Camera2 API,它提供了更加强大的功能和更灵活的控制。
尽管如此,Camera1 API 仍然在许多旧应用程序中使用。为了帮助这些应用程序顺利过渡到 Camera2 API,本文将深入剖析 Camera1 源码中的 open() 方法,从 Framework 层到 Android Runtime 层再到 C/C++ Libraries 层,最后到 HAL 层,逐层解析整个调用流程。通过对 open() 方法的理解,读者可以更好地理解 Camera1 的工作原理,以便在应用程序中正确使用 Camera1 API。
Camera.java 中的 open() 方法
Camera.java 是 Camera1 API 的核心类。它提供了对摄像头设备的直接控制,允许应用程序配置摄像头参数、捕获图像和视频数据。open() 方法是 Camera.java 类中最重要的方法之一,它用于打开摄像头设备并初始化摄像头对象。
public Camera open() {
return open(0);
}
open() 方法首先调用 open(int cameraId) 方法,其中 cameraId 参数指定要打开的摄像头设备的 ID。如果 cameraId 参数为 0,则表示打开后置摄像头;如果 cameraId 参数为 1,则表示打开前置摄像头。
public static Camera open(int cameraId) {
Camera camera = new Camera();
camera.openInner(cameraId);
return camera;
}
openInner(int cameraId) 方法是 Camera.java 类中另一个重要的方法,它用于实际打开摄像头设备并初始化摄像头对象。
private void openInner(int cameraId) {
synchronized (this) {
if (mNativeContext == 0) {
throw new RuntimeException("Attempt to use a Camera object that was not initialized.");
}
if (mCameraDevice != null) {
throw new RuntimeException("Camera is already open.");
}
openCameraDevice(cameraId);
}
}
openInner(int cameraId) 方法首先检查 mNativeContext 是否为 0,如果为 0,则表示摄像头对象还没有被初始化,抛出异常。然后,它检查 mCameraDevice 是否为 null,如果为 null,则表示摄像头设备还没有被打开,继续打开摄像头设备。
openCameraDevice(int cameraId) 方法
openCameraDevice(int cameraId) 方法是 Camera.java 类中另一个重要的方法,它用于实际打开摄像头设备。
private void openCameraDevice(int cameraId) {
try {
native_setup(mNativeContext, cameraId);
mCameraDevice = CameraDeviceClient.connectAndConfigureCamera(mNativeContext, cameraId);
} catch (CameraAccessException e) {
throw new RuntimeException("Fail to connect CameraService.");
}
}
openCameraDevice(int cameraId) 方法首先调用 native_setup(int nativeContext, int cameraId) 方法,该方法在 JNI 层中实现,用于设置摄像头设备的原生上下文和摄像头 ID。然后,它调用 CameraDeviceClient.connectAndConfigureCamera(int nativeContext, int cameraId) 方法,该方法用于连接和配置摄像头设备。
native_setup(int nativeContext, int cameraId) 方法
native_setup(int nativeContext, int cameraId) 方法在 JNI 层中实现,用于设置摄像头设备的原生上下文和摄像头 ID。
void Java_android_hardware_Camera_native_setup(JNIEnv* env, jobject thiz, jint nativeContext, jint cameraId) {
Camera* camera = CameraFactory::GetCamera(cameraId);
if (camera != NULL) {
camera->SetContext(nativeContext);
}
}
native_setup(int nativeContext, int cameraId) 方法首先调用 CameraFactory::GetCamera(int cameraId) 方法,该方法用于获取指定摄像头 ID 的摄像头设备。然后,它调用摄像头设备的 SetContext(int nativeContext) 方法,该方法用于设置摄像头设备的原生上下文。
CameraDeviceClient.connectAndConfigureCamera(int nativeContext, int cameraId) 方法
CameraDeviceClient.connectAndConfigureCamera(int nativeContext, int cameraId) 方法用于连接和配置摄像头设备。
public static CameraDeviceClient connectAndConfigureCamera(int nativeContext, int cameraId) throws CameraAccessException {
CameraDeviceClient client = null;
try {
client = CameraDeviceClient.createAndConnect(nativeContext);
configureCamera(nativeContext, client, cameraId);
} catch (IOException e) {
throw new CameraAccessException(CameraAccessException.CAMERA_ERROR, "Fail to connect to camera service");
}
return client;
}
CameraDeviceClient.connectAndConfigureCamera(int nativeContext, int cameraId) 方法首先调用 CameraDeviceClient.createAndConnect(int nativeContext) 方法,该方法用于创建和连接摄像头设备客户端。然后,它调用 configureCamera(int nativeContext, CameraDeviceClient client, int cameraId) 方法,该方法用于配置摄像头设备。
configureCamera(int nativeContext, CameraDeviceClient client, int cameraId) 方法
configureCamera(int nativeContext, CameraDeviceClient client, int cameraId) 方法用于配置摄像头设备。
private static void configureCamera(int nativeContext, CameraDeviceClient client, int cameraId) {
try {
client.configureStreams(nativeContext,
sCameraInfo[cameraId].supportedStreamCombinations);
} catch (CameraAccessException e) {
throw new RuntimeException("Fail to configure camera.");