在安卓 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 { List<CaptureRequest> requestList = new ArrayList<CaptureRequest>(); requestList.add(request); return submitCaptureRequest(requestList, callback, executor, /*streaming*/true); } 2. CameraDeviceImpl#submitCaptureRequest private int submitCaptureRequest(List<CaptureRequest> 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)、CaptureRequest(setting,dynamic metadata)、CaptureResult(底层实际生效的meta,dynamic metadata),对应到native层本质上都是CameraMetadata,这三个类里面都封装了CameraMetadataNative成员属性来实现和native层对应上:
CameraCharacteristic:private final CameraMetadataNative mProperties;
CaptureRequest:private CameraMetadataNative mLogicalCameraSettings; private final HashMap<String, CameraMetadataNative> mPhysicalCameraSettings;
CaptureResult:private final CameraMetadataNative mResults。
native层流程
Camera3Device中的核心结构体类型:
class CaptureRequest : public LightRefBase<CaptureRequest> { public: // cameraId + metadata PhysicalCameraSettingsList mSettingsList; // surface信息+流信息 Vector<sp<camera3::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 List<sp<CaptureRequest> > RequestList; // Used to prepare a batch of requests. struct NextRequest { sp<CaptureRequest> captureRequest;// Camera3Device中的request,只有setting、surface和stream信息 camera_capture_request_t halRequest; // 给HAL下的request,多了帧号和buffer句柄 Vector<camera_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 hasn't arrived. // It's 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. Vector<camera_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::set<std::set<std::string>> physicalCameraIds; // Map of physicalCameraId <-> Metadata std::vector<PhysicalCaptureResultInfo> 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 KeyedVector<uint32_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 Vector<NextRequest> mNextRequests: uint32_t mFrameNumber: 帧号,从0开始 // SessionKey Vector<int32_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::vector<hardware::camera2::CaptureRequest>& requests, bool streaming, /*out*/ hardware::camera2::utils::SubmitInfo *submitInfo) { List<const CameraDeviceBase::PhysicalCameraSettingsList> metadataRequestList; std::list<SurfaceMap> surfaceMapList; submitInfo->mRequestId = mRequestIdCounter; uint32_t loopCounter = 0; // 一般情况下,requests的size都为1 for (auto&& request: requests) { SurfaceMap surfaceMap; Vector<int32_t> outputStreamIds; std::vector<std::string> requestedPhysicalIds; int64_t dynamicProfileBitmap = 0; if (request.mSurfaceList.size() > 0) { for (const sp<Surface>& surface : request.mSurfaceList) { if (surface == 0) continue; int32_t streamId; sp<IGraphicBufferProducer> 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 List<const PhysicalCameraSettingsList> &requestsList, const std::list<SurfaceMap> &surfaceMaps, int64_t *lastFrameNumber) { ATRACE_CALL(); return submitRequestsHelper(requestsList, surfaceMaps, /*repeating*/true, lastFrameNumber); } status_t Camera3Device::submitRequestsHelper( const List<const PhysicalCameraSettingsList> &requests, const std::list<SurfaceMap> &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; }(2)Camera3Device::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状态,配完流后设置为false,threadLoop重新进入工作状态。 if (waitIfPaused()) { return true; } // 从mRepeatingRequests队列或mRequestQueue队列取出一个NextRequest对象(此时halReqeust还没ready),并插入到mNextRequests队列 // 帧号先赋值给nextRequest,然后+1:mFrameNumber++ 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的高帧率录制场景则会插入多个请求同时下个hal)
void 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); sp<CaptureRequest> captureRequest = nextRequest.captureRequest; camera_capture_request_t* halRequest = &nextRequest.halRequest; Vector<camera_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) { // Can't get output buffer from gralloc queue - this could be due to // abandoned queue or other consumer misbehavior, so not a fatal // error ALOGV("RequestThread: Can't 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()流程:
待补充