美文网首页
相机——打开流程

相机——打开流程

作者: 王志强_9380 | 来源:发表于2020-07-07 16:27 被阅读0次

Framework

frameworks\base\core\java\android\hardware\Camera.java
public static Camera open(int cameraId) {
    return new Camera(cameraId);
}

public static Camera open() {
    int numberOfCameras = getNumberOfCameras();
    CameraInfo cameraInfo = new CameraInfo();
    for (int i = 0; i < numberOfCameras; i++) {
        getCameraInfo(i, cameraInfo);
        Log.e(TAG, "Camera open 11111 id:" + i);
        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
            Log.e(TAG, "Camera open 22222 id:" + i);
            return new Camera(i);
        }
    }
    return null;
}

Camera(int cameraId) {
    if (cameraId >= getNumberOfCameras()) {
        throw new RuntimeException("Unknown camera ID");
    }
    int err = cameraInitNormal(cameraId);
    if (checkInitErrors(err)) {
        if (err == -EACCES) {
            throw new RuntimeException("Fail to connect to camera service");
        } else if (err == -ENODEV) {
            throw new RuntimeException("Camera initialization failed");
        }
        // Should never hit this.
        throw new RuntimeException("Unknown camera error");
    }
}

主要的初始化在cameraInitNormal中

private int cameraInitVersion(int cameraId, int halVersion) {
    ......省略代码......
    return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName);
}

private int cameraInitNormal(int cameraId) {
    return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
}

最终调用到了native_setup的jni方法

Android Runtime

frameworks\base\core\jni\android_hardware_Camera.cpp
{ "native_setup",
"(Ljava/lang/Object;IILjava/lang/String;)I",
(void*)android_hardware_Camera_native_setup },

static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
{
    // Convert jstring to String16
    const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
        env->GetStringChars(clientPackageName, NULL));
    jsize rawClientNameLen = env->GetStringLength(clientPackageName);
    String16 clientName(rawClientName, rawClientNameLen);
    env->ReleaseStringChars(clientPackageName,
                            reinterpret_cast<const jchar*>(rawClientName));

    sp<Camera> camera;
    if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
        // Default path: hal version is don't care, do normal camera connect.
        camera = Camera::connect(cameraId, clientName,
                Camera::USE_CALLING_UID, Camera::USE_CALLING_PID);
    } else {
        jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
                Camera::USE_CALLING_UID, camera);
        if (status != NO_ERROR) {
            return status;
        }
    }
    ......省略代码......
}

Library

android_hardware_Camera_native_setup()方法通过调用Camera::connect()方法请求连接CameraService服务

frameworks\av\camera\Camera.cpp
sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
        int clientUid, int clientPid)
{
    return CameraBaseT::connect(cameraId, clientPackageName, clientUid, clientPid);
}

status_t Camera::connectLegacy(int cameraId, int halVersion,
        const String16& clientPackageName,
        int clientUid,
        sp<Camera>& camera)
{
    ALOGV("%s: connect legacy camera device", __FUNCTION__);
    sp<Camera> c = new Camera(cameraId);
    sp<::android::hardware::ICameraClient> cl = c;
    status_t status = NO_ERROR;
    const sp<::android::hardware::ICameraService>& cs = CameraBaseT::getCameraService();

    binder::Status ret;
    if (cs != nullptr) {
        ret = cs.get()->connectLegacy(cl, cameraId, halVersion, clientPackageName,
                clientUid, /*out*/&(c->mCamera));
    }
    ......省略代码......
}
connectLegacy

我们先看下connectLegacy

sp<Camera> c = new Camera(cameraId);
sp<::android::hardware::ICameraClient> cl = c;
这里把一个Camera对象直接赋值给了一个ICameraClient对象
看下Camera的定义,在Camera.h中

class Camera :
    public CameraBase<Camera>,
    public ::android::hardware::BnCameraClient

可以看到继承了两个父类CameraBase和BnCameraClient
我们接着看BnCameraClient

frameworks\av\include\camera\android\hardware\ICameraClient.h
class BnCameraClient: public BnInterface<ICameraClient>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};

可以看到BnCameraClient继承了BnInterface

frameworks\native\include\binder\IInterface.h
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
                                BpInterface(const sp<IBinder>& remote);

protected:
    virtual IBinder*            onAsBinder();
};

