[Android P] CameraAPI1 轉 HAL3 預覽流程(三) — setPreviewCallbackFlag

系列文章

總覽

注意一下,雖然題目主要寫的是 setPreviewCallbackFlag,但實際上這對於 Camera 應用,它的動作是調用 API1 的 setPreviewCallbackWithBufferaddCallbackBuffer,這樣會把 Preview Callback 的 Buffer 模式設置爲手動模式(由 APP 主動帶 Callback Buffer 下來,底層數據回來後會被 Copy 到這塊 APP Buffer 中)。

本篇文章對這一部分進行的時序分析,有幾個前提條件:

  1. APP 先調用了 startPreview
  2. 緊隨其後的是調用 addCallbackBuffer 帶下 Buffer;
  3. 然後調用了 setPreviewCallbackWithBuffer,該接口設置 manualModetrue,標誌 APP 自主帶下 Callback Buffer;
  4. 第三點會觸發第一次 setPreviewCallbackFlag(0x05)

需要注意的幾個點:

  1. 由於 Callback 是單獨的一路 stream,所以這裏相當於是要打開第二路 stream,會觸發 re-configure 機制
  2. configureStream 的邏輯是在 CallbackProcessor 中 updateStream 期間觸發的,注意這裏的時機區別於 startPreviewstartStream

setPreviewCallbackFlag

主要涉及到的類及其對應的代碼地址分別是:

  1. Camera-JNI/frameworks/base/core/jni/android_hardware_Camera.cpp
  2. Camera2Client/frameworks/av/services/camera/libcameraservice/api1/Camera2Client.cpp
  3. StreamingProcessor/frameworks/av/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
  4. CallbackProcessor/frameworks/av/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
  5. Camera3Device/frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

接下來我會照着上面的時序圖,結合具體代碼進行更深入一些的解釋。

代碼分析

根據時序圖來看,可以分成三個部分來看:

  1. Camera2Client 中的 setPreviewCallbackFlag
  2. CallBackProcessor 中的 updateStream;
  3. StreamingProcessor 中的 startStream

setPreviewCallbackFlag 相關內容

需要注意的是:

  1. 從時序上看,通常 APP 會先調用到 addCallbackBuffer,這會使得 JNI 這邊有至少一個 Callback Buffer 存在;
  2. setPreviewCallbackWithBuffer 會調用到 setHasPreviewCallback 這一 native 方法,傳下去的 manualBuffer 參數值是 true。

所以接下來從 JNI 部分開始看起。

Camera-JNI::addCallbackBuffer

這個函數主要關注第 8~23 行:

  1. 第 10 行,把 APP 送下來的 Buffer 放到向量中,此時 size 增加
  2. 第 18 行,由於此時 mManualBufferMode 處於初始的 false 狀態,所以該分支就此結束。
void JNICameraContext::addCallbackBuffer(
        JNIEnv *env, jbyteArray cbb, int msgType)
{
    ALOGV("addCallbackBuffer: 0x%x", msgType);
    if (cbb != NULL) {
        Mutex::Autolock _l(mLock);
        switch (msgType) {
            case CAMERA_MSG_PREVIEW_FRAME: {
                jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
                mCallbackBuffers.push(callbackBuffer);

                ALOGV("Adding callback buffer to queue, %zu total",
                        mCallbackBuffers.size());

                // We want to make sure the camera knows we're ready for the
                // next frame. This may have come unset had we not had a
                // callbackbuffer ready for it last time.
                if (mManualBufferMode && !mManualCameraCallbackSet) {
                    mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_CAMERA);
                    mManualCameraCallbackSet = true;
                }
                break;
            }
            case CAMERA_MSG_RAW_IMAGE: {
                jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
                mRawImageCallbackBuffers.push(callbackBuffer);
                break;
            }
            default: {
                jniThrowException(env,
                        "java/lang/IllegalArgumentException",
                        "Unsupported message type");
                return;
            }
        }
    } else {
       ALOGE("Null byte array!");
    }
}

