Android camera2

一、序言

为了对阶段性的知识积累、方便以后调查问题,特做此文档!
将以camera app 使用camera2 api进行分析。
(1)、打开相机 openCamera
(2)、创建会话 createCaptureSession
(3)、开始预览 setRepeatingRequest
(4)、停止预览 stopRepeating
(5)、关闭相机 closeCamera

二、打开相机

1、camera app在使用camera2 api的第一步就是调用cameraManager的openCamera接口此接口有三个参数

在这里插入图片描述

2、调用时序

2.1 调用openCamera接口

在这里插入图片描述

2.2 内部调用到openCameraDeviceUserAsync

调用内部方法getCameraCharacteristics查询camera设备的相关属性,这里会通过binder调用到CameraService(c++), 主要是camera 的前后朝向、图像显示角度(0度、90度、180度、270度)

在这里插入图片描述
new CameraDeviceImpl 的时候将一些变量保存在该对象内,这个CameraDeviceImpl会返回一个CameraDeviceCallbacks后面会将这个callback通过CameraService的接口connect()给到CameraDeviceClientBase, 后续不管是预览、录制、拍照存在帧相关的error都会通过CameraDeviceCallbacks --> CaptureCallback
在这里插入图片描述接着去new client
在这里插入图片描述走到makeClient的方法里面,会根据camera api的版本选择new 不同的client
在这里插入图片描述

new CameraDeviceClient -> new Camera2ClientBase -> new CameraDeviceClientBase() -> new BasicClient(), 在Camera2ClientBase的构造函数里面还会new Camera3Device

在这里插入图片描述
在这里插入图片描述
等new client结束后就会去调用initialize
在这里插入图片描述
CameraDeviceClient::initialize() -> Camera2ClientBase::initialize() -> Camera2ClientBase::initializeImpl() -> Camera3Device::initialize -> CameraProviderManager::openSession, CameraProviderManager类可以理解为hal camera的代理类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Camera3Device持有CameraProviderManager对象,而CameraProviderManager可以理解native和hal camera直接的桥梁,它会枚举出camera provider以及这些provider提供的摄像头设备,并提供方法去访问它们.
在这里插入图片描述
在这里插入图片描述
这里必须要插播一下CameraProviderManager的实例化和初始化了,如下图在CameraService 被new的时候就会自动走进onFirstRef(), 然后在该方法里面去new CameraProviderManager,紧接着调用mCameraProviderManager的initialize()方法,initialize()第二个参数是默认参数,直接赋值了HardwareServiceInteractionProxy的对象sHardwareServiceInteractionProxy, HardwareServiceInteractionProxy有两个方法,一个是registerForNotifications(), 一个是getService(), 这里getService()会拿到进程android.hardware.camera.provider@2.4-service中CameraProvider类的远端代理,而CameraProvider中的initialize()方法在CameraProvider的结构体中会被调用,在CameraProvider::initialize() 会去通过hw_get_module()方法打开动态库(camera*.so), 然后CameraProvider::
CameraModule中的camera_module_t *mModule 持有这个真正实现操作camera device的so句柄。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
接着看addDevice方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
好了插播到此结束,接着上面的2.15 deviceInfo3->mInterface->open, mInterface就是CameraDevice,并且持有CameraModule,那么这里就会调用到CameraModule::open,紧接着调用到hal层真正实现者v4l2_camera_hal中的open

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、创建会话

1、在opencamera成功后,就会返回一个对象CameraDeviceImpl,后面在创建的会话和请求预览的时候都会调用该对象的方法。

2、创建会话会调用CameraDeviceImpl::createCaptureSession,分别有三个参数

在这里插入图片描述
3、创建会话代码流程分析
frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java

    // 当open camera成功之后,就会返回CameraDeviceImpl对象,然后在opened回调里面去创建会话,// 需要传进来两个surface,一个用于拍照,一个用于预览public void createCaptureSession(List<Surface> outputs,CameraCaptureSession.StateCallback callback, Handler handler)throws CameraAccessException {List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());for (Surface surface : outputs) {outConfigurations.add(new OutputConfiguration(surface));}createCaptureSessionInternal(null, outConfigurations, callback,checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,/*sessionParams*/ null);}