这里可以看到定义了一个模板,也就是说
BnInterface<ICameraClient>相当于就是
BnInterface : public ICameraClient,也就是说BnInterface 继承于ICameraClient,所以,回到上面的
sp<::android::hardware::ICameraClient> cl = c;可以直接赋值

const sp<::android::hardware::ICameraService>& cs = CameraBaseT::getCameraService();这里获取了CameraBase中CameraService对象,和后面的connect中一样,后面一起说

connect

connect方法位于CameraBase中,就是Camera的父类

frameworks\av\camera\CameraBase.cpp
template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
                                               const String16& clientPackageName,
                                               int clientUid, int clientPid)
{
    ALOGV("%s: connect", __FUNCTION__);
    sp<TCam> c = new TCam(cameraId);
    sp<TCamCallbacks> cl = c;
    const sp<::android::hardware::ICameraService> cs = getCameraService();

    binder::Status ret;
    if (cs != nullptr) {
        TCamConnectService fnConnectService = TCamTraits::fnConnectService;
        ret = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
                                               clientPid, /*out*/ &c->mCamera);
    }
    if (ret.isOk() && c->mCamera != nullptr) {
        IInterface::asBinder(c->mCamera)->linkToDeath(c);
        c->mStatus = NO_ERROR;
    } else {
        ALOGW("An error occurred while connecting to camera %d: %s", cameraId,
                (cs != nullptr) ? "Service not available" : ret.toString8().string());
        c.clear();
    }
    return c;
}

首先我们去CameraBase.h中看看定义

frameworks\av\include\camera\CameraBase.h
template <typename TCam>
struct CameraTraits {
};

template <typename TCam, typename TCamTraits = CameraTraits<TCam> >
class CameraBase : public IBinder::DeathRecipient
{
public:
    typedef typename TCamTraits::TCamListener       TCamListener;
    typedef typename TCamTraits::TCamUser           TCamUser;
    typedef typename TCamTraits::TCamCallbacks      TCamCallbacks;
    typedef typename TCamTraits::TCamConnectService TCamConnectService;

    static sp<TCam>      connect(int cameraId,
                                 const String16& clientPackageName,
                                 int clientUid, int clientPid);
    ......省略代码......

protected:
    CameraBase(int cameraId);
    ......省略代码......
    typedef CameraBase<TCam>         CameraBaseT;
};

在调用的时候

sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
        int clientUid, int clientPid)
{
    return CameraBaseT::connect(cameraId, clientPackageName, clientUid, clientPid);
}

那么,这里的CameraBaseT其实就是CameraBase<Camera>
ok,那么TCam就是Camera
回到上面

sp<TCam> c = new TCam(cameraId);
sp<TCamCallbacks> cl = c;
这条语句就可以转换为
sp<Camera> c = new Camera(cameraId);
sp<CameraTraits<Camera>::TCamCallbacks> cl = c;
在Camera.h中

template <>
struct CameraTraits<Camera>
{
    typedef CameraListener                     TCamListener;
    typedef ::android::hardware::ICamera       TCamUser;
    typedef ::android::hardware::ICameraClient TCamCallbacks;
    typedef ::android::binder::Status(::android::hardware::ICameraService::*TCamConnectService)
        (const sp<::android::hardware::ICameraClient>&,
        int, const String16&, int, int,
        /*out*/
        sp<::android::hardware::ICamera>*);
    static TCamConnectService     fnConnectService;
};

所以上面的语句就是

sp<Camera> c = new Camera(cameraId);
sp<::android::hardware::ICameraClient > cl = c;

可以看到,和之前connectLegacy中的一模一样
现在我们来看const sp<::android::hardware::ICameraService> cs = getCameraService();

getCameraService
template <typename TCam, typename TCamTraits>
const sp<::android::hardware::ICameraService> CameraBase<TCam, TCamTraits>::getCameraService()
{
    Mutex::Autolock _l(gLock);
    if (gCameraService.get() == 0) {
        char value[PROPERTY_VALUE_MAX];
        property_get("config.disable_cameraservice", value, "0");
        if (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0) {
            return gCameraService;
        }

        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
            binder = sm->getService(String16(kCameraServiceName));
            if (binder != 0) {
                break;
            }
            ALOGW("CameraService not published, waiting...");
            usleep(kCameraServicePollDelay);
        } while(true);
        if (gDeathNotifier == NULL) {
            gDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(gDeathNotifier);
        gCameraService = interface_cast<::android::hardware::ICameraService>(binder);
    }
    ALOGE_IF(gCameraService == 0, "no CameraService!?");
    return gCameraService;
}

