Android Camera HAL3中拍照Capture模式下多模块间的交互与帧Result与帧数据回调_第1页
Android Camera HAL3中拍照Capture模式下多模块间的交互与帧Result与帧数据回调_第2页
Android Camera HAL3中拍照Capture模式下多模块间的交互与帧Result与帧数据回调_第3页
Android Camera HAL3中拍照Capture模式下多模块间的交互与帧Result与帧数据回调_第4页
Android Camera HAL3中拍照Capture模式下多模块间的交互与帧Result与帧数据回调_第5页
已阅读5页,还剩25页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

AndroidCameraHAL3中拍照Capture模式下多模块间的交互与帧Result与帧数据回调本文均属自己阅读源码的点滴总结,转账请注明出处谢谢。欢迎和大家交流。qq:1037701636email:gzzaigcn2009@163.comSoftware:系统源码Android5.1前沿:之前的两篇博文算是比较详细的记录了整个Camera3HAL3架构下完全不同于HAL1的preview预览处理过程,包括主要涉及到的控制流和视频流等。比较详细的阐述了Camera2Client下streamProcessor、CallbackProcessor、CaptureSequencer等模块在Camera3架构下的功能。分析得出每个模块下均会在Camera3Device下以一个Stream的形式存在,而每个stream又是由多个buffer来构成主体的。与HAL3进行数据的交互时,以Request和result来作为数据传输的载体。在这些基础上本文将描述具体拍照Capture模式下的数据流和控制流,主要会涉及到jpegprocessor、CaptureSequencer这几个模块的工作原理。鉴于Capture模式下的数据流更复杂,在这里重点会分析数据流result回传时,每个模块的响应以及处理过程,填补前一博文的空白。HAL3中Camera2Client下的takepicture的入口函数作为标准的capturepicture功能的入口,主要完成了以下两件事情:updateProcessorStream(mJpegProcessor,l.mParameters);mCaptureSequencer->startCapture(msgType)对于JpegProcessor模块而言,他的stream流第一次是在preview阶段进行了create与初始化,这里之所以再次调用JpegProcessor::updateStream目的是参考原先JpegProcessorstream的width与height是否变化即是否照片要求的分辨率发生了变化,如果是的话就需要delete原先的stream,重新建立一个streamo在JpegProcessor中重点关注CpuConsumer与Surface的生产者与消费者处理模式,官方称之为CreateCPUbufferqueueendpoint。CaptureSequencer模块CaptureSequencer模块是takepicture下操作的重点,在Camera2Client中进行了创建,首先来看CaptureSequencer线程的threadLoop函数:[cpp]viewplaincopyboolCaptureSequencer::threadLoop(){2.sp<Camera2Client>client=mCmote();if(client==0)returnfalse;5.Capturestatecurrentstate;7・{Mutex::Autolockl(mStateMutex);currentstate=mCaptureState;}11.currentstate=(this->*kStateManagers[currentState])(client);13.Mutex::Autolockl(mStateMutex);if(currentState!=mCaptureState){if(mCaptureState!=IDLE){ATRACE_ASYNC_END(kStateNames[mCaptureState],mStateTransitionCount);TOC\o"1-5"\h\z}mCaptureState=currentState;//保留新的状态mStateTransitionCount++;if(mCaptureState!=IDLE){ATRACE_ASYNC_BEGIN(kStateNames[mCaptureState],mStateTransitionCount);}ALOGV("Camera%d:Newcapturestate%s”,client->getCameraId(),kStateNames[mCaptureState]);mStateChanged.signal();}28.if(mCaptureState==ERROR){ALOGE("Camera%d:Stoppingcapturesequencerduetoerror",client->getCameraId());returnfalse;}34.returntrue;}CaptureSequencer是一个以不同的state状态机来循环工作的模块,currentState=(this->*kStateManagers[currentState])(client)函数是执行对应状态机下的执行函数,其中的state值如下:[cpp]viewplaincopyconstCaptureSequencer::StateManager

CaptureSequencer::kStateManagers[CaptureSequencer::NUM_CAPTURE_STATES-1]={&CaptureSequencer::manageIdle,&CaptureSequencer::manageStart,&CaptureSequencer::manageZslStart,&CaptureSequencer::manageZslWaiting,&CaptureSequencer::manageZslReprocessing,&CaptureSequencer::manageStandardStart,&CaptureSequencer::manageStandardPrecaptureWait,&CaptureSequencer::manageStandardCapture,&CaptureSequencer::manageStandardCaptureWait,&CaptureSequencer::manageBurstCaptureStart,&CaptureSequencer::manageBurstCaptureWait,&CaptureSequencer::manageDone,};我们以一个standardcapture的操作模式,来分析一次完成的takepicture的过程。初始化的mCaptureState(IDLE),进入的函数入口为manageldle:[cpp]viewplaincopyCaptureSequencer::CaptureStateCaptureSequencer::manageIdle(sp<Camera2Client>&/*client*/){status_tres;Mutex::Autolockl(mInputMutex);while(ImStartCapture){res=mStartCaptureSignal.waitRelative(mInputMutex,kWaitDuration);if(res==TIMED_OUT)break;TOC\o"1-5"\h\z}if(mStartCapture){mStartCapture=false;mBusy=true;returnSTART;}returnIDLE;}函数主要在轮训mStartCapture的值,这个值是由CameraService端的拍照触发线程来启动的,代码如下:[cpp]viewplaincopystatus_tCaptureSequencer::startCapture(intmsgType){

ALOGV("%s”,__FUNCTION__);ATRACE_CALL()y一一Mutex::Autolockl(mInputMutex);if(mBusy){ALOGE("%s:Alreadybusycapturing!",__FUNCTION__);returnINVALID_OPERATION;}一if(!mStartCapture){mMsgType=msgType;mStartCapture=true;mStartCaptureSignal.signal();//启动CaptureSequencer}returnOK;}对比CaptureSequencerThreadloop线程中,在阻塞式的等待mStartCapture=true,并在修改完mStartCapture后向Threadloop发出signaloThreadloop线程被唤醒后,执行返回一个新的状态机mCaptureState=START:2.1START状态机主要调用了updateCaptureRequest(l.mParameters,client)函数:[cpp]viewplaincopy....5.ATRACE_CALL();status_tres;if(mCaptureRequest.entryCount()==0){res=client->getCameraDevice()->createDefaultRequest(CAMERA2_TEMPLATE_STILL_CAPTURE,&mCaptureRequest);if(res!=OK){ALOGE("%s:Camera%d:Unabletocreatedefaultstillimagerequest:""%s(%d)”,__FUNCTION__,client->getCameraId(),strerror(-res),res);returnres;}}

16.res=params,updateRequest(&mCaptureRequest);if(res!=OK){ALOGE("%s:Camera%d:Unabletoupdatecommonentriesofcapture""request:%s(%d)”,__FUNCTION__,client->getCameraId(),strerror(-res),res);returnres;}24.res=params.updateRequestJpeg(&mCaptureRequest);//更新JPEG需要的参数4.ALOGE("%s:Camera%d:UnabletoupdateJPEGentriesofcapture""request:%s(%d)”,__FUNCTION__,client->getCameraId(),strerror(-res),res);returnres;}returnOK;}该函数和preview模式下的updatePreviewRequest很类似,这里首先检查mCaptureRequest是否是一个空的CameraMetadata,如果为空则由createDefaultRequest来请求HAL3来创建一个Request,其中相应的类型为CAMERA2_TEMPLATE_STILL_CAPTURE。随后分别是使用当前模式下的配置参数来更新CameraMetadatamCaptureRequest中不同tag的参数值,便于传递给HAL3,这个过程是类似与以前Camera1中直接的setParamters操作string的过程。2.2STANDARD_START状态manageStandardCapture该状态是启动整个takepicture的重点所在:[cpp]viewplaincopyCaptureSequencer::CaptureStateCaptureSequencer::manageStandardCapture(sp<Camera2Client>&client){status_tres;ATRACE_CALL();SharedParameters::Lockl(client->getParameters());

Vector<int32_t>outputstreams;uint8_tcaptureIntent=static_cast<uint8_t>(ANDROID_CONtrol_capture_intent_still_capture);4.15.16.Setupoutputstreamsintherequest-preview-capture/jpeg-callback(ifpreviewcallbacksenabled)-recording(ifrecordingenabled)17.outputStreams.push(client->getCaptureStreamId());//captureStream18.if(l.mParameters.previewCallbackFlags&CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK){outputStreams.push(client->getCallbackStreamId());//capturecallback}23.24.HOT)25.if(l.mParameters.state==24.HOT)25.>getRecordingStreamId());captureintent=static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT);—}一——2>getRecordingStreamId());captureintent=static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT);—}一——28.resT_STREAMS,30.31.32.D,33.ID34.35.36.=mCaptureRequest.update(ANDROID_REQUEST_OUTPUif}if(res

res(res

resoutputStreams);==OK){=mCaptureRequest.update(ANDROID_REQUEST_I&mCaptureId,1);//当前request对应的==OK){=mCaptureRequest.update(ANDROID_CONTROL_CAPTURE_INTENT,37.&captureIntent,1);38.}39.if(res==OK){40.res=mCaptureRequest.sort();41.}42.43.if(res!=OK){44.ALOGE("%s:Camera%d:Unabletosetupstillcapturerequest:%s(%d)",45.__FUNCTION__,client->getCameraId(),strerror(-res),res);46.returnDONE;47.}48.49.//CreateacapturecopysinceCameraDeviceBase#capturetakesownership50.CameraMetadatacaptureCopy=mCaptureRequest;51.if(captureCopy.entryCount()==0){52.ALOGE("%s:Camera%d:UnabletocopycapturerequestforHALdevice",53.__FUNCTION__,client->getCameraId());54.returnDONE;55.}56.57./**58.*Clearthestreamingrequestforstill-capturepictures59.*(asopposedtoi.e.videosnapshots)60.*/61.if(l.mParameters.state==Parameters::STILL_CAPTURE){62.//APIdefinitionoftakePicture()-stoppreviewbeforetakingpic63.res=client->stopStream();64.if(res!=OK){65.ALOGE("%s:Camera%d:Unabletostoppreviewforstillcapture:"66."%s(%d)”,67.__FUNCTION__,client->getCameraId(),strerror(-res),res);68.returnDONE;69.}70.}71.//TODO:CaptureshouldbeatomicwithsetStreamingRequesthere

72.res=client->getCameraDevice()->capture(captureCopy);//启动camera3device的capture,提交capturerequest73.if(res!=OK){74.ALOGE("%s:Camera%d:Unabletosubmitstillimagecapturerequest:"75."%s(%d)",76.__FUNCTION__,client->getCameraId(),strerror(-res),res);77.returnDONE;78.}79.80.mTimeoutCount=kMaxTimeoutsForCaptureEnd;81.returnSTANDARD_CAPTURE_WAIT;82.}83.84.CaptureSequencer::CaptureStateCaptureSequencer::manageStandardCaptureWait(85.sp<Camera2Client>&client){86.status_tres;87.ATRACE_CALL();88.Mutex::Autolockl(mlnputMutex);89.90.//Waitfornewmetadataresult(mNewFrame)91.while(!mNewFrameReceived){92.res=mNewFrameSignal.waitRelative(mInputMutex,kWaitDuration);//waitnew一帧metadata93.if(res==TIMED_OUT){94.mTimeoutCount--;95.break;96.}97.}98.99.//Approximationoftheshutterbeingclosed100.//-TODO:usethehal3exposurecallbackinCamera3Deviceinstead101.if(mNewFrameReceived&&!mShutterNotified){102.SharedParameters::Lockl(client->getParameters());103./*warning:thisalsolocksaSharedCameraCallbacks*/104.shutterNotifyLocked(l.mParameters,client,mMsgType);

mShutterNotified=true;}107.//WaituntiljpegwascapturedbyJpegProcessorwhile(mNewFrameReceived&&ImNewCaptureReceived){res=mNewCaptureSignal.waitRelative(mInputMutex,kWaitDuration);//等待JPEG数据111.if(res==TIMED_OUT){112.mTimeoutCount--;113.break;114.}115.}116.if(mTimeoutCount<=0){117.ALOGW("Timedoutwaitingforcapturetocomplete");118.returnDONE;119.}120.if(mNewFrameReceived&&mNewCaptureReceived){//满足mNewFrameReceivedif(mNewFrameId!=mCaptureId){ALOGW("MismatchedcaptureframeIDs:Expected%d,got%d”,mCaptureId,mNewFrameId);}camera_metadata_entry_tentry;entry=mNewFrame.find(ANDROID_SENSOR_TIMESTAMP);一一if(entry.count==0){ALOGE("Notimestampfieldincaptureframe!");}elseif(entry.count==1){if(entry.data.i64[0]!=mCaptureTimestamp){ALOGW("Mismatchedcapturetimestamps:Metadataframe%"PRId64",""capturedbuffer%"PRId64,entry.data.i64[0],134.mCaptureTimestamp);135.136.137.}}else{ALOGE("Timestampmetadataismalformed!");138.}

