am 76dea1de: libstagefright: check overflow before memory allocation in OMXCodec.cpp

* commit '76dea1de8c92588358923300cbbc038144d302eb':
  libstagefright: check overflow before memory allocation in OMXCodec.cpp
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/media/img_utils/include/img_utils/DngUtils.h b/media/img_utils/include/img_utils/DngUtils.h
index 3dcedc5..1d8df9c 100644
--- a/media/img_utils/include/img_utils/DngUtils.h
+++ b/media/img_utils/include/img_utils/DngUtils.h
@@ -138,6 +138,34 @@
                                             double opticalCenterY,
                                             const double* kCoeffs);
 
+
+        /**
+         * Add FixBadPixelsList opcode for the given metadata parameters.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t addBadPixelListForMetadata(const uint32_t* hotPixels,
+                                                    uint32_t xyPairCount,
+                                                    uint32_t colorFilterArrangement);
+
+        /**
+         * Add FixBadPixelsList opcode.
+         *
+         * bayerPhase - 0=top-left of image is red, 1=top-left of image is green pixel in red row,
+         *              2=top-left of image is green pixel in blue row, 3=top-left of image is
+         *              blue.
+         * badPointCount - number of (x,y) pairs of bad pixels are given in badPointRowColPairs.
+         * badRectCount - number of (top, left, bottom, right) tuples are given in
+         *              badRectTopLeftBottomRightTuples
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t addBadPixelList(uint32_t bayerPhase,
+                                         uint32_t badPointCount,
+                                         uint32_t badRectCount,
+                                         const uint32_t* badPointRowColPairs,
+                                         const uint32_t* badRectTopLeftBottomRightTuples);
+
         // TODO: Add other Opcode methods
     protected:
         static const uint32_t FLAG_OPTIONAL = 0x1u;
@@ -146,6 +174,7 @@
         // Opcode IDs
         enum {
             WARP_RECTILINEAR_ID = 1,
+            FIX_BAD_PIXELS_LIST = 5,
             GAIN_MAP_ID = 9,
         };
 
@@ -161,6 +190,8 @@
         ByteArrayOutput mOpList;
         EndianOutput mEndianOut;
 
+        status_t addOpcodePreamble(uint32_t opcodeId);
+
 };
 
 } /*namespace img_utils*/
diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp
index b213403..9473dce 100644
--- a/media/img_utils/src/DngUtils.cpp
+++ b/media/img_utils/src/DngUtils.cpp
@@ -224,13 +224,7 @@
                                        uint32_t mapPlanes,
                                        const float* mapGains) {
 
-    uint32_t opcodeId = GAIN_MAP_ID;
-
-    status_t err = mEndianOut.write(&opcodeId, 0, 1);
-    if (err != OK) return err;
-
-    uint8_t version[] = {1, 3, 0, 0};
-    err = mEndianOut.write(version, 0, NELEMS(version));
+    status_t err = addOpcodePreamble(GAIN_MAP_ID);
     if (err != OK) return err;
 
     // Allow this opcode to be skipped if not supported
@@ -334,13 +328,7 @@
                                                double opticalCenterY,
                                                const double* kCoeffs) {
 
-    uint32_t opcodeId = WARP_RECTILINEAR_ID;
-
-    status_t err = mEndianOut.write(&opcodeId, 0, 1);
-    if (err != OK) return err;
-
-    uint8_t version[] = {1, 3, 0, 0};
-    err = mEndianOut.write(version, 0, NELEMS(version));
+    status_t err = addOpcodePreamble(WARP_RECTILINEAR_ID);
     if (err != OK) return err;
 
     // Allow this opcode to be skipped if not supported
@@ -373,5 +361,74 @@
     return OK;
 }
 
