Adaptation of Hal layer in camera display (1)

King of heaven and earth tiger 626 2021-04-02 22:41:11 阅读数:999

本文一共[544]字,预计阅读时长:1分钟~
adaptation hal layer camera display

This article goes on to the previous one :
Camera Show it Framework Layer settings display window
The last one said

else if ( window == 0 ) {  
        result = mHardware->setPreviewWindow(window);// take window Set to hal layer , Android The real implementation of the code architecture ends here ,hal Layer of things depends on the specific manufacturers according to their own situation to achieve .   } 

What the hell is that mHardware How and hal It's connected ?


1. stay CameraClient.cpp in :

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);// Notice here .
    res = mHardware->initialize(&module->common);// Notice here
    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;
}

From the code snippet :
mHardware = new CameraHardwareInterface(camera_device_name);// Notice here .

mHardware Is defined as CameraHardwareInterface, He is also Android The general interface of . All the functions provided by various manufacturers should be passed CameraHardwareInterface Adaptive direction CameraService Provide hardware operation interface .

The theme of this article is to share CameraHardwareInterface How to adapt .
2. next 1 Code snippet in :

res = mHardware->initialize(&module->common);// involves module,module That is to say CameraClient::initialize(camera_module_t *module) Parameters passed in , A pointer to a struct variable .

CameraClient::initialize(camera_module_t *module) The place to call is CameraService in connect camera Called when :
 
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) {// Call it here CameraClient Of initialize, The parameter passed in is mModule.
#ifdef  MTK_CAMERAPROFILE_SUPPORT
        CPTLogStr(Event_CS_newCamHwIF, CPTFlagEnd,  "new CameraHardwareInterface failed");
#endif  
#ifdef  MTK_CAMERA_BSP_SUPPORT

So here we focus on mModule This member , mModule The definition of :
    Mutex               mSoundLock;
    sp<MediaPlayer>     mSoundPlayer[NUM_SOUNDS];
    int                 mSoundRef;  // reference count (release all MediaPlayer when 0)
 
    camera_module_t *mModule;//
For one camera_module_t Pointer to the structure variable .

Camera The first place to be used is in onFirstRef() Function , Here, it's mainly initialization mModule Some variables of . as for onFirstRef When to call , Follow up and share , Here, just remember , This is and sp dependent , And building sp It will call . You can refer to this blog :http://blog.csdn.net/gzzaigcnforever/article/details/20649781


void CameraService::onFirstRef()
{
    BnCameraService::onFirstRef();
 
    if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,// This is defined as "came"
                (const hw_module_t **)&mModule) < 0) {// Notice the function call
        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 by camera, inst by null, So now 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, Generate the file name according to the configuration value of the property .
 
            if (access(path, R_OK) == 0) break;// Determine whether you have read file permission .
 
            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);// Dynamic loading dynamic library .
    }
 
    return status;
}

The idea above is :

Traverse

#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
#define HAL_LIBRARY_PATH3 "/system/lib"
These are the contents of so library ,so The name of the library is : a.camera. Property name .so and b.camera.default.so. Among them, priority will be given to finding a, I didn't find a I'll find it later b. stay mtk On the platform , Compile generated so The library is for camera.default.so, So the final load will be camera.default.so This library .

Keep looking. :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);// Focus on these two sentences
    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;
}
 
Focus on these two sentences :
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
    hmi = (struct hw_module_t *)dlsym(handle, sym);// Focus on these two sentences
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"
It can be seen from the above that we want to be named “HMI” Pointer to function , and HMI again HAL_MODULE_INFO_SYM The macro definition of , So the ultimate goal is to find HAL_MODULE_INFO_SYM Where it comes true :

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

