Camera: Use capture result metadata to override EXIF
Use static and dynamic metadata to override Exif tags.
Also added back a missing ATRACE_ASYNC_ENDs statement.
Test: Camera CTS
Test: ERROR_BUFFER of internal streams is propagated to app
Test: ERROR_RESULT only results in EXIF not being overridden
Bug: 124066183
Change-Id: Id2c69c6bee04ae724ff5f190b2dd96d0159700c9
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 8e9c39e..a61cdee 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -136,6 +136,8 @@
mAppSegmentConsumer->setName(String8("Camera3-HeicComposite-AppSegmentStream"));
mAppSegmentSurface = new Surface(producer);
+ mStaticInfo = device->info();
+
res = device->createStream(mAppSegmentSurface, mAppSegmentMaxSize, 1, format,
kAppSegmentDataSpace, rotation, &mAppSegmentStreamId, physicalCameraId, surfaceIds);
if (res == OK) {
@@ -606,9 +608,42 @@
mFrameNumberMap.erase(it);
}
- // Heic composition doesn't depend on capture result, so no need to check
- // mErrorFrameNumbers. Just remove them.
- mErrorFrameNumbers.clear();
+ while (!mCaptureResults.empty()) {
+ auto it = mCaptureResults.begin();
+ // Negative timestamp indicates that something went wrong during the capture result
+ // collection process.
+ if (it->first >= 0) {
+ if (mPendingInputFrames[it->first].frameNumber == std::get<0>(it->second)) {
+ mPendingInputFrames[it->first].result =
+ std::make_unique<CameraMetadata>(std::get<1>(it->second));
+ } else {
+ ALOGE("%s: Capture result frameNumber/timestamp mapping changed between "
+ "shutter and capture result!", __FUNCTION__);
+ }
+ }
+ mCaptureResults.erase(it);
+ }
+
+ // mErrorFrameNumbers stores frame number of dropped buffers.
+ auto it = mErrorFrameNumbers.begin();
+ while (it != mErrorFrameNumbers.end()) {
+ bool frameFound = false;
+ for (auto &inputFrame : mPendingInputFrames) {
+ if (inputFrame.second.frameNumber == *it) {
+ inputFrame.second.error = true;
+ frameFound = true;
+ break;
+ }
+ }
+
+ if (frameFound) {
+ it = mErrorFrameNumbers.erase(it);
+ } else {
+ ALOGW("%s: Not able to find failing input with frame number: %" PRId64, __FUNCTION__,
+ *it);
+ it++;
+ }
+ }
// Distribute codec input buffers to be filled out from YUV output
for (auto it = mPendingInputFrames.begin();
@@ -639,14 +674,14 @@
bool newInputAvailable = false;
for (const auto& it : mPendingInputFrames) {
- bool appSegmentBufferReady = (it.second.appSegmentBuffer.data != nullptr) &&
- !it.second.appSegmentWritten;
+ bool appSegmentReady = (it.second.appSegmentBuffer.data != nullptr) &&
+ !it.second.appSegmentWritten && it.second.result != nullptr;
bool codecOutputReady = !it.second.codecOutputBuffers.empty();
bool codecInputReady = (it.second.yuvBuffer.data != nullptr) &&
(!it.second.codecInputBuffers.empty());
if ((!it.second.error) &&
(it.first < *currentTs) &&
- (appSegmentBufferReady || codecOutputReady || codecInputReady)) {
+ (appSegmentReady || codecOutputReady || codecInputReady)) {
*currentTs = it.first;
newInputAvailable = true;
break;
@@ -678,13 +713,13 @@
ATRACE_CALL();
status_t res = OK;
- bool appSegmentBufferReady = inputFrame.appSegmentBuffer.data != nullptr &&
- !inputFrame.appSegmentWritten;
+ bool appSegmentReady = inputFrame.appSegmentBuffer.data != nullptr &&
+ !inputFrame.appSegmentWritten && inputFrame.result != nullptr;
bool codecOutputReady = inputFrame.codecOutputBuffers.size() > 0;
bool codecInputReady = inputFrame.yuvBuffer.data != nullptr &&
!inputFrame.codecInputBuffers.empty();
- if (!appSegmentBufferReady && !codecOutputReady && !codecInputReady) {
+ if (!appSegmentReady && !codecOutputReady && !codecInputReady) {
ALOGW("%s: No valid appSegmentBuffer/codec input/outputBuffer available!", __FUNCTION__);
return OK;
}
@@ -710,7 +745,7 @@
}
// Write JPEG APP segments data to the muxer.
- if (appSegmentBufferReady && inputFrame.muxer != nullptr) {
+ if (appSegmentReady && inputFrame.muxer != nullptr) {
res = processAppSegment(timestamp, inputFrame);
if (res != OK) {
ALOGE("%s: Failed to process JPEG APP segments: %s (%d)", __FUNCTION__,
@@ -829,10 +864,8 @@
ALOGE("%s: Failed to initialize ExifUtils object!", __FUNCTION__);
return BAD_VALUE;
}
- //TODO: Use capture result metadata and static metadata to fill out the
- //rest.
- CameraMetadata dummyMeta;
- exifRes = exifUtils->setFromMetadata(dummyMeta, mOutputWidth, mOutputHeight);
+ exifRes = exifUtils->setFromMetadata(*inputFrame.result, mStaticInfo,
+ mOutputWidth, mOutputHeight);
if (!exifRes) {
ALOGE("%s: Failed to set Exif tags using metadata and main image sizes", __FUNCTION__);
return BAD_VALUE;
@@ -1012,6 +1045,7 @@
}
inputFrame.anb = nullptr;
+ ATRACE_ASYNC_END("HEIC capture", inputFrame.frameNumber);
return OK;
}
@@ -1497,6 +1531,36 @@
return res;
}
+void HeicCompositeStream::onResultError(const CaptureResultExtras& resultExtras) {
+ // For result error, since the APPS_SEGMENT buffer already contains EXIF,
+ // simply skip using the capture result metadata to override EXIF.
+ Mutex::Autolock l(mMutex);
+
+ int64_t timestamp = -1;
+ for (const auto& fn : mFrameNumberMap) {
+ if (fn.first == resultExtras.frameNumber) {
+ timestamp = fn.second;
+ break;
+ }
+ }
+ if (timestamp == -1) {
+ for (const auto& inputFrame : mPendingInputFrames) {
+ if (inputFrame.second.frameNumber == resultExtras.frameNumber) {
+ timestamp = inputFrame.first;
+ break;
+ }
+ }
+ }
+
+ if (timestamp == -1) {
+ ALOGE("%s: Failed to find shutter timestamp for result error!", __FUNCTION__);
+ return;
+ }
+
+ mCaptureResults.emplace(timestamp, std::make_tuple(resultExtras.frameNumber, CameraMetadata()));
+ mInputReadyCondition.signal();
+}
+
void HeicCompositeStream::CodecCallbackHandler::onMessageReceived(const sp<AMessage> &msg) {
sp<HeicCompositeStream> parent = mParent.promote();
if (parent == nullptr) return;