+status_t OpcodeListBuilder::addBadPixelListForMetadata(const uint32_t* hotPixels,
+                                                       uint32_t xyPairCount,
+                                                       uint32_t colorFilterArrangement) {
+    if (colorFilterArrangement > 3) {
+        ALOGE("%s:  Unknown color filter arrangement %" PRIu32, __FUNCTION__,
+                colorFilterArrangement);
+        return BAD_VALUE;
+    }
+
+    return addBadPixelList(colorFilterArrangement, xyPairCount, 0, hotPixels, nullptr);
+}
+
+status_t OpcodeListBuilder::addBadPixelList(uint32_t bayerPhase,
+                                            uint32_t badPointCount,
+                                            uint32_t badRectCount,
+                                            const uint32_t* badPointRowColPairs,
+                                            const uint32_t* badRectTopLeftBottomRightTuples) {
+
+    status_t err = addOpcodePreamble(FIX_BAD_PIXELS_LIST);
+    if (err != OK) return err;
+
+    // Allow this opcode to be skipped if not supported
+    uint32_t flags = FLAG_OPTIONAL;
+
+    err = mEndianOut.write(&flags, 0, 1);
+    if (err != OK) return err;
+
+    const uint32_t NUM_NON_VARLEN_FIELDS = 3;
+    const uint32_t SIZE_OF_POINT = 2;
+    const uint32_t SIZE_OF_RECT = 4;
+
+    uint32_t totalSize =  (NUM_NON_VARLEN_FIELDS  + badPointCount * SIZE_OF_POINT +
+            badRectCount * SIZE_OF_RECT) * sizeof(uint32_t);
+    err = mEndianOut.write(&totalSize, 0, 1);
+    if (err != OK) return err;
+
+    err = mEndianOut.write(&bayerPhase, 0, 1);
+    if (err != OK) return err;
+
+    err = mEndianOut.write(&badPointCount, 0, 1);
+    if (err != OK) return err;
+
+    err = mEndianOut.write(&badRectCount, 0, 1);
+    if (err != OK) return err;
+
+    if (badPointCount > 0) {
+        err = mEndianOut.write(badPointRowColPairs, 0, SIZE_OF_POINT * badPointCount);
+        if (err != OK) return err;
+    }
+
+    if (badRectCount > 0) {
+        err = mEndianOut.write(badRectTopLeftBottomRightTuples, 0, SIZE_OF_RECT * badRectCount);
+        if (err != OK) return err;
+    }
+
+    mCount++;
+    return OK;
+}
+
+status_t OpcodeListBuilder::addOpcodePreamble(uint32_t opcodeId) {
+    status_t err = mEndianOut.write(&opcodeId, 0, 1);
+    if (err != OK) return err;
+
+    uint8_t version[] = {1, 3, 0, 0};
+    err = mEndianOut.write(version, 0, NELEMS(version));
+    if (err != OK) return err;
+    return OK;
+}
+
 } /*namespace img_utils*/
 } /*namespace android*/
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 58ff113..af0351e 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -134,7 +134,9 @@
             return;
         }
     }
-    mHandler->pause();
+    if (mHandler != NULL) {
+        mHandler->pause();
+    }
 }
 
 void NuPlayer::RTSPSource::resume() {
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 3505844..6e4a1dd 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -290,6 +290,10 @@
 
 status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) {
     int64_t timeUs = systemTime() / 1000ll;
+    // Estimate the real sampling time of the 1st sample in this buffer
+    // from AudioRecord's latency. (Apply this adjustment first so that
+    // the start time logic is not affected.)
+    timeUs -= mRecord->latency() * 1000LL;
 
     ALOGV("dataCallbackTimestamp: %" PRId64 " us", timeUs);
     Mutex::Autolock autoLock(mLock);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e7f6864..b1d7b13 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1066,7 +1066,7 @@
     *delayMs = 0;
     if (stream == AUDIO_STREAM_TTS) {
         ALOGV("\t found BEACON stream");
-        if (mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) {
+        if (!mTtsOutputAvailable && mOutputs.isAnyOutputActive(AUDIO_STREAM_TTS /*streamToIgnore*/)) {
             return INVALID_OPERATION;
         } else {
             beaconMuteLatency = handleEventForBeacon(STARTING_BEACON);
@@ -2000,6 +2000,9 @@
     snprintf(buffer, SIZE, " Force use for hdmi system audio %d\n",
             mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO));
     result.append(buffer);
+    snprintf(buffer, SIZE, " TTS output %s\n", mTtsOutputAvailable ? "available" : "not available");
+    result.append(buffer);
+
     write(fd, result.string(), result.size());
 
     mAvailableOutputDevices.dump(fd, String8("output"));
@@ -2680,7 +2683,8 @@
     mAudioPortGeneration(1),
     mBeaconMuteRefCount(0),
     mBeaconPlayingRefCount(0),
-    mBeaconMuted(false)
+    mBeaconMuted(false),
+    mTtsOutputAvailable(false)
 {
     audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
     if (!engineInstance) {
@@ -2737,6 +2741,9 @@
                 ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName);
                 continue;
             }
+            if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_TTS) != 0) {
+                mTtsOutputAvailable = true;
+            }
 
             if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
                 continue;
@@ -4036,6 +4043,12 @@
 }
 
 uint32_t AudioPolicyManager::handleEventForBeacon(int event) {
+
+    // skip beacon mute management if a dedicated TTS output is available
+    if (mTtsOutputAvailable) {
+        return 0;
+    }
+
     switch(event) {
     case STARTING_OUTPUT:
         mBeaconMuteRefCount++;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index bf3ae4a..bbdf396 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -548,6 +548,7 @@
         uint32_t mBeaconMuteRefCount;   // ref count for stream that would mute beacon
         uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams
         bool mBeaconMuted;              // has STREAM_TTS been muted
+        bool mTtsOutputAvailable;       // true if a dedicated output for TTS stream is available
 
         AudioPolicyMixCollection mPolicyMixes; // list of registered mixes
 
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 0c941fb..e4d75cb 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1408,6 +1408,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);
@@ -1432,7 +1436,7 @@
         return BAD_VALUE;
     }
 
-    return mPreparerThread->prepare(stream);
+    return mPreparerThread->prepare(maxCount, stream);
 }
 
 status_t Camera3Device::tearDown(int streamId) {
@@ -3478,12 +3482,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 5287058..1f39940 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;
@@ -698,10 +701,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.