frameworks/base/core/java/android/hardware/camera2/params/OutputConfiguration.java

    public OutputConfiguration(@NonNull Surface surface) {this(SURFACE_GROUP_ID_NONE, surface, ROTATION_0);}@SystemApipublic OutputConfiguration(int surfaceGroupId, @NonNull Surface surface, int rotation) {checkNotNull(surface, "Surface must not be null");checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");mSurfaceGroupId = surfaceGroupId;mSurfaceType = SURFACE_TYPE_UNKNOWN;mSurfaces = new ArrayList<Surface>(); // 有效值其实只有surfacemSurfaces.add(surface);mRotation = rotation;mConfiguredSize = SurfaceUtils.getSurfaceSize(surface);mConfiguredFormat = SurfaceUtils.getSurfaceFormat(surface);mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(surface);mConfiguredGenerationId = surface.getGenerationId();mIsDeferredConfig = false;mIsShared = false;mPhysicalCameraId = null;mIsMultiResolution = false;mSensorPixelModesUsed = new ArrayList<Integer>();}

frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
紧接着上面的createCaptureSessionInternal

private void createCaptureSessionInternal(InputConfiguration inputConfig,List<OutputConfiguration> outputConfigurations,CameraCaptureSession.StateCallback callback, Executor executor,int operatingMode, CaptureRequest sessionParams) throws CameraAccessException {.......try {// configure streams and then block until IDLE// 这里开始创建streamsconfigureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,operatingMode, sessionParams, createSessionStartTime);if (configureSuccess == true && inputConfig != null) {input = mRemoteDevice.getInputSurface();}} catch (CameraAccessException e) {configureSuccess = false;pendingException = e;input = null;if (DEBUG) {Log.v(TAG, "createCaptureSession - failed with exception ", e);}}// Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.CameraCaptureSessionCore newSession = null;if (isConstrainedHighSpeed) {ArrayList<Surface> surfaces = new ArrayList<>(outputConfigurations.size());for (OutputConfiguration outConfig : outputConfigurations) {surfaces.add(outConfig.getSurface());}StreamConfigurationMap config =getCharacteristics().get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);SurfaceUtils.checkConstrainedHighSpeedSurfaces(surfaces, /*fpsRange*/null, config);newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,callback, executor, this, mDeviceExecutor, configureSuccess,mCharacteristics);} else {// 上面创建了stream之后就会去创建session, 后面又用session对象去请求预览camera// 创建session就是直接一个java的对象newSession = new CamerraCaptureSessionImpl(mNextSessionId++, input,callback, executor, this, mDeviceExecutor, configureSuccess);}// TODO: wait until current session closes, then create the new sessionmCurrentSession = newSession;if (pendingException != null) {throw pendingException;}mSessionStateCallback = mCurrentSession.getDeviceStateCallback();}}

构建Streams

 public boolean configureStreamsChecked(InputConfiguration inputConfig,List<OutputConfiguration> outputs, int operatingMode, CaptureRequest sessionParams,long createSessionStartTime)throws CameraAccessException {// Treat a null input the same an empty listif (outputs == null) {outputs = new ArrayList<OutputConfiguration>();}if (outputs.size() == 0 && inputConfig != null) {throw new IllegalArgumentException("cannot configure an input stream without " +"any output streams");}// 传进来的inputConfig就是 nullcheckInputConfiguration(inputConfig);boolean success = false;synchronized(mInterfaceLock) {checkIfCameraClosedOrInError();// Streams to createHashSet<OutputConfiguration> addSet = new HashSet<OutputConfiguration>(outputs);// Streams to deleteList<Integer> deleteList = new ArrayList<Integer>();// Determine which streams need to be created, which to be deleted// 这里新创建的CameraDeviceImpl 对象 mConfiguredOutputs.size() 都是0for (int i = 0; i < mConfiguredOutputs.size(); ++i) {int streamId = mConfiguredOutputs.keyAt(i);OutputConfiguration outConfig = mConfiguredOutputs.valueAt(i);if (!outputs.contains(outConfig) || outConfig.isDeferredConfiguration()) {// Always delete the deferred output configuration when the session// is created, as the deferred output configuration doesn't have unique surface// related identifies.deleteList.add(streamId);} else {addSet.remove(outConfig);  // Don't create a stream previously created}}mDeviceExecutor.execute(mCallOnBusy);// 这里新创建的CameraDeviceImpl 对象, mRepeatingRequestId == REQUEST_ID_NONE , // stopRepeating()等于什么都没有做stopRepeating();try {waitUntilIdle();// 调到 CameraDeviceClient::beginConfigure 中这里是个空实现,什么都没有做mRemoteDevice.beginConfigure();......// Delete all streams first (to free up HW resources)for (Integer streamId : deleteList) {mRemoteDevice.deleteStream(streamId);mConfiguredOutputs.delete(streamId);}// Add all new streams// 根据新的OutputConfiguration创建streamfor (OutputConfiguration outConfig : outputs) {`if (addSet.contains(outConfig)) {// 这里创建了Camera3OutputStreamint streamId = mRemoteDevice.createStream(outConfig);mConfiguredOutputs.put(streamId, outConfig);}}int offlineStreamIds[];if (sessionParams != null) {// 这里将stream的一些配置给到hal层,最终会调用到V4L2Camera::setupStreamsofflineStreamIds = mRemoteDevice.endConfigure(operatingMode,sessionParams.getNativeCopy(), createSessionStartTime);} else {offlineStreamIds = mRemoteDevice.endConfigure(operatingMode, null,createSessionStartTime);}......success = true;} catch (IllegalArgumentException e) {// OK. camera service can reject stream config if it's not supported by HAL// This is only the result of a programmer misusing the camera2 api.Log.w(TAG, "Stream configuration failed due to: " + e.getMessage());return false;} catch (CameraAccessException e) {if (e.getReason() == CameraAccessException.CAMERA_IN_USE) {throw new IllegalStateException("The camera is currently busy." +" You must wait until the previous operation completes.", e);}throw e;} finally {if (success && outputs.size() > 0) {mDeviceExecutor.execute(mCallOnIdle);} else {// Always return to the 'unconfigured' state if we didn't hit a fatal errormDeviceExecutor.execute(mCallOnUnconfigured);}}}return success;}

frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient
根据outputConfiguration去创建stream


binder::Status CameraDeviceClient::createStream(const hardware::camera2::params::OutputConfiguration &outputConfiguration,/*out*/int32_t* newStreamId) {ATRACE_CALL();binder::Status res;if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;Mutex::Autolock icl(mBinderSerializationLock);// outputConfiguration是持有surface, surface中持有graphicBufferProducer,这个producer就是// 给到camera hal去填充camera数据的const std::vector<sp<IGraphicBufferProducer>>& bufferProducers =outputConfiguration.getGraphicBufferProducers();size_t numBufferProducers = bufferProducers.size();bool deferredConsumer = outputConfiguration.isDeferred();bool isShared = outputConfiguration.isShared();String8 physicalCameraId = String8(outputConfiguration.getPhysicalCameraId());bool deferredConsumerOnly = deferredConsumer && numBufferProducers == 0;bool isMultiResolution = outputConfiguration.isMultiResolution();..........std::vector<sp<Surface>> surfaces;std::vector<sp<IBinder>> binders;..........OutputStreamInfo streamInfo;bool isStreamInfoValid = false;const std::vector<int32_t> &sensorPixelModesUsed =outputConfiguration.getSensorPixelModesUsed();for (auto& bufferProducer : bufferProducers) {// Don't create multiple streams for the same target surface// 一个stream 可以对应多个surface,但是一个surface只能对应一个streamsp<IBinder> binder = IInterface::asBinder(bufferProducer);ssize_t index = mStreamMap.indexOfKey(binder);// if 走进去说明这个surface 已经对应了 stream,之前已经保存在了mStreamMap中if (index != NAME_NOT_FOUND) {String8 msg = String8::format("Camera %s: Surface already has a stream created for it ""(ID %zd)", mCameraIdStr.string(), index);ALOGW("%s: %s", __FUNCTION__, msg.string());return STATUS_ERROR(CameraService::ERROR_ALREADY_EXISTS, msg.string());}// 根据前面app申请的surface,获取其中的bufferProducer,然后去创建streamInfo和 c++ surface,// 并返回sp<Surface> surface;res = SessionConfigurationUtils::createSurfaceFromGbp(streamInfo,isStreamInfoValid, surface, bufferProducer, mCameraIdStr,mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed);.......binders.push_back(IInterface::asBinder(bufferProducer));surfaces.push_back(surface);}// If mOverrideForPerfClass is true, do not fail createStream() for small// JPEG sizes because existing createSurfaceFromGbp() logic will find the// closest possible supported size.int streamId = camera3::CAMERA3_STREAM_ID_INVALID;std::vector<int> surfaceIds;......} else {// 这里走到Camera3Device中,注意这里的streamId、surfaceIds是要在createStream进行赋值的,而surfaces给到Camera3OutputStream// 中,createStream 创建一个Camera3OutputStream 就会streamId++err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width,streamInfo.height, streamInfo.format, streamInfo.dataSpace,static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),&streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution);}if (err != OK) {......} else {int i = 0;// binders 中对应的是每个surface的bufferProducer,即可以理解binder中存在的就是surfacefor (auto& binder : binders) {ALOGV("%s: mStreamMap add binder %p streamId %d, surfaceId %d",__FUNCTION__, binder.get(), streamId, i);// streamMap 一个surface的bufferProducer, 对应一个StreamSurfaceId对象,// 该对象又存一个streamId和对应的surfaceIds[i], 这个streamId就是创建第几个// Camera3OutputStream,surfaceIds[i] 存在的都是0;mStreamMap.add(binder, StreamSurfaceId(streamId, surfaceIds[i]));i++;}// 一个streamId对应一个outputConfigurationmConfiguredOutputs.add(streamId, outputConfiguration);// 每个Camera3OutputStream 和 streamInfo对应关系mStreamInfoMap[streamId] = streamInfo;ALOGV("%s: Camera %s: Successfully created a new stream ID %d for output surface"" (%d x %d) with format 0x%x.",__FUNCTION__, mCameraIdStr.string(), streamId, streamInfo.width,streamInfo.height, streamInfo.format);// Set transform flags to ensure preview to be rotated correctly.res = setStreamTransformLocked(streamId);// Fill in mHighResolutionCameraIdToStreamIdSet mapconst String8 &cameraIdUsed =physicalCameraId.size() != 0 ? physicalCameraId : mCameraIdStr;const char *cameraIdUsedCStr = cameraIdUsed.string();// Only needed for high resolution sensorsif (mHighResolutionSensors.find(cameraIdUsedCStr) !=mHighResolutionSensors.end()) {mHighResolutionCameraIdToStreamIdSet[cameraIdUsedCStr].insert(streamId);}// 这个返回给app*newStreamId = streamId;}return res;
}

frameworks/av/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp

// 构建OutputStreamInfo,从app 申请的surface 获取wdith、height、fromat等信息 
binder::Status SessionConfigurationUtils::createSurfaceFromGbp(OutputStreamInfo& streamInfo, bool isStreamInfoValid,sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp,const String8 &logicalCameraId, const CameraMetadata &physicalCameraMetadata,const std::vector<int32_t> &sensorPixelModesUsed){.......// 其实前面的surface 中的gbp,new 一个c++ 层的Surface对象,C++ Surface 继承自ANativeWindowsurface = new Surface(gbp, useAsync);ANativeWindow *anw = surface.get();int width, height, format;android_dataspace dataSpace;// 从ANativeWindow 中获取surface的width、height、format等,if ((err = anw->query(anw, NATIVE_WINDOW_WIDTH, &width)) != OK) {String8 msg = String8::format("Camera %s: Failed to query Surface width: %s (%d)",logicalCameraId.string(), strerror(-err), err);ALOGE("%s: %s", __FUNCTION__, msg.string());return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());}if ((err = anw->query(anw, NATIVE_WINDOW_HEIGHT, &height)) != OK) {String8 msg = String8::format("Camera %s: Failed to query Surface height: %s (%d)",logicalCameraId.string(), strerror(-err), err);ALOGE("%s: %s", __FUNCTION__, msg.string());return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());}if ((err = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) {String8 msg = String8::format("Camera %s: Failed to query Surface format: %s (%d)",logicalCameraId.string(), strerror(-err), err);ALOGE("%s: %s", __FUNCTION__, msg.string());return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());}if ((err = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE,reinterpret_cast<int*>(&dataSpace))) != OK) {String8 msg = String8::format("Camera %s: Failed to query Surface dataspace: %s (%d)",logicalCameraId.string(), strerror(-err), err);ALOGE("%s: %s", __FUNCTION__, msg.string());return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());}......// isStreamInfoValid 传进来就是false,然后将上面的信息给到streaminfoif (!isStreamInfoValid) {streamInfo.width = width;streamInfo.height = height;streamInfo.format = format;streamInfo.dataSpace = dataSpace;streamInfo.consumerUsage = consumerUsage;streamInfo.sensorPixelModesUsed = overriddenSensorPixelModes;return binder::Status::ok();}......}return binder::Status::ok();
}

frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

        bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,const String8& physicalCameraId, const std::unordered_set<int32_t> &sensorPixelModesUsed,std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution,uint64_t consumerUsage) {......sp<Camera3OutputStream> newStream;......if (format == HAL_PIXEL_FORMAT_BLOB) {......} else {// new 一个 Camera3OutputStreamnewStream = new Camera3OutputStream(mNextStreamId, consumers[0],width, height, format, dataSpace, rotation,mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,isMultiResolution);}size_t consumerCount = consumers.size();for (size_t i = 0; i < consumerCount; i++) {// 这里Camera3OutputStream::getSurfaceId 的实现就是返回0;int id = newStream->getSurfaceId(consumers[i]);if (id < 0) {SET_ERR_L("Invalid surface id");return BAD_VALUE;}// 这里将前面传进来的surface其中的Id都存到surfaceIds中 if (surfaceIds != nullptr) {surfaceIds->push_back(id);}}newStream->setStatusTracker(mStatusTracker);newStream->setBufferManager(mBufferManager);newStream->setImageDumpMask(mImageDumpMask);res = mOutputStreams.add(mNextStreamId, newStream);if (res < 0) {SET_ERR_L("Can't add new stream to set: %s (%d)", strerror(-res), res);return res;}mSessionStatsBuilder.addStream(mNextStreamId);*id = mNextStreamId++;mNeedConfig = true;// Continue captures if active at startif (wasActive) {ALOGV("%s: Restarting activity to reconfigure streams", __FUNCTION__);// Reuse current operating mode and session parameters for new stream configres = configureStreamsLocked(mOperatingMode, mSessionParams);if (res != OK) {CLOGE("Can't reconfigure device for new stream %d: %s (%d)",mNextStreamId, strerror(-res), res);return res;}internalResumeLocked();}ALOGV("Camera %s: Created new stream", mId.string());return OK;
}

frameworks/av/services/camera/libcameraservice/device3/Camera3OutputStream.cpp

Camera3OutputStream::Camera3OutputStream(int id,sp<Surface> consumer,uint32_t width, uint32_t height, int format,android_dataspace dataSpace, camera_stream_rotation_t rotation,nsecs_t timestampOffset, const String8& physicalCameraId,const std::unordered_set<int32_t> &sensorPixelModesUsed,int setId, bool isMultiResolution) :Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height,/*maxSize*/0, format, dataSpace, rotation,physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution),mConsumer(consumer),mTransform(0),mTraceFirstBuffer(true),mUseBufferManager(false),mTimestampOffset(timestampOffset),mConsumerUsage(0),mDropBuffers(false),mDequeueBufferLatency(kDequeueLatencyBinSize) {if (mConsumer == NULL) {ALOGE("%s: Consumer is NULL!", __FUNCTION__);mState = STATE_ERROR;}bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
}

时序图如下:
在这里插入图片描述

四、开始预览

1、从CameraManger -> openCamera() 获取CameraDeviceImpl ,然后调用CameraDeviceImpl的createCaptureSession的去创建会话,获取CameraCaptureSessionImpl对象,接着调用CameraCaptureSessionImpl的setRepeatingRequest去预览。

frameworks/base/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java

  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));}}

frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java

            Executor executor) throws CameraAccessException {List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();requestList.add(request);return submitCaptureRequest(requestList, callback, executor, /*streaming*/true);}
 private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,Executor executor, boolean repeating) throws CameraAccessException {......// 如果打开过了就先停掉,然后再打开if (repeating) {stopRepeating();}SubmitInfo requestInfo;CaptureRequest[] requestArray = requestList.toArray(new CaptureRequest[requestList.size()]);// Convert Surface to streamIdx and surfaceIdxfor (CaptureRequest request : requestArray) {request.convertSurfaceToStreamId(mConfiguredOutputs);}// 调到CameraDeviceClient的submitRequestListrequestInfo = mRemoteDevice.submitRequestList(requestArray, repeating);if (DEBUG) {Log.v(TAG, "last frame number " + requestInfo.getLastFrameNumber());}......if (repeating) {if (mRepeatingRequestId != REQUEST_ID_NONE) {checkEarlyTriggerSequenceCompleteLocked(mRepeatingRequestId,requestInfo.getLastFrameNumber(),mRepeatingRequestTypes);}mRepeatingRequestId = requestInfo.getRequestId();mRepeatingRequestTypes = getRequestTypes(requestArray);} else {mRequestLastFrameNumbersList.add(new RequestLastFrameNumbersHolder(requestList, requestInfo));}if (mIdle) {mDeviceExecutor.execute(mCallOnActive);}mIdle = false;return requestInfo.getRequestId();}}

frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp

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<const SurfaceMap> surfaceMapList;submitInfo->mRequestId = mRequestIdCounter;uint32_t loopCounter = 0;// for (auto&& request: requests) {if (request.mIsReprocess) {if (!mInputStream.configured) {ALOGE("%s: Camera %s: no input stream is configured.", __FUNCTION__,mCameraIdStr.string());return STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,"No input configured for camera %s but request is for reprocessing",mCameraIdStr.string());} else if (streaming) {ALOGE("%s: Camera %s: streaming reprocess requests not supported.", __FUNCTION__,mCameraIdStr.string());return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,"Repeating reprocess requests not supported");} else if (request.mPhysicalCameraSettings.size() > 1) {ALOGE("%s: Camera %s: reprocess requests not supported for ""multiple physical cameras.", __FUNCTION__,mCameraIdStr.string());return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,"Reprocess requests not supported for multiple cameras");}}if (request.mPhysicalCameraSettings.empty()) {ALOGE("%s: Camera %s: request doesn't contain any settings.", __FUNCTION__,mCameraIdStr.string());return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,"Request doesn't contain any settings");}//The first capture settings should always match the logical camera idString8 logicalId(request.mPhysicalCameraSettings.begin()->id.c_str());if (mDevice->getId() != logicalId) {ALOGE("%s: Camera %s: Invalid camera request settings.", __FUNCTION__,mCameraIdStr.string());return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,"Invalid camera request settings");}if (request.mSurfaceList.isEmpty() && request.mStreamIdxList.size() == 0) {ALOGE("%s: Camera %s: Requests must have at least one surface target. ""Rejecting request.", __FUNCTION__, mCameraIdStr.string());return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,"Request has no output targets");}/*** Write in the output stream IDs and map from stream ID to surface ID* which we calculate from the capture request's list of surface target*/SurfaceMap surfaceMap;Vector<int32_t> outputStreamIds;std::vector<std::string> requestedPhysicalIds;if (request.mSurfaceList.size() > 0) {for (const sp<Surface>& surface : request.mSurfaceList) {if (surface == 0) continue;int32_t streamId;sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();res = insertGbpLocked(gbp, &surfaceMap, &outputStreamIds, &streamId);if (!res.isOk()) {return res;}ssize_t index = mConfiguredOutputs.indexOfKey(streamId);if (index >= 0) {String8 requestedPhysicalId(mConfiguredOutputs.valueAt(index).getPhysicalCameraId());requestedPhysicalIds.push_back(requestedPhysicalId.string());} else {ALOGW("%s: Output stream Id not found among configured outputs!", __FUNCTION__);}}} else {for (size_t i = 0; i < request.mStreamIdxList.size(); i++) {int streamId = request.mStreamIdxList.itemAt(i);int surfaceIdx = request.mSurfaceIdxList.itemAt(i);ssize_t index = mConfiguredOutputs.indexOfKey(streamId);if (index < 0) {ALOGE("%s: Camera %s: Tried to submit a request with a surface that"" we have not called createStream on: stream %d",__FUNCTION__, mCameraIdStr.string(), streamId);return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,"Request targets Surface that is not part of current capture session");}const auto& gbps = mConfiguredOutputs.valueAt(index).getGraphicBufferProducers();if ((size_t)surfaceIdx >= gbps.size()) {ALOGE("%s: Camera %s: Tried to submit a request with a surface that"" we have not called createStream on: stream %d, surfaceIdx %d",__FUNCTION__, mCameraIdStr.string(), streamId, surfaceIdx);return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,"Request targets Surface has invalid surface index");}res = insertGbpLocked(gbps[surfaceIdx], &surfaceMap, &outputStreamIds, nullptr);if (!res.isOk()) {return res;}String8 requestedPhysicalId(mConfiguredOutputs.valueAt(index).getPhysicalCameraId());requestedPhysicalIds.push_back(requestedPhysicalId.string());}}CameraDeviceBase::PhysicalCameraSettingsList physicalSettingsList;for (const auto& it : request.mPhysicalCameraSettings) {if (it.settings.isEmpty()) {ALOGE("%s: Camera %s: Sent empty metadata packet. Rejecting request.",__FUNCTION__, mCameraIdStr.string());return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,"Request settings are empty");}// Check whether the physical / logical stream has settings// consistent with the sensor pixel mode(s) it was configured with.// mCameraIdToStreamSet will only have ids that are high resolutionconst auto streamIdSetIt = mHighResolutionCameraIdToStreamIdSet.find(it.id);if (streamIdSetIt != mHighResolutionCameraIdToStreamIdSet.end()) {std::list<int> streamIdsUsedInRequest = getIntersection(streamIdSetIt->second,outputStreamIds);if (!request.mIsReprocess &&!isSensorPixelModeConsistent(streamIdsUsedInRequest, it.settings)) {ALOGE("%s: Camera %s: Request settings CONTROL_SENSOR_PIXEL_MODE not ""consistent with configured streams. Rejecting request.",__FUNCTION__, it.id.c_str());return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,"Request settings CONTROL_SENSOR_PIXEL_MODE are not consistent with ""streams configured");}}String8 physicalId(it.id.c_str());bool hasTestPatternModePhysicalKey = std::find(mSupportedPhysicalRequestKeys.begin(),mSupportedPhysicalRequestKeys.end(), ANDROID_SENSOR_TEST_PATTERN_MODE) !=mSupportedPhysicalRequestKeys.end();bool hasTestPatternDataPhysicalKey = std::find(mSupportedPhysicalRequestKeys.begin(),mSupportedPhysicalRequestKeys.end(), ANDROID_SENSOR_TEST_PATTERN_DATA) !=mSupportedPhysicalRequestKeys.end();if (physicalId != mDevice->getId()) {auto found = std::find(requestedPhysicalIds.begin(), requestedPhysicalIds.end(),it.id);if (found == requestedPhysicalIds.end()) {ALOGE("%s: Camera %s: Physical camera id: %s not part of attached outputs.",__FUNCTION__, mCameraIdStr.string(), physicalId.string());return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,"Invalid physical camera id");}if (!mSupportedPhysicalRequestKeys.empty()) {// Filter out any unsupported physical request keys.CameraMetadata filteredParams(mSupportedPhysicalRequestKeys.size());camera_metadata_t *meta = const_cast<camera_metadata_t *>(filteredParams.getAndLock());set_camera_metadata_vendor_id(meta, mDevice->getVendorTagId());filteredParams.unlock(meta);for (const auto& keyIt : mSupportedPhysicalRequestKeys) {camera_metadata_ro_entry entry = it.settings.find(keyIt);if (entry.count > 0) {filteredParams.update(entry);}}physicalSettingsList.push_back({it.id, filteredParams,hasTestPatternModePhysicalKey, hasTestPatternDataPhysicalKey});}} else {physicalSettingsList.push_back({it.id, it.settings});}}if (!enforceRequestPermissions(physicalSettingsList.begin()->metadata)) {// Callee logsreturn 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);loopCounter++; // loopCounter starts from 1ALOGV("%s: Camera %s: Creating request with ID %d (%d of %zu)",__FUNCTION__, mCameraIdStr.string(), submitInfo->mRequestId,loopCounter, requests.size());metadataRequestList.push_back(physicalSettingsList);surfaceMapList.push_back(surfaceMap);}mRequestIdCounter++;if (streaming) {// 预览走这里err = mDevice->setStreamingRequestList(metadataRequestList, surfaceMapList,&(submitInfo->mLastFrameNumber));} else {// 拍照走这里err = mDevice->captureList(metadataRequestList, surfaceMapList,&(submitInfo->mLastFrameNumber));}ALOGV("%s: Camera %s: End of function", __FUNCTION__, mCameraIdStr.string());return res;
}
status_t Camera3Device::setStreamingRequestList(const List<const PhysicalCameraSettingsList> &requestsList,const std::list<const 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<const SurfaceMap> &surfaceMaps,bool repeating,/*out*/int64_t *lastFrameNumber) {// 预览走这里if (repeating) {res = mRequestThread->setRepeatingRequests(requestList, lastFrameNumber);} else {res = mRequestThread->queueRequestList(requestList, lastFrameNumber);}......return res;
}status_t Camera3Device::RequestThread::setRepeatingRequests(const RequestList &requests,/*out*/int64_t *lastFrameNumber) {ATRACE_CALL();Mutex::Autolock l(mRequestLock);if (lastFrameNumber != NULL) {*lastFrameNumber = mRepeatingLastFrameNumber;}mRepeatingRequests.clear();mFirstRepeating = true;// 将requests请求都给到mRepeatingRequests里面mRepeatingRequests.insert(mRepeatingRequests.begin(),requests.begin(), requests.end());unpauseForNewRequests();mRepeatingLastFrameNumber = hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES;return OK;
}void Camera3Device::RequestThread::unpauseForNewRequests() {ATRACE_CALL();// With work to do, mark thread as unpaused.// If paused by request (setPaused), don't resume, to avoid// extra signaling/waiting overhead to waitUntilPaused// 主要是这里的signal然后,唤醒一个线程去进行发送请求给halmRequestSignal.signal();Mutex::Autolock p(mPauseLock);if (!mDoPause) {ALOGV("%s: RequestThread: Going active", __FUNCTION__);if (mPaused) {sp<StatusTracker> statusTracker = mStatusTracker.promote();if (statusTracker != 0) {statusTracker->markComponentActive(mStatusId);}}mPaused = false;}
}

