Dynamically configure the number of video buffers used by camera source, if supported

o related-to-bug: 6920805

Change-Id: I413bb50954cc84e32ed40bcb713842dc7b58e2b6
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index 3f1a677..6e26b5f 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -58,7 +58,8 @@
         mCaptureStreamId(NO_STREAM),
         mCaptureRequest(NULL),
         mRecordingStreamId(NO_STREAM),
-        mRecordingRequest(NULL)
+        mRecordingRequest(NULL),
+        mRecordingHeapCount(kDefaultRecordingHeapCount)
 {
     ATRACE_CALL();
 
@@ -1544,6 +1545,30 @@
         } else {
             return NO_INIT;
         }
+    } else if (cmd == CAMERA_CMD_SET_VIDEO_BUFFER_COUNT) {
+        if (recordingEnabled()) {
+            ALOGE("%s: Camera %d: Error setting video buffer count after "
+                    "recording was started", __FUNCTION__, mCameraId);
+            return INVALID_OPERATION;
+        }
+
+        // 32 is the current upper limit on the video buffer count for BufferQueue
+        if (arg1 <= 0 || arg1 > 32) {
+            ALOGE("%s: Camera %d: Error setting %d as video buffer count value",
+                    __FUNCTION__, mCameraId, arg1);
+            return BAD_VALUE;
+        }
+
+        // Need to reallocate memory for heap
+        if (mRecordingHeapCount != arg1) {
+            if  (mRecordingHeap != 0) {
+                mRecordingHeap.clear();
+                mRecordingHeap = NULL;
+            }
+            mRecordingHeapCount = arg1;
+        }
+
+        return OK;
     }
 
     ALOGE("%s: Camera %d: Unimplemented command %d (%d, %d)", __FUNCTION__,
@@ -1649,17 +1674,17 @@
             const size_t bufferSize = 4 + sizeof(buffer_handle_t);
             ALOGV("%s: Camera %d: Creating recording heap with %d buffers of "
                     "size %d bytes", __FUNCTION__, mCameraId,
-                    kRecordingHeapCount, bufferSize);
+                    mRecordingHeapCount, bufferSize);
             if (mRecordingHeap != 0) {
                 ALOGV("%s: Camera %d: Previous heap has size %d "
                         "(new will be %d) bytes", __FUNCTION__, mCameraId,
                         mRecordingHeap->mHeap->getSize(),
-                        bufferSize * kRecordingHeapCount);
+                        bufferSize * mRecordingHeapCount);
             }
             // Need to allocate memory for heap
             mRecordingHeap.clear();
 
-            mRecordingHeap = new Camera2Heap(bufferSize, kRecordingHeapCount,
+            mRecordingHeap = new Camera2Heap(bufferSize, mRecordingHeapCount,
                     "Camera2Client::RecordingHeap");
             if (mRecordingHeap->mHeap->getSize() == 0) {
                 ALOGE("%s: Camera %d: Unable to allocate memory for recording",
@@ -1668,7 +1693,7 @@
                 return;
             }
             mRecordingHeapHead = 0;
-            mRecordingHeapFree = kRecordingHeapCount;
+            mRecordingHeapFree = mRecordingHeapCount;
         }
 
         if ( mRecordingHeapFree == 0) {
@@ -1678,7 +1703,7 @@
             return;
         }
         heapIdx = mRecordingHeapHead;
-        mRecordingHeapHead = (mRecordingHeapHead + 1) % kRecordingHeapCount;
+        mRecordingHeapHead = (mRecordingHeapHead + 1) % mRecordingHeapCount;
         mRecordingHeapFree--;
 
         ALOGV("%s: Camera %d: Timestamp %lld",
@@ -2688,7 +2713,7 @@
 
     if (mRecordingConsumer == 0) {
         // Create CPU buffer queue endpoint
-        mRecordingConsumer = new MediaConsumer(kRecordingHeapCount);
+        mRecordingConsumer = new MediaConsumer(mRecordingHeapCount);
         mRecordingConsumer->setFrameAvailableListener(new RecordingWaiter(this));
         mRecordingConsumer->setName(String8("Camera2Client::RecordingConsumer"));
         mRecordingWindow = new SurfaceTextureClient(
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
index 8ae16a4..9bea8f1 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -288,7 +288,8 @@
     // TODO: This needs to be queried from somewhere, or the BufferQueue needs
     // to be passed all the way to stagefright. Right now, set to a large number
     // to avoid starvation of the video encoders.
-    static const size_t kRecordingHeapCount = 8;
+    static const size_t kDefaultRecordingHeapCount = 8;
+    size_t mRecordingHeapCount;
     size_t mRecordingHeapHead, mRecordingHeapFree;
     // Handle new recording image buffers
     void onRecordingFrameAvailable();
diff --git a/services/camera/libcameraservice/CameraClient.cpp b/services/camera/libcameraservice/CameraClient.cpp
index 54829ef..562384d 100644
--- a/services/camera/libcameraservice/CameraClient.cpp
+++ b/services/camera/libcameraservice/CameraClient.cpp
@@ -619,6 +619,9 @@
         return OK;
     } else if (cmd == CAMERA_CMD_PLAY_RECORDING_SOUND) {
         mCameraService->playSound(CameraService::SOUND_RECORDING);
+    } else if (cmd == CAMERA_CMD_SET_VIDEO_BUFFER_COUNT) {
+        // Silently ignore this command
+        return INVALID_OPERATION;
     } else if (cmd == CAMERA_CMD_PING) {
         // If mHardware is 0, checkPidAndHardware will return error.
         return OK;