Android(安卓)camera预览流程
前面已经简单介绍了,在Android系统中open camera的流程,但是,它又是怎么预览、怎么配置流,如何最终操作到camera HAL的呢。接下来以android原生相机应用,android9,API2,camera HAL3为例,继续阅读代码,看看预览过程到底进行了什么操作?
阅读代码前,先看图。
configureStreams 操作
APP — 从open camera说起
在 Camera2 相机应用,打开相机应用将会调用到 Camera2OneCameraOpenerImpl 类 [packages/apps/Camera2/src/com/android/camera/one/v2/Camera2OneCameraOpenerImpl.java] 的 open() 方法,在该方法中,将会通过 CameraManager 对象的 openCamera() 方法打开camera设备。打开流程就不再述说了,可以参考 Android openCamera流程 ,在这里主要看看该方法的第二个参数 CameraDevice.StateCallback()。当camera成功打开之后,将会调用到 StateCallback 的 onOpened() 方法,而该方法将调用 OneCameraCreator 类的 create() 方法。在 OneCameraCreator::create() 中,将会根据应用层的设置,填充 PictureSizeCalculator.Configuration,将包含分辨率、格式、裁剪的大小等信息。最后在 onOpened() 方法中将会通过 openCallback.onCameraOpened(oneCamera) ,继续将成功打开设备的信息回调到上层。这里将调到 CaptureModule 类 [packages/apps/Camera2/src/com/android/camera/CaptureModule.java] 的 onCameraOpened() 方法。在该方法中,将会进行预览操作 camera.startPreview()。camera.startPreview() 方法将调用 GenericOneCameraImpl 类的 startPreview() 方法,在该方法中,又将通过 mPreviewStarter.startPreview(surface) 调用 PreviewStarter 类的 startPreview() 方法进行预览。在 PreviewStarter::startPreview() 方法中,将通过 mCaptureSessionCreator.createCaptureSession(surfaceList) 调用 CaptureSessionCreator::createCaptureSession() 方法,而在 createCaptureSession() 方法中,又将调用 AndroidCameraDeviceProxy::createCaptureSession(),最后在该方法中,通过 mCameraDevice.createCaptureSession() 调用到 Framework 代码。
Framework
CameraDeviceImpl
在上述的 mCameraDevice.createCaptureSession() 接口将会调用到哪里呢?看看open camera时是如何赋值的。
在open camera的流程中,将会调用到 CameraManager::openCameraDeviceUserAsync() 方法,该方法如下:
private CameraDevice openCameraDeviceUserAsync(String cameraId, CameraDevice.StateCallback callback, Executor executor, final int uid) throws CameraAccessException { CameraDevice device = null; android.hardware.camera2.impl.CameraDeviceImpl deviceImpl = new android.hardware.camera2.impl.CameraDeviceImpl( cameraId, callback, executor, characteristics, mContext.getApplicationInfo().targetSdkVersion); ... device = deviceImpl; return device; }
从 openCameraDeviceUserAsync() 的实现可以知道返回给应用的是 CameraDeviceImpl 实例对象,所以当应用通过 mCameraDevice.createCaptureSession() 将会调用到 CameraDeviceImpl::createCaptureSession() 方法,从这里,进入了Framework代码。
而 CameraDeviceImpl::createCaptureSession() 方法[android/frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java],是用来创建预览session,输出位置是 Surface,会有两个 Surface,一个现实预览画面的 Surface,一个接收预览数据的 Surface。
@Override 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); }
在 createCaptureSessionInternal() 方法中,将会通过 configureStreamsChecked(inputConfig, outputConfigurations, operatingMode, sessionParams)
配置流。在 configureStreamsChecked() 方法中,主要是通过 mRemoteDevice 操作到 CameraService 中的CameraDeviceClient。(同样的在 openCameraDeviceUserAsync() 方法中,connectDevice()返回的CameraDeviceClient,通过CameraDeviceImpl::setRemoteDevice()封装保存到 mRemoteDevice,所以,通过 mRemoteDevice 将会操作到CameraService中的具体函数。)
而 configureStreamsChecked() 方法的操作,可以概括如下:
public boolean configureStreamsChecked(InputConfiguration inputConfig, List<OutputConfiguration> outputs, int operatingMode, CaptureRequest sessionParams) throws CameraAccessException {... mRemoteDevice.beginConfigure(); .../* 注意传递进来的方法参数,inputConfig为null,sessionParams为null */ // Add all new streams for (OutputConfiguration outConfig : outputs) { if (addSet.contains(outConfig)) { /* 将会在这里创建并配置输出流,该流输出显示, * 注意 outConfig 中有显示 surface */ int streamId = mRemoteDevice.createStream(outConfig); mConfiguredOutputs.put(streamId, outConfig); } } ... if (sessionParams != null) { mRemoteDevice.endConfigure(operatingMode, sessionParams.getNativeCopy()); } else { /* 上述只是保存配置,这里才会真正的设置到 HAL */ mRemoteDevice.endConfigure(operatingMode, null); }
我们主要分析 mRemoteDevice.createStream(outConfig) 的操作,在这里,将会通过Binder将相应的配置信息传输到 CameraService 端的CameraDeviceClient。
CameraService — frameworks/av/services/camera/libcameraservice
在通过Binder之后,CameraDeviceImpl 操作的 createStream() 将会由CameraService调用 CameraDeviceClient::createStream() 函数并返回,注意 CameraDeviceClient::createStream() 有两个函数参数,但是第二个可以默认为NULL。
binder::Status CameraDeviceClient::createStream( const hardware::camera2::params::OutputConfiguration &outputConfiguration, /*out*/ int32_t* newStreamId) { const std::vector>& bufferProducers = outputConfiguration.getGraphicBufferProducers(); ... OutputStreamInfo streamInfo; bool isStreamInfoValid = false; ... sp surface; /* 将OutputConfiguration中的配置信息转换保存到streamInfo */ res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer); ... /* 将 outputConfiguration 中的 surface 提取出来并添加到 surfaces */ surfaces.push_back(surface); ... int streamId = camera3::CAMERA3_STREAM_ID_INVALID; std::vector surfaceIds; /* 这里将传递 surfaces 作为参数创建流 */ /* 这里又调用device的 createStream() 函数,那么这里又是调用到了哪里呢,看下面的解析 */ err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width, streamInfo.height, streamInfo.format, streamInfo.dataSpace, static_cast(outputConfiguration.getRotation()), &streamId, physicalCameraId, &surfaceIds, outputConfiguration.getSurfaceSetID(), isShared); .../* 保存相应的信息 */ mStreamMap.add(binder, StreamSurfaceId(streamId, surfaceIds[i])); mConfiguredOutputs.add(streamId, outputConfiguration); mStreamInfoMap[streamId] = streamInfo;}
上面的 mDevice->createStream() 将会调用到哪里呢?
CameraDeviceClient 类是继承模板类 Camera2ClientBase,看 mDevice 的定义,我们可以知道是 sp
,mDevice 的赋值是在模板类Camera2ClientBase 的构造函数中,mDevice = new Camera3Device(cameraId)
,通过其构造函数可以知道 mDevice 指向 Camera3Device 实例对象。所以,mDevice->createStream() 将调用到 Camera3Device::createStream() 函数。
status_t Camera3Device::createStream(const std::vector>& consumers, bool hasDeferredConsumer, uint32_t width, uint32_t height, int format, android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id, const String8& physicalCameraId, std::vector *surfaceIds, int streamSetId, bool isShared, uint64_t consumerUsage) {... } else { /* 创建 Camera3OutputStream 实例对象,注意第二个参数,它是 Surface, * 将保存在 Camera3OutputStream 的 mConsumer 成员 */ newStream = new Camera3OutputStream(mNextStreamId, consumers[0], width, height, format, dataSpace, rotation, mTimestampOffset, physicalCameraId, streamSetId); }.../* newStream 实例对象保存到 mOutputStreams */ res = mOutputStreams.add(mNextStreamId, newStream);mNeedConfig = true;...}
到这里为止,似乎 CameraDeviceClient::createStream() 函数已经跟踪完了,最后只是看到保存一些stream的配置信息,并没有设置到 HAL,那么,导致是在哪里设置的呢,我们回头看看 CameraDeviceImpl::configureStreamsChecked() 方法,在该方法中,通过 mRemoteDevice 操作影响到 CameraService,在 createStream() 之后,还将会调用 endConfigure() 操作,既然 createStream() 并没有设置到 HAL,那么,有没有可能是 endConfigure() 操作呢,我们来看看 CameraDeviceClient::endConfigure() 实现。
binder::Status CameraDeviceClient::endConfigure(int operatingMode, const hardware::camera2::impl::CameraMetadataNative& sessionParams) { .../* 和上述一样,将会调用到 Camera3Device::configureStreams() */ status_t err = mDevice->configureStreams(sessionParams, operatingMode); ...}
而在 Camera3Device::configureStreams() 中,最终又将是调用到 Camera3Device::configureStreamsLocked() 函数。而在 Camera3Device::configureStreamsLocked() 函数主要进行了以下操作:
- 将 Camera3Device::createStream() 保存到 mOutputStreams 中的 stream 添加到 config.streams;
- 通过 mInterface->configureStreams(sessionBuffer, &config, bufferSizes) 操作到HAL配置流;
- 通知上层,配置完成;
上述的 mInterface 变量是在 Camera3Device::initialize() 时,保存 HalInterface 实例对象的,所以,mInterface->configureStreams() 将调用到 Camera3Device::HalInterface::configureStreams()。
Camera3Device::HalInterface::configureStreams() 将stream config转换为 HIDL 接口使用的之后,将按照 HAL 版本调用不同的接口函数,下面我们以 HAL 3.3 为例进行跟踪,将调用 mHidlSession_3_3->configureStreams_3_3()。注:mHidlSession_3_3 是在 HalInterface 构造函数中赋值的,而 mHidlSession_3_3 是 ICameraDeviceSession转换得来的,ICameraDeviceSession 则是Camera3Device::initialize() 中通过 manager->openSession() 获取的。
在上述的 mHidlSession_3_3->configureStreams_3_3() 调用,将会调用到 BpHwCameraDeviceSession::configureStreams_3_3() [android/out/soong/.intermediates/hardware/interfaces/camera/device/3.3/[email protected]_genc++/gen/android/hardware/camera/device/3.3/CameraDeviceSessionAll.cpp],最终调用到 CameraProvider 中的 CameraDeviceSession::configureStreams_3_3()函数。具体怎么调用到这里的就不详细跟踪,知道是通过HIDL影响到这边即可,感兴趣是怎么调用到这边的可以继续跟踪下去。
所以,以上,在 Camera3Device::configureStreamsLocked() 中,将会通过 mInterface->configureStreams(sessionBuffer, &config, bufferSizes) 调用到 CameraProvider,从而配置流操作进入 CameraProvider。
CameraProvider — hardware/interfaces/camera
上述已经说到,在CameraService 通过 mInterface->configureStreams(sessionBuffer, &config, bufferSizes) 函数将配置信息通过HIDL传递到 CameraProvider,将调用 CameraDeviceSession::configureStreams_3_3() 函数。
Return CameraDeviceSession::configureStreams_3_3( const StreamConfiguration& requestedConfiguration, ICameraDeviceSession::configureStreams_3_3_cb _hidl_cb) {.../* 在完成函数参数的转换之后,将通过 mDevice 操作到 HAL 的 configure_streams() */ status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list); ...}
至于为什么会可以通过 mDevice->ops->configure_streams() 操作到HAL呢?
首先,通过代码,我们了解到 mDevice 是在 CameraDeviceSession 构造函数中初始化的,而 CameraDeviceSession 是在 CameraDevice::createSession() 中实例化的。而 createSession() 则是在 open阶段,在 CameraDevice::open() 函数中调用的,跟踪到这里,可以知道,mDevice 是在 CameraDevice::open() 函数中,通过 mModule->open() 获取再赋值的。而 mModule->open() 函数返回的 device 则是在 HAL 中的 Camera::openDevice() 赋值的,该 ops 为 camera3_device_ops_t。
所以,到这里,完成了 configure streams 操作。完成了流的配置之后,又是怎么预览的呢,继续看。
预览操作
回到 APP 的 PreviewStarter
从APP的代码我们可以知道,在创建 PreviewStarter 实例对象时,有一个 onCameraCaptureSessionCreated() 回调函数,当session创建成功时,将会执行这个函数,而从这个函数,最终将进行预览操作,流程如下:
onCameraCaptureSessionCreated()cameraStarter.startCamera()SimpleOneCameraFactory::startCamera()BasicPreviewCommandFactory() preview命令CameraDeviceRequestBuilderFactory::create()AndroidCameraDeviceProxy::createCaptureRequest()
同理,在APP中,通过 mCameraDevice.createCaptureRequest() 将会调用到 CameraDeviceImpl::createCaptureRequest() 方法,从这里,进入了Framework代码。
Framework
CameraDeviceImpl
@Override public CaptureRequest.Builder createCaptureRequest(int templateType) throws CameraAccessException { synchronized(mInterfaceLock) { checkIfCameraClosedOrInError(); CameraMetadataNative templatedRequest = null; /* 一样的,也是通过 mRemoteDevice 代理操作 CameraDeviceClient, * 将调用到 CameraDeviceClient::createDefaultRequest() */ templatedRequest = mRemoteDevice.createDefaultRequest(templateType); ... return builder; } }
CameraService — frameworks/av/services/camera/libcameraservice
CameraDeviceClient
// Create a request object from a template.binder::Status CameraDeviceClient::createDefaultRequest(int templateId, /*out*/ hardware::camera2::impl::CameraMetadataNative* request){ ... CameraMetadata metadata; status_t err; /* 与 createStream() 相同,将会调用到 Camera3Device::createDefaultRequest() */ if ( (err = mDevice->createDefaultRequest(templateId, &metadata) ) == OK && request != NULL) { request->swap(metadata); } ... }
Camera3Device
status_t Camera3Device::createDefaultRequest(int templateId, CameraMetadata *request) {... camera_metadata_t *rawRequest; /* 又将通过 mInterface 调用到 CameraProvider*/ status_t res = mInterface->constructDefaultRequestSettings( (camera3_request_template_t) templateId, &rawRequest); {.../* 保存这个类型请求的信息 */ set_camera_metadata_vendor_id(rawRequest, mVendorTagId); mRequestTemplateCache[templateId].acquire(rawRequest); ... }}
CameraProvider — hardware/interfaces/camera
上述的操作,最后将按照HAL版本的差异,调用不同的HAL接口函数,HAL3.3将调用 device::V3_3::CameraDeviceSession::constructDefaultRequestSettings(),这个也将调用到 device::V3_2::CameraDeviceSession::constructDefaultRequestSettings()。
// Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow.Return CameraDeviceSession::constructDefaultRequestSettings( RequestTemplate type, ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) { CameraMetadata outMetadata; Status status = constructDefaultRequestSettingsRaw( (int) type, &outMetadata); _hidl_cb(status, outMetadata); return Void();}Status CameraDeviceSession::constructDefaultRequestSettingsRaw(int type, CameraMetadata *outMetadata) {... /* 这里将调用到相应平台 HAL 代码,完成这个操作之后,相机设备硬件已经开始输出图像数据了 */ rawRequest = mDevice->ops->construct_default_request_settings(mDevice, (int) type); ...}
图像开始输出,又是怎么通过 SurfaceFlinger 最终显示出来的呢?
从APP的预览命令看起
public class PreviewCommand implements CameraCommand {public void run() throws InterruptedException, CameraAccessException, CameraCaptureSessionClosedException, ResourceAcquisitionFailedException { try (FrameServer.Session session = mFrameServer.createExclusiveSession()) { /* 这个就是之前的 CameraDeviceRequestBuilderFactory::create() 调用处 */ RequestBuilder photoRequest = mBuilderFactory.create(mRequestType); /* 请求图像数据 */ session.submitRequest(Arrays.asList(photoRequest.build()), FrameServer.RequestType.REPEATING); } } }
上述的 session.submitRequest() 操作,最终将经过 FrameServerImpl::submitRequest() 调用到 Framework 的 ICameraDeviceUserWrapper::submitRequest()。
Framework
public class ICameraDeviceUserWrapper { ...public SubmitInfo submitRequest(CaptureRequest request, boolean streaming) throws CameraAccessException { try { /* 调用到 CameraService 的 CameraDeviceClient */ return mRemoteDevice.submitRequest(request, streaming); } catch (Throwable t) { CameraManager.throwAsPublicException(t); throw new UnsupportedOperationException("Unexpected exception", t); } } }
CameraService
[frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp]binder::Status CameraDeviceClient::submitRequest( const hardware::camera2::CaptureRequest& request, bool streaming, /*out*/ hardware::camera2::utils::SubmitInfo *submitInfo) { std::vector requestList = { request }; return submitRequestList(requestList, streaming, submitInfo);}binder::Status CameraDeviceClient::submitRequestList( const std::vector& requests, bool streaming, /*out*/ hardware::camera2::utils::SubmitInfo *submitInfo) {... } 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); const auto& gbps = mConfiguredOutputs.valueAt(index).getGraphicBufferProducers(); /* 获取 surfaceMap 等信息 */ res = insertGbpLocked(gbps[surfaceIdx], &surfaceMap, &outputStreamIds, nullptr); ...} .../* 添加到 surfaceMapList */ surfaceMapList.push_back(surfaceMap); ... } else { /* 调用到 CameraDevice3 的 captureList() */ err = mDevice->captureList(metadataRequestList, surfaceMapList, &(submitInfo->mLastFrameNumber));}}[frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp]status_t Camera3Device::captureList(const List &requestsList, const std::list &surfaceMaps, int64_t *lastFrameNumber) { return submitRequestsHelper(requestsList, surfaceMaps, /*repeating*/false, lastFrameNumber);}status_t Camera3Device::submitRequestsHelper( const List &requests, const std::list &surfaceMaps, bool repeating, /*out*/ int64_t *lastFrameNumber) {.../* 转换信息,并指定 surface id */ res = convertMetadataListToRequestListLocked(requests, surfaceMaps, repeating, /*out*/&requestList); ... } else { /* 添加信息到 mRequestThread 线程的 mRequestQueue 队列, * 该线程在open camera时已经运行,在该函数中,将调用 * Camera3Device::RequestThread::unpauseForNewRequests() * 函数发送信号量告知 mRequestThread 线程 */ res = mRequestThread->queueRequestList(requestList, lastFrameNumber); }...}/* 通过该函数将会获取得到 surface id */status_t Camera3Device::convertMetadataListToRequestListLocked( const List &metadataList, const std::list &surfaceMaps, bool repeating, RequestList *requestList) {... List::const_iterator metadataIt = metadataList.begin(); std::list::const_iterator surfaceMapIt = surfaceMaps.begin(); /* 逐个转换处理 */ for (; metadataIt != metadataList.end() && surfaceMapIt != surfaceMaps.end(); ++metadataIt, ++surfaceMapIt) { /* 将会通过 setUpRequestLocked() 创建 CaptureRequest */ sp newRequest = setUpRequestLocked(*metadataIt, *surfaceMapIt); ... requestList->push_back(newRequest); ... } ...}sp Camera3Device::setUpRequestLocked( const PhysicalCameraSettingsList &request, const SurfaceMap &surfaceMap) { .../* 实质是调用 createCaptureRequest() 创建的请求 */ sp newRequest = createCaptureRequest(request, surfaceMap); return newRequest;}sp Camera3Device::createCaptureRequest( const PhysicalCameraSettingsList &request, const SurfaceMap &surfaceMap) { sp newRequest = new CaptureRequest; ... for (size_t i = 0; i < streams.count; i++) { sp stream = mOutputStreams.editValueAt(idx); // It is illegal to include a deferred consumer output stream into a request auto iter = surfaceMap.find(streams.data.i32[i]); if (iter != surfaceMap.end()) { const std::vector& surfaces = iter->second; .../* 这里,获取到这次请求的 surfaces id 并保存到 * mOutputSurfaces,接下来将会用到 */ newRequest->mOutputSurfaces[i] = surfaces; ... } }}
在 mRequestThread 线程中,操作如下:
bool Camera3Device::RequestThread::threadLoop() { /* 等待请求信息 */ waitForNextRequestBatch(); ... /* 处理请求并申请output buffer,以待 HAL 填充图像数据 */ res = prepareHalRequests(); ... if (mInterface->supportBatchRequest()) { submitRequestSuccess = sendRequestsBatch(); } else { /* 发送请求到 HAL */ submitRequestSuccess = sendRequestsOneByOne(); } ...}
那么 prepareHalRequests() 进行了什么操作呢,接着往下看。
status_t Camera3Device::RequestThread::prepareHalRequests() { for (size_t i = 0; i < mNextRequests.size(); i++) { /* 获取上层传递下来的请求信息 */ auto& nextRequest = mNextRequests.editItemAt(i); sp captureRequest = nextRequest.captureRequest; Vector* outputBuffers = &nextRequest.outputBuffers; ... for (size_t j = 0; j < captureRequest->mOutputStreams.size(); j++) { sp outputStream = captureRequest->mOutputStreams.editItemAt(j); .../* 这里将会根据当前请求配置的 surfaces id 获取surfaces buffer */ res = outputStream->getBuffer(&outputBuffers->editItemAt(j), captureRequest->mOutputSurfaces[j]); ... } }}status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer, const std::vector& surface_ids) { ... res = getBufferLocked(buffer, surface_ids); ...}status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer, const std::vector&) { ... res = getBufferLockedCommon(&anb, &fenceFd); ...}status_t Camera3OutputStream::getBufferLockedCommon(ANativeWindowBuffer** anb, int* fenceFd) { ... /* 这个 mConsumer 是在创建 Camera3OutputStream 实例对象时传递进来的参数, * 而这个实例对象是在 Camera3Device::createStream() 时创建的,可以看看上面 * 的章节,mConsumer 是在创建流时传递下来的 Surface */ sp currentConsumer = mConsumer; ... /* 这里将申请buf,待HAL填充数据 *//* 直接调用 ANativeWindow 对象的 dequeueBuffer 方法将申请 buffer, * ANativeWindow 是 OpenGL 定义的图形接口,在 Android上 的实现就是 * Surface 和 SurfaceFlinger,一个用于生产 buffer ,一个用于消费 buffer */ res = currentConsumer->dequeueBuffer(currentConsumer.get(), anb, fenceFd); ...}
所以,通过上述的跟踪,了解到 prepareHalRequests() 是进行请求信息填充以及buffer申请等。
在 mRequestThread 线程中,获取请求信息之后,经过转换,将会通过 submitRequestSuccess = sendRequestsOneByOne()
经过CameraProvider提交请求信息到 HAL。
bool Camera3Device::RequestThread::sendRequestsOneByOne() { ... for (auto& nextRequest : mNextRequests) { /* 将请求信息传递到 CameraProvider 处理 */ res = mInterface->processCaptureRequest(&nextRequest.halRequest); ... }}
CameraProvider
Return CameraDeviceSession::processCaptureRequest( const hidl_vec& requests, const hidl_vec& cachesToRemove, ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) { updateBufferCaches(cachesToRemove); uint32_t numRequestProcessed = 0; Status s = Status::OK; for (size_t i = 0; i < requests.size(); i++, numRequestProcessed++) { s = processOneCaptureRequest(requests[i]); if (s != Status::OK) { break; } } .... return Void();}Status CameraDeviceSession::processOneCaptureRequest(const CaptureRequest& request) { /* 在该函数中,经过前面一系列的参数转换之后,将调用 HAL 的 * process_capture_request() 函数,将请求添加到 HAL 队列 */ status_t ret = mDevice->ops->process_capture_request(mDevice, &halRequest); }
从源头HAL回调
首先的,Camera HAL通过 VIDIOC_DQBUF 拿到图像数据之后,将会通过 mCallbackOps->notify()、mCallbackOps->process_capture_result() 回调通知 CameraProvider,而 mCallbackOps 是 CameraProvider 在调用 CameraDeviceSession::initialize() 时传递 this 指针下来赋值的,而 process_capture_result() 指针指向implementation 的 CameraDeviceSession::sProcessCaptureResult(),notify() 指向implementation 的 CameraDeviceSession::sNotify()。
typedef struct camera3_capture_result { uint32_t frame_number; const camera_metadata_t *result; uint32_t num_output_buffers; const camera3_stream_buffer_t *output_buffers; const camera3_stream_buffer_t *input_buffer; uint32_t partial_result; uint32_t num_physcam_metadata; const char **physcam_ids; const camera_metadata_t **physcam_metadata;} camera3_capture_result_t;
一般的,camera HAL中,在获取图像数据之后,图像数据信息拷贝到 request->output_buffers[0] ,接着将调用 mCallbackOps->notify() 发送请求完成的消息到 CameraProvider,再调用 mCallbackOps->process_capture_result() 发送请求返回的相应数据信息。
void Camera::notifyShutter(uint32_t frame_number, uint64_t timestamp){ camera3_notify_msg_t message; memset(&message, 0, sizeof(message)); message.type = CAMERA3_MSG_SHUTTER; message.message.shutter.frame_number = frame_number; message.message.shutter.timestamp = timestamp; mCallbackOps->notify(mCallbackOps, &message);}void Camera::sendResult(std::shared_ptr request) { // Fill in the result struct // (it only needs to live until the end of the framework callback). camera3_capture_result_t result { request->frame_number, request->settings.getAndLock(), static_cast(request->output_buffers.size()), request->output_buffers.data(), request->input_buffer.get(), 1 // Total result; only 1 part. }; // Make the framework callback. mCallbackOps->process_capture_result(mCallbackOps, &result);}
将会通过 process_capture_result() 函数指针调用 CameraProvider 中的 CameraDeviceSession::sProcessCaptureResult() 函数,而传递的函数参数就是 camera3_capture_result_t,从 camera3_capture_result_t 的定义我们可以知道,传递下来的信息有帧序号、图像数据信息等。
CameraProvider
CameraDeviceSession::sNotify()
void CameraDeviceSession::sNotify( const camera3_callback_ops *cb, const camera3_notify_msg *msg) { CameraDeviceSession *d = const_cast(static_cast(cb)); NotifyMsg hidlMsg; convertToHidl(msg, &hidlMsg); .../* 在进行一些参数检查之后,将调用回调的 notify() 函数, * mResultBatcher 实际是在open camera时创建 CameraDeviceSession * 实例对象时传递下来的回调函数,而通过阅读代码可以知道,这个mResultBatcher * 实质是 CameraService 端的 Camera3Device */ d->mResultBatcher.notify(hidlMsg);}
通过上面代码的理解,我们知道,CameraDeviceSession::sNotify() 最终将会把这个消息传递到 CameraService 的 Camera3Device 实例对象进行处理。
CameraDeviceSession::sProcessCaptureResult()
/** * Static callback forwarding methods from HAL to instance */void CameraDeviceSession::sProcessCaptureResult( const camera3_callback_ops *cb, const camera3_capture_result *hal_result) { CameraDeviceSession *d = const_cast(static_cast(cb)); CaptureResult result = {}; camera3_capture_result shadowResult; bool handlePhysCam = (d->mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_5); std::vector<::android::hardware::camera::common::V1_0::helper::CameraMetadata> compactMds; std::vector physCamMdArray; sShrinkCaptureResult(&shadowResult, hal_result, &compactMds, &physCamMdArray, handlePhysCam); /* 检查数据的完成性以及擦除之前提交请求信息时的一些参数信息 */ status_t ret = d->constructCaptureResult(result, &shadowResult); if (ret == OK) { /* 一样的,调用到CameraService 的 Camera3Device */ d->mResultBatcher.processCaptureResult(result); }}
CameraService
notify()
在CameraProvider 中通过 notify() 传递到CameraService 之后,最终将调用到以下函数:
void Camera3Device::notify(const camera3_notify_msg *msg) { ATRACE_CALL(); sp listener; { Mutex::Autolock l(mOutputLock); listener = mListener.promote(); } switch (msg->type) { ... case CAMERA3_MSG_SHUTTER: { notifyShutter(msg->message.shutter, listener); break; } ... }}void Camera3Device::notifyShutter(const camera3_shutter_msg_t &msg, sp listener) { idx = mInFlightMap.indexOfKey(msg.frame_number); if (idx >= 0) { InFlightRequest &r = mInFlightMap.editValueAt(idx); ... r.shutterTimestamp = msg.timestamp; if (r.hasCallback) { // Call listener, if any if (listener != NULL) { /* CameraDeviceClient::notifyShutter() */ listener->notifyShutter(r.resultExtras, msg.timestamp); } // send pending result and buffers sendCaptureResult(r.pendingMetadata, r.resultExtras, r.collectedPartialResult, msg.frame_number, r.hasInputBuffer, r.physicalMetadatas); } returnOutputBuffers(r.pendingOutputBuffers.array(), r.pendingOutputBuffers.size(), r.shutterTimestamp); r.pendingOutputBuffers.clear(); removeInFlightRequestIfReadyLocked(idx);}
在 Camera3Device::notifyShutter() 中,将调用到 CameraDeviceClient::notifyShutter(),在该函数中,将会逐步经过 JAVA 层代码传递到 APP。
processCaptureResult()
在CameraProvider 中通过 processCaptureResult() 传递到CameraService 之后,最终将调用到以下函数:
/** * Camera HAL device callback methods */void Camera3Device::processCaptureResult(const camera3_capture_result *result) { /* 在该函数中,还是进行取帧号的操作,isPartialResult是指部分, * 目前对Partial的具体含义还不是很了解,可能的情况比如拍HDR,需要 * 采集三帧,三帧的FrameNumber相同,这三帧一起才能解析合成一帧图片, * 所以三帧中的每一帧就是Partial的意思了。(源自参考文章的理解) */ ... if (shutterTimestamp == 0) { request.pendingOutputBuffers.appendArray(result->output_buffers, result->num_output_buffers); } else { /* 在这里,将会返回buf到 Surface 进行显示 */ returnOutputBuffers(result->output_buffers, result->num_output_buffers, shutterTimestamp); } ... if (shutterTimestamp == 0) { request.pendingMetadata = result->result; request.collectedPartialResult = collectedPartialResult; } else if (request.hasCallback) { CameraMetadata metadata; metadata = result->result; /* 返回结果到 APP */ sendCaptureResult(metadata, request.resultExtras, collectedPartialResult, frameNumber, hasInputBufferInRequest, request.physicalMetadatas); }}
Camera3Device::returnOutputBuffers()
上面介绍到,在 Camera3Device::processCaptureResult() 中将调用到 returnOutputBuffers() 函数,而该函数的调用流程将如下:
Camera3Device::processCaptureResult() ---> stream->returnBuffer() Camera3Stream::returnBuffer() ---> returnBufferLocked() Camera3OutputStream::returnBufferLocked() ---> returnAnyBufferLocked( , , true) Camera3IOStreamBase::returnAnyBufferLocked() ---> returnBufferCheckedLocked() Camera3OutputStream::returnBufferCheckedLocked()
下面我们来看看 Camera3OutputStream::returnBufferCheckedLocked() 进行了什么操作。
status_t Camera3OutputStream::returnBufferCheckedLocked( const camera3_stream_buffer &buffer, nsecs_t timestamp, bool output, /*out*/ sp *releaseFenceOut) { ... /* 这个 mConsumer 是在创建 Camera3OutputStream 实例对象时传递进来的参数, * 而这个实例对象是在 Camera3Device::createStream() 时创建的,可以看看上面 * 的章节,mConsumer 是在创建流时传递下来的 Surface */ sp currentConsumer = mConsumer; mLock.unlock(); ANativeWindowBuffer *anwBuffer = container_of(buffer.buffer, ANativeWindowBuffer, handle); /** * Return buffer back to ANativeWindow */ ... } else { ... /* 将调用 queueBufferToConsumer() 归还 buffer,这时 * buffer 已经经过ISP HAL等处理、填充完毕,可以进行显示了 */ res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence); if (res != OK) { ALOGE("%s: Stream %d: Error queueing buffer to native window: " "%s (%d)", __FUNCTION__, mId, strerror(-res), res); } } ... return res;}status_t Camera3OutputStream::queueBufferToConsumer(sp& consumer, ANativeWindowBuffer* buffer, int anwReleaseFence) { /* 直接调用 ANativeWindow 对象的 queueBuffer 方法将 buffer 归还回去, * ANativeWindow 是 OpenGL 定义的图形接口,在 Android上 的实现就是 * Surface 和 SurfaceFlinger,一个用于生产 buffer ,一个用于消费 buffer */ return consumer->queueBuffer(consumer.get(), buffer, anwReleaseFence);}
这样在 queueBuffer() 之后,buffer 将可以通过 Surface 显示出来了。
Camera3Device::sendCaptureResult()
了解到显示buffer的填充之后,我们再来看看,CameraService 又是如何通过 sendCaptureResult() 告知 APP 的。
void Camera3Device::sendCaptureResult(CameraMetadata &pendingMetadata, CaptureResultExtras &resultExtras, CameraMetadata &collectedPartialResult, uint32_t frameNumber, bool reprocess, const std::vector& physicalMetadatas) { ... /* 在完成 captureResult 的填充之后,将会把结果通过 * insertResultLocked() 添加到 mResultQueue 队列中 */ insertResultLocked(&captureResult, frameNumber);}void Camera3Device::insertResultLocked(CaptureResult *result, uint32_t frameNumber) { ... // Valid result, insert into queue List::iterator queuedResult = mResultQueue.insert(mResultQueue.end(), CaptureResult(*result)); /* 添加完毕之后,发送信号 */ mResultSignal.signal();}
在 Camera3Device::insertResultLocked() 中的 mResultSignal 信号到底是发给谁呢?
通过搜索代码可以知道,在 FrameProcessorBase 帧处理线程中将会接收该信号。而帧处理线程是在 CameraDeviceClient 对象的 CameraDeviceClient::initializeImpl() 中启动的(open camera阶段调用到该函数)。
看看帧处理线程进行什么操作?
bool FrameProcessorBase::threadLoop() { status_t res; sp device; { device = mDevice.promote(); if (device == 0) return false; } /* 就是在这里等待 mResultSignal 信号 */ res = device->waitForNextFrame(kWaitDuration); if (res == OK) { /* 处理帧 */ processNewFrames(device); } ... return true;}void FrameProcessorBase::processNewFrames(const sp &device) { CaptureResult result; /* 读取队列中的 captureResult 信息 */ while ( (res = device->getNextResult(&result)) == OK) { ... if (!processSingleFrame(result, device)) { break; } ...}bool FrameProcessorBase::processSingleFrame(CaptureResult &result, const sp &device) { return processListeners(result, device) == OK;} status_t FrameProcessorBase::processListeners(const CaptureResult &result, const sp &device) { ... List > listeners; { /* 获取监听并添加到 listeners,mRangeListeners 是通过 * FrameProcessorBase::registerListener() 登记监听的, * 在 CameraDeviceClient::initializeImpl() 中创建 * FrameProcessorBase 实例时,将会把 CameraDeviceClient * 作为监听者进行注册登记到 mRangeListeners */ List::iterator item = mRangeListeners.begin(); while (item != mRangeListeners.end()) { ... listeners.push_back(listener); } } List >::iterator item = listeners.begin(); for (; item != listeners.end(); item++) { /* 针对监听者,将会调用 onResultAvailable(),这里将调 * 用到 CameraDeviceClient::onResultAvailable() */ (*item)->onResultAvailable(result); } return OK;} /** Device-related methods */void CameraDeviceClient::onResultAvailable(const CaptureResult& result) { /* 这里的 mRemoteCallback 就是在CameraService 创建 CameraDeviceClient * 实例时传递进来的 remoteCb,自然就是 Camera APP当中的成员了,它是 * CameraDeviceImpl 类的内部类CameraDeviceCallbacks对象 */ sp remoteCb = mRemoteCallback; if (remoteCb != NULL) { remoteCb->onResultReceived(result.mMetadata, result.mResultExtras, result.mPhysicalMetadatas); }}
上述的这个camera数据的流转,可以使用下图简单描述:
APP
上述已经说到,在 CameraDeviceClient::onResultAvailable() 中将会将结果返回到 CameraDeviceImpl 中,在这里不再详细的跟踪,粗略看了一下代码,主要也是 onCaptureCompleted() 回调函数,一路设置到APP进行操作。
关于APP怎么获取buffer数据,引用参考文章 Android 8.0系统源码分析–Camera processCaptureResult结果回传源码分析 的一段话作为解析。
我们来看一下回调回来的两个参数,分别是CameraMetadataNative、CaptureResultExtras类型,其中根本没有buffer数据,那我们怎么取预览或者拍照数据呢?这就是API2架构的修改了,API2的架构已经不像API1那样直接在回调接口中支持buffer数据的回调了,而我们要想取到预览或者拍照结果的buffer数据,可以通过ImageReader来实现,关于使用ImageReader获取预览和拍照的buffer数据的,网上有很多教程,这里就不讲了,大家可以自己去查,主要的重点就是将构造好的ImageReader的Surface通过createCaptureSession下发下去,然后重写OnImageAvailableListener类的onImageAvailable方法,当我们前面讲过的returnBuffer将buffer数据回填给Surface之后,显示系统就会回调onImageAvailable方法,我们就可以取到想要的buffer了。
至此,camera预览流程整理完成。
附上android camera官方网站模型图。
参考
Android 8.0系统源码分析–Camera processCaptureResult结果回传源码分析
更多相关文章
- C语言函数的递归(上)
- Android(安卓)启动过程分析--笔记缩减
- Android(安卓)View中的onMeasure()方法详解
- 如果我是Android面试官九
- Android(安卓)bionic缺失pthread_cancel的解决方法
- 一篇文章看明白 Android(安卓)Service 启动过程
- Android(安卓)init源代码分析(1)概要分析
- Android中的UI线程详解
- ubuntu 编译 Android(安卓)出现的若干错误及解决方法