Camera显示之Hal层的适配(一)

天王盖地虎626 2021-04-02 00:53:51 阅读数:961

本文一共[544]字,预计阅读时长:1分钟~
openid sym

本篇接着上一篇:
Camera显示之Framework层设置显示窗口
话说上一篇说道

else if ( window == 0 ) {  
        result = mHardware->setPreviewWindow(window);//将window设置到hal层, Android代码架构真正的实现就止于此,hal层的东西就看具体厂家根据自身情况进行实现了。   } 

那究竟mHardware是如何和hal联系起来的的呢?


1.在CameraClient.cpp中:

status_t CameraClient::initialize(camera_module_t *module) {
    int callingPid = getCallingPid();
    LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
 
    char camera_device_name[10];
    status_t res;
    snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
 
    mHardware = new CameraHardwareInterface(camera_device_name);//注意到此处。
    res = mHardware->initialize(&module->common);//注意此处
    if (res != OK) {
        ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        mHardware.clear();
        return NO_INIT;
    }
 
    mHardware->setCallbacks(notifyCallback,
            dataCallback,
            dataCallbackTimestamp,
            (void *)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);
 
//!++
#ifdef  MTK_CAMERA_BSP_SUPPORT
    // Enable MTK-extended messages by default
    enableMsgType(MTK_CAMERA_MSG_EXT_NOTIFY | MTK_CAMERA_MSG_EXT_DATA);
#endif
//!--
 
    LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);
    return OK;
}

从代码片段:
mHardware = new CameraHardwareInterface(camera_device_name);//注意到此处。

mHardware 定义是 CameraHardwareInterface, 他也是Android的通用接口。 各个厂家提供的功能都要通过CameraHardwareInterface适配向CameraService提供硬件操作接口。

这篇的主题就是主要分享CameraHardwareInterface如何进行适配的。
2. 接着1中的代码片段:

res = mHardware->initialize(&module->common);//涉及到module,module即为CameraClient::initialize(camera_module_t *module)传进来的参数, 为一个结构体变量的指针。

CameraClient::initialize(camera_module_t *module)调用的地方为CameraService中connect camera的时候调用:
 
sp<ICamera> CameraService::connect(
        const sp<ICameraClient>& cameraClient, int cameraId) {
#ifdef  MTK_CAMERAPROFILE_SUPPORT
    initCameraProfile(); 
    AutoCPTLog cptlog(Event_CS_connect);
#endif
    int callingPid = getCallingPid();
 
    LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);
 
    if (!mModule) {
        ALOGE("Camera HAL module not loaded");
...........................
............................
 
#endif
 
    if (client->initialize(mModule) != OK) {//在这里调用CameraClient的initialize, 而传入的参数为mModule。
#ifdef  MTK_CAMERAPROFILE_SUPPORT
        CPTLogStr(Event_CS_newCamHwIF, CPTFlagEnd,  "new CameraHardwareInterface failed");
#endif  
#ifdef  MTK_CAMERA_BSP_SUPPORT

所以这里我们就关注下mModule这成员, mModule的定义:
    Mutex               mSoundLock;
    sp<MediaPlayer>     mSoundPlayer[NUM_SOUNDS];
    int                 mSoundRef;  // reference count (release all MediaPlayer when 0)
 
    camera_module_t *mModule;//
为一个camera_module_t结构体变量的指针。

Camera最先被使用到的地方是在onFirstRef()函数中, 在这里主要是初始化了mModule的一些变量。 至于onFirstRef何时调用, 后续进行相关的分享, 这里大家只要记住,这个是和sp相关的, 并且在构建sp的时候就会调用。 可以参考这位的博客:http://blog.csdn.net/gzzaigcnforever/article/details/20649781


void CameraService::onFirstRef()
{
    BnCameraService::onFirstRef();
 
    if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,//这个定义为"came"
                (const hw_module_t **)&mModule) < 0) {//注意这个函数调用
        ALOGE("Could not load camera HAL module");
        mNumberOfCameras = 0;
    }
    else {
        mNumberOfCameras = mModule->get_number_of_cameras();
        if (mNumberOfCameras > MAX_CAMERAS) {
            ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
                    mNumberOfCameras, MAX_CAMERAS);
            mNumberOfCameras = MAX_CAMERAS;
        }
        for (int i = 0; i < mNumberOfCameras; i++) {
            setCameraFree(i);
        }
    }
}
 
 
 
