赞
踩
相机,从上到下概览一下,真是太大了,上面的APP->Framework->CameraServer->CameraHAL,HAL进程中Pipeline、接各种算法的Node、再往下的ISP、3A、Driver,真是太大了,想把它搞懂真不是个简单的事情。不过我们奔着要把它搞懂的目标,一点点的啃,弄懂一点少一点,我们的功力也在不断的前进中一步步的增强。
本节,我们就来看一下HAL层一帧处理完成,通过HIDL定义的接口processCaptureResult将数据回传的逻辑。我自己使用的Android8.0的系统源码是通过百度云盘分享的,大家可从Android 8.0系统源码分析--开篇中下载,百度云盘的下载链接和密码都有。
Camera系统也提供了非常多的dump方式,可以dump metadata、dump buffer,对我们分析问题都有非常大的帮助。
1、MTK系统中camera sensor的信息会通过kernal中imagesensor.c中的逻辑将所有camera sensor info写入到proc/driver/camera_info文件中,我们可以直接cat proc/driver/camera_info查看camera sensor的详细信息,其中记录了sensor类型,比如IMX386_mipi_raw;记录了sensor支持的分辨率大小,还有一些其他原始信息;
2、我们可以执行adb shell dumpsys media.camera > camerainfo.txt收集camera metadata信息,大家可以试一下,从这里可以轻易得到很多camera metadata信息;
3、android-8.0.0\system\media\camera\docs\docs.html文件中定义了AOSP所有的metadata,我们可以直接双击用浏览器打开它,就可以看到所有metadata,当然,每个SOC厂商肯定会自己新增一些,一般metadata的命名都是下划线拼接的,比如android.scaler.cropRegion,它的命名为ANDROID_SCALER_CROP_REGION,我们在HAL进程中就可以通过它去查询当前cropRegion的值。
4、Google提供的基于Camera API2 Demo地址:android-Camera2Basic(普通的预览拍照功能)、android-Camera2Video(录像功能)。
HIDL接口的定义有ICameraDevice.hal、ICameraDeviceSession.hal、ICameraDeviceCallback.hal,文件目录在hardware\interfaces\camera\device\xx目录下,xx为版本号,我所下载的源码有1.0和3.2两个版本,我们来看一下3.2版本下ICameraDeviceCallback.hal的定义,源码如下:
- package android.hardware.camera.device@3.2;
-
- import android.hardware.camera.common@1.0::types;
-
- /**
- *
- * Callback methods for the HAL to call into the framework.
- *
- * These methods are used to return metadata and image buffers for a completed
- * or failed captures, and to notify the framework of asynchronous events such
- * as errors.
- *
- * The framework must not call back into the HAL from within these callbacks,
- * and these calls must not block for extended periods.
- *
- */
- interface ICameraDeviceCallback {
-
- /**
- * processCaptureResult:
- *
- * Send results from one or more completed or partially completed captures
- * to the framework.
- * processCaptureResult() may be invoked multiple times by the HAL in
- * response to a single capture request. This allows, for example, the
- * metadata and low-resolution buffers to be returned in one call, and
- * post-processed JPEG buffers in a later call, once it is available. Each
- * call must include the frame number of the request it is returning
- * metadata or buffers for. Only one call to processCaptureResult
- * may be made at a time by the HAL although the calls may come from
- * different threads in the HAL.
- *
- * A component (buffer or metadata) of the complete result may only be
- * included in one process_capture_result call. A buffer for each stream,
- * and the result metadata, must be returned by the HAL for each request in
- * one of the processCaptureResult calls, even in case of errors producing
- * some of the output. A call to processCaptureResult() with neither
- * output buffers or result metadata is not allowed.
- *
- * The order of returning metadata and buffers for a single result does not
- * matter, but buffers for a given stream must be returned in FIFO order. So
- * the buffer for request 5 for stream A must always be returned before the
- * buffer for request 6 for stream A. This also applies to the result
- * metadata; the metadata for request 5 must be returned before the metadata
- * for request 6.
- *
- * However, different streams are independent of each other, so it is
- * acceptable and expected that the buffer for request 5 for stream A may be
- * returned after the buffer for request 6 for stream B is. And it is
- * acceptable that the result metadata for request 6 for stream B is
- * returned before the buffer for request 5 for stream A is. If multiple
- * capture results are included in a single call, camera framework must
- * process results sequentially from lower index to higher index, as if
- * these results were sent to camera framework one by one, from lower index
- * to higher index.
- *
- * The HAL retains ownership of result structure, which only needs to be
- * valid to access during this call.
- *
- * The output buffers do not need to be filled yet; the framework must wait
- * on the stream buffer release sync fence before reading the buffer
- * data. Therefore, this method should be called by the HAL as soon as
- * possible, even if some or all of the output buffers are still in
- * being filled. The HAL must include valid release sync fences into each
- * output_buffers stream buffer entry, or -1 if that stream buffer is
- * already filled.
- *
- * If the result buffer cannot be constructed for a request, the HAL must
- * return an empty metadata buffer, but still provide the output buffers and
- * their sync fences. In addition, notify() must be called with an
- * ERROR_RESULT message.
- *
- * If an output buffer cannot be filled, its status field must be set to
- * STATUS_ERROR. In addition, notify() must be called with a ERROR_BUFFER
- * message.
- *
- * If the entire capture has failed, then this method still needs to be
- * called to return the output buffers to the framework. All the buffer
- * statuses must be STATUS_ERROR, and the result metadata must be an
- * empty buffer. In addition, notify() must be called with a ERROR_REQUEST
- * message. In this case, individual ERROR_RESULT/ERROR_BUFFER messages
- * must not be sent.
- *
- * Performance requirements:
- *
- * This is a non-blocking call. The framework must handle each CaptureResult
- * within 5ms.
- *
- * The pipeline latency (see S7 for definition) should be less than or equal to
- * 4 frame intervals, and must be less than or equal to 8 frame intervals.
- *
- */
- processCaptureResult(vec<CaptureResult> results);
-
- /**
- * notify:
- *
- * Asynchronous notification callback from the HAL, fired for various
- * reasons. Only for information independent of frame capture, or that
- * require specific timing. Multiple messages may be sent in one call; a
- * message with a higher index must be considered to have occurred after a
- * message with a lower index.
- *
- * Multiple threads may call notify() simultaneously.
- *
- * Buffers delivered to the framework must not be dispatched to the
- * application layer until a start of exposure timestamp (or input image's
- * start of exposure timestamp for a reprocess request) has been received
- * via a SHUTTER notify() call. It is highly recommended to dispatch this
- * call as early as possible.
- *
- * ------------------------------------------------------------------------
- * Performance requirements:
- *
- * This is a non-blocking call. The framework must handle each message in 5ms.
- */
- notify(vec<NotifyMsg> msgs);
-
- };

