Android Camera API和HAL版本对应关系

Android Camera API和HAL版本对应关系

前言

  Android在版本更新和迭代过程中,Camera相关代码也经历了几个版本的更新,主要表现为Camera HAL版本更新(HAL1 -> HAL2 -> HAL3),Camera API版本更新(Camera API1 -> Camera API2),由于Android版本是向后兼容的,所以为了解决兼容问题,势必要做一些特殊的处理来保证不同版本调用问题,本文主要说明 Camera HAL1,Camera HAL3,API1,API2之间的调用关系,由于Camera HAL2只是一个过渡版本,并且实际上并没有使用,所以不做讨论。

说明: Camera API1泛指 android.hardware.camera 包下的相关API, Camera API2泛指
android.hardware.camera2 android.hardware.camera 包下的相关API.

HAL版本和Java API版本是否能交叉调用?

  由于HAL版本有HAL1和HAL3,Java API有 API1和API2. 两两组合调用就要4种方式,那么这4种方式在Android中是否都有其使用场景呢?
  答案是肯定的,即4种组合(API1 -> HAL1、API1 -> HAL3、API2 -> HAL1、API2 -> HAL3)在Android系统中都能正常调用, 根据Android系统HAL层支持情况和API使用情况不同,就会出现上述四种组合的使用场景,下面就具体介绍一下4种组合是在那种情况下使用到的,以及基本实现原理。

版本转换以及代码位置

  对于Google最初的设计初衷,Camera API1就是用来调用HAL1的,Camera API2则是用来调用HAL3的,但由于Android碎片化严重,加上要兼容版本,所以API1也可以调用HAL3,API2也可以调用HAL1,转换原理如下:

说明:以下所有代码片段为高通平台,Android 7.1.1源码中的代码

API1调用HAL3

  API1调用HAL3是在CameraService中完成转换,使用了不同的Client(Client泛指CameraService和HAL层之间的接口,有三个版本),代码如下:
源码位置: frameworks/av/services/camera/libcameraservice/CameraService.cpp

Status CameraService::makeClient(const sp<CameraService>& cameraService,
        const sp<IInterface>& cameraCb, const String16& packageName, int cameraId,
        int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
        int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
        /*out*/sp<BasicClient>* client) {

    if (halVersion < 0 || halVersion == deviceVersion) {
        // Default path: HAL version is unspecified by caller, create CameraClient
        // based on device version reported by the HAL.
        switch(deviceVersion) {
          case CAMERA_DEVICE_API_VERSION_1_0:
            if (effectiveApiLevel == API_1) {  // Camera1 API route
                sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
                *client = new CameraClient(cameraService, tmp, packageName, cameraId, facing,
                        clientPid, clientUid, getpid(), legacyMode);
            } else { // Camera2 API route
                ALOGW("Camera using old HAL version: %d", deviceVersion);
                return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
                        "Camera device \"%d\" HAL version %d does not support camera2 API",
                        cameraId, deviceVersion);
            }
            break;
          case CAMERA_DEVICE_API_VERSION_3_0:
          case CAMERA_DEVICE_API_VERSION_3_1:
          case CAMERA_DEVICE_API_VERSION_3_2:
          case CAMERA_DEVICE_API_VERSION_3_3:
          case CAMERA_DEVICE_API_VERSION_3_4:
            if (effectiveApiLevel == API_1) { // Camera1 API route
                sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
                *client = new Camera2Client(cameraService, tmp, packageName, cameraId, facing,
                        clientPid, clientUid, servicePid, legacyMode);
            } else { // Camera2 API route
                sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
                        static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
                *client = new CameraDeviceClient(cameraService, tmp, packageName, cameraId,
                        facing, clientPid, clientUid, servicePid);
            }
            break;
          default:
            // Should not be reachable
            ALOGE("Unknown camera device HAL version: %d", deviceVersion);
            return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                    "Camera device \"%d\" has unknown HAL version %d",
                    cameraId, deviceVersion);
        }
    } else {
        // A particular HAL version is requested by caller. Create CameraClient
        // based on the requested HAL version.
        if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 &&
            halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
            // Only support higher HAL version device opened as HAL1.0 device.
            sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
            *client = new CameraClient(cameraService, tmp, packageName, cameraId, facing,
                    clientPid, clientUid, servicePid, legacyMode);
        } else {
            // Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
            ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
                    " opened as HAL %x device", halVersion, deviceVersion,
                    CAMERA_DEVICE_API_VERSION_1_0);
            return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
                    "Camera device \"%d\" (HAL version %d) cannot be opened as HAL version %d",
                    cameraId, deviceVersion, halVersion);
        }
    }
    return Status::ok();
}