client->removeFrameListener(mCaptureId,mCaptureld+1,this);140.mNewFrameReceived=false;mNewCaptureReceived=false;returnDONE;}returnSTANDARD_CAPTURE_WAIT;}--整个函数的处理可以分为以下几个小点:a:Vector<int32_t>outputstreams;outputStreams.push(client->getPreviewStreamId());//previewStreamoutputStreams.push(client->getCaptureStreamId());//capturejpegStreamoutputStreams.push(client->getCallbackStreamId());//capturecallback通过以上的操作,可以很清楚是看到,这里集合了takepicture所需要使用到的stream流,对应的模块分别是:streamProcessor、jpegProcessor、CallbackProcessor。这个过程和Preview模式下是类似的,收集当前Camera2Client下的所有stream,并以stream的ID号作为区别。b:将当前操作所有的stream信息全部加入到CameraMetadatamCaptureRequestres=mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,outputStreams);if(res==OK){res=mCaptureRequest.update(ANDROID_REQUEST_ID,&mCaptureId,1);//当前request对应的ID}ANDROID_REQUEST_ID这项值表明,当前只存在3种Request类型:[cpp]viewplaincopy预览RequestmPreviewRequest:mPreviewRequestId(Camera2Client::kPreviewRequestIdStart),拍照RequestmCaptureRequest:mCaptureId(Camera2Client::kCaptureRequestIdStart),录像RequestmRecordingRequest:mRecordingRequestId(Camera2Client::kRecordingRequestIdStart),对于STILL_CAPTURE类型的pictureclient->stopStream(),实现的本质是res=device->clearStreamingRequest(),mRequestThread->clearRepeatingRequests(lastFrameNumber);该函数是将之前Preview模式下的建立的captureRequest作delete处理,之前在预览模式下是将最终生产的capturelist加入到了一个mRepeatingRequests当中,这里通过clear使之为empty,即不会再发送Request和HAL3进行数据的交互。Camera3Devicecapture函数首先关注capture函数传入的参数为captureCopy,艮口CameraMetadatamCaptureRequest的一个copy值。[cpp]viewplaincopystatus_tCamera3Device::capture(CameraMetadata&request,int64_t*/*lastFrameNumber*/){一ATRACE_CALL();一List<constCameraMetadata〉requests;requests.push_back(request);//对于一个CameraMetadata转为listreturncaptureList(requests,/*lastFrameNumber*/NULL);7・}[cpp]viewplaincopystatus_tCamera3Device::captureList(constList<constCameraMetadata>&requests,int64_t*lastFrameNumberTOC\o"1-5"\h\z){一ATRACE_CALL();一returnsubmitRequestsHelper(requests,/*repeating*/false,lastFrameNumber);//非重复的,制定于拍照}capture函数由Camera3Device来响应处理,其传入的mCaptureRequest转变为一个list,再交由submitRequestsHelper来处理,对比之前Preview下的处理方式,其startstream入口为setStreamingRequest->setStreamingRequestList->submitRequestsHelper。这也表明了最终CameraMetadata类型的Request都是由submitRequestsHelper来完成的,所以convertMetadataListToRequestListLocked这个将CameraMetadata转换为List<sp<CaptureRequest>>RequestList的处理过程对两者来说都是一致的。但在后续处理时,对picture模式下的Request,其不再是repeating的处理,mRequestThread->queueRequestList():[cpp]viewplaincopystatus_tCamera3Device::RequestThread::queueRequestList(List<sp<CaptureRequest>>&requests,/*out*/int64_t*lastFrameNumber){Mutex::Autolockl(mRequestLock);for(List<sp<CaptureRequest>>::iteratorit=requests.begin();it!=requests.end();++it){mRequestQueue.push_back(*it);}一unpauseForNewRequests();11.returnOK;}这里直接是将CaptureRequest加入到RequestQueue这个队列之中,区别于Preview模式是将captureRequest加入到一个mRepeatingRequests,重复的将其中的captureRequest加入到0RequestQueue。最简单的理解是picture模式下是拍去几帧的数据流即可,Preview模式下是实时的获取帧,前者是几次onesnop,后者是连续continuous。到这里为止,可以说CaptureSequence已经完成了START状态机的处理。从START到STANDARD_CAPTURE_WAIT该状态下对应的状态机处理函数为manageStandardCaptureWait:[cpp]viewplaincopyCaptureSequencer::CaptureStateCaptureSequencer::manageStandardCaptureWait(sp<Camera2Client>&client){status_tres;ATRACE_CALL();Mutex::Autolockl(mInputMutex);6.//Waitfornewmetadataresult(mNewFrame)while(!mNewFrameReceived){res=mNewFrameSignal.waitRelative(mInputMutex,kWaitDuration);//waitnew一帧metadataif(res==TIMED_OUT){mTimeoutCount--;

