Camera: Add lastCompletedFrameNumber in CaptureResultExtras (take 2)
The new fields in CaptureResultExtras notify the application the last
completed frame numbers. A frame number is completed if:
- All buffers are returned, and
- Final capture result is returned, or RESULT_ERROR/REQUEST_ERROR is called,
Ignore the HAL's notify(ERROR_BUFFER), and depends on the buffers'
STATUS_ERROR bit, capture result metadata, and ERROR_RESULT/ERROR_REQUEST
for sending ERROR_BUFFER to the application.
This makes sure client doesn't ignore BUFFER_ERROR after capture
result metadata callback.
Public API and NDK logic are fixed. VNDK is yet to be done.
Test: Camera CTS
Bug: 155353799
Change-Id: I54d198080b251239aeb88a8f93456bba6b3630d8
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 0d7180a..c15c5a5 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -1336,56 +1336,97 @@
void
CameraDevice::checkAndFireSequenceCompleteLocked() {
int64_t completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
- //std::map<int, int64_t> mSequenceLastFrameNumberMap;
auto it = mSequenceLastFrameNumberMap.begin();
while (it != mSequenceLastFrameNumberMap.end()) {
int sequenceId = it->first;
- int64_t lastFrameNumber = it->second;
- bool seqCompleted = false;
- bool hasCallback = true;
+ int64_t lastFrameNumber = it->second.lastFrameNumber;
+ bool hasCallback = true;
+
+ if (mRemote == nullptr) {
+ ALOGW("Camera %s closed while checking sequence complete", getId());
+ return;
+ }
+ ALOGV("%s: seq %d's last frame number %" PRId64 ", completed %" PRId64,
+ __FUNCTION__, sequenceId, lastFrameNumber, completedFrameNumber);
+ if (!it->second.isSequenceCompleted) {
+ // Check if there is callback for this sequence
+ // This should not happen because we always register callback (with nullptr inside)
+ if (mSequenceCallbackMap.count(sequenceId) == 0) {
+ ALOGW("No callback found for sequenceId %d", sequenceId);
+ hasCallback = false;
+ }
+
+ if (lastFrameNumber <= completedFrameNumber) {
+ ALOGV("Mark sequenceId %d as sequence completed", sequenceId);
+ it->second.isSequenceCompleted = true;
+ }
+
+ if (it->second.isSequenceCompleted && hasCallback) {
+ auto cbIt = mSequenceCallbackMap.find(sequenceId);
+ CallbackHolder cbh = cbIt->second;
+
+ // send seq complete callback
+ sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler);
+ msg->setPointer(kContextKey, cbh.mContext);
+ msg->setObject(kSessionSpKey, cbh.mSession);
+ msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceCompleted);
+ msg->setInt32(kSequenceIdKey, sequenceId);
+ msg->setInt64(kFrameNumberKey, lastFrameNumber);
+
+ // Clear the session sp before we send out the message
+ // This will guarantee the rare case where the message is processed
+ // before cbh goes out of scope and causing we call the session
+ // destructor while holding device lock
+ cbh.mSession.clear();
+ postSessionMsgAndCleanup(msg);
+ }
+ }
+
+ if (it->second.isSequenceCompleted && it->second.isInflightCompleted) {
+ if (mSequenceCallbackMap.find(sequenceId) != mSequenceCallbackMap.end()) {
+ mSequenceCallbackMap.erase(sequenceId);
+ }
+ it = mSequenceLastFrameNumberMap.erase(it);
+ ALOGV("%s: Remove holder for sequenceId %d", __FUNCTION__, sequenceId);
+ } else {
+ ++it;
+ }
+ }
+}
+
+void
+CameraDevice::removeCompletedCallbackHolderLocked(int64_t lastCompletedRegularFrameNumber) {
+ auto it = mSequenceLastFrameNumberMap.begin();
+ while (it != mSequenceLastFrameNumberMap.end()) {
+ int sequenceId = it->first;
+ int64_t lastFrameNumber = it->second.lastFrameNumber;
if (mRemote == nullptr) {
ALOGW("Camera %s closed while checking sequence complete", getId());
return;
}
- // Check if there is callback for this sequence
- // This should not happen because we always register callback (with nullptr inside)
- if (mSequenceCallbackMap.count(sequenceId) == 0) {
- ALOGW("No callback found for sequenceId %d", sequenceId);
- hasCallback = false;
- }
+ ALOGV("%s: seq %d's last frame number %" PRId64
+ ", completed inflight frame number %" PRId64,
+ __FUNCTION__, sequenceId, lastFrameNumber,
+ lastCompletedRegularFrameNumber);
+ if (lastFrameNumber <= lastCompletedRegularFrameNumber) {
+ if (it->second.isSequenceCompleted) {
+ // Check if there is callback for this sequence
+ // This should not happen because we always register callback (with nullptr inside)
+ if (mSequenceCallbackMap.count(sequenceId) == 0) {
+ ALOGW("No callback found for sequenceId %d", sequenceId);
+ } else {
+ mSequenceCallbackMap.erase(sequenceId);
+ }
- if (lastFrameNumber <= completedFrameNumber) {
- ALOGV("seq %d reached last frame %" PRId64 ", completed %" PRId64,
- sequenceId, lastFrameNumber, completedFrameNumber);
- seqCompleted = true;
- }
-
- if (seqCompleted && hasCallback) {
- // remove callback holder from callback map
- auto cbIt = mSequenceCallbackMap.find(sequenceId);
- CallbackHolder cbh = cbIt->second;
- mSequenceCallbackMap.erase(cbIt);
- // send seq complete callback
- sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler);
- msg->setPointer(kContextKey, cbh.mContext);
- msg->setObject(kSessionSpKey, cbh.mSession);
- msg->setPointer(kCallbackFpKey, (void*) cbh.mOnCaptureSequenceCompleted);
- msg->setInt32(kSequenceIdKey, sequenceId);
- msg->setInt64(kFrameNumberKey, lastFrameNumber);
-
- // Clear the session sp before we send out the message
- // This will guarantee the rare case where the message is processed
- // before cbh goes out of scope and causing we call the session
- // destructor while holding device lock
- cbh.mSession.clear();
- postSessionMsgAndCleanup(msg);
- }
-
- // No need to track sequence complete if there is no callback registered
- if (seqCompleted || !hasCallback) {
- it = mSequenceLastFrameNumberMap.erase(it);
+ it = mSequenceLastFrameNumberMap.erase(it);
+ ALOGV("%s: Remove holder for sequenceId %d", __FUNCTION__, sequenceId);
+ } else {
+ ALOGV("Mark sequenceId %d as inflight completed", sequenceId);
+ it->second.isInflightCompleted = true;
+ ++it;
+ }
} else {
++it;
}
@@ -1480,6 +1521,9 @@
return ret;
}
+ dev->removeCompletedCallbackHolderLocked(
+ std::numeric_limits<int64_t>::max()/*lastCompletedRegularFrameNumber*/);
+
if (dev->mIdle) {
// Already in idle state. Possibly other thread did waitUntilIdle
return ret;
@@ -1522,6 +1566,9 @@
return ret;
}
+ dev->removeCompletedCallbackHolderLocked(
+ resultExtras.lastCompletedRegularFrameNumber);
+
int sequenceId = resultExtras.requestId;
int32_t burstId = resultExtras.burstId;
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 6c2ceb3..d937865 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -267,8 +267,23 @@
static const int REQUEST_ID_NONE = -1;
int mRepeatingSequenceId = REQUEST_ID_NONE;
- // sequence id -> last frame number map
- std::map<int, int64_t> mSequenceLastFrameNumberMap;
+ // sequence id -> last frame number holder map
+ struct RequestLastFrameNumberHolder {
+ int64_t lastFrameNumber;
+ // Whether the current sequence is completed (capture results are
+ // generated). May be set to true, but
+ // not removed from the map if not all inflight requests in the sequence
+ // have been completed.
+ bool isSequenceCompleted = false;
+ // Whether all inflight requests in the sequence are completed
+ // (capture results and buffers are generated). May be
+ // set to true, but not removed from the map yet if the capture results
+ // haven't been delivered to the app yet.
+ bool isInflightCompleted = false;
+ RequestLastFrameNumberHolder(int64_t lastFN) :
+ lastFrameNumber(lastFN) {}
+ };
+ std::map<int, RequestLastFrameNumberHolder> mSequenceLastFrameNumberMap;
struct CallbackHolder {
CallbackHolder(sp<ACameraCaptureSession> session,
@@ -338,6 +353,7 @@
void checkRepeatingSequenceCompleteLocked(const int sequenceId, const int64_t lastFrameNumber);
void checkAndFireSequenceCompleteLocked();
+ void removeCompletedCallbackHolderLocked(int64_t lastCompletedRegularFrameNumber);
// Misc variables
int32_t mShadingMapSize[2]; // const after constructor