Camera-JNI::setHasPreviewCallback

這個函數主要因調用 setPreviewCallbackWithBuffer 接口而觸發,該接口可以在 Camera.java 看到,這裏不多做解釋。

它主要是繼續調用 JNI 裏的 setCallbackMode 函數(第 13 行),注意 manualBuffer 這一參數值爲 true

static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean manualBuffer)
{
    ALOGV("setHasPreviewCallback: installed:%d, manualBuffer:%d", (int)installed, (int)manualBuffer);
    // Important: Only install preview_callback if the Java code has called
    // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy
    // each preview frame for nothing.
    JNICameraContext* context;
    sp<Camera> camera = get_native_camera(env, thiz, &context);
    if (camera == 0) return;

    // setCallbackMode will take care of setting the context flags and calling
    // camera->setPreviewCallbackFlags within a mutex for us.
    context->setCallbackMode(env, installed, manualBuffer);
}

Camera-JNI::setCallbackMode

關於這個函數需要注意的:

  1. 第 4 行,mManualBufferMode 被設置爲 true
  2. 第 17~21 行,由於之前調用了 addCallbackBuffer,此時 mCallbackBuffers 非空,於是會調用到 setPreviewCallbackFlags注意傳入的參數是 CAMERA_FRAME_CALLBACK_FLAG_CAMERA,可以查到這個宏定義對應的數值是 0x05
  3. 注意下第 20 行,把 mManualCameraCallbackSet 設置爲 true
void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualMode)
{
    Mutex::Autolock _l(mLock);
    mManualBufferMode = manualMode;
    mManualCameraCallbackSet = false;

    // In order to limit the over usage of binder threads, all non-manual buffer
    // callbacks use CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now.
    //
    // Continuous callbacks will have the callback re-registered from handleMessage.
    // Manual buffer mode will operate as fast as possible, relying on the finite supply
    // of buffers for throttling.

    if (!installed) {
        mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
        clearCallbackBuffers_l(env, &mCallbackBuffers);
    } else if (mManualBufferMode) {
        if (!mCallbackBuffers.isEmpty()) {
            mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_CAMERA);
            mManualCameraCallbackSet = true;
        }
    } else {
        mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER);
        clearCallbackBuffers_l(env, &mCallbackBuffers);
    }
}

Camera2Client::setPreviewCallbackFlag

看到這你可能會奇怪,前面調用的是 setPreviewCallbackFlags,怎麼這裏就到了 setPreviewCallbackFlag(缺了一個字母 s)。這裏是因爲我省略了 Camera.cpp 的內容,有興趣可以去看看。

回到正題,這個函數只是個入口,主要是第 9 行進入正題。

void Camera2Client::setPreviewCallbackFlag(int flag) {
    ATRACE_CALL();
    ALOGV("%s: Camera %d: Flag 0x%x", __FUNCTION__, mCameraId, flag);
    Mutex::Autolock icl(mBinderSerializationLock);

    if ( checkPid(__FUNCTION__) != OK) return;

    SharedParameters::Lock l(mParameters);
    setPreviewCallbackFlagL(l.mParameters, flag);
}

Camera2Client::setPreviewCallbackFlagL

該函數主要邏輯如下:

  1. 第 4~17 行,由於前面已經 startPreview 過,此處 state 爲 PREVIEW 狀態(即走第 7 行的分支,直接離開 switch);
  2. 第 21 行,之前的 previewCallbackFlags 還是默認的 0x00,此處 flag 帶下來 0x05 這個值,於是走入這個分支;
  3. 第 25 行,更新 previewCallbackFlags 值爲 0x05
  4. 第 28 行,再次進入 startPreviewL 流程,注意這次 restart 參數值是 true
