Camera: Narrow down cases preview spacer is used
HW_TEXTURE usage flag may be used for ImageReader. Do not treat the
surface as SurfaceTexture if the surface has CPU read flag at the
same time.
In addition:
- Only enable preview spacer if timestamp base is DEFAULT,
- Use readoutTimestamp for re-spacing.
- Remove the system property to disable frame spacing.
Test: Camera CTS, Observe smoother GCA photo preview
Bug: 195025014
Change-Id: I40a3b1acac44ed8a474aad94b77aee8f7399eb31
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index b5d0746..add1483 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -89,9 +89,10 @@
if (strlen(camera_stream::physical_camera_id) > 0) {
lines.appendFormat(" Physical camera id: %s\n", camera_stream::physical_camera_id);
}
- lines.appendFormat(" Dynamic Range Profile: 0x%" PRIx64,
+ lines.appendFormat(" Dynamic Range Profile: 0x%" PRIx64 "\n",
camera_stream::dynamic_range_profile);
lines.appendFormat(" Stream use case: %" PRId64 "\n", camera_stream::use_case);
+ lines.appendFormat(" Timestamp base: %d\n", getTimestampBase());
lines.appendFormat(" Frames produced: %d, last timestamp: %" PRId64 " ns\n",
mFrameCount, mLastTimestamp);
lines.appendFormat(" Total buffers: %zu, currently dequeued: %zu\n",
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 30e9fba..8e30ed3 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -466,8 +466,10 @@
nsecs_t captureTime = (mUseReadoutTime && readoutTimestamp != 0 ?
readoutTimestamp : timestamp) - mTimestampOffset;
if (mPreviewFrameSpacer != nullptr) {
- res = mPreviewFrameSpacer->queuePreviewBuffer(captureTime, transform,
- anwBuffer, anwReleaseFence);
+ nsecs_t readoutTime = (readoutTimestamp != 0 ? readoutTimestamp : timestamp)
+ - mTimestampOffset;
+ res = mPreviewFrameSpacer->queuePreviewBuffer(captureTime, readoutTime,
+ transform, anwBuffer, anwReleaseFence);
if (res != OK) {
ALOGE("%s: Stream %d: Error queuing buffer to preview buffer spacer: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
@@ -684,12 +686,15 @@
bool forceChoreographer = (timestampBase ==
OutputConfiguration::TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED);
bool defaultToChoreographer = (isDefaultTimeBase &&
- isConsumedByHWComposer() &&
- !property_get_bool("camera.disable_preview_scheduler", false));
+ isConsumedByHWComposer());
+ bool defaultToSpacer = (isDefaultTimeBase &&
+ isConsumedByHWTexture() &&
+ !isConsumedByCPU() &&
+ !isVideoStream());
if (forceChoreographer || defaultToChoreographer) {
mSyncToDisplay = true;
mTotalBufferCount += kDisplaySyncExtraBuffer;
- } else if (isConsumedByHWTexture() && !isVideoStream()) {
+ } else if (defaultToSpacer) {
mPreviewFrameSpacer = new PreviewFrameSpacer(*this, mConsumer);
mTotalBufferCount ++;
res = mPreviewFrameSpacer->run(String8::format("PreviewSpacer-%d", mId).string());
@@ -1268,6 +1273,17 @@
return (usage & GRALLOC_USAGE_HW_TEXTURE) != 0;
}
+bool Camera3OutputStream::isConsumedByCPU() const {
+ uint64_t usage = 0;
+ status_t res = getEndpointUsage(&usage);
+ if (res != OK) {
+ ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res);
+ return false;
+ }
+
+ return (usage & GRALLOC_USAGE_SW_READ_MASK) != 0;
+}
+
void Camera3OutputStream::dumpImageToDisk(nsecs_t timestamp,
ANativeWindowBuffer* anwBuffer, int fence) {
// Deriver output file name
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 79461bd..4ab052b 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -160,6 +160,11 @@
bool isConsumedByHWTexture() const;
/**
+ * Return if this output stream is consumed by CPU.
+ */
+ bool isConsumedByCPU() const;
+
+ /**
* Return if the consumer configuration of this stream is deferred.
*/
virtual bool isConsumerConfigurationDeferred(size_t surface_id) const;
diff --git a/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp b/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp
index 9112b93..496580f 100644
--- a/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp
+++ b/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp
@@ -36,12 +36,12 @@
Thread::requestExitAndWait();
}
-status_t PreviewFrameSpacer::queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
- ANativeWindowBuffer* anwBuffer, int releaseFence) {
+status_t PreviewFrameSpacer::queuePreviewBuffer(nsecs_t timestamp, nsecs_t readoutTimestamp,
+ int32_t transform, ANativeWindowBuffer* anwBuffer, int releaseFence) {
Mutex::Autolock l(mLock);
- mPendingBuffers.emplace(timestamp, transform, anwBuffer, releaseFence);
- ALOGV("%s: mPendingBuffers size %zu, timestamp %" PRId64, __FUNCTION__,
- mPendingBuffers.size(), timestamp);
+ mPendingBuffers.emplace(timestamp, readoutTimestamp, transform, anwBuffer, releaseFence);
+ ALOGV("%s: mPendingBuffers size %zu, timestamp %" PRId64 ", readoutTime %" PRId64,
+ __FUNCTION__, mPendingBuffers.size(), timestamp, readoutTimestamp);
mBufferCond.signal();
return OK;
@@ -56,17 +56,17 @@
nsecs_t currentTime = systemTime();
auto buffer = mPendingBuffers.front();
- nsecs_t captureInterval = buffer.timestamp - mLastCameraCaptureTime;
- // If the capture interval exceeds threshold, directly queue
+ nsecs_t readoutInterval = buffer.readoutTimestamp - mLastCameraReadoutTime;
+ // If the readout interval exceeds threshold, directly queue
// cached buffer.
- if (captureInterval >= kFrameIntervalThreshold) {
+ if (readoutInterval >= kFrameIntervalThreshold) {
mPendingBuffers.pop();
queueBufferToClientLocked(buffer, currentTime);
return true;
}
- // Cache the frame to match capture time interval, for up to 33ms
- nsecs_t expectedQueueTime = mLastCameraPresentTime + captureInterval;
+ // Cache the frame to match readout time interval, for up to 33ms
+ nsecs_t expectedQueueTime = mLastCameraPresentTime + readoutInterval;
nsecs_t frameWaitTime = std::min(kMaxFrameWaitTime, expectedQueueTime - currentTime);
if (frameWaitTime > 0 && mPendingBuffers.size() < 2) {
mBufferCond.waitRelative(mLock, frameWaitTime);
@@ -75,8 +75,8 @@
}
currentTime = systemTime();
}
- ALOGV("%s: captureInterval %" PRId64 ", queueInterval %" PRId64 ", waited for %" PRId64
- ", timestamp %" PRId64, __FUNCTION__, captureInterval,
+ ALOGV("%s: readoutInterval %" PRId64 ", queueInterval %" PRId64 ", waited for %" PRId64
+ ", timestamp %" PRId64, __FUNCTION__, readoutInterval,
currentTime - mLastCameraPresentTime, frameWaitTime, buffer.timestamp);
mPendingBuffers.pop();
queueBufferToClientLocked(buffer, currentTime);
@@ -114,7 +114,7 @@
}
mLastCameraPresentTime = currentTime;
- mLastCameraCaptureTime = bufferHolder.timestamp;
+ mLastCameraReadoutTime = bufferHolder.readoutTimestamp;
}
}; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/PreviewFrameSpacer.h b/services/camera/libcameraservice/device3/PreviewFrameSpacer.h
index 5062553..fb0a563 100644
--- a/services/camera/libcameraservice/device3/PreviewFrameSpacer.h
+++ b/services/camera/libcameraservice/device3/PreviewFrameSpacer.h
@@ -42,8 +42,8 @@
*
* The PreviewFrameSpacer improves the viewfinder user experience by:
* - Cache the frame buffers if the intervals between queueBuffer is shorter
- * than the camera capture intervals.
- * - Queue frame buffers in the same cadence as the camera capture time.
+ * than the camera readout intervals.
+ * - Queue frame buffers in the same cadence as the camera readout time.
* - Maintain at most 1 queue-able buffer. If the 2nd preview buffer becomes
* available, queue the oldest cached buffer to the buffer queue.
*/
@@ -53,8 +53,8 @@
virtual ~PreviewFrameSpacer();
// Queue preview buffer locally
- status_t queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
- ANativeWindowBuffer* anwBuffer, int releaseFence);
+ status_t queuePreviewBuffer(nsecs_t timestamp, nsecs_t readoutTimestamp,
+ int32_t transform, ANativeWindowBuffer* anwBuffer, int releaseFence);
bool threadLoop() override;
void requestExit() override;
@@ -63,12 +63,14 @@
// structure holding cached preview buffer info
struct BufferHolder {
nsecs_t timestamp;
+ nsecs_t readoutTimestamp;
int32_t transform;
sp<ANativeWindowBuffer> anwBuffer;
int releaseFence;
- BufferHolder(nsecs_t t, int32_t tr, ANativeWindowBuffer* anwb, int rf) :
- timestamp(t), transform(tr), anwBuffer(anwb), releaseFence(rf) {}
+ BufferHolder(nsecs_t t, nsecs_t readoutT, int32_t tr, ANativeWindowBuffer* anwb, int rf) :
+ timestamp(t), readoutTimestamp(readoutT), transform(tr), anwBuffer(anwb),
+ releaseFence(rf) {}
};
void queueBufferToClientLocked(const BufferHolder& bufferHolder, nsecs_t currentTime);
@@ -80,7 +82,7 @@
Condition mBufferCond;
std::queue<BufferHolder> mPendingBuffers;
- nsecs_t mLastCameraCaptureTime = 0;
+ nsecs_t mLastCameraReadoutTime = 0;
nsecs_t mLastCameraPresentTime = 0;
static constexpr nsecs_t kWaitDuration = 5000000LL; // 50ms
static constexpr nsecs_t kFrameIntervalThreshold = 80000000LL; // 80ms