Add experimental camera session prepare API.

Bug: 18949148
Change-Id: I8f73e68ea2e3acc60d98954106f364d13f439a82
diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp
index d2dc200..2a9fd2b 100644
--- a/camera/camera2/ICameraDeviceUser.cpp
+++ b/camera/camera2/ICameraDeviceUser.cpp
@@ -49,7 +49,8 @@
     WAIT_UNTIL_IDLE,
     FLUSH,
     PREPARE,
-    TEAR_DOWN
+    TEAR_DOWN,
+    PREPARE2
 };
 
 namespace {
@@ -366,6 +367,21 @@
         return reply.readInt32();
     }
 
+    virtual status_t prepare2(int maxCount, int streamId)
+    {
+        ALOGV("prepare2");
+        Parcel data, reply;
+
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        data.writeInt32(maxCount);
+        data.writeInt32(streamId);
+
+        remote()->transact(PREPARE2, data, &reply);
+
+        reply.readExceptionCode();
+        return reply.readInt32();
+    }
+
     virtual status_t tearDown(int streamId)
     {
         ALOGV("tearDown");
@@ -592,7 +608,14 @@
             reply->writeInt32(tearDown(streamId));
             return NO_ERROR;
         } break;
-
+        case PREPARE2: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+            int maxCount = data.readInt32();
+            int streamId = data.readInt32();
+            reply->writeNoException();
+            reply->writeInt32(prepare2(maxCount, streamId));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/include/camera/camera2/ICameraDeviceUser.h b/include/camera/camera2/ICameraDeviceUser.h
index a7bf8ab..4d8eb53 100644
--- a/include/camera/camera2/ICameraDeviceUser.h
+++ b/include/camera/camera2/ICameraDeviceUser.h
@@ -140,6 +140,11 @@
     virtual status_t        prepare(int streamId) = 0;
 
     /**
+     * Preallocate up to maxCount buffers for a given output stream asynchronously.
+     */
+    virtual status_t        prepare2(int maxCount, int streamId) = 0;
+
+    /**
      * Free all unused buffers for a given output stream.
      */
     virtual status_t        tearDown(int streamId) = 0;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index c717a56..f6a0221 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -719,6 +719,43 @@
     return res;
 }
 
+status_t CameraDeviceClient::prepare2(int maxCount, int streamId) {
+    ATRACE_CALL();
+    ALOGV("%s", __FUNCTION__);
+
+    status_t res = OK;
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    // Guard against trying to prepare non-created streams
+    ssize_t index = NAME_NOT_FOUND;
+    for (size_t i = 0; i < mStreamMap.size(); ++i) {
+        if (streamId == mStreamMap.valueAt(i)) {
+            index = i;
+            break;
+        }
+    }
+
+    if (index == NAME_NOT_FOUND) {
+        ALOGW("%s: Camera %d: Invalid stream ID (%d) specified, no stream created yet",
+                __FUNCTION__, mCameraId, streamId);
+        return BAD_VALUE;
+    }
+
+    if (maxCount <= 0) {
+        ALOGE("%s: Camera %d: Invalid maxCount (%d) specified, must be greater than 0.",
+                __FUNCTION__, mCameraId, maxCount);
+        return BAD_VALUE;
+    }
+
+    // Also returns BAD_VALUE if stream ID was not valid, or stream already
+    // has been used
+    res = mDevice->prepare(maxCount, streamId);
+
+    return res;
+}
+
 status_t CameraDeviceClient::tearDown(int streamId) {
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 1f8b39d..0b73f6c 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -114,6 +114,9 @@
     // Tear down stream resources by freeing its unused buffers
     virtual status_t      tearDown(int streamId);
 
+    // Prepare stream by preallocating up to maxCount of its buffers
+    virtual status_t      prepare2(int maxCount, int streamId);
+
     /**
      * Interface used by CameraService
      */
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index cd25949..7b083a3 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -294,6 +294,12 @@
     virtual status_t tearDown(int streamId) = 0;
 
     /**
+     * Prepare stream by preallocating up to maxCount buffers for it asynchronously.
+     * Calls notifyPrepared() once allocation is complete.
+     */
+    virtual status_t prepare(int maxCount, int streamId) = 0;
+
+    /**
      * Get the HAL device version.
      */
     virtual uint32_t getDeviceVersion() = 0;
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
index c9c990c..d74f976 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ b/services/camera/libcameraservice/device2/Camera2Device.cpp
@@ -632,6 +632,12 @@
     return NO_INIT;
 }
 
