Camera: ProCamera - implement onResultReceived callback for metadata callbacks

Change-Id: I46775402b007244bc383d6343a620eebbd492aad
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index c7a8e4a..f76c861 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -20,7 +20,8 @@
     camera2/ZslProcessor.cpp \
     camera2/BurstCapture.cpp \
     camera2/JpegCompressor.cpp \
-    camera2/CaptureSequencer.cpp
+    camera2/CaptureSequencer.cpp \
+    camera2/ProFrameProcessor.cpp \
 
 LOCAL_SHARED_LIBRARIES:= \
     libui \
diff --git a/services/camera/libcameraservice/ProCamera2Client.cpp b/services/camera/libcameraservice/ProCamera2Client.cpp
index f850034..7611796 100644
--- a/services/camera/libcameraservice/ProCamera2Client.cpp
+++ b/services/camera/libcameraservice/ProCamera2Client.cpp
@@ -26,6 +26,7 @@
 #include <gui/Surface.h>
 #include "camera2/Parameters.h"
 #include "ProCamera2Client.h"
+#include "camera2/ProFrameProcessor.h"
 
 namespace android {
 using namespace camera2;
@@ -82,6 +83,16 @@
 
     res = mDevice->setNotifyCallback(this);
 
+    String8 threadName;
+    mFrameProcessor = new ProFrameProcessor(this);
+    threadName = String8::format("PC2-%d-FrameProc",
+            mCameraId);
+    mFrameProcessor->run(threadName.string());
+
+    mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
+                                      FRAME_PROCESSOR_LISTENER_MAX_ID,
+                                      /*listener*/this);
+
     return OK;
 }
 
@@ -307,6 +318,7 @@
     result.append("  State: ");
 
     // TODO: print dynamic/request section from most recent requests
+    mFrameProcessor->dump(fd, args);
 
 #define CASE_APPEND_ENUM(x) case x: result.append(#x "\n"); break;
 
@@ -338,7 +350,12 @@
     if (mDevice == 0) return;
 
     ALOGV("Camera %d: Shutting down", mCameraId);
+    mFrameProcessor->removeListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
+                                    FRAME_PROCESSOR_LISTENER_MAX_ID,
+                                    /*listener*/this);
+    mFrameProcessor->requestExit();
     ALOGV("Camera %d: Waiting for threads", mCameraId);
+    mFrameProcessor->join();
     ALOGV("Camera %d: Disconnecting device", mCameraId);
 
     mDevice->disconnect();
@@ -446,4 +463,22 @@
     mRemoteCallback.clear();
 }
 
+void ProCamera2Client::onFrameAvailable(int32_t frameId,
+                                        const CameraMetadata& frame) {
+    ATRACE_CALL();
+    ALOGV("%s", __FUNCTION__);
+
+    Mutex::Autolock icl(mIProCameraUserLock);
+    SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
+
+    if (mRemoteCallback != NULL) {
+        CameraMetadata tmp(frame);
+        camera_metadata_t* meta = tmp.release();
+        ALOGV("%s: meta = %p ", __FUNCTION__, meta);
+        mRemoteCallback->onResultReceived(frameId, meta);
+        tmp.acquire(meta);
+    }
+
+}
+
 } // namespace android
diff --git a/services/camera/libcameraservice/ProCamera2Client.h b/services/camera/libcameraservice/ProCamera2Client.h
index b72fd63..dfea1e1 100644
--- a/services/camera/libcameraservice/ProCamera2Client.h
+++ b/services/camera/libcameraservice/ProCamera2Client.h
@@ -19,6 +19,7 @@
 
 #include "Camera2Device.h"
 #include "CameraService.h"
