CameraService: Add support for burst capture and repeating burst.

Bug: 10749500
Change-Id: I292a485b222e5cf97388d76bf0d956a6ac54bb2f
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 187220e..a02381d 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -159,7 +159,7 @@
 
     int32_t requestId = mRequestIdCounter++;
     metadata.update(ANDROID_REQUEST_ID, &requestId, /*size*/1);
-    ALOGV("%s: Camera %d: Submitting request with ID %d",
+    ALOGV("%s: Camera %d: Creating request with ID %d",
           __FUNCTION__, mCameraId, requestId);
 
     if (streaming) {
@@ -186,6 +186,116 @@
     return res;
 }
 
+status_t CameraDeviceClient::submitRequestList(List<sp<CaptureRequest> > requests,
+                                               bool streaming) {
+    ATRACE_CALL();
+    ALOGV("%s-start of function", __FUNCTION__);
+
+    status_t res;
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    if (requests.empty()) {
+        ALOGE("%s: Camera %d: Sent null request. Rejecting request.",
+              __FUNCTION__, mCameraId);
+        return BAD_VALUE;
+    }
+
+    List<const CameraMetadata> metadataRequestList;
+    int32_t requestId = mRequestIdCounter;
+    uint32_t loopCounter = 0;
+
+    for (List<sp<CaptureRequest> >::iterator it = requests.begin(); it != requests.end(); ++it) {
+        sp<CaptureRequest> request = *it;
+        if (request == 0) {
+            ALOGE("%s: Camera %d: Sent null request.",
+                    __FUNCTION__, mCameraId);
+            return BAD_VALUE;
+        }
+
+        CameraMetadata metadata(request->mMetadata);
+        if (metadata.isEmpty()) {
+            ALOGE("%s: Camera %d: Sent empty metadata packet. Rejecting request.",
+                   __FUNCTION__, mCameraId);
+            return BAD_VALUE;
+        } else if (request->mSurfaceList.isEmpty()) {
+            ALOGE("%s: Camera %d: Requests must have at least one surface target. "
+                  "Rejecting request.", __FUNCTION__, mCameraId);
+            return BAD_VALUE;
+        }
+
+        if (!enforceRequestPermissions(metadata)) {
+            // Callee logs
+            return PERMISSION_DENIED;
+        }
+
+        /**
+         * Write in the output stream IDs which we calculate from
+         * the capture request's list of surface targets
+         */
+        Vector<int32_t> outputStreamIds;
+        outputStreamIds.setCapacity(request->mSurfaceList.size());
+        for (Vector<sp<Surface> >::iterator surfaceIt = 0;
+                surfaceIt != request->mSurfaceList.end(); ++surfaceIt) {
+            sp<Surface> surface = *surfaceIt;
+            if (surface == 0) continue;
+
+            sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();
+            int idx = mStreamMap.indexOfKey(gbp->asBinder());
+
+            // Trying to submit request with surface that wasn't created
+            if (idx == NAME_NOT_FOUND) {
+                ALOGE("%s: Camera %d: Tried to submit a request with a surface that"
+                      " we have not called createStream on",
+                      __FUNCTION__, mCameraId);
+                return BAD_VALUE;
+            }
+
+            int streamId = mStreamMap.valueAt(idx);
+            outputStreamIds.push_back(streamId);
+            ALOGV("%s: Camera %d: Appending output stream %d to request",
+                  __FUNCTION__, mCameraId, streamId);
+        }
+
+        metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreamIds[0],
+                        outputStreamIds.size());
+
+        metadata.update(ANDROID_REQUEST_ID, &requestId, /*size*/1);
+        loopCounter++; // loopCounter starts from 1
+        ALOGV("%s: Camera %d: Creating request with ID %d (%d of %d)",
+              __FUNCTION__, mCameraId, requestId, loopCounter, requests.size());
+
+        metadataRequestList.push_back(metadata);
+    }
+    mRequestIdCounter++;
+
+    if (streaming) {
+        res = mDevice->setStreamingRequestList(metadataRequestList);
+        if (res != OK) {
+            ALOGE("%s: Camera %d:  Got error %d after trying to set streaming "
+                  "request", __FUNCTION__, mCameraId, res);
+        } else {
+            mStreamingRequestList.push_back(requestId);
+        }
+    } else {
+        res = mDevice->captureList(metadataRequestList);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Got error %d after trying to set capture",
+                __FUNCTION__, mCameraId, res);
+        }
+    }
+
+    ALOGV("%s: Camera %d: End of function", __FUNCTION__, mCameraId);
+    if (res == OK) {
+        return requestId;
+    }
+
+    return res;
+}
+
 status_t CameraDeviceClient::cancelRequest(int requestId) {
     ATRACE_CALL();
     ALOGV("%s, requestId = %d", __FUNCTION__, requestId);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index b9c16aa..e96e1ae 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -63,8 +63,11 @@
      */
 
     // Note that the callee gets a copy of the metadata.
-    virtual int           submitRequest(sp<CaptureRequest> request,
-                                        bool streaming = false);
+    virtual status_t           submitRequest(sp<CaptureRequest> request,
+                                             bool streaming = false);
+    // List of requests are copied.
+    virtual status_t           submitRequestList(List<sp<CaptureRequest> > requests,
+                                                 bool streaming = false);
     virtual status_t      cancelRequest(int requestId);
 
     // Returns -EBUSY if device is not idle
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index e80abf1..a4ae179 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -22,6 +22,7 @@
 #include <utils/String16.h>
 #include <utils/Vector.h>
 #include <utils/Timers.h>
+#include <utils/List.h>
 
 #include "hardware/camera2.h"
 #include "camera/CameraMetadata.h"
@@ -58,12 +59,22 @@
     virtual status_t capture(CameraMetadata &request) = 0;
 
     /**
+     * Submit a list of requests.
+     */
+    virtual status_t captureList(const List<const CameraMetadata> &requests) = 0;
+
+    /**
      * Submit request for streaming. The CameraDevice makes a copy of the
      * passed-in buffer and the caller retains ownership.
      */
     virtual status_t setStreamingRequest(const CameraMetadata &request) = 0;
 
     /**
+     * Submit a list of requests for streaming.
+     */
+    virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests) = 0;
+
+    /**
      * Clear the streaming request slot.
      */
     virtual status_t clearStreamingRequest() = 0;
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
index dc97c47..3e58c4b 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ b/services/camera/libcameraservice/device2/Camera2Device.cpp
@@ -221,6 +221,12 @@
     return OK;
 }
 
