前面已经简单介绍了,在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,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结果回传源码分析

更多相关文章

  1. C语言函数的递归(上)
  2. Android(安卓)启动过程分析--笔记缩减
  3. Android(安卓)View中的onMeasure()方法详解
  4. 如果我是Android面试官九
  5. Android(安卓)bionic缺失pthread_cancel的解决方法
  6. 一篇文章看明白 Android(安卓)Service 启动过程
  7. Android(安卓)init源代码分析(1)概要分析
  8. Android中的UI线程详解
  9. ubuntu 编译 Android(安卓)出现的若干错误及解决方法

随机推荐

  1. 2021-03-17:手写代码:单链表插入排序。
  2. 3-17(排序)
  3. 时隔三年再更新!绝对良心工具,免费好用
  4. 3.17 c语言自定义函数
  5. Bug!Redis 6.0.8紧急发布,请尽快升级!
  6. 超赞!墙裂推荐一个 MySQL 自动化运维工具!
  7. 介绍一个可以离线查询 IP 来源和 ISP 信
  8. 史上首例!阿里程序员写的这三行代码,被国家
  9. 时间同步、双因子安全验证及自动化安装实
  10. 2021年全新永久有效Phpstorm激活码