From 6adc9ccb2948d9421a0ed4b74f52b909bcec2037 Mon Sep 17 00:00:00 2001 From: Zhijun He Date: Tue, 15 Apr 2014 14:09:55 -0700 Subject: Camera3: block until get an available buffer Camera3Stream shouldn't error out when the max number of buffers are already dequeued. It should block until next buffer returned from camera device. Bug: 11595505 Change-Id: If65a70c29cb04219e14ded0744059c0ab783444b --- .../device3/Camera3IOStreamBase.cpp | 44 +++++++++++++------ .../libcameraservice/device3/Camera3IOStreamBase.h | 12 +++++- .../device3/Camera3InputStream.cpp | 4 +- .../device3/Camera3OutputStream.cpp | 4 +- .../libcameraservice/device3/Camera3Stream.cpp | 50 +++++++++++++++++++++- .../libcameraservice/device3/Camera3Stream.h | 9 ++++ .../libcameraservice/device3/Camera3ZslStream.cpp | 2 +- 7 files changed, 103 insertions(+), 22 deletions(-) (limited to 'services/camera') diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp index 2257682..50a2c10 100644 --- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp +++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp @@ -34,7 +34,8 @@ Camera3IOStreamBase::Camera3IOStreamBase(int id, camera3_stream_type_t type, Camera3Stream(id, type, width, height, maxSize, format), mTotalBufferCount(0), - mDequeuedBufferCount(0), + mHandoutTotalBufferCount(0), + mHandoutOutputBufferCount(0), mFrameCount(0), mLastTimestamp(0) { @@ -55,8 +56,8 @@ bool Camera3IOStreamBase::hasOutstandingBuffersLocked() const { nsecs_t signalTime = mCombinedFence->getSignalTime(); ALOGV("%s: Stream %d: Has %zu outstanding buffers," " buffer signal time is %" PRId64, - __FUNCTION__, mId, mDequeuedBufferCount, signalTime); - if (mDequeuedBufferCount > 0 || signalTime == INT64_MAX) { + __FUNCTION__, mId, mHandoutTotalBufferCount, signalTime); + if (mHandoutTotalBufferCount > 0 || signalTime == INT64_MAX) { return true; } return false; @@ -75,7 +76,7 @@ void Camera3IOStreamBase::dump(int fd, const Vector &args) const { lines.appendFormat(" Frames produced: %d, last timestamp: %" PRId64 " ns\n", mFrameCount, mLastTimestamp); lines.appendFormat(" Total buffers: %zu, currently dequeued: %zu\n", - mTotalBufferCount, mDequeuedBufferCount); + mTotalBufferCount, mHandoutTotalBufferCount); write(fd, lines.string(), lines.size()); } @@ -104,6 +105,14 @@ size_t Camera3IOStreamBase::getBufferCountLocked() { return mTotalBufferCount; } +size_t Camera3IOStreamBase::getHandoutOutputBufferCountLocked() { + return mHandoutOutputBufferCount; +} + +size_t Camera3IOStreamBase::getHandoutInputBufferCountLocked() { + return (mHandoutTotalBufferCount - mHandoutOutputBufferCount); +} + status_t Camera3IOStreamBase::disconnectLocked() { switch (mState) { case STATE_IN_RECONFIG: @@ -117,9 +126,9 @@ status_t Camera3IOStreamBase::disconnectLocked() { return -ENOTCONN; } - if (mDequeuedBufferCount > 0) { + if (mHandoutTotalBufferCount > 0) { ALOGE("%s: Can't disconnect with %zu buffers still dequeued!", - __FUNCTION__, mDequeuedBufferCount); + __FUNCTION__, mHandoutTotalBufferCount); return INVALID_OPERATION; } @@ -130,7 +139,8 @@ void Camera3IOStreamBase::handoutBufferLocked(camera3_stream_buffer &buffer, buffer_handle_t *handle, int acquireFence, int releaseFence, - camera3_buffer_status_t status) { + camera3_buffer_status_t status, + bool output) { /** * Note that all fences are now owned by HAL. */ @@ -144,7 +154,7 @@ void Camera3IOStreamBase::handoutBufferLocked(camera3_stream_buffer &buffer, buffer.status = status; // Inform tracker about becoming busy - if (mDequeuedBufferCount == 0 && mState != STATE_IN_CONFIG && + if (mHandoutTotalBufferCount == 0 && mState != STATE_IN_CONFIG && mState != STATE_IN_RECONFIG) { /** * Avoid a spurious IDLE->ACTIVE->IDLE transition when using buffers @@ -158,7 +168,11 @@ void Camera3IOStreamBase::handoutBufferLocked(camera3_stream_buffer &buffer, statusTracker->markComponentActive(mStatusId); } } - mDequeuedBufferCount++; + mHandoutTotalBufferCount++; + + if (output) { + mHandoutOutputBufferCount++; + } } status_t Camera3IOStreamBase::getBufferPreconditionCheckLocked() const { @@ -172,7 +186,7 @@ status_t Camera3IOStreamBase::getBufferPreconditionCheckLocked() const { // Only limit dequeue amount when fully configured if (mState == STATE_CONFIGURED && - mDequeuedBufferCount == camera3_stream::max_buffers) { + mHandoutTotalBufferCount == camera3_stream::max_buffers) { ALOGE("%s: Stream %d: Already dequeued maximum number of simultaneous" " buffers (%d)", __FUNCTION__, mId, camera3_stream::max_buffers); @@ -190,7 +204,7 @@ status_t Camera3IOStreamBase::returnBufferPreconditionCheckLocked() const { __FUNCTION__, mId, mState); return INVALID_OPERATION; } - if (mDequeuedBufferCount == 0) { + if (mHandoutTotalBufferCount == 0) { ALOGE("%s: Stream %d: No buffers outstanding to return", __FUNCTION__, mId); return INVALID_OPERATION; @@ -228,8 +242,12 @@ status_t Camera3IOStreamBase::returnAnyBufferLocked( mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence); } - mDequeuedBufferCount--; - if (mDequeuedBufferCount == 0 && mState != STATE_IN_CONFIG && + if (output) { + mHandoutOutputBufferCount--; + } + + mHandoutTotalBufferCount--; + if (mHandoutTotalBufferCount == 0 && mState != STATE_IN_CONFIG && mState != STATE_IN_RECONFIG) { /** * Avoid a spurious IDLE->ACTIVE->IDLE transition when using buffers diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h index fcb9d04..a35c290 100644 --- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h +++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h @@ -48,7 +48,10 @@ class Camera3IOStreamBase : protected: size_t mTotalBufferCount; // sum of input and output buffers that are currently acquired by HAL - size_t mDequeuedBufferCount; + size_t mHandoutTotalBufferCount; + // number of output buffers that are currently acquired by HAL. This will be + // Redundant when camera3 streams are no longer bidirectional streams. + size_t mHandoutOutputBufferCount; Condition mBufferReturnedSignal; uint32_t mFrameCount; // Last received output buffer's timestamp @@ -76,6 +79,10 @@ class Camera3IOStreamBase : virtual size_t getBufferCountLocked(); + virtual size_t getHandoutOutputBufferCountLocked(); + + virtual size_t getHandoutInputBufferCountLocked(); + virtual status_t getEndpointUsage(uint32_t *usage) = 0; status_t getBufferPreconditionCheckLocked() const; @@ -92,7 +99,8 @@ class Camera3IOStreamBase : buffer_handle_t *handle, int acquire_fence, int release_fence, - camera3_buffer_status_t status); + camera3_buffer_status_t status, + bool output); }; // class Camera3IOStreamBase diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp index dd7fb6c..319be1d 100644 --- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp @@ -81,7 +81,7 @@ status_t Camera3InputStream::getInputBufferLocked( * in which case we reassign it to acquire_fence */ handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd, - /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK); + /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/false); mBuffersInFlight.push_back(bufferItem); return OK; @@ -199,7 +199,7 @@ status_t Camera3InputStream::configureQueueLocked() { assert(mMaxSize == 0); assert(camera3_stream::format != HAL_PIXEL_FORMAT_BLOB); - mDequeuedBufferCount = 0; + mHandoutTotalBufferCount = 0; mFrameCount = 0; if (mConsumer.get() == 0) { diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp index 682755d..7ec649b 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp @@ -119,7 +119,7 @@ status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) { * in which case we reassign it to acquire_fence */ handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd, - /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK); + /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/true); return OK; } @@ -324,7 +324,7 @@ status_t Camera3OutputStream::configureQueueLocked() { } mTotalBufferCount = maxConsumerBuffers + camera3_stream::max_buffers; - mDequeuedBufferCount = 0; + mHandoutTotalBufferCount = 0; mFrameCount = 0; mLastTimestamp = 0; diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 646f286..abfb602 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -212,8 +212,30 @@ status_t Camera3Stream::finishConfiguration(camera3_device *hal3Device) { status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) { ATRACE_CALL(); Mutex::Autolock l(mLock); + status_t res = OK; - status_t res = getBufferLocked(buffer); + // This function should be only called when the stream is configured already. + if (mState != STATE_CONFIGURED) { + ALOGE("%s: Stream %d: Can't get buffers if stream is not in CONFIGURED state %d", + __FUNCTION__, mId, mState); + return INVALID_OPERATION; + } + + // Wait for new buffer returned back if we are running into the limit. + if (getHandoutOutputBufferCountLocked() == camera3_stream::max_buffers) { + ALOGV("%s: Already dequeued max output buffers (%d), wait for next returned one.", + __FUNCTION__, camera3_stream::max_buffers); + res = mOutputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration); + if (res != OK) { + if (res == TIMED_OUT) { + ALOGE("%s: wait for output buffer return timed out after %lldms", __FUNCTION__, + kWaitForBufferDuration / 1000000LL); + } + return res; + } + } + + res = getBufferLocked(buffer); if (res == OK) { fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/true); } @@ -237,6 +259,7 @@ status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer, status_t res = returnBufferLocked(buffer, timestamp); if (res == OK) { fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/true); + mOutputBufferReturnedSignal.signal(); } return res; @@ -245,8 +268,30 @@ status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer, status_t Camera3Stream::getInputBuffer(camera3_stream_buffer *buffer) { ATRACE_CALL(); Mutex::Autolock l(mLock); + status_t res = OK; + + // This function should be only called when the stream is configured already. + if (mState != STATE_CONFIGURED) { + ALOGE("%s: Stream %d: Can't get input buffers if stream is not in CONFIGURED state %d", + __FUNCTION__, mId, mState); + return INVALID_OPERATION; + } + + // Wait for new buffer returned back if we are running into the limit. + if (getHandoutInputBufferCountLocked() == camera3_stream::max_buffers) { + ALOGV("%s: Already dequeued max input buffers (%d), wait for next returned one.", + __FUNCTION__, camera3_stream::max_buffers); + res = mInputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration); + if (res != OK) { + if (res == TIMED_OUT) { + ALOGE("%s: wait for input buffer return timed out after %lldms", __FUNCTION__, + kWaitForBufferDuration / 1000000LL); + } + return res; + } + } - status_t res = getInputBufferLocked(buffer); + res = getInputBufferLocked(buffer); if (res == OK) { fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/false); } @@ -261,6 +306,7 @@ status_t Camera3Stream::returnInputBuffer(const camera3_stream_buffer &buffer) { status_t res = returnInputBufferLocked(buffer); if (res == OK) { fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/false); + mInputBufferReturnedSignal.signal(); } return res; } diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h index 766b772..14f5387 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.h +++ b/services/camera/libcameraservice/device3/Camera3Stream.h @@ -279,6 +279,12 @@ class Camera3Stream : // Get the total number of buffers in the queue virtual size_t getBufferCountLocked() = 0; + // Get handout output buffer count. + virtual size_t getHandoutOutputBufferCountLocked() = 0; + + // Get handout input buffer count. + virtual size_t getHandoutInputBufferCountLocked() = 0; + // Get the usage flags for the other endpoint, or return // INVALID_OPERATION if they cannot be obtained. virtual status_t getEndpointUsage(uint32_t *usage) = 0; @@ -291,6 +297,9 @@ class Camera3Stream : private: uint32_t oldUsage; uint32_t oldMaxBuffers; + Condition mOutputBufferReturnedSignal; + Condition mInputBufferReturnedSignal; + static const nsecs_t kWaitForBufferDuration = 3000000000LL; // 3000 ms // Gets all buffers from endpoint and registers them with the HAL. status_t registerBuffersLocked(camera3_device *hal3Device); diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp index 09e14c5..05b3d1f 100644 --- a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp @@ -176,7 +176,7 @@ status_t Camera3ZslStream::getInputBufferLocked(camera3_stream_buffer *buffer) { * in which case we reassign it to acquire_fence */ handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd, - /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK); + /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/false); mBuffersInFlight.push_back(bufferItem); -- cgit v1.1