mRequestSignal.signal()要去唤醒之前跑起来阻塞住的线程

在这里插入图片描述
下发请求
在这里插入图片描述
Threadloop 开始工作
在这里插入图片描述
等待的线程被打断开始获取buffer,通过processBatchCaptureRequests下发请求到camera hal
在这里插入图片描述
通过onResultAvailable 通知app camera data准备好了

五、关闭预览

停止预览app会调用接口CameraDeviceImpl的stopRepeating接口,通过trace可以看到如下调用在这里插入图片描述
CameraDeviceImpl::stopRepeating -> CameraDeviceClient::cancelRequest -> Camera3Device::clearStreamingRequest -> Camera3Device::RequestThread::clearRepeatingRequests->
Camera3Device::RequestThread::clearRepeatingRequestsLocked
会在clearRepeatingRequestsLocked中clear mRepeatingRequests List, 然后mRepeatingRequests为0后
Camera3Device 的threadloop 就会走到
在这里插入图片描述
然后停止获取buffer向camera hal发送

六、关闭相机

在这里插入图片描述
app调用close接口关闭camera,调用时序如上,在cameraserver中会退出相关的threadloop线程,在camera hal会正式做camera ioctrl close 销毁ais client 对应的camera context

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/465097.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Javascript属性遮蔽问题

