Merge "Create another thread to handle frames" into rvc-dev
diff --git a/surround_view/service-impl/SurroundView3dSession.cpp b/surround_view/service-impl/SurroundView3dSession.cpp
index 88913af..ed7a16c 100644
--- a/surround_view/service-impl/SurroundView3dSession.cpp
+++ b/surround_view/service-impl/SurroundView3dSession.cpp
@@ -41,6 +41,33 @@
 static const int kNumChannels = 4;
 static const int kFrameDelayInMilliseconds = 30;
 
+void SurroundView3dSession::processFrames() {
+    if (mSurroundView->Start3dPipeline()) {
+        LOG(INFO) << "Start3dPipeline succeeded";
+    } else {
+        LOG(ERROR) << "Start3dPipeline failed";
+        return;
+    }
+
+    while(mStreamState == RUNNING) {
+        {
+            unique_lock<mutex> lock(mAccessLock);
+
+            mSignal.wait(lock, [this]() {
+                return framesAvailable;
+            });
+        }
+
+        handleFrames(sequenceId);
+
+        {
+            // Set the boolean to false to receive the next set of frames.
+            unique_lock<mutex> lock(mAccessLock);
+            framesAvailable = false;
+        }
+    }
+}
+
 SurroundView3dSession::SurroundView3dSession() :
     mStreamState(STOPPED){
     mEvsCameraIds = {"0" , "1", "2", "3"};
@@ -86,6 +113,10 @@
         generateFrames();
     });
 
+    mProcessThread = thread([this]() {
+        processFrames();
+    });
+
     return SvResult::OK;
 }
 
