Merge changes I9953dcec,I5bc7034e into rvc-dev

* changes:
  Handles invalid requests to open EVS display
  Add a command line option for the buffer format
diff --git a/evs/apps/default/ConfigManager.h b/evs/apps/default/ConfigManager.h
index 6acd83d..9c6d1a2 100644
--- a/evs/apps/default/ConfigManager.h
+++ b/evs/apps/default/ConfigManager.h
@@ -19,6 +19,8 @@
 #include <vector>
 #include <string>
 
+#include <system/graphics-base.h>
+
 
 class ConfigManager {
 public:
@@ -91,6 +93,12 @@
     const DisplayInfo& getActiveDisplay() const { return mDisplays[mActiveDisplayId]; };
     void  useExternalMemory(bool flag) { mUseExternalMemory = flag; }
     bool  getUseExternalMemory() const { return mUseExternalMemory; }
+    void  setExternalMemoryFormat(android_pixel_format_t format) {
+        mExternalMemoryFormat = format;
+    }
+    android_pixel_format_t getExternalMemoryFormat() const {
+        return mExternalMemoryFormat;
+    }
 
 private:
     // Camera information
@@ -103,6 +111,9 @@
     // Memory management
     bool mUseExternalMemory;
 
+    // Format of external memory
+    android_pixel_format_t mExternalMemoryFormat;
+
     // Car body information (assumes front wheel steering and origin at center of rear axel)
     // Note that units aren't specified and don't matter as long as all length units are consistent
     // within the JSON file from which we parse.  That is, if everything is in meters, that's fine.
diff --git a/evs/apps/default/RenderDirectView.cpp b/evs/apps/default/RenderDirectView.cpp
index 2938521..68b731e 100644
--- a/evs/apps/default/RenderDirectView.cpp
+++ b/evs/apps/default/RenderDirectView.cpp
@@ -116,7 +116,8 @@
                                       mCameraDesc.v1.cameraId.c_str(),
                                       foundCfg ? std::move(targetCfg) : nullptr,
                                       sDisplay,
-                                      mConfig.getUseExternalMemory()));
+                                      mConfig.getUseExternalMemory(),
+                                      mConfig.getExternalMemoryFormat()));
     if (!mTexture) {
         LOG(ERROR) << "Failed to set up video texture for " << mCameraDesc.v1.cameraId;
 // TODO:  For production use, we may actually want to fail in this case, but not yet...
diff --git a/evs/apps/default/StreamHandler.cpp b/evs/apps/default/StreamHandler.cpp
index b1cfd1f..d350af1 100644
--- a/evs/apps/default/StreamHandler.cpp
+++ b/evs/apps/default/StreamHandler.cpp
@@ -30,6 +30,7 @@
 StreamHandler::StreamHandler(android::sp <IEvsCamera> pCamera,
                              uint32_t numBuffers,
                              bool useOwnBuffers,
+                             android_pixel_format_t format,
                              int32_t width,
                              int32_t height)
     : mCamera(pCamera),
@@ -46,7 +47,6 @@
         const auto usage = GRALLOC_USAGE_HW_TEXTURE |
                            GRALLOC_USAGE_SW_READ_RARELY |
                            GRALLOC_USAGE_SW_WRITE_OFTEN;
-        const auto format = HAL_PIXEL_FORMAT_RGBA_8888;
         for (auto i = 0; i < numBuffers; ++i) {
             unsigned pixelsPerLine;
             android::status_t result = alloc.allocate(width,
@@ -64,10 +64,10 @@
                 BufferDesc_1_1 buf;
                 AHardwareBuffer_Desc* pDesc =
                     reinterpret_cast<AHardwareBuffer_Desc *>(&buf.buffer.description);
-                pDesc->width = 640;
-                pDesc->height = 360;
+                pDesc->width = width;
+                pDesc->height = height;
                 pDesc->layers = 1;
-                pDesc->format = HAL_PIXEL_FORMAT_RGBA_8888;
+                pDesc->format = format;
                 pDesc->usage = GRALLOC_USAGE_HW_TEXTURE |
                                GRALLOC_USAGE_SW_READ_RARELY |
                                GRALLOC_USAGE_SW_WRITE_OFTEN;
diff --git a/evs/apps/default/StreamHandler.h b/evs/apps/default/StreamHandler.h
index f877c78..cb22b36 100644
--- a/evs/apps/default/StreamHandler.h
+++ b/evs/apps/default/StreamHandler.h
@@ -51,6 +51,7 @@
     StreamHandler(android::sp <IEvsCamera> pCamera,
                   uint32_t numBuffers = 2,
                   bool useOwnBuffers = false,
+                  android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888,
                   int32_t width = 640,
                   int32_t height = 360);
     void shutdown();
diff --git a/evs/apps/default/VideoTex.cpp b/evs/apps/default/VideoTex.cpp
index 94e734a..7491dfe 100644
--- a/evs/apps/default/VideoTex.cpp
+++ b/evs/apps/default/VideoTex.cpp
@@ -137,29 +137,39 @@
                              const char* evsCameraId,
                              std::unique_ptr<Stream> streamCfg,
                              EGLDisplay glDisplay,
-                             bool useExternalMemory) {
+                             bool useExternalMemory,
+                             android_pixel_format_t format) {
     // Set up the camera to feed this texture
     sp<IEvsCamera> pCamera = nullptr;
+    sp<StreamHandler> pStreamHandler = nullptr;
     if (streamCfg != nullptr) {
         pCamera = pEnum->openCamera_1_1(evsCameraId, *streamCfg);
+
+        // Initialize the stream that will help us update this texture's contents
+        pStreamHandler = new StreamHandler(pCamera,
+                                           2,     // number of buffers
+                                           useExternalMemory,
+                                           format,
+                                           streamCfg->width,
+                                           streamCfg->height);
     } else {
         pCamera =
             IEvsCamera::castFrom(pEnum->openCamera(evsCameraId))
             .withDefault(nullptr);
+
+        // Initialize the stream with the default resolution
+        pStreamHandler = new StreamHandler(pCamera,
+                                           2,     // number of buffers
+                                           useExternalMemory,
+                                           format);
     }
 
-    if (pCamera.get() == nullptr) {
+    if (pCamera == nullptr) {
         LOG(ERROR) << "Failed to allocate new EVS Camera interface for " << evsCameraId;
         return nullptr;
     }
 
-    // Initialize the stream that will help us update this texture's contents
-    sp<StreamHandler> pStreamHandler = new StreamHandler(pCamera,
-                                                         2,     // number of buffers
-                                                         useExternalMemory,
-                                                         streamCfg->width,
-                                                         streamCfg->height);
-    if (pStreamHandler.get() == nullptr) {
+    if (pStreamHandler == nullptr) {
         LOG(ERROR) << "Failed to allocate FrameHandler";
         return nullptr;
     }
diff --git a/evs/apps/default/VideoTex.h b/evs/apps/default/VideoTex.h
index d884faa..097d086 100644
--- a/evs/apps/default/VideoTex.h
+++ b/evs/apps/default/VideoTex.h
@@ -16,6 +16,9 @@
 #ifndef VIDEOTEX_H
 #define VIDEOTEX_H
 
+#include "StreamHandler.h"
+#include "TexWrapper.h"
+
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <GLES2/gl2.h>
@@ -25,9 +28,7 @@
 
 #include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
-
-#include "TexWrapper.h"
-#include "StreamHandler.h"
+#include <system/graphics-base.h>
 
 using ::android::hardware::camera::device::V3_2::Stream;
 using namespace ::android::hardware::automotive::evs::V1_1;
@@ -38,7 +39,8 @@
                                         const char *evsCameraId,
                                         std::unique_ptr<Stream> streamCfg,
                                         EGLDisplay glDisplay,
-                                        bool useExternalMemory);
+                                        bool useExternalMemory,
+                                        android_pixel_format_t format);
 
 public:
     VideoTex() = delete;
@@ -62,10 +64,13 @@
 };
 
 
+// Creates a video texture to draw the camera preview.  format is effective only
+// when useExternalMemory is true.
 VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
                              const char * deviceName,
                              std::unique_ptr<Stream> streamCfg,
                              EGLDisplay glDisplay,
-                             bool useExternalMemory = false);
+                             bool useExternalMemory = false,
+                             android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888);
 
 #endif // VIDEOTEX_H