getCameraService最终得到的是一个BpCameraService(BpBinder(handle))实例
接着往下看

fnConnectService

TCamConnectService fnConnectService = TCamTraits::fnConnectService;
ret = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid, clientPid, &c->mCamera);

之前我们在Camera.h中看到

typedef ::android::binder::Status(::android::hardware::ICameraService::*TCamConnectService)
        (const sp<::android::hardware::ICameraClient>&,
        int, const String16&, int, int,
        /*out*/
        sp<::android::hardware::ICamera>*); //这是类成员函数指针
static TCamConnectService     fnConnectService;//变量声明 指针 fnConnectService

我们看看他的实现

CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService =
        &::android::hardware::ICameraService::connect;

其目的是用指针fnConnectService 指向ICameraService 类下的函数connect 地址
最终调用到了CameraService.cpp中的connect

CameraService::connect
frameworks\av\services\camera\libcameraservice\CameraService.cpp
Status CameraService::connect(
        const sp<ICameraClient>& cameraClient,
        int cameraId,
        const String16& clientPackageName,
        int clientUid,
        int clientPid,
        /*out*/
        sp<ICamera>* device) {

    ALOGE("CameraService cameraId:%d",cameraId);
    ATRACE_CALL();
    Status ret = Status::ok();
    String8 id = String8::format("%d", cameraId);
    sp<Client> client = nullptr;
    ret = connectHelper<ICameraClient,Client>(cameraClient, id,
            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, clientPid, API_1,
            /*legacyMode*/ false, /*shimUpdateOnly*/ false,
            /*out*/client);

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

    *device = client;
    return ret;
}

Status CameraService::connectLegacy(
        const sp<ICameraClient>& cameraClient,
        int cameraId, int halVersion,
        const String16& clientPackageName,
        int clientUid,
        /*out*/
        sp<ICamera>* device) {

    ......省略代码......
    Status ret = Status::ok();
    sp<Client> client = nullptr;
    ret = connectHelper<ICameraClient,Client>(cameraClient, id, halVersion,
            clientPackageName, clientUid, USE_CALLING_PID, API_1,
            /*legacyMode*/ true, /*shimUpdateOnly*/ false,
            /*out*/client);

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

    *device = client;
    return ret;
}

核心是调用connectHelper, connectHelper实现在CameraService.h中

template<class CALLBACK, class CLIENT>
binder::Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
        int halVersion, const String16& clientPackageName, int clientUid, int clientPid,
        apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
        /*out*/sp<CLIENT>& device) {
    ......省略代码......
    int facing = -1;
    int deviceVersion = getDeviceVersion(id, /*out*/&facing);
    sp<BasicClient> tmp = nullptr;
    if(!(ret = makeClient(this, cameraCb, clientPackageName, id, facing, clientPid,
            clientUid, getpid(), legacyMode, halVersion, deviceVersion, effectiveApiLevel,
            /*out*/&tmp)).isOk()) {
        return ret;
    }
    client = static_cast<CLIENT*>(tmp.get());

    LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
            __FUNCTION__);

    if ((err = client->initialize(mModule)) != OK) {
        ALOGE("%s: Could not initialize client from HAL module.", __FUNCTION__);
        // Errors could be from the HAL module open call or from AppOpsManager
        switch(err) {
            case BAD_VALUE:
                return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
                        "Illegal argument to HAL module for camera \"%s\"", cameraId.string());
            case -EBUSY:
                return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
                        "Camera \"%s\" is already open", cameraId.string());
            case -EUSERS:
                return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
                        "Too many cameras already open, cannot open camera \"%s\"",
                        cameraId.string());
            case PERMISSION_DENIED:
                return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
                        "No permission to open camera \"%s\"", cameraId.string());
            case -EACCES:
                return STATUS_ERROR_FMT(ERROR_DISABLED,
                        "Camera \"%s\" disabled by policy", cameraId.string());
            case -ENODEV:
            default:
                return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                        "Failed to initialize camera \"%s\": %s (%d)", cameraId.string(),
                        strerror(-err), err);
        }
    }
    ......省略代码......
    // 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;
}

关键点makeClient获取CameraClient/Camera2Client对象

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();
}

上面根据halVersion 来判断使用哪个Client,一般来说:

