Camera NDK library: capture session implementation

Bug: 23012001
Change-Id: I3fd93205dcf1b9ed5a947cb944919eb531f219fc
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 061175c..b73e621 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -17,26 +17,35 @@
 #define _ACAMERA_DEVICE_H
 
 #include <memory>
+#include <map>
+#include <set>
 #include <atomic>
 #include <utils/StrongPointer.h>
 #include <utils/Mutex.h>
 #include <utils/String8.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
 
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AHandler.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <camera/CaptureResult.h>
 #include <camera/camera2/ICameraDeviceCallbacks.h>
 #include <camera/camera2/ICameraDeviceUser.h>
+#include <camera/camera2/OutputConfiguration.h>
+#include <camera/camera2/CaptureRequest.h>
 
 #include <NdkCameraDevice.h>
 #include "ACameraMetadata.h"
 
-
 using namespace android;
 
 namespace android {
 
-struct CameraDevice final : public RefBase {
+// Wrap ACameraCaptureFailure so it can be ref-counter
+struct CameraCaptureFailure : public RefBase, public ACameraCaptureFailure {};
+
+class CameraDevice final : public RefBase {
   public:
     CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
                   std::unique_ptr<ACameraMetadata> chars,
@@ -49,6 +58,11 @@
             ACameraDevice_request_template templateId,
             ACaptureRequest** request) const;
 
+    camera_status_t createCaptureSession(
+            const ACaptureSessionOutputContainer*       outputs,
+            const ACameraCaptureSession_stateCallbacks* callbacks,
+            /*out*/ACameraCaptureSession** session);
+
     // Callbacks from camera service
     class ServiceCallback : public BnCameraDeviceCallbacks {
       public:
@@ -69,10 +83,60 @@
     // Camera device is only functional after remote being set
     void setRemoteDevice(sp<ICameraDeviceUser> remote);
 
+    inline ACameraDevice* getWrapper() const { return mWrapper; };
+
   private:
-    void disconnectLocked(); // disconnect from camera service
+    friend ACameraCaptureSession;
     camera_status_t checkCameraClosedOrErrorLocked() const;
 
+    // device goes into fatal error state after this
+    void setCameraDeviceErrorLocked(camera_status_t error);
+
+    void disconnectLocked(); // disconnect from camera service
+
+    camera_status_t stopRepeatingLocked();
+
+    camera_status_t waitUntilIdleLocked();
+
+
+    camera_status_t captureLocked(sp<ACameraCaptureSession> session,
+            /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+            int numRequests, ACaptureRequest** requests,
+            /*optional*/int* captureSequenceId);
+
+    camera_status_t setRepeatingRequestsLocked(sp<ACameraCaptureSession> session,
+            /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+            int numRequests, ACaptureRequest** requests,
+            /*optional*/int* captureSequenceId);
+
+    camera_status_t submitRequestsLocked(
+            sp<ACameraCaptureSession> session,
+            /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+            int numRequests, ACaptureRequest** requests,
+            /*out*/int* captureSequenceId,
+            bool isRepeating);
+
+    static camera_status_t allocateCaptureRequest(
+            const ACaptureRequest* request, sp<CaptureRequest>& outReq);
+
+    static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req);
+    static void freeACaptureRequest(ACaptureRequest*);
+
+    // only For session to hold device lock
+    // Always grab device lock before grabbing session lock
+    void lockDeviceForSessionOps() const { mDeviceLock.lock(); };
+    void unlockDevice() const { mDeviceLock.unlock(); };
+
+    // For capture session to notify its end of life
+    void notifySessionEndOfLifeLocked(ACameraCaptureSession* session);
+
+    camera_status_t configureStreamsLocked(const ACaptureSessionOutputContainer* outputs);
+
+    static camera_status_t getIGBPfromSessionOutput(
+            const ACaptureSessionOutput& config, sp<IGraphicBufferProducer>& out);
+
+    static camera_status_t getSurfaceFromANativeWindow(
+            ANativeWindow* anw, sp<Surface>& out);
 
     mutable Mutex mDeviceLock;
     const String8 mCameraId;                          // Camera ID
@@ -81,6 +145,9 @@
     const sp<ServiceCallback> mServiceCallback;
     ACameraDevice* mWrapper;
 
+    // stream id -> OutputConfiguration map
+    std::map<int, OutputConfiguration> mConfiguredOutputs;
+
     // TODO: maybe a bool will suffice for synchronous implementation?
     std::atomic_bool mClosing;
     inline bool isClosed() { return mClosing; }
@@ -92,6 +159,8 @@
             const CaptureResultExtras& resultExtras);
 
     bool mIdle;
+    // This will avoid a busy session being deleted before it's back to idle state
+    sp<ACameraCaptureSession> mBusySession;
 
     sp<ICameraDeviceUser> mRemote;
 
@@ -99,13 +168,29 @@
     sp<ALooper> mCbLooper;
     // definition of handler and message
     enum {
-        kWhatOnDisconnected,
-        kWhatOnError
+        // Device state callbacks
+        kWhatOnDisconnected, // onDisconnected
+        kWhatOnError,        // onError
+        // Session state callbacks
+        kWhatSessionStateCb, // onReady, onActive
+        // Capture callbacks
+        kWhatCaptureStart,   // onCaptureStarted
+        kWhatCaptureResult,  // onCaptureProgressed, onCaptureCompleted
+        kWhatCaptureFail,    // onCaptureFailed
+        kWhatCaptureSeqEnd,  // onCaptureSequenceCompleted
+        kWhatCaptureSeqAbort // onCaptureSequenceAborted
     };
     static const char* kContextKey;
     static const char* kDeviceKey;
     static const char* kErrorCodeKey;
-    static const char* kCallbackKey;
+    static const char* kCallbackFpKey;
+    static const char* kSessionSpKey;
+    static const char* kCaptureRequestKey;
+    static const char* kTimeStampKey;
+    static const char* kCaptureResultKey;
+    static const char* kCaptureFailureKey;
+    static const char* kSequenceIdKey;
+    static const char* kFrameNumberKey;
     class CallbackHandler : public AHandler {
       public:
         CallbackHandler() {}
@@ -113,10 +198,65 @@
     };
     sp<CallbackHandler> mHandler;
 
-    inline ACameraDevice* getWrapper() { return mWrapper; };
+    /***********************************
+     * Capture session related members *
+     ***********************************/
+    // The current active session
+    ACameraCaptureSession* mCurrentSession = nullptr;
 
+    int mNextSessionId = 0;
     // TODO: might need another looper/handler to handle callbacks from service
 
+    static const int REQUEST_ID_NONE = -1;
+    int mRepeatingSequenceId = REQUEST_ID_NONE;
+
+    // sequence id -> last frame number map
+    std::map<int, int64_t> mSequenceLastFrameNumberMap;
+
+    struct CallbackHolder {
+        CallbackHolder(sp<ACameraCaptureSession>          session,
+                       const Vector<sp<CaptureRequest> >& requests,
+                       bool                               isRepeating,
+                       ACameraCaptureSession_captureCallbacks* cbs);
+
+        static ACameraCaptureSession_captureCallbacks fillCb(
+                ACameraCaptureSession_captureCallbacks* cbs) {
+            if (cbs != nullptr) {
+                return *cbs;
+            }
+            return { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
+        }
+
+        sp<ACameraCaptureSession>   mSession;
+        Vector<sp<CaptureRequest> > mRequests;
+        const bool                  mIsRepeating;
+        ACameraCaptureSession_captureCallbacks mCallbacks;
+    };
+    // sequence id -> callbacks map
+    std::map<int, CallbackHolder> mSequenceCallbackMap;
+
+    static const int64_t NO_FRAMES_CAPTURED = -1;
+    class FrameNumberTracker {
+      public:
+        // TODO: Called in onResultReceived and onCaptureErrorLocked
+        void updateTracker(int64_t frameNumber, bool isError);
+        inline int64_t getCompletedFrameNumber() { return mCompletedFrameNumber; }
+      private:
+        void update();
+        void updateCompletedFrameNumber(int64_t frameNumber);
+
+        int64_t mCompletedFrameNumber = NO_FRAMES_CAPTURED;
+        List<int64_t> mSkippedFrameNumbers;
+        std::set<int64_t> mFutureErrorSet;
+    };
+    FrameNumberTracker mFrameNumberTracker;
+
+    void checkRepeatingSequenceCompleteLocked(const int sequenceId, const int64_t lastFrameNumber);
+    void checkAndFireSequenceCompleteLocked();
+
+    // Misc variables
+    int32_t mShadingMapSize[2];   // const after constructor
+    int32_t mPartialResultCount;  // const after constructor
 
 };
 
@@ -133,6 +273,9 @@
 
     ~ACameraDevice() {};
 
+    /*******************
+     * NDK public APIs *
+     *******************/
     inline const char* getId() const { return mDevice->getId(); }
 
     camera_status_t createCaptureRequest(
@@ -141,6 +284,16 @@
         return mDevice->createCaptureRequest(templateId, request);
     }
 
+    camera_status_t createCaptureSession(
+            const ACaptureSessionOutputContainer*       outputs,
+            const ACameraCaptureSession_stateCallbacks* callbacks,
+            /*out*/ACameraCaptureSession** session) {
+        return mDevice->createCaptureSession(outputs, callbacks, session);
+    }
+
+    /***********************
+     * Device interal APIs *
+     ***********************/
     inline sp<ICameraDeviceCallbacks> getServiceCallback() {
         return mDevice->getServiceCallback();
     };
@@ -151,7 +304,6 @@
     }
 
   private:
-    // TODO: might need an API to give wp of mDevice to capture session
     sp<CameraDevice> mDevice;
 };