void Camera2Client::setPreviewCallbackFlagL(Parameters &params, int flag) {
    status_t res = OK;

    switch(params.state) {
        case Parameters::STOPPED:
        case Parameters::WAITING_FOR_PREVIEW_WINDOW:
        case Parameters::PREVIEW:
        case Parameters::STILL_CAPTURE:
            // OK
            break;
        default:
            if (flag & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) {
                ALOGE("%s: Camera %d: Can't use preview callbacks "
                        "in state %d", __FUNCTION__, mCameraId, params.state);
                return;
            }
    }
    
    // NOTE: N Lines are omitted here
    
    if (params.previewCallbackFlags != (uint32_t)flag) {

        // NOTE: N Lines are omitted here

        params.previewCallbackFlags = flag;

        if (params.state == Parameters::PREVIEW) {
            res = startPreviewL(params, true);
            if (res != OK) {
                ALOGE("%s: Camera %d: Unable to refresh request in state %s",
                        __FUNCTION__, mCameraId,
                        Parameters::getStateName(params.state));
            }
        }
    }
}

Camera2Client::startPreviewL

該函數主要邏輯如下:

  1. 第 4 行,將 state 設置爲 STOPPED
  2. 第 5~14 行,由於已經 startPreview 過, 這裏能拿到當前 preview stream 的 ID,相關邏輯需要關注的信息不多,就不深入去看了;
  3. 第 19 行,由於 params.previewCallbackFlags 是 0x05,這裏的 callbacksEnabled 被設置爲 true
  4. 第 26 行,調用到 CallbackProcessor 的 updateStream,此處就是後續關注的重點了,由於需要新的這一路 callback stream,此處會有相關的創建新 stream 的邏輯,包括觸發 re-config 動作
  5. 第 32 行,callback stream 準備好後,加入到 output buffer 集合中;
  6. 第 44 行,將 preview stream 加入到 output buffer 集合中;
  7. 第 58 行,這次的 startStream 就不會觸發 configureStream 的動作了,需要注意的是它會調用到 setRepeatingRequests
  8. 第 65 行,將 state 恢復爲 PREVIEW