/** Base path of the hal modules */
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
#define HAL_LIBRARY_PATH3 "/system/lib"
 
 
int hw_get_module(const char *id, const struct hw_module_t **module)
{
    return hw_get_module_by_class(id, NULL, module);
}
 
 
int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    int status;
    int i;
    const struct hw_module_t *hmi = NULL;
    char prop[PATH_MAX];
    char path[PATH_MAX];
    char name[PATH_MAX];
 
    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);//class_id为camera, inst为null, 所以现在name=“camera”
    else
        strlcpy(name, class_id, PATH_MAX);
 
    /*
     * Here we rely on the fact that calling dlopen multiple times on
     * the same .so will simply increment a refcount (and not load
     * a new copy of the library).
     * We also assume that dlopen() is thread-safe.
     */
 
    /* Loop through the configuration variants looking for a module */
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
        if (i < HAL_VARIANT_KEYS_COUNT) {
            if (property_get(variant_keys[i], prop, NULL) == 0) {
                continue;
            }
            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH2, name, prop);//path=/vendor/lib/hw/camera.**.so, 根据属性的配置值生成文件名。
 
            if (access(path, R_OK) == 0) break;//判断是否有读文件权限。
 
            snprintf(path, sizeof(path), "%s/%s.%s.so",//path=/system/lib/hw/camera.**.so
                     HAL_LIBRARY_PATH1, name, prop);
            if (access(path, R_OK) == 0) break;
 
            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH3, name, prop);//path=/system/lib/camera.**.so
            if (access(path, R_OK) == 0) break;
        } else {
            snprintf(path, sizeof(path), "%s/%s.default.so",
                     HAL_LIBRARY_PATH1, name);//path=/vendor/lib/hw/camera.default.so
            if (access(path, R_OK) == 0) break;
 
            snprintf(path, sizeof(path), "%s/%s.default.so",//path=/system/lib/camera.default.so
                     HAL_LIBRARY_PATH3, name);
            if (access(path, R_OK) == 0) break;
        }
    }
 
    status = -ENOENT;
    if (i < HAL_VARIANT_KEYS_COUNT+1) {
        /* load the module, if this fails, we're doomed, and we should not try
         * to load a different variant. */
        status = load(class_id, path, module);//动态加载动态库。
    }
 
    return status;
}

上面的思路就是:

遍历

#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
#define HAL_LIBRARY_PATH3 "/system/lib"
这几个目录下的so库,so库的名字为: a.camera.属性名.so和b.camera.default.so。 其中会优先找到a, 在没找到a后再去找到b。 在mtk平台上, 编译生成的so库就为 camera.default.so, 所以最终加载的会是camera.default.so这个库。

继续看看:load(class_id, path, module);:

static int load(const char *id,
        const char *path,
        const struct hw_module_t **pHmi)
{
    int status;
    void *handle;
    struct hw_module_t *hmi;
 
    /*
     * load the symbols resolving undefined symbols before
     * dlopen returns. Since RTLD_GLOBAL is not or'd in with
     * RTLD_NOW the external symbols will not be global
     */
    handle = dlopen(path, RTLD_NOW);
    if (handle == NULL) {
        char const *err_str = dlerror();
        ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
        status = -EINVAL;
        goto done;
    }
 
    /* Get the address of the struct hal_module_info. */
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
    hmi = (struct hw_module_t *)dlsym(handle, sym);//关注这两句
    if (hmi == NULL) {
        ALOGE("load: couldn't find symbol %s", sym);
        status = -EINVAL;
        goto done;
    }
 
    /* Check that the id matches */
    if (strcmp(id, hmi->id) != 0) {
        ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
        status = -EINVAL;
        goto done;
    }
 
    hmi->dso = handle;
 
    /* success */
    status = 0;
 
    done:
    if (status != 0) {
        hmi = NULL;
        if (handle != NULL) {
            dlclose(handle);
            handle = NULL;
        }
    } else {
        ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
                id, path, *pHmi, handle);
    }
 
    *pHmi = hmi;
 
    return status;
}
 