先了解一下Object.defineProperty()方法 Object.defineProperty() 静态方法会直接在一个对象上定义一个新属性&#xff0c;或修改其现有属性&#xff0c;并返回此对象。 //obj&#xff1a;要定义的对象 //prop&#xff1a;一个字符串或 Symbol&#xff0c;指定了要定义或修改…

vue3项目history模式部署404处理,使用 historyApiFallback 中间件支持单页面应用路由

vue3项目history模式部署404处理&#xff0c;使用 historyApiFallback 中间件支持单页面应用路由 在现代的 web 开发中&#xff0c;单页面应用&#xff08;SPA&#xff09;变得越来越流行。这类应用通常依赖于客户端路由来提供流畅的用户体验&#xff0c;但在服务器端&#xf…

【vim文本编辑器gcc编译器gdb调试器】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、vimvim安装vim常用快捷键vim使用vimtutor zh文档 二、gcc编译器安装gcc工具编译源代码 三、gdb调试器gdb安装gdb常用指令gdb简单上手使用gdb的单步调试功能 总结…

企业数字化转型的架构治理策略:核心问题、深度分析与优化路径

在当今的商业环境中&#xff0c;企业数字化转型已成为实现可持续发展、增强竞争力的战略选择。企业架构治理&#xff08;Enterprise Architecture Governance Capability, EAGC&#xff09;在数字化转型中扮演着保障架构一致性、提升变革效能的关键角色。本指南深入解析了如何通…

