OSDN Git Service

Camera3: block until get an available buffer
authorZhijun He <zhijunhe@google.com>
Tue, 15 Apr 2014 21:09:55 +0000 (14:09 -0700)
committerZhijun He <zhijunhe@google.com>
Sat, 19 Apr 2014 00:55:51 +0000 (17:55 -0700)
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

services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
services/camera/libcameraservice/device3/Camera3IOStreamBase.h
services/camera/libcameraservice/device3/Camera3InputStream.cpp
services/camera/libcameraservice/device3/Camera3OutputStream.cpp
services/camera/libcameraservice/device3/Camera3Stream.cpp
services/camera/libcameraservice/device3/Camera3Stream.h
services/camera/libcameraservice/device3/Camera3ZslStream.cpp

index 2257682..50a2c10 100644 (file)
@@ -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<String16> &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
index fcb9d04..a35c290 100644 (file)
@@ -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
 
index dd7fb6c..319be1d 100644 (file)
@@ -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) {
index 682755d..7ec649b 100644 (file)
@@ -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;
 
index 646f286..abfb602 100644 (file)
@@ -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;
 }
index 766b772..14f5387 100644 (file)
@@ -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);
index 09e14c5..05b3d1f 100644 (file)
@@ -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);