Camera: Retry JPEG capture if buffer is dropped.
Camera api1 doesn't have error notification if JPEG buffer is dropped.
Add retry logic to try again if such error happens.
Bug: 27074407
Change-Id: I646566c6ee5a064896b5a433d8e1797140f0d257
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 61e1442..e3d6906 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -41,6 +41,7 @@
mNewAEState(false),
mNewFrameReceived(false),
mNewCaptureReceived(false),
+ mNewCaptureErrorCnt(0),
mShutterNotified(false),
mHalNotifiedShutter(false),
mShutterCaptureId(-1),
@@ -131,7 +132,7 @@
}
void CaptureSequencer::onCaptureAvailable(nsecs_t timestamp,
- sp<MemoryBase> captureBuffer) {
+ sp<MemoryBase> captureBuffer, bool captureError) {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
Mutex::Autolock l(mInputMutex);
@@ -139,6 +140,11 @@
mCaptureBuffer = captureBuffer;
if (!mNewCaptureReceived) {
mNewCaptureReceived = true;
+ if (captureError) {
+ mNewCaptureErrorCnt++;
+ } else {
+ mNewCaptureErrorCnt = 0;
+ }
mNewCaptureSignal.signal();
}
}
@@ -623,6 +629,17 @@
break;
}
}
+ if (mNewCaptureReceived) {
+ if (mNewCaptureErrorCnt > kMaxRetryCount) {
+ ALOGW("Exceeding multiple retry limit of %d due to buffer drop", kMaxRetryCount);
+ return DONE;
+ } else if (mNewCaptureErrorCnt > 0) {
+ ALOGW("Capture error happened, retry %d...", mNewCaptureErrorCnt);
+ mNewCaptureReceived = false;
+ return STANDARD_CAPTURE;
+ }
+ }
+
if (mTimeoutCount <= 0) {
ALOGW("Timed out waiting for capture to complete");
return DONE;
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index b05207e..a7c61d2 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -69,7 +69,7 @@
virtual void onResultAvailable(const CaptureResult &result);
// Notifications from the JPEG processor
- void onCaptureAvailable(nsecs_t timestamp, sp<MemoryBase> captureBuffer);
+ void onCaptureAvailable(nsecs_t timestamp, sp<MemoryBase> captureBuffer, bool captureError);
void dump(int fd, const Vector<String16>& args);
@@ -94,6 +94,7 @@
Condition mNewFrameSignal;
bool mNewCaptureReceived;
+ int32_t mNewCaptureErrorCnt;
nsecs_t mCaptureTimestamp;
sp<MemoryBase> mCaptureBuffer;
Condition mNewCaptureSignal;
@@ -110,6 +111,7 @@
static const int kMaxTimeoutsForPrecaptureStart = 10; // 1 sec
static const int kMaxTimeoutsForPrecaptureEnd = 20; // 2 sec
static const int kMaxTimeoutsForCaptureEnd = 40; // 4 sec
+ static const int kMaxRetryCount = 3; // 3 retries in case of buffer drop
wp<Camera2Client> mClient;
wp<ZslProcessor> mZslProcessor;
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index e97618c..ffe96fc 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -42,7 +42,8 @@
mDevice(client->getCameraDevice()),
mSequencer(sequencer),
mId(client->getCameraId()),
- mCaptureAvailable(false),
+ mCaptureDone(false),
+ mCaptureSuccess(false),
mCaptureStreamId(NO_STREAM) {
}
@@ -53,9 +54,26 @@
void JpegProcessor::onFrameAvailable(const BufferItem& /*item*/) {
Mutex::Autolock l(mInputMutex);
- if (!mCaptureAvailable) {
- mCaptureAvailable = true;
- mCaptureAvailableSignal.signal();
+ ALOGV("%s", __FUNCTION__);
+ if (!mCaptureDone) {
+ mCaptureDone = true;
+ mCaptureSuccess = true;
+ mCaptureDoneSignal.signal();
+ }
+}
+
+void JpegProcessor::onBufferAcquired(const BufferInfo& /*bufferInfo*/) {
+ // Intentionally left empty
+}
+
+void JpegProcessor::onBufferReleased(const BufferInfo& bufferInfo) {
+ Mutex::Autolock l(mInputMutex);
+ ALOGV("%s", __FUNCTION__);
+
+ if (bufferInfo.mError) {
+ mCaptureDone = true;
+ mCaptureSuccess = false;
+ mCaptureDoneSignal.signal();
}
}
@@ -154,6 +172,12 @@
return res;
}
+ res = device->addBufferListenerForStream(mCaptureStreamId, this);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't add buffer listeneri: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
}
return OK;
}
@@ -192,24 +216,26 @@
bool JpegProcessor::threadLoop() {
status_t res;
+ bool captureSuccess = false;
{
Mutex::Autolock l(mInputMutex);
- while (!mCaptureAvailable) {
- res = mCaptureAvailableSignal.waitRelative(mInputMutex,
+
+ while (!mCaptureDone) {
+ res = mCaptureDoneSignal.waitRelative(mInputMutex,
kWaitDuration);
if (res == TIMED_OUT) return true;
}
- mCaptureAvailable = false;
+
+ captureSuccess = mCaptureSuccess;
+ mCaptureDone = false;
}
- do {
- res = processNewCapture();
- } while (res == OK);
+ res = processNewCapture(captureSuccess);
return true;
}
-status_t JpegProcessor::processNewCapture() {
+status_t JpegProcessor::processNewCapture(bool captureSuccess) {
ATRACE_CALL();
status_t res;
sp<Camera2Heap> captureHeap;
@@ -217,7 +243,7 @@
CpuConsumer::LockedBuffer imgBuffer;
- {
+ if (captureSuccess) {
Mutex::Autolock l(mInputMutex);
if (mCaptureStreamId == NO_STREAM) {
ALOGW("%s: Camera %d: No stream is available", __FUNCTION__, mId);
@@ -269,7 +295,7 @@
sp<CaptureSequencer> sequencer = mSequencer.promote();
if (sequencer != 0) {
- sequencer->onCaptureAvailable(imgBuffer.timestamp, captureBuffer);
+ sequencer->onCaptureAvailable(imgBuffer.timestamp, captureBuffer, !captureSuccess);
}
return OK;
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.h b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
index ac6f5c7..7187ad9 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
@@ -41,7 +41,8 @@
* Still image capture output image processing
*/
class JpegProcessor:
- public Thread, public CpuConsumer::FrameAvailableListener {
+ public Thread, public CpuConsumer::FrameAvailableListener,
+ public camera3::Camera3StreamBufferListener {
public:
JpegProcessor(sp<Camera2Client> client, wp<CaptureSequencer> sequencer);
~JpegProcessor();
@@ -49,6 +50,10 @@
// CpuConsumer listener implementation
void onFrameAvailable(const BufferItem& item);
+ // Camera3StreamBufferListener implementation
+ void onBufferAcquired(const BufferInfo& bufferInfo) override;
+ void onBufferReleased(const BufferInfo& bufferInfo) override;
+
status_t updateStream(const Parameters ¶ms);
status_t deleteStream();
int getStreamId() const;
@@ -61,8 +66,9 @@
int mId;
mutable Mutex mInputMutex;
- bool mCaptureAvailable;
- Condition mCaptureAvailableSignal;
+ bool mCaptureDone;
+ bool mCaptureSuccess;
+ Condition mCaptureDoneSignal;
enum {
NO_STREAM = -1
@@ -75,7 +81,7 @@
virtual bool threadLoop();
- status_t processNewCapture();
+ status_t processNewCapture(bool captureSuccess);
size_t findJpegSize(uint8_t* jpegBuffer, size_t maxSize);
};
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index ccb3bc8..d570d4b 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -296,6 +296,12 @@
virtual status_t tearDown(int streamId) = 0;
/**
+ * Add buffer listener for a particular stream in the device.
+ */
+ virtual status_t addBufferListenerForStream(int streamId,
+ wp<camera3::Camera3StreamBufferListener> listener) = 0;
+
+ /**
* Prepare stream by preallocating up to maxCount buffers for it asynchronously.
* Calls notifyPrepared() once allocation is complete.
*/
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 331f10d..1caf157 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1652,6 +1652,26 @@
return stream->tearDown();
}
+status_t Camera3Device::addBufferListenerForStream(int streamId,
+ wp<Camera3StreamBufferListener> listener) {
+ ATRACE_CALL();
+ ALOGV("%s: Camera %d: Adding buffer listener for stream %d", __FUNCTION__, mId, streamId);
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ sp<Camera3StreamInterface> stream;
+ ssize_t outputStreamIdx = mOutputStreams.indexOfKey(streamId);
+ if (outputStreamIdx == NAME_NOT_FOUND) {
+ CLOGE("Stream %d does not exist", streamId);
+ return BAD_VALUE;
+ }
+
+ stream = mOutputStreams.editValueAt(outputStreamIdx);
+ stream->addBufferListener(listener);
+
+ return OK;
+}
+
uint32_t Camera3Device::getDeviceVersion() {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index ba092d0..96ca7b7 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -146,6 +146,9 @@
virtual status_t tearDown(int streamId);
+ virtual status_t addBufferListenerForStream(int streamId,
+ wp<camera3::Camera3StreamBufferListener> listener);
+
virtual status_t prepare(int maxCount, int streamId);
virtual uint32_t getDeviceVersion();
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 50f7a91..a4714a7 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -560,7 +560,7 @@
}
void Camera3Stream::fireBufferListenersLocked(
- const camera3_stream_buffer& /*buffer*/, bool acquired, bool output) {
+ const camera3_stream_buffer& buffer, bool acquired, bool output) {
List<wp<Camera3StreamBufferListener> >::iterator it, end;
// TODO: finish implementing
@@ -568,6 +568,7 @@
Camera3StreamBufferListener::BufferInfo info =
Camera3StreamBufferListener::BufferInfo();
info.mOutput = output;
+ info.mError = (buffer.status == CAMERA3_BUFFER_STATUS_ERROR);
// TODO: rest of fields
for (it = mBufferListenerList.begin(), end = mBufferListenerList.end();
diff --git a/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h b/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
index 62ea6c0..2db333d 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
@@ -34,6 +34,7 @@
uint32_t mScalingMode;
int64_t mTimestamp;
uint64_t mFrameNumber;
+ bool mError;
};
// Buffer was acquired by the HAL