+status_t Camera2Device::prepare(int maxCount, int streamId) {
+    ATRACE_CALL();
+    ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId);
+    return NO_INIT;
+}
+
 uint32_t Camera2Device::getDeviceVersion() {
     ATRACE_CALL();
     return mDeviceVersion;
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
index 34c1ded..b4d343c 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ b/services/camera/libcameraservice/device2/Camera2Device.h
@@ -88,6 +88,7 @@
     // Prepare and tearDown are no-ops
     virtual status_t prepare(int streamId);
     virtual status_t tearDown(int streamId);
+    virtual status_t prepare(int maxCount, int streamId);
 
     virtual uint32_t getDeviceVersion();
     virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 0a4440f..cf47bc8 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1380,6 +1380,10 @@
 }
 
 status_t Camera3Device::prepare(int streamId) {
+    return prepare(camera3::Camera3StreamInterface::ALLOCATE_PIPELINE_MAX, streamId);
+}
+
+status_t Camera3Device::prepare(int maxCount, int streamId) {
     ATRACE_CALL();
     ALOGV("%s: Camera %d: Preparing stream %d", __FUNCTION__, mId, streamId);
     Mutex::Autolock il(mInterfaceLock);
@@ -1404,7 +1408,7 @@
         return BAD_VALUE;
     }
 
-    return mPreparerThread->prepare(stream);
+    return mPreparerThread->prepare(maxCount, stream);
 }
 
 status_t Camera3Device::tearDown(int streamId) {
@@ -3455,12 +3459,12 @@
     clear();
 }
 