@@ -288,18 +319,7 @@
 }
 
 void SurroundView3dSession::generateFrames() {
-    if (mSurroundView->Start3dPipeline()) {
-        LOG(INFO) << "Start3dPipeline succeeded";
-    } else {
-        LOG(ERROR) << "Start3dPipeline failed";
-        return;
-    }
-
-    int sequenceId = 0;
-
-    // TODO(b/150412555): do not use the setViews for frames generation
-    // since there is a discrepancy between the HIDL APIs and core lib APIs.
-    array<array<float, 4>, 4> matrix;
+    sequenceId = 0;
 
     while(true) {
         {
@@ -355,82 +375,106 @@
             }
         }
 
-        // TODO(b/150412555): use hard-coded views for now. Change view every
-        // frame.
-        int recViewId = sequenceId % 16;
-        for (int i=0; i<4; i++)
-            for (int j=0; j<4; j++) {
-                matrix[i][j] = kRecViews[recViewId][i*4+j];
-        }
+        LOG(INFO) << "Notify all. SequenceId " << sequenceId << " is ready";
+        framesAvailable = true;
+        mSignal.notify_all();
 
-        if (mSurroundView->Get3dSurroundView(
-            mInputPointers, matrix, &mOutputPointer)) {
-            LOG(INFO) << "Get3dSurroundView succeeded";
+        // TODO(b/150412555): adding delays explicitly. This delay should be
+        // removed when EVS camera is used.
+        this_thread::sleep_for(chrono::milliseconds(
+            kFrameDelayInMilliseconds));
+
+        sequenceId++;
+    }
+
+    // If we've been asked to stop, send an event to signal the actual end of stream
+    LOG(DEBUG) << "Notify SvEvent::STREAM_STOPPED";
+    mStream->notify(SvEvent::STREAM_STOPPED);
+}
+
+bool SurroundView3dSession::handleFrames(int sequenceId) {
+
+    LOG(INFO) << __FUNCTION__ << "Handling sequenceId " << sequenceId << ".";
+
+    // TODO(b/150412555): do not use the setViews for frames generation
+    // since there is a discrepancy between the HIDL APIs and core lib APIs.
+    array<array<float, 4>, 4> matrix;
+
+    // TODO(b/150412555): use hard-coded views for now. Change view every
+    // frame.
+    int recViewId = sequenceId % 16;
+    for (int i=0; i<4; i++)
+        for (int j=0; j<4; j++) {
+            matrix[i][j] = kRecViews[recViewId][i*4+j];
+    }
+
+    if (mSurroundView->Get3dSurroundView(
+        mInputPointers, matrix, &mOutputPointer)) {
+        LOG(INFO) << "Get3dSurroundView succeeded";
+    } else {
+        LOG(ERROR) << "Get3dSurroundView failed. "
+                   << "Using memset to initialize to gray.";
+        memset(mOutputPointer.data_pointer, kGrayColor,
+               mOutputHeight * mOutputWidth * kNumChannels);
+    }
+
+    void* textureDataPtr = nullptr;
+    mSvTexture->lock(GRALLOC_USAGE_SW_WRITE_OFTEN
+                    | GRALLOC_USAGE_SW_READ_NEVER,
+                    &textureDataPtr);
+    if (!textureDataPtr) {
+        LOG(ERROR) << "Failed to gain write access to GraphicBuffer!";
+        return false;
+    }
+
+    // Note: there is a chance that the stride of the texture is not the
+    // same as the width. For example, when the input frame is 1920 * 1080,
+    // the width is 1080, but the stride is 2048. So we'd better copy the
+    // data line by line, instead of single memcpy.
+    uint8_t* writePtr = static_cast<uint8_t*>(textureDataPtr);
+    uint8_t* readPtr = static_cast<uint8_t*>(mOutputPointer.data_pointer);
+    const int readStride = mOutputWidth * kNumChannels;
+    const int writeStride = mSvTexture->getStride() * kNumChannels;
+    if (readStride == writeStride) {
+        memcpy(writePtr, readPtr, readStride * mSvTexture->getHeight());
+    } else {
+        for (int i=0; i<mSvTexture->getHeight(); i++) {
+            memcpy(writePtr, readPtr, readStride);
+            writePtr = writePtr + writeStride;
+            readPtr = readPtr + readStride;
+        }
+    }
+    LOG(INFO) << "memcpy finished!";
+    mSvTexture->unlock();
+
+    ANativeWindowBuffer* buffer = mSvTexture->getNativeBuffer();
+    LOG(DEBUG) << "ANativeWindowBuffer->handle: " << buffer->handle;
+
+    framesRecord.frames.svBuffers.resize(1);
+    SvBuffer& svBuffer = framesRecord.frames.svBuffers[0];
+    svBuffer.viewId = 0;
+    svBuffer.hardwareBuffer.nativeHandle = buffer->handle;
+    AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<AHardwareBuffer_Desc *>(
+            &svBuffer.hardwareBuffer.description);
+    pDesc->width = mOutputWidth;
+    pDesc->height = mOutputHeight;
+    pDesc->layers = 1;
+    pDesc->usage = GRALLOC_USAGE_HW_TEXTURE;
+    pDesc->stride = mSvTexture->getStride();
+    pDesc->format = HAL_PIXEL_FORMAT_RGBA_8888;
+    framesRecord.frames.timestampNs = elapsedRealtimeNano();
+    framesRecord.frames.sequenceId = sequenceId;
+
+    {
+        scoped_lock<mutex> lock(mAccessLock);
+
+        if (framesRecord.inUse) {
+            LOG(DEBUG) << "Notify SvEvent::FRAME_DROPPED";
+            mStream->notify(SvEvent::FRAME_DROPPED);
         } else {
-            LOG(ERROR) << "Get3dSurroundView failed. "
-                       << "Using memset to initialize to gray.";
-            memset(mOutputPointer.data_pointer, kGrayColor,
-                   mOutputHeight * mOutputWidth * kNumChannels);
-        }
-
-        void* textureDataPtr = nullptr;
-        mSvTexture->lock(GRALLOC_USAGE_SW_WRITE_OFTEN
-                        | GRALLOC_USAGE_SW_READ_NEVER,
-                        &textureDataPtr);
-        if (!textureDataPtr) {
-            LOG(ERROR) << "Failed to gain write access to GraphicBuffer!";
-            break;
-        }
-
-        // Note: there is a chance that the stride of the texture is not the
-        // same as the width. For example, when the input frame is 1920 * 1080,
-        // the width is 1080, but the stride is 2048. So we'd better copy the
-        // data line by line, instead of single memcpy.
-        uint8_t* writePtr = static_cast<uint8_t*>(textureDataPtr);
-        uint8_t* readPtr = static_cast<uint8_t*>(mOutputPointer.data_pointer);
-        const int readStride = mOutputWidth * kNumChannels;
-        const int writeStride = mSvTexture->getStride() * kNumChannels;
-        if (readStride == writeStride) {
-            memcpy(writePtr, readPtr, readStride * mSvTexture->getHeight());
-        } else {
-            for (int i=0; i<mSvTexture->getHeight(); i++) {
-                memcpy(writePtr, readPtr, readStride);
-                writePtr = writePtr + writeStride;
-                readPtr = readPtr + readStride;
-            }
-        }
-        LOG(INFO) << "memcpy finished!";
-        mSvTexture->unlock();
-
-        ANativeWindowBuffer* buffer = mSvTexture->getNativeBuffer();
-        LOG(DEBUG) << "ANativeWindowBuffer->handle: " << buffer->handle;
-
-        framesRecord.frames.svBuffers.resize(1);
-        SvBuffer& svBuffer = framesRecord.frames.svBuffers[0];
-        svBuffer.viewId = 0;
-        svBuffer.hardwareBuffer.nativeHandle = buffer->handle;
-        AHardwareBuffer_Desc* pDesc =
-            reinterpret_cast<AHardwareBuffer_Desc *>(
-                &svBuffer.hardwareBuffer.description);
-        pDesc->width = mOutputWidth;
-        pDesc->height = mOutputHeight;
-        pDesc->layers = 1;
-        pDesc->usage = GRALLOC_USAGE_HW_TEXTURE;
-        pDesc->stride = mSvTexture->getStride();
-        pDesc->format = HAL_PIXEL_FORMAT_RGBA_8888;
-        framesRecord.frames.timestampNs = elapsedRealtimeNano();
-        framesRecord.frames.sequenceId = sequenceId++;
-
-        {
-            scoped_lock<mutex> lock(mAccessLock);
-
-            if (framesRecord.inUse) {
-                LOG(DEBUG) << "Notify SvEvent::FRAME_DROPPED";
-                mStream->notify(SvEvent::FRAME_DROPPED);
-            } else {
-                framesRecord.inUse = true;
-                mStream->receiveFrames(framesRecord.frames);
-            }
+            framesRecord.inUse = true;
+            mStream->receiveFrames(framesRecord.frames);
         }
 
         // TODO(b/150412555): adding delays explicitly. This delay should be
@@ -439,9 +483,7 @@
             kFrameDelayInMilliseconds));
     }
 