关注这两句:
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
    hmi = (struct hw_module_t *)dlsym(handle, sym);//关注这两句
HAL_MODULE_INFO_SYM_AS_STR:
/**
 * Name of the hal_module_info
 */
#define HAL_MODULE_INFO_SYM         HMI
 
/**
 * Name of the hal_module_info as a string
 */
#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"
从上面可以看出就是要获取名为“HMI”函数的指针, 而HMI又是HAL_MODULE_INFO_SYM 的宏定义, 所以最终就是要找HAL_MODULE_INFO_SYM实现的地方:

static
camera_module
instantiate_camera_module()
{
    CAM_LOGD("[%s]", __FUNCTION__);
    //
    //  (1) Prepare One-shot init.
    MtkCamUtils::Property::clear();
 
    //  (2)
    camera_module module = {
        common: {
             tag:                   HARDWARE_MODULE_TAG,
             module_api_version:    1,
             hal_api_version:       0,
             id:                    CAMERA_HARDWARE_MODULE_ID,
             name:                  "MTK Camera Module",
             author:                "MTK",
             methods:               CamDeviceManager::get_module_methods(),
             dso:                   NULL, 
             reserved:              {0}, 
        }, 
        get_number_of_cameras:  CamDeviceManager::get_number_of_cameras, 
        get_camera_info:        CamDeviceManager::get_camera_info, 
    };
    return  module;
}
 
 
/*******************************************************************************
* Implementation of camera_module
*******************************************************************************/
camera_module HAL_MODULE_INFO_SYM = instantiate_camera_module();

上面这个代码片段就是mtk实现的, 结合上边, 可以得到*pHmi指向了module这个结构体。 也即是说最后将*pHmi指向这里的module。 进一步回到上面, 就是CameraService中的mModule指向了这里的module。所以说后面的引用大概是CameraService中通过mModule->common->methods这种方式去或则mModule->get_number_of_cameras实现到MTK的hal层的调用。 这样就将Android原生CameraService通过CameraHardwareInterface连接到MTK实现的Hal层, 通过CamDeviceManager来承上启下的作用。
3.继续2关注到CamDeviceManager::get_module_methods()这个函数:

hw_module_methods_t*
CamDeviceManager::
get_module_methods()
{
    static
    hw_module_methods_t
    _methods =
    {
        open:   CamDeviceManager::open_device
    };
 
    return  &_methods;
}
呵呵, 可以看到通过mModule->common->methods-->open可以引用到CamDeviceManager::open_device。

通过名字可以猜测到这个方法应该是在Camera启动的时候会去调用。
所以我们看看何时调用CamDeviceManager::open_device这个方法:


回到CameraService:CameraClient:

