文章目录

  • 1. CameraService模块启动流程
  • 2. 相机startPreview流程图
    • - Camera的请求和响应处理流程
    • - repeating原理:
    • - 注意
  • 3. Camera2 录像流程图
  • 4. Camera2 API_2 从CameraActivity初始化到Camera preview的流程
  • 5. Camera2 takePicture代码流程

1. CameraService模块启动流程


CameraService是NativeService, 所以随着init启动并加入到Native ServiceManager中。


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代码流程

更多相关文章

  1. android 如何定义全局变量
  2. Android(安卓)studio 设计简易的计算器
  3. [转]Android(安卓)获取当前Activity的屏幕截图
  4. 获取 Andorid 手机WIFI连接的Mac地址和IP地址
  5. 使用git工具获取android源代码
  6. android点击任意非EditText区域,隐藏键盘
  7. Android获取assets目录下的文件和图片
  8. OkHttp得拦截机制
  9. delphixe10 android操作 打电话,摄像头,定位等

随机推荐

  1. [linux]循序渐进学运维-基础命令篇-diff
  2. Linux中Navicat Premium连接MySQL报错:205
  3. 【linux】循序渐进学运维-用户管理篇
  4. [linux]循序渐进学运维-基础命令篇-文件
  5. 【linux】循序渐进学运维-基础篇-文件权
  6. 【linux】循序渐进学运维-基础篇-Linux系
  7. Linux下DNS正、反向解析报错:** server c
  8. 手机电脑文件自动同步
  9. 【linux】循序渐进学运维-基础篇-文件的
  10. css 实现中文繁体翻译 font-variant-ea