我们直接调用Camera里的open方法,里面默认传的是CAMERA_HAL_API_VERSION_NORMAL_CONNECT,这个值是-2,所以一般会调用到Camera2Client
骁龙相机打开相机调用的是openLegacy,这个需要自己传VERSION,并且里面有判断halVersion < CAMERA_HAL_API_VERSION_1_0会抛异常,也就是halVersion <0x100就会报错,所以一般这个会跑CameraClient

接着就是调用Client的initialize方法
这里以CameraClient为例

status_t CameraClient::initialize(CameraModule *module) {
    int callingPid = getCallingPid();
    status_t res;

    ALOGE("CameraService mCameraId CameraClient:%d",mCameraId);
    LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);

    // Verify ops permissions
    res = startCameraOps();
    if (res != OK) {
        return res;
    }

    char camera_device_name[10];
    snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);

    mHardware = new CameraHardwareInterface(camera_device_name);
    res = mHardware->initialize(module);
    if (res != OK) {
        ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        mHardware.clear();
        return res;
    }

    mHardware->setCallbacks(notifyCallback,
            dataCallback,
            dataCallbackTimestamp,
            (void *)(uintptr_t)mCameraId);

    // Enable zoom, error, focus, and metadata messages by default
    enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
                  CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);

    LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);
    return OK;
}

CameraHardwareInterface新建了了一个Camera硬件接口
mHardware->initialize(&module->common):调用底层硬件的初始化方法;
mHardware->setCallbacks:将CamerService处的回调函数注册到HAL处。
CameraHardwareInterface:定义了Camera的硬件抽象特征,由此进入到HAL。

tps:有的打印看不到,可以通过下面命令打开
adb shell dumpsys media.camera -v 2

HAL:CameraHardwareInterface

frameworks\av\services\camera\libcameraservice\device1\CameraHardwareInterface.h
status_t initialize(CameraModule *module)
{
    ALOGI("Opening camera %s", mName.string());
    camera_info info;
    status_t res = module->getCameraInfo(atoi(mName.string()), &info);
    if (res != OK) {
        return res;
    }

    int rc = OK;
    if (module->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_3 &&
        info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {
        // Open higher version camera device as HAL1.0 device.
        rc = module->openLegacy(mName.string(),
                                 CAMERA_DEVICE_API_VERSION_1_0,
                                 (hw_device_t **)&mDevice);
    } else {
        rc = module->open(mName.string(), (hw_device_t **)&mDevice);
    }
    if (rc != OK) {
        ALOGE("Could not open camera %s: %d", mName.string(), rc);
        return rc;
    }
    initHalPreviewWindow();
    return rc;
}

在initialize()方法中,通过cameraModule->open_legacy打开摄像头模组,如果成功,对象会保存在mDevice中,initHalPreviewWindow()用于初始化Preview的相关流opspreview_stream_ops,初始化hal的预览窗口。

void setCallbacks(notify_callback notify_cb,
                      data_callback data_cb,
                      data_callback_timestamp data_cb_timestamp,
                      void* user)
{
    mNotifyCb = notify_cb;
    mDataCb = data_cb;
    mDataCbTimestamp = data_cb_timestamp;
    mCbUser = user;

    ALOGV("%s(%s)", __FUNCTION__, mName.string());

    if (mDevice->ops->set_callbacks) {
        mDevice->ops->set_callbacks(mDevice,
                               __notify_cb,
                               __data_cb,
                               __data_cb_timestamp,
                               __get_memory,
                               this);
    }
}

set_callbacks中,__notify_cb、__data_cb、__data_cb_timestamp和__get_memory分别消息回调,数据回调,时间戳回调,以及内存相关操作的回调。

关键代码

if (module->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_3 &&
    info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {
    // Open higher version camera device as HAL1.0 device.
    rc = module->openLegacy(mName.string(),
                             CAMERA_DEVICE_API_VERSION_1_0,
                             (hw_device_t **)&mDevice);
} else {
    rc = module->open(mName.string(), (hw_device_t **)&mDevice);
}

先看看open_legacy

cameraModule->open_legacy

我们来看一下这个module怎么来的

frameworks\av\services\camera\libcameraservice\CameraService.cpp
void CameraService::onFirstRef()
{
    ALOGI("CameraService process starting");

    BnCameraService::onFirstRef();

    // Update battery life tracking if service is restarting
    BatteryNotifier& notifier(BatteryNotifier::getInstance());
    notifier.noteResetCamera();
    notifier.noteResetFlashlight();

    camera_module_t *rawModule;
    int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID,
            (const hw_module_t **)&rawModule);
    if (err < 0) {
        ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err));
        logServiceError("Could not load camera HAL module", err);
        return;
    }

    mModule = new CameraModule(rawModule);
    err = mModule->init();
    if (err != OK) {
        ALOGE("Could not initialize camera HAL module: %d (%s)", err,
            strerror(-err));
        logServiceError("Could not initialize camera HAL module", err);

        delete mModule;
        mModule = nullptr;
        return;
    }
    ......省略代码......
}
frameworks\av\services\camera\libcameraservice\common\CameraModule.h
camera_module_t *mModule;
frameworks\av\services\camera\libcameraservice\common\CameraModule.cpp
CameraModule::CameraModule(camera_module_t *module) {
    if (module == NULL) {
        ALOGE("%s: camera hardware module must not be null", __FUNCTION__);
        assert(0);
    }
    mModule = module;
}

