Camera顯示之Hal層的適配



一.基本關係

1.先來看看KTM hal層大概類圖關係:

大概類圖關係就是這樣, 其中和顯示相關的類圖關係如紅線所圈區域。

可以猜測到 與顯示相關的邏輯處理應該都會在DisplayClient這個類去實現。


2.CamDeviceManager和DisplayClient關係的建立:

以後app下達有關預覽顯示相關的東西啊在hal層基本上都是這一條先進行傳遞命令, 不過總1中我們可以看到CamDevice還有一些衍生類, 這些都是mtk爲不同設備做的一些定製, 主要的路徑還是如上圖所示。


二.接着之前的在CameraClient中的代碼:

  1. //!++  
  2. else if ( window == 0 ) {  
  3.     result = mHardware->setPreviewWindow(window);  
  4. }  
    //!++
    else if ( window == 0 ) {
        result = mHardware->setPreviewWindow(window);
    }

1.setPreviewWindow(window)通過CameraHardwareInterface適配:

  1. mDevice->ops->set_preview_window(mDevice,  
  2.                     buf.get() ? &mHalPreviewWindow.nw : 0);  
mDevice->ops->set_preview_window(mDevice,
                    buf.get() ? &mHalPreviewWindow.nw : 0);

來實現向hal層下達命令和設置參數。

在這裏我們發現傳入的是mHalPreviewWindow.nw, 而不是我們之前所講述的ANativeWindow 這是因爲mHalPreviewWindow.nw將ANativeWindow的一些流的操作進行封裝, 使之操作更加簡便。

mHalPreviewWindow.nw的定義:

  1. struct camera_preview_window {  
  2.        struct preview_stream_ops nw;  
  3.        void *user;  
  4.    };  
 struct camera_preview_window {
        struct preview_stream_ops nw;
        void *user;
    };

