HAL3.0 Frameworks层总体框架
v3将更多的工作集中在了Framework去完成,将更多的控制权掌握在自己的手里,从而与HAL的交互的数据信息更少,也进一步减轻了一些在旧版本中HAL层所需要做的事情,也更加模块化。
下面以initialize为起点进行分析:
Camera2Client后会进行initialize操作,完成各个处理模块的创建:
代码目录:frameworks/av/services/camera/libcameraservice/api1/Camera2Client.cpp
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 |
status_t Camera2Client::initialize(CameraModule *module) { ……… mStreamingProcessor = new StreamingProcessor(this);//preview和recorder threadName = String8::format(C2-%d-StreamProc, mCameraId); mStreamingProcessor->run(threadName.string());//预览与录像 mFrameProcessor = new FrameProcessor(mDevice, this);// 3A threadName = String8::format(C2-%d-FrameProc, mCameraId); mFrameProcessor->run(threadName.string()); //3A mCaptureSequencer = new CaptureSequencer(this); threadName = String8::format(C2-%d-CaptureSeq, mCameraId); mCaptureSequencer->run(threadName.string());//录像,拍照 mJpegProcessor = new JpegProcessor(this, mCaptureSequencer); threadName = String8::format(C2-%d-JpegProc, mCameraId); mJpegProcessor->run(threadName.string()); ……… mCallbackProcessor = new CallbackProcessor(this);//回调处理 threadName = String8::format(C2-%d-CallbkProc, mCameraId); mCallbackProcessor->run(threadName.string()); ……… } |
依次分别创建了:
1、StreamingProcessor并启动一个它所属的thread,该模块主要负责处理previews与record两种视频流的处理,用于从hal层获取原始的视频数据
2、FrameProcessor并启动一个thread,该模块专门用于处理回调回来的每一帧的3A等信息,即每一帧视频除去原始视频数据外,还应该有其他附加的数据信息,如3A值。
3、CaptureSequencer并启动一个thread,该模块需要和其他模块配合使用,主要用于向APP层告知capture到的picture。
4、JpegProcessor并启动一个thread,该模块和streamprocessor类似,他启动一个拍照流,一般用于从HAL层获取jpeg编码后的图像照片数据。
5、另外ZslProcessor模块称之为0秒快拍,其本质是直接从原始的Preview流中获取预存着的最近的几帧,直接编码后返回给APP,而不 需要再经过take picture去请求获取jpeg数据。0秒快拍技术得意于当下处理器CSI2 MIPI性能的提升以及Sensor支持全像素高帧率的实时输出。一般手机拍照在按下快门后都会有一定的延时,是因为需要切换底层Camera以及ISP 等的工作模式,并重新设置参数以及重新对焦等等,都需要花一定时间后才抓取一帧用于编码为jpeg图像。
以上5个模块整合在一起基本上实现了Camera应用开发所需的基本业务功能。
2.3.2 Preview模式下的控制流
代码目录,直接以Camera2Client::startPreview()作为入口来分析整个Framework层中Preview相关的数据流:
1、调用Camera2Client::startPreview函数
代码目录-1:frameworks/av/services/camera/libcameraservice/api1/Camera2Client.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
status_t Camera2Client::startPreview() { ATRACE_CALL(); ALOGV(%s: E, __FUNCTION__); Mutex::Autolock icl(mBinderSerializationLock); status_t res; if ( (res = checkPid(__FUNCTION__) ) != OK) return res; SharedParameters::Lock l(mParameters); return startPreviewL(l.mParameters, false); } |
startPreview通过startPreviewL提取参数后真正的开始执行Preview相关的控制流。该函数看上去内容虽然较多,但基本采用了同一种处理方式:
- 2、 调用Camera2Client::startPreviewL函数
代码目录-1:frameworks/av/services/camera/libcameraservice/api1/Camera2Client.cpp
后面会详细介绍2.1-2.6粗体标注部分;
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 |
status_t Camera2Client::startPreviewL(Parameters ¶ms, bool restart){ ...... //获取上一层Preview stream id int lastPreviewStreamId = mStreamingProcessor->getPreviewStreamId(); //2.1创建camera3device stream, Camera3OutputStream res = mStreamingProcessor->updatePreviewStream(params); ..... int lastJpegStreamId = mJpegProcessor->getStreamId(); //2.2预览启动时就建立一个jpeg的outstream res = updateProcessorStream(mJpegProcessor, params); ..... //2.3回调处理建立一个Camera3outputstream res = mCallbackProcessor->updateStream(params); ……… //2.4 outputStreams.push(getCallbackStreamId()); ...... outputStreams.push(getPreviewStreamId());//预览stream ...... if (!params.recordingHint) { if (!restart) { //2.5 request处理,更新了mPreviewrequest res = mStreamingProcessor->updatePreviewRequest(params); ...... } //2.6 res = mStreamingProcessor->startStream(StreamingProcessor::PREVIEW, outputStreams);//启动stream,传入outputStreams即stream 的id } ...... } |
2.1、调用mStreamingProcessor->updatePreviewStream函数
代码目录-2:
frameworks/av/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
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 |
status_t StreamingProcessor::updatePreviewStream (const Parameters ¶ms) { ...... sp device = mDevice.promote();//Camera3Device ...... if (mPreviewStreamId != NO_STREAM) { // Check if stream parameters have to change uint32_t currentWidth, currentHeight; res = device->getStreamInfo(mPreviewStreamId, &tWidth, &tHeight, 0); ...... if (currentWidth != (uint32_t)params.previewWidth || currentHeight != (uint32_t)params.previewHeight) { ...... res = device->waitUntilDrained(); ...... res = device->deleteStream(mPreviewStreamId); ...... mPreviewStreamId = NO_STREAM; } } if (mPreviewStreamId == NO_STREAM) {//首次create stream //创建一个Camera3OutputStream res = device->createStream(mPreviewWindow, params.previewWidth, params.previewHeight, CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, &mPreviewStreamId); ...... } } res = device->setStreamTransform(mPreviewStreamId, params.previewTransform); ...... } |
该函数首先是查看当前StreamingProcessor模块下是否存在Stream,没有的话,则交由Camera3Device创建一个 stream。显然,一个StreamingProcessor只能拥有一个PreviewStream,而一个Camera3Device显然控制着所 有的Stream。
注意:在Camera2Client中,5大模块的数据交互均以stream作为基础。
下面我们来重点关注Camera3Device的接口createStream,他是5个模块创建stream的基础:
代码目录-3:
frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
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 |
status_t Camera3Device::createStream(sp consumer, uint32_t width, uint32_t height, int format, int *id) { ...... assert(mStatus != STATUS_ACTIVE); sp newStream; if (format == HAL_PIXEL_FORMAT_BLOB) {//图片 ssize_t jpegBufferSize = getJpegBufferSize(width, height); ...... newStream = new Camera3OutputStream(mNextStreamId, consumer, width, height, jpegBufferSize, format);//jpeg 缓存的大小 } else { newStream = new Camera3OutputStream(mNextStreamId, consumer, width, height, format);//Camera3OutputStream } newStream->setStatusTracker(mStatusTracker); //一个streamid与Camera3OutputStream绑定 res = mOutputStreams.add(mNextStreamId, newStream); ...... *id = mNextStreamId++;//至少一个previewstream 一般还有CallbackStream mNeedConfig = true; // Continue captures if active at start if (wasActive) { ALOGV(%s: Restarting activity to reconfigure streams, __FUNCTION__); res = configureStreamsLocked(); ...... internalResumeLocked(); } ALOGV(Camera %d: Created new stream, mId); return OK; } |
该函数重点是关注一个new Camera3OutputStream,在Camera3Device主要存在Camera3OutputStream和Camera3InputStream,两种stream,前者主要作为HAL的输出,是请求HAL填充数据的OutPutStream,后者是由Framework将Stream进行填充。无论是Preview、record还是capture均是从HAL层获取数据,故都会以OutPutStream的形式存在,是我们关注的重点,后面在描述Preview的数据流时还会进一步的阐述。
每当创建一个OutPutStream后,相关的stream信息被push维护在一个mOutputStreams的KeyedVector表中,分别是该stream在Camera3Device中创建时的ID以及Camera3OutputStream的sp值。同时对mNextStreamId记录下一个Stream的ID号。
上述过程完成StreamingProcessor模块中一个PreviewStream的创建,其中Camera3OutputStream创建时的ID值被返回记录作为mPreviewStreamId的值,此外每个Stream都会有一个对应的ANativeWindow,这里称之为Consumer。
2.2、调用updateProcessorStream(mJpegProcessor, params)函数
代码目录-2:
frameworks/av/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
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 |
status_t Camera2Client::updateProcessorStream(sp processor, camera2::Parameters params) { // No default template arguments until C++11, so we need this overload return updateProcessorStream( processor, params); } template status_t Camera2Client::updateProcessorStream(sp processor, Parameters params) { status_t res; // Get raw pointer since sp doesn't have operator->* ProcessorT *processorPtr = processor.get(); res = (processorPtr->*updateStreamF)(params); ....... } |
该模板函数处理过程最终通过非显示实例到显示实例调用JpegProcessor::updateStream,该函数处理的逻辑基本和Callback 模块处理一致,创建的一个OutPutStream和CaptureWindow相互绑定,同时Stream的ID保存在 mCaptureStreamId中。
此外需要说明一点:
在preview模式下,就去创建一个jpeg处理的stream,目的在于启动takepicture时,可以更快的进行capture操作,是通过牺牲内存空间来提升效率。
2.3、调用mCallbackProcessor->updateStream函数
代码目录-2:
frameworks/av/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
对比StreamingProcessor模块创建previewstream的过程,很容易定位到Callback模块是需要建立一个 callback流,同样需要创建一个Camera3OutputStream来接收HAL返回的每一帧帧数据,是否需要callback可以通过 callbackenable来控制。一般但预览阶段可能不需要回调每一帧的数据到APP,但涉及到相应的其他业务如视频处理时,就需要进行 callback的enable。
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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
status_t CallbackProcessor::updateStream(const Parameters ¶ms) { ……… sp device = mDevice.promote(); ……… // If possible, use the flexible YUV format int32_t callbackFormat = params.previewFormat; if (mCallbackToApp) { // TODO: etalvala: This should use the flexible YUV format as well, but // need to reconcile HAL2/HAL3 requirements. callbackFormat = HAL_PIXEL_FORMAT_YV12; } else if(params.fastInfo.useFlexibleYuv && (params.previewFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP || params.previewFormat == HAL_PIXEL_FORMAT_YV12) ) { callbackFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; } if (!mCallbackToApp && mCallbackConsumer == 0) { // Create CPU buffer queue endpoint, since app hasn't given us one // Make it async to avoid disconnect deadlocks spproducer; spconsumer; //BufferQueueProducer与BufferQueueConsumer BufferQueue::createBufferQueue(&producer, &consumer); mCallbackConsumer = new CpuConsumer(consumer, kCallbackHeapCount); //当前CallbackProcessor继承于CpuConsumer::FrameAvailableListener mCallbackConsumer->setFrameAvailableListener(this); mCallbackConsumer->setName(String8(Camera2Client::CallbackConsumer)); //用于queue操作,这里直接进行本地的buffer操作 mCallbackWindow = new Surface(producer); } if (mCallbackStreamId != NO_STREAM) { // Check if stream parameters have to change uint32_t currentWidth, currentHeight, currentFormat; res = device->getStreamInfo(mCallbackStreamId, &tWidth, &tHeight, &tFormat); ……… } if (mCallbackStreamId == NO_STREAM) { ALOGV(Creating callback stream: %d x %d, format 0x%x, API format 0x%x, params.previewWidth, params.previewHeight, callbackFormat, params.previewFormat); res = device->createStream(mCallbackWindow, params.previewWidth, params.previewHeight, callbackFormat, &mCallbackStreamId);//Creating callback stream ……… } return OK; } |
2.4、整合startPreviewL中所有的stream 到Vector outputStreams
outputStreams.push(getPreviewStreamId());//预览stream
outputStreams.push(getCallbackStreamId())//Callback stream
目前一次Preview构建的stream数目至少为两个。
2.5、调用mStreamingProcessor->updatePreviewRequest函数
代码目录-2:
frameworks/av/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
在创建好多路stream后,由StreamingProcessor模块来将所有的stream信息交由Camera3Device去打包成Request请求。
注意:
Camera HAL2/3的特点是:将所有stream的请求都转化为几个典型的Request请求,而这些Request需要由HAL去解析,进而处理所需的业务,这也是Camera3数据处理复杂化的原因所在。
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 |
status_t StreamingProcessor::updatePreviewRequest(const Parameters ¶ms) { ……… if (mPreviewRequest.entryCount() == 0) { sp client = mClient.promote(); if (client == 0) { ALOGE(%s: Camera %d: Client does not exist, __FUNCTION__, mId); return INVALID_OPERATION; } // Use CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG for ZSL streaming case. if (client->getCameraDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_0) { if (params.zslMode && !params.recordingHint) { res = device->createDefaultRequest(CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG, &mPreviewRequest); } else { res = device->createDefaultRequest(CAMERA3_TEMPLATE_PREVIEW, &mPreviewRequest); } } else { //创建一个Preview相关的request,由底层的hal来完成default创建 res = device->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW, &mPreviewRequest); ……… } //根据参数来更新CameraMetadata request,用于app设置参数,如antibanding设置 res = params.updateRequest(&mPreviewRequest); ……… res = mPreviewRequest.update(ANDROID_REQUEST_ID, &mPreviewRequestId, 1);//mPreviewRequest的ANDROID_REQUEST_ID ……… } |
a mPreviewRequest是一个CameraMetadata类型数据,用于封装当前previewRequest;
b 调用device->createDefaultRequest(CAMERA3_TEMPLATE_PREVIEW, &mPreviewRequest)函数
代码目录-3:
frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
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 |
status_t Camera3Device::createDefaultRequest(int templateId, CameraMetadata *request) { ……… const camera_metadata_t *rawRequest; ATRACE_BEGIN(camera3->construct_default_request_settings); rawRequest = mHal3Device->ops->construct_default_request_settings( mHal3Device, templateId); ATRACE_END(); if (rawRequest == NULL) { SET_ERR_L(HAL is unable to construct default settings for template %d, templateId); return DEAD_OBJECT; } *request = rawRequest; mRequestTemplateCache[templateId] = rawRequest; ……… } |
最终是由hal来实现构建一个rawrequest,即对于Preview,而言是构建了一个CAMERA3_TEMPLATE_PREVIEW类型的 Request。其实对HAL而言,rawrequest本质是用于操作一个camera_metadata_t类型的数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
struct camera_metadata { metadata_size_t size; uint32_t version; uint32_t flags; metadata_size_t entry_count; metadata_size_t entry_capacity; metadata_uptrdiff_t entries_start; // Offset from camera_metadata metadata_size_t data_count; metadata_size_t data_capacity; metadata_uptrdiff_t data_start; // Offset from camera_metadata uint8_t reserved[]; }; |
该数据结构可以存储多种数据,且可以根据entry tag的不同类型来存储数据,同时数据量的大小也可以自动调整;
c mPreviewRequest.update(ANDROID_REQUEST_ID,&mPreviewRequestId, 1)
将当前的PreviewRequest相应的ID保存到camera metadata。
2.6、调用mStreamingProcessor->startStream函数启动整个预览的stream流
代码目录-2:
frameworks/av/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
该函数的处理过程较为复杂,可以说是整个Preview正常工作的核心控制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
status_t StreamingProcessor::startStream(StreamType type, const Vector&outputStreams) { ..... CameraMetadata &request = (type == PREVIEW) ? mPreviewRequest : mRecordingRequest;//取preview的CameraMetadata request //CameraMetadata中添加outputStreams res = request.update(ANDROID_REQUEST_OUTPUT_STREAMS, outputStreams); res = device->setStreamingRequest(request);//向hal发送request ..... } |
该函数首先是根据当前工作模式来确定StreamingProcessor需要处理的Request,该模块负责Preview和Record两个Request。
以PreviewRequest就是之前createDefaultRequest构建的,这里先是将这个Request所需要操作的Outputstream打包到一个tag叫ANDROID_REQUEST_OUTPUT_STREAMS的entry当中。
a 调用setStreamingRequest函数
代码目录:
frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
真正的请求Camera3Device去处理这个带有多路stream的PreviewRequest。
a.1
1 2 3 4 5 6 7 8 9 10 11 12 13 |
status_t Camera3Device::setStreamingRequest(const CameraMetadata &request, int64_t* ) { ATRACE_CALL(); List requests; requests.push_back(request); return setStreamingRequestList(requests, NULL); } |
该函数将mPreviewRequest push到一个list,调用setStreamingRequestList
a.2
1 2 3 4 5 6 7 |
status_t Camera3Device::setStreamingRequestList(const List &requests, int64_t *lastFrameNumber) { ATRACE_CALL(); return submitRequestsHelper(requests, true, lastFrameNumber); } |
a.3
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 |
status_t Camera3Device::submitRequestsHelper( const List &requests, bool repeating, int64_t *lastFrameNumber) {//repeating = 1;lastFrameNumber = NULL ……… status_t res = checkStatusOkToCaptureLocked(); ……… RequestList requestList; //返回的是CaptureRequest RequestList res = convertMetadataListToRequestListLocked(requests, &requestList); ……… if (repeating) { //重复的request存入到RequestThread res = mRequestThread->setRepeatingRequests(requestList, lastFrameNumber); } else { //capture模式,拍照单词 res = mRequestThread->queueRequestList(requestList,lastFrameNumber); } if (res == OK) { waitUntilStateThenRelock(true, kActiveTimeout); if (res != OK) { SET_ERR_L(Can't transition to active in %f seconds!, kActiveTimeout/1e9); } ALOGV(Camera %d: Capture request % PRId32 enqueued, mId, (*(requestList.begin()))->mResultExtras.requestId); } else { CLOGE(Cannot queue request. Impossible.); return BAD_VALUE; } return res; } |
a.4 convertMetadataListToRequestListLocked
这个函数是需要将Requestlist中保存的CameraMetadata数据转换为List;
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 |
status_t Camera3Device::convertMetadataListToRequestListLocked( const List &metadataList, RequestList *requestList) { ……… for (List::const_iterator it = metadataList.begin();//CameraMetadata, mPreviewRequest it != metadataList.end(); ++it) { //新建CaptureRequest由CameraMetadata转化而来 sp<<b>capturerequest> newRequest = setUpRequestLocked(*it); ……… // Setup burst Id and request Id newRequest->mResultExtras.burstId = burstId++; if (it->exists(ANDROID_REQUEST_ID)) { if (it->find(ANDROID_REQUEST_ID).count == 0) { CLOGE(RequestID entry exists; but must not be empty in metadata); return BAD_VALUE; } //设置该request对应的id newRequest->mResultExtras.requestId = it->find(ANDROID_REQUEST_ID).data.i32[0]; } else { CLOGE(RequestID does not exist in metadata); return BAD_VALUE; } requestList->push_back(newRequest); ……… } return OK; } |
这里是对List进行迭代解析处理,如当前模式下仅存在PreviewRequest这一个CameraMetadata,通过setUpRequestLocked将其转换为一个CaptureRequest。
a.5 setUpRequestLocked
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
spCamera3Device::setUpRequestLocked( const CameraMetadata &request) {//mPreviewRequest status_t res; if (mStatus == STATUS_UNCONFIGURED || mNeedConfig) { res = configureStreamsLocked(); ...... //CameraMetadata转为CaptureRequest,包含mOutputStreams sp newRequest = createCaptureRequest(request); return newRequest; } |
configureStreamsLocked函数主要是将Camera3Device侧建立的所有Stream包括Output与InPut格式 的交由HAL3层的Device去实现处理的核心接口是configure_streams与register_stream_buffer。
createCaptureRequest函数是将一个CameraMetadata格式的数据如PreviewRequest转换为一个CaptureRequest:
a.6
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 67 68 69 70 71 72 73 |
spCamera3Device::createCaptureRequest( const CameraMetadata &request) {//mPreviewRequest ……… spnewRequest = new CaptureRequest; newRequest->mSettings = request;//CameraMetadata camera_metadata_entry_t inputStreams = newRequest->mSettings.find(ANDROID_REQUEST_INPUT_STREAMS); if (inputStreams.count > 0) { if (mInputStream == NULL || mInputStream->getId() != inputStreams.data.i32[0]) { CLOGE(Request references unknown input stream %d, inputStreams.data.u8[0]); return NULL; } ……… newRequest->mInputStream = mInputStream; newRequest->mSettings.erase(ANDROID_REQUEST_INPUT_STREAMS); } //读取存储在CameraMetadata的stream id信息 camera_metadata_entry_t streams = newRequest->mSettings.find(ANDROID_REQUEST_OUTPUT_STREAMS); ……… for (size_t i = 0; i < streams.count; i++) { //Camera3OutputStream的id在mOutputStreams中 int idx = mOutputStreams.indexOfKey(streams.data.i32[i]); ……… } //返回的是Camera3OutputStream,preview/callback等stream spstream = mOutputStreams.editValueAt(idx); ……… //Camera3OutputStream添加到CaptureRequest的mOutputStreams newRequest->mOutputStreams.push(stream); } newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS); return newRequest; } |
该函数主要处理指定的这个CameraMetadata mPreviewRequest下对应所拥有的Output与Input Stream,对于Preview而言,至少存在OutPutStream包括一路StreamProcessor与一路可选的 CallbackProcessor。
在构建这个PreviewRequest时,已经将ANDROID_REQUEST_OUTPUT_STREAMS这个Tag进行了初始化,相应的内容为Vector &outputStreams,包含着属于PreviewRequest这个Request所需要的输出stream的ID值,通过这个ID index值,可以遍历到Camera3Device下所createstream创造的Camera3OutputStream,即说明不同类型的 Request在Camera3Device端存在多个Stream,而每次不同业务下所需要Request的对应的Stream又仅是其中的个别而已。
idx = mOutputStreams.indexOfKey(streams.data.i32[i])是通过属于PreviewRequest中包含的一个 stream的ID值来查找到mOutputStreams这个KeyedVector中对应的标定值index。注意:两个索引值不一定是一致的。
mOutputStreams.editValueAt(idx)是获取一个与该ID值(如Previewstream ID、Callback Stream ID等等)相对应的Camera3OutputStream。
在找到了当前Request中所有的Camera3OutputStream后,将其维护在CaptureRequest中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class CaptureRequest : public LightRefBase { public: CameraMetadata mSettings; sp mInputStream; Vector > mOutputStreams; CaptureResultExtras mResultExtras; }; |
mSettings是保存CameraMetadata PreviewRequest,vector mOutPutStreams保存着当前Request提取出来的Camera3OutputStream,至此构建了一个CaptureRequest。
回到a.4:convertMetadataListToRequestListLocked
返回到convertMetadataListToRequestListLocked中,现在已经完成了一个CameraMetadata Request的处理,生产的是一个CaptureRequest。我们将这个ANDROID_REQUEST_ID的ID值,保留在newRequest->mResultExtras.requestId = it->find(ANDROID_REQUEST_ID).data.i32[0]。
这个值在整个Camera3的架构中,仅存在3大种Request类型,说明了整个和HAL层交互的Request类型是不多的:
预览Request mPreviewRequest:
1 |
mPreviewRequestId(Camera2Client::kPreviewRequestIdStart), |
拍照Request mCaptureRequest:
1 |
mCaptureId(Camera2Client::kCaptureRequestIdStart), |
录像Request mRecordingRequest:
1 |
mRecordingRequestId(Camera2Client::kRecordingRequestIdStart); |
1 2 3 4 5 6 7 8 9 10 11 |
static const int32_t kPreviewRequestIdStart = 10000000; static const int32_t kPreviewRequestIdEnd = 20000000; static const int32_t kRecordingRequestIdStart = 20000000; static const int32_t kRecordingRequestIdEnd = 30000000; static const int32_t kCaptureRequestIdStart = 30000000; static const int32_t kCaptureRequestIdEnd = 40000000; |
回到a.3:mRequestThread->setRepeatingRequests(requestList)
对于Preview来说,一次Preview后底层硬件就该可以连续的工作,而不需要进行过多的切换,故Framework每次向HAL发送的Request均是一种repeat的操作模式,故调用了一个重复的RequestQueue来循环处理每次的Request。
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 |
status_t Camera3Device::RequestThread::setRepeatingRequests( const RequestList &requests, int64_t *lastFrameNumber) { Mutex::Autolock l(mRequestLock); if (lastFrameNumber != NULL) {//第一次进来为null *lastFrameNumber = mRepeatingLastFrameNumber; } mRepeatingRequests.clear(); mRepeatingRequests.insert(mRepeatingRequests.begin(), requests.begin(), requests.end()); unpauseForNewRequests();//signal request_thread in waitfornextrequest mRepeatingLastFrameNumber = NO_IN_FLIGHT_REPEATING_FRAMES; return OK; } |
将Preview线程提交的Request加入到mRepeatingRequests中后,唤醒RequestThread线程去处理当前新的Request。
2.7、经过2.6步骤将开启RequestThread 请求处理线程
RequestThread::threadLoop()函数主要用于响应并处理新加入到Request队列中的请求。
代码目录-2:
frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
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 |
bool Camera3Device::RequestThread::threadLoop() { .... //返回的是mRepeatingRequests,mPreviewRequest sp nextRequest = waitForNextRequest(); ……… // Create request to HAL //CaptureRequest转为给HAL3.0的camera3_capture_request_t camera3_capture_request_t request = camera3_capture_request_t(); request.frame_number = nextRequest->mResultExtras.frameNumber;//当前帧号 VectoroutputBuffers; // Get the request ID, if any int requestId; camera_metadata_entry_t requestIdEntry = nextRequest->mSettings.find(ANDROID_REQUEST_ID); if (requestIdEntry.count > 0) { //获取requestid,这里是mPreviewRequest的id requestId = requestIdEntry.data.i32[0]; } ..... for (size_t i = 0; i < nextRequest->mOutputStreams.size(); i++) { res = nextRequest->mOutputStreams.editItemAt(i)-> getBuffer(&outputBuffers.editItemAt(i)); ..... // Submit request and block until ready for next one ATRACE_ASYNC_BEGIN(frame capture, request.frame_number); ATRACE_BEGIN(camera3->process_capture_request); //调用底层hal的process_capture_request,如antibanding参数设置 res = mHal3Device->ops->process_capture_request(mHal3Device, &request); ATRACE_END(); ....... } |
a.1 waitForNextRequest()
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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
Camera3Device::RequestThread::waitForNextRequest() { ……… while (mRequestQueue.empty()) { if (!mRepeatingRequests.empty()) { // Always atomically enqueue all requests in a repeating request // list. Guarantees a complete in-sequence set of captures to // application. const RequestList &requests = mRepeatingRequests; RequestList::const_iterator firstRequest = requests.begin(); nextRequest = *firstRequest; //把当前的mRepeatingRequests插入到mRequestQueue mRequestQueue.insert(mRequestQueue.end(), ++firstRequest, requests.end()); // No need to wait any longer mRepeatingLastFrameNumber = mFrameNumber + requests.size() - 1; break; } //等待下一个request res = mRequestSignal.waitRelative(mRequestLock, kRequestTimeout); if ((mRequestQueue.empty() && mRepeatingRequests.empty()) || exitPending()) { Mutex::Autolock pl(mPauseLock); if (mPaused == false) { ALOGV(%s: RequestThread: Going idle, __FUNCTION__); mPaused = true; // Let the tracker know spstatusTracker = mStatusTracker.promote(); if (statusTracker != 0) { statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE); } } // Stop waiting for now and let thread management happen return NULL; } } if (nextRequest == NULL) { // Don't have a repeating request already in hand, so queue // must have an entry now. RequestList::iterator firstRequest = mRequestQueue.begin(); nextRequest = *firstRequest; //取一根mRequestQueue中的CaptureRequest,来自于mRepeatingRequests的next mRequestQueue.erase(firstRequest); } ……… if (nextRequest != NULL) { //对每一个非空的request需要帧号++ nextRequest->mResultExtras.frameNumber = mFrameNumber++; nextRequest->mResultExtras.afTriggerId = mCurrentAfTriggerId; nextRequest->mResultExtras.precaptureTriggerId = mCurrentPreCaptureTriggerId; } return nextRequest; } |
该函数是响应RequestList的核心,通过不断的轮训休眠等待一旦mRepeatingRequests有Request可处理时,就将他内部所有 的CaptureRequest加入到mRequestQueue 中去,理论来说每一个CaptureRequest对应着一帧的请求处理,每次响应时可能会出现mRequestQueue包含了多个 CaptureRequest。
通过nextRequest->mResultExtras.frameNumber = mFrameNumber++表示当前CaptureRequest在处理的一帧图像号。
对于mRepeatingRequests而言,只有其非空,在执行完一次queue操作后,在循环进入执行时,会自动对 mRequestQueue进行erase操作,是的mRequestQueue变为empty后再次重新加载mRepeatingRequests中的 内容,从而形成一个队repeatRequest的重复响应过程。
a.2
1 |
camera_metadata_entry_t requestIdEntry = nextRequest->mSettings.find(ANDROID_REQUEST_ID); |
提取该CaptureRequest对应的 Request 类型值;
a.3 getBuffer操作
a.4
1 |
mHal3Device->ops->process_capture_request(mHal3Device, &request) |
这里的request是已经由一个CaptureRequest转换为和HAL3.0交互的camera3_capture_request_t结构。
- 3、 总结
至此已经完成了一次向HAL3.0 Device发送一次完整的Request的请求。从最初Preview启动建立多个OutPutStream,再是将这些Stream打包成一个 mPreviewRequest来启动stream,随后将这个Request又转变为一个CaptureRequest,直到转为Capture list后交由RequestThread来处理这些请求。每一次的Request简单可以说是Camera3Device向HAL3.0请求一帧数据, 当然每一次Request也可以包含各种控制操作,如AutoFocus等内容。