int CameraModule::init() {
    ATRACE_CALL();
    int res = OK;
    if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 &&
            mModule->init != NULL) {
        ATRACE_BEGIN("camera_module->init");
        res = mModule->init();
        ATRACE_END();
    }
    mCameraInfoMap.setCapacity(getNumberOfCameras());
    return res;
}

hw_get_module是jni层获取HAL层module的接口函数,原型为:int hw_get_module(const char *id, const struct hw_module_t **module) 这个id是hal层注册时加入的
hw_get_module详解
我们看下camera_module_t 的定义

hardware\qcom\camera\QCamera2\QCamera2Hal.cpp
camera_module_t HAL_MODULE_INFO_SYM = {
    .common                 = camera_common,
    .get_number_of_cameras  = qcamera::QCamera2Factory::get_number_of_cameras,
    .get_camera_info        = qcamera::QCamera2Factory::get_camera_info,
    .set_callbacks          = qcamera::QCamera2Factory::set_callbacks,
    .get_vendor_tag_ops     = qcamera::QCamera3VendorTags::get_vendor_tag_ops,
    .open_legacy            = qcamera::QCamera2Factory::open_legacy,
    .set_torch_mode         = qcamera::QCamera2Factory::set_torch_mode,
    .init                   = NULL,
    .reserved               = {0}
};

可以看到open_legacy实际上是调用了qcamera::QCamera2Factory::open_legacy

hardware\qcom\camera\QCamera2\QCamera2Factory.cpp
int QCamera2Factory::open_legacy(const struct hw_module_t* module,
            const char* id, uint32_t halVersion, struct hw_device_t** device)
{
    int rc = NO_ERROR;
    if (module != &HAL_MODULE_INFO_SYM.common) {
        LOGE("Invalid module. Trying to open %p, expect %p",
            module, &HAL_MODULE_INFO_SYM.common);
        return INVALID_OPERATION;
    }
    if (!id) {
        LOGE("Invalid camera id");
        return BAD_VALUE;
    }
#ifdef QCAMERA_HAL1_SUPPORT
    if(gQCameraMuxer)
        rc =  gQCameraMuxer->open_legacy(module, id, halVersion, device);
    else
#endif
        rc =  gQCamera2Factory->openLegacy(atoi(id), halVersion, device);

    return rc;
}

再来看先看看open

cameraModule->open

hardware\qcom\camera\QCamera2\QCamera2Factory.cpp
int QCamera2Factory::camera_device_open(
    const struct hw_module_t *module, const char *id,
    struct hw_device_t **hw_device)
{
    int rc = NO_ERROR;
    if (module != &HAL_MODULE_INFO_SYM.common) {
        LOGE("Invalid module. Trying to open %p, expect %p",
            module, &HAL_MODULE_INFO_SYM.common);
        return INVALID_OPERATION;
    }
    if (!id) {
        LOGE("Invalid camera id");
        return BAD_VALUE;
    }
#ifdef QCAMERA_HAL1_SUPPORT
    if(gQCameraMuxer)
        rc =  gQCameraMuxer->camera_device_open(module, id, hw_device);
    else
#endif
        rc = gQCamera2Factory->cameraDeviceOpen(atoi(id), hw_device);
    return rc;
}

struct hw_module_methods_t QCamera2Factory::mModuleMethods = {
    .open = QCamera2Factory::camera_device_open,
};

可以看到,最终都是跑到了QCamera2Factory中
我们看下两者的区别