就是結構體:struct :

  1. typedef struct preview_stream_ops {  
  2.     int (*dequeue_buffer)(struct preview_stream_ops* w,  
  3.                           buffer_handle_t** buffer, int *stride);  
  4.     int (*enqueue_buffer)(struct preview_stream_ops* w,  
  5.                 buffer_handle_t* buffer);  
  6.     int (*cancel_buffer)(struct preview_stream_ops* w,  
  7.                 buffer_handle_t* buffer);  
  8.     int (*set_buffer_count)(struct preview_stream_ops* w, int count);  
  9.     int (*set_buffers_geometry)(struct preview_stream_ops* pw,  
  10.                 int w, int h, int format);  
  11.     int (*set_crop)(struct preview_stream_ops *w,  
  12.                 int left, int top, int right, int bottom);  
  13.     int (*set_usage)(struct preview_stream_ops* w, int usage);  
  14.     int (*set_swap_interval)(struct preview_stream_ops *w, int interval);  
  15.     int (*get_min_undequeued_buffer_count)(const struct preview_stream_ops *w,  
  16.                 int *count);  
  17.     int (*lock_buffer)(struct preview_stream_ops* w,  
  18.                 buffer_handle_t* buffer);  
  19.     // Timestamps are measured in nanoseconds, and must be comparable  
  20.     // and monotonically increasing between two frames in the same  
  21.     // preview stream. They do not need to be comparable between  
  22.     // consecutive or parallel preview streams, cameras, or app runs.  
  23.     int (*set_timestamp)(struct preview_stream_ops *w, int64_t timestamp);  
typedef struct preview_stream_ops {
    int (*dequeue_buffer)(struct preview_stream_ops* w,
                          buffer_handle_t** buffer, int *stride);
    int (*enqueue_buffer)(struct preview_stream_ops* w,
                buffer_handle_t* buffer);
    int (*cancel_buffer)(struct preview_stream_ops* w,
                buffer_handle_t* buffer);
    int (*set_buffer_count)(struct preview_stream_ops* w, int count);
    int (*set_buffers_geometry)(struct preview_stream_ops* pw,
                int w, int h, int format);
    int (*set_crop)(struct preview_stream_ops *w,
                int left, int top, int right, int bottom);
    int (*set_usage)(struct preview_stream_ops* w, int usage);
    int (*set_swap_interval)(struct preview_stream_ops *w, int interval);
    int (*get_min_undequeued_buffer_count)(const struct preview_stream_ops *w,
                int *count);
    int (*lock_buffer)(struct preview_stream_ops* w,
                buffer_handle_t* buffer);
    // Timestamps are measured in nanoseconds, and must be comparable
    // and monotonically increasing between two frames in the same
    // preview stream. They do not need to be comparable between
    // consecutive or parallel preview streams, cameras, or app runs.
    int (*set_timestamp)(struct preview_stream_ops *w, int64_t timestamp);

對顯示流的操作都是通過這些函數實現的,而mHalPreviewWindow中實現了具體操的方法, 在這些方法的實現中實現對作ANativeWindow的操作。 而在hal端就是通過mHalPreviewWindow.nw 進行對ANativeWindow的具體操作。


基本類圖關係:


2.繼續1中的:

  1. mDevice->ops->set_preview_window(mDevice,  
  2.                     buf.get() ? &mHalPreviewWindow.nw : 0);  
mDevice->ops->set_preview_window(mDevice,
                    buf.get() ? &mHalPreviewWindow.nw : 0);

我已經知道了mHalPreviewWindow.nw爲傳入的一個重要參數mHalPreviewWindow.nw 爲preview_stream_ops。

繼續看看set_preview_window這個方法。 我們有上篇文章知道ops是ICamDevice的一個成員gCameraDevOps,類型爲camera_device_ops_t:

可以看到:

  1. static camera_device_ops_t const gCameraDevOps = {  
  2.     set_preview_window:         camera_set_preview_window,   
  3.     set_callbacks:              camera_set_callbacks,   
  4.     enable_msg_type:            camera_enable_msg_type,   
  5.     disable_msg_type:           camera_disable_msg_type,   
  6.     msg_type_enabled:           camera_msg_type_enabled,   
  7.     start_preview:              camera_start_preview,   
  8.     stop_preview:               camera_stop_preview,   
  9.     preview_enabled:            camera_preview_enabled,   
  10.     store_meta_data_in_buffers: camera_store_meta_data_in_buffers,   
  11.     start_recording:            camera_start_recording,   
  12.     stop_recording:             camera_stop_recording,   
  13.     recording_enabled:          camera_recording_enabled,   
  14.     release_recording_frame:    camera_release_recording_frame,   
  15.     auto_focus:                 camera_auto_focus,   
  16.     cancel_auto_focus:          camera_cancel_auto_focus,   
  17.     take_picture:               camera_take_picture,   
  18.     cancel_picture:             camera_cancel_picture,   
  19.     set_parameters:             camera_set_parameters,   
  20.     get_parameters:             camera_get_parameters,   
  21.     put_parameters:             camera_put_parameters,   
  22.     send_command:               camera_send_command,   
  23.     release:                    camera_release,   
  24.     dump:                       camera_dump,   
  25.   
  26. };  
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, 

};


gCameraDevOps 中的函數地址映射到ICamDevice中的函數實現。

所以 :ops->set_preview_window(mDevice, buf.get() ? &mHalPreviewWindow.nw : 0) 就對應到ICamDevice::camera_set_preview_window的發發調用。

  1. static int camera_set_preview_window(  
  2.     struct camera_device * device,  
  3.     struct preview_stream_ops *window  
  4. )  
  5. {  
  6.     int err = -EINVAL;  
  7.     //  
  8.     ICamDevice*const pDev = ICamDevice::getIDev(device);  
  9.     if  ( pDev )  
  10.     {  
  11.         err = pDev->setPreviewWindow(window);  
  12.     }  
  13.     //  
  14.     return  err;  
  15. }  
static int camera_set_preview_window(
    struct camera_device * device,
    struct preview_stream_ops *window
)
{
    int err = -EINVAL;
    //
    ICamDevice*const pDev = ICamDevice::getIDev(device);
    if  ( pDev )
    {
        err = pDev->setPreviewWindow(window);
    }
    //
    return  err;
}

  1. static inline ICamDevice*   getIDev(camera_device*const device)  
  2.                                 {  
  3.                                     return (NULL == device)  
  4.                                                 ? NULL  
  5.                                                 : reinterpret_cast<ICamDevice*>(device->priv);//得到device->priv  
static inline ICamDevice*   getIDev(camera_device*const device)
                                {
                                    return (NULL == device)
                                                ? NULL
                                                : reinterpret_cast<ICamDevice*>(device->priv);//得到device->priv


由上篇文章:

知道device->pri實際上是在創建實例的時候指向的自己:

  1. ICamDevice::    
  2. ICamDevice()    
  3.     : camera_device_t()    
  4.     , RefBase()    
  5.     , mDevOps()    
  6.     //    
  7.     , mMtxLock()    
  8.     //    
  9. {    
  10.     MY_LOGD("ctor");    
  11.     ::memset(static_cast<camera_device_t*>(this), 0, sizeof(camera_device_t));    
  12.     this->priv  = this//用priv指針保存自己。  
  13.     this->ops   = &mDevOps;//ops指向了mDevOps    
  14.     mDevOps     = gCameraDevOps;//mDevOps爲gCameraDevOps指向的結構體    
  15. }    
    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; //用priv指針保存自己。
        this->ops   = &mDevOps;//ops指向了mDevOps  
        mDevOps     = gCameraDevOps;//mDevOps爲gCameraDevOps指向的結構體  
    }  


繼續回到pDev->setPreviewWindow(window);

在ICamDevice中沒有對setPreviewWindow具體的實現,而是在其子類CamDevice對ICamDevice進行了具體的實現;

隨意代碼定位到CamDevice:

  1. status_t  
  2. CamDevice::  
  3. setPreviewWindow(preview_stream_ops* window)  
  4. {  
  5.     MY_LOGI("+ window(%p)", window);  
  6.     //  
  7.     status_t status = initDisplayClient(window);//開始初始化DisplayClient  
  8.     if  ( OK == status && previewEnabled() && mpDisplayClient != 0 )  
  9.     {  
  10.         status = enableDisplayClient();//時能DisplayClient端  
  11.     }  
  12.     //  
  13.     return  status;  
  14. }  
status_t
CamDevice::
setPreviewWindow(preview_stream_ops* window)
{
    MY_LOGI("+ window(%p)", window);
    //
    status_t status = initDisplayClient(window);//開始初始化DisplayClient
    if  ( OK == status && previewEnabled() && mpDisplayClient != 0 )
    {
        status = enableDisplayClient();//時能DisplayClient端
    }
    //
    return  status;
}

  1. status_t  
  2. CamDevice::  
  3. initDisplayClient(preview_stream_ops* window)  
  4. {  
  5. #if '1'!=MTKCAM_HAVE_DISPLAY_CLIENT  
  6.     #warning "Not Build Display Client"  
  7.     MY_LOGD("Not Build Display Client");  
  8. ..............  
  9. .............  
  10. /  [3.1] create a Display Client.  
  11.     mpDisplayClient = IDisplayClient::createInstance();  
  12.     if  ( mpDisplayClient == 0 )  
  13.     {  
  14.         MY_LOGE("Cannot create mpDisplayClient");  
  15.         status = NO_MEMORY;  
  16.         goto lbExit;  
  17.     }  
  18.     //  [3.2] initialize the newly-created Display Client.  
  19.     if  ( ! mpDisplayClient->init() )  
  20.     {  
  21.         MY_LOGE("mpDisplayClient init() failed");  
  22.         mpDisplayClient->uninit();  
  23.         mpDisplayClient.clear();  
  24.         status = NO_MEMORY;  
  25.         goto lbExit;  
  26.     }  
  27.     //  [3.3] set preview_stream_ops & related window info.  
  28.     if  ( ! mpDisplayClient->setWindow(window, previewSize.width, previewSize.height, queryDisplayBufCount()) )//綁定window  
  29.     {  
  30.         status = INVALID_OPERATION;  
  31.         goto lbExit;  
  32.     }  
  33.     //  [3.4] set Image Buffer Provider Client if it exist.  
  34.     if  ( mpCamAdapter != 0 && ! mpDisplayClient->setImgBufProviderClient(mpCamAdapter) )//重要! 設置流數據的Buffer提供者。  
  35.     {  
  36.         status = INVALID_OPERATION;  
  37.         goto lbExit;  
  38.     }  
  39. ..................  
  40. ..................  
status_t
CamDevice::
initDisplayClient(preview_stream_ops* window)
{
#if '1'!=MTKCAM_HAVE_DISPLAY_CLIENT
    #warning "Not Build Display Client"
    MY_LOGD("Not Build Display Client");
..............
.............
/  [3.1] create a Display Client.
    mpDisplayClient = IDisplayClient::createInstance();
    if  ( mpDisplayClient == 0 )
    {
        MY_LOGE("Cannot create mpDisplayClient");
        status = NO_MEMORY;
        goto lbExit;
    }
    //  [3.2] initialize the newly-created Display Client.
    if  ( ! mpDisplayClient->init() )
    {
        MY_LOGE("mpDisplayClient init() failed");
        mpDisplayClient->uninit();
        mpDisplayClient.clear();
        status = NO_MEMORY;
        goto lbExit;
    }
    //  [3.3] set preview_stream_ops & related window info.
    if  ( ! mpDisplayClient->setWindow(window, previewSize.width, previewSize.height, queryDisplayBufCount()) )//綁定window
    {
        status = INVALID_OPERATION;
        goto lbExit;
    }
    //  [3.4] set Image Buffer Provider Client if it exist.
    if  ( mpCamAdapter != 0 && ! mpDisplayClient->setImgBufProviderClient(mpCamAdapter) )//重要! 設置流數據的Buffer提供者。
    {
        status = INVALID_OPERATION;
        goto lbExit;
    }
..................
..................

  1. status_t  
  2. CamDevice::  
  3. enableDisplayClient()  
  4. {  
  5.     status_t status = OK;  
  6.     Size previewSize;  
  7.     //  
  8.     //  [1] Get preview size.  
  9.     if  ( ! queryPreviewSize(previewSize.width, previewSize.height) )  
  10.     {  
  11.         MY_LOGE("queryPreviewSize");  
  12.         status = DEAD_OBJECT;  
  13.         goto lbExit;  
  14.     }  
  15.     //  
  16.     //  [2] Enable  
  17.     if  ( ! mpDisplayClient->enableDisplay(previewSize.width, previewSize.height, queryDisplayBufCount(), mpCamAdapter) )//設置了預覽數據的尺寸和Buffer提供者相關的數據  
  18.     {  
  19.         MY_LOGE("mpDisplayClient(%p)->enableDisplay()", mpDisplayClient.get());  
  20.         status = INVALID_OPERATION;  
  21.         goto lbExit;  
  22.     }  
  23.     //  
  24.     status = OK;  
  25. lbExit:  
  26.     return  status;  
  27. }  
status_t
CamDevice::
enableDisplayClient()
{
    status_t status = OK;
    Size previewSize;
    //
    //  [1] Get preview size.
    if  ( ! queryPreviewSize(previewSize.width, previewSize.height) )
    {
        MY_LOGE("queryPreviewSize");
        status = DEAD_OBJECT;
        goto lbExit;
    }
    //
    //  [2] Enable
    if  ( ! mpDisplayClient->enableDisplay(previewSize.width, previewSize.height, queryDisplayBufCount(), mpCamAdapter) )//設置了預覽數據的尺寸和Buffer提供者相關的數據
    {
        MY_LOGE("mpDisplayClient(%p)->enableDisplay()", mpDisplayClient.get());
        status = INVALID_OPERATION;
        goto lbExit;
    }
    //
    status = OK;
lbExit:
    return  status;
}


3.定位到DisplayClient中:

  1. enableDisplay(  
  2.     int32_t const   i4Width,   
  3.     int32_t const   i4Height,   
  4.     int32_t const   i4BufCount,   
  5.     sp<IImgBufProviderClient>const& rpClient  
  6. )  
  7. {  
  8.     bool ret = false;  
  9.     preview_stream_ops* pStreamOps = mpStreamOps;  
  10.     //  
  11.     //  [1] Re-configurate this instance if any setting changes.  
  12.     if  ( ! checkConfig(i4Width, i4Height, i4BufCount, rpClient) )  
  13.     {  
  14.         MY_LOGW("<Config Change> Uninit the current DisplayClient(%p) and re-config..."this);  
  15.         //  
  16.         //  [.1] uninitialize  
  17.         uninit();  
  18.         //  
  19.         //  [.2] initialize  
  20.         if  ( ! init() )  
  21.         {  
  22.             MY_LOGE("re-init() failed");  
  23.             goto lbExit;  
  24.         }  
  25.         //  
  26.         //  [.3] set related window info.  
  27.         if  ( ! setWindow(pStreamOps, i4Width, i4Height, i4BufCount) )//window的尺寸和預覽數據的大小一致  
  28.         {  
  29.             goto lbExit;  
  30.         }  
  31.         //  
  32.         //  [.4] set Image Buffer Provider Client.  
  33.         if  ( ! setImgBufProviderClient(rpClient) )//Buffer的數據提供者爲mpCamAdapter, 就是CamAdapter, 後面的預覽數據元都是通過它來提供。  
  34.         {  
  35.             goto lbExit;  
  36.         }  
  37.     }  
  38.     //  
  39.     //  [2] Enable.  
  40.     if  ( ! enableDisplay() )//開始進行數據的獲取和顯示  
  41.     {  
  42.         goto lbExit;  
  43.     }  
  44.     //  
  45.     ret = true;  
  46. lbExit:  
  47.     return  ret;  
  48. }  
enableDisplay(
    int32_t const   i4Width, 
    int32_t const   i4Height, 
    int32_t const   i4BufCount, 
    sp<IImgBufProviderClient>const& rpClient
)
{
    bool ret = false;
    preview_stream_ops* pStreamOps = mpStreamOps;
    //
    //  [1] Re-configurate this instance if any setting changes.
    if  ( ! checkConfig(i4Width, i4Height, i4BufCount, rpClient) )
    {
        MY_LOGW("<Config Change> Uninit the current DisplayClient(%p) and re-config...", this);
        //
        //  [.1] uninitialize
        uninit();
        //
        //  [.2] initialize
        if  ( ! init() )
        {
            MY_LOGE("re-init() failed");
            goto lbExit;
        }
        //
        //  [.3] set related window info.
        if  ( ! setWindow(pStreamOps, i4Width, i4Height, i4BufCount) )//window的尺寸和預覽數據的大小一致
        {
            goto lbExit;
        }
        //
        //  [.4] set Image Buffer Provider Client.
        if  ( ! setImgBufProviderClient(rpClient) )//Buffer的數據提供者爲mpCamAdapter, 就是CamAdapter, 後面的預覽數據元都是通過它來提供。
        {
            goto lbExit;
        }
    }
    //
    //  [2] Enable.
    if  ( ! enableDisplay() )//開始進行數據的獲取和顯示
    {
        goto lbExit;
    }
    //
    ret = true;
lbExit:
    return  ret;
}

先來看看第一個關鍵函數:setWindow(pStreamOps, i4Width, i4Height, i4BufCount)

  1. bool  
  2. DisplayClient::  
  3. setWindow(  
  4.     preview_stream_ops*const window,   
  5.     int32_t const   wndWidth,   
  6.     int32_t const   wndHeight,   
  7.     int32_t const   i4MaxImgBufCount  
  8. )  
  9. {  
  10.     MY_LOGI("+ window(%p), WxH=%dx%d, count(%d)", window, wndWidth, wndHeight, i4MaxImgBufCount);  
  11.     //  
  12.     if  ( ! window )  
  13.     {  
  14.         MY_LOGE("NULL window passed into");  
  15.         return  false;  
  16.     }  
  17.     //  
  18.     if  ( 0 >= wndWidth || 0 >= wndHeight || 0 >= i4MaxImgBufCount )  
  19.     {  
  20.         MY_LOGE("bad arguments - WxH=%dx%d, count(%d)", wndWidth, wndHeight, i4MaxImgBufCount);  
  21.         return  false;  
  22.     }  
  23.     //  
  24.     //  
  25.     Mutex::Autolock _l(mModuleMtx);  
  26.     return  set_preview_stream_ops(window, wndWidth, wndHeight, i4MaxImgBufCount);//  
  27. }  
bool
DisplayClient::
setWindow(
    preview_stream_ops*const window, 
    int32_t const   wndWidth, 
    int32_t const   wndHeight, 
    int32_t const   i4MaxImgBufCount
)
{
    MY_LOGI("+ window(%p), WxH=%dx%d, count(%d)", window, wndWidth, wndHeight, i4MaxImgBufCount);
    //
    if  ( ! window )
    {
        MY_LOGE("NULL window passed into");
        return  false;
    }
    //
    if  ( 0 >= wndWidth || 0 >= wndHeight || 0 >= i4MaxImgBufCount )
    {
        MY_LOGE("bad arguments - WxH=%dx%d, count(%d)", wndWidth, wndHeight, i4MaxImgBufCount);
        return  false;
    }
    //
    //
    Mutex::Autolock _l(mModuleMtx);
    return  set_preview_stream_ops(window, wndWidth, wndHeight, i4MaxImgBufCount);//
}

  1. ool  
  2. DisplayClient::  
  3. set_preview_stream_ops(  
  4.     preview_stream_ops*const window,   
  5.     int32_t const   wndWidth,   
  6.     int32_t const   wndHeight,   
  7.     int32_t const   i4MaxImgBufCount  
  8. )  
  9. {  
  10.     CamProfile profile(__FUNCTION__, "DisplayClient");  
  11.     //  
  12.     bool        ret = false;  
  13.     status_t    err = 0;  
  14.     int32_t     min_undequeued_buf_count = 0;  
  15.     //  
  16.     //  (2) Check  
  17.     if  ( ! mStreamBufList.empty() )  
  18.     {  
  19.         MY_LOGE(  
  20.             "locked buffer count(%d)!=0, "  
  21.             "callers must return all dequeued buffers, "  
  22. //            "and then call cleanupQueue()"  
  23.             , mStreamBufList.size()  
  24.         );  
  25.         dumpDebug(mStreamBufList, __FUNCTION__);  
  26.         goto lbExit;  
  27.     }  
  28.     //  
  29.     //  (3) Sava info.  
  30.     mpStreamImgInfo.clear();//mpStreamImgInfo封裝的視屏數據流的基本信息。  
  31.     mpStreamImgInfo     = new ImgInfo(wndWidth, wndHeight, CAMERA_DISPLAY_FORMAT, CAMERA_DISPLAY_FORMAT_HAL, "Camera@Display");//設置了Stream的寬高和顯示類型。  
  32.     mpStreamOps         = window;//mpStreamOps保存了上層傳進來的對象指針。後面就通過它和顯示方進行交互。  
  33.     mi4MaxImgBufCount   = i4MaxImgBufCount;  
  34.   
  35. ........................  
  36. ........................  
  37.   
  38.  err = mpStreamOps->set_buffer_count(mpStreamOps, mi4MaxImgBufCount+min_undequeued_buf_count);  
  39.     if  ( err )  
  40.     {  
  41.         MY_LOGE("set_buffer_count failed: status[%s(%d)]", ::strerror(-err), -err);  
  42.         if ( ENODEV == err )  
  43.         {  
  44.             MY_LOGD("Preview surface abandoned!");  
  45.             mpStreamOps = NULL;  
  46.         }  
  47.         goto lbExit;  
  48.     }  
  49.     //  
  50.     //  (4.4) Set window geometry  
  51.     err = mpStreamOps->set_buffers_geometry(//設置基本的流信息  
  52.             mpStreamOps,   
  53.             mpStreamImgInfo->mu4ImgWidth,   
  54.             mpStreamImgInfo->mu4ImgHeight,   
  55.             mpStreamImgInfo->mi4ImgFormat  
  56.         );  
ool
DisplayClient::
set_preview_stream_ops(
    preview_stream_ops*const window, 
    int32_t const   wndWidth, 
    int32_t const   wndHeight, 
    int32_t const   i4MaxImgBufCount
)
{
    CamProfile profile(__FUNCTION__, "DisplayClient");
    //
    bool        ret = false;
    status_t    err = 0;
    int32_t     min_undequeued_buf_count = 0;
    //
    //  (2) Check
    if  ( ! mStreamBufList.empty() )
    {
        MY_LOGE(
            "locked buffer count(%d)!=0, "
            "callers must return all dequeued buffers, "
//            "and then call cleanupQueue()"
            , mStreamBufList.size()
        );
        dumpDebug(mStreamBufList, __FUNCTION__);
        goto lbExit;
    }
    //
    //  (3) Sava info.
    mpStreamImgInfo.clear();//mpStreamImgInfo封裝的視屏數據流的基本信息。
    mpStreamImgInfo     = new ImgInfo(wndWidth, wndHeight, CAMERA_DISPLAY_FORMAT, CAMERA_DISPLAY_FORMAT_HAL, "Camera@Display");//設置了Stream的寬高和顯示類型。
    mpStreamOps         = window;//mpStreamOps保存了上層傳進來的對象指針。後面就通過它和顯示方進行交互。
    mi4MaxImgBufCount   = i4MaxImgBufCount;

........................
........................

 err = mpStreamOps->set_buffer_count(mpStreamOps, mi4MaxImgBufCount+min_undequeued_buf_count);
    if  ( err )
    {
        MY_LOGE("set_buffer_count failed: status[%s(%d)]", ::strerror(-err), -err);
        if ( ENODEV == err )
        {
            MY_LOGD("Preview surface abandoned!");
            mpStreamOps = NULL;
        }
        goto lbExit;
    }
    //
    //  (4.4) Set window geometry
    err = mpStreamOps->set_buffers_geometry(//設置基本的流信息
            mpStreamOps, 
            mpStreamImgInfo->mu4ImgWidth, 
            mpStreamImgInfo->mu4ImgHeight, 
            mpStreamImgInfo->mi4ImgFormat
        );

通過 上面的代碼片段和分析, 確定了上層傳遞下來的對象指針保存在mpStreamOps, 與顯示相關的交互都將通過mpStreamOps來進行操作。 而mpStreamImgInfo封裝了流數據的大小和格式等。


再來看看第二個關鍵函數:setImgBufProviderClient(rpClient):

  1. bool  
  2. DisplayClient::  
  3. setImgBufProviderClient(sp<IImgBufProviderClient>const& rpClient)  
  4. {  
  5.     bool ret = false;  
  6.     //  
  7.     MY_LOGD("+ ImgBufProviderClient(%p), mpImgBufQueue.get(%p)", rpClient.get(), mpImgBufQueue.get());  
  8.     //  
  9.     if  ( rpClient == 0 )  
  10.     {  
  11.         MY_LOGE("NULL ImgBufProviderClient");  
  12.         mpImgBufPvdrClient = NULL;  
  13.         goto lbExit;  
  14.     }  
  15.     //  
  16.     if  ( mpImgBufQueue != 0 )  
  17.     {  
  18.         if  ( ! rpClient->onImgBufProviderCreated(mpImgBufQueue) )//通知Provider端(Buffer數據提供者端),我這邊已經建好Buffer隊列, 後面你就填充數據到對應的Buffer供我使用。  
  19.         {  
  20.             goto lbExit;  
  21.         }  
  22.         mpImgBufPvdrClient = rpClient;//用mpImgBufPvdrClient保存provider的對象指針, 方便使用。  
  23.     }  
  24.     //  
  25.     ret = true;  
  26. lbExit:  
  27.     MY_LOGD("-");  
  28.     return  ret;  
  29. };  
bool
DisplayClient::
setImgBufProviderClient(sp<IImgBufProviderClient>const& rpClient)
{
    bool ret = false;
    //
    MY_LOGD("+ ImgBufProviderClient(%p), mpImgBufQueue.get(%p)", rpClient.get(), mpImgBufQueue.get());
    //
    if  ( rpClient == 0 )
    {
        MY_LOGE("NULL ImgBufProviderClient");
        mpImgBufPvdrClient = NULL;
        goto lbExit;
    }
    //
    if  ( mpImgBufQueue != 0 )
    {
        if  ( ! rpClient->onImgBufProviderCreated(mpImgBufQueue) )//通知Provider端(Buffer數據提供者端),我這邊已經建好Buffer隊列, 後面你就填充數據到對應的Buffer供我使用。
        {
            goto lbExit;
        }
        mpImgBufPvdrClient = rpClient;//用mpImgBufPvdrClient保存provider的對象指針, 方便使用。
    }
    //
    ret = true;
lbExit:
    MY_LOGD("-");
    return  ret;
};

再來看看第三個關鍵函數 enableDisplay() :

  1. bool  
  2. DisplayClient::  
  3. enableDisplay()  
  4. {  
  5.     bool ret = false;  
  6.     //  
  7.     //  (1) Lock  
  8.     Mutex::Autolock _l(mModuleMtx);  
  9.     //  
  10.     MY_LOGD("+ isDisplayEnabled(%d), mpDisplayThread.get(%p)", isDisplayEnabled(), mpDisplayThread.get());  
  11.     //  
  12.     //  (2) Check to see if it has been enabled.  
  13.     if  ( isDisplayEnabled() )  
  14.     {  
  15.         MY_LOGD("Display is already enabled");  
  16.         ret = true;  
  17.         goto lbExit;  
  18.     }  
  19.     //  
  20.     //  (3) Check to see if thread is alive.  
  21.     if  ( mpDisplayThread == 0 )  
  22.     {  
  23.         MY_LOGE("NULL mpDisplayThread");  
  24.         goto lbExit;  
  25.     }  
  26.     //  
  27.     //  (4) Enable the flag.  
  28.     ::android_atomic_write(1, &mIsDisplayEnabled);  
  29.     //  
  30.     //  (5) Post a command to wake up the thread.  
  31.     mpDisplayThread->postCommand(Command(Command::eID_WAKEUP));//通知獲取數據的線程開始運行  
  32.     //  
  33.     //  
  34.     ret = true;  
  35. lbExit:  
  36.     MY_LOGD("- ret(%d)", ret);  
  37.     return ret;  
  38. }  
bool
DisplayClient::
enableDisplay()
{
    bool ret = false;
    //
    //  (1) Lock
    Mutex::Autolock _l(mModuleMtx);
    //
    MY_LOGD("+ isDisplayEnabled(%d), mpDisplayThread.get(%p)", isDisplayEnabled(), mpDisplayThread.get());
    //
    //  (2) Check to see if it has been enabled.
    if  ( isDisplayEnabled() )
    {
        MY_LOGD("Display is already enabled");
        ret = true;
        goto lbExit;
    }
    //
    //  (3) Check to see if thread is alive.
    if  ( mpDisplayThread == 0 )
    {
        MY_LOGE("NULL mpDisplayThread");
        goto lbExit;
    }
    //
    //  (4) Enable the flag.
    ::android_atomic_write(1, &mIsDisplayEnabled);
    //
    //  (5) Post a command to wake up the thread.
    mpDisplayThread->postCommand(Command(Command::eID_WAKEUP));//通知獲取數據的線程開始運行
    //
    //
    ret = true;
lbExit:
    MY_LOGD("- ret(%d)", ret);
    return ret;
}



  1. bool  
  2. DisplayThread::  
  3. threadLoop()  
  4. {  
  5.     Command cmd;  
  6.     if  ( getCommand(cmd) )  
  7.     {  
  8.         switch  (cmd.eId)  
  9.         {  
  10.         case Command::eID_EXIT:  
  11.             MY_LOGD("Command::%s", cmd.name());  
  12.             break;  
  13.         //  
  14.         case Command::eID_WAKEUP://對應上面發送的命令  
  15.         default:  
  16.             if  ( mpThreadHandler != 0 )  
  17.             {  
  18.                 mpThreadHandler->onThreadLoop(cmd);//注意此處, mpThreadHandler就是DisplayClient(它繼承了IDisplayThreadHandler),  
  19.             }  
  20.             else  
  21.             {  
  22.                 MY_LOGE("cannot handle cmd(%s) due to mpThreadHandler==NULL", cmd.name());  
  23.             }  
  24.             break;  
  25.         }  
  26.     }  
  27.     //  
  28.     MY_LOGD("- mpThreadHandler.get(%p)", mpThreadHandler.get());  
  29.     return  true;  
  30. }  
bool
DisplayThread::
threadLoop()
{
    Command cmd;
    if  ( getCommand(cmd) )
    {
        switch  (cmd.eId)
        {
        case Command::eID_EXIT:
            MY_LOGD("Command::%s", cmd.name());
            break;
        //
        case Command::eID_WAKEUP://對應上面發送的命令
        default:
            if  ( mpThreadHandler != 0 )
            {
                mpThreadHandler->onThreadLoop(cmd);//注意此處, mpThreadHandler就是DisplayClient(它繼承了IDisplayThreadHandler),
            }
            else
            {
                MY_LOGE("cannot handle cmd(%s) due to mpThreadHandler==NULL", cmd.name());
            }
            break;
        }
    }
    //
    MY_LOGD("- mpThreadHandler.get(%p)", mpThreadHandler.get());
    return  true;
}



回到DisplayClient的onThreadLoop函數:

  1. bool  
  2. DisplayClient::  
  3. onThreadLoop(Command const& rCmd)  
  4. {  
  5.     //  (0) lock Processor.  
  6.     sp<IImgBufQueue> pImgBufQueue;  
  7.     {  
  8.         Mutex::Autolock _l(mModuleMtx);  
  9.         pImgBufQueue = mpImgBufQueue;  
  10.         if  ( pImgBufQueue == 0 || ! isDisplayEnabled() )//判斷顯示相關的初始化是否完成和啓動  
  11.         {  
  12.             MY_LOGW("pImgBufQueue.get(%p), isDisplayEnabled(%d)", pImgBufQueue.get(), isDisplayEnabled());  
  13.             return  true;  
  14.         }  
  15.     }  
  16.   
  17.     //  (1) Prepare all TODO buffers.  
  18.     if  ( ! prepareAllTodoBuffers(pImgBufQueue) )//爲pImgBufQueue添加空Buffer。  
  19.     {  
  20.         return  true;  
  21.     }  
  22.   
  23.     //  (2) Start  
  24.     if  ( ! pImgBufQueue->startProcessor() )//開始獲取數據  
  25.     {  
  26.         return  true;  
  27.     }  
  28.     //  
  29.     {  
  30.         Mutex::Autolock _l(mStateMutex);  
  31.         mState = eState_Loop;  
  32.         mStateCond.broadcast();  
  33.     }  
  34.     //  
  35.     //  (3) Do until disabled.  
  36.     while   ( 1 )//進入無限循環  
  37.     {  
  38.         //  (.1)  
  39.         waitAndHandleReturnBuffers(pImgBufQueue);//等待pImgBufQueue中的數據,並送到顯示端顯示  
  40.   
  41.         //  (.2) break if disabled.  
  42.         if  ( ! isDisplayEnabled() )  
  43.         {  
  44.             MY_LOGI("Display disabled");  
  45.             break;  
  46.         }  
  47.   
  48.         //  (.3) re-prepare all TODO buffers, if possible,   
  49.         //  since some DONE/CANCEL buffers return.  
  50.         prepareAllTodoBuffers(pImgBufQueue);//又重新準備Buffer。  
  51.     }  
  52.     //  
  53.     //  (4) Stop  
  54.     pImgBufQueue->pauseProcessor();  
  55.     pImgBufQueue->flushProcessor();  
  56.     pImgBufQueue->stopProcessor();//停止數據獲取  
  57.     //  
  58.     //  (5) Cancel all un-returned buffers.  
  59.     cancelAllUnreturnBuffers();//沒有來得及顯示額數據, 也取消掉。  
  60.     //  
  61.     {  
  62.         Mutex::Autolock _l(mStateMutex);  
  63.         mState = eState_Suspend;  
  64.         mStateCond.broadcast();  
  65.     }  
  66.     //  
  67.     return  true;  
  68. }  
bool
DisplayClient::
onThreadLoop(Command const& rCmd)
{
    //  (0) lock Processor.
    sp<IImgBufQueue> pImgBufQueue;
    {
        Mutex::Autolock _l(mModuleMtx);
        pImgBufQueue = mpImgBufQueue;
        if  ( pImgBufQueue == 0 || ! isDisplayEnabled() )//判斷顯示相關的初始化是否完成和啓動
        {
            MY_LOGW("pImgBufQueue.get(%p), isDisplayEnabled(%d)", pImgBufQueue.get(), isDisplayEnabled());
            return  true;
        }
    }

    //  (1) Prepare all TODO buffers.
    if  ( ! prepareAllTodoBuffers(pImgBufQueue) )//爲pImgBufQueue添加空Buffer。
    {
        return  true;
    }

    //  (2) Start
    if  ( ! pImgBufQueue->startProcessor() )//開始獲取數據
    {
        return  true;
    }
    //
    {
        Mutex::Autolock _l(mStateMutex);
        mState = eState_Loop;
        mStateCond.broadcast();
    }
    //
    //  (3) Do until disabled.
    while   ( 1 )//進入無限循環
    {
        //  (.1)
        waitAndHandleReturnBuffers(pImgBufQueue);//等待pImgBufQueue中的數據,並送到顯示端顯示

        //  (.2) break if disabled.
        if  ( ! isDisplayEnabled() )
        {
            MY_LOGI("Display disabled");
            break;
        }

        //  (.3) re-prepare all TODO buffers, if possible, 
        //  since some DONE/CANCEL buffers return.
        prepareAllTodoBuffers(pImgBufQueue);//又重新準備Buffer。
    }
    //
    //  (4) Stop
    pImgBufQueue->pauseProcessor();
    pImgBufQueue->flushProcessor();
    pImgBufQueue->stopProcessor();//停止數據獲取
    //
    //  (5) Cancel all un-returned buffers.
    cancelAllUnreturnBuffers();//沒有來得及顯示額數據, 也取消掉。
    //
    {
        Mutex::Autolock _l(mStateMutex);
        mState = eState_Suspend;
        mStateCond.broadcast();
    }
    //
    return  true;
}

上邊這個代碼片段對預覽數據的處理就在waitAndHandleReturnBuffers(pImgBufQueue);中。


4.對waitAndHandleReturnBuffers(pImgBufQueue);進行分析:

  1. bool  
  2. DisplayClient::  
  3. waitAndHandleReturnBuffers(sp<IImgBufQueue>const& rpBufQueue)  
  4. {  
  5.     bool ret = false;  
  6.     Vector<ImgBufQueNode> vQueNode;  
  7.     //  
  8.     MY_LOGD_IF((1<=miLogLevel), "+");  
  9.     //  
  10.     //  (1) deque buffers from processor.  
  11.     rpBufQueue->dequeProcessor(vQueNode);//從provider端(數據提供端)獲取一個填充數據了的Buffer。  
  12.     if  ( vQueNode.empty() ) {  
  13.         MY_LOGW("vQueNode.empty()");  
  14.         goto lbExit;  
  15.     }  
  16.   
  17.     //  (2) handle buffers dequed from processor.  
  18.     ret = handleReturnBuffers(vQueNode);//處理填充了數據的這個Buffer中的數據。  
  19.   
  20. lbExit:  
  21.     //  
  22.     MY_LOGD_IF((2<=miLogLevel), "- ret(%d)", ret);  
  23.     return ret;  
  24. }  
bool
DisplayClient::
waitAndHandleReturnBuffers(sp<IImgBufQueue>const& rpBufQueue)
{
    bool ret = false;
    Vector<ImgBufQueNode> vQueNode;
    //
    MY_LOGD_IF((1<=miLogLevel), "+");
    //
    //  (1) deque buffers from processor.
    rpBufQueue->dequeProcessor(vQueNode);//從provider端(數據提供端)獲取一個填充數據了的Buffer。
    if  ( vQueNode.empty() ) {
        MY_LOGW("vQueNode.empty()");
        goto lbExit;
    }

    //  (2) handle buffers dequed from processor.
    ret = handleReturnBuffers(vQueNode);//處理填充了數據的這個Buffer中的數據。

lbExit:
    //
    MY_LOGD_IF((2<=miLogLevel), "- ret(%d)", ret);
    return ret;
}


看看handleReturnBuffers函數:

  1. bool  
  2. DisplayClient::  
  3. handleReturnBuffers(Vector<ImgBufQueNode>const& rvQueNode)  
  4. {  
  5.     /* 
  6.      * Notes: 
  7.      *  For 30 fps, we just enque (display) the latest frame,  
  8.      *  and cancel the others. 
  9.      *  For frame rate > 30 fps, we should judge the timestamp here or source. 
  10.      */  
  11.     //  (1) determine the latest DONE buffer index to display; otherwise CANCEL.  
  12.     int32_t idxToDisp = 0;  
  13.     for ( idxToDisp = rvQueNode.size()-1; idxToDisp >= 0; idxToDisp--)  
  14.     {  
  15.         if  ( rvQueNode[idxToDisp].isDONE() )  
  16.             break;  
  17.     }  
  18.     if  ( rvQueNode.size() > 1 )  
  19.     {  
  20.         MY_LOGW("(%d) display frame count > 1 --> select %d to display", rvQueNode.size(), idxToDisp);  
  21.     }  
  22.     //  
  23.     //  Show Time duration.  
  24.     if  ( 0 <= idxToDisp )  
  25.     {  
  26.         nsecs_t const _timestamp1 = rvQueNode[idxToDisp].getImgBuf()->getTimestamp();  
  27.         mProfile_buffer_timestamp.pulse(_timestamp1);  
  28.         nsecs_t const _msDuration_buffer_timestamp = ::ns2ms(mProfile_buffer_timestamp.getDuration());  
  29.         mProfile_buffer_timestamp.reset(_timestamp1);  
  30.         //  
  31.         mProfile_dequeProcessor.pulse();  
  32.         nsecs_t const _msDuration_dequeProcessor = ::ns2ms(mProfile_dequeProcessor.getDuration());  
  33.         mProfile_dequeProcessor.reset();  
  34.         //  
  35.         MY_LOGD_IF(  
  36.             (1<=miLogLevel), "+ %s(%lld) %s(%lld)",   
  37.             (_msDuration_buffer_timestamp < 0 ) ? "time inversion!" : "", _msDuration_buffer_timestamp,   
  38.             (_msDuration_dequeProcessor > 34) ? "34ms < Duration" : "", _msDuration_dequeProcessor  
  39.         );  
  40.     }  
  41.     //  
  42.     //  (2) Lock  
  43.     Mutex::Autolock _l(mModuleMtx);  
  44.     //  
  45.     //  (3) Remove from List and enquePrvOps/cancelPrvOps, one by one.  
  46.     int32_t const queSize = rvQueNode.size();  
  47.     for (int32_t i = 0; i < queSize; i++)  
  48.     {  
  49.         sp<IImgBuf>const&       rpQueImgBuf = rvQueNode[i].getImgBuf(); //  ImgBuf in Queue.  
  50.         sp<StreamImgBuf>const pStreamImgBuf = *mStreamBufList.begin();  //  ImgBuf in List.  
  51.         //  (.1)  Check valid pointers to image buffers in Queue & List  
  52.         if  ( rpQueImgBuf == 0 || pStreamImgBuf == 0 )  
  53.         {  
  54.             MY_LOGW("Bad ImgBuf:(Que[%d], List.begin)=(%p, %p)", i, rpQueImgBuf.get(), pStreamImgBuf.get());  
  55.             continue;  
  56.         }  
  57.         //  (.2)  Check the equality of image buffers between Queue & List.  
  58.         if  ( rpQueImgBuf->getVirAddr() != pStreamImgBuf->getVirAddr() )  
  59.         {  
  60.             MY_LOGW("Bad address in ImgBuf:(Que[%d], List.begin)=(%p, %p)", i, rpQueImgBuf->getVirAddr(), pStreamImgBuf->getVirAddr());  
  61.             continue;  
  62.         }  
  63.         //  (.3)  Every check is ok. Now remove the node from the list.  
  64.         mStreamBufList.erase(mStreamBufList.begin());//經過檢查返回的這一幀數據的Buffer是DisplayClient端分配和提供的。  
  65.         //  
  66.         //  (.4)  enquePrvOps/cancelPrvOps  
  67.         if  ( i == idxToDisp ) {  
  68.             MY_LOGD_IF(  
  69.                 (1<=miLogLevel),   
  70.                 "Show frame:%d %d [ion:%d %p/%d %lld]",   
  71.                 i, rvQueNode[i].getStatus(), pStreamImgBuf->getIonFd(),   
  72.                 pStreamImgBuf->getVirAddr(), pStreamImgBuf->getBufSize(), pStreamImgBuf->getTimestamp()  
  73.             );  
  74.             //  
  75.             if(mpExtImgProc != NULL)  
  76.             {  
  77.                 if(mpExtImgProc->getImgMask() & ExtImgProc::BufType_Display)  
  78.                 {  
  79.                     IExtImgProc::ImgInfo img;  
  80.                     //  
  81.                     img.bufType     = ExtImgProc::BufType_Display;  
  82.                     img.format      = pStreamImgBuf->getImgFormat();  
  83.                     img.width       = pStreamImgBuf->getImgWidth();  
  84.                     img.height      = pStreamImgBuf->getImgHeight();  
  85.                     img.stride[0]   = pStreamImgBuf->getImgWidthStride(0);  
  86.                     img.stride[1]   = pStreamImgBuf->getImgWidthStride(1);  
  87.                     img.stride[2]   = pStreamImgBuf->getImgWidthStride(2);  
  88.                     img.virtAddr    = (MUINT32)(pStreamImgBuf->getVirAddr());  
  89.                     img.bufSize     = pStreamImgBuf->getBufSize();  
  90.                     //  
  91.                     mpExtImgProc->doImgProc(img);  
  92.                 }  
  93.             }  
  94.             //  
  95.             enquePrvOps(pStreamImgBuf);//送入顯示端顯示  
  96.         }  
  97.         else {  
  98.             MY_LOGW(  
  99.                 "Drop frame:%d %d [ion:%d %p/%d %lld]",   
  100.                 i, rvQueNode[i].getStatus(), pStreamImgBuf->getIonFd(),   
  101.                 pStreamImgBuf->getVirAddr(), pStreamImgBuf->getBufSize(), pStreamImgBuf->getTimestamp()  
  102.             );  
  103.             cancelPrvOps(pStreamImgBuf);  
  104.         }  
  105.     }  
  106.     //  
  107.     MY_LOGD_IF((1<=miLogLevel), "-");  
  108.     return  true;  
  109. }  
  110.   
  111.   
  112.   
  113. void  
  114. DisplayClient::  
  115. enquePrvOps(sp<StreamImgBuf>const& rpImgBuf)  
  116. {  
  117.     mProfile_enquePrvOps.pulse();  
  118.     if  ( mProfile_enquePrvOps.getDuration() >= ::s2ns(2) ) {  
  119.         mProfile_enquePrvOps.updateFps();  
  120.         mProfile_enquePrvOps.showFps();  
  121.         mProfile_enquePrvOps.reset();  
  122.     }  
  123.     //  
  124.     status_t    err = 0;  
  125.     //  
  126.     CamProfile profile(__FUNCTION__, "DisplayClient");  
  127.     profile.print_overtime(  
  128.         ((1<=miLogLevel) ? 0 : 1000),   
  129.         "+ locked buffer count(%d), rpImgBuf(%p,%p), Timestamp(%lld)",   
  130.         mStreamBufList.size(), rpImgBuf.get(), rpImgBuf->getVirAddr(), rpImgBuf->getTimestamp()  
  131.     );  
  132.     //  
  133.     //  [1] unlock buffer before sending to display  
  134.     GraphicBufferMapper::get().unlock(rpImgBuf->getBufHndl());  
  135.     profile.print_overtime(1, "GraphicBufferMapper::unlock");  
  136.     //  
  137.     //  [2] Dump image if wanted.  
  138.     dumpImgBuf_If(rpImgBuf);  
  139.     //  
  140.     //  [3] set timestamp.  
  141.     err = mpStreamOps->set_timestamp(mpStreamOps, rpImgBuf->getTimestamp());  
  142.     profile.print_overtime(2, "mpStreamOps->set_timestamp, Timestamp(%lld)", rpImgBuf->getTimestamp());  
  143.     if  ( err )  
  144.     {  
  145.         MY_LOGE(  
  146.             "mpStreamOps->set_timestamp failed: status[%s(%d)], rpImgBuf(%p), Timestamp(%lld)",   
  147.             ::strerror(-err), -err, rpImgBuf.get(), rpImgBuf->getTimestamp()  
  148.         );  
  149.     }  
  150.     //  
  151.     //  [4] set gralloc buffer type & dirty  
  152.     ::gralloc_extra_setBufParameter(  
  153.         rpImgBuf->getBufHndl(),   
  154.         GRALLOC_EXTRA_MASK_TYPE | GRALLOC_EXTRA_MASK_DIRTY,   
  155.         GRALLOC_EXTRA_BIT_TYPE_CAMERA | GRALLOC_EXTRA_BIT_DIRTY  
  156.     );  
  157.     //  
  158.     //  [5] unlocks and post the buffer to display.  
  159.     err = mpStreamOps->enqueue_buffer(mpStreamOps, rpImgBuf->getBufHndlPtr());//注意這裏可以看到最終是通過mpStreamOps送入送給顯示端顯示的。  
  160.     profile.print_overtime(10, "mpStreamOps->enqueue_buffer, Timestamp(%lld)", rpImgBuf->getTimestamp());  
  161.     if  ( err )  
  162.     {  
  163.         MY_LOGE(  
  164.             "mpStreamOps->enqueue_buffer failed: status[%s(%d)], rpImgBuf(%p,%p)",   
  165.             ::strerror(-err), -err, rpImgBuf.get(), rpImgBuf->getVirAddr()  
  166.         );  
  167.     }  
  168. }  
bool
DisplayClient::
handleReturnBuffers(Vector<ImgBufQueNode>const& rvQueNode)
{
    /*
     * Notes:
     *  For 30 fps, we just enque (display) the latest frame, 
     *  and cancel the others.
     *  For frame rate > 30 fps, we should judge the timestamp here or source.
     */
    //  (1) determine the latest DONE buffer index to display; otherwise CANCEL.
    int32_t idxToDisp = 0;
    for ( idxToDisp = rvQueNode.size()-1; idxToDisp >= 0; idxToDisp--)
    {
        if  ( rvQueNode[idxToDisp].isDONE() )
            break;
    }
    if  ( rvQueNode.size() > 1 )
    {
        MY_LOGW("(%d) display frame count > 1 --> select %d to display", rvQueNode.size(), idxToDisp);
    }
    //
    //  Show Time duration.
    if  ( 0 <= idxToDisp )
    {
        nsecs_t const _timestamp1 = rvQueNode[idxToDisp].getImgBuf()->getTimestamp();
        mProfile_buffer_timestamp.pulse(_timestamp1);
        nsecs_t const _msDuration_buffer_timestamp = ::ns2ms(mProfile_buffer_timestamp.getDuration());
        mProfile_buffer_timestamp.reset(_timestamp1);
        //
        mProfile_dequeProcessor.pulse();
        nsecs_t const _msDuration_dequeProcessor = ::ns2ms(mProfile_dequeProcessor.getDuration());
        mProfile_dequeProcessor.reset();
        //
        MY_LOGD_IF(
            (1<=miLogLevel), "+ %s(%lld) %s(%lld)", 
            (_msDuration_buffer_timestamp < 0 ) ? "time inversion!" : "", _msDuration_buffer_timestamp, 
            (_msDuration_dequeProcessor > 34) ? "34ms < Duration" : "", _msDuration_dequeProcessor
        );
    }
    //
    //  (2) Lock
    Mutex::Autolock _l(mModuleMtx);
    //
    //  (3) Remove from List and enquePrvOps/cancelPrvOps, one by one.
    int32_t const queSize = rvQueNode.size();
    for (int32_t i = 0; i < queSize; i++)
    {
        sp<IImgBuf>const&       rpQueImgBuf = rvQueNode[i].getImgBuf(); //  ImgBuf in Queue.
        sp<StreamImgBuf>const pStreamImgBuf = *mStreamBufList.begin();  //  ImgBuf in List.
        //  (.1)  Check valid pointers to image buffers in Queue & List
        if  ( rpQueImgBuf == 0 || pStreamImgBuf == 0 )
        {
            MY_LOGW("Bad ImgBuf:(Que[%d], List.begin)=(%p, %p)", i, rpQueImgBuf.get(), pStreamImgBuf.get());
            continue;
        }
        //  (.2)  Check the equality of image buffers between Queue & List.
        if  ( rpQueImgBuf->getVirAddr() != pStreamImgBuf->getVirAddr() )
        {
            MY_LOGW("Bad address in ImgBuf:(Que[%d], List.begin)=(%p, %p)", i, rpQueImgBuf->getVirAddr(), pStreamImgBuf->getVirAddr());
            continue;
        }
        //  (.3)  Every check is ok. Now remove the node from the list.
        mStreamBufList.erase(mStreamBufList.begin());//經過檢查返回的這一幀數據的Buffer是DisplayClient端分配和提供的。
        //
        //  (.4)  enquePrvOps/cancelPrvOps
        if  ( i == idxToDisp ) {
            MY_LOGD_IF(
                (1<=miLogLevel), 
                "Show frame:%d %d [ion:%d %p/%d %lld]", 
                i, rvQueNode[i].getStatus(), pStreamImgBuf->getIonFd(), 
                pStreamImgBuf->getVirAddr(), pStreamImgBuf->getBufSize(), pStreamImgBuf->getTimestamp()
            );
            //
            if(mpExtImgProc != NULL)
            {
                if(mpExtImgProc->getImgMask() & ExtImgProc::BufType_Display)
                {
                    IExtImgProc::ImgInfo img;
                    //
                    img.bufType     = ExtImgProc::BufType_Display;
                    img.format      = pStreamImgBuf->getImgFormat();
                    img.width       = pStreamImgBuf->getImgWidth();
                    img.height      = pStreamImgBuf->getImgHeight();
                    img.stride[0]   = pStreamImgBuf->getImgWidthStride(0);
                    img.stride[1]   = pStreamImgBuf->getImgWidthStride(1);
                    img.stride[2]   = pStreamImgBuf->getImgWidthStride(2);
                    img.virtAddr    = (MUINT32)(pStreamImgBuf->getVirAddr());
                    img.bufSize     = pStreamImgBuf->getBufSize();
                    //
                    mpExtImgProc->doImgProc(img);
                }
            }
            //
            enquePrvOps(pStreamImgBuf);//送入顯示端顯示
        }
        else {
            MY_LOGW(
                "Drop frame:%d %d [ion:%d %p/%d %lld]", 
                i, rvQueNode[i].getStatus(), pStreamImgBuf->getIonFd(), 
                pStreamImgBuf->getVirAddr(), pStreamImgBuf->getBufSize(), pStreamImgBuf->getTimestamp()
            );
            cancelPrvOps(pStreamImgBuf);
        }
    }
    //
    MY_LOGD_IF((1<=miLogLevel), "-");
    return  true;
}



void
DisplayClient::
enquePrvOps(sp<StreamImgBuf>const& rpImgBuf)
{
    mProfile_enquePrvOps.pulse();
    if  ( mProfile_enquePrvOps.getDuration() >= ::s2ns(2) ) {
        mProfile_enquePrvOps.updateFps();
        mProfile_enquePrvOps.showFps();
        mProfile_enquePrvOps.reset();
    }
    //
    status_t    err = 0;
    //
    CamProfile profile(__FUNCTION__, "DisplayClient");
    profile.print_overtime(
        ((1<=miLogLevel) ? 0 : 1000), 
        "+ locked buffer count(%d), rpImgBuf(%p,%p), Timestamp(%lld)", 
        mStreamBufList.size(), rpImgBuf.get(), rpImgBuf->getVirAddr(), rpImgBuf->getTimestamp()
    );
    //
    //  [1] unlock buffer before sending to display
    GraphicBufferMapper::get().unlock(rpImgBuf->getBufHndl());
    profile.print_overtime(1, "GraphicBufferMapper::unlock");
    //
    //  [2] Dump image if wanted.
    dumpImgBuf_If(rpImgBuf);
    //
    //  [3] set timestamp.
    err = mpStreamOps->set_timestamp(mpStreamOps, rpImgBuf->getTimestamp());
    profile.print_overtime(2, "mpStreamOps->set_timestamp, Timestamp(%lld)", rpImgBuf->getTimestamp());
    if  ( err )
    {
        MY_LOGE(
            "mpStreamOps->set_timestamp failed: status[%s(%d)], rpImgBuf(%p), Timestamp(%lld)", 
            ::strerror(-err), -err, rpImgBuf.get(), rpImgBuf->getTimestamp()
        );
    }
    //
    //  [4] set gralloc buffer type & dirty
    ::gralloc_extra_setBufParameter(
        rpImgBuf->getBufHndl(), 
        GRALLOC_EXTRA_MASK_TYPE | GRALLOC_EXTRA_MASK_DIRTY, 
        GRALLOC_EXTRA_BIT_TYPE_CAMERA | GRALLOC_EXTRA_BIT_DIRTY
    );
    //
    //  [5] unlocks and post the buffer to display.
    err = mpStreamOps->enqueue_buffer(mpStreamOps, rpImgBuf->getBufHndlPtr());//注意這裏可以看到最終是通過mpStreamOps送入送給顯示端顯示的。
    profile.print_overtime(10, "mpStreamOps->enqueue_buffer, Timestamp(%lld)", rpImgBuf->getTimestamp());
    if  ( err )
    {
        MY_LOGE(
            "mpStreamOps->enqueue_buffer failed: status[%s(%d)], rpImgBuf(%p,%p)", 
            ::strerror(-err), -err, rpImgBuf.get(), rpImgBuf->getVirAddr()
        );
    }
}



從上面的代碼片段, 可以看到從顯示數據最終是通過mpStreamOps(CameraHardwareInterface中傳下來的的mHalPreviewWindow.nw)來進行處理的。

至此預覽數據就算完全交給了ANativeWindow進行顯示。

轉載:http://blog.csdn.net/wsb1321/article/details/21975951

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章