status_t Camera2Client::startPreviewL(Parameters &params, bool restart) {
    // NOTE: N Lines are omitted here

    params.state = Parameters::STOPPED;
    int lastPreviewStreamId = mStreamingProcessor->getPreviewStreamId();

    res = mStreamingProcessor->updatePreviewStream(params);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to update preview stream: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        return res;
    }

    bool previewStreamChanged = mStreamingProcessor->getPreviewStreamId() != lastPreviewStreamId;

    // NOTE: N Lines are omitted here

    Vector<int32_t> outputStreams;
    bool callbacksEnabled = (params.previewCallbackFlags &
            CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) ||
            params.previewCallbackSurface;

    if (callbacksEnabled) {
        // NOTE: N Lines are omitted here

        res = mCallbackProcessor->updateStream(params);
        if (res != OK) {
            ALOGE("%s: Camera %d: Unable to update callback stream: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }
        outputStreams.push(getCallbackStreamId());
    } else if (previewStreamChanged && mCallbackProcessor->getStreamId() != NO_STREAM) {
        // NOTE: N Lines are omitted here
    }

    if (params.useZeroShutterLag() &&
            getRecordingStreamId() == NO_STREAM) {
        // NOTE: N Lines are omitted here
    } else {
        mZslProcessor->deleteStream();
    }

    outputStreams.push(getPreviewStreamId());

    // NOTE: N Lines are omitted here

    if (!params.recordingHint) {
        if (!restart) {
            res = mStreamingProcessor->updatePreviewRequest(params);
            if (res != OK) {
                ALOGE("%s: Camera %d: Can't set up preview request: "
                        "%s (%d)", __FUNCTION__, mCameraId,
                        strerror(-res), res);
                return res;
            }
        }
        res = mStreamingProcessor->startStream(StreamingProcessor::PREVIEW,
                outputStreams);
    } else {
        // NOTE: N Lines are omitted here
    }
    // NOTE: N Lines are omitted here

    params.state = Parameters::PREVIEW;
    return OK;
}

updateStream 相關內容

這裏主要就是更新一個 callback stream,觸發 re-config 動作。

CallbackProcessor::updateStream

此處邏輯如下:

  1. 第 4~14 行,創建 BufferQueue,並進行相應的配置。這裏面需要注意一下 Consumer 這個類,它與後續接收 callback buffer,觸發 onFrameAvailable 回調密切相關,但由於此處關係略複雜,就不深入去分析了,有興趣可以自己看看;
  2. 第 22 行,由於當前無 callback stream,所以需要新創建一個。
status_t CallbackProcessor::updateStream(const Parameters &params) {
    // NOTE: N Lines are omitted here

    if (!mCallbackToApp && mCallbackConsumer == 0) {
        // Create CPU buffer queue endpoint, since app hasn't given us one
        // Make it async to avoid disconnect deadlocks
        sp<IGraphicBufferProducer> producer;
        sp<IGraphicBufferConsumer> consumer;
        BufferQueue::createBufferQueue(&producer, &consumer);
        mCallbackConsumer = new CpuConsumer(consumer, kCallbackHeapCount);
        mCallbackConsumer->setFrameAvailableListener(this);
        mCallbackConsumer->setName(String8("Camera2-CallbackConsumer"));
        mCallbackWindow = new Surface(producer);
    }

    // NOTE: N Lines are omitted here

    if (mCallbackStreamId == NO_STREAM) {
        ALOGV("Creating callback stream: %d x %d, format 0x%x, API format 0x%x",
                params.previewWidth, params.previewHeight,
                callbackFormat, params.previewFormat);
        res = device->createStream(mCallbackWindow,
                params.previewWidth, params.previewHeight, callbackFormat,
                HAL_DATASPACE_V0_JFIF, CAMERA3_STREAM_ROTATION_0, &mCallbackStreamId,
                String8());
        if (res != OK) {
            ALOGE("%s: Camera %d: Can't create output stream for callbacks: "
                    "%s (%d)", __FUNCTION__, mId,
                    strerror(-res), res);
            return res;
        }
    }

    return OK;
}

Camera3Device::createStream

實際上 createStream 有兩個,這裏只看最後執行的那一個:

  1. 第 8 行,注意 wasActive 初始值是 false
  2. 第 21~29 行,當前 mStatus 是 STATUS_ACTIVE在第 23 行會把 RequestThread 暫停,等待到 STATUS_CONFIGURED,至於爲什麼會有這樣的轉變,與 StatusTracker 有關,有興趣可以再深入看看,這裏先忽略該細節。第 28 行將 wasActive 改爲 true
  3. 第 49 行,創建用於 preview callback 的 stream;
  4. 第 54~64 行,根據 consumer 個數將 callback stream 中的各 Surface ID 找出來,通過參數 surfaceIds 返回;
  5. 第 70 行,將 callback stream 加入到 Camera3Device 的成員 mOutputStreams 中,這是一個 StreamSet,這裏需要注意的是,要和 Camera3Device::CaptureRequest 類的成員 mOutputStreams 區別開來,不是同一個東西
  6. 第 80~90 行,由於 wasActive 爲 true,走入該 if 分支中,並在第 83 行調用了 configureStreamsLocked,這裏面就會觸發 re-config 情況。注意第 89 行的函數會把 Pause 住的 RequestThread 重新開起來。
status_t Camera3Device::createStream(const std::vector<sp<Surface>>& 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<int> *surfaceIds, int streamSetId, bool isShared, uint64_t consumerUsage) {
    // NOTE: N Lines are omitted here
    
    bool wasActive = false;

    switch (mStatus) {
        case STATUS_ERROR:
            CLOGE("Device has encountered a serious error");
            return INVALID_OPERATION;
        case STATUS_UNINITIALIZED:
            CLOGE("Device not initialized");
            return INVALID_OPERATION;
        case STATUS_UNCONFIGURED:
        case STATUS_CONFIGURED:
            // OK
            break;
        case STATUS_ACTIVE:
            ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__);
            res = internalPauseAndWaitLocked(maxExpectedDuration);
            if (res != OK) {
                SET_ERR_L("Can't pause captures to reconfigure streams!");
                return res;
            }
            wasActive = true;
            break;
        default:
            SET_ERR_L("Unexpected status: %d", mStatus);
            return INVALID_OPERATION;
    }
    assert(mStatus != STATUS_ACTIVE);

    sp<Camera3OutputStream> newStream;

    // NOTE: N Lines are omitted here

    if (format == HAL_PIXEL_FORMAT_BLOB) {
        // NOTE: N Lines are omitted here
    } else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
        // NOTE: N Lines are omitted here
    } else if (isShared) {
        // NOTE: N Lines are omitted here
    } else if (consumers.size() == 0 && hasDeferredConsumer) {
        // NOTE: N Lines are omitted here
    } else {
        newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
                width, height, format, dataSpace, rotation,
                mTimestampOffset, physicalCameraId, streamSetId);
    }

    size_t consumerCount = consumers.size();
    for (size_t i = 0; i < consumerCount; i++) {
        int id = newStream->getSurfaceId(consumers[i]);
        if (id < 0) {
            SET_ERR_L("Invalid surface id");
            return BAD_VALUE;
        }
        if (surfaceIds != nullptr) {
            surfaceIds->push_back(id);
        }
    }

    newStream->setStatusTracker(mStatusTracker);

    newStream->setBufferManager(mBufferManager);

    res = mOutputStreams.add(mNextStreamId, newStream);
    if (res < 0) {
        SET_ERR_L("Can't add new stream to set: %s (%d)", strerror(-res), res);
        return res;
    }

    *id = mNextStreamId++;
    mNeedConfig = true;

    // Continue captures if active at start
    if (wasActive) {
        ALOGV("%s: Restarting activity to reconfigure streams", __FUNCTION__);
        // Reuse current operating mode and session parameters for new stream config
        res = configureStreamsLocked(mOperatingMode, mSessionParams);
        if (res != OK) {
            CLOGE("Can't reconfigure device for new stream %d: %s (%d)",
                    mNextStreamId, strerror(-res), res);
            return res;
        }
        internalResumeLocked();
    }
    ALOGV("Camera %s: Created new stream", mId.string());
    return OK;
}