status_t CameraClient::initialize(camera_module_t *module) {
    int callingPid = getCallingPid();
    LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
 
    char camera_device_name[10];
    status_t res;
    snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
 
    mHardware = new CameraHardwareInterface(camera_device_name);
    res = mHardware->initialize(&module->common);//这里初始化了, 并且传入的module->common


回到CameraHardwareInterface:

status_t initialize(hw_module_t *module)
    {
        ALOGI("Opening camera %s", mName.string());
        int rc = module->methods->open(module, mName.string(),
                                       (hw_device_t **)&mDevice);//这里进行了打开camera的操作, 这里调用到的已经是MTK hal层的方法了, 注意最后一个参数。
        if (rc != OK) {
            ALOGE("Could not open camera %s: %d", mName.string(), rc);
            return rc;
        }
        initHalPreviewWindow();
        return rc;
    }

关注到CamDeviceManager::open_device
int
CamDeviceManager::
open_device(const hw_module_t* module, const char* name, hw_device_t** device)
{
    return  CamDeviceManager::getInstance().openDevice(module, name, device);
}
 
 
int
CamDeviceManager::
openDevice(const hw_module_t* module, const char* name, hw_device_t** device)
{
    int err = OK;
    //
    ICamDevice* pdev = NULL;
    int32_t     i4OpenId = 0;
    //
    Mutex::Autolock lock(mMtxOpenLock);
    //
    MY_LOGI("+ mi4OpenNum(%d), mi4DeviceNum(%d)", mi4OpenNum, mi4DeviceNum);
 
    if (name != NULL)
    {
        i4OpenId = ::atoi(name);
        //
        if  ( DevMetaInfo::queryNumberOfDevice() < i4OpenId )
        {
            err = -EINVAL;
            goto lbExit;
        }
        //
        if  ( MAX_SIMUL_CAMERAS_SUPPORTED <= mi4OpenNum )
        {
            MY_LOGW("open number(%d) >= maximum number(%d)", mi4OpenNum, MAX_SIMUL_CAMERAS_SUPPORTED);
            MY_LOGE("does not support multi-open");
            err = -ENOMEM;
            goto lbExit;
        }
        //
        pdev = createIDevice(
            i4OpenId, 
            *get_hw_device(), 
            module
        );//注意此处, 进行camDevice的创建
        //
        if  ( ! pdev )
        {
            MY_LOGE("camera device allocation fail: pdev(0)");
            err = -ENOMEM;
            goto lbExit;
        }
 
        *device = pdev->get_hw_device();//此处将CamDevice的指针付给传进来形参, 最终是CameraHardwareInterface中的mDevice指向了CamDevice。
        //
        mi4OpenNum++;
    }
 
lbExit:
    if  ( OK != err )
    {
        if  ( pdev )
        {
            destroyDevice(pdev);
            pdev = NULL;
        }
        //
        *device = NULL;
    }
    MY_LOGI("- mi4OpenNum(%d)", mi4OpenNum);
    return  err;
}
4.继续往下关注到

 pdev = createIDevice(
            i4OpenId, 
            *get_hw_device(), 
            module
        );
的实现:
static
ICamDevice*
createIDevice(
    int32_t const           i4DevOpenId, 
    hw_device_t const&      hwdevice, 
    hw_module_t const*const hwmodule
)
{
    g_s8ClientAppMode = queryClientAppMode();
    //
    MY_LOGI("+ tid:%d OpenID:%d ClientAppMode:%s", ::gettid(), i4DevOpenId, g_s8ClientAppMode.string());
    //
    ICamDevice* pdev = NSCamDevice::createDevice(g_s8ClientAppMode, i4DevOpenId);//pDeve 指向的就是ICamDevice的一个对象
    //
    if  ( pdev != 0 )
    {
        pdev->incStrong(pdev);
        //
        hw_device_t* hwdev = pdev->get_hw_device();//
        *hwdev = hwdevice;
        hwdev->module = const_cast<hw_module_t*>(hwmodule);
        //
        if  ( ! pdev->init() )//在这里初始化了ICamDvice
        {
            MY_LOGE("fail to initialize a newly-created instance");
            pdev->uninit();
            pdev = NULL;
        }
    }
    //
    MY_LOGI("- created instance=%p", &(*pdev));
    return  pdev;//返回创建的ICamDevice。
}

现在可以得出pdev即是指向ICamDevice对象

注意到ICamDevice对象的构造函数:

ICamDevice::
ICamDevice()
    : camera_device_t()
    , RefBase()
    , mDevOps()
    //
    , mMtxLock()
    //
{
    MY_LOGD("ctor");
    ::memset(static_cast<camera_device_t*>(this), 0, sizeof(camera_device_t));
    this->priv  = this;
    this->ops   = &mDevOps;//ops指向了mDevOps
    mDevOps     = gCameraDevOps;//mDevOps为gCameraDevOps指向的结构体
}

gCameraDevOps:
static camera_device_ops_t const gCameraDevOps = {
    set_preview_window:         camera_set_preview_window, 
    set_callbacks:              camera_set_callbacks, 
    enable_msg_type:            camera_enable_msg_type, 
    disable_msg_type:           camera_disable_msg_type, 
    msg_type_enabled:           camera_msg_type_enabled, 
    start_preview:              camera_start_preview, 
    stop_preview:               camera_stop_preview, 
    preview_enabled:            camera_preview_enabled, 
    store_meta_data_in_buffers: camera_store_meta_data_in_buffers, 
    start_recording:            camera_start_recording, 
    stop_recording:             camera_stop_recording, 
    recording_enabled:          camera_recording_enabled, 
    release_recording_frame:    camera_release_recording_frame, 
    auto_focus:                 camera_auto_focus, 
    cancel_auto_focus:          camera_cancel_auto_focus, 
    take_picture:               camera_take_picture, 
    cancel_picture:             camera_cancel_picture, 
    set_parameters:             camera_set_parameters, 
    get_parameters:             camera_get_parameters, 
    put_parameters:             camera_put_parameters, 
    send_command:               camera_send_command, 
    release:                    camera_release, 
    dump:                       camera_dump, 
 
};

所以在CameraHardwareInterface中通过:
mDevice->ops->set_preview_window(mDevice, 0)类似的方法就可以调用到ICamDevice中对应的方法了。


5. 我们回到Camera显示相关的东西,

在CameraClient中//!++
    else if ( window == 0 ) {
        result = mHardware->setPreviewWindow(window);
    }

进而在CameraHardwareInterface中:

 /** Set the ANativeWindow to which preview frames are sent */
    status_t setPreviewWindow(const sp<ANativeWindow>& buf)
    {
        ALOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get());
 
        if (mDevice->ops->set_preview_window) {
            //!++
            if  ( buf == 0 ) {
                ALOGD("set_preview_window(0) before mPreviewWindow = 0");
                mDevice->ops->set_preview_window(mDevice, 0);//直接调用了ICamDevice的相关的方法。
                mPreviewWindow = 0;
                return  OK;
            }
            //!--
            mPreviewWindow = buf;
            mHalPreviewWindow.user = this;
            ALOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p", __FUNCTION__,
                    &mHalPreviewWindow, mHalPreviewWindow.user);
            return mDevice->ops->set_preview_window(mDevice,
                    buf.get() ? &mHalPreviewWindow.nw : 0);
        }
        return INVALID_OPERATION;
    }

5.说到这里, CameraService::CameraClient--->CameraHardwareInterface-->CamDeviceManager-->ICamDevice这一条完整的路线非常清楚。

具体思路就是:

a.CameraHardwareInterface是Android原生定义的和硬件hal层连接的适配接口。各个厂家根据需要去具体实现这些接口,并具体实现底层的相关功能。

b.为了代码通用性和模块的分离性, 对hal层模块的实现封装成动态库(so), CameraService根据需要动态加载hal层的库。

c.CamDeviceManager是Hal层的一个入口类, 从CameraService打开关闭camera的时候都是通过它进行总的安排。

d.hal层下具体的实现都是不断的适配CameraHardwareInterface向上提供的接口的一个过程。

附上以一个打开Camera的流程图供参考:

 

版权声明:本文为[天王盖地虎626]所创,转载请带上原文链接,感谢。 https://my.oschina.net/u/920274/blog/5006047