From b3a0fb55cf567043db7470f22f791858a62d2cbf Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Thu, 13 Sep 2018 17:24:08 -0700 Subject: [PATCH] Camera: Fix high speed recording failure due to prepare() In case application sends 2 consecutive setRepeatingBurst, the first request may be preparing the video stream, whiel the second request fails the isPreparing check. Fix this by distinguishing between internal and external prepare. For internal prepare, allow new requests to come through to the request thread. Bug: 114422231 Bug: 109830370 Test: Camera CTS Change-Id: I55a7271e3924f2cb8cf9c452e934b070a82bc4ca --- .../libcameraservice/device3/Camera3Device.cpp | 15 ++++++++------- .../libcameraservice/device3/Camera3Stream.cpp | 11 ++++++----- .../libcameraservice/device3/Camera3Stream.h | 12 +++++++++--- .../device3/Camera3StreamInterface.h | 11 ++++++++--- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 25c9d3c30e..c85d00fd5c 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -2261,8 +2261,8 @@ sp Camera3Device::createCaptureRequest( return NULL; } } - // Check if stream is being prepared - if (mInputStream->isPreparing()) { + // Check if stream prepare is blocking requests. + if (mInputStream->isBlockedByPrepare()) { CLOGE("Request references an input stream that's being prepared!"); return NULL; } @@ -2312,8 +2312,8 @@ sp Camera3Device::createCaptureRequest( return NULL; } } - // Check if stream is being prepared - if (stream->isPreparing()) { + // Check if stream prepare is blocking requests. + if (stream->isBlockedByPrepare()) { CLOGE("Request references an output stream that's being prepared!"); return NULL; } @@ -4871,7 +4871,8 @@ status_t Camera3Device::RequestThread::prepareHalRequests() { // Only try to prepare video stream on the first video request. mPrepareVideoStream = false; - res = outputStream->startPrepare(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX); + res = outputStream->startPrepare(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX, + false /*blockRequest*/); while (res == NOT_ENOUGH_DATA) { res = outputStream->prepareNextBuffer(); } @@ -5536,7 +5537,7 @@ status_t Camera3Device::PreparerThread::prepare(int maxCount, sp listener = mListener.promote(); - res = stream->startPrepare(maxCount); + res = stream->startPrepare(maxCount, true /*blockRequest*/); if (res == OK) { // No preparation needed, fire listener right off ALOGV("%s: Stream %d already prepared", __FUNCTION__, stream->getId()); @@ -5624,7 +5625,7 @@ status_t Camera3Device::PreparerThread::resume() { auto it = mPendingStreams.begin(); for (; it != mPendingStreams.end();) { - res = it->second->startPrepare(it->first); + res = it->second->startPrepare(it->first, true /*blockRequest*/); if (res == OK) { if (listener != NULL) { listener->notifyPrepared(it->second->getId()); diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 87476612a4..68703507df 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -61,6 +61,7 @@ Camera3Stream::Camera3Stream(int id, mOldUsage(0), mOldMaxBuffers(0), mPrepared(false), + mPrepareBlockRequest(true), mPreparedBufferIdx(0), mLastMaxCount(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX), mBufferLimitLatency(kBufferLimitLatencyBinSize), @@ -327,6 +328,7 @@ status_t Camera3Stream::finishConfiguration() { // Reset prepared state, since buffer config has changed, and existing // allocations are no longer valid mPrepared = false; + mPrepareBlockRequest = true; mStreamUnpreparable = false; status_t res; @@ -381,7 +383,7 @@ bool Camera3Stream::isUnpreparable() { return mStreamUnpreparable; } -status_t Camera3Stream::startPrepare(int maxCount) { +status_t Camera3Stream::startPrepare(int maxCount, bool blockRequest) { ATRACE_CALL(); Mutex::Autolock l(mLock); @@ -413,8 +415,6 @@ status_t Camera3Stream::startPrepare(int maxCount) { return INVALID_OPERATION; } - - size_t pipelineMax = getBufferCountLocked(); size_t clampedCount = (pipelineMax < static_cast(maxCount)) ? pipelineMax : static_cast(maxCount); @@ -422,6 +422,7 @@ status_t Camera3Stream::startPrepare(int maxCount) { pipelineMax : clampedCount; mPrepared = bufferCount <= mLastMaxCount; + mPrepareBlockRequest = blockRequest; if (mPrepared) return OK; @@ -435,9 +436,9 @@ status_t Camera3Stream::startPrepare(int maxCount) { return NOT_ENOUGH_DATA; } -bool Camera3Stream::isPreparing() const { +bool Camera3Stream::isBlockedByPrepare() const { Mutex::Autolock l(mLock); - return mState == STATE_PREPARING; + return mState == STATE_PREPARING && mPrepareBlockRequest; } bool Camera3Stream::isAbandoned() const { diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h index e6fb7f9f42..9c0f4c0e66 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.h +++ b/services/camera/libcameraservice/device3/Camera3Stream.h @@ -232,6 +232,11 @@ class Camera3Stream : * * This call performs no allocation, so is quick to call. * + * blockRequest specifies whether prepare will block upcoming capture + * request. This flag should only be set to false if the caller guarantees + * the whole buffer preparation process is done before capture request + * comes in. + * * Returns: * OK if no more buffers need to be preallocated * NOT_ENOUGH_DATA if calls to prepareNextBuffer are needed to finish @@ -240,12 +245,12 @@ class Camera3Stream : * INVALID_OPERATION if called when not in CONFIGURED state, or a * valid buffer has already been returned to this stream. */ - status_t startPrepare(int maxCount); + status_t startPrepare(int maxCount, bool blockRequest); /** - * Check if the stream is mid-preparing. + * Check if the request on a stream is blocked by prepare. */ - bool isPreparing() const; + bool isBlockedByPrepare() const; /** * Continue stream buffer preparation by allocating the next @@ -534,6 +539,7 @@ class Camera3Stream : // has been called sufficient number of times, or stream configuration // had to register buffers with the HAL bool mPrepared; + bool mPrepareBlockRequest; Vector mPreparedBuffers; size_t mPreparedBufferIdx; diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h index 2dde1c3258..3d45c8943a 100644 --- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h +++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h @@ -160,6 +160,11 @@ class Camera3StreamInterface : public virtual RefBase { * PREPARING state. Otherwise, returns NOT_ENOUGH_DATA and transitions * to PREPARING. * + * blockRequest specifies whether prepare will block upcoming capture + * request. This flag should only be set to false if the caller guarantees + * the whole buffer preparation process is done before capture request + * comes in. + * * Returns: * OK if no more buffers need to be preallocated * NOT_ENOUGH_DATA if calls to prepareNextBuffer are needed to finish @@ -168,12 +173,12 @@ class Camera3StreamInterface : public virtual RefBase { * INVALID_OPERATION if called when not in CONFIGURED state, or a * valid buffer has already been returned to this stream. */ - virtual status_t startPrepare(int maxCount) = 0; + virtual status_t startPrepare(int maxCount, bool blockRequest) = 0; /** - * Check if the stream is mid-preparing. + * Check if the request on a stream is blocked by prepare. */ - virtual bool isPreparing() const = 0; + virtual bool isBlockedByPrepare() const = 0; /** * Continue stream buffer preparation by allocating the next