1. 程式人生 > >Camera顯示之Hal層的適配(一)

Camera顯示之Hal層的適配(一)

本篇接著上一篇:

話說上一篇說道

elseif ( 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的流程圖供參考:


相關推薦

Camera顯示Hal()

本篇接著上一篇: 話說上一篇說道 elseif ( window == 0 ) {           result = mHardware->setPreviewWindow(window);//將window設定到hal層, Android程式碼架構真正的實現就

相容iOS 10 _升級xcode8_()

轉自:http://www.jianshu.com/p/0cc7aad638d9 字數2646  閱讀18217  評論103  喜歡515 1.Notification(通知) 自從N

Android開發HAL

本文摘自 羅昇陽的《Anroid系統原始碼情景分析》,更新至Android7.0分析 一、概念 一、Android系統為硬體抽象層中的模組介面定義了編寫規範,我們必須按照這個規範來編寫自己的硬體模組介面。 二、Android系統的硬體

SpringBoot實現Java高併發秒殺系統DAO開發(

秒殺系統在如今電商專案中是很常見的,最近在學習電商專案時講到了秒殺系統的實現,於是打算使用SpringBoot框架學習一下秒殺系統(本專案基於慕課網的一套免費視訊教程:Java高併發秒殺API,視訊教程中講解的很詳細,非常感謝這位講師)。也是因為最近學習了Spr

劉海屏全面屏攻略

劉海屏之全面屏攻略 前言 由於蘋果公司的“先進設計”導致各大手機廠商紛紛跟風其設計,導致Android的螢幕適配出現新的剛需——劉海屏的適配。為了簡化這些適配操作以及繁瑣的判斷封裝優化出一個工具庫:BangScreenToolsMaster 適配方案及原理 適配流程

Binder機制情景分析linux環境

binder安裝 一. 環境 - 執行環境:linux4.1.15 - 開發板為天嵌imx6ul 二. 核心修改 2.1 開啟核心配置選單 make menuconfig 2.2 修改配置 配置驅動 轉到Device Drivers->Android,選

Android OHAL開發

這裡介紹的是一種簡單HAL的寫法與呼叫。 我將會編寫一個app直接呼叫HAL的介面,而HAL層程式碼將直接讀寫驅動的節點。 簡介 Android O的一項新元素是 Project Treble。這是 Android 作業系統框架在架構方面的一項重大

android螢幕精準

([email protected])(android精準適配工具)最近這段時間專案要做適配,在網上方便的方法。後來根據http://blog.csdn.net/jdsjlzx/article/details/45891551文章最後提出的適配思路,進行了總結優化

Android camera 使用框架(自前後攝像頭、Preview)

由於最近要用攝像頭進行圖片的採集,並做人臉識別。而由於手機種類與自開發板子種類繁多,螢幕適配、前後攝像頭的管理繁瑣,所以本人利用幾天時間,自己寫了一個簡單的框架,嚴格來說不是框架,就是個工具,使用起來更方便點。使相機支援的預覽大小很好的與手機螢幕需要展示的大小做了適配,從來

iOS學習iOS 11跳轉App Store評論

iOS 11已經出來一陣子了,市面上也出了不少文章來說大家遇到的坑,我也來湊湊熱鬧。 在iOS 11之前,為了讓使用者直接跳到App Store的評論頁面,你的程式碼大概是這樣寫的: 但是今天QA給我提了個bug,說是這個已經在iOS 11上不靈了,直接提示“無法連

Android 8.0應用圖示

前言:Android 8.0系統出來這麼久了,也是時候來適配一下了。8.0 系統修改的地方挺多的,但是需要我們程式猿開發適配的倒不是很多。這篇部落格主要介紹8.0系統適配中的應用圖示適配。 在Android 7.1系統之前APP的應用圖示都是mipmap中的靜態圖片andr

XCode模擬器上下黑邊、顯示不完整、問題

其實出現上下黑邊是因為iOS預設將啟動時的LaunchImage的寬高當成程式的寬高,所以啟動圖片如果只有小屏的圖片,那麼就會出現大屏狀態下螢幕不能滿屏的錯誤。 解決方法: 新增所有尺寸螢幕的

Camera顯示app實現簡單camera

要寫一個基本功能的Camera應用其實很簡單。 一.佈局檔案: main.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.a

[quick-cocos2d-x lua學習] 官網多解析度詳解

感覺官網的這篇文章很不錯,為了自己日後檢視方便,就轉過來了~ 下面是正題: 多種解析度的適配一直都是一個蛋疼的問題,各家公司可能都有自己的一套方案。今天我為大家介紹的是我們在多款遊戲裡實踐後的解決方案,相對來說成本和實現難度都較低,效果也很不錯。 多種解析度適配的

android實現萬能RecyclerView的adapter

現在基本大家都推薦RecyclerView,很少有人使用ListView了,包括我自己也是,已經很久沒用ListView了,所以關於ListView的萬能adapter就不寫了。 每次寫專案的時候,每次遇到RecyclerView都要重新寫一個Adapter,

iPhone6解析度與(

解析度和畫素 經新xcode6模擬器驗證(解析度為pt,畫素為真實pixel): 1.iPhone5解析度320x568,畫素640x1136,@2x 2.iPhone6解析度375x667,畫素750x1334,@2x     3.iPhone6 Plus解析度414x736,畫素1242x2208,@

Android native程序間通訊例項-binder篇——HAL訪問JAVA的服務

有一天在群裡聊天的時候,有人提出一個問題,怎樣才能做到HAL層訪問JAVA層的介面?剛好我不會,所以做了一點研究。   之前的文章末尾部分說過了service call 可以用來除錯系統的binder服務。 傳送門: Android native程序間通訊例項-binder篇之&mda

Camera專題】你應該熟悉的Camera驅動框架(Hal->kernel)

一、前言 本文主要研究展訊平臺 Camera驅動 和 HAL層程式碼架構,熟悉展訊Camera的控制流程。 Hal版本:【HAL3】 平臺:【Sprd展訊平臺】 知識點如下: 從HAL層到kernel層 1.Camera的開啟(open)、初始化(init)和供電(power on)呼叫流程 2

從零開始學 Web 移動Web()螢幕相關基本知識,除錯,視口,螢幕

一、基礎知識 1、螢幕 移動裝置與PC裝置最大的差異在於螢幕,這主要體現在螢幕尺寸和螢幕解析度兩個方面。 通常我們所指的螢幕尺寸,實際上指的是螢幕對角線的長度(一般用英寸來度量)。 而解析度則一般用畫素來度量 px,表示螢幕水平和垂直方向的畫素數,例如 1920*1080 指的是螢幕垂直方向和水平方向分別

Android驅動()硬體訪問服務學習(三)Android加入HAL訪問硬體

硬體平臺:tiny4412系統:Android  5.0.2編譯器: arm-linux-gcc-4.5.1 當時我們把對硬體的操作放在了JNI層,但是Android並不是這樣,google提出HAL層,即硬體封裝層 這一節我們把硬體的操作封裝裝HAL層。 andr