Use the incoming frames from EVS for SV 3d.

Bug: 157498592
Test: Used ffmpeg to simulate 4 cameras and then manually launched SV
service and app on Osprey

Change-Id: I970dd979efb7ebc4afb6f58668d2bb0170e9eb9d
diff --git a/surround_view/service-impl/SurroundView3dSession.cpp b/surround_view/service-impl/SurroundView3dSession.cpp
index fec0ce7..50015ff 100644
--- a/surround_view/service-impl/SurroundView3dSession.cpp
+++ b/surround_view/service-impl/SurroundView3dSession.cpp
@@ -57,6 +57,7 @@
 
 static const size_t kStreamCfgSz = sizeof(RawStreamConfig);
 static const uint8_t kGrayColor = 128;
+static const int kNumFrames = 4;
 static const int kNumChannels = 4;
 
 SurroundView3dSession::FramesHandler::FramesHandler(
@@ -69,7 +70,7 @@
     LOG(INFO) << "Ignores a frame delivered from v1.0 EVS service.";
     mCamera->doneWithFrame(bufDesc_1_0);
 
-    return Void();
+    return {};
 }
 
 Return<void> SurroundView3dSession::FramesHandler::deliverFrame_1_1(
@@ -80,13 +81,30 @@
     {
         scoped_lock<mutex> lock(mSession->mAccessLock);
         if (mSession->mProcessingEvsFrames) {
-            LOG(WARNING) << "EVS frames are being processed. Skip frames:" << mSession->mSequenceId;
+            LOG(WARNING) << "EVS frames are being processed. Skip frames:"
+                         << mSession->mSequenceId;
             mCamera->doneWithFrame_1_1(buffers);
             return {};
         }
     }
 
-    // TODO(b/157498592): Use EVS frames for SV stitching.
+    if (buffers.size() != kNumFrames) {
+        LOG(ERROR) << "The number of incoming frames is " << buffers.size()
+                   << ", which is different from the number " << kNumFrames
+                   << ", specified in config file";
+        return {};
+    }
+
+    {
+        scoped_lock<mutex> lock(mSession->mAccessLock);
+        for (int i = 0; i < kNumFrames; i++) {
+            LOG(DEBUG) << "Copying buffer No." << i
+                       << " to Surround View Service";
+            mSession->copyFromBufferToPointers(buffers[i],
+                                               mSession->mInputPointers[i]);
+        }
+    }
+
     mCamera->doneWithFrame_1_1(buffers);
 
     // Notify the session that a new set of frames is ready
@@ -96,7 +114,7 @@
     }
     mSession->mFramesSignal.notify_all();
 
-    return Void();
+    return {};
 }
 
 Return<void> SurroundView3dSession::FramesHandler::notify(const EvsEventDesc& event) {
@@ -129,7 +147,69 @@
             break;
     }
 
-    return Void();
+    return {};
+}
+
+bool SurroundView3dSession::copyFromBufferToPointers(
+    BufferDesc_1_1 buffer, SurroundViewInputBufferPointers pointers) {
+
+    AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<AHardwareBuffer_Desc *>(&buffer.buffer.description);
+
+    // create a GraphicBuffer from the existing handle
+    sp<GraphicBuffer> inputBuffer = new GraphicBuffer(
+        buffer.buffer.nativeHandle, GraphicBuffer::CLONE_HANDLE, pDesc->width,
+        pDesc->height, pDesc->format, pDesc->layers,
+        GRALLOC_USAGE_HW_TEXTURE, pDesc->stride);
+
+    if (inputBuffer == nullptr) {
+        LOG(ERROR) << "Failed to allocate GraphicBuffer to wrap image handle";
+        // Returning "true" in this error condition because we already released the
+        // previous image (if any) and so the texture may change in unpredictable
+        // ways now!
+        return false;
+    } else {
+        LOG(INFO) << "Managed to allocate GraphicBuffer with "
+                  << " width: " << pDesc->width
+                  << " height: " << pDesc->height
+                  << " format: " << pDesc->format
+                  << " stride: " << pDesc->stride;
+    }
+
+    // Lock the input GraphicBuffer and map it to a pointer.  If we failed to
+    // lock, return false.
+    void* inputDataPtr;
+    inputBuffer->lock(
+        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
+        &inputDataPtr);
+    if (!inputDataPtr) {
+        LOG(ERROR) << "Failed to gain read access to GraphicBuffer";
+        inputBuffer->unlock();
+        return false;
+    } else {
+        LOG(INFO) << "Managed to get read access to GraphicBuffer";
+    }
+
+    int stride = pDesc->stride;
+
+    // readPtr comes from EVS, and it is with 4 channels
+    uint8_t* readPtr = static_cast<uint8_t*>(inputDataPtr);
+
+    // writePtr is with 3 channels, since that is what SV core lib expects.
+    uint8_t* writePtr = static_cast<uint8_t*>(pointers.cpu_data_pointer);
+
+    for (int i = 0; i < pDesc->width; i++)
+        for (int j = 0; j < pDesc->height; j++) {
+            writePtr[(i + j * stride) * 3 + 0] =
+                readPtr[(i + j * stride) * 4 + 0];
+            writePtr[(i + j * stride) * 3 + 1] =
+                readPtr[(i + j * stride) * 4 + 1];
+            writePtr[(i + j * stride) * 3 + 2] =
+                readPtr[(i + j * stride) * 4 + 2];
+        }
+    LOG(INFO) << "Brute force copying finished";
+
+    return true;
 }
 
 void SurroundView3dSession::processFrames() {
@@ -627,19 +707,19 @@
                                      map<string, CarPart>());
     mSurroundView->SetStaticData(params);
 
-    // TODO(b/150412555): remove after EVS camera is used
-    mInputPointers = mSurroundView->ReadImages(
-        "/etc/automotive/sv/cam0.png",
-        "/etc/automotive/sv/cam1.png",
-        "/etc/automotive/sv/cam2.png",
-        "/etc/automotive/sv/cam3.png");
-    if (mInputPointers.size() == 4
-        && mInputPointers[0].cpu_data_pointer != nullptr) {
-        LOG(INFO) << "ReadImages succeeded";
-    } else {
-        LOG(ERROR) << "Failed to read images";
-        return false;
+    mInputPointers.resize(4);
+    // TODO(b/157498737): the following parameters should be fed from config
+    // files. Remove the hard-coding values once I/O module is ready.
+    for (int i = 0; i < 4; i++) {
+        mInputPointers[i].width = 1920;
+        mInputPointers[i].height = 1024;
+        mInputPointers[i].format = Format::RGB;
+        mInputPointers[i].cpu_data_pointer =
+                (void*)new uint8_t[mInputPointers[i].width *
+                                   mInputPointers[i].height *
+                                   kNumChannels];
     }
+    LOG(INFO) << "Allocated 4 input pointers";
 
     mOutputWidth = Get3dParams().resolution.width;
     mOutputHeight = Get3dParams().resolution.height;
diff --git a/surround_view/service-impl/SurroundView3dSession.h b/surround_view/service-impl/SurroundView3dSession.h
index 2e43030..263cfd3 100644
--- a/surround_view/service-impl/SurroundView3dSession.h
+++ b/surround_view/service-impl/SurroundView3dSession.h
@@ -116,6 +116,9 @@
 
     bool handleFrames(int sequenceId);
 
+    bool copyFromBufferToPointers(BufferDesc_1_1 buffer,
+                                  SurroundViewInputBufferPointers pointers);
+
     enum StreamStateValues {
         STOPPED,
         RUNNING,