一.基本關係
1.先來看看KTM hal層大概類圖關係:
大概類圖關係就是這樣, 其中和顯示相關的類圖關係如紅線所圈區域。
可以猜測到 與顯示相關的邏輯處理應該都會在DisplayClient這個類去實現。
以後app下達有關預覽顯示相關的東西啊在hal層基本上都是這一條先進行傳遞命令, 不過總1中我們可以看到CamDevice還有一些衍生類, 這些都是mtk爲不同設備做的一些定製, 主要的路徑還是如上圖所示。
二.接着之前的在CameraClient中的代碼:
- //!++
- else if ( window == 0 ) {
- result = mHardware->setPreviewWindow(window);
- }
//!++
else if ( window == 0 ) {
result = mHardware->setPreviewWindow(window);
}
1.setPreviewWindow(window)通過CameraHardwareInterface適配:
- mDevice->ops->set_preview_window(mDevice,
- 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的定義:
- struct camera_preview_window {
- struct preview_stream_ops nw;
- void *user;
- };
struct camera_preview_window {
struct preview_stream_ops nw;
void *user;
};
就是結構體:struct :
- 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);
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中的:
- mDevice->ops->set_preview_window(mDevice,
- 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:
可以看到:
- 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,
- };
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的發發調用。
- 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;
- }
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;
}
- static inline ICamDevice* getIDev(camera_device*const device)
- {
- return (NULL == device)
- ? NULL
- : 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實際上是在創建實例的時候指向的自己:
- 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指向的結構體
- }
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:
- 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;
- }
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;
}
- 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;
- }
- ..................
- ..................
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;
}
..................
..................
- 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;
- }
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中:
- 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;
- }
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)
- 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);//
- }
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);//
}
- 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
- );
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):
- 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;
- };
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() :
- 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;
- }
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;
}
- 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;
- }
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函數:
- 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;
- }
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);進行分析:
- 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;
- }
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函數:
- 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()
- );
- }
- }
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進行顯示。