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
gugelfrei
Shuzhen Wang 6 years ago
parent daba8f4f19
commit b3a0fb55cf

@ -2261,8 +2261,8 @@ sp<Camera3Device::CaptureRequest> 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::CaptureRequest> 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<Camera3StreamIn
Mutex::Autolock l(mLock);
sp<NotificationListener> 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());

@ -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<size_t>(maxCount)) ?
pipelineMax : static_cast<size_t>(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 {

@ -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<camera3_stream_buffer_t> mPreparedBuffers;
size_t mPreparedBufferIdx;

@ -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

Loading…
Cancel
Save