上述代码中基本判断逻辑是:
API1: frameworks/av/services/camera/libcameraservice/api1/
API2: frameworks/av/services/camera/libcameraservice/api2/
  打开HAL版本没有特殊指定(即正常调用Camera.open()),或者指定的HAL版本和要打开的Camera默认的HAL版本相同,则根据要打开的Camera的默认HAL版本创建 Client,此时,如果HAL层默认使用HAL1,则创建 CameraClient,如果HAL层默认使用HAL3,根据使用API进行判断,使用API1则创建 Camera2Client,使用API2则创建 CameraDeviceClient。如果指定了一个特殊的HAL版本,并且不是默认的HAL版本,此时只会创建 CameraClient,其他情况不支持, 原因注释里面也说明了。
上述几个Client代码位置为:
  其中 CameraClient.cpp 是API调用HAL1的接口, Camera2Client.cpp是API1调用HAL3接口, CameraDeviceClient是API2调用HAL3接口,是不是发现没有API2调用HAL1接口? 接下来就会讲这个了,和上述转换有区别.

API2调用HAL1

  在4种调用组合里面,有3种是通过在CameraService中创建不同的Client来实现的,只有API2调用HAL1是在API层面实现的,即把Camera API2的API调用转为Camera API1,下面通过源码来看下使用API2调用HAL1时打开Camera操作是如何转换的。

