上一篇讲了怎么让Camera进入预览模式,提到了DisplayClient负责显示图像数据,而CamAdapter负责提供图像数据,这里主要记录了CamAdapter怎么获取图像,然后DisplayClient怎么将图像显示在屏幕上。
2. DisplayClient
上一篇提到在setPreviewWindow的时候会构造并初始化DisplayClient,之前没有仔细分析,现在来看看
bool
DisplayClient::
init()
{
bool ret = false;
ret = createDisplayThread()
&& createImgBufQueue();
return ret;
}
创建了一个显示线程和一个ImgBuf队列,看下这两个函数的具体实现
bool
DisplayClient::
createDisplayThread()
{
bool ret = false;
status_t status = OK;
mpDisplayThread = IDisplayThread::createInstance(this);
if ( mpDisplayThread == 0 || OK != (status = mpDisplayThread->run()) )
{
......
}
ret = true;
lbExit:
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
bool
DisplayClient::
createImgBufQueue()
{
bool ret = false;
mpImgBufQueue = new ImgBufQueue(IImgBufProvider::eID_DISPLAY, "CameraDisplay@ImgBufQue");
if ( mpImgBufQueue == 0 )
{
MY_LOGE("Fail to new ImgBufQueue");
goto lbExit;
}
......
ret = true;
lbExit:
MY_LOGD("-");
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
ImgBufQueue暂时放一边,createDisplayThread创建了DisplayThread,作为线程关注的重点当然是threadLoop,所以接着看DisplayThread的threadLoop函数
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);
}
break;
}
}
return true;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
DisplayThread将接收WAKEUP命令,然后做出响应。那么由谁来发这个WAKEUP命令呢,就在上一篇提到的enableDisplayClient函数里面发送。这里的mpThreadHandler 指的是DisplayClient,也就是在接收到WAKEUP命令后,将回调DisplayClient的onThreadLoop函数
bool
DisplayClient::
onThreadLoop(Command const& rCmd)
{
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;
}
}
if ( ! prepareAllTodoBuffers(pImgBufQueue) )
{
return true;
}
if ( ! pImgBufQueue->startProcessor() )
{
return true;
}
while(1)
{
waitAndHandleReturnBuffers(pImgBufQueue);
if ( ! isDisplayEnabled() )
{
MY_LOGI("Display disabled");
break;
}
prepareAllTodoBuffers(pImgBufQueue);
}
......
return true;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
先分析步骤(1)准备好接收数据的buffers
/******************************************************************************
* dequePrvOps() -> enqueProcessor() & enque Buf List
*******************************************************************************/
bool
DisplayClient::
prepareAllTodoBuffers(sp<IImgBufQueue>const& rpBufQueue)
{
bool ret = false;
while ( mStreamBufList.size() < (size_t)mi4MaxImgBufCount )
{
if ( ! prepareOneTodoBuffer(rpBufQueue) )
{
break;
}
}
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
bool
DisplayClient::
prepareOneTodoBuffer(sp<IImgBufQueue>const& rpBufQueue)
{
bool ret = false;
......
sp<StreamImgBuf> pStreamImgBuf;
if ( ! dequePrvOps(pStreamImgBuf) )
{
goto lbExit;
}
ret = rpBufQueue->enqueProcessor(
ImgBufQueNode(pStreamImgBuf, ImgBufQueNode::eSTATUS_TODO)
);
mStreamBufList.push_back(pStreamImgBuf);
ret = true;
lbExit:
MY_LOGD_IF((2<=miLogLevel), "- ret(%d)", ret);
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
这里的ImgBufQueue就是DisplayClient初始化的时候创建的那个ImgBufQueue,里有两个Buf队列,mTodoImgBufQue和mDoneImgBufQue。prepareOneTodoBuffer函数做的事情就是从dequePrvOps 函数deque出StreamImgBuf,并用它生成ImgBufQueNode,把ImgBufQueNode的标志位设eSTATUS_TODO后调用ImgBufQueue的enqueProcessor函数把所有的ImgBufQueNode都放入到mTodoImgBufQue做接收数据的准备。看下dequePrvOps和enqueProcessor的实现
bool
DisplayClient::
dequePrvOps(sp<StreamImgBuf>& rpImgBuf)
{
err = mpStreamOps->dequeue_buffer(mpStreamOps, &phBuffer, &stride);
err = mpStreamOps->lock_buffer(mpStreamOps, phBuffer);
......
rpImgBuf = new StreamImgBuf(mpStreamImgInfo, stride, address, phBuffer, fdIon);
ret = true;
lbExit:
return ret;
}
值得一提的是mpStreamOps,它就是上一篇不断提到的mHalPreviewWindow.nw,调用它的dequeue_buffer函数就相当于从Surface中dequeue一个buffer出来,将buffer填满后通过调用enqueue_buffer函数将buffer传给Surface,这样图像就得以显示。
bool
ImgBufQueue::
enqueProcessor(ImgBufQueNode const& rNode)
{
......
mTodoImgBufQue.push_back(rNode);
return true;
}
把所有的ImgBufQueNode都放入到mTodoImgBufQue做接收数据的准备。
回到onThreadLoop函数,步骤(3)进入死循环,不断调用waitAndHandleReturnBuffers函数来接收处理buffer,同时调用 prepareAllTodoBuffers函数来将处理完的buffer重新放回 mTodoImgBufQue,接着看如何接收处理buffer
bool
DisplayClient::
waitAndHandleReturnBuffers(sp<IImgBufQueue>const& rpBufQueue)
{
bool ret = false;
Vector<ImgBufQueNode> vQueNode;
......
rpBufQueue->dequeProcessor(vQueNode);
ret = handleReturnBuffers(vQueNode);
lbExit:
return ret;
}
在此处调用ImgBufQueue的dequeProcessor()等待通知并接收数据。然后再调用handleReturnBuffers函数将数据发给Surface
ImgBufQueue::
dequeProcessor(Vector<ImgBufQueNode>& rvNode)
{
bool ret = false;
while ( mDoneImgBufQue.empty() && mbIsProcessorRunning )
{
status_t status = mDoneImgBufQueCond.wait(mDoneImgBufQueMtx);
}
if ( ! mDoneImgBufQue.empty() )
{
ret = true;
rvNode = mDoneImgBufQue;
mDoneImgBufQue.clear();
}
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
通过mDoneImgBufQueCond.wait(mDoneImgBufQueMtx)等待通知,收到通知后,从mDoneImgBufQue取出所有的ImgBufQueNode,这时候ImgBufQueNode里面已经包含了图像数据。
bool
DisplayClient::
handleReturnBuffers(Vector<ImgBufQueNode>const& rvQueNode)
{
for (int32_t i = 0; i < queSize; i++)
{
sp<IImgBuf>const& rpQueImgBuf = rvQueNode[i].getImgBuf();
sp<StreamImgBuf>const pStreamImgBuf = *mStreamBufList.begin();
if ( rpQueImgBuf == 0 || pStreamImgBuf == 0 )
{
......
continue;
}
if ( rpQueImgBuf->getVirAddr() != pStreamImgBuf->getVirAddr() )
{
......
continue;
}
mStreamBufList.erase(mStreamBufList.begin());
if ( i == idxToDisp ) {
......
enquePrvOps(pStreamImgBuf);
}
}
return true;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
for循环里面通过 enquePrvOps函数将一个个StreamImgBuf发给Surface
void
DisplayClient::
enquePrvOps(sp<StreamImgBuf>const& rpImgBuf)
{
......
err = mpStreamOps->enqueue_buffer(mpStreamOps, rpImgBuf->getBufHndlPtr());
}
就如前面提到的,将buffer填满后需要调用enqueue_buffer函数,这样图像就已经发往Surface。
那么图像数据从哪里来呢,DisplayClient一共维护了两个队列 mTodoImgBufQue和mDoneImgBufQue,也就是说肯定在某个地方有人从mTodoImgBufQue deque了一个ImgBufQueNode,将它填满后enque到mDoneImgBufQue里面并发送通知告诉DisplayClient数据已经准备好
3. Pass1Node
上一篇提到由CamAdapter提供图像数据给DisplayClient。它的大部分工作分别由各个CamNode完成,其中Pass1Node负责和sensor driver打交道,最初的图像数据就是由它来获取,之前已经看过它的onInit和onStart函数,现在来看它的threadLoopUpdate函数
MBOOL
Pass1NodeImpl::
threadLoopUpdate()
{
MBOOL ret = MTRUE;
if( keepLooping() )
{
ret = dequeLoop();
enqueBuffer();
}
else
{
ret = stopHw();
syncWithThread();
}
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
这里值得关注的只有dequeLoop函数
MBOOL
Pass1NodeImpl::
dequeLoop()
{
MBOOL ret = MTRUE;
QBufInfo dequeBufInfo;
dequeBufInfo.mvOut.reserve(2);
if( mpRingImgo ) {
BufInfo OutBuf(mpRingImgo->getPortID(), 0);
dequeBufInfo.mvOut.push_back(OutBuf);
}
if( mpRingRrzo ) {
BufInfo OutBuf(mpRingRrzo->getPortID(), 0);
dequeBufInfo.mvOut.push_back(OutBuf);
}
for(MUINT32 i=0; i<2; i++)
{
MY_LOGD("frame %d: deque+", muFrameCnt);
ret = mpCamIO->deque(dequeBufInfo);
MY_LOGD("frame %d: deque-,%d", muFrameCnt, ret);
......
}
......
handleNotify(
PASS1_EOF,
newMagicNum,
muSensorDelay == 0 ? dequeMagicNum : MAGIC_NUM_INVALID);
configFrame(newMagicNum);
......
vector<BufInfo>::const_iterator iter;
for( iter = dequeBufInfo.mvOut.begin(); iter != dequeBufInfo.mvOut.end(); iter++ )
{
mpIspSyncCtrlHw->addPass1Info(
iter->mMetaData.mMagicNum_hal,
iter->mBuffer,
iter->mMetaData,
iter->mPortID == PORT_RRZO);
......
ret = ret && handlePostBuffer( mapToNodeDataType(iter->mPortID, bIsDynamicPureRaw), (MUINTPTR)iter->mBuffer, iter->mMetaData.mMagicNum_hal);
}
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
第23行,通过mpCamIO->deque取出一帧数据
第30-33行,发送 PASS1_EOF消息,其它的CamNode接收到消息后做相应的处理,例如更新3A
第35行, configFrame不知道它在做什么,有待研究
第42-46行,将Pass1的deque信息加入到IspSyncCtrl
第48行,将deque到的数据post到Pass2Node(其实是post到DefaultCtrlNode,再由它post给Pass2Node)
这里CamIO指的是NormalPipe,在Pass1Node的onInit函数里创建,看下它如何deque数据
MBOOL
NormalPipe::deque(QBufInfo& rQBuf, MUINT32 u4TimeoutMs)
{
for (MUINT32 ii=0
if (MFALSE == mpCamIOPipe->dequeOutBuf(portID, rQTSBufInfo) ) {
......
}
if ( rQTSBufInfo.vBufInfo.size() >= 1 ) {
......
buff.mPortID = rQBuf.mvOut.at(ii).mPortID
buff.mBuffer = pframe
buff.mMetaData = result
buff.mSize = rQTSBufInfo.vBufInfo.at(idx).u4BufSize[0]
buff.mVa = rQTSBufInfo.vBufInfo.at(idx).u4BufVA[0]
buff.mPa = rQTSBufInfo.vBufInfo.at(idx).u4BufPA[0]
rQBuf.mvOut.at(ii) = buff
}
}
return ret
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
MBOOL
CamIOPipe::
dequeOutBuf(PortID const portID, QTimeStampBufInfo& rQBufInfo, MUINT32 const u4TimeoutMs )
{
MUINT32 dmaChannel = 0
stISP_FILLED_BUF_LIST bufInfo
ISP_BUF_INFO_L bufList
......
bufInfo.pBufList = &bufList
if ( 0 != this->m_CamPathPass1.dequeueBuf( dmaChannel,bufInfo) ) {
......
}
rQBufInfo.vBufInfo.resize(bufList.size())
for ( MINT32 i = 0
rQBufInfo.vBufInfo[i].memID[0] = bufList.front().memID
rQBufInfo.vBufInfo[i].u4BufSize[0] = bufList.front().size
rQBufInfo.vBufInfo[i].u4BufVA[0] = bufList.front().base_vAddr
rQBufInfo.vBufInfo[i].u4BufPA[0] = bufList.front().base_pAddr
rQBufInfo.vBufInfo[i].i4TimeStamp_sec = bufList.front().timeStampS
rQBufInfo.vBufInfo[i].i4TimeStamp_us = bufList.front().timeStampUs
rQBufInfo.vBufInfo[i].img_w = bufList.front().img_w
rQBufInfo.vBufInfo[i].img_h = bufList.front().img_h
rQBufInfo.vBufInfo[i].img_stride = bufList.front().img_stride
rQBufInfo.vBufInfo[i].img_fmt = bufList.front().img_fmt
......
bufList.pop_front()
}
return MTRUE
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
int CamPathPass1::dequeueBuf( MUINT32 dmaChannel ,stISP_FILLED_BUF_LIST& bufInfo )
{
int ret = 0;
Mutex *_localVar;
if ( MFALSE == this->ispBufCtrl.waitBufReady(dmaChannel) ) {
......
}
if ( eIspRetStatus_Success != this->ispBufCtrl.dequeueHwBuf( dmaChannel, bufInfo ) ) {
......
}
return ret;
}
第7行,当buffer准备好时ISP会产生一个中断,而这里将通过ioctl去等待获取这个中断
第11行,从底层获取已经填满的buffer
EIspRetStatus
ISP_BUF_CTRL::
dequeueHwBuf( MUINT32 dmaChannel, stISP_FILLED_BUF_LIST& bufList )
{
if ( ISP_PASS1 == this->path || \
ISP_PASS1_D == this->path_D || \
ISP_PASS1_CAMSV == this->path || \
ISP_PASS1_CAMSV_D == this->path_D
) {
buf_ctrl.ctrl = ISP_RT_BUF_CTRL_DEQUE;
buf_ctrl.buf_id = (_isp_dma_enum_)rt_dma;
buf_ctrl.data_ptr = 0;
buf_ctrl.pExtend = (unsigned char*)&deque_buf;
if ( MTRUE != this->m_pIspDrvShell->m_pPhyIspDrv_bak->rtBufCtrl((void*)&buf_ctrl) ) {
ISP_FUNC_ERR("ERROR:rtBufCtrl");
ret = eIspRetStatus_Failed;
goto EXIT;
}
......
} else {
......
}
EXIT:
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
MBOOL IspDrvImp::rtBufCtrl(void *pBuf_ctrl)
{
MINT32 Ret;
Ret = ioctl(mFd,ISP_BUFFER_CTRL,pBuf_ctrl);
return MTRUE;
}
mFd是通过open(“/dev/camera-isp”, O_RDWR)得到的,而这里通过ioctl获取到已经填满的buffer的地址。
Pass1NodeImplPass1NodeImplNormalPipeNormalPipeCamIOPipeCamIOPipeCamPathPass1CamPathPass1ISP_BUF_CTRLISP_BUF_CTRLIspDrvImpIspDrvImpdequeLoopdequedequeOutBufdequeueBufwaitBufReadywaitIrqioctl(ISP_WAIT_IRQ)check if there is already filled bufferdequeueHwBufrtBufCtrlioctl(ISP_BUFFER_CTRL)move FILLED buffer from hw to sw list
到这里我们已经获取到了一帧图像,但还是不知道是谁把buffer放到DisplayClient的mDoneImgBufQue里面去
4. Pass2Node
回到Pass1Node的dequeLoop函数,最后一个步骤handlePostBuffer函数。上一篇提到在CamAdapter的onHandleStartPreview函数里面,通过connectData把Pass1Node和DefaultCtrlNode连接起来,把Pass2Node和DefaultCtrlNode连接起来
mpCamGraph->connectData(PASS1_RESIZEDRAW,CONTROL_RESIZEDRAW,mpPass1Node,mpDefaultCtrlNode);
mpCamGraph->connectData(CONTROL_PRV_SRC,PASS2_PRV_SRC,mpDefaultCtrlNode,mpPass2Node);
所以Pass1Node的handlePostBuffer函数会先把buffer post到DefaultCtrlNode,DefaultCtrlNode接收到之后再将它post给Pass2Node,这里直接看Pass2Node的onPostBuffer函数
4.1 onPostBuffer函数分析
MBOOL
Pass2NodeImpl::
onPostBuffer(MUINT32 const data, MUINTPTR const buf, MUINT32 const ext)
{
if( pushBuf(data, (IImageBuffer*)buf, ext) )
{
// no thing
}
}
MBOOL
Pass2NodeImpl::
pushBuf(MUINT32 const data, IImageBuffer* const buf, MUINT32 const ext)
{
PostBufInfo postBufData = {data, buf, ext};
mlPostBufData.push_back(postBufData);
muPostFrameCnt++;
if( isReadyToEnque() )
{
triggerLoop();
}
return MTRUE;
}
保存好buffer之后调用triggerLoop函数,triggerLoop会给自身的线程发送update命令,然后Pass2Node的threadLoopUpdate函数就会被调用
MBOOL
Pass2NodeImpl::
threadLoopUpdate()
{
MBOOL ret = MTRUE
ret = enquePass2(MTRUE)
return ret
}
MBOOL
Pass2NodeImpl::
enquePass2(MBOOL const doCallback)
{
QParams enqueParams;
vector<p2data> vP2data;
if( !getPass2Buffer(vP2data) )
{
return MTRUE;
}
......
configFeature();
if( !mpIspSyncCtrlHw->lockHw(IspSyncControlHw::HW_PASS2) )
{
......
}
enqueParams.mpfnCallback = pass2CbFunc;
enqueParams.mpCookie = this;
if( !mpPostProcPipe->enque(enqueParams) )
{
......
}
return MTRUE;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
第8行,通过DefaultBufHandler从mTodoImgBufQue取出buffer
第23行,enque目标buffer到IHalPostProcPipe,至于IHalPostProcPipe做了些什么事情我也不知道,可能是图像缩放之类的工作,有待研究。IHalPostProcPipe处理完之后会回调pass2CbFunc函数。Pass2CbFunc会把处理过的buffer通过DefaultBufHandler放回mDoneImgBufQue里面。
DefaultBufHandler的作用是管理所有的CamClient的buffer队列,例如DisplayClient。DisplayClient需要调用setImgBufProviderClient函数来把它的ImgBufQueue加入到ImgBufProvidersManager的IImgBufProvider列表中。从类图可以看到,Pass2Node只要获取到DefaultBufHandler,就能拿到DisplayClient的ImgBufQueue
4.2 getPass2Buffer函数分析
MBOOL
PrvPass2::
getPass2Buffer(vector<p2data>& vP2data)
{
MBOOL haveDst = MFALSE;
{
Mutex::Autolock lock(mLock);
p2data one;
MUINT32 count = 0;
if( mlPostBufData.size() < muMultiFrameNum )
{
......
}
list<PostBufInfo>::iterator iter = mlPostBufData.begin();
while( iter != mlPostBufData.end() )
{
one.src = *iter;
iter = mlPostBufData.erase(iter);
vP2data.push_back(one);
count++;
if(count == muMultiFrameNum)
{
break;
}
}
}
{
MBOOL bDequeDisplay = MTRUE;
vector<p2data>::iterator pData = vP2data.begin();
while( pData != vP2data.end() )
{
for(MUINT32 i = 0; i < MAX_DST_PORT_NUM; i++)
{
MBOOL ret;
ImgRequest outRequest;
......
ret = getDstBuffer(
muDequeOrder[i],
&outRequest);
if(ret)
{
haveDst = MTRUE;
if(muDequeOrder[i] == PASS2_PRV_DST_0)
{
bDequeDisplay = MFALSE;
}
pData->vDstReq.push_back(outRequest);
pData->vDstData.push_back(muDequeOrder[i]);
}
}
......
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
第6-31行,把之前保存在mlPostBufData里的图像数据取出来并保存在p2data中
第46-48行,从DefaultBufHandler取出所有CamClient的buffer
第50-61行,把从DefaultBufHandler获取到的目标buffer一起放到p2data中
MBOOL
Pass2NodeImpl::
getDstBuffer(
MUINT32 nodeData,
ImgRequest* pImgReq)
{
MBOOL ret = MFALSE
ICamBufHandler* pBufHdl = getBufferHandler(nodeData)
if(pBufHdl && pBufHdl->dequeBuffer(nodeData, pImgReq))
{
ret = MTRUE
}
return ret
}
MBOOL
DefaultBufHandlerImpl::
dequeBuffer(MUINT32 const data, ImgRequest * pImgReq)
{
......
sp<IImgBufProvider> bufProvider = NULL;
switch((*iterMapPort).bufType)
{
case eBuf_Disp:
{
bufProvider = mspImgBufProvidersMgr->getDisplayPvdr();
pImgReq->mUsage = NSIoPipe::EPortCapbility_Disp;
break;
}
......
}
......
if(bufProvider->dequeProvider(node))
{
node.setCookieDE((*iterMapPort).bufType);
mvBufQueNode[bufQueIdx].push_back(node);
isDequeProvider = MTRUE;
break;
}
......
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
第11行,这里获取到的就是DisplayClient的ImgBufQueue,它继承了IImgBufProvider类
第18行,获取ImgBufQueNode
bool
ImgBufQueue::
dequeProvider(ImgBufQueNode& rNode)
{
bool ret = false;
Mutex::Autolock _lock(mTodoImgBufQueMtx);
if ( ! mTodoImgBufQue.empty() )
{
ret = true;
rNode = *mTodoImgBufQue.begin();
mTodoImgBufQue.erase(mTodoImgBufQue.begin());
}
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
第13行,可以看到deque最后是从mTodoImgBufQue里面取出buffer
4.3 pass2CbFunc函数分析
之前提到过IHalPostProcPipe处理完之后会回调pass2CbFunc函数。
MVOID
Pass2NodeImpl::
pass2CbFunc(QParams& rParams)
{
Pass2NodeImpl* pPass2NodeImpl = (Pass2NodeImpl*)(rParams.mpCookie)
pPass2NodeImpl->handleP2Done(rParams)
}
MBOOL
Pass2NodeImpl::
handleP2Done(QParams& rParams)
{
......
if( !mpIspSyncCtrlHw->unlockHw(IspSyncControlHw::HW_PASS2) )
{
MY_LOGE("isp sync unlock pass2 failed");
goto lbExit;
}
for( iterIn = rParams.mvIn.begin() ; iterIn != rParams.mvIn.end() ; iterIn++ )
{
MUINT32 nodeDataType = mapToNodeDataType( iterIn->mPortID );
handleReturnBuffer( nodeDataType, (MUINTPTR)iterIn->mBuffer, 0 );
}
vpDstBufAddr.clear();
for( iterOut = rParams.mvOut.begin() ; iterOut != rParams.mvOut.end() ; iterOut++ )
{
MBOOL bFind = MFALSE;
......
if(!bFind)
{
MUINT32 nodeDataType = mapToNodeDataType( iterOut->mPortID );
handlePostBuffer( nodeDataType, (MUINTPTR)iterOut->mBuffer, 0 );
vpDstBufAddr.push_back(iterOut->mBuffer);
}
}
return ret;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
第13-17行,之前Pass1Node调用handlePostBuffer把buffer传到Pass2Node,而现在调用handleReturnBuffer则会把buffer返回给Pass1Node,由Pass1Node的onReturnBuffer函数接收处理
第29行,再次调用handlePostBuffer函数,这里由于没有连接其它的CamNode,所以会回调Pass2Node的onReturnBuffer函数
Pass1Node的onReturnBuffer函数就是把处理完的buffer放回ring buffer里面,这里不再分析,来看看Pass2Node的onReturnBuffer函数
MBOOL
Pass2NodeImpl::
onReturnBuffer(MUINT32 const data, MUINTPTR const buf, MUINT32 const ext)
{
ICamBufHandler* pBufHdl = getBufferHandler(data);
......
MBOOL ret = pBufHdl->enqueBuffer(data, (IImageBuffer*)buf);
......
return MTRUE;
}
MBOOL
DefaultBufHandlerImpl::
enqueBuffer(MUINT32 const data, IImageBuffer const * pImageBuffer)
{
......
switch(keepImgBufQueNode.getCookieDE())
{
case eBuf_Disp:
{
bufProvider = mspImgBufProvidersMgr->getDisplayPvdr();
break;
}
......
}
......
bufProvider->enqueProvider(keepImgBufQueNode);
......
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
bool
ImgBufQueue::
enqueProvider(ImgBufQueNode const& rNode)
{
......
Mutex::Autolock _lock(mDoneImgBufQueMtx);
mDoneImgBufQue.push_back(rNode);
mDoneImgBufQueCond.broadcast();
return true;
}
第8行,流程上和之前的deque差不多,可以看到enque最终将buffer放到mDoneImgBufQue里面
第9行,准备好之后发送广播通知DisplayClient
5. 总结
DisplayClient准备好buffer放到mTodoImgBufQue里面。
Pass1Node从底层deque一帧数据,然后将数据post给DefaultCtrlNode,DefaultCtrlNode又将数据post给Pass2Node。
Pass2Node保存好buffer之后会触发threadLoopUpdate,threadLoopUpdate通过DefaultBufHandler从mTodoImgBufQue取出buffer,再将buffer交给IHalPostProcPipe处理,当IHalPostProcPipe处理完之后会回调Pass2CbFunc函数,Pass2CbFunc通过DefaultBufHandler把buffer放回mDoneImgBufQue里面。
最后DisplayClient不断从mDoneImgBufQue里面取出已经处理好的buffer送到Surface里面