+#include "camera2/ProFrameProcessor.h"
 
 namespace android {
 
@@ -29,7 +30,8 @@
  */
 class ProCamera2Client :
         public CameraService::ProClient,
-        public Camera2Device::NotificationListener
+        public Camera2Device::NotificationListener,
+        public camera2::ProFrameProcessor::FilteredListener
 {
 public:
     /**
@@ -120,6 +122,10 @@
         mutable Mutex mRemoteCallbackLock;
     } mSharedCameraCallbacks;
 
+protected:
+    /** FilteredListener implementation **/
+    virtual void onFrameAvailable(int32_t frameId, const CameraMetadata& frame);
+
 private:
     /** IProCameraUser interface-related private members */
 
@@ -137,6 +143,10 @@
     sp<IBinder> mPreviewSurface;
 
     /** Preview callback related members */
+    sp<camera2::ProFrameProcessor> mFrameProcessor;
+    static const int32_t FRAME_PROCESSOR_LISTENER_MIN_ID = 0;
+    static const int32_t FRAME_PROCESSOR_LISTENER_MAX_ID = 0x7fffffffL;
+
     /** Camera2Device instance wrapping HAL2 entry */
 
     sp<Camera2Device> mDevice;
diff --git a/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp b/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
new file mode 100644
index 0000000..8d4933c
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Camera2-ProFrameProcessor"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "ProFrameProcessor.h"
+#include "../Camera2Device.h"
+#include "../ProCamera2Client.h"
+
+namespace android {
+namespace camera2 {
+
+ProFrameProcessor::ProFrameProcessor(wp<ProCamera2Client> client):
+        Thread(false), mClient(client) {
+}
+
+ProFrameProcessor::~ProFrameProcessor() {
+    ALOGV("%s: Exit", __FUNCTION__);
+}
+
+status_t ProFrameProcessor::registerListener(int32_t minId,
+        int32_t maxId, wp<FilteredListener> listener) {
+    Mutex::Autolock l(mInputMutex);
+    ALOGV("%s: Registering listener for frame id range %d - %d",
+            __FUNCTION__, minId, maxId);
+    RangeListener rListener = { minId, maxId, listener };
+    mRangeListeners.push_back(rListener);
+    return OK;
+}
+
+status_t ProFrameProcessor::removeListener(int32_t minId,
+        int32_t maxId, wp<FilteredListener> listener) {
+    Mutex::Autolock l(mInputMutex);
+    List<RangeListener>::iterator item = mRangeListeners.begin();
+    while (item != mRangeListeners.end()) {
+        if (item->minId == minId &&
+                item->maxId == maxId &&
+                item->listener == listener) {
+            item = mRangeListeners.erase(item);
+        } else {
+            item++;
+        }
+    }
+    return OK;
+}
+
+void ProFrameProcessor::dump(int fd, const Vector<String16>& args) {
+    String8 result("    Latest received frame:\n");
+    write(fd, result.string(), result.size());
+    mLastFrame.dump(fd, 2, 6);
+}
+
+bool ProFrameProcessor::threadLoop() {
+    status_t res;
+
+    sp<Camera2Device> device;
+    {
+        sp<ProCamera2Client> client = mClient.promote();
+        if (client == 0) return false;
+        device = client->getCameraDevice();
+        if (device == 0) return false;
+    }
+
+    res = device->waitForNextFrame(kWaitDuration);
+    if (res == OK) {
+        sp<ProCamera2Client> client = mClient.promote();
+        if (client == 0) return false;
+        processNewFrames(client);
+    } else if (res != TIMED_OUT) {
+        ALOGE("ProCamera2Client::ProFrameProcessor: Error waiting for new "
+                "frames: %s (%d)", strerror(-res), res);
+    }
+
+    return true;
+}
+
+void ProFrameProcessor::processNewFrames(sp<ProCamera2Client> &client) {
+    status_t res;
+    ATRACE_CALL();
+    CameraMetadata frame;
+    while ( (res = client->getCameraDevice()->getNextFrame(&frame)) == OK) {
+        camera_metadata_entry_t entry;
+
+        entry = frame.find(ANDROID_REQUEST_FRAME_COUNT);
+        if (entry.count == 0) {
+            ALOGE("%s: Camera %d: Error reading frame number",
+                    __FUNCTION__, client->getCameraId());
+            break;
+        }
+        ATRACE_INT("cam2_frame", entry.data.i32[0]);
+
+        res = processListeners(frame, client);
+        if (res != OK) break;
+
+        if (!frame.isEmpty()) {
+            mLastFrame.acquire(frame);
+        }
+    }
+    if (res != NOT_ENOUGH_DATA) {
+        ALOGE("%s: Camera %d: Error getting next frame: %s (%d)",
+                __FUNCTION__, client->getCameraId(), strerror(-res), res);
+        return;
+    }
+
+    return;
+}
+
+status_t ProFrameProcessor::processListeners(const CameraMetadata &frame,
+        sp<ProCamera2Client> &client) {
+    status_t res;
+    ATRACE_CALL();
+    camera_metadata_ro_entry_t entry;
+
+    entry = frame.find(ANDROID_REQUEST_ID);
+    if (entry.count == 0) {
+        ALOGE("%s: Camera %d: Error reading frame id",
+                __FUNCTION__, client->getCameraId());
+        return BAD_VALUE;
+    }
+    int32_t frameId = entry.data.i32[0];
+
+    List<sp<FilteredListener> > listeners;
+    {
+        Mutex::Autolock l(mInputMutex);
+
+        List<RangeListener>::iterator item = mRangeListeners.begin();
+        while (item != mRangeListeners.end()) {
+            if (frameId >= item->minId &&
+                    frameId < item->maxId) {
+                sp<FilteredListener> listener = item->listener.promote();
+                if (listener == 0) {
+                    item = mRangeListeners.erase(item);
+                    continue;
+                } else {
+                    listeners.push_back(listener);
+                }
+            }
+            item++;
+        }
+    }
+    ALOGV("Got %d range listeners out of %d", listeners.size(), mRangeListeners.size());
+    List<sp<FilteredListener> >::iterator item = listeners.begin();
+    for (; item != listeners.end(); item++) {
+        (*item)->onFrameAvailable(frameId, frame);
+    }
+    return OK;
+}
+
+}; // namespace camera2
+}; // namespace android
diff --git a/services/camera/libcameraservice/camera2/ProFrameProcessor.h b/services/camera/libcameraservice/camera2/ProFrameProcessor.h
new file mode 100644
index 0000000..e4094a6
--- /dev/null
+++ b/services/camera/libcameraservice/camera2/ProFrameProcessor.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_CAMERA2_PROFRAMEPROCESSOR_H
+#define ANDROID_SERVERS_CAMERA_CAMERA2_PROFRAMEPROCESSOR_H
+
+#include <utils/Thread.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+#include <utils/List.h>
+#include <camera/CameraMetadata.h>
+
+struct camera_frame_metadata;
+
+namespace android {
+
+class ProCamera2Client;
+
+namespace camera2 {
+
+/* Output frame metadata processing thread.  This thread waits for new
+ * frames from the device, and analyzes them as necessary.
+ */
+class ProFrameProcessor: public Thread {
+  public:
+    ProFrameProcessor(wp<ProCamera2Client> client);
+    ~ProFrameProcessor();
+
+    struct FilteredListener: virtual public RefBase {
+        virtual void onFrameAvailable(int32_t frameId,
+                const CameraMetadata &frame) = 0;
+    };
+
+    // Register a listener for a range of IDs [minId, maxId). Multiple listeners
+    // can be listening to the same range
+    status_t registerListener(int32_t minId, int32_t maxId, wp<FilteredListener> listener);
+    status_t removeListener(int32_t minId, int32_t maxId, wp<FilteredListener> listener);
+
+    void dump(int fd, const Vector<String16>& args);
+  private:
+    static const nsecs_t kWaitDuration = 10000000; // 10 ms
+    wp<ProCamera2Client> mClient;
+
+    virtual bool threadLoop();
+
+    Mutex mInputMutex;
+
+    struct RangeListener {
+        int32_t minId;
+        int32_t maxId;
+        wp<FilteredListener> listener;
+    };
+    List<RangeListener> mRangeListeners;
+
+    void processNewFrames(sp<ProCamera2Client> &client);
+
+    status_t processListeners(const CameraMetadata &frame,
+            sp<ProCamera2Client> &client);
+
+    CameraMetadata mLastFrame;
+};
+
+
+}; //namespace camera2
+}; //namespace android
+
+#endif