break;TOC\o"1-5"\h\z}}15.//Approximationoftheshutterbeingclosed//-TODO:usethehal3exposurecallbackinCamera3Deviceinstead18.19.if(mNewFrameReceived&&ImShutterNotified){18.19.20.backs*//*warning:thisalsolocksaSharedCameraCallshutterNotifyLocked(l.mParameters,client,mMsgType);20.backs*/mShutterNotified=true;}24.//WaituntiljpegwascapturedbyJpegProcessorwhile(mNewFrameReceived&&ImNewCaptureReceived){res=mNewCaptureSignal.waitRelative(mInputMutex,kWaitDuration);//等待JPEG数据4.te");4.te");35.36.37.}if(mTimeoutCount<=0){ALOGW("TimedoutwaitingforcapturetocomplereturnDONE;}if(mNewFrameReceived&&mNewCaptureReceived){//满足mNewFrameReceivedif(mNewFrameld!=mCaptureld){ALOGW("MismatchedcaptureframeIDs:Expected%d,got%d”,mCaptureld,mNewFrameld);}camera_metadata_entry_tentry;entry匚mNewFrame.find(ANDROID_SENSOR_TIMESTAMP);一一if(entry.count==0){

ALOGE("Notimestampfieldincaptureframe!");}elseif(entry.count==1){if(entry.data.i64[0]!=mCaptureTimestamp){ALOGW("Mismatchedcapturetimestamps:Metadataframe%”PRId64",""capturedbuffer%"PRId64,entry.data.i64[0],mCaptureTimestamp);}}else{ALOGE("Timestampmetadataismalformed!");}client->removeFrameListener(mCaptureId,mCaptureld+1,this);57.mNewFrameReceived=false;mNewCaptureReceived=false;returnDONE;}returnSTANDARD_CAPTURE_WAIT;}一一具体分析该函数可以知道其处于两次wait休眠状态,主要响应两个条件等待信号mNewFrameSignal与mNewCaptureSignal,两者者的等待周期为100ms。只有当mNewFrameReceived&&mNewCaptureReceived同事满足条件时,才算是Capture到一帧picture。f.DoneStat状态这里先假设已经完成了wait这个状态,就会进入Done状态的执行函数manageDone(),最重要的部分如下:[cpp]viewplaincopyif(mCaptureBuffer!=0&&res==OK){ATRACE_ASYNC_END(Camera2Client::kTakepictureLabel,takePictureCounter);3.Camera2Client::SharedCameraCallbacks::Lockl(client->mSharedCameraCallbacks);ALOGv("%s:Sendingstillimagetoclient",__FUNCTION__);if(l.mRemoteCallback!=0){

l.mRemoteCallback->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,9.mCaptureBuffer,NULL);//回传压缩好的jpeg数据到上层3.14.}else{}mCaptureBuffer.clear();ALOGV("%s:Noclient!",__FUNCTION__);他将采集到的一帧jpeg压缩格式的图像,回传到APP层,便于后期写入到文件等。在以往CameraHAL1.0中这部分的数据回传玩玩都是由HAL层来完成的,这也给编码带来复杂度以及效率低下等问题。Google在Camera3.0中很好的封装了dataCallback2.13.14.}mCaptureBuffer.clear();其中mCaptureBuffer是回传回来的真实的jpeg格式的图像数据,其本质是从stream中提取的一个buffer然后被copy到一个heap中,等待APPCallback完成后,就会释放。完成了Done状态后,CaptureSequence又会再次进入到IDLE模式,等待下一次的takepicture的处理。3picture模式下Camera3Device处理Request与result对于picture模式下的Request处理,可以参考Preview模式下的RequestThread::threadLoop下的处理过程。这里主要分析result的响应过程:在前面已经提到CaptureSequence需要wait两个signal,一般都是有其他模块来触发回调这个signal,我们先来定位这两个signal发出的位置:[cpp]viewplaincopyvoidCaptureSequencer::onResultAvailable(constCaptureResult&result){ATRACE_CALL();ALOGV("%s:Newresultavailable.",__FUNCTION__);Mutex::Autolockl(mInputMutex);mNewFrameId=result.mResultExtras.requestId;//返回帧所属的requestidmNewFrame=result.mMetadata;if(!mNewFrameReceived){mNewFrameReceived=true;mNewFrameSignal.signal();//buffer相应的result信息,由FrameProcessor模块来触发listener}}12.voidCaptureSequencer::onCaptureAvailable(nsecs_ttimestamp,sp<MemoryBase>captureBuffer){ATRACE_CALL();ALOGV("%s”,__FUNCTION__);Mutex::Autolockl(mInputMutex);mCaptureTimestamp=timestamp;mCaptureBuffer=captureBuffer;if(ImNewCaptureReceived){mNewCaptureReceived=true;mNewCaptureSignal.signal();//真实的一帧jpeg图像}}那么这两个on回调函数是怎么触发的呢?下面来作具体的分析:3.1.明确picture模式下,一次处理需要的stream数目需要明确的是一次takepicture需要的stream分别有JpegProcessor、CallbackProcessor、StreamingProcessor三种,第一个主要接收的是jpeg格式的帧图像,第二个主要接收的是一帧的preview模式下回调到APP的视频帧,而最后一个是直接获取一帧视频图像后直接进行显示用的视频帧。3.2.帧数据回调响应的由来processCaptureResult函数:无论是哪一个模块,数据回调响应最初的入口是HAL3的process_capture_result函数即processCaptureResult。函数,该函数的处理之所以复杂是因为HAL3.0中允许一次result回来的数据可以是不完整的,其中以3A相关的cameraMetadata的数据为主,这里需要说明每一帧的result回来时camera3_capture_result都是含有一个camera_metadata_t的,包含着一帧图像的各种信息tag字段,其中以3A信息为主。在processCaptureResult函数中由三个核心函数:processPartial3AResult():处理回传回来的部分cameraMetadataresult数据;returnOutputBuffers():返回这次result中各个stream对应的buffer数据;sendCaptureResult():处理的是一次完整的cameraMetadataresult数据;3.3.FrameProcessor模块的帧Result响应,以3A回调处理为主processPartial3AResult()函数与sendCaptureResult()函数都是将3A的result结果发送给FrameProcessor去作处理的,因为无论是Request还是result都是必然带有一个类似stream的cameraMetadata的,所以在这个模块有别于其他模块,故不需要单独的stream流来交互数据的。[cpp]viewplaincopy

if(isPartialResult){//Fireoffa3A-onlyresultifpossibleif(!request.partialResult.haveSent3A){//返回的只是3A的数据request.partialResult.haveSent3A=processPartial3AResult(frameNumber,request.partialResult.collectedResult,request.resultExtras);//frame含有3A则notify处理}9・}processPartial3AResult是将当前帧收集到的partialResult进行处理,需要明确的是partialResult是指定帧framenum下返回的result最新组成的result:其内部需要确保目前收集到的result需要至少含有如下的tag的值,才算一次3A数据可True:[cpp]viewplaincopygotAllStates&=get3AResult(partial,ANDROID_CONTROL_AF_MODE,&afMode,frameNumber);3.gotAllStates&=get3AResult(partial,ANDROID_CONTROL_AWB_MODE,一一—&awbMode,frameNumber);6.gotAllStates&=get3AResult(partial,ANDROID_CONTROL_AE_STATE,一一一&aeState,frameNumber);9.gotAllStates&=get3AResult(partial,ANDROID_CONTROL_AF_STATE,&afState,frameNumber);12.gotAllStates&=get3AResult(partial,ANDROID_CONTROL_AWB_STATE,&awbState,frameNumber);<spanstyle="font-family:Arial;">if(!gotAllStates)returnfalse;</span>

只有这样才满足构建一个CaptureResultminResult的要求,上述过程表明对已有的Result需要AE、AF、AWB同时OK时才会构建一个CaptureResult。接着对比着来看sendCaptureResult:[cpp]viewplaincopyvoidCamera3Device::sendCaptureResult(CameraMetadata&pendingMetadata,CaptureResultExtras&resultExtras,CameraMetadata&collectedPartialResult,uint32_tframeNumber){if(pendingMetadata.isEmpty())return;7.Mutex::Autolockl(mOutputLock);9.//TODO:needtotrackerrorsfortighterboundsonexpectedframenumberif(frameNumber<mNextResultFrameNumber){SET_ERR("Out-of-ordercaptureresultmetadatasubmitted!""(gotframenumber%d,expecting%d)”,frameNumber,mNextResultFrameNumber);return;}mNextResultFrameNumber=frameNumber+1;//下一帧18.CaptureResultcaptureResult;captureResult.mResultExtras=resultExtras;captureResult.mMetadata=pendingMetadata;22.if(captureResult.mMetadata.update(ANDROID_REQUEST_FRAME_COUNT,(int32_t*)&frameNumber,1)!=OK){SET_ERR("Failedtosetframe#inmetadata(%d)9.(%d)",8.29.(%d)",30.31.}else{ALOGVV("%s:Camera%d:Setframe#inmetadata__FUNCTION__,mId,frameNumber);

32.33.//Appendanypreviouspartialstoformacompleteresult34.if(mUsePartialResult&&!collectedPartialResult.isEmpty()){35.captureResult.mMetadata.append(collectedPartiaIResult);//36.}37.38.captureResult.mMetadata.sort();39.40.//Checkthatthere'satimestampintheresultmetadata41.camera_metadata_entryentry=42.captureResult.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);43.if(entry.count==0){44.SET_ERR("NotimestampprovidedbyHALforframe%d!",45.frameNumber);46.return;47.}48.49.//Validresult,insertintoqueue50.List<CaptureResult>::iteratorqueuedResult=51.mResultQueue.insert(mResultQueue.end(),CaptureResult(captureResult));52.ALOGVV("%s:resultrequestId=%"PRId32",frameNumber=%"PRId6453.",burstId=%"PRId32,__FUNCTION__,54.queuedResult->mResultExtras.requestId,55.queuedResult->mResultExtras.frameNumber,56.queuedResult->mResultExtras.burstId);57.58.mResultSignal.signal();//发送signal59.}该函数的主要工作是创建一个CaptureResult,可以看到对于之前帧回传回来的部分result,需要在这里进行组合成一帧完整的result。collectedPartialResult指的是当一次Request下发时,回传的result可能是分几次返回的,比如第一次的result只含有部分的信息,在第二次返回如果result已经被标记为完全上传回到Threadloop中,那么这里就需要对前几次的result进行组合,而前几次的result都是保存在当前帧的Request的,整个Request以唯一的一个framenumber作为索引,确保返回的result组合后是对应的同一个Requesto个人理解这个partialResult的处理机制是每次返回的Result并不一定包含了当前frameNumber帧号所需要的tag信息,而且这个每次回传的mNumPartialResults值是由HAL3.0层来决定的。在每次一的Result中,会收集其中isPartialResult=(result->partial_result<mNumPartialResults)决定了当前的Result是否还是一个处于partialResult的模式,是的话每次都进行collectResult,此外对于此模式下会收集3A的tag信息,调用processPartial3AResult来处理3A的值,而这个过程也是单列的处理。而一旦当前的Result返回处于非partial模式时,直接提取之前collect的Result并和当前的Result共同组成一个新的CaptureResult。生成的CaptureResult会加入到mResultQueue队列。至此分析完了HAL3返回的CaptrueResult的处理过程,最终mResultSignal.signal()唤醒相应的等待线程,而这个过程就是由FrameProcessor模块来响应的。FrameProcessorBase是-一个FrameProcessor的基类,会启动一个Threadloop:[cpp]viewplaincopyboolFrameProcessorBase::threadLoop(){status_tres;TOC\o"1-5"\h\z一sp<CameraDeviceBase>device;5・{device=mDmote();if(device==0)returnfalse;}9.res=device->waitForNextFrame(kWaitDuration);if(res==OK){processNewFrames(device);//3A相关的处理等待}elseif(res!=TIMED_OUt){ALOGE("FrameProcessorBase:Errorwaitingfornew""frames:%s(%d)",strerror(-res),res);}17.returntrue;}调用camera3device的waitForNextFrame,等待周期为10ms.[cpp]viewplaincopy

status_tCamera3Device::waitForNextFrame(nsecs_ttimeout){status_tres;Mutex::Autolockl(mOutputLock);4.while(mResultQueue.empty()){//captureresult结果非空则继续执行res=mResultSignal.waitRelative(mOutputLock,timeout);if(res==TIMED_OUT){returnres;}elseif(res!=OK){ALOGW("%s:Camera%d:Noframein%”PRId64-ns:%s(%d)",__FUNCTION__,mid,timeout,strerror(-res),res);returnres;TOC\o"1-5"\h\z}}returnOK;}在这里一是看到了mResultQueue,二是看到了mResultSignal。对应于Camera3Device::sendCaptureResult()中的mOutputLock以及signal。线程被唤醒后调用processNewFrames来处理当前帧[cpp]viewplaincopyvoidFrameProcessorBase::processNewFrames(constsp<CameraDeviceBase>&device){status_tres;ATRACE_CALL();CaptureResultresult;5.ALOGV("%s:Camera%d:Processnewframes",__FUNCTION__,device->getid());7.while((res=device->getNextResult(&result))==OK){9.//TODO:insteadofgettingframenumberfrommetadata,weshouldread//thisfromresult.mResultExtraswhenCameraDeviceBaseinterfaceisfixed.

12.camera_metadata_entry_tentry;13.14.entry=result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT);15.一if(entry.count==0){16.ALOGE("%s:Camera%d:Errorreadingframenumber",17.__FUNCTION__,device->getId());18.break;19.}20.ATRACE_INT("cam2_frame”,entry.data.i32[0]);21.22.if(!processSingleFrame(result,device)){〃单独处理一帧23.break;24.}25.26.if(!result.mMetadata.isEmpty()){27.Mutex::Autolockal(mLastFrameMutex);28.mLastFrame.acquire(result.mMetadata);29.}30.}31.if(res!=NOT_ENOUGH_DATA){32.ALOGE("%s:Camera%d:Errorgettingnextframe:%s(%d)”,33.__FUNCTION__,device->getId(),strerror(-res),res);34.return;35.}36.37.return;38.}device->getNextResult(&result)是从mResultQueue提取一个可用的CaptureResult,提取完成后作erase的处理。再检验这个Result是否属于一个固定的framenum,然后由processSingleFrame来完成一件事:[cpp]viewplaincopyboolFrameProcessor::processSingleFrame(CaptureResult&frame,constsp<CameraDeviceBase>&device)(//处理帧3.4.

sp<Camera2Client>client=mCmote();if(!client.get()){returnfalse;}9.10.boolisPartialResult=false;if(mUsePartialResult){if(client->getCameraDeviceVersion()>=CAMERA_DEVICE_API_VERSION_3_2){-""""isPartialResult=frame.mResultExtras.partialResultCount<mNumPartialResults;}else{camera_metadata_entry_tentry;entry=frame.mMetadata.find(ANDROID_QUIRKTOC\o"1-5"\h\zS_PARTIAL_RESULT);一if(entry.count>0&&entry.data.u8[0]==ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL){一isPartialResult=true;}}}24.25.if(!isPartialResult&&processFaceDetect(frame.mMetadata,client)!=OK){returnfalse;}29.30.if(mSynthesize3ANotify){process3aState(frame,client);}34.35.returnFrameProcessorBase::processSingleFrame(frame,device);}[cpp]viewplaincopyboolFrameProcessorBase::processSingleFrame(CaptureResult&result,constsp<CameraDeviceBase>&device){ALOGV("%s:Camera%d:Processsingleframe(isempty?%d)",__FUNCTION__,device->getId(),result.mMetadata.isEmpty());returnprocessListeners(result,device)==OK;//处理所有的listener}[cpp]viewplaincopystatus_tFrameProcessorBase::processListeners(constCaptureResult&result,constsp<CameraDeviceBase>&device){ATRACE_CALL();一camera_metadata_ro_entry_tentry;6.//Checkifthisresultispartial.boolisPartialResult=false;if(device->getDeviceVersion()>=CAMERA_DEVICE_API_VERSION_3_2){isPartialResult=result.mResultExtras.partialResultCount<mNumPartialResults;}else{entry=result.mMetadata.find(ANDROID_QUIRKS_PARTIAL_RESULT);一一if(entry.count!=0&&entry.data.u8[0]==ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL){一—ALOGV("%s:Camera%d:Thisisapartialresult",__FUNCTION__,device->getId());isPartialResult=true;}}20.//TODO:insteadofgettingrequestIDfromCameraMetadata,weshouldgetit//fromCaptureResultExtras.ThiswillrequirechangingCamera2Device.//CurrentlyCamera2DeviceusesMetadataQueuetostoreresults,whichdoesnot

7.entry=result.mMetadata.find(ANDROID_REQUEST_ID);if(entry.count==0){ALOGE("%s:Camera%d:Errorreadingframeid”,__FUNCTION__,device->getId());6.List<RangeListener>::iteratoritem=mRangeListeners.begin();//Don'tdeliverpartialresultstolistenersthatdon'twantthemwhile(item!=mRangeListeners.end()){>minId&&requestId<40.>sendPartials)){4>minId&&requestId<40.>sendPartials)){41.>mote();42.43.(!isPartialResult||item-sp<FilteredListener>listener=item-if(listener==0){;0.51.52.item=mRangeListeners.erase(item)continue;;0.51.52.ALOGV("%s:Camera%d:Got%zurangelistenersoutof%zu”,__FUNCTION__,device->getId(),listeners.size(),mRangeListeners.size());54.List<sp<FilteredListener>>::iteratoritem=listeners.begin();for(;item!=listeners.end();item++){(*item)->onResultAvailable(result);//所有注册的listener,告知有result返回}returnOK;}这里简单的理解是在获取一个正常的CaptureResult时,就需要将这个Result分发给哪些感兴趣的模块,而这个过程由一个FilteredListener来完成:其他模块如果想要listenFrameProcessor模块,可以调用registerListener来注册,保存在mRangeListeners之中,具体的接口如下:[cpp]viewplaincopystatus_tCamera2Client::registerFrameListener(int32_tminId,int32_tmaxId,wp<camera2::FrameProcessor::FilteredListener>listener,boolsendPartials){returnmFrameProcessor->registerListener(minId,maxId,listener,sendPartials);}在这个对完整的Resul

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论