int QCamera2Factory::openLegacy(
        int32_t cameraId, uint32_t halVersion, struct hw_device_t** hw_device)
{
    ......省略代码......
    QCamera2HardwareInterface *hw =
        new QCamera2HardwareInterface((uint32_t)cameraId);
    if (!hw) {
        LOGE("Allocation of hardware interface failed");
        return NO_MEMORY;
    }
    rc = hw->openCamera(hw_device);
    if (rc != NO_ERROR) {
        delete hw;
    }
    ......省略代码......
}

int QCamera2Factory::cameraDeviceOpen(int camera_id,
                    struct hw_device_t **hw_device)
{
    ......省略代码......
    QCamera3HardwareInterface *hw = new QCamera3HardwareInterface(mHalDescriptors[camera_id].cameraId,
            mCallbacks);
    if (!hw) {
        LOGE("Allocation of hardware interface failed");
        return NO_MEMORY;
    }
    rc = hw->openCamera(hw_device);
    if (rc != 0) {
        delete hw;
    }
    ......省略代码......
}

可以看到,一个是QCamera2HardwareInterface一个是QCamera3HardwareInterface
测试发现:
骁龙相机调用的openLegacy会跑QCamera2HardwareInterface
我们自定义的相机会通过Camera2Client会跑到QCamera3HardwareInterface
我们拿QCamera3HardwareInterface来看
从这里开始进入HAL3的流程

HAL3

QCamera3HardwareInterface定义在
hardware\qcom\camera\QCamera2\HAL3\QCamera3HWI.h
我们直接看下openCamera

hardware\qcom\camera\QCamera2\HAL3\QCamera3HWI.cpp
int QCamera3HardwareInterface::openCamera(struct hw_device_t **hw_device)
{
    int rc = 0;
    if (mState != CLOSED) {
        *hw_device = NULL;
        return PERMISSION_DENIED;
    }

    m_perfLock.lock_acq();
    LOGI("[KPI Perf]: E PROFILE_OPEN_CAMERA camera id %d",
             mCameraId);

    rc = openCamera();
    if (rc == 0) {
        *hw_device = &mCameraDevice.common;
    } else
        *hw_device = NULL;

    m_perfLock.lock_rel();
    LOGI("[KPI Perf]: X PROFILE_OPEN_CAMERA camera id %d, rc: %d",
             mCameraId, rc);

    if (rc == NO_ERROR) {
        mState = OPENED;
    }
    return rc;
}