+status_t Camera2Device::captureList(const List<const CameraMetadata> &requests) {
+    ATRACE_CALL();
+    ALOGE("%s: Camera2Device burst capture not implemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
 
 status_t Camera2Device::setStreamingRequest(const CameraMetadata &request) {
     ATRACE_CALL();
@@ -229,6 +235,12 @@
     return mRequestQueue.setStreamSlot(streamRequest.release());
 }
 
+status_t Camera2Device::setStreamingRequestList(const List<const CameraMetadata> &requests) {
+    ATRACE_CALL();
+    ALOGE("%s, Camera2Device streaming burst not implemented", __FUNCTION__);
+    return INVALID_OPERATION;
+}
+
 status_t Camera2Device::clearStreamingRequest() {
     ATRACE_CALL();
     return mRequestQueue.setStreamSlot(NULL);
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
index 1f53c56..933c5f7 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ b/services/camera/libcameraservice/device2/Camera2Device.h
@@ -48,7 +48,9 @@
     virtual status_t dump(int fd, const Vector<String16>& args);
     virtual const CameraMetadata& info() const;
     virtual status_t capture(CameraMetadata &request);
+    virtual status_t captureList(const List<const CameraMetadata> &requests);
     virtual status_t setStreamingRequest(const CameraMetadata &request);
+    virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests);
     virtual status_t clearStreamingRequest();
     virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
     virtual status_t createStream(sp<ANativeWindow> consumer,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index da3e121..a700f30 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -388,6 +388,45 @@
     return mDeviceInfo;
 }
 
+status_t Camera3Device::checkStatusOkToCaptureLocked() {
+    switch (mStatus) {
+        case STATUS_ERROR:
+            CLOGE("Device has encountered a serious error");
+            return INVALID_OPERATION;
+        case STATUS_UNINITIALIZED:
+            CLOGE("Device not initialized");
+            return INVALID_OPERATION;
+        case STATUS_UNCONFIGURED:
+        case STATUS_CONFIGURED:
+        case STATUS_ACTIVE:
+            // OK
+            break;
+        default:
+            SET_ERR_L("Unexpected status: %d", mStatus);
+            return INVALID_OPERATION;
+    }
+    return OK;
+}
+
+status_t Camera3Device::convertMetadataListToRequestListLocked(
+        const List<const CameraMetadata> &metadataList, RequestList *requestList) {
+    if (requestList == NULL) {
+        CLOGE("requestList cannot be NULL.");
+        return BAD_VALUE;
+    }
+
+    for (List<const CameraMetadata>::const_iterator it = metadataList.begin();
+            it != metadataList.end(); ++it) {
+        sp<CaptureRequest> newRequest = setUpRequestLocked(*it);
+        if (newRequest == 0) {
+            CLOGE("Can't create capture request");
+            return BAD_VALUE;
+        }
+        requestList->push_back(newRequest);
+    }
+    return OK;
+}
+
 status_t Camera3Device::capture(CameraMetadata &request) {
     ATRACE_CALL();
     status_t res;
@@ -428,10 +467,59 @@
                     kActiveTimeout/1e9);
         }
         ALOGV("Camera %d: Capture request enqueued", mId);
+    } else {
+        CLOGE("Cannot queue request. Impossible."); // queueRequest always returns OK.
+        return BAD_VALUE;
     }
     return res;
 }
 