Camera API2 打开Camera流程
frameworks/base/core/java/android/hardware/camera2/CameraManager.java

 public void openCamera(@NonNull String cameraId,
            @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
            throws CameraAccessException {

        openCameraForUid(cameraId, callback, handler, USE_CALLING_UID);
    }

调用 openCameraForUid

public void openCameraForUid(@NonNull String cameraId,
            @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler,
            int clientUid)
            throws CameraAccessException {

        if (cameraId == null) {
            throw new IllegalArgumentException("cameraId was null");
        } else if (callback == null) {
            throw new IllegalArgumentException("callback was null");
        } else if (handler == null) {
            if (Looper.myLooper() != null) {
                handler = new Handler();
            } else {
                throw new IllegalArgumentException(
                        "Handler argument is null, but no looper exists in the calling thread");
            }
        }

        openCameraDeviceUserAsync(cameraId, callback, handler, clientUid);
    }

调用 openCameraDeviceUserAsync

private CameraDevice openCameraDeviceUserAsync(String cameraId,
            CameraDevice.StateCallback callback, Handler handler, final int uid)
            throws CameraAccessException {
//部分源码省略......
 ICameraDeviceUser cameraUser = null;
try {
    if (supportsCamera2ApiLocked(cameraId)) {
        // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
        ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
        if (cameraService == null) {
            throw new ServiceSpecificException(
                ICameraService.ERROR_DISCONNECTED,
                "Camera service is currently unavailable");
        }
        cameraUser = cameraService.connectDevice(callbacks, id,
                mContext.getOpPackageName(), uid);
    } else {
        // Use legacy camera implementation for HAL1 devices
        Log.i(TAG, "Using legacy camera HAL.");
        cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
    }
}
//部分源码省略......

  上面的 supportsCamera2ApiLocked(cameraId) 就是判断是否支持HAL3,如果不支持,就调用
CameraDeviceUserShim.connectBinderShim(callbacks, id)来获取
ICameraDeviceUser,最后看下函数 connectBinderShim()代码:

import android.hardware.Camera;

public static CameraDeviceUserShim connectBinderShim(ICameraDeviceCallbacks callbacks,
                                                     int cameraId) {
    //部分代码省略...
    // TODO: Make this async instead of blocking
    int initErrors = init.waitForOpen(OPEN_CAMERA_TIMEOUT_MS);
    Camera legacyCamera = init.getCamera();
    //部分代码省略...
    LegacyCameraDevice device = new LegacyCameraDevice(
            cameraId, legacyCamera, characteristics, threadCallbacks);
    return new CameraDeviceUserShim(cameraId, device, characteristics, init, threadCallbacks);
}

  从上面import语句和 Camera legacyCamera = init.getCamera()就能看出来,此处是调用Camera API1接口来实现的,所以Camera API2调用HAL1其实是在Framework层将API2接口转为了API1,对CameraService来说,就是使用API1来调用。转换代码路径在: frameworks/base/core/java/android/hardware/camera2/legacy/有兴趣的可以看下

各种版本调用使用场景

  从上面的分析大家都了解了API和HAL之间不同版本转换关系,之所以有这么多转换,就是为了实现兼容,因此下面简单说一下各个版本在什么场景下有用武之地.

  API1 调用 HAL1
  Android 5.0之前, 几乎所有手机都使用的场景,也是最开始Camera API1设计的初衷
  API1 调用 HAL3
  对于支持HAL3手机,并默认使用HAL3作为HAL的版本, 此种类型是手机想使用HAL3和Camera API2, 单由于没法限制第三方应用也使用Camera API2,而做出的一种兼容方式.
  API2 调用 HAL1
  手机不支持HAL3, 但应用使用了Camera API2, 常见于中低端手机, Android版本是5.0以上, 但底层不支持HAL3.
  API2 调用 HAL3
  Camera API2设计初衷就是调用HAL3的, 现在大多数中高端手机基本都是API2调用HAL3, 最大限度使用Camera提供的功能

总结

不同API和HAL版本直接调用可简单总结为以下几点:
  API1 -> HAL1, 原始Camera流程, CameraService中使用的Client为 CameraClient
  API1 -> HAL3, 兼容使用API1的应用, CameraService中使用的Client为 Camera2Client
  API2 -> HAL1, 底层只支持HAL1, 为了兼容API2应用, 通过Framework层将API2转为API1实现
  API2 -> HAL3, 未来趋势, 提供更好的Camera控制能力, CameraService使用的Client为 CameraDeviceClient
  API1调用HAL3和API2调用HAL1对于应用来说, 都没有发挥HAL3和API2的功能, 只是一个兼容方案.
最后通过一张图片来直观明了的说明版本直接关系:

HAL13

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Android相机硬件抽象层(Camera HAL)是Android系统中的一个组件,它提供了一个标准的接口,使应用程序可以与不同类型的相机硬件进行通信。Camera HAL负责管理相机硬件的驱动程序,并将相机数据传递给应用程序。它还提供了一些功能,如自动对焦、曝光控制和图像处理。Camera HALAndroid相机架构中的重要组成部分,它使得开发人员可以轻松地开发出高质量的相机应用程序。 ### 回答2: Android Camera HAL(硬件抽象层)是一种软件层,它实现了操作系统和相机硬件之间的通信。它为相机硬件提供了一种标准的接口,并允许操作系统与硬件之间进行通信,使用户可以在操作系统的界面上控制相机硬件。HAL为开发人员提供了一种开发相机驱动的标准接口,使他们能够使用相同的API在多个设备上编写相机应用程序。 Android Camera HAL提供了一些常见的功能,例如设置相机参数(如曝光时间、焦距、白平衡等)、捕获图像、处理传感器数据和检测触发事件等。HAL将这些功能作为API提供给应用程序,允许应用程序使用这些功能进行自定义图像处理。 除了这些常见的功能,HAL还放宽了操作系统和硬件之间的联系,因为它提供了一个统一的接口。这意味着开发人员可以通过编写HAL支持新的相机硬件,而不必修改操作系统的源代码。这种可扩展性使得HAL成为一个非常强大的工具,使开发人员能够轻松地集成新硬件和新功能。 总的来说,Android Camera HAL允许开发人员轻松访问和控制相机硬件,并通过使用标准API开发相机应用程序。HAL还促进了相机硬件的可扩展性和可配置性,因为它提供了一个单一的接口,使得不同的设备可以使用相同的API访问底层硬件。 ### 回答3: Android相机HAL(硬件抽象层)是一种旨在提高Android设备相机性能和兼容性的软件组件。HAL是指在底层(硬件、驱动程序、操作系统等)运行的一组软件接口,它们负责把应用程序的请求翻译成与底层硬件通信的命令。 Android相机HAL负责控制相机的硬件功能,例如焦距、曝光、闪光灯、白平衡和图像处理等。HAL相当于一个中间层,使应用程序能够从硬件细节中解放出来,并以一种统一的方式使用不同的摄像头硬件。 不同厂商的相机硬件有很多不同之处,例如像素密度、传感器类型、镜头质量等等。HAL的设计是为了让所有Android设备的应用程序在不同的相机硬件上都能很好地运行。 在HAL中,有两个主要组件:HAL模块和框架层。HAL模块是用于控制硬件的代码库,包括相机驱动程序、图像处理和传感器控制等。框架层按照HAL接口规范与HAL模块通信,并向应用程序提供相机服务。 与传统的相机API不同,Android相机HAL的架构是在原生级别上实现的。这意味着Android设备的各个供应商可以自由地为硬件开发HAL模块,以适应各自的需求。 总之,Android相机HAL的目的是提高相机性能和兼容性。HAL的设计使所有Android设备的应用程序都能使用不同的摄像头硬件,并简化了与底层硬件的通信。这种设计为各个供应商提供了灵活的发展空间,也推动了Android相机的发展和普及。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值