Camera 入门第一篇

和你一起终身学习,这里是程序员Android

本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:

一、openCamera 简单调用流程
二、CameraManager.getCameraCharacteristics 获取方法
三、supportsCamera2ApiLocked
四、CameraService.connectDevice
五、CameraManager.setRemoteDevice

一、openCamera 简单调用流程

打开相机是通过调用CameraManager.java (frameworks\base\core\java\android\hardware\camera2)的 openCamera 方法,根据指定的CameraId 打开。

1.1 CameraManager.openCamera 方法

  • cameraId 是一个标识,标识当前要打开的camera

  • callback 是一个状态回调,当前camera被打开的时候,这个状态回调会被触发的。

  • handler 是传入的一个执行耗时操作的handler

  • executor 操作线程池

    public void openCamera(@NonNull String cameraId...)
            throws CameraAccessException {
        // 通过Camera Id 打开Camera,调用1.2 openCameraForUid
        openCameraForUid(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler),
                USE_CALLING_UID);
    }
    public void openCamera(@NonNull String cameraId,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull final CameraDevice.StateCallback callback)

1.2 CameraManager.openCameraForUid 方法

    public void openCameraForUid(@NonNull String cameraId,
          .... ... )
            throws CameraAccessException {
        ... ...
        //调用异步 Camera 助手 打开Camera ,调用 1.3 openCameraDeviceUserAsync
        openCameraDeviceUserAsync(cameraId, callback, executor, clientUid);
    }

1.3 CameraManager.openCameraDeviceUserAsync 方法

  • 获取当前cameraId指定相机的设备信息

  • 利用获取相机的设备信息创建CameraDeviceImpl实例

  • 调用远程CameraService获取当前相机的远程服务

  • 将获取的远程服务设置到CameraDeviceImpl实例中

  • 返回CameraDeviceImpl实例

private CameraDevice openCameraDeviceUserAsync(String cameraId,... ...)
            throws CameraAccessException {
       //通过CamerService 获取CameraDevices的   Camera的设备信息 ,参考 二、getCameraCharacteristics 获取方法
        CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
        CameraDevice device = null;
            ... ...
            //  New 一个CameraDeviceImpl对象实例
            android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
                    new android.hardware.camera2.impl.CameraDeviceImpl(
                        cameraId,
                        callback,
                        executor,
                        characteristics,
                        mContext.getApplicationInfo().targetSdkVersion);

            ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();

            try {
               //判断是否支持 Camera2API
                // 参考 三、supportsCamera2ApiLocked
                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");
                    }
                     //调用远程CameraService获取当前相机的远程服务
                     // 参考四、CameraService.connectDevice
                    cameraUser = cameraService.connectDevice(callbacks, cameraId,
                            mContext.getOpPackageName(), uid);
                } else {
                   ... ...
                }
            } catch (ServiceSpecificException e) {
              ... ...
            } catch (RemoteException e) {
              ... ...
            }

            // TODO: factor out callback to be non-nested, then move setter to constructor
            // For now, calling setRemoteDevice will fire initial
            // onOpened/onUnconfigured callbacks.
            // This function call may post onDisconnected and throw CAMERA_DISCONNECTED if
            // cameraUser dies during setup.
           //将获取的远程服务设置到CameraDeviceImpl实例中
            // 参考 五、setRemoteDevice 方法
            deviceImpl.setRemoteDevice(cameraUser);
            device = deviceImpl;
        }
        //返回CameraDeviceImpl实例
        return device;
    }

1.4 Open Camera 大致时序图

Open Camera 时序图

二、CameraManager.getCameraCharacteristics 获取方法

