Camera: Switch to query function for display sync
The query function has the benefit of:
- Simpler code
- No need to use ndk, thus reduce size of cameraserver process
- Better latency compared to callbacks
The additional inflight preview buffers are still necessary so that
producer doesn't get starved.
Test: GoogleCamera app video mode preview, OpenCamera
Test: Camera CTS
Bug: 221499182
Change-Id: I8de42e5747afca79e85841705b9296de0fd668c7
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 0f61065..b822178 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -376,32 +376,26 @@
dumpImageToDisk(timestamp, anwBuffer, anwReleaseFence);
}
- nsecs_t t = mPreviewFrameScheduler != nullptr ? readoutTimestamp : timestamp;
- t -= mTimestampOffset;
- if (mPreviewFrameScheduler != nullptr) {
- res = mPreviewFrameScheduler->queuePreviewBuffer(t, transform,
- anwBuffer, anwReleaseFence);
- if (res != OK) {
- ALOGE("%s: Stream %d: Error queuing buffer to preview buffer scheduler: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- return res;
- }
- } else {
- setTransform(transform, true/*mayChangeMirror*/);
- res = native_window_set_buffers_timestamp(mConsumer.get(), t);
- if (res != OK) {
- ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- return res;
- }
+ nsecs_t captureTime = (mSyncToDisplay ? readoutTimestamp : timestamp) - mTimestampOffset;
+ nsecs_t presentTime = mSyncToDisplay ?
+ syncTimestampToDisplayLocked(captureTime) : captureTime;
+ mLastCaptureTime = captureTime;
+ mLastPresentTime = presentTime;
- queueHDRMetadata(anwBuffer->handle, currentConsumer, dynamic_range_profile);
+ setTransform(transform, true/*mayChangeMirror*/);
+ res = native_window_set_buffers_timestamp(mConsumer.get(), presentTime);
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
- res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence, surface_ids);
- if (shouldLogError(res, state)) {
- ALOGE("%s: Stream %d: Error queueing buffer to native window:"
- " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
- }
+ queueHDRMetadata(anwBuffer->handle, currentConsumer, dynamic_range_profile);
+
+ res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence, surface_ids);
+ if (shouldLogError(res, state)) {
+ ALOGE("%s: Stream %d: Error queueing buffer to native window:"
+ " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
}
}
mLock.lock();
@@ -476,7 +470,7 @@
return res;
}
- if ((res = configureConsumerQueueLocked(true /*allowPreviewScheduler*/)) != OK) {
+ if ((res = configureConsumerQueueLocked(true /*allowDisplaySync*/)) != OK) {
return res;
}
@@ -500,7 +494,7 @@
return OK;
}
-status_t Camera3OutputStream::configureConsumerQueueLocked(bool allowPreviewScheduler) {
+status_t Camera3OutputStream::configureConsumerQueueLocked(bool allowDisplaySync) {
status_t res;
mTraceFirstBuffer = true;
@@ -590,16 +584,17 @@
int timestampBase = getTimestampBase();
bool isDefaultTimeBase = (timestampBase ==
OutputConfiguration::TIMESTAMP_BASE_DEFAULT);
- if (allowPreviewScheduler) {
+ if (allowDisplaySync) {
// We cannot distinguish between a SurfaceView and an ImageReader of
- // preview buffer format. The PreviewFrameScheduler needs to handle both.
+ // preview buffer format. Frames are synchronized to display in both
+ // cases.
bool forceChoreographer = (timestampBase ==
OutputConfiguration::TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED);
bool defaultToChoreographer = (isDefaultTimeBase && isConsumedByHWComposer() &&
!property_get_bool("camera.disable_preview_scheduler", false));
if (forceChoreographer || defaultToChoreographer) {
- mPreviewFrameScheduler = std::make_unique<PreviewFrameScheduler>(*this, mConsumer);
- mTotalBufferCount += PreviewFrameScheduler::kQueueDepthWatermark;
+ mSyncToDisplay = true;
+ mTotalBufferCount += kDisplaySyncExtraBuffer;
}
}
@@ -1244,6 +1239,11 @@
return OK;
}
+void Camera3OutputStream::onMinDurationChanged(nsecs_t duration) {
+ Mutex::Autolock l(mLock);
+ mMinExpectedDuration = duration;
+}
+
void Camera3OutputStream::returnPrefetchedBuffersLocked() {
std::vector<Surface::BatchBuffer> batchedBuffers;
@@ -1261,9 +1261,52 @@
}
}
-bool Camera3OutputStream::shouldLogError(status_t res) {
- Mutex::Autolock l(mLock);
- return shouldLogError(res, mState);
+nsecs_t Camera3OutputStream::syncTimestampToDisplayLocked(nsecs_t t) {
+ ParcelableVsyncEventData parcelableVsyncEventData;
+ auto res = mDisplayEventReceiver.getLatestVsyncEventData(&parcelableVsyncEventData);
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Error getting latest vsync event data: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return t;
+ }
+
+ const VsyncEventData& vsyncEventData = parcelableVsyncEventData.vsync;
+ nsecs_t currentTime = systemTime();
+
+ // Reset capture to present time offset if more than 1 second
+ // between frames.
+ if (t - mLastCaptureTime > kSpacingResetIntervalNs) {
+ for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
+ if (vsyncEventData.frameTimelines[i].deadlineTimestamp >= currentTime) {
+ mCaptureToPresentOffset =
+ vsyncEventData.frameTimelines[i].expectedPresentationTime - t;
+ break;
+ }
+ }
+ }
+
+ nsecs_t idealPresentT = t + mCaptureToPresentOffset;
+ nsecs_t expectedPresentT = 0;
+ nsecs_t minDiff = INT64_MAX;
+ // Derive minimum intervals between presentation times based on minimal
+ // expected duration.
+ size_t minVsyncs = (mMinExpectedDuration + vsyncEventData.frameInterval - 1) /
+ vsyncEventData.frameInterval - 1;
+ nsecs_t minInterval = minVsyncs * vsyncEventData.frameInterval + kTimelineThresholdNs;
+ // Find best timestamp in the vsync timeline:
+ // - closest to the ideal present time,
+ // - deadline timestamp is greater than the current time, and
+ // - the candidate present time is at least minInterval in the future
+ // compared to last present time.
+ for (const auto& vsyncTime : vsyncEventData.frameTimelines) {
+ if (std::abs(vsyncTime.expectedPresentationTime - idealPresentT) < minDiff &&
+ vsyncTime.deadlineTimestamp >= currentTime &&
+ vsyncTime.expectedPresentationTime > mLastPresentTime + minInterval) {
+ expectedPresentT = vsyncTime.expectedPresentationTime;
+ minDiff = std::abs(vsyncTime.expectedPresentationTime - idealPresentT);
+ }
+ }
+ return expectedPresentT;
}
}; // namespace camera3