Camera3Device::configureStreamsLocked

此處邏輯如下:

  1. 第 6 行,這裏要注意了,mStatus 在前面 createStream 的流程中已經被改成 STATUS_CONFIGURED 了,所以此處不會被 return,如果還是 STATUS_ACTIVE 的話這裏就觸發 return,就不會繼續 config 了;
  2. 第 13 行,createStream 裏面有設置 mNeedConfig 爲 true,所以此處不會觸發 return;
  3. 第 20 行,先停掉 PrepareThread 的 Loop;
  4. 第 24~50 行,主要是對每個 output stream 執行 startConfiguration 的動作;
  5. 第 58 行,通過 Camera3Device::HalInterface 實例,透過 HIDL 啓動 HAL 層的 configureStreams 流程
  6. 第 63~75 行,對應第 4 點,這裏是執行 finishConfiguration 動作;
  7. 第 85 行,mNeedConfig 設置爲 false
  8. 第 87 行,這裏會再次設置 mStatus 爲 STATUS_CONFIGURED
  9. 第 95 行,繼續 PrepareThread 的 Loop。
status_t Camera3Device::configureStreamsLocked(int operatingMode,
        const CameraMetadata& sessionParams, bool notifyRequestThread) {
    ATRACE_CALL();
    status_t res;

    if (mStatus != STATUS_UNCONFIGURED && mStatus != STATUS_CONFIGURED) {
        CLOGE("Not idle");
        return INVALID_OPERATION;
    }

    // NOTE: N Lines are omitted here

    if (!mNeedConfig) {
        ALOGV("%s: Skipping config, no stream changes", __FUNCTION__);
        return OK;
    }

    // NOTE: N Lines are omitted here

    mPreparerThread->pause();

    // NOTE: N Lines are omitted here

    for (size_t i = 0; i < mOutputStreams.size(); i++) {

        // Don't configure bidi streams twice, nor add them twice to the list
        if (mOutputStreams[i].get() ==
            static_cast<Camera3StreamInterface*>(mInputStream.get())) {

            config.num_streams--;
            continue;
        }

        camera3_stream_t *outputStream;
        outputStream = mOutputStreams.editValueAt(i)->startConfiguration();
        if (outputStream == NULL) {
            CLOGE("Can't start output stream configuration");
            cancelStreamsConfigurationLocked();
            return INVALID_OPERATION;
        }
        streams.add(outputStream);

        if (outputStream->format == HAL_PIXEL_FORMAT_BLOB &&
                outputStream->data_space == HAL_DATASPACE_V0_JFIF) {
            size_t k = i + ((mInputStream != nullptr) ? 1 : 0); // Input stream if present should
                                                                // always occupy the initial entry.
            bufferSizes[k] = static_cast<uint32_t>(
                    getJpegBufferSize(outputStream->width, outputStream->height));
        }
    }

    config.streams = streams.editArray();

    // Do the HAL configuration; will potentially touch stream
    // max_buffers, usage, priv fields.

    const camera_metadata_t *sessionBuffer = sessionParams.getAndLock();
    res = mInterface->configureStreams(sessionBuffer, &config, bufferSizes);
    sessionParams.unlock(sessionBuffer);

    // NOTE: N Lines are omitted here

    for (size_t i = 0; i < mOutputStreams.size(); i++) {
        sp<Camera3OutputStreamInterface> outputStream =
            mOutputStreams.editValueAt(i);
        if (outputStream->isConfiguring() && !outputStream->isConsumerConfigurationDeferred()) {
            res = outputStream->finishConfiguration();
            if (res != OK) {
                CLOGE("Can't finish configuring output stream %d: %s (%d)",
                        outputStream->getId(), strerror(-res), res);
                cancelStreamsConfigurationLocked();
                return BAD_VALUE;
            }
        }
    }

    // Request thread needs to know to avoid using repeat-last-settings protocol
    // across configure_streams() calls
    if (notifyRequestThread) {
        mRequestThread->configurationComplete(mIsConstrainedHighSpeedConfiguration, sessionParams);
    }

    // NOTE: N Lines are omitted here

    mNeedConfig = false;

    internalUpdateStatusLocked((mDummyStreamId == NO_STREAM) ?
            STATUS_CONFIGURED : STATUS_UNCONFIGURED);

    ALOGV("%s: Camera %s: Stream configuration complete", __FUNCTION__, mId.string());

    // tear down the deleted streams after configure streams.
    mDeletedStreams.clear();

    auto rc = mPreparerThread->resume();
    if (rc != OK) {
        SET_ERR_L("%s: Camera %s: Preparer thread failed to resume!", __FUNCTION__, mId.string());
        return rc;
    }

    return OK;
}