基于springboot+vue实现的农产品物流系统

基于springbootvue实现的农产品物流系统 &#xff08;源码L文ppt&#xff09;4-107 摘 要 随着现代信息技术的迅猛发展&#xff0c;农产品物流系统应运而生&#xff0c;成为连接生产者与消费者的重要桥梁。该系统采用java语言&#xff0c; Spring Boot框架&#xff0c;结合My…

基于uniapp和java的电动车智能充电系统软件平台的设计

文章目录 项目介绍具体实现截图技术介绍mvc设计模式小程序框架以及目录结构介绍错误处理和异常处理java类核心代码部分展示详细视频演示源码获取 项目介绍 对电动车智能充电系统进行设计和开发。通过使用本系统可有效地减少运营成本&#xff0c;提高管理效率。 根据近年来社会…

Jmeter命令监控CPU等指标

JMeter 命令行执行脚本得到的报告中&#xff0c;是没有CPU、内存使用率等监控数据的&#xff0c;但是可以使用JMeter插件帮忙。 一、下载jmeter-plugins-manager.jar 下载后将文件放到jmeter安装包lib/ext目录下。打开Jmeter》菜单栏》选项》Plugins Manager 二、安装PerfMon…

ubuntu20.04 加固方案-检查是否设置登录超时

一、编辑/etc/profile配置文件 打开终端。 使用文本编辑器&#xff08;如vim&#xff09;编辑/etc/profile 文件。 vi /etc/profile 二、添加配置参数 在打开的配置文件中&#xff0c;如图位置添加如下参数&#xff1a; TMOUT1800 export TMOUT三、保存并退出 在vim编辑器…

