Camera2: Move still capture processing to separate thread.

To avoid stalling HAL when it queues up new buffers for still capture,
process still captures in a separate thread. Also move Camera2Heap to
its own class so it can be used by the CaptureProcessor.

Bug: 6243944
Change-Id: Id38e2a52367c0985812fcd4fd9af3ef90beef43f
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index 4edb49f..d296445 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -52,11 +52,11 @@
         int clientPid):
         Client(cameraService, cameraClient,
                 cameraId, cameraFacing, clientPid),
+        mSharedCameraClient(cameraClient),
         mParameters(cameraId, cameraFacing),
         mPreviewStreamId(NO_STREAM),
         mCallbackStreamId(NO_STREAM),
         mCallbackHeapId(0),
-        mCaptureStreamId(NO_STREAM),
         mRecordingStreamId(NO_STREAM),
         mRecordingHeapCount(kDefaultRecordingHeapCount)
 {
@@ -84,11 +84,6 @@
     ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId);
     status_t res;
 
-    mFrameProcessor = new FrameProcessor(this);
-    String8 frameThreadName = String8::format("Camera2Client[%d]::FrameProcessor",
-            mCameraId);
-    mFrameProcessor->run(frameThreadName.string());
-
     res = mDevice->initialize(module);
     if (res != OK) {
         ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
@@ -107,6 +102,16 @@
         return NO_INIT;
     }
 
+    mFrameProcessor = new FrameProcessor(this);
+    String8 frameThreadName = String8::format("Camera2Client[%d]::FrameProcessor",
+            mCameraId);
+    mFrameProcessor->run(frameThreadName.string());
+
+    mCaptureProcessor = new CaptureProcessor(this);
+    String8 captureThreadName =
+            String8::format("Camera2Client[%d]::CaptureProcessor", mCameraId);
+    mCaptureProcessor->run(captureThreadName.string());
+
     if (gLogLevel >= 1) {
         ALOGD("%s: Default parameters converted from camera %d:", __FUNCTION__,
               mCameraId);
@@ -292,7 +297,8 @@
 
     result.append("  Current streams:\n");
     result.appendFormat("    Preview stream ID: %d\n", mPreviewStreamId);
-    result.appendFormat("    Capture stream ID: %d\n", mCaptureStreamId);
+    result.appendFormat("    Capture stream ID: %d\n",
+            mCaptureProcessor->getStreamId());
     result.appendFormat("    Recording stream ID: %d\n", mRecordingStreamId);
 
     result.append("  Current requests:\n");
@@ -357,10 +363,7 @@
         mPreviewStreamId = NO_STREAM;
     }
 
-    if (mCaptureStreamId != NO_STREAM) {
-        mDevice->deleteStream(mCaptureStreamId);
-        mCaptureStreamId = NO_STREAM;
-    }
+    mCaptureProcessor->deleteStream();
 
     if (mRecordingStreamId != NO_STREAM) {
         mDevice->deleteStream(mRecordingStreamId);
@@ -1028,7 +1031,7 @@
 
     ALOGV("%s: Camera %d: Starting picture capture", __FUNCTION__, mCameraId);
 
-    res = updateCaptureStream(l.mParameters);
+    res = mCaptureProcessor->updateStream(l.mParameters);
     if (res != OK) {
         ALOGE("%s: Camera %d: Can't set up still image stream: %s (%d)",
                 __FUNCTION__, mCameraId, strerror(-res), res);
@@ -1048,32 +1051,34 @@
             CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK;
     bool recordingEnabled = (l.mParameters.state == Parameters::RECORD);
 
+    int captureStreamId = mCaptureProcessor->getStreamId();
+
     int streamSwitch = (callbacksEnabled ? 0x2 : 0x0) +
             (recordingEnabled ? 0x1 : 0x0);
     switch ( streamSwitch ) {
         case 0: { // No recording, callbacks
-            uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId };
+            uint8_t streamIds[2] = { mPreviewStreamId, captureStreamId };
             res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                     streamIds, 2);
             break;
         }
         case 1: { // Recording
             uint8_t streamIds[3] = { mPreviewStreamId, mRecordingStreamId,
-                                     mCaptureStreamId };
+                                     captureStreamId };
             res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                     streamIds, 3);
             break;
         }
         case 2: { // Callbacks
             uint8_t streamIds[3] = { mPreviewStreamId, mCallbackStreamId,
-                                     mCaptureStreamId };
+                                     captureStreamId };
             res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                     streamIds, 3);
             break;
         }
         case 3: { // Both
             uint8_t streamIds[4] = { mPreviewStreamId, mCallbackStreamId,
-                                     mRecordingStreamId, mCaptureStreamId };
+                                     mRecordingStreamId, captureStreamId };
             res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                     streamIds, 4);
             break;
@@ -1511,6 +1516,10 @@
     mSharedClient.mCameraClientLock.unlock();
 }
 
+Camera2Client::SharedCameraClient::SharedCameraClient(const sp<ICameraClient>&client):
+        mCameraClient(client) {
+}
+
 Camera2Client::SharedCameraClient& Camera2Client::SharedCameraClient::operator=(
         const sp<ICameraClient>&client) {
     Mutex::Autolock l(mCameraClientLock);
@@ -1650,71 +1659,6 @@
     ALOGV("%s: exit", __FUNCTION__);
 }
 