startStream 相關內容

這部分與 startPreview 流程比較重複,不過由於某些變量值不同,需要執行的邏輯少了許多。

StreamingProcessor::startStream

此處邏輯如下:

  1. 第 5~6 行,這裏拿到的是 mPreviewRequest;
  2. 第 8~10 行,更新 Request Metadata 裏的 output stream 參數,注意這裏傳入的 ouputStreams 的個數,會影響到 RequestThread 在 prepareHalRequest 時所準備的 buffer 個數;
  3. 第 14 行,將當前 request 更新到 Streaming 流程。
status_t StreamingProcessor::startStream(StreamType type,
        const Vector<int32_t> &outputStreams) {
    // NOTE: N Lines are omitted here

    CameraMetadata &request = (type == PREVIEW) ?
            mPreviewRequest : mRecordingRequest;

    res = request.update(
        ANDROID_REQUEST_OUTPUT_STREAMS,
        outputStreams);

    // NOTE: N Lines are omitted here

    res = device->setStreamingRequest(request);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to set preview request to start preview: "
                "%s (%d)",
                __FUNCTION__, mId, strerror(-res), res);
        return res;
    }
    mActiveRequest = type;
    mPaused = false;
    mActiveStreamIds = outputStreams;
    return OK;
}

Camera3Device::setStreamingRequest