getCameraCharacteristics 方法通过ICameraService.aidl 获取到 CameraService.cpp 中的getCameraCharacteristics 函数。

 public CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId)
            throws CameraAccessException {
        CameraCharacteristics characteristics = null;
 
        synchronized (mLock) {
            /*
             * Get the camera characteristics from the camera service directly if it supports it,
             * otherwise get them from the legacy shim instead.
             */
            //通过AIDL 调用CameraService.cpp中的函数
            ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
  
            try {
                Size displaySize = getDisplaySize();

                // First check isHiddenPhysicalCamera to avoid supportsCamera2ApiLocked throwing
                // exception in case cameraId is a hidden physical camera.
                if (!isHiddenPhysicalCamera(cameraId) && !supportsCamera2ApiLocked(cameraId)) {
                    // Legacy backwards compatibility path; build static info from the camera
                    // parameters
                    int id = Integer.parseInt(cameraId);

                    String parameters = cameraService.getLegacyParameters(id);

                    CameraInfo info = cameraService.getCameraInfo(id);

                    characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info,
                            id, displaySize);
                } else {
                    // Camera2API 从 CameraService 中直接获取Camera设备信息 参考 2.1 cameraService.getCameraCharacteristics
                    CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId);
                    try {
                        info.setCameraId(Integer.parseInt(cameraId));
                    } catch (NumberFormatException e) {
                        Log.e(TAG, "Failed to parse camera Id " + cameraId + " to integer");
                    }
                    info.setDisplaySize(displaySize);
                    // new CameraCharacteristics 返回Camera设备信息
                    characteristics = new CameraCharacteristics(info);
                }
            } catch (ServiceSpecificException e) {
           ... ...
        }
        return characteristics;
    }

2.1 CameraService::getCameraCharacteristics 函数

这里的CameraService.cpp(frameworks\av\services\camera\libcameraservice)

Status CameraService::getCameraCharacteristics(const String16& cameraId,
        CameraMetadata* cameraInfo) {
    ATRACE_CALL();
    ... ...
    Status ret{};
    // 通过 CameraProviderManger 获取Camera设备信息
    // 参考2.2 CPM.getCameraCharacteristics 函数
    status_t res = mCameraProviderManager->getCameraCharacteristics(
            String8(cameraId).string(), cameraInfo);
    ... ...
    int callingPid = CameraThreadState::getCallingPid();
    int callingUid = CameraThreadState::getCallingUid();
    std::vector<int32_t> tagsRemoved;
    // If it's not calling from cameraserver, check the permission.
    if ((callingPid != getpid()) &&
            !checkPermission(String16("android.permission.CAMERA"), callingPid, callingUid)) {
        res = cameraInfo->removePermissionEntries(
                mCameraProviderManager->getProviderTagIdLocked(String8(cameraId).string()),
                &tagsRemoved);
        if (res != OK) {
            cameraInfo->clear();
            return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to remove camera"
                    " characteristics needing camera permission for device %s: %s (%d)",
                    String8(cameraId).string(), strerror(-res), res);
        }
    }

    if (!tagsRemoved.empty()) {
        res = cameraInfo->update(ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION,
                tagsRemoved.data(), tagsRemoved.size());
        if (res != OK) {
            cameraInfo->clear();
            return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to insert camera "
                    "keys needing permission for device %s: %s (%d)", String8(cameraId).string(),
                    strerror(-res), res);
        }
    }

    return ret;
}

2.2 CameraProviderManager::getCameraCharacteristics 函数

CameraProviderManager.cpp frameworks\av\services\camera\libcameraservice\common

status_t CameraProviderManager::getCameraCharacteristics(const std::string &id,
        CameraMetadata* characteristics) const {
    std::lock_guard<std::mutex> lock(mInterfaceMutex);
    // 调用 CameraProviderManger 获取去Camera 设备信息方法
    // 参考 2.3 CameraProviderManger.getCameraCharacteristicsLocked
    return getCameraCharacteristicsLocked(id, characteristics);
}

2.3 CameraProviderManger::getCameraCharacteristicsLocked

status_t CameraProviderManager::getCameraCharacteristicsLocked(const std::string &id,
        CameraMetadata* characteristics) const {
    // 通过deviceinfo3 获取设备getCameraCharacteristics
    // 参考 2.4 CPM.findDeviceInfoLocked函数
    auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ {3,0}, /*maxVersion*/ {5,0});
    if (deviceInfo != nullptr) {
        return deviceInfo->getCameraCharacteristics(characteristics);
    }

    // Find hidden physical camera characteristics
    for (auto& provider : mProviders) {
        for (auto& deviceInfo : provider->mDevices) {
            status_t res = deviceInfo->getPhysicalCameraCharacteristics(id, characteristics);
            if (res != NAME_NOT_FOUND) return res;
        }
    }

    return NAME_NOT_FOUND;
}

