系列文章
- [Android P] CameraAPI1 轉 HAL3 預覽流程(一) — 背景概述
- [Android P] CameraAPI1 轉 HAL3 預覽流程(二) — startPreview
- [Android P] CameraAPI1 轉 HAL3 預覽流程(三) — setPreviewCallbackFlag
- [Android P] CameraAPI1 轉 HAL3 預覽流程(四) — Preview Data
總覽
注意一下,雖然題目主要寫的是 setPreviewCallbackFlag
,但實際上這對於 Camera 應用,它的動作是調用 API1 的 setPreviewCallbackWithBuffer
和 addCallbackBuffer
,這樣會把 Preview Callback 的 Buffer 模式設置爲手動模式(由 APP 主動帶 Callback Buffer 下來,底層數據回來後會被 Copy 到這塊 APP Buffer 中)。
本篇文章對這一部分進行的時序分析,有幾個前提條件:
- APP 先調用了
startPreview
; - 緊隨其後的是調用
addCallbackBuffer
帶下 Buffer; - 然後調用了
setPreviewCallbackWithBuffer
,該接口設置 manualMode 爲 true,標誌 APP 自主帶下 Callback Buffer; - 第三點會觸發第一次
setPreviewCallbackFlag(0x05)
。
需要注意的幾個點:
- 由於 Callback 是單獨的一路 stream,所以這裏相當於是要打開第二路 stream,會觸發 re-configure 機制;
- configureStream 的邏輯是在 CallbackProcessor 中
updateStream
期間觸發的,注意這裏的時機區別於startPreview
的startStream
。
主要涉及到的類及其對應的代碼地址分別是:
- Camera-JNI:
/frameworks/base/core/jni/android_hardware_Camera.cpp
- Camera2Client:
/frameworks/av/services/camera/libcameraservice/api1/Camera2Client.cpp
- StreamingProcessor:
/frameworks/av/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
- CallbackProcessor:
/frameworks/av/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
- Camera3Device:
/frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
接下來我會照着上面的時序圖,結合具體代碼進行更深入一些的解釋。
代碼分析
根據時序圖來看,可以分成三個部分來看:
- Camera2Client 中的
setPreviewCallbackFlag
; - CallBackProcessor 中的
updateStream
; - StreamingProcessor 中的
startStream
;
setPreviewCallbackFlag 相關內容
需要注意的是:
- 從時序上看,通常 APP 會先調用到
addCallbackBuffer
,這會使得 JNI 這邊有至少一個 Callback Buffer 存在; setPreviewCallbackWithBuffer
會調用到setHasPreviewCallback
這一 native 方法,傳下去的 manualBuffer 參數值是 true。
所以接下來從 JNI 部分開始看起。
Camera-JNI::addCallbackBuffer
這個函數主要關注第 8~23 行:
- 第 10 行,把 APP 送下來的 Buffer 放到向量中,此時 size 增加;
- 第 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
關於這個函數需要注意的:
- 第 4 行,mManualBufferMode 被設置爲 true;
- 第 17~21 行,由於之前調用了
addCallbackBuffer
,此時 mCallbackBuffers 非空,於是會調用到setPreviewCallbackFlags
,注意傳入的參數是 CAMERA_FRAME_CALLBACK_FLAG_CAMERA,可以查到這個宏定義對應的數值是 0x05; - 注意下第 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
該函數主要邏輯如下:
- 第 4~17 行,由於前面已經
startPreview
過,此處 state 爲 PREVIEW 狀態(即走第 7 行的分支,直接離開 switch); - 第 21 行,之前的 previewCallbackFlags 還是默認的 0x00,此處 flag 帶下來 0x05 這個值,於是走入這個分支;
- 第 25 行,更新 previewCallbackFlags 值爲 0x05;
- 第 28 行,再次進入
startPreviewL
流程,注意這次 restart 參數值是 true。
void Camera2Client::setPreviewCallbackFlagL(Parameters ¶ms, 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
該函數主要邏輯如下:
- 第 4 行,將 state 設置爲 STOPPED;
- 第 5~14 行,由於已經
startPreview
過, 這裏能拿到當前 preview stream 的 ID,相關邏輯需要關注的信息不多,就不深入去看了; - 第 19 行,由於 params.previewCallbackFlags 是 0x05,這裏的 callbacksEnabled 被設置爲 true;
- 第 26 行,調用到 CallbackProcessor 的
updateStream
,此處就是後續關注的重點了,由於需要新的這一路 callback stream,此處會有相關的創建新 stream 的邏輯,包括觸發 re-config 動作; - 第 32 行,callback stream 準備好後,加入到 output buffer 集合中;
- 第 44 行,將 preview stream 加入到 output buffer 集合中;
- 第 58 行,這次的
startStream
就不會觸發 configureStream 的動作了,需要注意的是它會調用到setRepeatingRequests
; - 第 65 行,將 state 恢復爲 PREVIEW。
status_t Camera2Client::startPreviewL(Parameters ¶ms, 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
此處邏輯如下:
- 第 4~14 行,創建 BufferQueue,並進行相應的配置。這裏面需要注意一下 Consumer 這個類,它與後續接收 callback buffer,觸發
onFrameAvailable
回調密切相關,但由於此處關係略複雜,就不深入去分析了,有興趣可以自己看看; - 第 22 行,由於當前無 callback stream,所以需要新創建一個。
status_t CallbackProcessor::updateStream(const Parameters ¶ms) {
// 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
有兩個,這裏只看最後執行的那一個:
- 第 8 行,注意 wasActive 初始值是 false;
- 第 21~29 行,當前 mStatus 是 STATUS_ACTIVE,在第 23 行會把 RequestThread 暫停,等待到 STATUS_CONFIGURED,至於爲什麼會有這樣的轉變,與 StatusTracker 有關,有興趣可以再深入看看,這裏先忽略該細節。第 28 行將 wasActive 改爲 true;
- 第 49 行,創建用於 preview callback 的 stream;
- 第 54~64 行,根據 consumer 個數將 callback stream 中的各 Surface ID 找出來,通過參數 surfaceIds 返回;
- 第 70 行,將 callback stream 加入到 Camera3Device 的成員 mOutputStreams 中,這是一個 StreamSet,這裏需要注意的是,要和 Camera3Device::CaptureRequest 類的成員 mOutputStreams 區別開來,不是同一個東西;
- 第 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
此處邏輯如下:
- 第 6 行,這裏要注意了,mStatus 在前面
createStream
的流程中已經被改成 STATUS_CONFIGURED 了,所以此處不會被 return,如果還是 STATUS_ACTIVE 的話這裏就觸發 return,就不會繼續 config 了; - 第 13 行,
createStream
裏面有設置 mNeedConfig 爲 true,所以此處不會觸發 return; - 第 20 行,先停掉 PrepareThread 的 Loop;
- 第 24~50 行,主要是對每個 output stream 執行
startConfiguration
的動作; - 第 58 行,通過 Camera3Device::HalInterface 實例,透過 HIDL 啓動 HAL 層的 configureStreams 流程;
- 第 63~75 行,對應第 4 點,這裏是執行
finishConfiguration
動作; - 第 85 行,mNeedConfig 設置爲 false;
- 第 87 行,這裏會再次設置 mStatus 爲 STATUS_CONFIGURED;
- 第 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
此處邏輯如下:
- 第 5~6 行,這裏拿到的是 mPreviewRequest;
- 第 8~10 行,更新 Request Metadata 裏的 output stream 參數,注意這裏傳入的 ouputStreams 的個數,會影響到 RequestThread 在
prepareHalRequest
時所準備的 buffer 個數; - 第 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
此處邏輯如下:
- 第 11 行,目的是獲取 RequestList,它是以 Camera3Device 內部定義的類 CaptureRequest 爲基礎的鏈表,此處還需要注意傳入的參數中 repeating 的值是 true;
- 第 19 行,由於 repeating 爲 true,所以走了
setRepeatingRequest
,這是 API2 啓預覽的接口; - 第 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
此處邏輯如下:
- 第 5 行,注意此處 mStatus 是 STATUS_CONFIGURED 並且 mNeedConfig 爲 false,所以這塊分支都不會走;
- 第 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
:
- 第 10~11 行,這裏先清除了 mRepeatingRequests 裏的內容,把新創建的 CaptureRequest 加了進來;
- 第 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 流動的時序。