Adds ConfigReader + CarModelConfigReader + IOModule

- Contain both config readers
- Note this cl adds changes from ag/11835330
- Adds IO Module impl.

Bug: b/158480203
Test: atest io_module_tests
Change-Id: I66cf7c490be8f4833397741810d48266bf9c2c88
diff --git a/surround_view/service-impl/Android.bp b/surround_view/service-impl/Android.bp
index 6abd8f2..97da1bb 100644
--- a/surround_view/service-impl/Android.bp
+++ b/surround_view/service-impl/Android.bp
@@ -38,8 +38,47 @@
         "libutils",
     ],
     required: [
-        "VolvoXC40_low.obj",
-        "VolvoXC40_low.mtl",
+        "cube.obj",
+        "cube.mtl",
+    ],
+}
+
+// Library for IO Module.
+cc_library {
+    name : "libio_module",
+    vendor : true,
+    srcs: [
+        "ConfigReader.cpp",
+        "CarModelConfigReader.cpp",
+        "ConfigReaderUtil.cpp",
+        "IOModule.cpp",
+    ],
+    shared_libs : [
+        "libbase",
+        "libobj_reader",
+        "libtinyxml2",
+    ]
+}
+
+cc_test{
+    name : "io_module_tests",
+    test_suites : ["device-tests"],
+    vendor : true,
+    srcs : [
+        "CarModelConfigReaderTests.cpp",
+        "ConfigReaderTests.cpp",
+    ],
+    shared_libs : [
+        "libbase",
+        "libcutils",
+        "libio_module",
+        "libobj_reader",
+        "libtinyxml2",
+        "libutils",
+    ],
+    required: [
+        "sv_sample_car_model_config.xml",
+        "sv_sample_config.xml",
     ],
 }
 
@@ -223,3 +262,15 @@
     src: "test_data/cube.mtl",
     sub_dir: "automotive/sv",
 }
+
+prebuilt_etc {
+    name: "sv_sample_config.xml",
+    src: "test_data/sv_sample_config.xml",
+    sub_dir: "automotive/sv",
+}
+
+prebuilt_etc {
+    name:"sv_sample_car_model_config.xml",
+    src : "test_data/sv_sample_car_model_config.xml",
+    sub_dir : "automotive/sv",
+}
diff --git a/surround_view/service-impl/AnimationModule.h b/surround_view/service-impl/AnimationModule.h
index 52845ac..de8dd35 100644
--- a/surround_view/service-impl/AnimationModule.h
+++ b/surround_view/service-impl/AnimationModule.h
@@ -17,6 +17,7 @@
 #ifndef SURROUND_VIEW_SERVICE_IMPL_ANIMATION_H_
 #define SURROUND_VIEW_SERVICE_IMPL_ANIMATION_H_
 
+#include "IOModuleCommon.h"
 #include "core_lib.h"
 
 #include <utils/SystemClock.h>