2.4 CameraProviderManger::findDeviceInfoLocked

CameraProviderManager::ProviderInfo::DeviceInfo* CameraProviderManager::findDeviceInfoLocked(
        const std::string& id,
        hardware::hidl_version minVersion, hardware::hidl_version maxVersion) const {
    // 通过   deviceinfo3 queryPhysicalCameraIds 查询对应id的Camera 信息
    // 见 2.5 CMP.queryPhysicalCameraIds  函数
    for (auto& provider : mProviders) {
        for (auto& deviceInfo : provider->mDevices) {
            if (deviceInfo->mId == id &&
                    minVersion <= deviceInfo->mVersion && maxVersion >= deviceInfo->mVersion) {
                return deviceInfo.get();
            }
        }
    }
    return nullptr;
}

2.5 CameraProviderManger::queryPhysicalCameraIds 函数

void CameraProviderManager::ProviderInfo::DeviceInfo3::queryPhysicalCameraIds() {
    camera_metadata_entry_t entryCap;

    entryCap = mCameraCharacteristics.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
    for (size_t i = 0; i < entryCap.count; ++i) {
        uint8_t capability = entryCap.data.u8[i];
        if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
            mIsLogicalCamera = true;
            break;
        }
    }
    if (!mIsLogicalCamera) {
        return;
    }

    camera_metadata_entry_t entryIds = mCameraCharacteristics.find(
            ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
    const uint8_t* ids = entryIds.data.u8;
    size_t start = 0;
    for (size_t i = 0; i < entryIds.count; ++i) {
        if (ids[i] == '\0') {
            if (start != i) {
                mPhysicalIds.push_back((const char*)ids+start);
            }
            start = i+1;
        }
    }
}

2.6 getCameraCharacteristics 大致时序图

getCameraCharacteristics

三、supportsCamera2ApiLocked

当前CameraService 是否支持Camera2Api,如果支持,返回true,如果不支持,返回false。

supportsCamera2ApiLocked(cameraId)方法实现如下:

 private boolean supportsCamera2ApiLocked(String cameraId) {
        // 参考 3.1 supportsCameraApiLocked
        return supportsCameraApiLocked(cameraId, API_VERSION_2);
    }

3.1 CameraManager.supportsCameraApiLocked

    private boolean supportsCameraApiLocked(String cameraId, int apiVersion) {
        /*
         * Possible return values:
         * - NO_ERROR => CameraX API is supported
         * - CAMERA_DEPRECATED_HAL => CameraX API is *not* supported (thrown as an exception)
         * - Remote exception => If the camera service died
         *
         * Anything else is an unexpected error we don't want to recover from.
         */
        try {
            ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
            // If no camera service, no support
           // 参考 3.2 CameraService supportsCameraApi 的方法
            if (cameraService == null) return false;

            return cameraService.supportsCameraApi(cameraId, apiVersion);
        } catch (RemoteException e) {
            // Camera service is now down, no support for any API level
        }
        return false;
    }

3.2 CameraService::supportsCameraApi

