Camera显示之Hal层的适配二.docx
- 文档编号:4368301
- 上传时间:2022-12-01
- 格式:DOCX
- 页数:6
- 大小:20.40KB
Camera显示之Hal层的适配二.docx
《Camera显示之Hal层的适配二.docx》由会员分享,可在线阅读,更多相关《Camera显示之Hal层的适配二.docx(6页珍藏版)》请在冰豆网上搜索。
Camera显示之Hal层的适配二
Camera显示之Hal层的适配
(二)
接着上一篇:
Camera显示之Hal层的适配
(一)
一.基本关系1.先来看看KTMhal层大概类图关系:
大概类图关系就是这样,其中和显示相关的类图关系如红线所圈区域。
可以猜测到与显示相关的逻辑处理应该都会在DisplayClient这个类去实现。
2.CamDeviceManager和DisplayClient关系的建立:
以后app下达有关预览显示相关的东西啊在hal层基本上都是这一条先进行传递命令,不过总1中我们可以看到CamDevice还有一些衍生类,这些都是mtk为不同设备做的一些定制,主要的路径还是如上图所示。
二.接着之前的在CameraClient中的代码:
//!
++elseif(window==0){result=mHardware->setPreviewWindow(window);}1.setPreviewWindow(window)通过CameraHardwareInterface适配:
mDevice->ops->set_preview_window(mDevice,buf.get()?
&mHalPreviewWindow.nw:
0);
来实现向hal层下达命令和设置参数。
在这里我们发现传入的是mHalPreviewWindow.nw,而不是我们之前所讲述的ANativeWindow这是因为mHalPreviewWindow.nw将ANativeWindow的一些流的操作进行封装,使之操作更加简便。
mHalPreviewWindow.nw的定义:
structcamera_preview_window{structpreview_stream_opsnw;void*user;};
就是结构体:
struct:
typedefstructpreview_stream_ops{int(*dequeue_buffer)(structpreview_stream_ops*w,buffer_handle_t**buffer,int*stride);int(*enqueue_buffer)(structpreview_stream_ops*w,buffer_handle_t*buffer);int(*cancel_buffer)(structpreview_stream_ops*w,buffer_handle_t*buffer);int(*set_buffer_count)(structpreview_stream_ops*w,intcount);int(*set_buffers_geometry)(structpreview_stream_ops*pw,intw,inth,intformat);int(*set_crop)(structpreview_stream_ops*w,intleft,inttop,intright,intbottom);int(*set_usage)(structpreview_stream_ops*w,intusage);int(*set_swap_interval)(structpreview_stream_ops*w,intinterval);int(*get_min_undequeued_buffer_count)(conststructpreview_stream_ops*w,int*count);int(*lock_buffer)(structpreview_stream_ops*w,buffer_handle_t*buffer);//Timestampsaremeasuredinnanoseconds,andmustbecomparable//andmonotonicallyincreasingbetweentwoframesinthesame//previewstream.Theydonotneedtobecomparablebetween//consecutiveorparallelpreviewstreams,cameras,orappruns.int(*set_timestamp)(structpreview_stream_ops*w,int64_ttimestamp);
对显示流的操作都是通过这些函数实现的,而mHalPreviewWindow中实现了具体操的方法,在这些方法的实现中实现对作ANativeWindow的操作。
而在hal端就是通过mHalPreviewWindow.nw进行对ANativeWindow的具体操作。
基本类图关系:
2.继续1中的:
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:
可以看到:
staticcamera_device_ops_tconstgCameraDevOps={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的发发调用。
staticintcamera_set_preview_window(structcamera_device*device,structpreview_stream_ops*window){interr=-EINVAL;//ICamDevice*constpDev=ICamDevice:
:
getIDev(device);if(pDev){err=pDev->setPreviewWindow(window);}//returnerr;}staticinlineICamDevice*getIDev(camera_device*constdevice){return(NULL==device)?
NULL:
reinterpret_cast(device->priv);//得到device->priv由上篇文章:
知道device->pri实际上是在创建实例的时候指向的自己:
ICamDevice:
:
ICamDevice():
camera_device_t(),RefBase(),mDevOps()//,mMtxLock()//{MY_LOGD('ctor');:
:
memset(static_cast(this),0,sizeof(camera_device_t));this->priv=this;//用priv指针保存自己。
this->ops=&mDevOps;//ops指向了mDevOpsmDevOps=gCameraDevOps;//mDevOps为gCameraDevOps指向的结构体}
继续回到pDev->setPreviewWindow(window);在ICamDevice中没有对setPreviewWindow具体的实现,而是在其子类CamDevice对ICamDevice进行了具体的实现;随意代码定位到CamDevice:
status_tCamDevice:
:
setPreviewWindow(preview_stream_ops*window){MY_LOGI('+window(%p)',window);//status_tstatus=initDisplayClient(window);//开始初始化DisplayClientif(OK==status&&previewEnabled()&&mpDisplayClient!
=0){status=enableDisplayClient();//时能DisplayClient端}//returnstatus;}status_tCamDevice:
:
initDisplayClient(preview_stream_ops*window){#if'1'!
=MTKCAM_HAVE_DISPLAY_CLIENT#warning'NotBuildDisplayClient'MY_LOGD('NotBuildDisplayClient');.........................../[3.1]createaDisplayClient.mpDisplayClient=IDisplayClient:
:
createInstance();if(mpDisplayClient==0){MY_LOGE('CannotcreatempDisplayClient');status=NO_MEMORY;gotolbExit;}//[3.2]initializethenewly-createdDisplayClient.if(!
mpDisplayClient->init()){MY_LOGE('mpDisplayClientinit()failed');mpDisplayClient->uninit();mpDisplayClient.clear();status=NO_MEMORY;gotolbExit;}//[3.3]setpreview_stream_ops&relatedwindowinfo.if(!
mpDisplayClient->setWindow(window,previewSize.width,previewSize.height,queryDisplayBufCount()))//绑定window{status=INVALID_OPERATION;gotolbExit;}//[3.4]setImageBufferProviderClientifitexist.if(mpCamAdapter!
=0&&!
mpDisplayClient->setImgBufProviderClient(mpCamAdapter))//重要!
设置流数据的Buffer提供者。
{status=INVALID_OPERATION;gotolbExit;}....................................
status_tCamDevice:
:
enableDisplayClient(){status_tstatus=OK;SizepreviewSize;////[1]Getpreviewsize.if(!
queryPreviewSize(previewSize.width,previewSize.height)){MY_LOGE('queryPreviewSize');status=DEAD_OBJECT;gotolbExit;}////[2]Enableif(!
mpDisplayClient->enableDisplay(previewSize.width,previewSize.height,queryDisplayBufCount(),mpCamAdapter))//设置了预览数据的尺寸和Buffer提供者相关的数据{MY_LOGE('mpDisplayClient(%p)->enableDisplay()',mpDisplayClient.get());status=INVALID_OPERATION;gotolbExit;}//status=OK;lbExit:
returnstatus;}3.定位到DisplayClient中:
enableDisplay(int32_tconsti4Width,int32_tconsti4Height,int32_tconsti4BufCount,spconst&rpClient){boolret=false;preview_stream_ops*pStreamOps=mpStreamOps;////[1]Re-configuratethisinstanceifanysettingchanges.if(!
checkConfig(i4Width,i4Height,i4BufCount,rpClient)){MY_LOGW('UninitthecurrentDisplayClient(%p)andre-config...',this);////[.1]uninitializeuninit();////[.2]initializeif(!
init()){MY_LOGE('re-init()failed');gotolbExit;}////[.3]setrelatedwindowinfo.if(!
setWindow(pStreamOps,i4Width,i4Height,i4BufCount))//window的尺寸和预览数据的大小一致{gotolbExit;}////[.4]setImageBufferProviderClient.if(!
setImgBufProviderClient(rpClient))//Buffer的数据提供者为mpCamAdapter,就是CamAdapter,后面的预览数据元都是通过它来提供。
{gotolbExit;}}////[2]Enable.if(!
enableDisplay())//开始进行数据的获取和显示{gotolbExit;}//ret=true;lbExit:
returnret;}
先来看看第一个关键函数:
setWindow(pStreamOps,i4Width,i4Height,i4BufCount)
boolDisplayClient:
:
setWindow(preview_stream_ops*constwindow,int32_tconstwndWidth,int32_tconstwndHeight,int32_tconsti4MaxImgBufCount){MY_LOGI('+window(%p),WxH=%dx%d,count(%d)',window,wndWidth,wndHeight,i4MaxImgBufCount);//if(!
window){MY_LOGE('NULLwindowpassedinto');returnfalse;}//if(0>=wndWidth||0>=wndHeight||0>=i4MaxImgBufCount){MY_LOGE('badarguments-WxH=%dx%d,count(%d)',wndWidth,wndHeight,i4MaxImgBufCount);returnfalse;}////Mutex:
:
Autolock_l(mModuleMtx);returnset_preview_stream_ops(window,wndWidth,wndHeight,i4MaxImgBufCount);//}oolDisplayClient:
:
set_preview_stream_ops(preview_stream_ops*constwindow,int32_tconstwndWidth,int32_tconstwndHeight,int32_tconsti4MaxImgBufCount){CamProfileprofile(__FUNCTION__,'DisplayClient');//boolret=false;status_terr=0;int32_tmin_undequeued_buf_count=0;////
(2)Checkif(!
mStreamBufList.empty()){MY_LOGE('lockedbuffercount(%d)!
=0,''callersmustreturnalldequeuedbuffers,'//'andthencallcleanupQueue()',mStreamBufList.size());dumpDebug(mStreamBufList,__FUNCTION__);gotolbExit;}////(3)Savainfo.mpStreamImgInfo.clear();//mpStreamImgInfo封装的视屏数据流的基本信息。
mpStreamImgInfo=newImgInfo(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_countfailed:
status[%s(%d)]',:
:
strerror(-err),-err);if(ENODEV==err){MY_LOGD('Previewsurfaceabandoned!
');mpStreamOps=NULL;}gotolbExit;}////(4.4)Setwindowgeometryerr=mpStreamOps->set_buffers_geometry(//设置基本的流信息mpStreamOps,mpStreamImgInfo->mu4ImgWidth,mpStreamImgInfo->mu4ImgHeight,mpStreamImgInfo->mi4ImgFormat);
通过上面的代码片段和分析,确定了上层传递下来的对象指针保存在mpStreamOps,与显示相关的交互都将通过mpStreamOps来进行操作。
而mpStreamImgInfo封装了流数据的大小和格式等。
再来看看第二个关键函数:
setImgBufProviderClient(rpClient):
boolDisplayClient:
:
setImgBufProviderClient(spconst&rpClient){boolret=false;//MY_LOGD('+ImgBufProviderClient(%p),mpImgBufQueue.get(%p)',rpClient.get(),mpImgBufQueue.get());//if(rpClient==0){MY_LOGE('NULLImgBufProviderClient');mpImgBufPvdrClient=NULL;gotolbExit;}//if(mpImgBufQueue!
=0){if(!
rpClient->onImgBufProviderCreated(mpImgBufQueue))//通知Provider端(Buffer数据提供者端),我这边已经建好Buffer队列,后面你就填充数据到对应的Buffer供我使用。
{gotolbExit;}mpImgBufPvdrClient=rpClient;//用mpImgBufPvdrClient保存provider的对象指针,方便使用。
}//ret=true;lbExit:
MY_LOGD('-');returnret;};
再来看看第三个关键函数
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Camera 显示 Hal 适配二