看到这些大段大段的注释,就能明白,这些接口肯定都是非常重要的,详细的注释也是很好的习惯,看Android的源码感觉确实很舒服,难怪人家的代码能成为标准,不管是命名,格式,注释,分包,分类,所有的地方都让人感觉舒服!!
好了,进入到我们本节的主题吧,ICameraDeviceCallback是HIDL定义的回调接口,processCaptureResult方法就是从HAL层回调到CameraServer的接口,CameraServer这一侧的回调类就是Camera3Device,因为在openCamera时,构造出来的Camera3Device进行初始化,Camera3Device类的initialize方法中与HAL进行连接,获取session时,将自己作为callback回调类传递到了HAL,所以后续HAL就会回调到Camera3Device类的processCaptureResult方法当中。
我们再来回顾一下Camera3Device类的initialize方法,Camera3Device文件的目录路径为frameworks\av\services\camera\libcameraservice\device3\Camera3Device.cpp,initialize方法的源码如下:
- status_t Camera3Device::initialize(sp<CameraProviderManager> manager) {
- ATRACE_CALL();
- Mutex::Autolock il(mInterfaceLock);
- Mutex::Autolock l(mLock);
-
- ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.string());
- if (mStatus != STATUS_UNINITIALIZED) {
- CLOGE("Already initialized!");
- return INVALID_OPERATION;
- }
- if (manager == nullptr) return INVALID_OPERATION;
-
- sp<ICameraDeviceSession> session;
- ATRACE_BEGIN("CameraHal::openSession");
- status_t res = manager->openSession(mId.string(), this,
- /*out*/ &session);
- ATRACE_END();
- if (res != OK) {
- SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
- return res;
- }
-
- res = manager->getCameraCharacteristics(mId.string(), &mDeviceInfo);
- if (res != OK) {
- SET_ERR_L("Could not retrive camera characteristics: %s (%d)", strerror(-res), res);
- session->close();
- return res;
- }
-
- std::shared_ptr<RequestMetadataQueue> queue;
- auto requestQueueRet = session->getCaptureRequestMetadataQueue(
- [&queue](const auto& descriptor) {
- queue = std::make_shared<RequestMetadataQueue>(descriptor);
- if (!queue->isValid() || queue->availableToWrite() <= 0) {
- ALOGE("HAL returns empty request metadata fmq, not use it");
- queue = nullptr;
- // don't use the queue onwards.
- }
- });
- if (!requestQueueRet.isOk()) {
- ALOGE("Transaction error when getting request metadata fmq: %s, not use it",
- requestQueueRet.description().c_str());
- return DEAD_OBJECT;
- }
- auto resultQueueRet = session->getCaptureResultMetadataQueue(
- [&queue = mResultMetadataQueue](const auto& descriptor) {
- queue = std::make_unique<ResultMetadataQueue>(descriptor);
- if (!queue->isValid() || queue->availableToWrite() <= 0) {
- ALOGE("HAL returns empty result metadata fmq, not use it");
- queue = nullptr;
- // Don't use the queue onwards.
- }
- });
- if (!resultQueueRet.isOk()) {
- ALOGE("Transaction error when getting result metadata queue from camera session: %s",
- resultQueueRet.description().c_str());
- return DEAD_OBJECT;
- }
-
- mInterface = std::make_unique<HalInterface>(session, queue);
- std::string providerType;
- mVendorTagId = manager->getProviderTagIdLocked(mId.string());
-
- return initializeCommonLocked();
- }