Status CameraService::supportsCameraApi(const String16& cameraId, int apiVersion,
        /*out*/ bool *isSupported) {
    ATRACE_CALL();

    const String8 id = String8(cameraId);

    ALOGV("%s: for camera ID = %s", __FUNCTION__, id.string());

    switch (apiVersion) {
        case API_VERSION_1:
        case API_VERSION_2:
            break;
        default:
            String8 msg = String8::format("Unknown API version %d", apiVersion);
            ALOGE("%s: %s", __FUNCTION__, msg.string());
            return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
    }

    int deviceVersion = getDeviceVersion(id);
    switch (deviceVersion) {
        case CAMERA_DEVICE_API_VERSION_1_0:
        case CAMERA_DEVICE_API_VERSION_3_0:
        case CAMERA_DEVICE_API_VERSION_3_1:
            if (apiVersion == API_VERSION_2) {
                ALOGV("%s: Camera id %s uses HAL version %d <3.2, doesn't support api2 without shim",
                        __FUNCTION__, id.string(), deviceVersion);
                *isSupported = false;
            } else { // if (apiVersion == API_VERSION_1) {
                ALOGV("%s: Camera id %s uses older HAL before 3.2, but api1 is always supported",
                        __FUNCTION__, id.string());
                *isSupported = true;
            }
            break;
        case CAMERA_DEVICE_API_VERSION_3_2:
        case CAMERA_DEVICE_API_VERSION_3_3:
        case CAMERA_DEVICE_API_VERSION_3_4:
        case CAMERA_DEVICE_API_VERSION_3_5:
            ALOGV("%s: Camera id %s uses HAL3.2 or newer, supports api1/api2 directly",
                    __FUNCTION__, id.string());
            *isSupported = true;
            break;
        case -1: {
            String8 msg = String8::format("Unknown camera ID %s", id.string());
            ALOGE("%s: %s", __FUNCTION__, msg.string());
            return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
        }
        default: {
            String8 msg = String8::format("Unknown device version %x for device %s",
                    deviceVersion, id.string());
            ALOGE("%s: %s", __FUNCTION__, msg.string());
            return STATUS_ERROR(ERROR_INVALID_OPERATION, msg.string());
        }
    }

    return Status::ok();
}

四、CameraService.connectDevice

cameraService.connectDevice 会通过AIDL 调用到CameraService.cppframeworks\av\services\camera\libcameraservice

4.1 CameraService::connectDevice

连接当前的cameraDevice设备

Status CameraService::connectDevice(
        const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
        const String16& cameraId,
        const String16& clientPackageName,
        int clientUid,
        /*out*/
        sp<hardware::camera2::ICameraDeviceUser>* device) {

    ATRACE_CALL();
    Status ret = Status::ok();
    String8 id = String8(cameraId);
    sp<CameraDeviceClient> client = nullptr;
    String16 clientPackageNameAdj = clientPackageName;

    if (getCurrentServingCall() == BinderCallType::HWBINDER) {
        std::string vendorClient =
                StringPrintf("vendor.client.pid<%d>", CameraThreadState::getCallingPid());
        clientPackageNameAdj = String16(vendorClient.c_str());
    }
    // connectHelper  链接助手,处理连接的一些情况 比如Camera 独占,flash 预打开等
    // 具体实现情况 4.2  CameraService::connectHelper
    ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
            /*api1CameraId*/-1,
            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageNameAdj,
            clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, /*out*/client);

    if(!ret.isOk()) {
        logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageNameAdj),
                ret.toString8());
        return ret;
    }

    *device = client;
    return ret;
}