@@ -37,206 +38,6 @@
 namespace V1_0 {
 namespace implementation {
 
-struct Range {
-    // Range start.
-    // Start value may be greater than end value.
-    float start;
-
-    // Range end.
-    float end;
-};
-
-// Rotation axis
-struct RotationAxis {
-    // Unit axis direction vector.
-    std::array<float, 3> axisVector;
-
-    // Rotate about this point.
-    std::array<float, 3> rotationPoint;
-};
-
-enum AnimationType {
-    // Rotate a part about an axis from a start to end angle.
-    ROTATION_ANGLE = 0,
-
-    // Continuously rotate a part about an axis by a specified angular speed.
-    ROTATION_SPEED = 1,
-
-    // Linearly translates a part from one point to another.
-    TRANSLATION = 2,
-
-    // Switch to another texture once.
-    SWITCH_TEXTURE_ONCE = 3,
-
-    // Adjust the brightness of the texture once.
-    ADJUST_GAMMA_ONCE = 4,
-
-    // Repeatedly toggle between two textures.
-    SWITCH_TEXTURE_REPEAT = 5,
-
-    // Repeatedly toggle between two gamma values.
-    ADJUST_GAMMA_REPEAT = 6,
-};
-
-// Rotation operation
-struct RotationOp {
-    // VHAL signal to trigger operation.
-    uint64_t vhalProperty;
-
-    // Rotation operation type.
-    AnimationType type;
-
-    // Rotation axis.
-    RotationAxis axis;
-
-    // Default rotation (angle/speed) value.
-    // It is used for default rotation when the signal is on while vhal_range is
-    // not provided.
-    float defaultRotationValue;
-
-    // Default animation time elapsed to finish the rotation operation.
-    // It is ignored if VHAL provides continuous signal value.
-    float animationTime;
-
-    // physical rotation range with start mapped to vhal_range start and
-    // end mapped to vhal_range end.
-    Range rotationRange;
-
-    // VHAL signal range.
-    // Un-supported types: STRING, BYTES and VEC
-    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
-    // VehiclePropertyType
-    Range vhalRange;
-};
-
-// Translation operation.
-struct TranslationOp {
-    // VHAL signal to trigger operation.
-    uint64_t vhalProperty;
-
-    // Translation operation type.
-    AnimationType type;
-
-    // Unit direction vector.
-    std::array<float, 3> direction;
-
-    // Default translation value.
-    // It is used for default translation when the signal is on while vhal_range
-    // is not provided.
-    float defaultTranslationValue;
-
-    // Default animation time elapsed to finish the texture operation.
-    // It is ignored if VHAL provides continuous signal value.
-    float animationTime;
-
-    // Physical translation range with start mapped to vhal_range start and
-    // end mapped to vhal_range end.
-    Range translationRange;
-
-    // VHAL signal range.
-    // Un-supported types: STRING, BYTES and VEC
-    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
-    // VehiclePropertyType
-    Range vhalRange;
-};
-
-// Texture operation.
-struct TextureOp {
-    // VHAL signal to trigger operation.
-    uint64_t vhalProperty;
-
-    // Texture operation type.
-    AnimationType type;
-
-    // Default texture id.
-    // It is used as default texture when the signal is on while vhal_range is
-    // not provided.
-    std::string defaultTexture;
-
-    // Default animation time elapsed to finish the texture operation.
-    // Unit is milliseconds.
-    // If the animation time is specified, the vhal_property is assumed to be
-    // on/off type.
-    // It is ignored if it is equal or less than zero and vhal_property is
-    // assumed to provide continuous value.
-    int animationTime;
-
-    // texture range mapped to texture_ids[i].first.
-    Range textureRange;
-
-    // VHAL signal range.
-    // Un-supported types: STRING, BYTES and VEC
-    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
-    // VehiclePropertyType
-    Range vhalRange;
-
-    // Texture ids for switching textures.
-    // Applicable for animation types: kSwitchTextureOnce and
-    // kSwitchTextureRepeated
-    // 0 - n-1
-    std::vector<std::pair<float, std::string>> textureIds;
-};
-
-// Gamma operation.
-struct GammaOp {
-    // VHAL signal to trigger operation.
-    uint64_t vhalProperty;
-
-    // Texture operation type.
-    // Applicable for animation types: kAdjustGammaOnce and kAdjustGammaRepeat.
-    AnimationType type;
-
-    // Default animation time elapsed to finish the gamma operation.
-    // Unit is milliseconds.
-    // If the animation time is specified, the vhal_property is assumed to be
-    // on/off type.
-    // It is ignored if it is equal or less than zero and vhal_property is
-    // assumed to provide continuous value.
-    int animationTime;
-
-    // Gamma range with start mapped to vhal_range start and
-    // end mapped to vhal_range end.
-    Range gammaRange;
-
-    // VHAL signal range.
-    // Un-supported types: STRING, BYTES and VEC
-    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
-    // VehiclePropertyType
-    Range vhalRange;
-};
-
-// Animation info of a car part
-struct AnimationInfo {
-    // Car animation part id(name). It is a unique id.
-    std::string partId;
-
-    // Car part parent name.
-    std::string parentId;
-
-    // Car part pose w.r.t parent's coordinate.
-    Mat4x4 pose;
-
-    // VHAL priority from high [0] to low [n-1]. Only VHALs specified in the
-    // vector have priority.
-    std::vector<uint64_t> vhalPriority;
-
-    // TODO(b/158245554): simplify xxOpsMap data structs.
-    // Map of gamma operations. Key value is VHAL property.
-    std::map<uint64_t, std::vector<GammaOp>> gammaOpsMap;
-
-    // Map of texture operations. Key value is VHAL property.
-    std::map<uint64_t, std::vector<TextureOp>> textureOpsMap;
-
-    // Map of rotation operations. Key value is VHAL property.
-    // Multiple rotation ops are supported and will be simultaneously animated in
-    // order if their rotation axis are different and rotation points are the
-    // same.
-    std::map<uint64_t, std::vector<RotationOp>> rotationOpsMap;
-
-    // Map of translation operations. Key value is VHAL property.
-    std::map<uint64_t, std::vector<TranslationOp>> translationOpsMap;
-};
-
 // Car animation class. It is constructed with textures, animations, and
 // vhal_handler. It automatically updates animation params when
 // GetUpdatedAnimationParams() is called.
diff --git a/surround_view/service-impl/CarModelConfigReader.cpp b/surround_view/service-impl/CarModelConfigReader.cpp
new file mode 100644
index 0000000..737d84a
--- /dev/null
+++ b/surround_view/service-impl/CarModelConfigReader.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2020 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 "IOModule"
+
+#include "CarModelConfigReader.h"
+#include "ConfigReaderUtil.h"
+#include "MathHelp.h"
+#include "core_lib.h"
+
+#include <android-base/logging.h>
+#include <tinyxml2.h>
+#include <sstream>
+#include <string>
+#include <utility>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// Macro returning IoStatus::ERROR_READ_ANIMATION if condition evaluates to false.
+#define RETURN_ERROR_STATUS_IF_FALSE(cond)         \
+    do {                                           \
+        if (!(cond)) {                             \
+            return IOStatus::ERROR_READ_ANIMATION; \
+        }                                          \
+    } while (0)
+
+using tinyxml2::XML_SUCCESS;
+using tinyxml2::XMLDocument;
+using tinyxml2::XMLElement;
+
+namespace {
+
+bool ReadValueHex(const XMLElement* parent, const char* elementName, uint32_t* hex) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    RETURN_IF_FALSE(ElementHasText(element));
+    *hex = std::stoul(element->GetText(), nullptr, 16);
+    return true;
+}
+
+bool ReadValueList(const XMLElement* parent, const char* elementName,
+                   std::vector<std::string>* valueList) {
+    valueList->clear();
+    for (const XMLElement* elem = parent->FirstChildElement(elementName); elem != nullptr;
+         elem = elem->NextSiblingElement(elementName)) {
+        RETURN_IF_FALSE(ElementHasText(elem));
+        valueList->push_back(std::string(elem->GetText()));
+    }
+    return true;
+}
+
+// ReadValue for SurroundView2dParams::BlendingType.
+bool ReadAnimationType(const XMLElement* parent, const char* elementName, AnimationType* type) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    RETURN_IF_FALSE(ElementHasText(element));
+    const std::string animationTypeStr(element->GetText());
+
+    if (animationTypeStr == "RotationAngle") {
+        *type = AnimationType::ROTATION_ANGLE;
+    } else if (animationTypeStr == "RotationSpeed") {
+        *type = AnimationType::ROTATION_SPEED;
+    } else if (animationTypeStr == "Translation") {
+        *type = AnimationType::TRANSLATION;
+    } else if (animationTypeStr == "SwitchTextureOnce") {
+        *type = AnimationType::SWITCH_TEXTURE_ONCE;
+    } else if (animationTypeStr == "AdjustGammaOnce") {
+        *type = AnimationType::ADJUST_GAMMA_ONCE;
+    } else if (animationTypeStr == "SwitchTextureRepeat") {
+        *type = AnimationType::SWITCH_TEXTURE_REPEAT;
+    } else if (animationTypeStr == "AdjustGammaRepeat") {
+        *type = AnimationType::ADJUST_GAMMA_REPEAT;
+    } else {
+        LOG(ERROR) << "Unknown AnimationType specified: " << animationTypeStr;
+        return false;
+    }
+    return true;
+}
+
+bool ReadRange(const XMLElement* parent, const char* elementName, Range* range) {
+    const XMLElement* rangeElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &rangeElem));
+    {
+        RETURN_IF_FALSE(ReadValue(rangeElem, "Start", &range->start));
+        RETURN_IF_FALSE(ReadValue(rangeElem, "End", &range->end));
+    }
+    return true;
+}
+
+bool ReadFloat3(const XMLElement* parent, const char* elementName, std::array<float, 3>* float3) {
+    const XMLElement* arrayElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &arrayElem));
+    {
+        RETURN_IF_FALSE(ReadValue(arrayElem, "X", &float3->at(0)));
+        RETURN_IF_FALSE(ReadValue(arrayElem, "Y", &float3->at(1)));
+        RETURN_IF_FALSE(ReadValue(arrayElem, "Z", &float3->at(2)));
+    }
+    return true;
+}
+
+// Generic template for reading a animation op, each op type must be specialized.
+template <typename OpType>
+bool ReadOp(const XMLElement* opElem, OpType* op) {
+    (void)opElem;
+    (void)op;
+    LOG(ERROR) << "Unexpected internal error: Op type in not supported.";
+    return false;
+}
+
+// Reads vhal property.
+bool ReadVhalProperty(const XMLElement* parent, const char* elementName, uint64_t* vhalProperty) {
+    const XMLElement* vhalPropElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &vhalPropElem));
+    {
+        uint32_t propertyId;
+        uint32_t areaId;
+        RETURN_IF_FALSE(ReadValueHex(vhalPropElem, "PropertyId", &propertyId));
+        RETURN_IF_FALSE(ReadValueHex(vhalPropElem, "AreaId", &areaId));
+        *vhalProperty = (static_cast<uint64_t>(propertyId) << 32) | areaId;
+    }
+    return true;
+}
+
+template <>
+bool ReadOp<RotationOp>(const XMLElement* rotationOpElem, RotationOp* rotationOp) {
+    RETURN_IF_FALSE(ReadVhalProperty(rotationOpElem, "VhalProperty", &rotationOp->vhalProperty));
+
+    RETURN_IF_FALSE(ReadAnimationType(rotationOpElem, "AnimationType", &rotationOp->type));
+
+    RETURN_IF_FALSE(ReadFloat3(rotationOpElem, "RotationAxis", &rotationOp->axis.axisVector));
+
+    RETURN_IF_FALSE(ReadFloat3(rotationOpElem, "RotationPoint", &rotationOp->axis.rotationPoint));
+
+    RETURN_IF_FALSE(
+            ReadValue(rotationOpElem, "DefaultRotationValue", &rotationOp->defaultRotationValue));
+
+    RETURN_IF_FALSE(ReadValue(rotationOpElem, "AnimationTimeMs", &rotationOp->animationTime));
+
+    RETURN_IF_FALSE(ReadRange(rotationOpElem, "RotationRange", &rotationOp->rotationRange));
+
+    RETURN_IF_FALSE(ReadRange(rotationOpElem, "VhalRange", &rotationOp->vhalRange));
+
+    return true;
+}
+
+template <>
+bool ReadOp<TranslationOp>(const XMLElement* translationOpElem, TranslationOp* translationOp) {
+    RETURN_IF_FALSE(
+            ReadVhalProperty(translationOpElem, "VhalProperty", &translationOp->vhalProperty));
+
+    RETURN_IF_FALSE(ReadAnimationType(translationOpElem, "AnimationType", &translationOp->type));
+
+    RETURN_IF_FALSE(ReadFloat3(translationOpElem, "Direction", &translationOp->direction));
+
+    RETURN_IF_FALSE(ReadValue(translationOpElem, "DefaultTranslationValue",
+                              &translationOp->defaultTranslationValue));
+
+    RETURN_IF_FALSE(ReadValue(translationOpElem, "AnimationTimeMs", &translationOp->animationTime));
+
+    RETURN_IF_FALSE(
+            ReadRange(translationOpElem, "TranslationRange", &translationOp->translationRange));
+
+    RETURN_IF_FALSE(ReadRange(translationOpElem, "VhalRange", &translationOp->vhalRange));
+
+    return true;
+}
+
+template <>
+bool ReadOp<TextureOp>(const XMLElement* textureOpElem, TextureOp* textureOp) {
+    RETURN_IF_FALSE(ReadVhalProperty(textureOpElem, "VhalProperty", &textureOp->vhalProperty));
+
+    RETURN_IF_FALSE(ReadAnimationType(textureOpElem, "AnimationType", &textureOp->type));
+
+    RETURN_IF_FALSE(ReadValue(textureOpElem, "DefaultTexture", &textureOp->defaultTexture));
+
+    RETURN_IF_FALSE(ReadValue(textureOpElem, "AnimationTimeMs", &textureOp->animationTime));
+
+    RETURN_IF_FALSE(ReadRange(textureOpElem, "TextureRange", &textureOp->textureRange));
+
+    RETURN_IF_FALSE(ReadRange(textureOpElem, "VhalRange", &textureOp->vhalRange));
+
+    return true;
+}
+
+template <>
+bool ReadOp<GammaOp>(const XMLElement* gammaOpElem, GammaOp* gammaOp) {
+    RETURN_IF_FALSE(ReadVhalProperty(gammaOpElem, "VhalProperty", &gammaOp->vhalProperty));
+
+    RETURN_IF_FALSE(ReadAnimationType(gammaOpElem, "AnimationType", &gammaOp->type));
+
+    RETURN_IF_FALSE(ReadValue(gammaOpElem, "AnimationTimeMs", &gammaOp->animationTime));
+
+    RETURN_IF_FALSE(ReadRange(gammaOpElem, "GammaRange", &gammaOp->gammaRange));
+
+    RETURN_IF_FALSE(ReadRange(gammaOpElem, "VhalRange", &gammaOp->vhalRange));
+
+    return true;
+}
+
+template <typename OpType>
+bool ReadAllOps(const XMLElement* animationElem, const char* elemName,
+                std::map<uint64_t, std::vector<OpType>>* mapOps) {
+    for (const XMLElement* elem = animationElem->FirstChildElement(elemName); elem != nullptr;
+         elem = elem->NextSiblingElement(elemName)) {
+        OpType op;
+        RETURN_IF_FALSE(ReadOp(elem, &op));
+        if (mapOps->find(op.vhalProperty) == mapOps->end()) {
+            mapOps->emplace(op.vhalProperty, std::vector<OpType>());
+        }
+        mapOps->at(op.vhalProperty).push_back(op);
+    }
+    return true;
+}
+
+bool ReadAnimation(const XMLElement* animationElem, AnimationInfo* animationInfo) {
+    RETURN_IF_FALSE(ReadValue(animationElem, "PartId", &animationInfo->partId));
+    RETURN_IF_FALSE(ReadValue(animationElem, "ParentPartId", &animationInfo->parentId));
+
+    // Child Part Ids (Optional)
+    const XMLElement* childPartsElem = nullptr;
+    GetElement(animationElem, "ChildParts", &childPartsElem);
+    if (childPartsElem != nullptr) {
+        RETURN_IF_FALSE(ReadValueList(childPartsElem, "PartId", &animationInfo->childIds));
+    }
+
+    // Set to the default Identity.
+    animationInfo->pose = gMat4Identity;
+
+    // All animation operations.
+    RETURN_IF_FALSE(ReadAllOps(animationElem, "RotationOp", &animationInfo->rotationOpsMap));
+    RETURN_IF_FALSE(ReadAllOps(animationElem, "TranslationOp", &animationInfo->translationOpsMap));
+    RETURN_IF_FALSE(ReadAllOps(animationElem, "TextureOp", &animationInfo->textureOpsMap));
+    RETURN_IF_FALSE(ReadAllOps(animationElem, "GammaOp", &animationInfo->gammaOpsMap));
+    return true;
+}
+
+bool ReadAllAnimations(const XMLElement* rootElem, std::vector<AnimationInfo>* animations) {
+    animations->clear();
+    // Loop over animation elements.
+    for (const XMLElement* elem = rootElem->FirstChildElement("Animation"); elem != nullptr;
+         elem = elem->NextSiblingElement("Animation")) {
+        AnimationInfo animationInfo;
+        RETURN_IF_FALSE(ReadAnimation(elem, &animationInfo));
+        animations->push_back(animationInfo);
+    }
+    return true;
+}
+
+}  // namespace
+
+IOStatus ReadCarModelConfig(const std::string& carModelConfigFile,
+                            AnimationConfig* animationConfig) {
+    XMLDocument xmlDoc;
+
+    /* load and parse a configuration file */
+    xmlDoc.LoadFile(carModelConfigFile.c_str());
+    if (xmlDoc.ErrorID() != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to load and/or parse a configuration file, " << xmlDoc.ErrorStr();
+        return IOStatus::ERROR_READ_ANIMATION;
+    }
+
+    const XMLElement* rootElem = xmlDoc.RootElement();
+    if (strcmp(rootElem->Name(), "SurroundViewCarModelConfig")) {
+        LOG(ERROR) << "A configuration file is not in the required format.  "
+                   << "See /etc/automotive/sv/sv_car_model_config.dtd";
+        return IOStatus::ERROR_READ_ANIMATION;
+    }
+
+    // version
+    RETURN_ERROR_STATUS_IF_FALSE(ReadValue(rootElem, "Version", &animationConfig->version));
+
+    // animations
+    RETURN_ERROR_STATUS_IF_FALSE(ReadAllAnimations(rootElem, &animationConfig->animations));
+
+    return IOStatus::OK;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/CarModelConfigReader.h b/surround_view/service-impl/CarModelConfigReader.h
new file mode 100644
index 0000000..c2e9049
--- /dev/null
+++ b/surround_view/service-impl/CarModelConfigReader.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 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 SURROUND_VIEW_SERVICE_IMPL_CARMODELCONFIGREADER_H_
+#define SURROUND_VIEW_SERVICE_IMPL_CARMODELCONFIGREADER_H_
+
+#include <string>
+
+#include "IOModuleCommon.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+IOStatus ReadCarModelConfig(const std::string& carModelConfigFile,
+                            AnimationConfig* animationConfig);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+
+}  // namespace android
+
+#endif  // SURROUND_VIEW_SERVICE_IMPL_CARMODELCONFIGREADER_H_
diff --git a/surround_view/service-impl/CarModelConfigReaderTests.cpp b/surround_view/service-impl/CarModelConfigReaderTests.cpp
new file mode 100644
index 0000000..c3c30d5
--- /dev/null
+++ b/surround_view/service-impl/CarModelConfigReaderTests.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2020 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 "IoModuleTests"
+
+#include "CarModelConfigReader.h"
+
+#include "MathHelp.h"
+#include "core_lib.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+namespace {
+
+TEST(CarModelConfigReaderTests, CarModelReadConfigSuccess) {
+    AnimationConfig animationConfig;
+    EXPECT_EQ(ReadCarModelConfig("/etc/automotive/sv/sv_sample_car_model_config.xml",
+                                 &animationConfig),
+              IOStatus::OK);
+
+    EXPECT_EQ(animationConfig.version, "1.0");
+
+    ASSERT_EQ(animationConfig.animations.size(), 2);
+
+    {
+        AnimationInfo frontLeftDoorAnimation = animationConfig.animations.at(0);
+        EXPECT_EQ(frontLeftDoorAnimation.partId, "front_left_door");
+        EXPECT_EQ(frontLeftDoorAnimation.childIds.size(), 2);
+        EXPECT_EQ(frontLeftDoorAnimation.pose, gMat4Identity);
+
+        EXPECT_EQ(frontLeftDoorAnimation.rotationOpsMap.size(), 1);
+        {
+            RotationOp frontLeftDoorRotationOp =
+                    (frontLeftDoorAnimation.rotationOpsMap.at(0x100000002)).at(0);
+            EXPECT_EQ(frontLeftDoorRotationOp.vhalProperty, 0x100000002);
+            EXPECT_EQ(frontLeftDoorRotationOp.type, AnimationType::ROTATION_ANGLE);
+            EXPECT_EQ(frontLeftDoorRotationOp.animationTime, 2000);
+            std::array<float, 3> axis = {1, 0, 0};
+            EXPECT_EQ(frontLeftDoorRotationOp.axis.axisVector, axis);
+            std::array<float, 3> point = {2, 2, 2};
+            EXPECT_EQ(frontLeftDoorRotationOp.axis.rotationPoint, point);
+            EXPECT_EQ(frontLeftDoorRotationOp.rotationRange.start, 0.0);
+            EXPECT_EQ(frontLeftDoorRotationOp.rotationRange.end, 90.0);
+            EXPECT_EQ(frontLeftDoorRotationOp.vhalRange.start, 0);
+            EXPECT_EQ(frontLeftDoorRotationOp.vhalRange.end, 0xFFFF);
+        }
+    }
+
+    {
+        AnimationInfo windowAnimation = animationConfig.animations.at(1);
+        EXPECT_EQ(windowAnimation.partId, "front_left_window");
+        EXPECT_EQ(windowAnimation.childIds.size(), 0);
+        EXPECT_EQ(windowAnimation.pose, gMat4Identity);
+
+        EXPECT_EQ(windowAnimation.translationOpsMap.size(), 1);
+        {
+            TranslationOp translationOp = (windowAnimation.translationOpsMap.at(0x200000001)).at(0);
+            EXPECT_EQ(translationOp.vhalProperty, 0x200000001);
+            EXPECT_EQ(translationOp.type, AnimationType::TRANSLATION);
+            EXPECT_EQ(translationOp.animationTime, 2000);
+            std::array<float, 3> dir = {0.0, 0.0, -1.0};
+            EXPECT_EQ(translationOp.direction, dir);
+            EXPECT_EQ(translationOp.defaultTranslationValue, 0.0);
+            EXPECT_EQ(translationOp.translationRange.start, 0.0);
+            EXPECT_EQ(translationOp.translationRange.end, 5.0);
+            EXPECT_EQ(translationOp.vhalRange.start, 0);
+            EXPECT_EQ(translationOp.vhalRange.end, 0xFFFF);
+        }
+    }
+}
+
+}  // namespace
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/ConfigReader.cpp b/surround_view/service-impl/ConfigReader.cpp
new file mode 100644
index 0000000..919427e
--- /dev/null
+++ b/surround_view/service-impl/ConfigReader.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2020 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 "IOModule"
+
+#include "ConfigReader.h"
+#include "ConfigReaderUtil.h"
+#include "core_lib.h"
+
+#include <android-base/logging.h>
+#include <tinyxml2.h>
+#include <sstream>
+#include <string>
+#include <utility>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using tinyxml2::XML_SUCCESS;
+using tinyxml2::XMLDocument;
+using tinyxml2::XMLElement;
+
+using android_auto::surround_view::SurroundView2dParams;
+using android_auto::surround_view::SurroundView3dParams;
+
+namespace {
+
+// Macro returning IoStatus::ERROR_CONFIG_FILE_FORMAT if condition evaluates to false.
+#define RETURN_ERROR_STATUS_IF_FALSE(cond)             \
+    do {                                               \
+        if (!(cond)) {                                 \
+            return IOStatus::ERROR_CONFIG_FILE_FORMAT; \
+        }                                              \
+    } while (0)
+
+// ReadValue for SurroundView2dParams::BlendingType.
+bool ReadValue2dBlendType(const XMLElement* parent, const char* elementName,
+                          SurroundView2dParams::BlendingType* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    RETURN_IF_FALSE(ElementHasText(element));
+    const std::string blendingTypeStr(element->GetText());
+
+    if (blendingTypeStr == "multiband") {
+        *value = SurroundView2dParams::BlendingType::MULTIBAND;
+    } else if (blendingTypeStr == "alpha") {
+        *value = SurroundView2dParams::BlendingType::ALPHA;
+    } else {
+        LOG(ERROR) << "Unknown BlendingType specified: " << blendingTypeStr;
+        return false;
+    }
+    return true;
+}
+
+bool ReadSvConfig2d(const XMLElement* parent, SvConfig2d* sv2dConfig) {
+    LOG(INFO) << "Seraching elem:"
+              << "Sv2dEnabled"
+              << "in parent: " << parent->Name();
+    RETURN_IF_FALSE(ReadValue(parent, "Sv2dEnabled", &sv2dConfig->sv2dEnabled));
+    if (!sv2dConfig->sv2dEnabled) {
+        return true;
+    }
+
+    SurroundView2dParams* sv2dParams = &sv2dConfig->sv2dParams;
+    const XMLElement* param2dElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, "Sv2dParams", &param2dElem));
+    {
+        // OutputResolution
+        const XMLElement* outputResolutionElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param2dElem, "OutputResolution", &outputResolutionElem));
+        {
+            RETURN_IF_FALSE(
+                    ReadValue(outputResolutionElem, "Width", &sv2dParams->resolution.width));
+            RETURN_IF_FALSE(
+                    ReadValue(outputResolutionElem, "Height", &sv2dParams->resolution.height));
+        }
+
+        // GroundMapping
+        const XMLElement* groundMappingElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param2dElem, "GroundMapping", &groundMappingElem));
+        {
+            RETURN_IF_FALSE(
+                    ReadValue(groundMappingElem, "Width", &sv2dParams->physical_size.width));
+            RETURN_IF_FALSE(
+                    ReadValue(groundMappingElem, "Height", &sv2dParams->physical_size.height));
+
+            // Center
+            const XMLElement* centerElem = nullptr;
+            RETURN_IF_FALSE(GetElement(groundMappingElem, "Center", &centerElem));
+            {
+                RETURN_IF_FALSE(ReadValue(centerElem, "X", &sv2dParams->physical_center.x));
+                RETURN_IF_FALSE(ReadValue(centerElem, "Y", &sv2dParams->physical_center.y));
+            }
+        }
+
+        // Car Bounding Box
+        const XMLElement* carBoundingBoxElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param2dElem, "CarBoundingBox", &carBoundingBoxElem));
+        {
+            RETURN_IF_FALSE(
+                    ReadValue(carBoundingBoxElem, "Width", &sv2dConfig->carBoundingBox.width));
+            RETURN_IF_FALSE(
+                    ReadValue(carBoundingBoxElem, "Height", &sv2dConfig->carBoundingBox.height));
+
+            // Center
+            const XMLElement* leftTopCornerElem = nullptr;
+            RETURN_IF_FALSE(GetElement(carBoundingBoxElem, "LeftTopCorner", &leftTopCornerElem));
+            {
+                RETURN_IF_FALSE(ReadValue(leftTopCornerElem, "X", &sv2dConfig->carBoundingBox.x));
+                RETURN_IF_FALSE(ReadValue(leftTopCornerElem, "Y", &sv2dConfig->carBoundingBox.y));
+            }
+        }
+
+        // Blending type
+        const XMLElement* blendingTypeElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param2dElem, "BlendingType", &blendingTypeElem));
+        {
+            RETURN_IF_FALSE(ReadValue2dBlendType(blendingTypeElem, "HighQuality",
+                                                 &sv2dParams->high_quality_blending));
+            RETURN_IF_FALSE(ReadValue2dBlendType(blendingTypeElem, "LowQuality",
+                                                 &sv2dParams->low_quality_blending));
+        }
+    }
+    return true;
+}
+
+bool ReadSvConfig3d(const XMLElement* parent, SvConfig3d* sv3dConfig) {
+    RETURN_IF_FALSE(ReadValue(parent, "Sv3dEnabled", &sv3dConfig->sv3dEnabled));
+    if (!sv3dConfig->sv3dEnabled) {
+        return true;
+    }
+    RETURN_IF_FALSE(ReadValue(parent, "Sv3dAnimationsEnabled", &sv3dConfig->sv3dAnimationsEnabled));
+
+    if (sv3dConfig->sv3dAnimationsEnabled) {
+        RETURN_IF_FALSE(ReadValue(parent, "CarModelConfigFile", &sv3dConfig->carModelConfigFile));
+    }
+
+    RETURN_IF_FALSE(ReadValue(parent, "CarModelObjFile", &sv3dConfig->carModelObjFile));
+
+    SurroundView3dParams* sv3dParams = &sv3dConfig->sv3dParams;
+    const XMLElement* param3dElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, "Sv3dParams", &param3dElem));
+    {
+        // OutputResolution
+        const XMLElement* outputResolutionElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param3dElem, "OutputResolution", &outputResolutionElem));
+        {
+            RETURN_IF_FALSE(
+                    ReadValue(outputResolutionElem, "Width", &sv3dParams->resolution.width));
+            RETURN_IF_FALSE(
+                    ReadValue(outputResolutionElem, "Height", &sv3dParams->resolution.height));
+        }
+
+        // Bowl Params
+        const XMLElement* bowlParamsElem = nullptr;
+        RETURN_IF_FALSE(GetElement(param3dElem, "BowlParams", &bowlParamsElem));
+        {
+            RETURN_IF_FALSE(ReadValue(bowlParamsElem, "PlaneRadius", &sv3dParams->plane_radius));
+            RETURN_IF_FALSE(
+                    ReadValue(bowlParamsElem, "PlaneDivisions", &sv3dParams->plane_divisions));
+            RETURN_IF_FALSE(ReadValue(bowlParamsElem, "CurveHeight", &sv3dParams->curve_height));
+            RETURN_IF_FALSE(
+                    ReadValue(bowlParamsElem, "CurveDivisions", &sv3dParams->curve_divisions));
+            RETURN_IF_FALSE(
+                    ReadValue(bowlParamsElem, "AngularDivisions", &sv3dParams->angular_divisions));
+            RETURN_IF_FALSE(
+                    ReadValue(bowlParamsElem, "CurveCoefficient", &sv3dParams->curve_coefficient));
+        }
+
+        // High Quality details
+        const XMLElement* highQualityDetailsElem = nullptr;
+        GetElement(param3dElem, "HighQualityDetails", &highQualityDetailsElem);
+        {
+            RETURN_IF_FALSE(ReadValue(highQualityDetailsElem, "Shadows",
+                                      &sv3dParams->high_details_shadows));
+            RETURN_IF_FALSE(ReadValue(highQualityDetailsElem, "Reflections",
+                                      &sv3dParams->high_details_reflections));
+        }
+    }
+    return true;
+}
+
+bool ReadCameraConfig(const XMLElement* parent, CameraConfig* cameraConfig) {
+    const XMLElement* cameraConfigElem = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, "CameraConfig", &cameraConfigElem));
+    {
+        // Evs Group Id
+        RETURN_IF_FALSE(ReadValue(cameraConfigElem, "EvsGroupId", &cameraConfig->evsGroupId));
+
+        // Evs Cameras Ids
+        const XMLElement* cameraIdsElem = nullptr;
+        RETURN_IF_FALSE(GetElement(cameraConfigElem, "EvsCameraIds", &cameraIdsElem));
+        {
+            cameraConfig->evsCameraIds.resize(4);
+            RETURN_IF_FALSE(ReadValue(cameraIdsElem, "Front", &cameraConfig->evsCameraIds[0]));
+            RETURN_IF_FALSE(ReadValue(cameraIdsElem, "Right", &cameraConfig->evsCameraIds[1]));
+            RETURN_IF_FALSE(ReadValue(cameraIdsElem, "Rear", &cameraConfig->evsCameraIds[2]));
+            RETURN_IF_FALSE(ReadValue(cameraIdsElem, "Left", &cameraConfig->evsCameraIds[3]));
+        }
+
+        // Masks (Optional).
+        const XMLElement* masksElem = nullptr;
+        GetElement(cameraConfigElem, "Masks", &masksElem);
+        if (masksElem != nullptr) {
+            cameraConfig->maskFilenames.resize(4);
+            RETURN_IF_FALSE(ReadValue(masksElem, "Front", &cameraConfig->maskFilenames[0]));
+            RETURN_IF_FALSE(ReadValue(masksElem, "Right", &cameraConfig->maskFilenames[1]));
+            RETURN_IF_FALSE(ReadValue(masksElem, "Rear", &cameraConfig->maskFilenames[2]));
+            RETURN_IF_FALSE(ReadValue(masksElem, "Left", &cameraConfig->maskFilenames[3]));
+        }
+    }
+    return true;
+}
+
+}  // namespace
+
+IOStatus ReadSurroundViewConfig(const std::string& configFile, SurroundViewConfig* svConfig) {
+    XMLDocument xmlDoc;
+
+    /* load and parse a configuration file */
+    xmlDoc.LoadFile(configFile.c_str());
+    if (xmlDoc.ErrorID() != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to load and/or parse a configuration file, " << xmlDoc.ErrorStr();
+        return IOStatus::ERROR_READ_CONFIG_FILE;
+    }
+
+    const XMLElement* rootElem = xmlDoc.RootElement();
+    if (strcmp(rootElem->Name(), "SurroundViewConfig")) {
+        LOG(ERROR) << "A configuration file is not in the required format.  "
+                   << "See /etc/automotive/sv/sv_config.dtd";
+        return IOStatus::ERROR_READ_CONFIG_FILE;
+    }
+
+    // version
+    RETURN_ERROR_STATUS_IF_FALSE(ReadValue(rootElem, "Version", &svConfig->version));
+
+    // CameraConfig
+    RETURN_ERROR_STATUS_IF_FALSE(ReadCameraConfig(rootElem, &svConfig->cameraConfig));
+
+    // Surround View 2D
+    RETURN_ERROR_STATUS_IF_FALSE(ReadSvConfig2d(rootElem, &svConfig->sv2dConfig));
+
+    // Surround View 3D
+    RETURN_ERROR_STATUS_IF_FALSE(ReadSvConfig3d(rootElem, &svConfig->sv3dConfig));
+
+    return IOStatus::OK;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/ConfigReader.h b/surround_view/service-impl/ConfigReader.h
new file mode 100644
index 0000000..7bdbe2a
--- /dev/null
+++ b/surround_view/service-impl/ConfigReader.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 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 SURROUND_VIEW_SERVICE_IMPL_CONFIGREADER_H_
+#define SURROUND_VIEW_SERVICE_IMPL_CONFIGREADER_H_
+
+#include <string>
+
+#include "IOModuleCommon.h"
+#include "core_lib.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// Parses the surround view config xml into struct SurroundViewConfig.
+IOStatus ReadSurroundViewConfig(const std::string& configFile, SurroundViewConfig* svConfig);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SURROUND_VIEW_SERVICE_IMPL_CONFIGREADER_H_
diff --git a/surround_view/service-impl/ConfigReaderTests.cpp b/surround_view/service-impl/ConfigReaderTests.cpp
new file mode 100644
index 0000000..a7042b7
--- /dev/null
+++ b/surround_view/service-impl/ConfigReaderTests.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2020 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 "ConfigReaderTests"
+
+#include "ConfigReader.h"
+
+#include "core_lib.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+namespace {
+
+using android_auto::surround_view::SurroundView2dParams;
+using android_auto::surround_view::SurroundView3dParams;
+
+TEST(ConfigReaderTests, ReadConfigSuccess) {
+    SurroundViewConfig svConfig;
+    EXPECT_EQ(ReadSurroundViewConfig("/etc/automotive/sv/sv_sample_config.xml", &svConfig),
+              IOStatus::OK);
+
+    EXPECT_EQ(svConfig.version, "1.0");
+
+    // Camera config
+    EXPECT_EQ(svConfig.cameraConfig.evsGroupId, "group0");
+
+    // Camera Ids
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[0], "/dev/video0");
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[1], "/dev/video1");
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[2], "/dev/video2");
+    EXPECT_EQ(svConfig.cameraConfig.evsCameraIds[3], "/dev/video3");
+
+    // Masks
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames.size(), 4);
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[0], "/vendor/mask_front.png");
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[1], "/vendor/mask_right.png");
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[2], "/vendor/mask_rear.png");
+    EXPECT_EQ(svConfig.cameraConfig.maskFilenames[3], "/vendor/mask_left.png");
+
+    // Surround view 2D
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dEnabled, true);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.resolution.width, 600);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.resolution.height, 900);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_size.width, 6.0);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_size.height, 9.0);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_center.x, 0.0);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.physical_center.y, 0.0);
+    EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.width, 2.0);
+    EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.height, 3.0);
+    EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.x, 1.0);
+    EXPECT_EQ(svConfig.sv2dConfig.carBoundingBox.y, 1.5);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.high_quality_blending,
+              SurroundView2dParams::BlendingType::MULTIBAND);
+    EXPECT_EQ(svConfig.sv2dConfig.sv2dParams.low_quality_blending,
+              SurroundView2dParams::BlendingType::ALPHA);
+
+    // Surround view 3D
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dEnabled, true);
+    EXPECT_NE(svConfig.sv3dConfig.carModelConfigFile, "");
+    EXPECT_NE(svConfig.sv3dConfig.carModelObjFile, "");
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.plane_radius, 6.0);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.plane_divisions, 20);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_height, 5.0);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_divisions, 30);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.angular_divisions, 50);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.curve_coefficient, 2.0);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.high_details_shadows, true);
+    EXPECT_EQ(svConfig.sv3dConfig.sv3dParams.high_details_reflections, true);
+}
+
+}  // namespace
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/ConfigReaderUtil.cpp b/surround_view/service-impl/ConfigReaderUtil.cpp
new file mode 100644
index 0000000..553108e
--- /dev/null
+++ b/surround_view/service-impl/ConfigReaderUtil.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2020 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 "IOModule"
+
+#include "ConfigReaderUtil.h"
+
+#include <android-base/logging.h>
+#include <tinyxml2.h>
+#include <utility>
+
+#include "core_lib.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+using tinyxml2::XML_SUCCESS;
+using tinyxml2::XMLElement;
+
+bool ElementHasText(const XMLElement* element) {
+    if (element->GetText() == "") {
+        LOG(ERROR) << "Expected element to have text: " << element->Name();
+        return false;
+    }
+    return true;
+}
+
+bool GetElement(const XMLElement* parent, const char* elementName, XMLElement const** element) {
+    *element = parent->FirstChildElement(elementName);
+    if (*element == nullptr) {
+        LOG(ERROR) << "Expected element '" << elementName << "' in parent '" << parent->Name()
+                   << "' not found";
+        return false;
+    }
+    return true;
+}
+
+bool ReadValue(const XMLElement* parent, const char* elementName, bool* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    if (element->QueryBoolText(value) != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to read valid boolean value from: " << element->Name();
+        return false;
+    }
+    return true;
+}
+
+bool ReadValue(const XMLElement* parent, const char* elementName, std::string* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    RETURN_IF_FALSE(ElementHasText(element));
+    *value = std::string(element->GetText());
+    return true;
+}
+
+bool ReadValue(const XMLElement* parent, const char* elementName, float* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    if (element->QueryFloatText(value) != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to read valid float value from: " << element->Name();
+        return false;
+    }
+    return true;
+}
+
+bool ReadValue(const XMLElement* parent, const char* elementName, int* value) {
+    const XMLElement* element = nullptr;
+    RETURN_IF_FALSE(GetElement(parent, elementName, &element));
+    if (element->QueryIntText(value) != XML_SUCCESS) {
+        LOG(ERROR) << "Failed to read valid int value from: " << element->Name();
+        return false;
+    }
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/ConfigReaderUtil.h b/surround_view/service-impl/ConfigReaderUtil.h
new file mode 100644
index 0000000..d4bd713
--- /dev/null
+++ b/surround_view/service-impl/ConfigReaderUtil.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 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 SURROUND_VIEW_SERVICE_IMPL_CONFIGREADERUTIL_H_
+#define SURROUND_VIEW_SERVICE_IMPL_CONFIGREADERUTIL_H_
+
+#include <tinyxml2.h>
+#include <sstream>
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// Macro returning false if condition evaluates to false.
+#define RETURN_IF_FALSE(cond) \
+    do {                      \
+        if (!(cond)) {        \
+            return false;     \
+        }                     \
+    } while (0)
+
+// Returns true if element has text.
+bool ElementHasText(const tinyxml2::XMLElement* element);
+
+// Gets a xml element from the parent element, returns false if not found.
+bool GetElement(const tinyxml2::XMLElement* parent, const char* elementName,
+                tinyxml2::XMLElement const** element);
+
+// Reads a boolean value from a element.
+bool ReadValue(const tinyxml2::XMLElement* parent, const char* elementName, bool* value);
+
+// Reads a string value from a element.
+bool ReadValue(const tinyxml2::XMLElement* parent, const char* elementName, std::string* value);
+
+// Reads a float value from a element.
+bool ReadValue(const tinyxml2::XMLElement* parent, const char* elementName, float* value);
+
+// Reads a int value from a element.
+bool ReadValue(const tinyxml2::XMLElement* parent, const char* elementName, int* value);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SURROUND_VIEW_SERVICE_IMPL_CONFIGREADERUTIL_H_
diff --git a/surround_view/service-impl/IOModule.cpp b/surround_view/service-impl/IOModule.cpp
new file mode 100644
index 0000000..3ab644b
--- /dev/null
+++ b/surround_view/service-impl/IOModule.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 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 "IOModule"
+
+#include <android-base/logging.h>
+
+#include "CarModelConfigReader.h"
+#include "ConfigReader.h"
+#include "IOModule.h"
+#include "ObjReader.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+IOModule::IOModule(const std::string& svConfigFile) :
+      mSvConfigFile(svConfigFile), mIsInitialized(false) {}
+
+IOStatus IOModule::initialize() {
+    if (mIsInitialized) {
+        LOG(INFO) << "IOModule is already initialized.";
+        return IOStatus::OK;
+    }
+
+    SurroundViewConfig svConfig;
+    IOStatus status;
+    if ((status = ReadSurroundViewConfig(mSvConfigFile, &svConfig)) != IOStatus::OK) {
+        LOG(ERROR) << "ReadSurroundViewConfig() failed.";
+        return status;
+    }
+
+    mIOModuleConfig.cameraConfig = svConfig.cameraConfig;
+    mIOModuleConfig.sv2dConfig = svConfig.sv2dConfig;
+    mIOModuleConfig.sv3dConfig = svConfig.sv3dConfig;
+
+    if (mIOModuleConfig.sv3dConfig.sv3dEnabled) {
+        // Read obj and mtl files.
+        if (!ReadObjFromFile(svConfig.sv3dConfig.carModelObjFile,
+                             &mIOModuleConfig.carModelConfig.carModel.partsMap)) {
+            LOG(ERROR) << "ReadObjFromFile() failed.";
+            return IOStatus::ERROR_READ_CAR_MODEL;
+        }
+        // Read animations.
+        if (mIOModuleConfig.sv3dConfig.sv3dAnimationsEnabled) {
+            if ((status = ReadCarModelConfig(svConfig.sv3dConfig.carModelConfigFile,
+                                             &mIOModuleConfig.carModelConfig.animationConfig)) !=
+                IOStatus::OK) {
+                LOG(ERROR) << "ReadObjFromFile() failed.";
+                return status;
+            }
+        }
+    }
+    mIsInitialized = true;
+    return IOStatus::OK;
+}
+
+bool IOModule::getConfig(IOModuleConfig* ioModuleConfig) {
+    if (!mIsInitialized) {
+        LOG(ERROR) << "IOModule not initalized.";
+        return false;
+    }
+    *ioModuleConfig = mIOModuleConfig;
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/IOModule.h b/surround_view/service-impl/IOModule.h
new file mode 100644
index 0000000..2e19dc5
--- /dev/null
+++ b/surround_view/service-impl/IOModule.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 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 SURROUND_VIEW_SERVICE_IMPL_IOMODULE_H_
+#define SURROUND_VIEW_SERVICE_IMPL_IOMODULE_H_
+
+#include "IOModuleCommon.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// I/O Module class processing all I/O related operations.
+class IOModule {
+public:
+    // Constructor with file name( and path) of config file.
+    IOModule(const std::string& svConfigFile);
+
+    // Reads all config files and stores parsed results in mIOModuleConfig.
+    IOStatus initialize();
+
+    // Gets config data read from files. initialize must be called this.
+    bool getConfig(IOModuleConfig* ioModuleConfig);
+
+private:
+    // Config string filename.
+    std::string mSvConfigFile;
+
+    // Indicates initialize success/fail.
+    bool mIsInitialized;
+
+    // Stores the parsed config.
+    IOModuleConfig mIOModuleConfig;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+#endif  // SURROUND_VIEW_SERVICE_IMPL_IOMODULE_H_
diff --git a/surround_view/service-impl/IOModuleCommon.h b/surround_view/service-impl/IOModuleCommon.h
new file mode 100644
index 0000000..fba878f
--- /dev/null
+++ b/surround_view/service-impl/IOModuleCommon.h
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2020 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 SURROUND_VIEW_SERVICE_IMPL_IOMODULECOMMON_H_
+#define SURROUND_VIEW_SERVICE_IMPL_IOMODULECOMMON_H_
+
+#include <string>
+
+#include "core_lib.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+// Struct for camera related configurations.
+// Note: Does not camera intrinsics and extrinsics, these are specified in EVS metadata.
+struct CameraConfig {
+    // Id of logical group containing surronnd view cameras.
+    std::string evsGroupId;
+
+    // List of evs camera Ids  in order: front, right, rear, left.
+    std::vector<std::string> evsCameraIds;
+
+    // In order: front, right, rear, left.
+    std::vector<std::string> maskFilenames;
+};
+
+struct SvConfig2d {
+    // Bool flag for surround view 2d.
+    bool sv2dEnabled;
+
+    // Surround view 2d params.
+    android_auto::surround_view::SurroundView2dParams sv2dParams;
+
+    // Car model bounding box for 2d surround view.
+    // To be moved into sv 2d params.
+    android_auto::surround_view::BoundingBox carBoundingBox;
+};
+
+struct SvConfig3d {
+    // Bool flag for enabling/disabling surround view 3d.
+    bool sv3dEnabled;
+
+    // Bool flag for enabling/disabling animations.
+    bool sv3dAnimationsEnabled;
+
+    // Car model config file.
+    std::string carModelConfigFile;
+
+    // Car model obj file.
+    std::string carModelObjFile;
+
+    // Surround view 3d params.
+    android_auto::surround_view::SurroundView3dParams sv3dParams;
+};
+
+// Main struct in which surround view config is parsed into.
+struct SurroundViewConfig {
+    // Version info.
+    std::string version;
+
+    // Camera config.
+    CameraConfig cameraConfig;
+
+    // Surround view 2d config.
+    SvConfig2d sv2dConfig;
+
+    // Surround view 3d config.
+    SvConfig3d sv3dConfig;
+};
+
+struct Range {
+    // Range start.
+    // Start value may be greater than end value.
+    float start;
+
+    // Range end.
+    float end;
+};
+
+// Rotation axis
+struct RotationAxis {
+    // Unit axis direction vector.
+    std::array<float, 3> axisVector;
+
+    // Rotate about this point.
+    std::array<float, 3> rotationPoint;
+};
+
+enum AnimationType {
+    // Rotate a part about an axis from a start to end angle.
+    ROTATION_ANGLE = 0,
+
+    // Continuously rotate a part about an axis by a specified angular speed.
+    ROTATION_SPEED = 1,
+
+    // Linearly translates a part from one point to another.
+    TRANSLATION = 2,
+
+    // Switch to another texture once.
+    SWITCH_TEXTURE_ONCE = 3,
+
+    // Adjust the brightness of the texture once.
+    ADJUST_GAMMA_ONCE = 4,
+
+    // Repeatedly toggle between two textures.
+    SWITCH_TEXTURE_REPEAT = 5,
+
+    // Repeatedly toggle between two gamma values.
+    ADJUST_GAMMA_REPEAT = 6,
+};
+
+// Rotation operation
+struct RotationOp {
+    // VHAL signal to trigger operation.
+    uint64_t vhalProperty;
+
+    // Rotation operation type.
+    AnimationType type;
+
+    // Rotation axis.
+    RotationAxis axis;
+
+    // Default rotation (angle/speed) value.
+    // It is used for default rotation when the signal is on while vhal_range is
+    // not provided.
+    float defaultRotationValue;
+
+    // Default animation time elapsed to finish the rotation operation.
+    // It is ignored if VHAL provides continuous signal value.
+    float animationTime;
+
+    // physical rotation range with start mapped to vhal_range start and
+    // end mapped to vhal_range end.
+    Range rotationRange;
+
+    // VHAL signal range.
+    // Un-supported types: STRING, BYTES and VEC
+    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
+    // VehiclePropertyType
+    Range vhalRange;
+};
+
+// Translation operation.
+struct TranslationOp {
+    // VHAL signal to trigger operation.
+    uint64_t vhalProperty;
+
+    // Translation operation type.
+    AnimationType type;
+
+    // Unit direction vector.
+    std::array<float, 3> direction;
+
+    // Default translation value.
+    // It is used for default translation when the signal is on while vhal_range
+    // is not provided.
+    float defaultTranslationValue;
+
+    // Default animation time elapsed to finish the texture operation.
+    // It is ignored if VHAL provides continuous signal value.
+    float animationTime;
+
+    // Physical translation range with start mapped to vhal_range start and
+    // end mapped to vhal_range end.
+    Range translationRange;
+
+    // VHAL signal range.
+    // Un-supported types: STRING, BYTES and VEC
+    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
+    // VehiclePropertyType
+    Range vhalRange;
+};
+
+// Texture operation.
+struct TextureOp {
+    // VHAL signal to trigger operation.
+    uint64_t vhalProperty;
+
+    // Texture operation type.
+    AnimationType type;
+
+    // Default texture id.
+    // It is used as default texture when the signal is on while vhal_range is
+    // not provided.
+    std::string defaultTexture;
+
+    // Default animation time elapsed to finish the texture operation.
+    // Unit is milliseconds.
+    // If the animation time is specified, the vhal_property is assumed to be
+    // on/off type.
+    // It is ignored if it is equal or less than zero and vhal_property is
+    // assumed to provide continuous value.
+    int animationTime;
+
+    // texture range mapped to texture_ids[i].first.
+    Range textureRange;
+
+    // VHAL signal range.
+    // Un-supported types: STRING, BYTES and VEC
+    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
+    // VehiclePropertyType
+    Range vhalRange;
+
+    // Texture ids for switching textures.
+    // Applicable for animation types: kSwitchTextureOnce and
+    // kSwitchTextureRepeated
+    // 0 - n-1
+    std::vector<std::pair<float, std::string>> textureIds;
+};
+
+// Gamma operation.
+struct GammaOp {
+    // VHAL signal to trigger operation.
+    uint64_t vhalProperty;
+
+    // Texture operation type.
+    // Applicable for animation types: kAdjustGammaOnce and kAdjustGammaRepeat.
+    AnimationType type;
+
+    // Default animation time elapsed to finish the gamma operation.
+    // Unit is milliseconds.
+    // If the animation time is specified, the vhal_property is assumed to be
+    // on/off type.
+    // It is ignored if it is equal or less than zero and vhal_property is
+    // assumed to provide continuous value.
+    int animationTime;
+
+    // Gamma range with start mapped to vhal_range start and
+    // end mapped to vhal_range end.
+    Range gammaRange;
+
+    // VHAL signal range.
+    // Un-supported types: STRING, BYTES and VEC
+    // Refer:  hardware/interfaces/automotive/vehicle/2.0/types.hal
+    // VehiclePropertyType
+    Range vhalRange;
+};
+
+// Animation info of a car part
+struct AnimationInfo {
+    // Car animation part id(name). It is a unique id.
+    std::string partId;
+
+    // Car part parent name.
+    std::string parentId;
+
+    // List of child Ids.
+    std::vector<std::string> childIds;
+
+    // Car part pose w.r.t parent's coordinate.
+    android_auto::surround_view::Mat4x4 pose;
+
+    // VHAL priority from high [0] to low [n-1]. Only VHALs specified in the
+    // vector have priority.
+    std::vector<uint64_t> vhalPriority;
+
+    // TODO(b/158245554): simplify xxOpsMap data structs.
+    // Map of gamma operations. Key value is VHAL property.
+    std::map<uint64_t, std::vector<GammaOp>> gammaOpsMap;
+
+    // Map of texture operations. Key value is VHAL property.
+    std::map<uint64_t, std::vector<TextureOp>> textureOpsMap;
+
+    // Map of rotation operations. Key value is VHAL property.
+    // Multiple rotation ops are supported and will be simultaneously animated in
+    // order if their rotation axis are different and rotation points are the
+    // same.
+    std::map<uint64_t, std::vector<RotationOp>> rotationOpsMap;
+
+    // Map of translation operations. Key value is VHAL property.
+    std::map<uint64_t, std::vector<TranslationOp>> translationOpsMap;
+};
+
+// Main struct in which surround view car model config is parsed into.
+struct AnimationConfig {
+    std::string version;
+
+    std::vector<AnimationInfo> animations;
+};
+
+// Car model.
+struct CarModel {
+    // Car model parts map.
+    std::map<std::string, android_auto::surround_view::CarPart> partsMap;
+
+    // Car testures map.
+    std::map<std::string, android_auto::surround_view::CarTexture> texturesMap;
+};
+
+struct CarModelConfig {
+    CarModel carModel;
+
+    AnimationConfig animationConfig;
+};
+
+struct IOModuleConfig {
+    // Camera config.
+    CameraConfig cameraConfig;
+
+    // Surround view 2d config.
+    SvConfig2d sv2dConfig;
+
+    // Surround view 3d config.
+    SvConfig3d sv3dConfig;
+
+    // Car model config.
+    CarModelConfig carModelConfig;
+};
+
+enum IOStatus : uint8_t {
+    // OK ststus. ALL fields read and parsed.
+    OK = 0,
+
+    // Error status. Cannot read the config file (config file missing or not
+    // accessible)
+    ERROR_READ_CONFIG_FILE = 1,
+
+    // Error ststus. Config file format doesn't match.
+    ERROR_CONFIG_FILE_FORMAT = 2,
+
+    // Warning status. Read car model (obj, mtl) error. Either the files are
+    // missing or wrong format.
+    ERROR_READ_CAR_MODEL = 3,
+
+    // Warning status. Read animation config file error. Either the file is
+    // missing or wrong format.
+    ERROR_READ_ANIMATION = 4,
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SURROUND_VIEW_SERVICE_IMPL_IOMODULECOMMON_H_
diff --git a/surround_view/service-impl/MathHelp.h b/surround_view/service-impl/MathHelp.h
index fa20af6..6623594 100644
--- a/surround_view/service-impl/MathHelp.h
+++ b/surround_view/service-impl/MathHelp.h
@@ -28,6 +28,8 @@
 namespace V1_0 {
 namespace implementation {
 
+using android_auto::surround_view::Mat4x4;
+
 const int gMat4Size = 4 * 4 * sizeof(float);
 
 const Mat4x4 gMat4Identity = {1, 0, 0, /*tx=*/0.0, 0, 1, 0, /*ty=*/0,
diff --git a/surround_view/service-impl/MtlReader.cpp b/surround_view/service-impl/MtlReader.cpp
index d86a15a..3d8bf8c 100644
--- a/surround_view/service-impl/MtlReader.cpp
+++ b/surround_view/service-impl/MtlReader.cpp
@@ -13,13 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#define LOG_TAG "IOModule"
+
 #include "MtlReader.h"
 
 #include <android-base/logging.h>
 #include <cstdio>
 
-#define LOG_TAG "MtlReader"
-
 namespace android {
 namespace hardware {
 namespace automotive {
diff --git a/surround_view/service-impl/ObjReader.cpp b/surround_view/service-impl/ObjReader.cpp
index 174ef5b..5473287 100644
--- a/surround_view/service-impl/ObjReader.cpp
+++ b/surround_view/service-impl/ObjReader.cpp
@@ -13,6 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#define LOG_TAG "IOModule"
+
 #include "ObjReader.h"
 
 #include <array>
diff --git a/surround_view/service-impl/core_lib.h b/surround_view/service-impl/core_lib.h
index c2d31af..7a9e67d 100644
--- a/surround_view/service-impl/core_lib.h
+++ b/surround_view/service-impl/core_lib.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2020 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 WIRELESS_ANDROID_AUTOMOTIVE_CAML_SURROUND_VIEW_CORE_LIB_H_
 #define WIRELESS_ANDROID_AUTOMOTIVE_CAML_SURROUND_VIEW_CORE_LIB_H_
 
@@ -16,60 +32,57 @@
 // Of course, it is compatible to the 2d version bounding box and may be used
 // for other bounding box purpose (e.g., 2d bounding box in image).
 struct BoundingBox {
-  // (x,y) is bounding box's top left corner coordinate.
-  float x;
-  float y;
+    // (x,y) is bounding box's top left corner coordinate.
+    float x;
+    float y;
 
-  // (width, height) is the size of the bounding box.
-  float width;
-  float height;
+    // (width, height) is the size of the bounding box.
+    float width;
+    float height;
 
-  BoundingBox() : x(0.0f), y(0.0f), width(0.0f), height(0.0f) {}
+    BoundingBox() : x(0.0f), y(0.0f), width(0.0f), height(0.0f) {}
 
-  BoundingBox(float x_, float y_, float width_, float height_)
-      : x(x_), y(y_), width(width_), height(height_) {}
+    BoundingBox(float x_, float y_, float width_, float height_) :
+          x(x_), y(y_), width(width_), height(height_) {}
 
-  BoundingBox(const BoundingBox& bb_)
-      : x(bb_.x), y(bb_.y), width(bb_.width), height(bb_.height) {}
+    BoundingBox(const BoundingBox& bb_) :
+          x(bb_.x), y(bb_.y), width(bb_.width), height(bb_.height) {}
 
-  // Checks if data is valid.
-  bool IsValid() const { return width >= 0 && height >= 0; }
+    // Checks if data is valid.
+    bool IsValid() const { return width >= 0 && height >= 0; }
 
-  bool operator==(const BoundingBox& rhs) const {
-    return x == rhs.x && y == rhs.y && width == rhs.width &&
-           height == rhs.height;
-  }
+    bool operator==(const BoundingBox& rhs) const {
+        return x == rhs.x && y == rhs.y && width == rhs.width && height == rhs.height;
+    }
 
-  BoundingBox& operator=(const BoundingBox& rhs) {
-    x = rhs.x;
-    y = rhs.y;
-    width = rhs.width;
-    height = rhs.height;
-    return *this;
-  }
+    BoundingBox& operator=(const BoundingBox& rhs) {
+        x = rhs.x;
+        y = rhs.y;
+        width = rhs.width;
+        height = rhs.height;
+        return *this;
+    }
 };
 
 template <typename T>
 struct Coordinate2dBase {
-  // x coordinate.
-  T x;
+    // x coordinate.
+    T x;
 
-  // y coordinate.
-  T y;
+    // y coordinate.
+    T y;
 
-  Coordinate2dBase() : x(0), y(0) {}
+    Coordinate2dBase() : x(0), y(0) {}
 
-  Coordinate2dBase(T x_, T y_) : x(x_), y(y_) {}
+    Coordinate2dBase(T x_, T y_) : x(x_), y(y_) {}
 
-  bool operator==(const Coordinate2dBase& rhs) const {
-    return x == rhs.x && y == rhs.y;
-  }
+    bool operator==(const Coordinate2dBase& rhs) const { return x == rhs.x && y == rhs.y; }
 
-  Coordinate2dBase& operator=(const Coordinate2dBase& rhs) {
-    x = rhs.x;
-    y = rhs.y;
-    return *this;
-  }
+    Coordinate2dBase& operator=(const Coordinate2dBase& rhs) {
+        x = rhs.x;
+        y = rhs.y;
+        return *this;
+    }
 };
 
 // integer type size.
@@ -79,82 +92,80 @@
 typedef Coordinate2dBase<float> Coordinate2dFloat;
 
 struct Coordinate3dFloat {
-  // x coordinate.
-  float x;
+    // x coordinate.
+    float x;
 
-  // y coordinate.
-  float y;
+    // y coordinate.
+    float y;
 
-  // z coordinate.
-  float z;
+    // z coordinate.
+    float z;
 
-  Coordinate3dFloat() : x(0), y(0), z(0) {}
+    Coordinate3dFloat() : x(0), y(0), z(0) {}
 
-  Coordinate3dFloat(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {}
+    Coordinate3dFloat(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {}
 
-  bool operator==(const Coordinate3dFloat& rhs) const {
-    return x == rhs.x && y == rhs.y;
-  }
+    bool operator==(const Coordinate3dFloat& rhs) const { return x == rhs.x && y == rhs.y; }
 
-  Coordinate3dFloat& operator=(const Coordinate3dFloat& rhs) {
-    x = rhs.x;
-    y = rhs.y;
-    return *this;
-  }
+    Coordinate3dFloat& operator=(const Coordinate3dFloat& rhs) {
+        x = rhs.x;
+        y = rhs.y;
+        return *this;
+    }
 };
 
 //  pixel weight used for illumination assessment
 struct PixelWeight {
-  // x and y are the coordinates (absolute value) in image space.
-  // pixel coordinate x in horizontal direction.
-  float x;
+    // x and y are the coordinates (absolute value) in image space.
+    // pixel coordinate x in horizontal direction.
+    float x;
 
-  // pixel coordinate y in vertical direction.
-  float y;
+    // pixel coordinate y in vertical direction.
+    float y;
 
-  // pixel weight, range in [0, 1].
-  float weight;
+    // pixel weight, range in [0, 1].
+    float weight;
 
-  PixelWeight() : x(-1), y(-1), weight(0) {}
+    PixelWeight() : x(-1), y(-1), weight(0) {}
 
-  PixelWeight(int x_, int y_, int weight_) : x(x_), y(y_), weight(weight_) {}
+    PixelWeight(int x_, int y_, int weight_) : x(x_), y(y_), weight(weight_) {}
 
-  bool operator==(const PixelWeight& rhs) const {
-    return x == rhs.x && y == rhs.y && weight == rhs.weight;
-  }
+    bool operator==(const PixelWeight& rhs) const {
+        return x == rhs.x && y == rhs.y && weight == rhs.weight;
+    }
 
-  PixelWeight& operator=(const PixelWeight& rhs) {
-    x = rhs.x;
-    y = rhs.y;
-    weight = rhs.weight;
-    return *this;
-  }
+    PixelWeight& operator=(const PixelWeight& rhs) {
+        x = rhs.x;
+        y = rhs.y;
+        weight = rhs.weight;
+        return *this;
+    }
 };
 
 // base size 2d type template.
 template <typename T>
 struct Size2dBase {
-  // width of size.
-  T width;
+    // width of size.
+    T width;
 
-  // height of size.
-  T height;
+    // height of size.
+    T height;
 
-  Size2dBase() : width(0), height(0) {}
+    Size2dBase() : width(0), height(0) {}
 
-  Size2dBase(T width_, T height_) : width(width_), height(height_) {}
+    Size2dBase(T width_, T height_) : width(width_), height(height_) {}
 
-  bool IsValid() const { return width > 0 && height > 0; }
+    bool IsValid() const { return width > 0 && height > 0; }
 
-  bool operator==(const Size2dBase& rhs) const {
-    return width == rhs.width && height == rhs.height;
-  }
+    bool operator==(const Size2dBase& rhs) const {
+        return width == rhs.width && height == rhs.height;
+    }
 
-  Size2dBase& operator=(const Size2dBase& rhs) {
-    width = rhs.width;
-    height = rhs.height;
-    return *this;
-  }
+    Size2dBase& operator=(const Size2dBase& rhs) {
+        width = rhs.width;
+        height = rhs.height;
+        return *this;
+    }
 };
 
 // integer type size.
@@ -165,314 +176,338 @@
 
 //  surround view 2d parameters
 struct SurroundView2dParams {
-  // surround view 2d image resolution (width, height).
-  Size2dInteger resolution;
+    // surround view 2d image resolution (width, height).
+    Size2dInteger resolution;
 
-  // the physical size of surround view 2d area in surround view coordinate.
-  // (surround view coordinate is defined as X rightward, Y forward and
-  // the origin lies on the center of the (symmetric) bowl (ground).
-  // When bowl is not used, surround view coordinate origin lies on the
-  // center of car model bounding box.)
-  // The unit should be consistent with camera extrinsics (translation).
-  Size2dFloat physical_size;
+    // the physical size of surround view 2d area in surround view coordinate.
+    // (surround view coordinate is defined as X rightward, Y forward and
+    // the origin lies on the center of the (symmetric) bowl (ground).
+    // When bowl is not used, surround view coordinate origin lies on the
+    // center of car model bounding box.)
+    // The unit should be consistent with camera extrinsics (translation).
+    Size2dFloat physical_size;
 
-  // the center of surround view 2d area in surround view coordinate
-  // (consistent with extrinsics coordinate).
-  Coordinate2dFloat physical_center;
+    // the center of surround view 2d area in surround view coordinate
+    // (consistent with extrinsics coordinate).
+    Coordinate2dFloat physical_center;
 
-  SurroundView2dParams()
-      : resolution{0, 0},
-        physical_size{0.0f, 0.0f},
-        physical_center{0.0f, 0.0f} {}
+    // Enumeration for list of 2d blending types.
+    enum BlendingType { MULTIBAND = 0, ALPHA };
 
-  SurroundView2dParams(Size2dInteger resolution_, Size2dFloat physical_size_,
-                       Coordinate2dFloat physical_center_)
-      : resolution(resolution_),
-        physical_size(physical_size_),
-        physical_center(physical_center_) {}
+    // Blending type for high quality preset.
+    BlendingType high_quality_blending;
 
-  // Checks if data is valid.
-  bool IsValid() const {
-    return resolution.IsValid() && physical_size.IsValid();
-  }
+    // Blending type for low quality preset.
+    BlendingType low_quality_blending;
 
-  bool operator==(const SurroundView2dParams& rhs) const {
-    return resolution == rhs.resolution && physical_size == rhs.physical_size &&
-           physical_center == rhs.physical_center;
-  }
+    SurroundView2dParams() :
+          resolution{0, 0},
+          physical_size{0.0f, 0.0f},
+          physical_center{0.0f, 0.0f},
+          high_quality_blending(BlendingType::MULTIBAND),
+          low_quality_blending(BlendingType::ALPHA) {}
 
-  SurroundView2dParams& operator=(const SurroundView2dParams& rhs) {
-    resolution = rhs.resolution;
-    physical_size = rhs.physical_size;
-    physical_center = rhs.physical_center;
-    return *this;
-  }
+    SurroundView2dParams(Size2dInteger resolution_, Size2dFloat physical_size_,
+                         Coordinate2dFloat physical_center_) :
+          resolution(resolution_),
+          physical_size(physical_size_),
+          physical_center(physical_center_),
+          high_quality_blending(BlendingType::MULTIBAND),
+          low_quality_blending(BlendingType::ALPHA) {}
+
+    // Checks if data is valid.
+    bool IsValid() const { return resolution.IsValid() && physical_size.IsValid(); }
+
+    bool operator==(const SurroundView2dParams& rhs) const {
+        return resolution == rhs.resolution && physical_size == rhs.physical_size &&
+                physical_center == rhs.physical_center &&
+                high_quality_blending == rhs.high_quality_blending &&
+                low_quality_blending == rhs.low_quality_blending;
+    }
+
+    SurroundView2dParams& operator=(const SurroundView2dParams& rhs) {
+        resolution = rhs.resolution;
+        physical_size = rhs.physical_size;
+        physical_center = rhs.physical_center;
+        high_quality_blending = rhs.high_quality_blending;
+        low_quality_blending = rhs.low_quality_blending;
+        return *this;
+    }
 };
 
 //  surround view 3d parameters
 struct SurroundView3dParams {
-  // Bowl center is the origin of the surround view coordinate. If surround view
-  // coordinate is different from the global one, a coordinate system
-  // transformation function is required.
+    // Bowl center is the origin of the surround view coordinate. If surround view
+    // coordinate is different from the global one, a coordinate system
+    // transformation function is required.
 
-  // planar area radius.
-  // Range in (0, +Inf).
-  float plane_radius;
+    // planar area radius.
+    // Range in (0, +Inf).
+    float plane_radius;
 
-  // the number of divisions on the plane area of bowl, in the direction
-  // of the radius.
-  // Range in [1, +Inf).
-  int plane_divisions;
+    // the number of divisions on the plane area of bowl, in the direction
+    // of the radius.
+    // Range in [1, +Inf).
+    int plane_divisions;
 
-  // bowl curve curve height.
-  // Range in (0, +Inf).
-  float curve_height;
+    // bowl curve curve height.
+    // Range in (0, +Inf).
+    float curve_height;
 
-  // the number of points on bowl curve curve along radius direction.
-  // Range in [1, +Inf).
-  int curve_divisions;
+    // the number of points on bowl curve curve along radius direction.
+    // Range in [1, +Inf).
+    int curve_divisions;
 
-  // the number of points along circle (360 degrees)
-  // Range in [1, +Inf).
-  int angular_divisions;
+    // the number of points along circle (360 degrees)
+    // Range in [1, +Inf).
+    int angular_divisions;
 
-  // the parabola coefficient of bowl curve curve.
-  // The curve formula is z = a * (x^2 + y^2) for sqrt(x^2 + y^2) >
-  // plane_radius; a is curve_coefficient.
-  // Range in (0, +Inf).
-  float curve_coefficient;
+    // the parabola coefficient of bowl curve curve.
+    // The curve formula is z = a * (x^2 + y^2) for sqrt(x^2 + y^2) >
+    // plane_radius; a is curve_coefficient.
+    // Range in (0, +Inf).
+    float curve_coefficient;
 
-  // render output image size.
-  Size2dInteger resolution;
+    // render output image size.
+    Size2dInteger resolution;
 
-  SurroundView3dParams()
-      : plane_radius(0.0f),
-        plane_divisions(0),
-        curve_height(0.0f),
-        curve_divisions(0),
-        angular_divisions(0),
-        curve_coefficient(0.0f),
-        resolution(0, 0) {}
+    // Include shadows in high details preset.
+    bool high_details_shadows;
 
-  SurroundView3dParams(float plane_radius_, int plane_divisions_,
-                       float curve_height_, int curve_divisions_,
-                       int angular_divisions_, float curve_coefficient_,
-                       Size2dInteger resolution_)
-      : plane_radius(plane_radius_),
-        plane_divisions(plane_divisions_),
-        curve_height(curve_height_),
-        curve_divisions(curve_divisions_),
-        angular_divisions(angular_divisions_),
-        curve_coefficient(curve_coefficient_),
-        resolution(resolution_) {}
+    // Include reflections in high details preset.
+    bool high_details_reflections;
 
-  // Checks if data is valid.
-  bool IsValid() const {
-    return plane_radius > 0 && plane_divisions > 0 && curve_height > 0 &&
-           angular_divisions > 0 && curve_coefficient > 0 &&
-           curve_divisions > 0 && resolution.IsValid();
-  }
+    SurroundView3dParams() :
+          plane_radius(0.0f),
+          plane_divisions(0),
+          curve_height(0.0f),
+          curve_divisions(0),
+          angular_divisions(0),
+          curve_coefficient(0.0f),
+          resolution(0, 0),
+          high_details_shadows(true),
+          high_details_reflections(true) {}
 
-  bool operator==(const SurroundView3dParams& rhs) const {
-    return plane_radius == rhs.plane_radius &&
-           plane_divisions == rhs.plane_divisions &&
-           curve_height == rhs.curve_height &&
-           curve_divisions == rhs.curve_divisions &&
-           angular_divisions == rhs.angular_divisions &&
-           curve_coefficient == rhs.curve_coefficient &&
-           resolution == rhs.resolution;
-  }
+    SurroundView3dParams(float plane_radius_, int plane_divisions_, float curve_height_,
+                         int curve_divisions_, int angular_divisions_, float curve_coefficient_,
+                         Size2dInteger resolution_) :
+          plane_radius(plane_radius_),
+          plane_divisions(plane_divisions_),
+          curve_height(curve_height_),
+          curve_divisions(curve_divisions_),
+          angular_divisions(angular_divisions_),
+          curve_coefficient(curve_coefficient_),
+          resolution(resolution_),
+          high_details_shadows(true),
+          high_details_reflections(true) {}
 
-  SurroundView3dParams& operator=(const SurroundView3dParams& rhs) {
-    plane_radius = rhs.plane_radius;
-    plane_divisions = rhs.plane_divisions;
-    curve_height = rhs.curve_height;
-    curve_divisions = rhs.curve_divisions;
-    angular_divisions = rhs.angular_divisions;
-    curve_coefficient = rhs.curve_coefficient;
-    resolution = rhs.resolution;
-    return *this;
-  }
+    // Checks if data is valid.
+    bool IsValid() const {
+        return plane_radius > 0 && plane_divisions > 0 && curve_height > 0 &&
+                angular_divisions > 0 && curve_coefficient > 0 && curve_divisions > 0 &&
+                resolution.IsValid();
+    }
+
+    bool operator==(const SurroundView3dParams& rhs) const {
+        return plane_radius == rhs.plane_radius && plane_divisions == rhs.plane_divisions &&
+                curve_height == rhs.curve_height && curve_divisions == rhs.curve_divisions &&
+                angular_divisions == rhs.angular_divisions &&
+                curve_coefficient == rhs.curve_coefficient && resolution == rhs.resolution &&
+                high_details_shadows == rhs.high_details_shadows &&
+                high_details_reflections == rhs.high_details_reflections;
+    }
+
+    SurroundView3dParams& operator=(const SurroundView3dParams& rhs) {
+        plane_radius = rhs.plane_radius;
+        plane_divisions = rhs.plane_divisions;
+        curve_height = rhs.curve_height;
+        curve_divisions = rhs.curve_divisions;
+        angular_divisions = rhs.angular_divisions;
+        curve_coefficient = rhs.curve_coefficient;
+        resolution = rhs.resolution;
+        high_details_shadows = rhs.high_details_shadows;
+        high_details_reflections = rhs.high_details_reflections;
+        return *this;
+    }
 };
 
 // surround view camera parameters with native types only.
 struct SurroundViewCameraParams {
-  // All calibration data |intrinsics|, |rvec| and |tvec|
-  // follow OpenCV format excepting using native arrays, refer:
-  // https://docs.opencv.org/3.4.0/db/d58/group__calib3d__fisheye.html
-  // camera intrinsics. It is the 1d array of camera matrix(3X3) with row first.
-  float intrinsics[9];
+    // All calibration data |intrinsics|, |rvec| and |tvec|
+    // follow OpenCV format excepting using native arrays, refer:
+    // https://docs.opencv.org/3.4.0/db/d58/group__calib3d__fisheye.html
+    // camera intrinsics. It is the 1d array of camera matrix(3X3) with row first.
+    float intrinsics[9];
 
-  // lens distortion parameters.
-  float distorion[4];
+    // lens distortion parameters.
+    float distorion[4];
 
-  // rotation vector.
-  float rvec[3];
+    // rotation vector.
+    float rvec[3];
 
-  // translation vector.
-  float tvec[3];
+    // translation vector.
+    float tvec[3];
 
-  // camera image size (width, height).
-  Size2dInteger size;
+    // camera image size (width, height).
+    Size2dInteger size;
 
-  // fisheye circular fov.
-  float circular_fov;
+    // fisheye circular fov.
+    float circular_fov;
 
-  bool operator==(const SurroundViewCameraParams& rhs) const {
-    return (0 == std::memcmp(intrinsics, rhs.intrinsics, 9 * sizeof(float))) &&
-           (0 == std::memcmp(distorion, rhs.distorion, 4 * sizeof(float))) &&
-           (0 == std::memcmp(rvec, rhs.rvec, 3 * sizeof(float))) &&
-           (0 == std::memcmp(tvec, rhs.tvec, 3 * sizeof(float))) &&
-           size == rhs.size && circular_fov == rhs.circular_fov;
-  }
+    bool operator==(const SurroundViewCameraParams& rhs) const {
+        return (0 == std::memcmp(intrinsics, rhs.intrinsics, 9 * sizeof(float))) &&
+                (0 == std::memcmp(distorion, rhs.distorion, 4 * sizeof(float))) &&
+                (0 == std::memcmp(rvec, rhs.rvec, 3 * sizeof(float))) &&
+                (0 == std::memcmp(tvec, rhs.tvec, 3 * sizeof(float))) && size == rhs.size &&
+                circular_fov == rhs.circular_fov;
+    }
 
-  SurroundViewCameraParams& operator=(const SurroundViewCameraParams& rhs) {
-    std::memcpy(intrinsics, rhs.intrinsics, 9 * sizeof(float));
-    std::memcpy(distorion, rhs.distorion, 4 * sizeof(float));
-    std::memcpy(rvec, rhs.rvec, 3 * sizeof(float));
-    std::memcpy(tvec, rhs.tvec, 3 * sizeof(float));
-    size = rhs.size;
-    circular_fov = rhs.circular_fov;
-    return *this;
-  }
+    SurroundViewCameraParams& operator=(const SurroundViewCameraParams& rhs) {
+        std::memcpy(intrinsics, rhs.intrinsics, 9 * sizeof(float));
+        std::memcpy(distorion, rhs.distorion, 4 * sizeof(float));
+        std::memcpy(rvec, rhs.rvec, 3 * sizeof(float));
+        std::memcpy(tvec, rhs.tvec, 3 * sizeof(float));
+        size = rhs.size;
+        circular_fov = rhs.circular_fov;
+        return *this;
+    }
 };
 
 // 3D vertex of an overlay object.
 struct OverlayVertex {
-  // Position in 3d coordinates in world space in order X,Y,Z.
-  float pos[3];
-  // RGBA values, A is used for transparency.
-  uint8_t rgba[4];
+    // Position in 3d coordinates in world space in order X,Y,Z.
+    float pos[3];
+    // RGBA values, A is used for transparency.
+    uint8_t rgba[4];
 
-  bool operator==(const OverlayVertex& rhs) const {
-    return (0 == std::memcmp(pos, rhs.pos, 3 * sizeof(float))) &&
-           (0 == std::memcmp(rgba, rhs.rgba, 4 * sizeof(uint8_t)));
-  }
+    bool operator==(const OverlayVertex& rhs) const {
+        return (0 == std::memcmp(pos, rhs.pos, 3 * sizeof(float))) &&
+                (0 == std::memcmp(rgba, rhs.rgba, 4 * sizeof(uint8_t)));
+    }
 
-  OverlayVertex& operator=(const OverlayVertex& rhs) {
-    std::memcpy(pos, rhs.pos, 3 * sizeof(float));
-    std::memcpy(rgba, rhs.rgba, 4 * sizeof(uint8_t));
-    return *this;
-  }
+    OverlayVertex& operator=(const OverlayVertex& rhs) {
+        std::memcpy(pos, rhs.pos, 3 * sizeof(float));
+        std::memcpy(rgba, rhs.rgba, 4 * sizeof(uint8_t));
+        return *this;
+    }
 };
 
 // Overlay is a list of vertices (may be a single or multiple objects in scene)
 // coming from a single source or type of sensor.
 struct Overlay {
-  // Uniqiue Id identifying each overlay.
-  uint16_t id;
+    // Uniqiue Id identifying each overlay.
+    uint16_t id;
 
-  // List of overlay vertices. 3 consecutive vertices form a triangle.
-  std::vector<OverlayVertex> vertices;
+    // List of overlay vertices. 3 consecutive vertices form a triangle.
+    std::vector<OverlayVertex> vertices;
 
-  // Constructor initializing all member.
-  Overlay(uint16_t id_, const std::vector<OverlayVertex>& vertices_) {
-    id = id_;
-    vertices = vertices_;
-  }
+    // Constructor initializing all member.
+    Overlay(uint16_t id_, const std::vector<OverlayVertex>& vertices_) {
+        id = id_;
+        vertices = vertices_;
+    }
 
-  // Default constructor.
-  Overlay() {
-    id = 0;
-    vertices = std::vector<OverlayVertex>();
-  }
+    // Default constructor.
+    Overlay() {
+        id = 0;
+        vertices = std::vector<OverlayVertex>();
+    }
 };
 
 // -----------   Structs related to car model  ---------------
 
 // 3D Vertex of a car model with normal and optionally texture coordinates.
 struct CarVertex {
-  // 3d position in (x, y, z).
-  std::array<float, 3> pos;
+    // 3d position in (x, y, z).
+    std::array<float, 3> pos;
 
-  // unit normal at vertex, used for diffuse shading.
-  std::array<float, 3> normal;
+    // unit normal at vertex, used for diffuse shading.
+    std::array<float, 3> normal;
 
-  // texture coordinates, valid in range [0, 1]. (-1, -1) implies no
-  // texture sampling. Note: only a single texture coordinate is currently
-  // supported per vertex. This struct will need to be extended with another
-  // tex_coord if multiple textures are needed per vertex.
-  std::array<float, 2> tex_coord;
+    // texture coordinates, valid in range [0, 1]. (-1, -1) implies no
+    // texture sampling. Note: only a single texture coordinate is currently
+    // supported per vertex. This struct will need to be extended with another
+    // tex_coord if multiple textures are needed per vertex.
+    std::array<float, 2> tex_coord;
 
-  // Default constructor.
-  CarVertex() {
-    pos = {0, 0, 0};
-    normal = {1, 0, 0};
-    tex_coord = {-1.0f, -1.0f};
-  }
+    // Default constructor.
+    CarVertex() {
+        pos = {0, 0, 0};
+        normal = {1, 0, 0};
+        tex_coord = {-1.0f, -1.0f};
+    }
 
-  CarVertex(const std::array<float, 3>& _pos,
-            const std::array<float, 3>& _normal,
-            const std::array<float, 2> _tex_coord)
-      : pos(_pos), normal(_normal), tex_coord(_tex_coord) {}
+    CarVertex(const std::array<float, 3>& _pos, const std::array<float, 3>& _normal,
+              const std::array<float, 2> _tex_coord) :
+          pos(_pos), normal(_normal), tex_coord(_tex_coord) {}
 };
 
 // Type of texture (color, bump, procedural etc.)
 // Currently only color is supported.
 enum CarTextureType : uint32_t {
-  // Texture map is applied to all color parameters: Ka, Kd and Ks.
-  // Data type of texture is RGB with each channel a uint8_t.
-  kKa = 0,
-  kKd,
-  kKs,
+    // Texture map is applied to all color parameters: Ka, Kd and Ks.
+    // Data type of texture is RGB with each channel a uint8_t.
+    kKa = 0,
+    kKd,
+    kKs,
 
-  // Texture for bump maps. Data type is 3 channel float.
-  kBumpMap
+    // Texture for bump maps. Data type is 3 channel float.
+    kBumpMap
 };
 
 // Textures to be used for rendering car model.
 struct CarTexture {
-  // Type and number of channels are dependant on each car texture type.
-  int width;
-  int height;
-  int channels;
-  int bytes_per_channel;
-  uint8_t* data;
+    // Type and number of channels are dependant on each car texture type.
+    int width;
+    int height;
+    int channels;
+    int bytes_per_channel;
+    uint8_t* data;
 
-  CarTexture() {
-    width = 0;
-    height = 0;
-    channels = 0;
-    bytes_per_channel = 0;
-    data = nullptr;
-  }
+    CarTexture() {
+        width = 0;
+        height = 0;
+        channels = 0;
+        bytes_per_channel = 0;
+        data = nullptr;
+    }
 };
 
 // Material parameters for a car part.
 // Refer to MTL properties: http://paulbourke.net/dataformats/mtl/
 struct CarMaterial {
-  // Illumination model - 0, 1, 2 currently supported
-  // 0 = Color on and Ambient off
-  // 1 = Color on and Ambient on
-  // 2 = Highlight on
-  // 3 = Reflection on and Ray trace on
-  // 4 - 10 = Reflection/Transparency options not supported,
-  //          Will default to option 3.
-  uint8_t illum;
+    // Illumination model - 0, 1, 2 currently supported
+    // 0 = Color on and Ambient off
+    // 1 = Color on and Ambient on
+    // 2 = Highlight on
+    // 3 = Reflection on and Ray trace on
+    // 4 - 10 = Reflection/Transparency options not supported,
+    //          Will default to option 3.
+    uint8_t illum;
 
-  std::array<float, 3> ka;  // Ambient RGB [0, 1]
-  std::array<float, 3> kd;  // Diffuse RGB [0, 1]
-  std::array<float, 3> ks;  // Specular RGB [0, 1]
+    std::array<float, 3> ka;  // Ambient RGB [0, 1]
+    std::array<float, 3> kd;  // Diffuse RGB [0, 1]
+    std::array<float, 3> ks;  // Specular RGB [0, 1]
 
-  // Dissolve factor [0, 1], 0 = full transparent, 1 = full opaque.
-  float d;
+    // Dissolve factor [0, 1], 0 = full transparent, 1 = full opaque.
+    float d;
 
-  // Specular exponent typically range from 0 to 1000.
-  // A high exponent results in a tight, concentrated highlight.
-  float ns;
+    // Specular exponent typically range from 0 to 1000.
+    // A high exponent results in a tight, concentrated highlight.
+    float ns;
 
-  // Set default values of material.
-  CarMaterial() {
-    illum = 0;                // Color on, ambient off
-    ka = {0.0f, 0.0f, 0.0f};  // No ambient.
-    kd = {0.0f, 0.0f, 0.0f};  // No dissolve.
-    ks = {0.0f, 0.0f, 0.0f};  // No specular.
-    d = 1.0f;                 // Fully opaque.
-    ns = 0;                   // No specular exponent.
-  }
+    // Set default values of material.
+    CarMaterial() {
+        illum = 0;                // Color on, ambient off
+        ka = {0.0f, 0.0f, 0.0f};  // No ambient.
+        kd = {0.0f, 0.0f, 0.0f};  // No dissolve.
+        ks = {0.0f, 0.0f, 0.0f};  // No specular.
+        d = 1.0f;                 // Fully opaque.
+        ns = 0;                   // No specular exponent.
+    }
 
-  // Map for texture type to a string id of a texture.
-  std::map<CarTextureType, std::string> textures;
+    // Map for texture type to a string id of a texture.
+    std::map<CarTextureType, std::string> textures;
 };
 
 // Type alias for 4x4 homogenous matrix, in row-major order.
@@ -482,318 +517,304 @@
 // Each car part is a object in the car that is individually animated and
 // has the same illumination properties. A car part may contain sub parts.
 struct CarPart {
-  // Car part vertices.
-  std::vector<CarVertex> vertices;
+    // Car part vertices.
+    std::vector<CarVertex> vertices;
 
-  // Properties/attributes describing car material.
-  CarMaterial material;
+    // Properties/attributes describing car material.
+    CarMaterial material;
 
-  // Model matrix to transform the car part from object space to its parent's
-  // coordinate space.
-  // The car's vertices are transformed by performing:
-  // parent_model_mat * model_mat * car_part_vertices to transform them to the
-  // global coordinate space.
-  // Model matrix must be a homogenous matrix with orthogonal rotation matrix.
-  Mat4x4 model_mat;
+    // Model matrix to transform the car part from object space to its parent's
+    // coordinate space.
+    // The car's vertices are transformed by performing:
+    // parent_model_mat * model_mat * car_part_vertices to transform them to the
+    // global coordinate space.
+    // Model matrix must be a homogenous matrix with orthogonal rotation matrix.
+    Mat4x4 model_mat;
 
-  // Id of parent part. Parent part's model matrix is used to animate this part.
-  // empty string implies the part has no parent.
-  std::string parent_part_id;
+    // Id of parent part. Parent part's model matrix is used to animate this part.
+    // empty string implies the part has no parent.
+    std::string parent_part_id;
 
-  // Ids of child parts. If current part is animated all its child parts
-  // are animated as well. Empty vector implies part has not children.
-  std::vector<std::string> child_part_ids;
+    // Ids of child parts. If current part is animated all its child parts
+    // are animated as well. Empty vector implies part has not children.
+    std::vector<std::string> child_part_ids;
 
-  CarPart(const std::vector<CarVertex>& car_vertices,
-          const CarMaterial& car_material, const Mat4x4& car_model_mat,
-          std::string car_parent_part_id,
-          const std::vector<std::string>& car_child_part_ids)
-      : vertices(car_vertices),
-        material(car_material),
-        model_mat(car_model_mat),
-        parent_part_id(car_parent_part_id),
-        child_part_ids(car_child_part_ids) {}
+    CarPart(const std::vector<CarVertex>& car_vertices, const CarMaterial& car_material,
+            const Mat4x4& car_model_mat, std::string car_parent_part_id,
+            const std::vector<std::string>& car_child_part_ids) :
+          vertices(car_vertices),
+          material(car_material),
+          model_mat(car_model_mat),
+          parent_part_id(car_parent_part_id),
+          child_part_ids(car_child_part_ids) {}
 
-  CarPart& operator=(const CarPart& car_part) {
-    this->vertices = car_part.vertices;
-    this->material = car_part.material;
-    this->model_mat = car_part.model_mat;
-    this->parent_part_id = car_part.parent_part_id;
-    this->child_part_ids = car_part.child_part_ids;
-    return *this;
-  }
+    CarPart& operator=(const CarPart& car_part) {
+        this->vertices = car_part.vertices;
+        this->material = car_part.material;
+        this->model_mat = car_part.model_mat;
+        this->parent_part_id = car_part.parent_part_id;
+        this->child_part_ids = car_part.child_part_ids;
+        return *this;
+    }
 };
 
 struct AnimationParam {
-  // part id
-  std::string part_id;
+    // part id
+    std::string part_id;
 
-  // model matrix.
-  Mat4x4 model_matrix;
+    // model matrix.
+    Mat4x4 model_matrix;
 
-  // bool flag indicating if the model matrix is updated from last
-  // SetAnimations() call.
-  bool is_model_update;
+    // bool flag indicating if the model matrix is updated from last
+    // SetAnimations() call.
+    bool is_model_update;
 
-  // gamma.
-  float gamma;
+    // gamma.
+    float gamma;
 
-  // bool flag indicating if gamma is updated from last
-  // SetAnimations() call.
-  bool is_gamma_update;
+    // bool flag indicating if gamma is updated from last
+    // SetAnimations() call.
+    bool is_gamma_update;
 
-  // texture id.
-  std::string texture_id;
+    // texture id.
+    std::string texture_id;
 
-  // bool flag indicating if texture is updated from last
-  // SetAnimations() call.
-  bool is_texture_update;
+    // bool flag indicating if texture is updated from last
+    // SetAnimations() call.
+    bool is_texture_update;
 
-  // Default constructor, no animations are updated.
-  AnimationParam() {
-    is_model_update = false;
-    is_gamma_update = false;
-    is_texture_update = false;
-  }
+    // Default constructor, no animations are updated.
+    AnimationParam() {
+        is_model_update = false;
+        is_gamma_update = false;
+        is_texture_update = false;
+    }
 
-  // Constructor with car part name.
-  explicit AnimationParam(const std::string& _part_id)
-      : part_id(_part_id),
-        is_model_update(false),
-        is_gamma_update(false),
-        is_texture_update(false) {}
+    // Constructor with car part name.
+    explicit AnimationParam(const std::string& _part_id) :
+          part_id(_part_id),
+          is_model_update(false),
+          is_gamma_update(false),
+          is_texture_update(false) {}
 
-  void SetModelMatrix(const Mat4x4& model_mat) {
-    is_model_update = true;
-    model_matrix = model_mat;
-  }
+    void SetModelMatrix(const Mat4x4& model_mat) {
+        is_model_update = true;
+        model_matrix = model_mat;
+    }
 
-  void SetGamma(float gamma_value) {
-    is_gamma_update = true;
-    gamma = gamma_value;
-  }
+    void SetGamma(float gamma_value) {
+        is_gamma_update = true;
+        gamma = gamma_value;
+    }
 
-  void SetTexture(const std::string& tex_id) {
-    is_texture_update = true;
-    texture_id = tex_id;
-  }
+    void SetTexture(const std::string& tex_id) {
+        is_texture_update = true;
+        texture_id = tex_id;
+    }
 };
 
 enum Format {
-  GRAY = 0,
-  RGB = 1,
-  RGBA = 2,
+    GRAY = 0,
+    RGB = 1,
+    RGBA = 2,
 };
 
 // collection of surround view static data params.
 struct SurroundViewStaticDataParams {
-  std::vector<SurroundViewCameraParams> cameras_params;
+    std::vector<SurroundViewCameraParams> cameras_params;
 
-  // surround view 2d parameters.
-  SurroundView2dParams surround_view_2d_params;
+    // surround view 2d parameters.
+    SurroundView2dParams surround_view_2d_params;
 
-  // surround view 3d parameters.
-  SurroundView3dParams surround_view_3d_params;
+    // surround view 3d parameters.
+    SurroundView3dParams surround_view_3d_params;
 
-  // undistortion focal length scales.
-  std::vector<float> undistortion_focal_length_scales;
+    // undistortion focal length scales.
+    std::vector<float> undistortion_focal_length_scales;
 
-  // car model bounding box for 2d surround view.
-  BoundingBox car_model_bb;
+    // car model bounding box for 2d surround view.
+    BoundingBox car_model_bb;
 
-  // map of texture name to a car texture. Lists all textures to be
-  // used for car model rendering.
-  std::map<std::string, CarTexture> car_textures;
+    // map of texture name to a car texture. Lists all textures to be
+    // used for car model rendering.
+    std::map<std::string, CarTexture> car_textures;
 
-  // map of car id to a car part. Lists all car parts to be used
-  // for car model rendering.
-  std::map<std::string, CarPart> car_parts;
+    // map of car id to a car part. Lists all car parts to be used
+    // for car model rendering.
+    std::map<std::string, CarPart> car_parts;
 
-  SurroundViewStaticDataParams(
-      const std::vector<SurroundViewCameraParams>& sv_cameras_params,
-      const SurroundView2dParams& sv_2d_params,
-      const SurroundView3dParams& sv_3d_params,
-      const std::vector<float>& scales, const BoundingBox& bb,
-      const std::map<std::string, CarTexture>& textures,
-      const std::map<std::string, CarPart>& parts)
-      : cameras_params(sv_cameras_params),
-        surround_view_2d_params(sv_2d_params),
-        surround_view_3d_params(sv_3d_params),
-        undistortion_focal_length_scales(scales),
-        car_model_bb(bb),
-        car_textures(textures),
-        car_parts(parts) {}
+    SurroundViewStaticDataParams(const std::vector<SurroundViewCameraParams>& sv_cameras_params,
+                                 const SurroundView2dParams& sv_2d_params,
+                                 const SurroundView3dParams& sv_3d_params,
+                                 const std::vector<float>& scales, const BoundingBox& bb,
+                                 const std::map<std::string, CarTexture>& textures,
+                                 const std::map<std::string, CarPart>& parts) :
+          cameras_params(sv_cameras_params),
+          surround_view_2d_params(sv_2d_params),
+          surround_view_3d_params(sv_3d_params),
+          undistortion_focal_length_scales(scales),
+          car_model_bb(bb),
+          car_textures(textures),
+          car_parts(parts) {}
 };
 
 struct SurroundViewInputBufferPointers {
-  void* gpu_data_pointer;
-  void* cpu_data_pointer;
-  Format format;
-  int width;
-  int height;
-  SurroundViewInputBufferPointers()
-      : gpu_data_pointer(nullptr),
-        cpu_data_pointer(nullptr),
-        width(0),
-        height(0) {}
-  SurroundViewInputBufferPointers(void* gpu_data_pointer_,
-                                  void* cpu_data_pointer_, Format format_,
-                                  int width_, int height_)
-      : gpu_data_pointer(gpu_data_pointer_),
-        cpu_data_pointer(cpu_data_pointer_),
-        format(format_),
-        width(width_),
-        height(height_) {}
+    void* gpu_data_pointer;
+    void* cpu_data_pointer;
+    Format format;
+    int width;
+    int height;
+    SurroundViewInputBufferPointers() :
+          gpu_data_pointer(nullptr), cpu_data_pointer(nullptr), width(0), height(0) {}
+    SurroundViewInputBufferPointers(void* gpu_data_pointer_, void* cpu_data_pointer_,
+                                    Format format_, int width_, int height_) :
+          gpu_data_pointer(gpu_data_pointer_),
+          cpu_data_pointer(cpu_data_pointer_),
+          format(format_),
+          width(width_),
+          height(height_) {}
 };
 
 struct SurroundViewResultPointer {
-  void* data_pointer;
-  Format format;
-  int width;
-  int height;
-  bool is_data_preallocated;
-  SurroundViewResultPointer()
-      : data_pointer(nullptr),
-        width(0),
-        height(0),
-        is_data_preallocated(false) {}
+    void* data_pointer;
+    Format format;
+    int width;
+    int height;
+    bool is_data_preallocated;
+    SurroundViewResultPointer() :
+          data_pointer(nullptr), width(0), height(0), is_data_preallocated(false) {}
 
-  // Constructor with result data pointer being allocated within core lib.
-  // Use for cases when no already existing buffer is available.
-  SurroundViewResultPointer(Format format_, int width_, int height_)
-      : format(format_), width(width_), height(height_) {
-    // default formate is gray.
-    const int byte_per_pixel = format_ == RGB ? 3 : format_ == RGBA ? 4 : 1;
-    data_pointer =
-        static_cast<void*>(new char[width * height * byte_per_pixel]);
-    is_data_preallocated = false;
-  }
-
-  // Constructor with pre-allocated data.
-  // Use for cases when results must be added to an existing allocated buffer.
-  // Example, pre-allocated buffer of a display.
-  SurroundViewResultPointer(void* data_pointer_, Format format_, int width_,
-                            int height_)
-      : data_pointer(data_pointer_),
-        format(format_),
-        width(width_),
-        height(height_),
-        is_data_preallocated(true) {}
-
-  ~SurroundViewResultPointer() {
-    if (data_pointer) {
-      // TODO(b/154365307): Fix freeing up of pre-allocated memory.
-      // if (!is_data_preallocated) {
-      //   delete[] static_cast<char*>(data_pointer);
-      // }
-      data_pointer = nullptr;
+    // Constructor with result data pointer being allocated within core lib.
+    // Use for cases when no already existing buffer is available.
+    SurroundViewResultPointer(Format format_, int width_, int height_) :
+          format(format_), width(width_), height(height_) {
+        // default formate is gray.
+        const int byte_per_pixel = format_ == RGB ? 3 : format_ == RGBA ? 4 : 1;
+        data_pointer = static_cast<void*>(new char[width * height * byte_per_pixel]);
+        is_data_preallocated = false;
     }
-  }
+
+    // Constructor with pre-allocated data.
+    // Use for cases when results must be added to an existing allocated buffer.
+    // Example, pre-allocated buffer of a display.
+    SurroundViewResultPointer(void* data_pointer_, Format format_, int width_, int height_) :
+          data_pointer(data_pointer_),
+          format(format_),
+          width(width_),
+          height(height_),
+          is_data_preallocated(true) {}
+
+    ~SurroundViewResultPointer() {
+        if (data_pointer) {
+            // TODO(b/154365307): Fix freeing up of pre-allocated memory.
+            // if (!is_data_preallocated) {
+            //   delete[] static_cast<char*>(data_pointer);
+            // }
+            data_pointer = nullptr;
+        }
+    }
 };
 
 class SurroundView {
- public:
-  virtual ~SurroundView() = default;
+public:
+    virtual ~SurroundView() = default;
 
-  // Sets SurroundView static data.
-  // For details of SurroundViewStaticDataParams, please refer to the
-  // definition.
-  virtual bool SetStaticData(
-      const SurroundViewStaticDataParams& static_data_params) = 0;
+    // Sets SurroundView static data.
+    // For details of SurroundViewStaticDataParams, please refer to the
+    // definition.
+    virtual bool SetStaticData(const SurroundViewStaticDataParams& static_data_params) = 0;
 
-  // Starts 2d pipeline. Returns false if error occurs.
-  virtual bool Start2dPipeline() = 0;
+    // Starts 2d pipeline. Returns false if error occurs.
+    virtual bool Start2dPipeline() = 0;
 
-  // Starts 3d pipeline. Returns false if error occurs.
-  virtual bool Start3dPipeline() = 0;
+    // Starts 3d pipeline. Returns false if error occurs.
+    virtual bool Start3dPipeline() = 0;
 
-  // Stops 2d pipleline. It releases resource owned by the pipeline.
-  // Returns false if error occurs.
-  virtual void Stop2dPipeline() = 0;
+    // Stops 2d pipleline. It releases resource owned by the pipeline.
+    // Returns false if error occurs.
+    virtual void Stop2dPipeline() = 0;
 
-  // Stops 3d pipeline. It releases resource owned by the pipeline.
-  virtual void Stop3dPipeline() = 0;
+    // Stops 3d pipeline. It releases resource owned by the pipeline.
+    virtual void Stop3dPipeline() = 0;
 
-  // Updates 2d output resolution on-the-fly. Starts2dPipeline() must be called
-  // before this can be called. For quality assurance, the |resolution| should
-  // not be larger than the original one. This call is not thread safe and there
-  // is no sync between Get2dSurroundView() and this call.
-  virtual bool Update2dOutputResolution(const Size2dInteger& resolution) = 0;
+    // Updates 2d output resolution on-the-fly. Starts2dPipeline() must be called
+    // before this can be called. For quality assurance, the |resolution| should
+    // not be larger than the original one. This call is not thread safe and there
+    // is no sync between Get2dSurroundView() and this call.
+    virtual bool Update2dOutputResolution(const Size2dInteger& resolution) = 0;
 
-  // Updates 3d output resolution on-the-fly. Starts3dPipeline() must be called
-  // before this can be called. For quality assurance, the |resolution| should
-  // not be larger than the original one. This call is not thread safe and there
-  // is no sync between Get3dSurroundView() and this call.
-  virtual bool Update3dOutputResolution(const Size2dInteger& resolution) = 0;
+    // Updates 3d output resolution on-the-fly. Starts3dPipeline() must be called
+    // before this can be called. For quality assurance, the |resolution| should
+    // not be larger than the original one. This call is not thread safe and there
+    // is no sync between Get3dSurroundView() and this call.
+    virtual bool Update3dOutputResolution(const Size2dInteger& resolution) = 0;
 
-  // Projects camera's pixel location to surround view 2d image location.
-  // |camera_point| is the pixel location in raw camera's space.
-  // |camera_index| is the camera's index.
-  // |surround_view_2d_point| is the surround view 2d image pixel location.
-  virtual bool GetProjectionPointFromRawCameraToSurroundView2d(
-      const Coordinate2dInteger& camera_point, int camera_index,
-      Coordinate2dFloat* surround_view_2d_point) = 0;
+    // Projects camera's pixel location to surround view 2d image location.
+    // |camera_point| is the pixel location in raw camera's space.
+    // |camera_index| is the camera's index.
+    // |surround_view_2d_point| is the surround view 2d image pixel location.
+    virtual bool GetProjectionPointFromRawCameraToSurroundView2d(
+            const Coordinate2dInteger& camera_point, int camera_index,
+            Coordinate2dFloat* surround_view_2d_point) = 0;
 
-  // Projects camera's pixel location to surround view 3d bowl coordinate.
-  // |camera_point| is the pixel location in raw camera's space.
-  // |camera_index| is the camera's index.
-  // |surround_view_3d_point| is the surround view 3d vertex.
-  virtual bool GetProjectionPointFromRawCameraToSurroundView3d(
-      const Coordinate2dInteger& camera_point, int camera_index,
-      Coordinate3dFloat* surround_view_3d_point) = 0;
+    // Projects camera's pixel location to surround view 3d bowl coordinate.
+    // |camera_point| is the pixel location in raw camera's space.
+    // |camera_index| is the camera's index.
+    // |surround_view_3d_point| is the surround view 3d vertex.
+    virtual bool GetProjectionPointFromRawCameraToSurroundView3d(
+            const Coordinate2dInteger& camera_point, int camera_index,
+            Coordinate3dFloat* surround_view_3d_point) = 0;
 
-  // Gets 2d surround view image.
-  // It takes input_pointers as input, and output is result_pointer.
-  // Please refer to the definition of SurroundViewInputBufferPointers and
-  // SurroundViewResultPointer.
-  virtual bool Get2dSurroundView(
-      const std::vector<SurroundViewInputBufferPointers>& input_pointers,
-      SurroundViewResultPointer* result_pointer) = 0;
+    // Gets 2d surround view image.
+    // It takes input_pointers as input, and output is result_pointer.
+    // Please refer to the definition of SurroundViewInputBufferPointers and
+    // SurroundViewResultPointer.
+    virtual bool Get2dSurroundView(
+            const std::vector<SurroundViewInputBufferPointers>& input_pointers,
+            SurroundViewResultPointer* result_pointer) = 0;
 
-  // Gets 3d surround view image.
-  // It takes |input_pointers| and |view_matrix| as input, and output is
-  // |result_pointer|. |view_matrix| is 4 x 4 matrix.
-  // Please refer to the definition of
-  // SurroundViewInputBufferPointers and
-  // SurroundViewResultPointer.
-  virtual bool Get3dSurroundView(
-      const std::vector<SurroundViewInputBufferPointers>& input_pointers,
-      const std::array<std::array<float, 4>, 4>& view_matrix,
-      SurroundViewResultPointer* result_pointer) = 0;
+    // Gets 3d surround view image.
+    // It takes |input_pointers| and |view_matrix| as input, and output is
+    // |result_pointer|. |view_matrix| is 4 x 4 matrix.
+    // Please refer to the definition of
+    // SurroundViewInputBufferPointers and
+    // SurroundViewResultPointer.
+    virtual bool Get3dSurroundView(
+            const std::vector<SurroundViewInputBufferPointers>& input_pointers,
+            const std::array<std::array<float, 4>, 4>& view_matrix,
+            SurroundViewResultPointer* result_pointer) = 0;
 
-  // Gets 3d surround view image overload.
-  // It takes |input_pointers|, |quaternion| and |translation| as input,
-  // and output is |result_pointer|.
-  // |quaternion| is 4 x 1 array (X, Y, Z, W).
-  // It is required to be unit quaternion as rotation quaternion.
-  // |translation| is 3 X 1 array (x, y, z).
-  // Please refer to the definition of
-  // SurroundViewInputBufferPointers and
-  // SurroundViewResultPointer.
-  virtual bool Get3dSurroundView(
-      const std::vector<SurroundViewInputBufferPointers>& input_pointers,
-      const std::array<float, 4>& quaternion,
-      const std::array<float, 3>& translation,
-      SurroundViewResultPointer* result_pointer) = 0;
+    // Gets 3d surround view image overload.
+    // It takes |input_pointers|, |quaternion| and |translation| as input,
+    // and output is |result_pointer|.
+    // |quaternion| is 4 x 1 array (X, Y, Z, W).
+    // It is required to be unit quaternion as rotation quaternion.
+    // |translation| is 3 X 1 array (x, y, z).
+    // Please refer to the definition of
+    // SurroundViewInputBufferPointers and
+    // SurroundViewResultPointer.
+    virtual bool Get3dSurroundView(
+            const std::vector<SurroundViewInputBufferPointers>& input_pointers,
+            const std::array<float, 4>& quaternion, const std::array<float, 3>& translation,
+            SurroundViewResultPointer* result_pointer) = 0;
 
-  // Sets 3d overlays.
-  virtual bool Set3dOverlay(const std::vector<Overlay>& overlays) = 0;
+    // Sets 3d overlays.
+    virtual bool Set3dOverlay(const std::vector<Overlay>& overlays) = 0;
 
-  // Animates a set of car parts.
-  // Only updated car parts are included.
-  // |car_animations| is a vector of AnimationParam specifying updated
-  // car parts with updated animation parameters.
-  virtual bool SetAnimations(
-      const std::vector<AnimationParam>& car_animations) = 0;
+    // Animates a set of car parts.
+    // Only updated car parts are included.
+    // |car_animations| is a vector of AnimationParam specifying updated
+    // car parts with updated animation parameters.
+    virtual bool SetAnimations(const std::vector<AnimationParam>& car_animations) = 0;
 
-  // for test only.
-  // TODO(xxqian): remove thest two fns.
-  virtual std::vector<SurroundViewInputBufferPointers> ReadImages(
-      const char* filename0, const char* filename1, const char* filename2,
-      const char* filename3) = 0;
+    // for test only.
+    virtual std::vector<SurroundViewInputBufferPointers> ReadImages(const char* filename0,
+                                                                    const char* filename1,
+                                                                    const char* filename2,
+                                                                    const char* filename3) = 0;
 
-  virtual void WriteImage(const SurroundViewResultPointer result_pointerer,
-                          const char* filename) = 0;
+    virtual void WriteImage(const SurroundViewResultPointer result_pointerer,
+                            const char* filename) = 0;
 };
 
 SurroundView* Create();
diff --git a/surround_view/service-impl/test_data/sv_sample_car_model_config.xml b/surround_view/service-impl/test_data/sv_sample_car_model_config.xml
new file mode 100644
index 0000000..9bc0118
--- /dev/null
+++ b/surround_view/service-impl/test_data/sv_sample_car_model_config.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SurroundViewCarModelConfig>
+    <Version>1.0</Version>
+
+    <!-- Rotation animation for front left door -->
+    <Animation>
+        <PartId>front_left_door</PartId>
+        <ChildParts>
+            <PartId>left_mirror</PartId>
+            <PartId>front_left_window</PartId>
+        </ChildParts>
+        <ParentPartId>car_frame</ParentPartId>
+        <RotationOp>
+            <VhalProperty>
+                <PropertyId>0x0001</PropertyId>
+                <AreaId>0x0002</AreaId>
+            </VhalProperty>
+            <AnimationType>RotationAngle</AnimationType>
+            <AnimationTimeMs>2000</AnimationTimeMs>
+            <RotationAxis>
+                <X>1.0</X>
+                <Y>0.0</Y>
+                <Z>0.0</Z>
+            </RotationAxis>
+            <RotationPoint>
+                <X>2.0</X>
+                <Y>2.0</Y>
+                <Z>2.0</Z>
+            </RotationPoint>
+            <DefaultRotationValue>0.0</DefaultRotationValue>
+            <RotationRange>
+                <Start>0.0</Start>
+                <End>90</End>
+            </RotationRange>
+            <VhalRange>
+                <Start>0</Start>
+                <End>0xFFFF</End>
+            </VhalRange>
+        </RotationOp>
+    </Animation>
+
+    <!-- Translation animation for front left window -->
+    <Animation>
+        <PartId>front_left_window</PartId>
+        <ParentPartId>front_left_door</ParentPartId>
+        <ChildParts>
+        </ChildParts>
+        <TranslationOp>
+            <VhalProperty>
+                <PropertyId>0x0002</PropertyId>
+                <AreaId>0x0001</AreaId>
+            </VhalProperty>
+            <AnimationType>Translation</AnimationType>
+            <AnimationTimeMs>2000</AnimationTimeMs>
+            <Direction>
+                <X>0.0</X>
+                <Y>0.0</Y>
+                <Z>-1.0</Z>
+            </Direction>
+            <DefaultTranslationValue>0.0</DefaultTranslationValue>
+            <TranslationRange>
+                <Start>0.0</Start>
+                <End>5</End>
+            </TranslationRange>
+            <VhalRange>
+                <Start>0</Start>
+                <End>0xFFFF</End>
+            </VhalRange>
+        </TranslationOp>
+    </Animation>
+
+</SurroundViewCarModelConfig>
diff --git a/surround_view/service-impl/test_data/sv_sample_config.xml b/surround_view/service-impl/test_data/sv_sample_config.xml
new file mode 100644
index 0000000..b831849
--- /dev/null
+++ b/surround_view/service-impl/test_data/sv_sample_config.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SurroundViewConfig>
+    <Version>1.0</Version>
+
+    <CameraConfig>
+        <EvsGroupId>group0</EvsGroupId>
+        <EvsCameraIds>
+            <Front>/dev/video0</Front>
+            <Right>/dev/video1</Right>
+            <Rear>/dev/video2</Rear>
+            <Left>/dev/video3</Left>
+        </EvsCameraIds>
+        <Masks>
+            <Front>/vendor/mask_front.png</Front>
+            <Right>/vendor/mask_right.png</Right>
+            <Rear>/vendor/mask_rear.png</Rear>
+            <Left>/vendor/mask_left.png</Left>
+        </Masks>
+    </CameraConfig>
+
+    <Sv2dEnabled>true</Sv2dEnabled>
+    <Sv2dParams>
+        <OutputResolution>
+            <Width>600</Width>
+            <Height>900</Height>
+        </OutputResolution>
+        <GroundMapping>
+            <Width>6.0</Width>
+            <Height>9.0</Height>
+            <Center>
+                <X>0.0</X>
+                <Y>0.0</Y>
+            </Center>
+        </GroundMapping>
+        <CarBoundingBox>
+            <Width>2.0</Width>
+            <Height>3.0</Height>
+            <LeftTopCorner>
+                <X>1.0</X>
+                <Y>1.5</Y>
+            </LeftTopCorner>
+        </CarBoundingBox>
+        <BlendingType>
+            <HighQuality>multiband</HighQuality>
+            <LowQuality>alpha</LowQuality>
+        </BlendingType>
+    </Sv2dParams>
+
+    <Sv3dEnabled>true</Sv3dEnabled>
+    <Sv3dAnimationsEnabled>true</Sv3dAnimationsEnabled>
+    <CarModelConfigFile>/vendor/car_model_config.xml</CarModelConfigFile>
+    <CarModelObjFile>/vendor/car.obj</CarModelObjFile>
+    <Sv3dParams>
+        <OutputResolution>
+            <Width>1920</Width>
+            <Height>1080</Height>
+        </OutputResolution>
+        <BowlParams>
+            <PlaneRadius>6.0</PlaneRadius>
+            <PlaneDivisions>20</PlaneDivisions>
+            <CurveHeight>5.0</CurveHeight>
+            <CurveDivisions>30</CurveDivisions>
+            <AngularDivisions>50</AngularDivisions>
+            <CurveCoefficient>2.0</CurveCoefficient>
+        </BowlParams>
+        <HighQualityDetails>
+            <Shadows>true</Shadows>
+            <Reflections>true</Reflections>
+        </HighQualityDetails>
+    </Sv3dParams>
+</SurroundViewConfig>