-    // If we've been asked to stop, send an event to signal the actual end of stream
-    LOG(DEBUG) << "Notify SvEvent::STREAM_STOPPED";
-    mStream->notify(SvEvent::STREAM_STOPPED);
+    return true;
 }
 
 bool SurroundView3dSession::initialize() {
diff --git a/surround_view/service-impl/SurroundView3dSession.h b/surround_view/service-impl/SurroundView3dSession.h
index 12337b6..ded6406 100644
--- a/surround_view/service-impl/SurroundView3dSession.h
+++ b/surround_view/service-impl/SurroundView3dSession.h
@@ -32,6 +32,8 @@
 using ::android::hardware::hidl_vec;
 using ::android::sp;
 
+using std::condition_variable;
+
 using namespace android_auto::surround_view;
 
 namespace android {
@@ -62,9 +64,13 @@
         projectCameraPointsTo3dSurface_cb _hidl_cb);
 
 private:
-    void generateFrames();
     bool initialize();
 
+    void generateFrames();
+    void processFrames();
+
+    bool handleFrames(int sequenceId);
+
     enum StreamStateValues {
         STOPPED,
         RUNNING,
@@ -77,6 +83,13 @@
     StreamStateValues mStreamState GUARDED_BY(mAccessLock);
 
     thread mCaptureThread; // The thread we'll use to synthesize frames
+    thread mProcessThread; // The thread we'll use to process frames
+
+    // Used to signal a set of frames is ready
+    condition_variable mSignal GUARDED_BY(mAccessLock);
+    bool framesAvailable GUARDED_BY(mAccessLock);
+
+    int sequenceId;
 
     struct FramesRecord {
         SvFramesDesc frames;