HarmonyOS使用arkTS拉起指定第三方应用程序

HarmonyOS使用arkTS拉起指定第三方应用程序 前言代码及说明bundleName获取abilityName获取 前言 本篇只说采用startAbility方式拉起第三方应用&#xff0c;需要用到两个必备的参数bundleName&#xff0c;abilityName&#xff0c;本篇就介绍如何获取参数… 代码及说明 bundle…

32位汇编——通用寄存器

通用寄存器 什么是寄存器呢&#xff1f; 计算机在三个地方可以存储数据&#xff0c;第一个是把数据存到CPU中&#xff0c;第二个把数据存到内存中&#xff0c;第三个把数据存到硬盘上。 那这个所谓的寄存器&#xff0c;就是CPU中用来存储数据的地方。那这个寄存器有多大呢&a…

江协科技STM32学习- P35 硬件I2C读写MPU6050

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

【大数据学习 | HBASE】habse的表结构

在使用的时候hbase就是一个普通的表&#xff0c;但是hbase是一个列式存储的表结构&#xff0c;与我们常用的mysql等关系型数据库的存储方式不同&#xff0c;mysql中的所有列的数据是按照行级别进行存储的&#xff0c;查询数据要整个一行查询出来&#xff0c;不想要的字段也需要…

【dvwa靶场:XSS系列】XSS (Reflected)低-中-高级别,通关啦