這裏主要作用是轉換 request 的形式,並調用到 setStreamingRequestList

status_t Camera3Device::setStreamingRequest(const CameraMetadata &request,
                                            int64_t* /*lastFrameNumber*/) {
    ATRACE_CALL();

    List<const PhysicalCameraSettingsList> requestsList;
    std::list<const SurfaceMap> surfaceMaps;
    convertToRequestList(requestsList, surfaceMaps, request);

    return setStreamingRequestList(requestsList, /*surfaceMap*/surfaceMaps,
                                   /*lastFrameNumber*/NULL);
}

Camera3Device::setStreamingRequestList

此處主要是對接到 submitRequestsHelper

status_t Camera3Device::setStreamingRequestList(
        const List<const PhysicalCameraSettingsList> &requestsList,
        const std::list<const SurfaceMap> &surfaceMaps, int64_t *lastFrameNumber) {
    ATRACE_CALL();

    return submitRequestsHelper(requestsList, surfaceMaps, /*repeating*/true, lastFrameNumber);
}

Camera3Device::submitRequestsHelper

此處邏輯如下:

  1. 第 11 行,目的是獲取 RequestList,它是以 Camera3Device 內部定義的類 CaptureRequest 爲基礎的鏈表,此處還需要注意傳入的參數中 repeating 的值是 true
  2. 第 19 行,由於 repeating 爲 true,所以走了 setRepeatingRequest,這是 API2 啓預覽的接口;
  3. 第 25 行,注意傳入的 active 參數爲 true,會等待 mStatus 變成 STATUS_ACTIVE
status_t Camera3Device::submitRequestsHelper(
        const List<const PhysicalCameraSettingsList> &requests,
        const std::list<const SurfaceMap> &surfaceMaps,
        bool repeating,
        /*out*/
        int64_t *lastFrameNumber) {
    // NOTE: N Lines are omitted here

    RequestList requestList;

    res = convertMetadataListToRequestListLocked(requests, surfaceMaps,
            repeating, /*out*/&requestList);
    if (res != OK) {
        // error logged by previous call
        return res;
    }

    if (repeating) {
        res = mRequestThread->setRepeatingRequests(requestList, lastFrameNumber);
    } else {
        res = mRequestThread->queueRequestList(requestList, lastFrameNumber);
    }

    if (res == OK) {
        waitUntilStateThenRelock(/*active*/true, kActiveTimeout);
        if (res != OK) {
            SET_ERR_L("Can't transition to active in %f seconds!",
                    kActiveTimeout/1e9);
        }
        ALOGV("Camera %s: Capture request %" PRId32 " enqueued", mId.string(),
              (*(requestList.begin()))->mResultExtras.requestId);
    } else {
        CLOGE("Cannot queue request. Impossible.");
        return BAD_VALUE;
    }

    return res;
}

Camera3Device::convertMetadataListToRequestListLocked

此處比較關鍵的是第 16 行,目的是獲取 CaptureRequest 實例。