diff --git a/evs/apps/default/evs_app.cpp b/evs/apps/default/evs_app.cpp
index a968990..9f2f2c8 100644
--- a/evs/apps/default/evs_app.cpp
+++ b/evs/apps/default/evs_app.cpp
@@ -14,24 +14,25 @@
  * limitations under the License.
  */
 
+#include "ConfigManager.h"
+#include "EvsStateControl.h"
+#include "EvsVehicleListener.h"
+
 #include <stdio.h>
 
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>    // arraysize
+#include <android-base/strings.h>
 #include <hidl/HidlTransportSupport.h>
+#include <hwbinder/ProcessState.h>
 #include <utils/Errors.h>
 #include <utils/StrongPointer.h>
 #include <utils/Log.h>
 
-#include "android-base/macros.h"    // arraysize
-#include "android-base/logging.h"
 
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
-
-#include <hwbinder/ProcessState.h>
-
-#include "EvsStateControl.h"
-#include "EvsVehicleListener.h"
-#include "ConfigManager.h"
+using android::base::EqualsIgnoreCase;
 
 // libhidl:
 using android::hardware::configureRpcThreadpool;
@@ -66,6 +67,24 @@
 }
 
 
+static bool convertStringToFormat(const char* str, android_pixel_format_t* output) {
+    bool result = true;
+    if (EqualsIgnoreCase(str, "RGBA8888")) {
+        *output = HAL_PIXEL_FORMAT_RGBA_8888;
+    } else if (EqualsIgnoreCase(str, "YV12")) {
+        *output = HAL_PIXEL_FORMAT_YV12;
+    } else if (EqualsIgnoreCase(str, "NV21")) {
+        *output = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+    } else if (EqualsIgnoreCase(str, "YUYV")) {
+        *output = HAL_PIXEL_FORMAT_YCBCR_422_I;
+    } else {
+        result = false;
+    }
+
+    return result;
+}
+
+
 // Main entry point
 int main(int argc, char** argv)
 {
@@ -77,6 +96,7 @@
     const char* evsServiceName = "default";
     int displayId = 1;
     bool useExternalMemory = false;
+    android_pixel_format_t extMemoryFormat = HAL_PIXEL_FORMAT_RGBA_8888;
     for (int i=1; i< argc; i++) {
         if (strcmp(argv[i], "--test") == 0) {
             useVehicleHal = false;
@@ -90,6 +110,19 @@
             displayId = std::stoi(argv[++i]);
         } else if (strcmp(argv[i], "--extmem") == 0) {
             useExternalMemory = true;
+            if (i + 1 >= argc) {
+                // use RGBA8888 by default
+                LOG(INFO) << "External buffer format is not set.  "
+                          << "RGBA8888 will be used.";
+            } else {
+                if (!convertStringToFormat(argv[i + 1], &extMemoryFormat)) {
+                    LOG(WARNING) << "Color format string " << argv[i + 1]
+                                 << " is unknown or not supported.  RGBA8888 will be used.";
+                } else {
+                    // move the index
+                    ++i;
+                }
+            }
         } else {
             printf("Ignoring unrecognized command line arg '%s'\n", argv[i]);
             printHelp = true;
@@ -97,11 +130,23 @@
     }
     if (printHelp) {
         printf("Options include:\n");
-        printf("  --test    Do not talk to Vehicle Hal, but simulate 'reverse' instead\n");
-        printf("  --hw      Bypass EvsManager by connecting directly to EvsEnumeratorHw\n");
-        printf("  --mock    Connect directly to EvsEnumeratorHw-Mock\n");
-        printf("  --display Specify the display to use\n");
-        printf("  --extmem  Application allocates buffers to capture camera frames\n");
+        printf("  --test\n\tDo not talk to Vehicle Hal, but simulate 'reverse' instead\n");
+        printf("  --hw\n\tBypass EvsManager by connecting directly to EvsEnumeratorHw\n");
+        printf("  --mock\n\tConnect directly to EvsEnumeratorHw-Mock\n");
+        printf("  --display\n\tSpecify the display to use\n");
+        printf("  --extmem  <format>\n\t"
+               "Application allocates buffers to capture camera frames.  "
+               "Available format strings are (case insensitive):\n");
+        printf("\t\tRGBA8888: 4x8-bit RGBA format.  This is the default format to be used "
+               "when no format is specified.\n");
+        printf("\t\tYV12: YUV420 planar format with a full resolution Y plane "
+               "followed by a V values, with U values last.\n");
+        printf("\t\tNV21: A biplanar format with a full resolution Y plane "
+               "followed by a single chrome plane with weaved V and U values.\n");
+        printf("\t\tYUYV: Packed format with a half horizontal chrome resolution.  "
+               "Known as YUV4:2:2.\n");
+
+        return EXIT_FAILURE;
     }
 
     // Load our configuration information
@@ -140,6 +185,7 @@
     }
     config.setActiveDisplayId(displayId);
     config.useExternalMemory(useExternalMemory);
+    config.setExternalMemoryFormat(extMemoryFormat);
 
     // Connect to the Vehicle HAL so we can monitor state
     sp<IVehicle> pVnet;
diff --git a/evs/manager/1.1/Enumerator.cpp b/evs/manager/1.1/Enumerator.cpp
index 8417828..8832db6 100644
--- a/evs/manager/1.1/Enumerator.cpp
+++ b/evs/manager/1.1/Enumerator.cpp
@@ -43,9 +43,13 @@
         // Get an internal display identifier.
         mHwEnumerator->getDisplayIdList(
             [this](const auto& displayPorts) {
-                if (displayPorts.size() > 0) {
-                    mInternalDisplayPort = displayPorts[0];
-                } else {
+                for (auto& port : displayPorts) {
+                    mDisplayPorts.push_back(port);
+                }
+
+                // The first element is the internal display
+                mInternalDisplayPort = mDisplayPorts.front();
+                if (mDisplayPorts.size() < 1) {
                     LOG(WARNING) << "No display is available to EVS service.";
                 }
             }
@@ -444,6 +448,11 @@
         return nullptr;
     }
 
+    if (std::find(mDisplayPorts.begin(), mDisplayPorts.end(), id) == mDisplayPorts.end()) {
+        LOG(ERROR) << "No display is available on the port " << static_cast<int32_t>(id);
+        return nullptr;
+    }
+
     // We simply keep track of the most recently opened display instance.
     // In the underlying layers we expect that a new open will cause the previous
     // object to be destroyed.  This avoids any race conditions associated with
diff --git a/evs/manager/1.1/Enumerator.h b/evs/manager/1.1/Enumerator.h
index f23871e..81c971f 100644
--- a/evs/manager/1.1/Enumerator.h
+++ b/evs/manager/1.1/Enumerator.h
@@ -93,6 +93,9 @@
     std::unordered_map<std::string,
                        CameraDesc>    mCameraDevices;
 
+    // List of available physical display devices
+    std::list<uint8_t>                mDisplayPorts;
+
     // Display port the internal display is connected to.
     uint8_t                           mInternalDisplayPort;
 
diff --git a/evs/sampleDriver/EvsEnumerator.cpp b/evs/sampleDriver/EvsEnumerator.cpp
index e108007..ef6009e 100644
--- a/evs/sampleDriver/EvsEnumerator.cpp
+++ b/evs/sampleDriver/EvsEnumerator.cpp
@@ -534,6 +534,12 @@
     }
 
     // Create a new display interface and return it
+    if (sDisplayPortList.find(port) == sDisplayPortList.end()) {
+        LOG(ERROR) << "No display is available on the port "
+                   << static_cast<int32_t>(port);
+        return nullptr;
+    }
+
     pActiveDisplay = new EvsGlDisplay(sDisplayProxy, sDisplayPortList[port]);
     sActiveDisplay = pActiveDisplay;