4.2 CameraService::connectHelper

Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
        int api1CameraId, int halVersion, const String16& clientPackageName, int clientUid,
        int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly,
        /*out*/sp<CLIENT>& device) {
    binder::Status ret = binder::Status::ok();

    String8 clientName8(clientPackageName);

    int originalClientPid = 0;

 

    if (shouldRejectHiddenCameraConnection(cameraId)) {
        ALOGW("Attempting to connect to system-only camera id %s, connection rejected",
              cameraId.c_str());
        return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
                                "No camera device with ID \"%s\" currently available",
                                cameraId.string());

    }
    sp<CLIENT> client = nullptr;
    {
        // Acquire mServiceLock and prevent other clients from connecting
        std::unique_ptr<AutoConditionLock> lock =
                AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);
 

        // 检查当前的camera device是否可用,这儿的判断比较简单,只是简单判断当前设备是否存在
        if(!(ret = validateConnectLocked(cameraId, clientName8,
                /*inout*/clientUid, /*inout*/clientPid, /*out*/originalClientPid)).isOk()) {
            return ret;
        }

        // Check the shim parameters after acquiring lock, if they have already been updated and
        // we were doing a shim update, return immediately
        if (shimUpdateOnly) {
            auto cameraState = getCameraState(cameraId);
            if (cameraState != nullptr) {
                if (!cameraState->getShimParams().isEmpty()) return ret;
            }
        }

        status_t err;

        sp<BasicClient> clientTmp = nullptr;
        std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;
        // 处理camera独占情况
        if ((err = handleEvictionsLocked(cameraId, originalClientPid, effectiveApiLevel,
                IInterface::asBinder(cameraCb), clientName8, /*out*/&clientTmp,
                /*out*/&partial)) != NO_ERROR) {
            switch (err) {
                case -ENODEV:
                    return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
                            "No camera device with ID \"%s\" currently available",
                            cameraId.string());
                case -EBUSY:
                    return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
                            "Higher-priority client using camera, ID \"%s\" currently unavailable",
                            cameraId.string());
                default:
                    return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                            "Unexpected error %s (%d) opening camera \"%s\"",
                            strerror(-err), err, cameraId.string());
            }
        }

        if (clientTmp.get() != nullptr) {
            // Handle special case for API1 MediaRecorder where the existing client is returned
            device = static_cast<CLIENT*>(clientTmp.get());
            return ret;
        }

        // 预备链接CameraDevices 必要时给手电筒关闭设备的机会.
        mFlashlight->prepareDeviceOpen(cameraId);

        int facing = -1;
        //获取当前的camera device的version 版本
        int deviceVersion = getDeviceVersion(cameraId, /*out*/&facing);
   

        sp<BasicClient> tmp = nullptr;
        // 我们采用的client都是CameraDeviceClient
        if(!(ret = makeClient(this, cameraCb, clientPackageName,
                cameraId, api1CameraId, facing,
                clientPid, clientUid, getpid(),
                halVersion, deviceVersion, effectiveApiLevel,
                /*out*/&tmp)).isOk()) {
            return ret;
        }
        client = static_cast<CLIENT*>(tmp.get());

        ... ...
 
        if (shimUpdateOnly) {
            // If only updating legacy shim parameters, immediately disconnect client
            mServiceLock.unlock();
            client->disconnect();
            mServiceLock.lock();
        } else {
            // Otherwise, add client to active clients list
            finishConnectLocked(client, partial);
        }
    } // lock is destroyed, allow further connect calls

    // Important: release the mutex here so the client can call back into the service from its
    // destructor (can be at the end of the call)
    device = client;
    return ret;
}

4.3 connectDevices 调用流程

connectdevices.jpg

五、CameraManager.setRemoteDevice 方法

// 参考 5.1 CameraDeviceImpl.setRemoteDevice
deviceImpl.setRemoteDevice(cameraUser);
device = deviceImpl;

5.1 CameraDeviceImpl.setRemoteDevice

CameraDeviceImpl.javaframeworks\base\core\java\android\hardware\camera2\impl
这个mRemoteDevice是应用程序进程和android camera service端之间链接的桥梁,上层操作camera的方法会通过调用mRemoteDevice来调用到camera service端来实现操作底层camera驱动的目的

    public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {
        synchronized(mInterfaceLock) {
            // TODO: Move from decorator to direct binder-mediated exceptions
            // If setRemoteFailure already called, do nothing
            if (mInError) return;

            mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);

            IBinder remoteDeviceBinder = remoteDevice.asBinder();
            // For legacy camera device, remoteDevice is in the same process, and
            // asBinder returns NULL.
            if (remoteDeviceBinder != null) {
                try {
                    remoteDeviceBinder.linkToDeath(this, /*flag*/ 0);
                } catch (RemoteException e) {
                    CameraDeviceImpl.this.mDeviceExecutor.execute(mCallOnDisconnected);

                    throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
                            "The camera device has encountered a serious error");
                }
            }

            mDeviceExecutor.execute(mCallOnOpened);
            mDeviceExecutor.execute(mCallOnUnconfigured);
        }
    }

相关文章友情推荐 

1. Android开发干货分享

至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

点个在看,方便您使用时快速查看!

posted @ 2020-08-24 08:00  程序员Android的博客  阅读(1683)  评论(0编辑  收藏  举报