-status_t Camera3Device::PreparerThread::prepare(sp<Camera3StreamInterface>& stream) {
+status_t Camera3Device::PreparerThread::prepare(int maxCount, sp<Camera3StreamInterface>& stream) {
     status_t res;
 
     Mutex::Autolock l(mLock);
 
-    res = stream->startPrepare();
+    res = stream->startPrepare(maxCount);
     if (res == OK) {
         // No preparation needed, fire listener right off
         ALOGV("%s: Stream %d already prepared", __FUNCTION__, stream->getId());
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 8bd0f8e..3ce6b0d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -62,6 +62,7 @@
             public CameraDeviceBase,
             private camera3_callback_ops {
   public:
+
     Camera3Device(int id);
 
     virtual ~Camera3Device();
@@ -143,6 +144,8 @@
 
     virtual status_t tearDown(int streamId);
 
+    virtual status_t prepare(int maxCount, int streamId);
+
     virtual uint32_t getDeviceVersion();
 
     virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
@@ -687,10 +690,11 @@
         void setNotificationListener(NotificationListener *listener);
 
         /**
-         * Queue up a stream to be prepared. Streams are processed by
-         * a background thread in FIFO order
+         * Queue up a stream to be prepared. Streams are processed by a background thread in FIFO
+         * order.  Pre-allocate up to maxCount buffers for the stream, or the maximum number needed
+         * for the pipeline if maxCount is ALLOCATE_PIPELINE_MAX.
          */
-        status_t prepare(sp<camera3::Camera3StreamInterface>& stream);
+        status_t prepare(int maxCount, sp<camera3::Camera3StreamInterface>& stream);
 
         /**
          * Cancel all current and pending stream preparation
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 2527fd6..7163d62 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -53,7 +53,8 @@
     mName(String8::format("Camera3Stream[%d]", id)),
     mMaxSize(maxSize),
     mState(STATE_CONSTRUCTED),
-    mStatusId(StatusTracker::NO_STATUS_ID) {
+    mStatusId(StatusTracker::NO_STATUS_ID),
+    mLastMaxCount(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX) {
 
     camera3_stream::stream_type = type;
     camera3_stream::width = width;
@@ -252,12 +253,18 @@
     return mStreamUnpreparable;
 }
 
-status_t Camera3Stream::startPrepare() {
+status_t Camera3Stream::startPrepare(int maxCount) {
     ATRACE_CALL();
 
     Mutex::Autolock l(mLock);
     status_t res = OK;
 
+    if (maxCount < 0) {
+        ALOGE("%s: Stream %d: Can't prepare stream if max buffer count (%d) is < 0",
+                __FUNCTION__, mId, maxCount);
+        return BAD_VALUE;
+    }
+
     // This function should be only called when the stream is configured already.
     if (mState != STATE_CONFIGURED) {
         ALOGE("%s: Stream %d: Can't prepare stream if stream is not in CONFIGURED "
@@ -279,9 +286,19 @@
         return INVALID_OPERATION;
     }
 
+
+
+    size_t pipelineMax = getBufferCountLocked();
+    size_t clampedCount = (pipelineMax < static_cast<size_t>(maxCount)) ?
+            pipelineMax : static_cast<size_t>(maxCount);
+    size_t bufferCount = (maxCount == Camera3StreamInterface::ALLOCATE_PIPELINE_MAX) ?
+            pipelineMax : clampedCount;
+
+    mPrepared = bufferCount <= mLastMaxCount;
+
     if (mPrepared) return OK;
 
-    size_t bufferCount = getBufferCountLocked();
+    mLastMaxCount = bufferCount;
 
     mPreparedBuffers.insertAt(camera3_stream_buffer_t(), /*index*/0, bufferCount);
     mPreparedBufferIdx = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index bab2177..753280b 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -188,7 +188,9 @@
 
     /**
      * Start stream preparation. May only be called in the CONFIGURED state,
-     * when no valid buffers have yet been returned to this stream.
+     * when no valid buffers have yet been returned to this stream. Prepares
+     * up to maxCount buffers, or the maximum number of buffers needed by the
+     * pipeline if maxCount is ALLOCATE_PIPELINE_MAX.
      *
      * If no prepartion is necessary, returns OK and does not transition to
      * PREPARING state. Otherwise, returns NOT_ENOUGH_DATA and transitions
@@ -204,7 +206,7 @@
      *    INVALID_OPERATION if called when not in CONFIGURED state, or a
      *        valid buffer has already been returned to this stream.
      */
-    status_t         startPrepare();
+    status_t         startPrepare(int maxCount);
 
     /**
      * Check if the stream is mid-preparing.
@@ -444,6 +446,9 @@
     Vector<camera3_stream_buffer_t> mPreparedBuffers;
     size_t mPreparedBufferIdx;
 
+    // Number of buffers allocated on last prepare call.
+    int mLastMaxCount;
+
 }; // class Camera3Stream
 
 }; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index c086eaf..54009ae 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -34,6 +34,11 @@
  */
 class Camera3StreamInterface : public virtual RefBase {
   public:
+
+    enum {
+        ALLOCATE_PIPELINE_MAX = 0, // Allocate max buffers used by a given surface
+    };
+
     /**
      * Get the stream's ID
      */
@@ -98,7 +103,9 @@
 
     /**
      * Start stream preparation. May only be called in the CONFIGURED state,
-     * when no valid buffers have yet been returned to this stream.
+     * when no valid buffers have yet been returned to this stream. Prepares
+     * up to maxCount buffers, or the maximum number of buffers needed by the
+     * pipeline if maxCount is ALLOCATE_PIPELINE_MAX.
      *
      * If no prepartion is necessary, returns OK and does not transition to
      * PREPARING state. Otherwise, returns NOT_ENOUGH_DATA and transitions
@@ -112,7 +119,7 @@
      *    INVALID_OPERATION if called when not in CONFIGURED state, or a
      *        valid buffer has already been returned to this stream.
      */
-    virtual status_t startPrepare() = 0;
+    virtual status_t startPrepare(int maxCount) = 0;
 
     /**
      * Check if the stream is mid-preparing.