The above code fragment is mtk Realized , Combined with the above , You can get *pHmi Yes module This structure . That is to say, in the end *pHmi It's pointing here module. Go back to the top , Namely CameraService Medium mModule It's pointing to module. So the following quotation is probably CameraService Pass through mModule->common->methods This way to or mModule->get_number_of_cameras To MTK Of hal Layer call . This will be Android Native CameraService adopt CameraHardwareInterface Connect to MTK Realized Hal layer , adopt CamDeviceManager To connect the preceding and the following .
3. continue 2 Focus on CamDeviceManager::get_module_methods() This function :

hw_module_methods_t*
CamDeviceManager::
get_module_methods()
{
    static
    hw_module_methods_t
    _methods =
    {
        open:   CamDeviceManager::open_device
    };
 
    return  &_methods;
}
ha-ha , You can see through mModule->common->methods-->open You can refer to CamDeviceManager::open_device.

You can guess from the name that this method should be in Camera When it starts, it will call .
So let's see when to call CamDeviceManager::open_device This method :


go back to 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);// It's initialized here , And the incoming module->common


go back to 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);// It's opened here camera The operation of , What is called here is already MTK hal Layer method , Notice the last parameter .
        if (rc != OK) {
            ALOGE("Could not open camera %s: %d", mName.string(), rc);
            return rc;
        }
        initHalPreviewWindow();
        return rc;
    }

Focus on 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
        );// Notice here , Conduct camDevice The creation of
        //
        if  ( ! pdev )
        {
            MY_LOGE("camera device allocation fail: pdev(0)");
            err = -ENOMEM;
            goto lbExit;
        }
 
        *device = pdev->get_hw_device();// Here will be CamDevice The pointer to the input parameter , In the end CameraHardwareInterface Medium mDevice Yes CamDevice.
        //
        mi4OpenNum++;
    }
 
lbExit:
    if  ( OK != err )
    {
        if  ( pdev )
        {
            destroyDevice(pdev);
            pdev = NULL;
        }
        //
        *device = NULL;
    }
    MY_LOGI("- mi4OpenNum(%d)", mi4OpenNum);
    return  err;
}
4. Continue to focus on

 pdev = createIDevice(
            i4OpenId, 
            *get_hw_device(), 
            module
        );
The implementation of the :
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 It points to ICamDevice An object of
    //
    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() )// It's initialized here ICamDvice
        {
            MY_LOGE("fail to initialize a newly-created instance");
            pdev->uninit();
            pdev = NULL;
        }
    }
    //
    MY_LOGI("- created instance=%p", &(*pdev));
    return  pdev;// Return to the created ICamDevice.
}

Now it can be concluded that pdev That is pointing. ICamDevice object

be aware ICamDevice Object's constructor :

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 Yes mDevOps
    mDevOps     = gCameraDevOps;//mDevOps by gCameraDevOps Pointing to the structure
}

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, 
 
};

So in CameraHardwareInterface Pass through :
mDevice->ops->set_preview_window(mDevice, 0) Similar methods can be called to ICamDevice The corresponding method in .


5. We go back to Camera Show related things ,

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

And then in CameraHardwareInterface in :

 /** 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);// Call directly ICamDevice Related methods of .
                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. Speaking of this , CameraService::CameraClient--->CameraHardwareInterface-->CamDeviceManager-->ICamDevice This whole route is very clear .

The specific idea is :

a.CameraHardwareInterface yes Android Native definition and hardware hal Layer connection adapter interface . Each manufacturer implements these interfaces according to their needs , And specific implementation of the underlying functions .

b. For code commonality and module separation , Yes hal The implementation of layer module is encapsulated as dynamic library (so), CameraService Load dynamically as needed hal Layer Library .

c.CamDeviceManager yes Hal An entry class to the layer , from CameraService Open and close camera It is through it that we make the general arrangement .

d.hal The specific implementation under the layer is continuous adaptation CameraHardwareInterface A process of providing an interface up .

Attach with an open Camera For your reference :

 

版权声明:本文为[King of heaven and earth tiger 626]所创,转载请带上原文链接,感谢。 https://netfreeman.com/2021/04/20210402005332041H.html