+status_t Camera3Device::submitRequestsHelper(
+        const List<const CameraMetadata> &requests, bool repeating) {
+    ATRACE_CALL();
+    Mutex::Autolock il(mInterfaceLock);
+    Mutex::Autolock l(mLock);
+
+    status_t res = checkStatusOkToCaptureLocked();
+    if (res != OK) {
+        // error logged by previous call
+        return res;
+    }
+
+    RequestList requestList;
+
+    res = convertMetadataListToRequestListLocked(requests, /*out*/&requestList);
+    if (res != OK) {
+        // error logged by previous call
+        return res;
+    }
+
+    if (repeating) {
+        res = mRequestThread->setRepeatingRequests(requestList);
+    } else {
+        res = mRequestThread->queueRequestList(requestList);
+    }
+
+    if (res == OK) {
+        waitUntilStateThenRelock(/*active*/true, kActiveTimeout);
+        if (res != OK) {
+            SET_ERR_L("Can't transition to active in %f seconds!",
+                    kActiveTimeout/1e9);
+        }
+        ALOGV("Camera %d: Capture request enqueued", mId);
+    } else {
+        CLOGE("Cannot queue request. Impossible.");
+        return BAD_VALUE;
+    }
+
+    return res;
+}
+
+status_t Camera3Device::captureList(const List<const CameraMetadata> &requests) {
+    ATRACE_CALL();
+
+    return submitRequestsHelper(requests, /*repeating*/false);
+}
 
 status_t Camera3Device::setStreamingRequest(const CameraMetadata &request) {
     ATRACE_CALL();
@@ -478,6 +566,11 @@
     return res;
 }
 
+status_t Camera3Device::setStreamingRequestList(const List<const CameraMetadata> &requests) {
+    ATRACE_CALL();
+
+    return submitRequestsHelper(requests, /*repeating*/true);
+}
 
 sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked(
         const CameraMetadata &request) {
@@ -1913,6 +2006,19 @@
     return OK;
 }
 
+status_t Camera3Device::RequestThread::queueRequestList(
+        List<sp<CaptureRequest> > &requests) {
+    Mutex::Autolock l(mRequestLock);
+    for (List<sp<CaptureRequest> >::iterator it = requests.begin(); it != requests.end();
+            ++it) {
+        mRequestQueue.push_back(*it);
+    }
+
+    unpauseForNewRequests();
+
+    return OK;
+}
+
 
 status_t Camera3Device::RequestThread::queueTrigger(
         RequestTrigger trigger[],
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 468f641..bbdb65d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -79,7 +79,9 @@
     // Capture and setStreamingRequest will configure streams if currently in
     // idle state
     virtual status_t capture(CameraMetadata &request);
+    virtual status_t captureList(const List<const CameraMetadata> &requests);
     virtual status_t setStreamingRequest(const CameraMetadata &request);
+    virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests);
     virtual status_t clearStreamingRequest();
 
     virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
@@ -202,6 +204,14 @@
     };
     typedef List<sp<CaptureRequest> > RequestList;
 
+    status_t checkStatusOkToCaptureLocked();
+
+    status_t convertMetadataListToRequestListLocked(
+            const List<const CameraMetadata> &metadataList,
+            /*out*/RequestList *requestList);
+
+    status_t submitRequestsHelper(const List<const CameraMetadata> &requests, bool repeating);
+
     /**
      * Get the last request submitted to the hal by the request thread.
      *
@@ -313,6 +323,8 @@
 
         status_t queueRequest(sp<CaptureRequest> request);
 
+        status_t queueRequestList(List<sp<CaptureRequest> > &requests);
+
         /**
          * Remove all queued and repeating requests, and pending triggers
          */