Android 9.0 Camera学习笔记

0. Camera简单结构

在这里插入图片描述

1. CameraService模块启动流程

在这里插入图片描述
CameraService是NativeService, 所以随着init启动并加入到Native ServiceManager中。

1.5 Camera连接流程

在这里插入图片描述

openCamera说明:

  1. openCamera实质上是创建客户端(CameraDevice)和服务端的通信渠道,而CameraManager是操作入口。
  2. CameraDevice在创建的过程中,会打开并初始化Camera设备。
  3. APP后续的操作基本都是基于CameraDevice的接口在和服务端通信。

2. 相机startPreview流程图

在这里插入图片描述

- Camera的请求和响应处理流程

Camera FW和HAL3的请求和响应,还有数据交互都是基于Stream的(Camera3InputStream,Camera3OutputStream)

请求分为三大类:

  • Preview(预览)
  • Capture(拍照)
  • Recording(录像)

流程:

  1. Camera2Client 发起预览/拍照/录像请求;
  2. 创建(Preview/Capture/Recording)OutputStream(mSurface), 返回对应的streamId, 并记录在对应的Processor中;
  3. 创建(Preview/Capture/Recording)Request;
  4. 将需要请求数据的outputstream添加到request中;
  5. 初始化Request, 并最终加入到Request列表中;
  6. 在Camera3Device的threadLoop中处理所有的Request请求;
  7. 处理请求前, 从每个ouputstream中保存的surfaceProducer各自申请一块buffer(dequeueBuffer);
  8. 将buffer携带到request中, 然后发送携带了请求包含的所有outputstreams和每个stream对应的buffer到HAL3;
  9. HAL3收到并处理请求, 然后会填充camera获取的图象数据到携带的buffer, 并填充结果信息,并返回给Camera FW.
  10. Camera FW收到返回的内容之后, 获取到填充了图像信息的buffer和outputstream;
  11. 遍历所有outputStreams(请求时带给HAL的outputstreams),获取到每个outputstream中的surfaceProducer, 通过surfaceProducer将获取的buffer queueBuffer到图形队列BufferQueue中, 交给Consumer来处理;

- repeating原理:

Camera3Device::RequestThread::waitForNextRequestBatch()

void Camera3Device::RequestThread::waitForNextRequestBatch() {
    ATRACE_CALL();
    // Optimized a bit for the simple steady-state case (single repeating
    // request), to avoid putting that request in the queue temporarily.
    Mutex::Autolock l(mRequestLock);

    assert(mNextRequests.empty());

    NextRequest nextRequest;
    //获取下一个请求(先只获取一个)
    nextRequest.captureRequest = waitForNextRequestLocked();
    if (nextRequest.captureRequest == nullptr) {
    	//请求队列和repeating类型的请求都没有
        return;
    }

    nextRequest.halRequest = camera3_capture_request_t();
    nextRequest.submitted = false;
    mNextRequests.add(nextRequest);

    // Wait for additional requests
    //当前要是支持批量请求的发送方式,则继续获取下一个请求
    //(注意:repeatingRequest最多只会获取一个,当队列不为空时, 将不会再获取
    //repeating请求,所以上面已经有一个请求(不管是不是repeating请求),这类都不会再获
    //取repeating请求, 二十从队列中获取其他类型的请求, 比如capture)
    const size_t batchSize = nextRequest.captureRequest->mBatchSize;

	//获取到camera HAL设备支持的最大批量数量的请求。
    for (size_t i = 1; i < batchSize; i++) {
        NextRequest additionalRequest;
        additionalRequest.captureRequest = waitForNextRequestLocked();
        if (additionalRequest.captureRequest == nullptr) {
            break;
        }

        additionalRequest.halRequest = camera3_capture_request_t();
        additionalRequest.submitted = false;
        mNextRequests.add(additionalRequest);
    }

    if (mNextRequests.size() < batchSize) {
        ALOGE("RequestThread: only get %zu out of %zu requests. Skipping requests.",
                mNextRequests.size(), batchSize);
        cleanUpFailedRequests(/*sendRequestError*/true);
    }

    return;
}