int QCamera3HardwareInterface::openCamera()
{
    int rc = 0;
    
    ......省略代码......

    rc = camera_open((uint8_t)mCameraId, &mCameraHandle);
    if (rc) {
        LOGE("camera_open failed. rc = %d, mCameraHandle = %p", rc, mCameraHandle);
        return rc;
    }
    ......省略代码......
}
camera_open
hardware\qcom\camera\QCamera2\stack\mm-camera-interface\src\mm_camera_interface.c
int32_t camera_open(uint8_t camera_idx, mm_camera_vtbl_t **camera_vtbl)
{
    int32_t rc = 0;
    mm_camera_obj_t *cam_obj = NULL;

#ifdef QCAMERA_REDEFINE_LOG
    mm_camera_set_dbg_log_properties();
#endif
    LOGE("E camera_idx = %d\n", camera_idx);
    LOGD("E camera_idx = %d\n", camera_idx);
    if (camera_idx >= g_cam_ctrl.num_cam) {
        LOGE("Invalid camera_idx (%d)", camera_idx);
        return -EINVAL;
    }

    pthread_mutex_lock(&g_intf_lock);
    /* opened already */
    if(NULL != g_cam_ctrl.cam_obj[camera_idx]) {
        /* Add reference */
        g_cam_ctrl.cam_obj[camera_idx]->ref_count++;
        pthread_mutex_unlock(&g_intf_lock);
        LOGD("opened alreadyn");
        *camera_vtbl = &g_cam_ctrl.cam_obj[camera_idx]->vtbl;
        return rc;
    }

    cam_obj = (mm_camera_obj_t *)malloc(sizeof(mm_camera_obj_t));
    if(NULL == cam_obj) {
        pthread_mutex_unlock(&g_intf_lock);
        LOGE("no mem");
        return -EINVAL;
    }

    /* initialize camera obj */
    memset(cam_obj, 0, sizeof(mm_camera_obj_t));
    cam_obj->ctrl_fd = -1;
    cam_obj->ds_fd = -1;
    cam_obj->ref_count++;
    cam_obj->my_hdl = mm_camera_util_generate_handler(camera_idx);
    cam_obj->vtbl.camera_handle = cam_obj->my_hdl; /* set handler */
    cam_obj->vtbl.ops = &mm_camera_ops;
    pthread_mutex_init(&cam_obj->cam_lock, NULL);
    /* unlock global interface lock, if not, in dual camera use case,
      * current open will block operation of another opened camera obj*/
    pthread_mutex_lock(&cam_obj->cam_lock);
    pthread_mutex_unlock(&g_intf_lock);

    rc = mm_camera_open(cam_obj);

    pthread_mutex_lock(&g_intf_lock);
    if (rc != 0) {
        LOGE("mm_camera_open err = %d", rc);
        pthread_mutex_destroy(&cam_obj->cam_lock);
        g_cam_ctrl.cam_obj[camera_idx] = NULL;
        free(cam_obj);
        cam_obj = NULL;
        pthread_mutex_unlock(&g_intf_lock);
        *camera_vtbl = NULL;
        return rc;
    } else {
        LOGD("Open succeded\n");
        g_cam_ctrl.cam_obj[camera_idx] = cam_obj;
        pthread_mutex_unlock(&g_intf_lock);
        *camera_vtbl = &cam_obj->vtbl;
        return 0;
    }
}
mm_camera_open
hardware\qcom\camera\QCamera2\stack\mm-camera-interface\src\mm_camera.c
int32_t mm_camera_open(mm_camera_obj_t *my_obj)
{
    char dev_name[MM_CAMERA_DEV_NAME_LEN];
    int32_t rc = 0;
    int8_t n_try=MM_CAMERA_DEV_OPEN_TRIES;
    uint8_t sleep_msec=MM_CAMERA_DEV_OPEN_RETRY_SLEEP;
    int cam_idx = 0;
    const char *dev_name_value = NULL;
    int l_errno = 0;
    pthread_condattr_t cond_attr;

    LOGD("begin\n");

    if (NULL == my_obj) {
        goto on_error;
    }
    dev_name_value = mm_camera_util_get_dev_name(my_obj->my_hdl);
    if (NULL == dev_name_value) {
        goto on_error;
    }
    snprintf(dev_name, sizeof(dev_name), "/dev/%s",
             dev_name_value);
    sscanf(dev_name, "/dev/video%d", &cam_idx);
    LOGD("dev name = %s, cam_idx = %d", dev_name, cam_idx);

    do{
        n_try--;
        errno = 0;
        my_obj->ctrl_fd = open(dev_name, O_RDWR | O_NONBLOCK);
        l_errno = errno;
        LOGD("ctrl_fd = %d, errno == %d", my_obj->ctrl_fd, l_errno);
        if((my_obj->ctrl_fd >= 0) || (errno != EIO && errno != ETIMEDOUT) || (n_try <= 0 )) {
            break;
        }
        LOGE("Failed with %s error, retrying after %d milli-seconds",
              strerror(errno), sleep_msec);
        usleep(sleep_msec * 1000U);
    }while (n_try > 0);
    ......省略代码......
}

通过open(dev_name, O_RDWR | O_NONBLOCK)来打开相机设备,接下来就会调用到Kernel层的代码

我们先看看这个dev_name_value 是怎么获取的
dev_name_value = mm_camera_util_get_dev_name(my_obj->my_hdl);

hardware\qcom\camera\QCamera2\stack\mm-camera-interface\src\mm_camera_interface.c
const char *mm_camera_util_get_dev_name(uint32_t cam_handle)
{
    char *dev_name = NULL;
    uint8_t cam_idx = mm_camera_util_get_index_by_handler(cam_handle);
    if(cam_idx < MM_CAMERA_MAX_NUM_SENSORS) {
        dev_name = g_cam_ctrl.video_dev_name[cam_idx];
    }
    return dev_name;
}

这里面看到先得到cam_idx

uint8_t mm_camera_util_get_index_by_handler(uint32_t handler)
{
    return (handler&0x000000ff);
}

这里得到相机的id号,就是我们常见的0、1,然后通过g_cam_ctrl.video_dev_name[cam_idx];获取dev_name
我们看一下这个
static mm_camera_ctrl_t g_cam_ctrl;