-void Camera2Client::onCaptureAvailable() {
-    ATRACE_CALL();
-    status_t res;
-    sp<Camera2Heap> captureHeap;
-    ALOGV("%s: Camera %d: Still capture available", __FUNCTION__, mCameraId);
-
-    {
-        SharedParameters::Lock l(mParameters);
-        CpuConsumer::LockedBuffer imgBuffer;
-
-        res = mCaptureConsumer->lockNextBuffer(&imgBuffer);
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Error receiving still image buffer: %s (%d)",
-                    __FUNCTION__, mCameraId, strerror(-res), res);
-            return;
-        }
-
-        // TODO: Signal errors here upstream
-        if (l.mParameters.state != Parameters::STILL_CAPTURE &&
-                l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
-            ALOGE("%s: Camera %d: Still image produced unexpectedly!",
-                    __FUNCTION__, mCameraId);
-            mCaptureConsumer->unlockBuffer(imgBuffer);
-            return;
-        }
-
-        if (imgBuffer.format != HAL_PIXEL_FORMAT_BLOB) {
-            ALOGE("%s: Camera %d: Unexpected format for still image: "
-                    "%x, expected %x", __FUNCTION__, mCameraId,
-                    imgBuffer.format,
-                    HAL_PIXEL_FORMAT_BLOB);
-            mCaptureConsumer->unlockBuffer(imgBuffer);
-            return;
-        }
-
-        // TODO: Optimize this to avoid memcopy
-        void* captureMemory = mCaptureHeap->mHeap->getBase();
-        size_t size = mCaptureHeap->mHeap->getSize();
-        memcpy(captureMemory, imgBuffer.data, size);
-
-        mCaptureConsumer->unlockBuffer(imgBuffer);
-
-        switch (l.mParameters.state) {
-            case Parameters::STILL_CAPTURE:
-                l.mParameters.state = Parameters::STOPPED;
-                break;
-            case Parameters::VIDEO_SNAPSHOT:
-                l.mParameters.state = Parameters::RECORD;
-                break;
-            default:
-                ALOGE("%s: Camera %d: Unexpected state %d", __FUNCTION__,
-                        mCameraId, l.mParameters.state);
-                break;
-        }
-
-        captureHeap = mCaptureHeap;
-    }
-    // Call outside parameter locks to allow re-entrancy from notification
-    SharedCameraClient::Lock l(mSharedCameraClient);
-    if (l.mCameraClient != 0) {
-        l.mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
-                captureHeap->mBuffers[0], NULL);
-    }
-}
-
 void Camera2Client::onRecordingFrameAvailable() {
     ATRACE_CALL();
     status_t res;
@@ -1998,75 +1942,6 @@
     return OK;
 }
 
-
-status_t Camera2Client::updateCaptureStream(const Parameters &params) {
-    ATRACE_CALL();
-    status_t res;
-    // Find out buffer size for JPEG
-    camera_metadata_ro_entry_t maxJpegSize =
-            mParameters.staticInfo(ANDROID_JPEG_MAX_SIZE);
-    if (maxJpegSize.count == 0) {
-        ALOGE("%s: Camera %d: Can't find ANDROID_JPEG_MAX_SIZE!",
-                __FUNCTION__, mCameraId);
-        return INVALID_OPERATION;
-    }
-
-    if (mCaptureConsumer == 0) {
-        // Create CPU buffer queue endpoint
-        mCaptureConsumer = new CpuConsumer(1);
-        mCaptureConsumer->setFrameAvailableListener(new CaptureWaiter(this));
-        mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer"));
-        mCaptureWindow = new SurfaceTextureClient(
-            mCaptureConsumer->getProducerInterface());
-        // Create memory for API consumption
-        mCaptureHeap = new Camera2Heap(maxJpegSize.data.i32[0], 1,
-                                       "Camera2Client::CaptureHeap");
-        if (mCaptureHeap->mHeap->getSize() == 0) {
-            ALOGE("%s: Camera %d: Unable to allocate memory for capture",
-                    __FUNCTION__, mCameraId);
-            return NO_MEMORY;
-        }
-    }
-
-    if (mCaptureStreamId != NO_STREAM) {
-        // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight;
-        res = mDevice->getStreamInfo(mCaptureStreamId,
-                &currentWidth, &currentHeight, 0);
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Error querying capture output stream info: "
-                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
-            return res;
-        }
-        if (currentWidth != (uint32_t)params.pictureWidth ||
-                currentHeight != (uint32_t)params.pictureHeight) {
-            res = mDevice->deleteStream(mCaptureStreamId);
-            if (res != OK) {
-                ALOGE("%s: Camera %d: Unable to delete old output stream "
-                        "for capture: %s (%d)", __FUNCTION__, mCameraId,
-                        strerror(-res), res);
-                return res;
-            }
-            mCaptureStreamId = NO_STREAM;
-        }
-    }
-
-    if (mCaptureStreamId == NO_STREAM) {
-        // Create stream for HAL production
-        res = mDevice->createStream(mCaptureWindow,
-                params.pictureWidth, params.pictureHeight,
-                HAL_PIXEL_FORMAT_BLOB, maxJpegSize.data.i32[0],
-                &mCaptureStreamId);
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Can't create output stream for capture: "
-                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
-            return res;
-        }
-
-    }
-    return OK;
-}
-
 status_t Camera2Client::updateCaptureRequest(const Parameters &params) {
     ATRACE_CALL();
     status_t res;