一、低级low 简单拿捏 <script>alert(123)</script>二、中级middle 源码过滤了script但是没有过滤大小写&#xff0c;改成大写S <Script>alert(123)</script>三、高级high 比中级高&#xff0c;过滤了script并且以及大小写&#xff0c;使用其他标…

NAT实验

一、网络拓扑 二、实验步骤 1.配ip地址 用缺省路由充当网关 2.配置telent服务 3.配置公网互通&#xff0c;在PC1上ping R3的公网地址&#xff0c;测试是否可以访问互联网 [R1]ip route-static 0.0.0.0 0 10.1.1.2 [R3]ip route-static 0.0.0.0 0 10.2.2.2 此时私网是ping不通…

Centos 7系统一键安装宝塔教程

服务器推荐青鸟云服务器&#xff0c;2H2G低至16元/月 官网地址&#xff1a; 所有产品_香港轻量云 2核 2G-A型_青鸟云 推荐Finalshell软件连接至服务器&#xff0c;下载地址&#xff1a; https://dl.hostbuf.com/finalshell3/finalshell_windows_x64.exe 下载完成后连接服务…

Kafka 之顺序消息

前言&#xff1a; 在分布式消息系统中&#xff0c;消息的顺序性是一个重要的问题&#xff0c;也是一个常见的业务场景&#xff0c;那 Kafka 作为一个高性能的分布式消息中间件&#xff0c;又是如何实现顺序消息的呢&#xff1f;本篇我们将对 Kafka 的顺序消息展开讨论。 Kafk…

SpringBoot day 1105

ok了家人们&#xff0c;今天继续学习spring boot&#xff0c;let‘s go 六.SpringBoot实现SSM整合 6.1 创建工程&#xff0c;导入静态资源 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</…

fastbootd模式刷android固件的方法

1. fastbootd追根溯源 Google在Android 10上正式引入了动态分区机制来提升OTA的可扩展性。动态分区使能后&#xff1a;andorid系统可以在开机阶段动态地进行分区创建、分区销毁、分区大小调整等操作&#xff0c;下游厂商只需要规划好super分区的总大小&#xff0c;其内部的各个…

什么是多因素身份验证(MFA)的安全性?

多因素身份验证(MFA)简介 什么是MFA 多因素身份验证(MFA)是一种安全过程&#xff0c;要求用户在授予对系统、应用程序或账户的访问权限之前提供两种或多种形式的验证。仅使用单个因素&#xff08;通常是用户名和密码&#xff09;保护资源会使它们容易受到泄露&#xff0c;添加…