hardware\qcom\camera\QCamera2\stack\mm-camera-interface\inc\mm_camera.h
typedef struct {
    int8_t num_cam;
    mm_camera_shim_ops_t cam_shim_ops;
    char video_dev_name[MM_CAMERA_MAX_NUM_SENSORS][MM_CAMERA_DEV_NAME_LEN];
    mm_camera_obj_t *cam_obj[MM_CAMERA_MAX_NUM_SENSORS];
    struct camera_info info[MM_CAMERA_MAX_NUM_SENSORS];
    cam_sync_type_t cam_type[MM_CAMERA_MAX_NUM_SENSORS];
    cam_sync_mode_t cam_mode[MM_CAMERA_MAX_NUM_SENSORS];
    uint8_t is_yuv[MM_CAMERA_MAX_NUM_SENSORS]; // 1=CAM_SENSOR_YUV, 0=CAM_SENSOR_RAW
} mm_camera_ctrl_t;

看一下初始化的地方

uint8_t get_num_of_cameras()
{
    ......省略代码......    
    while (1) {
        uint32_t num_entities = 1U;
        char dev_name[32];

        snprintf(dev_name, sizeof(dev_name), "/dev/media%d", num_media_devices);
        LOGD("g_cam_ctrl dev_name: %s\n", dev_name);
        dev_fd = open(dev_name, O_RDWR | O_NONBLOCK);
        ......省略代码......
        while (1) {
            struct media_entity_desc entity;
            memset(&entity, 0, sizeof(entity));
            entity.id = num_entities++;
            rc = ioctl(dev_fd, MEDIA_IOC_ENUM_ENTITIES, &entity);
            if (rc < 0) {
                LOGD("Done enumerating media entities\n");
                rc = 0;
                break;
            }
            if(entity.type == MEDIA_ENT_T_DEVNODE_V4L && entity.group_id == QCAMERA_VNODE_GROUP_ID) {
                strlcpy(g_cam_ctrl.video_dev_name[num_cameras],
                     entity.name, sizeof(entity.name));
                LOGI("dev_info[id=%d,name='%s']\n",
                    (int)num_cameras, g_cam_ctrl.video_dev_name[num_cameras]);
                num_cameras++;
                break;
            }
        }
        close(dev_fd);
        dev_fd = -1;
        if (num_cameras >= MM_CAMERA_MAX_NUM_SENSORS) {
            LOGW("Maximum number of camera reached %d", num_cameras);
            break;
        }
    }
    g_cam_ctrl.num_cam = num_cameras;
    ......省略代码......    
}

这个方法在开机的时候会执行一次

相关文章

  • 相机——打开流程

    Framework 主要的初始化在cameraInitNormal中 最终调用到了native_setup的jni...

  • camera2简介

    新相机有套路,按照一下流程打开 1、打开相机,需要获取权限(代码中获取) 2、创建相机会话 在打开相机回调中创建 ...

  • 相机——解决多摄像头id错乱的问题

    我们在之前的文章中,通过相机的打开流程,知道,相机的id号,就是我们Camera.open(cameraid)里的...

  • MediaCodec 硬编码

    一:基本流程 MediaCodec编码视屏主要分三步: 1:打开相机,接收相机拿到的数据 2:初始化MediaCo...

  • 详记Android打开相机拍照流程

    写在前面 本文并不是基于Camera2的,所以想要了解Camera2的同学可以先散了。文题加了详记二字,因为相机整...

  • 相机相册的正确打开方式

    ** 直接上代码: ** 导入 一个金典的宏定义 打开相册的完整流程 打开相机的完整流程(或者是仅仅获取相册中的图...

  • PhotoScan 使用

    打开软件---工作流程--添加照片 添加照片完成之后 完成之后 文件---导出---导出相机---file_na...

  • chapter1

    内置渲染管线大致流程 这里是单个相机的流程,但如果有多个相机的话每个都会运行一遍对应的流程。再叠加前每个相机都会有...

  • 系统SDK介绍-02

    系统SDK介绍 打开相册选择图片 打开相册选择视频 打开相机拍摄图片 打开相机拍摄视频 配置权限: 在info.p...

  • 打开相机 打开相册 头像上传

    首相一定要注意处理权限问题 1.在AndroidManifest.xml(清单文件) 给的访问权限。

网友评论

      本文标题:相机——打开流程

      本文链接:https://www.haomeiwen.com/subject/eprtqktx.html