该方法中就是调用manager->openSession(mId.string(), this, /*out*/ &session)来打开session的,manager是方法入参sp<CameraProviderManager>,调用openSession方法的第二个参数就是回调接口,传值为this,第三个是输出参数,当session在HAL进程中创建成功,则会通过回调赋值给这个输出参数。进一步来看一下CameraProviderManager类的openSession方法的实现,源码如下:
- status_t CameraProviderManager::openSession(const std::string &id,
- const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback,
- /*out*/
- sp<hardware::camera::device::V3_2::ICameraDeviceSession> *session) {
-
- std::lock_guard<std::mutex> lock(mInterfaceMutex);
-
- auto deviceInfo = findDeviceInfoLocked(id,
- /*minVersion*/ {3,0}, /*maxVersion*/ {4,0});
- if (deviceInfo == nullptr) return NAME_NOT_FOUND;
-
- auto *deviceInfo3 = static_cast<ProviderInfo::DeviceInfo3*>(deviceInfo);
-
- Status status;
- hardware::Return<void> ret;
- ret = deviceInfo3->mInterface->open(callback, [&status, &session]
- (Status s, const sp<device::V3_2::ICameraDeviceSession>& cameraSession) {
- status = s;
- if (status == Status::OK) {
- *session = cameraSession;
- }
- });
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error opening a session for camera device %s: %s",
- __FUNCTION__, id.c_str(), ret.description().c_str());
- return DEAD_OBJECT;
- }
- return mapToStatusT(status);
- }

这里的deviceInfo3->mInterface->open就会通过HIDL进入到CameraHalServer进程当中了。
好,回过头来看Camera3Device类的processCaptureResult方法,源码如下:
- // Only one processCaptureResult should be called at a time, so
- // the locks won't block. The locks are present here simply to enforce this.
- hardware::Return<void> Camera3Device::processCaptureResult(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::CaptureResult>& results) {
-
- if (mProcessCaptureResultLock.tryLock() != OK) {
- // This should never happen; it indicates a wrong client implementation
- // that doesn't follow the contract. But, we can be tolerant here.
- ALOGE("%s: callback overlapped! waiting 1s...",
- __FUNCTION__);
- if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
- ALOGE("%s: cannot acquire lock in 1s, dropping results",
- __FUNCTION__);
- // really don't know what to do, so bail out.
- return hardware::Void();
- }
- }
- for (const auto& result : results) {
- processOneCaptureResultLocked(result);
- }
- mProcessCaptureResultLock.unlock();
- return hardware::Void();
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。