status_t Camera3Device::convertMetadataListToRequestListLocked(
        const List<const PhysicalCameraSettingsList> &metadataList,
        const std::list<const SurfaceMap> &surfaceMaps,
        bool repeating,
        RequestList *requestList) {
    if (requestList == NULL) {
        CLOGE("requestList cannot be NULL.");
        return BAD_VALUE;
    }

    int32_t burstId = 0;
    List<const PhysicalCameraSettingsList>::const_iterator metadataIt = metadataList.begin();
    std::list<const SurfaceMap>::const_iterator surfaceMapIt = surfaceMaps.begin();
    for (; metadataIt != metadataList.end() && surfaceMapIt != surfaceMaps.end();
            ++metadataIt, ++surfaceMapIt) {
        sp<CaptureRequest> newRequest = setUpRequestLocked(*metadataIt, *surfaceMapIt);
        if (newRequest == 0) {
            CLOGE("Can't create capture request");
            return BAD_VALUE;
        }

        newRequest->mRepeating = repeating;

        // NOTE: N Lines are omitted here

        requestList->push_back(newRequest);

        ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId);
    }
    // NOTE: N Lines are omitted here

    return OK;
}

Camera3Device::setUpRequestLocked

此處邏輯如下:

  1. 第 5 行,注意此處 mStatus 是 STATUS_CONFIGURED 並且 mNeedConfig 爲 false,所以這塊分支都不會走;
  2. 第 21 行,創建 CaptureRequest 實例,這裏面做的事和 startPreview 時一樣,就不贅述了。
sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked(
        const PhysicalCameraSettingsList &request, const SurfaceMap &surfaceMap) {
    status_t res;

    if (mStatus == STATUS_UNCONFIGURED || mNeedConfig) {
        // This point should only be reached via API1 (API2 must explicitly call configureStreams)
        // so unilaterally select normal operating mode.
        res = filterParamsAndConfigureLocked(request.begin()->metadata,
                CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE);
        // Stream configuration failed. Client might try other configuraitons.
        if (res != OK) {
            CLOGE("Can't set up streams: %s (%d)", strerror(-res), res);
            return NULL;
        } else if (mStatus == STATUS_UNCONFIGURED) {
            // Stream configuration successfully configure to empty stream configuration.
            CLOGE("No streams configured");
            return NULL;
        }
    }

    sp<CaptureRequest> newRequest = createCaptureRequest(request, surfaceMap);
    return newRequest;
}

Camera3Device::RequestThread::setRepeatingRequests

再次來到 setRepeatingRequests

  1. 第 10~11 行,這裏先清除了 mRepeatingRequests 裏的內容,把新創建的 CaptureRequest 加了進來;
  2. 第 14 行,此處會觸發一次 mRequestSignal 的 signal,會直接影響到 waitForNextRequestLocked
status_t Camera3Device::RequestThread::setRepeatingRequests(
        const RequestList &requests,
        /*out*/
        int64_t *lastFrameNumber) {
    ATRACE_CALL();
    Mutex::Autolock l(mRequestLock);
    if (lastFrameNumber != NULL) {
        *lastFrameNumber = mRepeatingLastFrameNumber;
    }
    mRepeatingRequests.clear();
    mRepeatingRequests.insert(mRepeatingRequests.begin(),
            requests.begin(), requests.end());

    unpauseForNewRequests();

    mRepeatingLastFrameNumber = hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES;
    return OK;
}

下集預告

這片文章主要介紹了 Android P 版本下,相機 APP 調用 Camera API1 的 startPreview 後,繼續調用 addCallbackBuffer 以及 setPreviewCallbackWithBuffer,Framework 層是轉換成 HAL3 的邏輯時序。

而下一篇文章將會介紹到,成功進入持續預覽狀態(兩路 stream,preview && callback)後,Framework 是如何持續下 Request 的,以及它收到對應的 Result 後,數據向 APP 流動的時序。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章