Revert "Revert "Revert "Revert "Extend EVS interfaces and data types""""
This reverts commit 468cc1d476ae4a78787e0730cac8cf53e1806ed1.
Change-Id: If7e80111213ba02bf2c49f17f9880cd9cd14429e
diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp
new file mode 100644
index 0000000..4f46f9d
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManager.cpp
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2019 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 <sstream>
+#include <fstream>
+#include <thread>
+
+#include <hardware/gralloc.h>
+#include <utils/SystemClock.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+
+#include "ConfigManager.h"
+
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+
+
+ConfigManager::~ConfigManager() {
+ /* Nothing to do */
+}
+
+
+void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) {
+ if (aCameraElem == nullptr) {
+ ALOGW("XML file does not have required camera element");
+ return;
+ }
+
+ const XMLElement *curElem = aCameraElem->FirstChildElement();
+ while (curElem != nullptr) {
+ if (!strcmp(curElem->Name(), "group")) {
+ /* camera group identifier */
+ const char *group_id = curElem->FindAttribute("group_id")->Value();
+
+ /* create CameraGroup */
+ unique_ptr<ConfigManager::CameraGroup> aCameraGroup(new ConfigManager::CameraGroup());
+
+ /* add a camera device to its group */
+ addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup);
+
+ /* a list of camera stream configurations */
+ const XMLElement *childElem =
+ curElem->FirstChildElement("caps")->FirstChildElement("stream");
+ while (childElem != nullptr) {
+ /* read 5 attributes */
+ const XMLAttribute *idAttr = childElem->FindAttribute("id");
+ const XMLAttribute *widthAttr = childElem->FindAttribute("width");
+ const XMLAttribute *heightAttr = childElem->FindAttribute("height");
+ const XMLAttribute *fmtAttr = childElem->FindAttribute("format");
+ const XMLAttribute *fpsAttr = childElem->FindAttribute("framerate");
+
+ const int32_t id = stoi(idAttr->Value());
+ int32_t framerate = 0;
+ if (fpsAttr != nullptr) {
+ framerate = stoi(fpsAttr->Value());
+ }
+
+ int32_t pixFormat;
+ if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+ pixFormat)) {
+ RawStreamConfiguration cfg = {
+ id,
+ stoi(widthAttr->Value()),
+ stoi(heightAttr->Value()),
+ pixFormat,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+ framerate
+ };
+ aCameraGroup->streamConfigurations[id] = cfg;
+ }
+
+ childElem = childElem->NextSiblingElement("stream");
+ }
+
+ /* camera group synchronization */
+ const char *sync = curElem->FindAttribute("synchronized")->Value();
+ aCameraGroup->synchronized =
+ static_cast<bool>(strcmp(sync, "false"));
+
+ /* add a group to hash map */
+ mCameraGroups[group_id] = std::move(aCameraGroup);
+ } else if (!strcmp(curElem->Name(), "device")) {
+ /* camera unique identifier */
+ const char *id = curElem->FindAttribute("id")->Value();
+
+ /* camera mount location */
+ const char *pos = curElem->FindAttribute("position")->Value();
+
+ /* store read camera module information */
+ mCameraInfo[id] = readCameraDeviceInfo(curElem);
+
+ /* assign a camera device to a position group */
+ mCameraPosition[pos].emplace(id);
+ } else {
+ /* ignore other device types */
+ ALOGD("Unknown element %s is ignored", curElem->Name());
+ }
+
+ curElem = curElem->NextSiblingElement();
+ }
+}
+
+
+unique_ptr<ConfigManager::CameraInfo>
+ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) {
+ if (aDeviceElem == nullptr) {
+ return nullptr;
+ }
+
+ /* create a CameraInfo to be filled */
+ unique_ptr<ConfigManager::CameraInfo> aCamera(new ConfigManager::CameraInfo());
+
+ /* size information to allocate camera_metadata_t */
+ size_t totalEntries = 0;
+ size_t totalDataSize = 0;
+
+ /* read device capabilities */
+ totalEntries +=
+ readCameraCapabilities(aDeviceElem->FirstChildElement("caps"),
+ aCamera,
+ totalDataSize);
+
+
+ /* read camera metadata */
+ totalEntries +=
+ readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"),
+ aCamera,
+ totalDataSize);
+
+ /* construct camera_metadata_t */
+ if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) {
+ ALOGW("Either failed to allocate memory or "
+ "allocated memory was not large enough");
+ }
+
+ return aCamera;
+}
+
+
+size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
+ unique_ptr<ConfigManager::CameraInfo> &aCamera,
+ size_t &dataSize) {
+ if (aCapElem == nullptr) {
+ return 0;
+ }
+
+ string token;
+ const XMLElement *curElem = nullptr;
+
+ /* a list of supported camera parameters/controls */
+ curElem = aCapElem->FirstChildElement("supported_controls");
+ if (curElem != nullptr) {
+ const XMLElement *ctrlElem = curElem->FirstChildElement("control");
+ while (ctrlElem != nullptr) {
+ const char *nameAttr = ctrlElem->FindAttribute("name")->Value();;
+ const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value());
+ const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value());
+
+ int32_t stepVal = 1;
+ const XMLAttribute *stepAttr = ctrlElem->FindAttribute("step");
+ if (stepAttr != nullptr) {
+ stepVal = stoi(stepAttr->Value());
+ }
+
+ CameraParam aParam;
+ if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr,
+ aParam)) {
+ aCamera->controls.emplace(
+ aParam,
+ make_tuple(minVal, maxVal, stepVal)
+ );
+ }
+
+ ctrlElem = ctrlElem->NextSiblingElement("control");
+ }
+ }
+
+ /* a list of camera stream configurations */
+ curElem = aCapElem->FirstChildElement("stream");
+ while (curElem != nullptr) {
+ /* read 5 attributes */
+ const XMLAttribute *idAttr = curElem->FindAttribute("id");
+ const XMLAttribute *widthAttr = curElem->FindAttribute("width");
+ const XMLAttribute *heightAttr = curElem->FindAttribute("height");
+ const XMLAttribute *fmtAttr = curElem->FindAttribute("format");
+ const XMLAttribute *fpsAttr = curElem->FindAttribute("framerate");
+
+ const int32_t id = stoi(idAttr->Value());
+ int32_t framerate = 0;
+ if (fpsAttr != nullptr) {
+ framerate = stoi(fpsAttr->Value());
+ }
+
+ int32_t pixFormat;
+ if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+ pixFormat)) {
+ RawStreamConfiguration cfg = {
+ id,
+ stoi(widthAttr->Value()),
+ stoi(heightAttr->Value()),
+ pixFormat,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+ framerate
+ };
+ aCamera->streamConfigurations[id] = cfg;
+ }
+
+ curElem = curElem->NextSiblingElement("stream");
+ }
+
+ dataSize = calculate_camera_metadata_entry_data_size(
+ get_camera_metadata_tag_type(
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ ),
+ aCamera->streamConfigurations.size() * kStreamCfgSz
+ );
+
+ /* a single camera metadata entry contains multiple stream configurations */
+ return dataSize > 0 ? 1 : 0;
+}
+
+
+size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
+ unique_ptr<ConfigManager::CameraInfo> &aCamera,
+ size_t &dataSize) {
+ if (aParamElem == nullptr) {
+ return 0;
+ }
+
+ const XMLElement *curElem = aParamElem->FirstChildElement("parameter");
+ size_t numEntries = 0;
+ camera_metadata_tag_t tag;
+ while (curElem != nullptr) {
+ if (!ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(),
+ tag)) {
+ switch(tag) {
+ case ANDROID_LENS_DISTORTION:
+ case ANDROID_LENS_POSE_ROTATION:
+ case ANDROID_LENS_POSE_TRANSLATION:
+ case ANDROID_LENS_INTRINSIC_CALIBRATION: {
+ /* float[] */
+ size_t count = 0;
+ void *data = ConfigManagerUtil::convertFloatArray(
+ curElem->FindAttribute("size")->Value(),
+ curElem->FindAttribute("value")->Value(),
+ count
+ );
+
+ aCamera->cameraMetadata[tag] =
+ make_pair(make_unique<void *>(data), count);
+
+ ++numEntries;
+ dataSize += calculate_camera_metadata_entry_data_size(
+ get_camera_metadata_tag_type(tag), count
+ );
+
+ break;
+ }
+
+ default:
+ ALOGW("Parameter %s is not supported",
+ curElem->FindAttribute("name")->Value());
+ break;
+ }
+ }
+
+ curElem = curElem->NextSiblingElement("parameter");
+ }
+
+ return numEntries;
+}
+
+
+bool ConfigManager::constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
+ const size_t totalEntries,
+ const size_t totalDataSize) {
+ if (!aCamera->allocate(totalEntries, totalDataSize)) {
+ ALOGE("Failed to allocate memory for camera metadata");
+ return false;
+ }
+
+ const size_t numStreamConfigs = aCamera->streamConfigurations.size();
+ unique_ptr<int32_t[]> data(new int32_t[kStreamCfgSz * numStreamConfigs]);
+ int32_t *ptr = data.get();
+ for (auto &cfg : aCamera->streamConfigurations) {
+ for (auto i = 0; i < kStreamCfgSz; ++i) {
+ *ptr++ = cfg.second[i];
+ }
+ }
+ int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ data.get(),
+ numStreamConfigs * kStreamCfgSz);
+
+ if (err) {
+ ALOGE("Failed to add stream configurations to metadata, ignored");
+ return false;
+ }
+
+ bool success = true;
+ for (auto &[tag, entry] : aCamera->cameraMetadata) {
+ /* try to add new camera metadata entry */
+ int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+ tag,
+ entry.first.get(),
+ entry.second);
+ if (err) {
+ ALOGE("Failed to add an entry with a tag 0x%X", tag);
+
+ /* may exceed preallocated capacity */
+ ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
+ get_camera_metadata_entry_count(aCamera->characteristics),
+ get_camera_metadata_entry_capacity(aCamera->characteristics),
+ get_camera_metadata_data_count(aCamera->characteristics),
+ get_camera_metadata_data_capacity(aCamera->characteristics));
+ ALOGE("\tCurrent metadata entry requires %ld bytes",
+ calculate_camera_metadata_entry_data_size(tag, entry.second));
+
+ success = false;
+ }
+ }
+
+ ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
+ get_camera_metadata_entry_count(aCamera->characteristics),
+ get_camera_metadata_entry_capacity(aCamera->characteristics),
+ get_camera_metadata_data_count(aCamera->characteristics),
+ get_camera_metadata_data_capacity(aCamera->characteristics));
+
+ return success;
+}
+
+
+void ConfigManager::readSystemInfo(const XMLElement * const aSysElem) {
+ if (aSysElem == nullptr) {
+ return;
+ }
+
+ /*
+ * Please note that this function assumes that a given system XML element
+ * and its child elements follow DTD. If it does not, it will cause a
+ * segmentation fault due to the failure of finding expected attributes.
+ */
+
+ /* read number of cameras available in the system */
+ const XMLElement *xmlElem = aSysElem->FirstChildElement("num_cameras");
+ if (xmlElem != nullptr) {
+ mSystemInfo.numCameras =
+ stoi(xmlElem->FindAttribute("value")->Value());
+ }
+}
+
+
+void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) {
+ if (aDisplayElem == nullptr) {
+ ALOGW("XML file does not have required camera element");
+ return;
+ }
+
+ const XMLElement *curDev = aDisplayElem->FirstChildElement("device");
+ while (curDev != nullptr) {
+ const char *id = curDev->FindAttribute("id")->Value();
+ //const char *pos = curDev->FirstAttribute("position")->Value();
+
+ unique_ptr<DisplayInfo> dpy(new DisplayInfo());
+ if (dpy == nullptr) {
+ ALOGE("Failed to allocate memory for DisplayInfo");
+ return;
+ }
+
+ const XMLElement *cap = curDev->FirstChildElement("caps");
+ if (cap != nullptr) {
+ const XMLElement *curStream = cap->FirstChildElement("stream");
+ while (curStream != nullptr) {
+ /* read 4 attributes */
+ const XMLAttribute *idAttr = curStream->FindAttribute("id");
+ const XMLAttribute *widthAttr = curStream->FindAttribute("width");
+ const XMLAttribute *heightAttr = curStream->FindAttribute("height");
+ const XMLAttribute *fmtAttr = curStream->FindAttribute("format");
+
+ const int32_t id = stoi(idAttr->Value());
+ int32_t pixFormat;
+ if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+ pixFormat)) {
+ RawStreamConfiguration cfg = {
+ id,
+ stoi(widthAttr->Value()),
+ stoi(heightAttr->Value()),
+ pixFormat,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
+ 0 // unused
+ };
+ dpy->streamConfigurations[id] = cfg;
+ }
+
+ curStream = curStream->NextSiblingElement("stream");
+ }
+ }
+
+ mDisplayInfo[id] = std::move(dpy);
+ curDev = curDev->NextSiblingElement("device");
+ }
+
+ return;
+}
+
+
+bool ConfigManager::readConfigDataFromXML() noexcept {
+ XMLDocument xmlDoc;
+
+ const int64_t parsingStart = android::elapsedRealtimeNano();
+
+ /* load and parse a configuration file */
+ xmlDoc.LoadFile(mConfigFilePath);
+ if (xmlDoc.ErrorID() != XML_SUCCESS) {
+ ALOGE("Failed to load and/or parse a configuration file, %s", xmlDoc.ErrorStr());
+ return false;
+ }
+
+ /* retrieve the root element */
+ const XMLElement *rootElem = xmlDoc.RootElement();
+ if (strcmp(rootElem->Name(), "configuration")) {
+ ALOGE("A configuration file is not in the required format. "
+ "See /etc/automotive/evs/evs_configuration.dtd");
+ return false;
+ }
+
+ /*
+ * parse camera information; this needs to be done before reading system
+ * information
+ */
+ readCameraInfo(rootElem->FirstChildElement("camera"));
+
+ /* parse system information */
+ readSystemInfo(rootElem->FirstChildElement("system"));
+
+ /* parse display information */
+ readDisplayInfo(rootElem->FirstChildElement("display"));
+
+ const int64_t parsingEnd = android::elapsedRealtimeNano();
+ ALOGI("Parsing configuration file takes %lf (ms)",
+ (double)(parsingEnd - parsingStart) / 1000000.0);
+
+
+ return true;
+}
+
+
+void ConfigManager::addCameraDevices(const char *devices,
+ unique_ptr<CameraGroup> &aGroup) {
+ stringstream device_list(devices);
+ string token;
+ while (getline(device_list, token, ',')) {
+ aGroup->devices.emplace(token);
+ }
+}
+
+
+std::unique_ptr<ConfigManager> ConfigManager::Create(const char *path) {
+ unique_ptr<ConfigManager> cfgMgr(new ConfigManager(path));
+
+ /*
+ * Read a configuration from XML file
+ *
+ * If this is too slow, ConfigManager::readConfigDataFromBinary() and
+ * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object
+ * to the filesystem and construct CameraInfo instead; this was
+ * evaluated as 10x faster.
+ */
+ if (!cfgMgr->readConfigDataFromXML()) {
+ return nullptr;
+ } else {
+ return cfgMgr;
+ }
+}
+