sp<Camera3Device::CaptureRequest>
        Camera3Device::RequestThread::waitForNextRequestLocked() {
    status_t res;
    sp<CaptureRequest> nextRequest;

	//注意 这里当队列为空的时候,才回去尝试获取repeating请求,获取不到说明
	//当前没有任何请求可以获取,则阻塞等待;
    while (mRequestQueue.empty()) {
        if (!mRepeatingRequests.empty()) {
        //请求队列为空,但是mRepeatingRequests不为空,尝试获取repeating request;
            // Always atomically enqueue all requests in a repeating request
            // list. Guarantees a complete in-sequence set of captures to
            // application.
            const RequestList &requests = mRepeatingRequests;
            RequestList::const_iterator firstRequest =
                    requests.begin();//获取一个repeating request;
            nextRequest = *firstRequest;
            //插入到请求队列中
            mRequestQueue.insert(mRequestQueue.end(),
                    ++firstRequest,
                    requests.end());
            // No need to wait any longer

            mRepeatingLastFrameNumber = mFrameNumber + requests.size() - 1;
            //获取到请求之后, 跳出
            break;
        }

		//没有获取到任何请求, 阻塞等待新的请求到来;
        res = mRequestSignal.waitRelative(mRequestLock, kRequestTimeout);

        if ((mRequestQueue.empty() && mRepeatingRequests.empty()) ||
                exitPending()) {
            Mutex::Autolock pl(mPauseLock);
            if (mPaused == false) {
                ALOGV("%s: RequestThread: Going idle", __FUNCTION__);
                mPaused = true;
                // Let the tracker know
                sp<StatusTracker> statusTracker = mStatusTracker.promote();
                if (statusTracker != 0) {
                    statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE);
                }
            }
            // Stop waiting for now and let thread management happen
            return NULL;
        }
    }

    if (nextRequest == NULL) {
    //没有获取到repeating请求
        // Don't have a repeating request already in hand, so queue
        // must have an entry now.
        //从请求队列中获取新的请求
        RequestList::iterator firstRequest =
                mRequestQueue.begin();
        nextRequest = *firstRequest;
        mRequestQueue.erase(firstRequest);
        if (mRequestQueue.empty() && !nextRequest->mRepeating) {
            sp<NotificationListener> listener = mListener.promote();
            if (listener != NULL) {
                listener->notifyRequestQueueEmpty();
            }
        }
    }

    // In case we've been unpaused by setPaused clearing mDoPause, need to
    // update internal pause state (capture/setRepeatingRequest unpause
    // directly).
    Mutex::Autolock pl(mPauseLock);
    if (mPaused) {
        ALOGV("%s: RequestThread: Unpaused", __FUNCTION__);
        sp<StatusTracker> statusTracker = mStatusTracker.promote();
        if (statusTracker != 0) {
            statusTracker->markComponentActive(mStatusId);
        }
    }
    mPaused = false;

    // Check if we've reconfigured since last time, and reset the preview
    // request if so. Can't use 'NULL request == repeat' across configure calls.
    if (mReconfigured) {
        mPrevRequest.clear();
        mReconfigured = false;
    }

    if (nextRequest != NULL) {
        nextRequest->mResultExtras.frameNumber = mFrameNumber++;
        nextRequest->mResultExtras.afTriggerId = mCurrentAfTriggerId;
        nextRequest->mResultExtras.precaptureTriggerId = mCurrentPreCaptureTriggerId;

        // Since RequestThread::clear() removes buffers from the input stream,
        // get the right buffer here before unlocking mRequestLock
        if (nextRequest->mInputStream != NULL) {
            res = nextRequest->mInputStream->getInputBuffer(&nextRequest->mInputBuffer);
            if (res != OK) {
                // Can't get input buffer from gralloc queue - this could be due to
                // disconnected queue or other producer misbehavior, so not a fatal
                // error
                ALOGE("%s: Can't get input buffer, skipping request:"
                        " %s (%d)", __FUNCTION__, strerror(-res), res);

                sp<NotificationListener> listener = mListener.promote();
                if (listener != NULL) {
                    listener->notifyError(
                            hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
                            nextRequest->mResultExtras);
                }
                return NULL;
            }
        }
    }

    return nextRequest; //最后返回获取到的请求
}

- 注意

  1. CallbackProcessor和JpegProcessor 的Consumer是CpuConsumer, 注册的FrameAvailableListener是自己, 所以queueBuffer之后, 回调响应是自己的onFrameAvailable函数。
  2. CpuConsumer的lockNextBuffer(&buffer)可以获取到来自produser queue的buffer.
    • JpegProcessor 收到的图象buffer最终在CaptureSequencer中处理.
    • CaptureSequencer是一个状态机模型, 每个状态函数的返回值代表了要转移的状态.
  3. 最终完成拍照数据获取,是在CaptureSequencer::manageDone函数.

3. Camera2 录像流程图

Camera2 的录像使用的是Camera2 API_1 的接口
在这里插入图片描述


4. Camera2 API_2 从CameraActivity初始化到Camera preview的流程

Camera2 preview流程使用的是Camera2 API_2 的接口
在这里插入图片描述开始预览流程
在这里插入图片描述


5. Camera2 takePicture代码流程

在这里插入图片描述

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值