270 lines
11 KiB
C++
270 lines
11 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
#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) {
|
|
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", ¶m2dElem));
|
|
{
|
|
// 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", ¢erElem));
|
|
{
|
|
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));
|
|
}
|
|
|
|
// GPU Acceleration enabled or not
|
|
RETURN_IF_FALSE(ReadValue(param2dElem, "GpuAccelerationEnabled",
|
|
&sv2dParams->gpu_acceleration_enabled));
|
|
}
|
|
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", ¶m3dElem));
|
|
{
|
|
// 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) << "Config file is not in the required format: " << configFile;
|
|
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
|