ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Camera Framework流程系列(一)setRepeatingRequest 流程

Camera Framework流程系列(一)setRepeatingRequest 流程 在安卓 Camera Framework 中setRepeatingRequest 是一个关键的 API用于设置重复的捕获请求。它允许应用层通过 CameraCaptureSession 发起连续的预览或录制请求。以下是关于 setRepeatingRequest 的详细流程解析。1. 调用链概述应用层调用 CameraCaptureSession.setRepeatingRequest 方法时会触发框架层和 HAL 层的一系列交互。具体流程如下应用层通过 CameraManager.openCamera() 获取到 CameraDevice 实例。在 CameraDevice 创建后应用层通过 createCaptureSession() 创建 CameraCaptureSession。应用层调用CameraCaptureSession的setRepeatingRequest 方法发起预览请求。相机框架Camera3Device中收到应用下发下来的RepeatingRequest后会不断地下发预览request给Camera HAL。一般情况下应用只需要调用一次setRepeatingRequest接口即可实现预览Camera3Device会实现重复下发request的动作。但是如果预览CaptureRequest的setting有变化比如需要改变sensor、lens、flash或3A相关的metadata参数就需要重新调用一次setRepeatingRequest接口将新的CaptureRequest下发下去。2. 具体实现分析java层流程CaptureRequest本质是对Settings和Output Surfaces的封装具体介绍可参考第23讲 CaptureRequest详解 - Android Camera2 API|极客笔记。CameraCaptureSessionImpl#setRepeatingRequest public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback, Handler handler) throws CameraAccessException { checkRepeatingRequest(request); synchronized (mDeviceImpl.mInterfaceLock) { checkNotClosed(); handler checkHandler(handler, callback); if (DEBUG) { Log.v(TAG, mIdString setRepeatingRequest - request request , callback callback handler handler); } return addPendingSequence(mDeviceImpl.setRepeatingRequest(request, createCaptureCallbackProxy(handler, callback), mDeviceExecutor)); } }1. CameraDeviceImpl#setRepeatingRequest public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback, Executor executor) throws CameraAccessException { ListCaptureRequest requestList new ArrayListCaptureRequest(); requestList.add(request); return submitCaptureRequest(requestList, callback, executor, /*streaming*/true); } 2. CameraDeviceImpl#submitCaptureRequest private int submitCaptureRequest(ListCaptureRequest requestList, CaptureCallback callback, Executor executor, boolean repeating) throws CameraAccessException { ...... // 如果是预览则调用stopRepeating通知cameraserver停止像HAL发送预览request if (repeating) { stopRepeating(); } SubmitInfo requestInfo; CaptureRequest[] requestArray requestList.toArray(new CaptureRequest[requestList.size()]); ...... // 调用native FWK层submitRequestList接口下发request requestInfo mRemoteDevice.submitRequestList(requestArray, repeating); ...... return requestInfo.getRequestId(); } }封装在SubmitInfo对象中的两个变量mRequestId对应native层CameraDeviceClient的mRequestIdCounter计数器从0开始表示调用submitRequestList的次数。mLastFrameNumber第一次下repeating request的时候为-1。java层的CameraCharacteristic静态metadata、CaptureRequestsettingdynamic metadata、CaptureResult底层实际生效的metadynamic metadata对应到native层本质上都是CameraMetadata这三个类里面都封装了CameraMetadataNative成员属性来实现和native层对应上CameraCharacteristicprivate final CameraMetadataNative mPropertiesCaptureRequestprivate CameraMetadataNative mLogicalCameraSettings; private final HashMapString, CameraMetadataNative mPhysicalCameraSettingsCaptureResultprivate final CameraMetadataNative mResults。native层流程Camera3Device中的核心结构体类型class CaptureRequest : public LightRefBaseCaptureRequest { public: // cameraId metadata PhysicalCameraSettingsList mSettingsList; // surface信息流信息 Vectorspcamera3::Camera3OutputStreamInterface mOutputStreams; SurfaceMap mOutputSurfaces; CaptureResultExtras mResultExtras; // The number of requests that should be submitted to HAL at a time. // For example, if batch size is 8, this request and the following 7 // requests will be submitted to HAL at a time. The batch size for // the following 7 requests will be ignored by the request thread. // 默认为1只有高帧率录制场景会不一样 int mBatchSize; // 是否是预览request bool mRepeating; // request被创建的时间戳 nsecs_t mRequestTimeNs; ...... }; typedef ListspCaptureRequest RequestList; // Used to prepare a batch of requests. struct NextRequest { spCaptureRequest captureRequest;// Camera3Device中的request只有setting、surface和stream信息 camera_capture_request_t halRequest; // 给HAL下的request多了帧号和buffer句柄 Vectorcamera_stream_buffer_t outputBuffers; bool submitted; };InFlightRequest.h中的核心结构体类型typedef struct camera_capture_request { uint32_t frame_number; const camera_metadata_t *settings; uint32_t num_output_buffers; const camera_stream_buffer_t *output_buffers; uint32_t num_physcam_settings; const char **physcam_id; const camera_metadata_t **physcam_settings; } camera_capture_request_t; typedef struct camera_capture_result { uint32_t frame_number; const camera_metadata_t *result; uint32_t num_output_buffers; const camera_stream_buffer_t *output_buffers; uint32_t partial_result; uint32_t num_physcam_metadata; const char **physcam_ids; const camera_metadata_t **physcam_metadata; } camera_capture_result_t; typedef struct camera_shutter_msg { uint32_t frame_number; uint64_t timestamp; bool readout_timestamp_valid; uint64_t readout_timestamp; } camera_shutter_msg_t; struct InFlightRequest { // Set by notify() SHUTTER call. nsecs_t shutterTimestamp; // Set by process_capture_result(). nsecs_t sensorTimestamp; // The last metadata that framework receives from HAL and // not yet send out because the shutter event hasnt arrived. // Its added by process_capture_result and sent when framework // receives the shutter event. CameraMetadata pendingMetadata; // The metadata of the partial results that framework receives from HAL so far // and has sent out. CameraMetadata collectedPartialResult; // Buffers are added by process_capture_result when output buffers // return from HAL but framework has not yet received the shutter // event. They will be returned to the streams when framework receives // the shutter event. Vectorcamera_stream_buffer_t pendingOutputBuffers; // The physical camera ids being requested. // For request on a physical camera stream, the inside set contains one Id // For request on a stream group containing physical camera streams, the // inside set contains all stream Ids in the group. std::setstd::setstd::string physicalCameraIds; // Map of physicalCameraId - Metadata std::vectorPhysicalCaptureResultInfo physicalMetadatas; // Indicates a still capture request. bool stillCapture; // Indicates a ZSL capture request bool zslCapture; // What shared surfaces an output should go to SurfaceMap outputSurfaces; // Current output transformation int32_t transform; }; // Map from frame number to the in-flight request state typedef KeyedVectoruint32_t, InFlightRequest InFlightRequestMap;Camera3Device中的核心变量// Request相关 // mRequestQueue和mRepeatingRequests队列的关系如果mRequestQueue队列为空则从mRepeatingRequests队列复制一个request下个hal并将mRepeatingRequests队列中剩下的reqeust复制到mRequestQueue队列如果mRequestQueue队列不为空则从mRequestQueue队列取出一个request下个hal然后从该队列erase刚刚取出的request。 RequestList mRequestQueue:预览or拍照请求队列 RequestList mRepeatingRequests: 保存应用下发下来的预览CaptureRequest InFlightRequestMap mInFlightMap: 帧号、in-flight request的map集合缓存了已经发送但是还没有收到响应的ClientRequset VectorNextRequest mNextRequests: uint32_t mFrameNumber: 帧号从0开始 // SessionKey Vectorint32_t mSessionParamKeys: CameraMetadata mLatestSessionParams: // 用于threadLoop控制下request Mutex mPauseLock: Condition mDoPauseSignal: bool mDoPause: 用于是否暂停threadLoop流程。一般为false开始重新配流会设置为true配完流会重置为false bool mPaused:1将预览request插入到mRepeatingRequests队列的流程CameraDeviceClient的submitRequestList作为native层的入口将java层下发的requests封装成metadataRequestList和surfaceMapList后将其作为参数调用Camera3Device的setStreamingRequestList接口最终会清除mRepeatingRequests队列并将新请求插入该队列。binder::Status CameraDeviceClient::submitRequestList( const std::vectorhardware::camera2::CaptureRequest requests, bool streaming, /*out*/ hardware::camera2::utils::SubmitInfo *submitInfo) { Listconst CameraDeviceBase::PhysicalCameraSettingsList metadataRequestList; std::listSurfaceMap surfaceMapList; submitInfo-mRequestId mRequestIdCounter; uint32_t loopCounter 0; // 一般情况下requests的size都为1 for (auto request: requests) { SurfaceMap surfaceMap; Vectorint32_t outputStreamIds; std::vectorstd::string requestedPhysicalIds; int64_t dynamicProfileBitmap 0; if (request.mSurfaceList.size() 0) { for (const spSurface surface : request.mSurfaceList) { if (surface 0) continue; int32_t streamId; spIGraphicBufferProducer gbp surface-getIGraphicBufferProducer(); // 这里根据request携带的surface从之前配流保存的mStreamMap中获取到surfaceMap res insertGbpLocked(gbp, surfaceMap, outputStreamIds, streamId); } // 声明physicalSettingsList后面给其赋值 CameraDeviceBase::PhysicalCameraSettingsList physicalSettingsList; for (const auto it : request.mPhysicalCameraSettings) { physicalSettingsList.push_back({resolvedId, it.settings}); } if (!enforceRequestPermissions(physicalSettingsList.begin()-metadata)) { // Callee logs return STATUS_ERROR(CameraService::ERROR_PERMISSION_DENIED, Caller does not have permission to change restricted controls); } physicalSettingsList.begin()-metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS, outputStreamIds[0], outputStreamIds.size()); if (request.mIsReprocess) { physicalSettingsList.begin()-metadata.update(ANDROID_REQUEST_INPUT_STREAMS, mInputStream.id, 1); } physicalSettingsList.begin()-metadata.update(ANDROID_REQUEST_ID, (submitInfo-mRequestId), /*size*/1); // 将requests中的setting和surface封装到metadataRequestList和surfaceMapList metadataRequestList.push_back(physicalSettingsList); surfaceMapList.push_back(surfaceMap); } // 计数器加1 mRequestIdCounter; if (streaming) { // 预览 err mDevice-setStreamingRequestList(metadataRequestList, surfaceMapList, (submitInfo-mLastFrameNumber)); mStreamingRequestId submitInfo-mRequestId; } else { // 拍照 err mDevice-captureList(metadataRequestList, surfaceMapList, (submitInfo-mLastFrameNumber)); } return res; }status_t Camera3Device::setStreamingRequestList( const Listconst PhysicalCameraSettingsList requestsList, const std::listSurfaceMap surfaceMaps, int64_t *lastFrameNumber) { ATRACE_CALL(); return submitRequestsHelper(requestsList, surfaceMaps, /*repeating*/true, lastFrameNumber); } status_t Camera3Device::submitRequestsHelper( const Listconst PhysicalCameraSettingsList requests, const std::listSurfaceMap surfaceMaps, bool repeating, /*out*/ int64_t *lastFrameNumber) { ATRACE_CALL(); nsecs_t requestTimeNs systemTime(); RequestList requestList; // 将requests转换成RequestList将PhysicalCameraSettingsList和SurfaceMap转换成Camera3Device定义的CaptureRequest res convertMetadataListToRequestListLocked(requests, surfaceMaps, repeating, requestTimeNs, /*out*/requestList); if (repeating) { res mRequestThread-setRepeatingRequests(requestList, lastFrameNumber); } else { res mRequestThread-queueRequestList(requestList, lastFrameNumber); } } status_t Camera3Device::RequestThread::setRepeatingRequests( const RequestList requests, /*out*/ int64_t *lastFrameNumber) { ATRACE_CALL(); Mutex::Autolock l(mRequestLock); if (lastFrameNumber ! NULL) { // mRepeatingLastFrameNumber初始值为-1也就是第一次下预览请求lastFrameNumber为-1 *lastFrameNumber mRepeatingLastFrameNumber; } // mRepeatingRequests: 类型为RequestList预览请求队列 mRepeatingRequests.clear(); mFirstRepeating true; mRepeatingRequests.insert(mRepeatingRequests.begin(), requests.begin(), requests.end()); unpauseForNewRequests(); mRepeatingLastFrameNumber hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES; return OK; }2Camera3Device::RequestThread::threadLoop()流程循环从请求队列取出请求并做prepareHalRequest操作后下发请求给HAL。bool Camera3Device::RequestThread::threadLoop() { ATRACE_CALL(); status_t res; // 如果mDoPause为false直接返回false // 如果mDoPause为true就会通过while循环和同步锁机制等待mDoPause被置为为false才退出循环返回false // 什么情况会wait正常情况mDoPause为false该接口直接返回false当重新配流时配流前设置为true此时threadLoop的流程进入到wait状态配完流后设置为falsethreadLoop重新进入工作状态。 if (waitIfPaused()) { return true; } // 从mRepeatingRequests队列或mRequestQueue队列取出一个NextRequest对象此时halReqeust还没ready并插入到mNextRequests队列 // 帧号先赋值给nextRequest然后1mFrameNumber waitForNextRequestBatch(); if (mNextRequests.size() 0) { return true; } ...... // 判断是否需要重配流 if (updateSessionParameters(mNextRequests[0].captureRequest-mSettingsList.begin()-metadata)) { } // 给mNextRequests队列中NextRequest的halRequest赋值buffer申请setting、帧号赋值 // 然后将这个request插入到mInFlightMap中 res prepareHalRequests(); // Submit a batch of requests to HAL. // Use flush lock only when submitting multilple requests in a batch. bool useFlushLock mNextRequests.size() 1; if (useFlushLock) { mFlushLock.lock(); } bool submitRequestSuccess false; nsecs_t tRequestStart systemTime(SYSTEM_TIME_MONOTONIC); // sendRequestsBatch给HAL下发request submitRequestSuccess sendRequestsBatch(); nsecs_t tRequestEnd systemTime(SYSTEM_TIME_MONOTONIC); mRequestLatency.add(tRequestStart, tRequestEnd); if (useFlushLock) { mFlushLock.unlock(); } // 清空mNextRequests队列 { Mutex::Autolock l(mRequestLock); mNextRequests.clear(); } mRequestSubmittedSignal.signal(); return submitRequestSuccess; }- waitForNextRequestBatch()流程从mRepeatingRequests队列或mRequestQueue队列取出一个NextRequest对象并插入到mNextRequests队列。mBatchSize不为1的高帧率录制场景则会插入多个请求同时下个halvoid Camera3Device::RequestThread::waitForNextRequestBatch() { ATRACE_CALL(); Mutex::Autolock l(mRequestLock); assert(mNextRequests.empty()); NextRequest nextRequest; // 针对预览总原则mRequestQueue中有request则从mRequestQueue中取否则从mRepeatingRequests中取。mRequestQueue中取一个删一个mRepeatingRequests中取只是复制操作。 // 1.如果应用下的是单个预览reqeust则直接从mRepeatingRequests队列复制该预览reqeust作为nextRequest返回。 // 2.如果应用下的是n个预览reqeust则会取从mRepeatingRequests队列中的第一个request作为nextRequest返回并将mRepeatingRequests队列中剩下的n-1个预览reqeust插入到mRequestQueue队列中下次下预览请求时则会开始从mRequestQueue队列取预览请求。mRequestQueue队列取完某个预览request会做erase的操作但mRepeatingRequests不会 // 该接口中会执行nextRequest-mResultExtras.frameNumber mFrameNumber; nextRequest.captureRequest waitForNextRequestLocked(); if (nextRequest.captureRequest nullptr) { return; } nextRequest.halRequest camera_capture_request_t(); nextRequest.submitted false; // 往mNextRequests添加NextRequest对象但此时halRequest还没做赋值 mNextRequests.add(nextRequest); // batchSize默认为1高帧率录制场景会不一样 const size_t batchSize nextRequest.captureRequest-mBatchSize; for (size_t i 1; i batchSize; i) { NextRequest additionalRequest; additionalRequest.captureRequest waitForNextRequestLocked(); if (additionalRequest.captureRequest nullptr) { break; } additionalRequest.halRequest camera_capture_request_t(); additionalRequest.submitted false; mNextRequests.add(additionalRequest); } if (mNextRequests.size() batchSize) { ALOGE(RequestThread: only get %zu out of %zu requests. Skipping requests., mNextRequests.size(), batchSize); cleanUpFailedRequests(/*sendRequestError*/true); } return; }-prepareHalRequests()流程prepare halRequest并将这个request插入到mInFlightMap中status_t Camera3Device::RequestThread::prepareHalRequests() { ATRACE_CALL(); bool batchedRequest mNextRequests[0].captureRequest-mBatchSize 1; for (size_t i 0; i mNextRequests.size(); i) { auto nextRequest mNextRequests.editItemAt(i); spCaptureRequest captureRequest nextRequest.captureRequest; camera_capture_request_t* halRequest nextRequest.halRequest; Vectorcamera_stream_buffer_t* outputBuffers nextRequest.outputBuffers; // Prepare a request to HAL halRequest-frame_number captureRequest-mResultExtras.frameNumber; ...... if (parent-isHalBufferManagedStream(streamId)) { if (outputStream-isAbandoned()) { ALOGV(%s: stream %d is abandoned, skipping request, __FUNCTION__, streamId); return TIMED_OUT; } // HAL will request buffer through requestStreamBuffer API camera_stream_buffer_t buffer outputBuffers-editItemAt(j); buffer.stream outputStream-asHalStream(); buffer.buffer nullptr; buffer.status CAMERA_BUFFER_STATUS_OK; buffer.acquire_fence -1; buffer.release_fence -1; // Mark the output stream as unpreparable to block clients from calling // prepare after this request reaches CameraHal and before the respective // buffers are requested. outputStream-markUnpreparable(); } else { // 如果没有使能hal buffer manager则申请buffer res outputStream-getBuffer(outputBuffers-editItemAt(j), waitDuration, captureRequest-mOutputSurfaces[streamId]); if (res ! OK) { // Cant get output buffer from gralloc queue - this could be due to // abandoned queue or other consumer misbehavior, so not a fatal // error ALOGV(RequestThread: Cant get output buffer, skipping request: %s (%d), strerror(-res), res); return TIMED_OUT; } } // 如果是拍照 if (!mNextRequests[0].captureRequest-mSettingsList.begin()-metadata.isEmpty()) { camera_metadata_ro_entry_t e camera_metadata_ro_entry_t(); find_camera_metadata_ro_entry(settings, ANDROID_CONTROL_CAPTURE_INTENT, e); if ((e.count 0) (e.data.u8[0] ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE)) { isStillCapture true; ATRACE_ASYNC_BEGIN(still capture, mNextRequests[i].halRequest.frame_number); } e camera_metadata_ro_entry_t(); find_camera_metadata_ro_entry(settings, ANDROID_CONTROL_ENABLE_ZSL, e); if ((e.count 0) (e.data.u8[0] ANDROID_CONTROL_ENABLE_ZSL_TRUE)) { isZslCapture true; } // 将这个request插入到mInFlightMap中 res parent-registerInFlight(halRequest-frame_number, totalNumBuffers, captureRequest-mResultExtras, /*hasInput*/halRequest-input_buffer ! NULL, hasCallback, expectedDurationInfo.minDuration, expectedDurationInfo.maxDuration, expectedDurationInfo.isFixedFps, requestedPhysicalCameras, isStillCapture, isZslCapture, captureRequest-mRotateAndCropAuto, captureRequest-mAutoframingAuto, mPrevCameraIdsWithZoom, passSurfaceMap ? uniqueSurfaceIdMap : SurfaceMap{}, captureRequest-mRequestTimeNs); } } return OK; }- sendRequestsBatch()流程待补充扩展一setRepeatingBurst和setRepeatingRequest的区别扩展二在setRepeatingRequest的过程中调用capture接口拍照会发生什么扩展三stopRepeating和abortCaptures的区别
返回列表