xref: /aosp_15_r20/hardware/interfaces/automotive/evs/1.1/default/ConfigManager.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker  *
4*4d7e907cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker  *
8*4d7e907cSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker  *
10*4d7e907cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker  * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker  */
16*4d7e907cSAndroid Build Coastguard Worker 
17*4d7e907cSAndroid Build Coastguard Worker #include "ConfigManager.h"
18*4d7e907cSAndroid Build Coastguard Worker 
19*4d7e907cSAndroid Build Coastguard Worker #include <android/hardware/camera/device/3.2/ICameraDevice.h>
20*4d7e907cSAndroid Build Coastguard Worker #include <hardware/gralloc.h>
21*4d7e907cSAndroid Build Coastguard Worker #include <utils/SystemClock.h>
22*4d7e907cSAndroid Build Coastguard Worker 
23*4d7e907cSAndroid Build Coastguard Worker #include <fstream>
24*4d7e907cSAndroid Build Coastguard Worker #include <sstream>
25*4d7e907cSAndroid Build Coastguard Worker #include <thread>
26*4d7e907cSAndroid Build Coastguard Worker 
27*4d7e907cSAndroid Build Coastguard Worker namespace android::hardware::automotive::evs::V1_1::implementation {
28*4d7e907cSAndroid Build Coastguard Worker 
29*4d7e907cSAndroid Build Coastguard Worker using namespace std;
30*4d7e907cSAndroid Build Coastguard Worker using namespace tinyxml2;
31*4d7e907cSAndroid Build Coastguard Worker using hardware::camera::device::V3_2::StreamRotation;
32*4d7e907cSAndroid Build Coastguard Worker 
~ConfigManager()33*4d7e907cSAndroid Build Coastguard Worker ConfigManager::~ConfigManager() {
34*4d7e907cSAndroid Build Coastguard Worker     /* Nothing to do */
35*4d7e907cSAndroid Build Coastguard Worker }
36*4d7e907cSAndroid Build Coastguard Worker 
readCameraInfo(const XMLElement * const aCameraElem)37*4d7e907cSAndroid Build Coastguard Worker void ConfigManager::readCameraInfo(const XMLElement* const aCameraElem) {
38*4d7e907cSAndroid Build Coastguard Worker     if (aCameraElem == nullptr) {
39*4d7e907cSAndroid Build Coastguard Worker         ALOGW("XML file does not have required camera element");
40*4d7e907cSAndroid Build Coastguard Worker         return;
41*4d7e907cSAndroid Build Coastguard Worker     }
42*4d7e907cSAndroid Build Coastguard Worker 
43*4d7e907cSAndroid Build Coastguard Worker     const XMLElement* curElem = aCameraElem->FirstChildElement();
44*4d7e907cSAndroid Build Coastguard Worker     while (curElem != nullptr) {
45*4d7e907cSAndroid Build Coastguard Worker         if (!strcmp(curElem->Name(), "group")) {
46*4d7e907cSAndroid Build Coastguard Worker             /* camera group identifier */
47*4d7e907cSAndroid Build Coastguard Worker             const char* id = curElem->FindAttribute("id")->Value();
48*4d7e907cSAndroid Build Coastguard Worker 
49*4d7e907cSAndroid Build Coastguard Worker             /* create a camera group to be filled */
50*4d7e907cSAndroid Build Coastguard Worker             CameraGroupInfo* aCamera = new CameraGroupInfo();
51*4d7e907cSAndroid Build Coastguard Worker 
52*4d7e907cSAndroid Build Coastguard Worker             /* read camera device information */
53*4d7e907cSAndroid Build Coastguard Worker             if (!readCameraDeviceInfo(aCamera, curElem)) {
54*4d7e907cSAndroid Build Coastguard Worker                 ALOGW("Failed to read a camera information of %s", id);
55*4d7e907cSAndroid Build Coastguard Worker                 delete aCamera;
56*4d7e907cSAndroid Build Coastguard Worker                 continue;
57*4d7e907cSAndroid Build Coastguard Worker             }
58*4d7e907cSAndroid Build Coastguard Worker 
59*4d7e907cSAndroid Build Coastguard Worker             /* camera group synchronization */
60*4d7e907cSAndroid Build Coastguard Worker             const char* sync = curElem->FindAttribute("synchronized")->Value();
61*4d7e907cSAndroid Build Coastguard Worker             if (!strcmp(sync, "CALIBRATED")) {
62*4d7e907cSAndroid Build Coastguard Worker                 aCamera->synchronized = ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED;
63*4d7e907cSAndroid Build Coastguard Worker             } else if (!strcmp(sync, "APPROXIMATE")) {
64*4d7e907cSAndroid Build Coastguard Worker                 aCamera->synchronized = ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE;
65*4d7e907cSAndroid Build Coastguard Worker             } else {
66*4d7e907cSAndroid Build Coastguard Worker                 aCamera->synchronized = 0;  // Not synchronized
67*4d7e907cSAndroid Build Coastguard Worker             }
68*4d7e907cSAndroid Build Coastguard Worker 
69*4d7e907cSAndroid Build Coastguard Worker             /* add a group to hash map */
70*4d7e907cSAndroid Build Coastguard Worker             mCameraGroupInfos.insert_or_assign(id, unique_ptr<CameraGroupInfo>(aCamera));
71*4d7e907cSAndroid Build Coastguard Worker         } else if (!strcmp(curElem->Name(), "device")) {
72*4d7e907cSAndroid Build Coastguard Worker             /* camera unique identifier */
73*4d7e907cSAndroid Build Coastguard Worker             const char* id = curElem->FindAttribute("id")->Value();
74*4d7e907cSAndroid Build Coastguard Worker 
75*4d7e907cSAndroid Build Coastguard Worker             /* camera mount location */
76*4d7e907cSAndroid Build Coastguard Worker             const char* pos = curElem->FindAttribute("position")->Value();
77*4d7e907cSAndroid Build Coastguard Worker 
78*4d7e907cSAndroid Build Coastguard Worker             /* create a camera device to be filled */
79*4d7e907cSAndroid Build Coastguard Worker             CameraInfo* aCamera = new CameraInfo();
80*4d7e907cSAndroid Build Coastguard Worker 
81*4d7e907cSAndroid Build Coastguard Worker             /* read camera device information */
82*4d7e907cSAndroid Build Coastguard Worker             if (!readCameraDeviceInfo(aCamera, curElem)) {
83*4d7e907cSAndroid Build Coastguard Worker                 ALOGW("Failed to read a camera information of %s", id);
84*4d7e907cSAndroid Build Coastguard Worker                 delete aCamera;
85*4d7e907cSAndroid Build Coastguard Worker                 continue;
86*4d7e907cSAndroid Build Coastguard Worker             }
87*4d7e907cSAndroid Build Coastguard Worker 
88*4d7e907cSAndroid Build Coastguard Worker             /* store read camera module information */
89*4d7e907cSAndroid Build Coastguard Worker             mCameraInfo.insert_or_assign(id, unique_ptr<CameraInfo>(aCamera));
90*4d7e907cSAndroid Build Coastguard Worker 
91*4d7e907cSAndroid Build Coastguard Worker             /* assign a camera device to a position group */
92*4d7e907cSAndroid Build Coastguard Worker             mCameraPosition[pos].emplace(id);
93*4d7e907cSAndroid Build Coastguard Worker         } else {
94*4d7e907cSAndroid Build Coastguard Worker             /* ignore other device types */
95*4d7e907cSAndroid Build Coastguard Worker             ALOGD("Unknown element %s is ignored", curElem->Name());
96*4d7e907cSAndroid Build Coastguard Worker         }
97*4d7e907cSAndroid Build Coastguard Worker 
98*4d7e907cSAndroid Build Coastguard Worker         curElem = curElem->NextSiblingElement();
99*4d7e907cSAndroid Build Coastguard Worker     }
100*4d7e907cSAndroid Build Coastguard Worker }
101*4d7e907cSAndroid Build Coastguard Worker 
readCameraDeviceInfo(CameraInfo * aCamera,const XMLElement * aDeviceElem)102*4d7e907cSAndroid Build Coastguard Worker bool ConfigManager::readCameraDeviceInfo(CameraInfo* aCamera, const XMLElement* aDeviceElem) {
103*4d7e907cSAndroid Build Coastguard Worker     if (aCamera == nullptr || aDeviceElem == nullptr) {
104*4d7e907cSAndroid Build Coastguard Worker         return false;
105*4d7e907cSAndroid Build Coastguard Worker     }
106*4d7e907cSAndroid Build Coastguard Worker 
107*4d7e907cSAndroid Build Coastguard Worker     /* size information to allocate camera_metadata_t */
108*4d7e907cSAndroid Build Coastguard Worker     size_t totalEntries = 0;
109*4d7e907cSAndroid Build Coastguard Worker     size_t totalDataSize = 0;
110*4d7e907cSAndroid Build Coastguard Worker 
111*4d7e907cSAndroid Build Coastguard Worker     /* read device capabilities */
112*4d7e907cSAndroid Build Coastguard Worker     totalEntries +=
113*4d7e907cSAndroid Build Coastguard Worker             readCameraCapabilities(aDeviceElem->FirstChildElement("caps"), aCamera, totalDataSize);
114*4d7e907cSAndroid Build Coastguard Worker 
115*4d7e907cSAndroid Build Coastguard Worker     /* read camera metadata */
116*4d7e907cSAndroid Build Coastguard Worker     totalEntries += readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"), aCamera,
117*4d7e907cSAndroid Build Coastguard Worker                                        totalDataSize);
118*4d7e907cSAndroid Build Coastguard Worker 
119*4d7e907cSAndroid Build Coastguard Worker     /* construct camera_metadata_t */
120*4d7e907cSAndroid Build Coastguard Worker     if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) {
121*4d7e907cSAndroid Build Coastguard Worker         ALOGW("Either failed to allocate memory or "
122*4d7e907cSAndroid Build Coastguard Worker               "allocated memory was not large enough");
123*4d7e907cSAndroid Build Coastguard Worker     }
124*4d7e907cSAndroid Build Coastguard Worker 
125*4d7e907cSAndroid Build Coastguard Worker     return true;
126*4d7e907cSAndroid Build Coastguard Worker }
127*4d7e907cSAndroid Build Coastguard Worker 
readCameraCapabilities(const XMLElement * const aCapElem,CameraInfo * aCamera,size_t & dataSize)128*4d7e907cSAndroid Build Coastguard Worker size_t ConfigManager::readCameraCapabilities(const XMLElement* const aCapElem, CameraInfo* aCamera,
129*4d7e907cSAndroid Build Coastguard Worker                                              size_t& dataSize) {
130*4d7e907cSAndroid Build Coastguard Worker     if (aCapElem == nullptr || aCamera == nullptr) {
131*4d7e907cSAndroid Build Coastguard Worker         return 0;
132*4d7e907cSAndroid Build Coastguard Worker     }
133*4d7e907cSAndroid Build Coastguard Worker 
134*4d7e907cSAndroid Build Coastguard Worker     string token;
135*4d7e907cSAndroid Build Coastguard Worker     const XMLElement* curElem = nullptr;
136*4d7e907cSAndroid Build Coastguard Worker 
137*4d7e907cSAndroid Build Coastguard Worker     /* a list of supported camera parameters/controls */
138*4d7e907cSAndroid Build Coastguard Worker     curElem = aCapElem->FirstChildElement("supported_controls");
139*4d7e907cSAndroid Build Coastguard Worker     if (curElem != nullptr) {
140*4d7e907cSAndroid Build Coastguard Worker         const XMLElement* ctrlElem = curElem->FirstChildElement("control");
141*4d7e907cSAndroid Build Coastguard Worker         while (ctrlElem != nullptr) {
142*4d7e907cSAndroid Build Coastguard Worker             const char* nameAttr = ctrlElem->FindAttribute("name")->Value();
143*4d7e907cSAndroid Build Coastguard Worker             ;
144*4d7e907cSAndroid Build Coastguard Worker             const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value());
145*4d7e907cSAndroid Build Coastguard Worker             const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value());
146*4d7e907cSAndroid Build Coastguard Worker 
147*4d7e907cSAndroid Build Coastguard Worker             int32_t stepVal = 1;
148*4d7e907cSAndroid Build Coastguard Worker             const XMLAttribute* stepAttr = ctrlElem->FindAttribute("step");
149*4d7e907cSAndroid Build Coastguard Worker             if (stepAttr != nullptr) {
150*4d7e907cSAndroid Build Coastguard Worker                 stepVal = stoi(stepAttr->Value());
151*4d7e907cSAndroid Build Coastguard Worker             }
152*4d7e907cSAndroid Build Coastguard Worker 
153*4d7e907cSAndroid Build Coastguard Worker             CameraParam aParam;
154*4d7e907cSAndroid Build Coastguard Worker             if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr, aParam)) {
155*4d7e907cSAndroid Build Coastguard Worker                 aCamera->controls.emplace(aParam, make_tuple(minVal, maxVal, stepVal));
156*4d7e907cSAndroid Build Coastguard Worker             }
157*4d7e907cSAndroid Build Coastguard Worker 
158*4d7e907cSAndroid Build Coastguard Worker             ctrlElem = ctrlElem->NextSiblingElement("control");
159*4d7e907cSAndroid Build Coastguard Worker         }
160*4d7e907cSAndroid Build Coastguard Worker     }
161*4d7e907cSAndroid Build Coastguard Worker 
162*4d7e907cSAndroid Build Coastguard Worker     /* a list of camera stream configurations */
163*4d7e907cSAndroid Build Coastguard Worker     curElem = aCapElem->FirstChildElement("stream");
164*4d7e907cSAndroid Build Coastguard Worker     while (curElem != nullptr) {
165*4d7e907cSAndroid Build Coastguard Worker         /* read 5 attributes */
166*4d7e907cSAndroid Build Coastguard Worker         const XMLAttribute* idAttr = curElem->FindAttribute("id");
167*4d7e907cSAndroid Build Coastguard Worker         const XMLAttribute* widthAttr = curElem->FindAttribute("width");
168*4d7e907cSAndroid Build Coastguard Worker         const XMLAttribute* heightAttr = curElem->FindAttribute("height");
169*4d7e907cSAndroid Build Coastguard Worker         const XMLAttribute* fmtAttr = curElem->FindAttribute("format");
170*4d7e907cSAndroid Build Coastguard Worker         const XMLAttribute* fpsAttr = curElem->FindAttribute("framerate");
171*4d7e907cSAndroid Build Coastguard Worker 
172*4d7e907cSAndroid Build Coastguard Worker         const int32_t id = stoi(idAttr->Value());
173*4d7e907cSAndroid Build Coastguard Worker         int32_t framerate = 0;
174*4d7e907cSAndroid Build Coastguard Worker         if (fpsAttr != nullptr) {
175*4d7e907cSAndroid Build Coastguard Worker             framerate = stoi(fpsAttr->Value());
176*4d7e907cSAndroid Build Coastguard Worker         }
177*4d7e907cSAndroid Build Coastguard Worker 
178*4d7e907cSAndroid Build Coastguard Worker         int32_t pixFormat;
179*4d7e907cSAndroid Build Coastguard Worker         if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), pixFormat)) {
180*4d7e907cSAndroid Build Coastguard Worker             RawStreamConfiguration cfg = {id,
181*4d7e907cSAndroid Build Coastguard Worker                                           stoi(widthAttr->Value()),
182*4d7e907cSAndroid Build Coastguard Worker                                           stoi(heightAttr->Value()),
183*4d7e907cSAndroid Build Coastguard Worker                                           pixFormat,
184*4d7e907cSAndroid Build Coastguard Worker                                           ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
185*4d7e907cSAndroid Build Coastguard Worker                                           framerate};
186*4d7e907cSAndroid Build Coastguard Worker             aCamera->streamConfigurations.insert_or_assign(id, cfg);
187*4d7e907cSAndroid Build Coastguard Worker         }
188*4d7e907cSAndroid Build Coastguard Worker 
189*4d7e907cSAndroid Build Coastguard Worker         curElem = curElem->NextSiblingElement("stream");
190*4d7e907cSAndroid Build Coastguard Worker     }
191*4d7e907cSAndroid Build Coastguard Worker 
192*4d7e907cSAndroid Build Coastguard Worker     dataSize = calculate_camera_metadata_entry_data_size(
193*4d7e907cSAndroid Build Coastguard Worker             get_camera_metadata_tag_type(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS),
194*4d7e907cSAndroid Build Coastguard Worker             aCamera->streamConfigurations.size() * kStreamCfgSz);
195*4d7e907cSAndroid Build Coastguard Worker 
196*4d7e907cSAndroid Build Coastguard Worker     /* a single camera metadata entry contains multiple stream configurations */
197*4d7e907cSAndroid Build Coastguard Worker     return dataSize > 0 ? 1 : 0;
198*4d7e907cSAndroid Build Coastguard Worker }
199*4d7e907cSAndroid Build Coastguard Worker 
readCameraMetadata(const XMLElement * const aParamElem,CameraInfo * aCamera,size_t & dataSize)200*4d7e907cSAndroid Build Coastguard Worker size_t ConfigManager::readCameraMetadata(const XMLElement* const aParamElem, CameraInfo* aCamera,
201*4d7e907cSAndroid Build Coastguard Worker                                          size_t& dataSize) {
202*4d7e907cSAndroid Build Coastguard Worker     if (aParamElem == nullptr || aCamera == nullptr) {
203*4d7e907cSAndroid Build Coastguard Worker         return 0;
204*4d7e907cSAndroid Build Coastguard Worker     }
205*4d7e907cSAndroid Build Coastguard Worker 
206*4d7e907cSAndroid Build Coastguard Worker     const XMLElement* curElem = aParamElem->FirstChildElement("parameter");
207*4d7e907cSAndroid Build Coastguard Worker     size_t numEntries = 0;
208*4d7e907cSAndroid Build Coastguard Worker     camera_metadata_tag_t tag;
209*4d7e907cSAndroid Build Coastguard Worker     while (curElem != nullptr) {
210*4d7e907cSAndroid Build Coastguard Worker         if (!ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(),
211*4d7e907cSAndroid Build Coastguard Worker                                                      tag)) {
212*4d7e907cSAndroid Build Coastguard Worker             switch (tag) {
213*4d7e907cSAndroid Build Coastguard Worker                 case ANDROID_LENS_DISTORTION:
214*4d7e907cSAndroid Build Coastguard Worker                 case ANDROID_LENS_POSE_ROTATION:
215*4d7e907cSAndroid Build Coastguard Worker                 case ANDROID_LENS_POSE_TRANSLATION:
216*4d7e907cSAndroid Build Coastguard Worker                 case ANDROID_LENS_INTRINSIC_CALIBRATION: {
217*4d7e907cSAndroid Build Coastguard Worker                     /* float[] */
218*4d7e907cSAndroid Build Coastguard Worker                     size_t count = 0;
219*4d7e907cSAndroid Build Coastguard Worker                     void* data = ConfigManagerUtil::convertFloatArray(
220*4d7e907cSAndroid Build Coastguard Worker                             curElem->FindAttribute("size")->Value(),
221*4d7e907cSAndroid Build Coastguard Worker                             curElem->FindAttribute("value")->Value(), count);
222*4d7e907cSAndroid Build Coastguard Worker 
223*4d7e907cSAndroid Build Coastguard Worker                     aCamera->cameraMetadata.insert_or_assign(
224*4d7e907cSAndroid Build Coastguard Worker                             tag, make_pair(make_unique<void*>(data), count));
225*4d7e907cSAndroid Build Coastguard Worker 
226*4d7e907cSAndroid Build Coastguard Worker                     ++numEntries;
227*4d7e907cSAndroid Build Coastguard Worker                     dataSize += calculate_camera_metadata_entry_data_size(
228*4d7e907cSAndroid Build Coastguard Worker                             get_camera_metadata_tag_type(tag), count);
229*4d7e907cSAndroid Build Coastguard Worker 
230*4d7e907cSAndroid Build Coastguard Worker                     break;
231*4d7e907cSAndroid Build Coastguard Worker                 }
232*4d7e907cSAndroid Build Coastguard Worker 
233*4d7e907cSAndroid Build Coastguard Worker                 case ANDROID_REQUEST_AVAILABLE_CAPABILITIES: {
234*4d7e907cSAndroid Build Coastguard Worker                     camera_metadata_enum_android_request_available_capabilities_t* data =
235*4d7e907cSAndroid Build Coastguard Worker                             new camera_metadata_enum_android_request_available_capabilities_t[1];
236*4d7e907cSAndroid Build Coastguard Worker                     if (ConfigManagerUtil::convertToCameraCapability(
237*4d7e907cSAndroid Build Coastguard Worker                                 curElem->FindAttribute("value")->Value(), *data)) {
238*4d7e907cSAndroid Build Coastguard Worker                         curElem->FindAttribute("value")->Value(),
239*4d7e907cSAndroid Build Coastguard Worker                                 aCamera->cameraMetadata.insert_or_assign(
240*4d7e907cSAndroid Build Coastguard Worker                                         tag, make_pair(make_unique<void*>(data), 1));
241*4d7e907cSAndroid Build Coastguard Worker 
242*4d7e907cSAndroid Build Coastguard Worker                         ++numEntries;
243*4d7e907cSAndroid Build Coastguard Worker                         dataSize += calculate_camera_metadata_entry_data_size(
244*4d7e907cSAndroid Build Coastguard Worker                                 get_camera_metadata_tag_type(tag), 1);
245*4d7e907cSAndroid Build Coastguard Worker                     }
246*4d7e907cSAndroid Build Coastguard Worker                     break;
247*4d7e907cSAndroid Build Coastguard Worker                 }
248*4d7e907cSAndroid Build Coastguard Worker 
249*4d7e907cSAndroid Build Coastguard Worker                 case ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS: {
250*4d7e907cSAndroid Build Coastguard Worker                     /* a comma-separated list of physical camera devices */
251*4d7e907cSAndroid Build Coastguard Worker                     size_t len = strlen(curElem->FindAttribute("value")->Value());
252*4d7e907cSAndroid Build Coastguard Worker                     char* data = new char[len + 1];
253*4d7e907cSAndroid Build Coastguard Worker                     memcpy(data, curElem->FindAttribute("value")->Value(), len * sizeof(char));
254*4d7e907cSAndroid Build Coastguard Worker 
255*4d7e907cSAndroid Build Coastguard Worker                     /* replace commas with null char */
256*4d7e907cSAndroid Build Coastguard Worker                     char* p = data;
257*4d7e907cSAndroid Build Coastguard Worker                     while (*p != '\0') {
258*4d7e907cSAndroid Build Coastguard Worker                         if (*p == ',') {
259*4d7e907cSAndroid Build Coastguard Worker                             *p = '\0';
260*4d7e907cSAndroid Build Coastguard Worker                         }
261*4d7e907cSAndroid Build Coastguard Worker                         ++p;
262*4d7e907cSAndroid Build Coastguard Worker                     }
263*4d7e907cSAndroid Build Coastguard Worker 
264*4d7e907cSAndroid Build Coastguard Worker                     aCamera->cameraMetadata.insert_or_assign(
265*4d7e907cSAndroid Build Coastguard Worker                             tag, make_pair(make_unique<void*>(data), len));
266*4d7e907cSAndroid Build Coastguard Worker 
267*4d7e907cSAndroid Build Coastguard Worker                     ++numEntries;
268*4d7e907cSAndroid Build Coastguard Worker                     dataSize += calculate_camera_metadata_entry_data_size(
269*4d7e907cSAndroid Build Coastguard Worker                             get_camera_metadata_tag_type(tag), len);
270*4d7e907cSAndroid Build Coastguard Worker                     break;
271*4d7e907cSAndroid Build Coastguard Worker                 }
272*4d7e907cSAndroid Build Coastguard Worker 
273*4d7e907cSAndroid Build Coastguard Worker                 default:
274*4d7e907cSAndroid Build Coastguard Worker                     ALOGW("Parameter %s is not supported", curElem->FindAttribute("name")->Value());
275*4d7e907cSAndroid Build Coastguard Worker                     break;
276*4d7e907cSAndroid Build Coastguard Worker             }
277*4d7e907cSAndroid Build Coastguard Worker         }
278*4d7e907cSAndroid Build Coastguard Worker 
279*4d7e907cSAndroid Build Coastguard Worker         curElem = curElem->NextSiblingElement("parameter");
280*4d7e907cSAndroid Build Coastguard Worker     }
281*4d7e907cSAndroid Build Coastguard Worker 
282*4d7e907cSAndroid Build Coastguard Worker     return numEntries;
283*4d7e907cSAndroid Build Coastguard Worker }
284*4d7e907cSAndroid Build Coastguard Worker 
constructCameraMetadata(CameraInfo * aCamera,const size_t totalEntries,const size_t totalDataSize)285*4d7e907cSAndroid Build Coastguard Worker bool ConfigManager::constructCameraMetadata(CameraInfo* aCamera, const size_t totalEntries,
286*4d7e907cSAndroid Build Coastguard Worker                                             const size_t totalDataSize) {
287*4d7e907cSAndroid Build Coastguard Worker     if (aCamera == nullptr || !aCamera->allocate(totalEntries, totalDataSize)) {
288*4d7e907cSAndroid Build Coastguard Worker         ALOGE("Failed to allocate memory for camera metadata");
289*4d7e907cSAndroid Build Coastguard Worker         return false;
290*4d7e907cSAndroid Build Coastguard Worker     }
291*4d7e907cSAndroid Build Coastguard Worker 
292*4d7e907cSAndroid Build Coastguard Worker     const size_t numStreamConfigs = aCamera->streamConfigurations.size();
293*4d7e907cSAndroid Build Coastguard Worker     unique_ptr<int32_t[]> data(new int32_t[kStreamCfgSz * numStreamConfigs]);
294*4d7e907cSAndroid Build Coastguard Worker     int32_t* ptr = data.get();
295*4d7e907cSAndroid Build Coastguard Worker     for (auto& cfg : aCamera->streamConfigurations) {
296*4d7e907cSAndroid Build Coastguard Worker         for (auto i = 0; i < kStreamCfgSz; ++i) {
297*4d7e907cSAndroid Build Coastguard Worker             *ptr++ = cfg.second[i];
298*4d7e907cSAndroid Build Coastguard Worker         }
299*4d7e907cSAndroid Build Coastguard Worker     }
300*4d7e907cSAndroid Build Coastguard Worker     int32_t err = add_camera_metadata_entry(aCamera->characteristics,
301*4d7e907cSAndroid Build Coastguard Worker                                             ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
302*4d7e907cSAndroid Build Coastguard Worker                                             data.get(), numStreamConfigs * kStreamCfgSz);
303*4d7e907cSAndroid Build Coastguard Worker 
304*4d7e907cSAndroid Build Coastguard Worker     if (err) {
305*4d7e907cSAndroid Build Coastguard Worker         ALOGE("Failed to add stream configurations to metadata, ignored");
306*4d7e907cSAndroid Build Coastguard Worker         return false;
307*4d7e907cSAndroid Build Coastguard Worker     }
308*4d7e907cSAndroid Build Coastguard Worker 
309*4d7e907cSAndroid Build Coastguard Worker     bool success = true;
310*4d7e907cSAndroid Build Coastguard Worker     for (auto& [tag, entry] : aCamera->cameraMetadata) {
311*4d7e907cSAndroid Build Coastguard Worker         /* try to add new camera metadata entry */
312*4d7e907cSAndroid Build Coastguard Worker         int32_t err = add_camera_metadata_entry(aCamera->characteristics, tag, entry.first.get(),
313*4d7e907cSAndroid Build Coastguard Worker                                                 entry.second);
314*4d7e907cSAndroid Build Coastguard Worker         if (err) {
315*4d7e907cSAndroid Build Coastguard Worker             ALOGE("Failed to add an entry with a tag 0x%X", tag);
316*4d7e907cSAndroid Build Coastguard Worker 
317*4d7e907cSAndroid Build Coastguard Worker             /* may exceed preallocated capacity */
318*4d7e907cSAndroid Build Coastguard Worker             ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
319*4d7e907cSAndroid Build Coastguard Worker                   (long)get_camera_metadata_entry_count(aCamera->characteristics),
320*4d7e907cSAndroid Build Coastguard Worker                   (long)get_camera_metadata_entry_capacity(aCamera->characteristics),
321*4d7e907cSAndroid Build Coastguard Worker                   (long)get_camera_metadata_data_count(aCamera->characteristics),
322*4d7e907cSAndroid Build Coastguard Worker                   (long)get_camera_metadata_data_capacity(aCamera->characteristics));
323*4d7e907cSAndroid Build Coastguard Worker             ALOGE("\tCurrent metadata entry requires %ld bytes",
324*4d7e907cSAndroid Build Coastguard Worker                   (long)calculate_camera_metadata_entry_data_size(tag, entry.second));
325*4d7e907cSAndroid Build Coastguard Worker 
326*4d7e907cSAndroid Build Coastguard Worker             success = false;
327*4d7e907cSAndroid Build Coastguard Worker         }
328*4d7e907cSAndroid Build Coastguard Worker     }
329*4d7e907cSAndroid Build Coastguard Worker 
330*4d7e907cSAndroid Build Coastguard Worker     ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
331*4d7e907cSAndroid Build Coastguard Worker           (long)get_camera_metadata_entry_count(aCamera->characteristics),
332*4d7e907cSAndroid Build Coastguard Worker           (long)get_camera_metadata_entry_capacity(aCamera->characteristics),
333*4d7e907cSAndroid Build Coastguard Worker           (long)get_camera_metadata_data_count(aCamera->characteristics),
334*4d7e907cSAndroid Build Coastguard Worker           (long)get_camera_metadata_data_capacity(aCamera->characteristics));
335*4d7e907cSAndroid Build Coastguard Worker 
336*4d7e907cSAndroid Build Coastguard Worker     return success;
337*4d7e907cSAndroid Build Coastguard Worker }
338*4d7e907cSAndroid Build Coastguard Worker 
readSystemInfo(const XMLElement * const aSysElem)339*4d7e907cSAndroid Build Coastguard Worker void ConfigManager::readSystemInfo(const XMLElement* const aSysElem) {
340*4d7e907cSAndroid Build Coastguard Worker     if (aSysElem == nullptr) {
341*4d7e907cSAndroid Build Coastguard Worker         return;
342*4d7e907cSAndroid Build Coastguard Worker     }
343*4d7e907cSAndroid Build Coastguard Worker 
344*4d7e907cSAndroid Build Coastguard Worker     /*
345*4d7e907cSAndroid Build Coastguard Worker      * Please note that this function assumes that a given system XML element
346*4d7e907cSAndroid Build Coastguard Worker      * and its child elements follow DTD.  If it does not, it will cause a
347*4d7e907cSAndroid Build Coastguard Worker      * segmentation fault due to the failure of finding expected attributes.
348*4d7e907cSAndroid Build Coastguard Worker      */
349*4d7e907cSAndroid Build Coastguard Worker 
350*4d7e907cSAndroid Build Coastguard Worker     /* read number of cameras available in the system */
351*4d7e907cSAndroid Build Coastguard Worker     const XMLElement* xmlElem = aSysElem->FirstChildElement("num_cameras");
352*4d7e907cSAndroid Build Coastguard Worker     if (xmlElem != nullptr) {
353*4d7e907cSAndroid Build Coastguard Worker         mSystemInfo.numCameras = stoi(xmlElem->FindAttribute("value")->Value());
354*4d7e907cSAndroid Build Coastguard Worker     }
355*4d7e907cSAndroid Build Coastguard Worker }
356*4d7e907cSAndroid Build Coastguard Worker 
readDisplayInfo(const XMLElement * const aDisplayElem)357*4d7e907cSAndroid Build Coastguard Worker void ConfigManager::readDisplayInfo(const XMLElement* const aDisplayElem) {
358*4d7e907cSAndroid Build Coastguard Worker     if (aDisplayElem == nullptr) {
359*4d7e907cSAndroid Build Coastguard Worker         ALOGW("XML file does not have required camera element");
360*4d7e907cSAndroid Build Coastguard Worker         return;
361*4d7e907cSAndroid Build Coastguard Worker     }
362*4d7e907cSAndroid Build Coastguard Worker 
363*4d7e907cSAndroid Build Coastguard Worker     const XMLElement* curDev = aDisplayElem->FirstChildElement("device");
364*4d7e907cSAndroid Build Coastguard Worker     while (curDev != nullptr) {
365*4d7e907cSAndroid Build Coastguard Worker         const char* id = curDev->FindAttribute("id")->Value();
366*4d7e907cSAndroid Build Coastguard Worker         // const char *pos = curDev->FirstAttribute("position")->Value();
367*4d7e907cSAndroid Build Coastguard Worker 
368*4d7e907cSAndroid Build Coastguard Worker         unique_ptr<DisplayInfo> dpy(new DisplayInfo());
369*4d7e907cSAndroid Build Coastguard Worker         if (dpy == nullptr) {
370*4d7e907cSAndroid Build Coastguard Worker             ALOGE("Failed to allocate memory for DisplayInfo");
371*4d7e907cSAndroid Build Coastguard Worker             return;
372*4d7e907cSAndroid Build Coastguard Worker         }
373*4d7e907cSAndroid Build Coastguard Worker 
374*4d7e907cSAndroid Build Coastguard Worker         const XMLElement* cap = curDev->FirstChildElement("caps");
375*4d7e907cSAndroid Build Coastguard Worker         if (cap != nullptr) {
376*4d7e907cSAndroid Build Coastguard Worker             const XMLElement* curStream = cap->FirstChildElement("stream");
377*4d7e907cSAndroid Build Coastguard Worker             while (curStream != nullptr) {
378*4d7e907cSAndroid Build Coastguard Worker                 /* read 4 attributes */
379*4d7e907cSAndroid Build Coastguard Worker                 const XMLAttribute* idAttr = curStream->FindAttribute("id");
380*4d7e907cSAndroid Build Coastguard Worker                 const XMLAttribute* widthAttr = curStream->FindAttribute("width");
381*4d7e907cSAndroid Build Coastguard Worker                 const XMLAttribute* heightAttr = curStream->FindAttribute("height");
382*4d7e907cSAndroid Build Coastguard Worker                 const XMLAttribute* fmtAttr = curStream->FindAttribute("format");
383*4d7e907cSAndroid Build Coastguard Worker 
384*4d7e907cSAndroid Build Coastguard Worker                 const int32_t id = stoi(idAttr->Value());
385*4d7e907cSAndroid Build Coastguard Worker                 int32_t pixFormat;
386*4d7e907cSAndroid Build Coastguard Worker                 if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(), pixFormat)) {
387*4d7e907cSAndroid Build Coastguard Worker                     RawStreamConfiguration cfg = {
388*4d7e907cSAndroid Build Coastguard Worker                             id,
389*4d7e907cSAndroid Build Coastguard Worker                             stoi(widthAttr->Value()),
390*4d7e907cSAndroid Build Coastguard Worker                             stoi(heightAttr->Value()),
391*4d7e907cSAndroid Build Coastguard Worker                             pixFormat,
392*4d7e907cSAndroid Build Coastguard Worker                             ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
393*4d7e907cSAndroid Build Coastguard Worker                             0  // unused
394*4d7e907cSAndroid Build Coastguard Worker                     };
395*4d7e907cSAndroid Build Coastguard Worker                     dpy->streamConfigurations.insert_or_assign(id, cfg);
396*4d7e907cSAndroid Build Coastguard Worker                 }
397*4d7e907cSAndroid Build Coastguard Worker 
398*4d7e907cSAndroid Build Coastguard Worker                 curStream = curStream->NextSiblingElement("stream");
399*4d7e907cSAndroid Build Coastguard Worker             }
400*4d7e907cSAndroid Build Coastguard Worker         }
401*4d7e907cSAndroid Build Coastguard Worker 
402*4d7e907cSAndroid Build Coastguard Worker         mDisplayInfo.insert_or_assign(id, std::move(dpy));
403*4d7e907cSAndroid Build Coastguard Worker         curDev = curDev->NextSiblingElement("device");
404*4d7e907cSAndroid Build Coastguard Worker     }
405*4d7e907cSAndroid Build Coastguard Worker 
406*4d7e907cSAndroid Build Coastguard Worker     return;
407*4d7e907cSAndroid Build Coastguard Worker }
408*4d7e907cSAndroid Build Coastguard Worker 
readConfigDataFromXML()409*4d7e907cSAndroid Build Coastguard Worker bool ConfigManager::readConfigDataFromXML() noexcept {
410*4d7e907cSAndroid Build Coastguard Worker     XMLDocument xmlDoc;
411*4d7e907cSAndroid Build Coastguard Worker 
412*4d7e907cSAndroid Build Coastguard Worker     const int64_t parsingStart = android::elapsedRealtimeNano();
413*4d7e907cSAndroid Build Coastguard Worker 
414*4d7e907cSAndroid Build Coastguard Worker     /* load and parse a configuration file */
415*4d7e907cSAndroid Build Coastguard Worker     xmlDoc.LoadFile(mConfigFilePath);
416*4d7e907cSAndroid Build Coastguard Worker     if (xmlDoc.ErrorID() != XML_SUCCESS) {
417*4d7e907cSAndroid Build Coastguard Worker         ALOGE("Failed to load and/or parse a configuration file, %s", xmlDoc.ErrorStr());
418*4d7e907cSAndroid Build Coastguard Worker         return false;
419*4d7e907cSAndroid Build Coastguard Worker     }
420*4d7e907cSAndroid Build Coastguard Worker 
421*4d7e907cSAndroid Build Coastguard Worker     /* retrieve the root element */
422*4d7e907cSAndroid Build Coastguard Worker     const XMLElement* rootElem = xmlDoc.RootElement();
423*4d7e907cSAndroid Build Coastguard Worker     if (strcmp(rootElem->Name(), "configuration")) {
424*4d7e907cSAndroid Build Coastguard Worker         ALOGE("A configuration file is not in the required format.  "
425*4d7e907cSAndroid Build Coastguard Worker               "See /etc/automotive/evs/evs_configuration.dtd");
426*4d7e907cSAndroid Build Coastguard Worker         return false;
427*4d7e907cSAndroid Build Coastguard Worker     }
428*4d7e907cSAndroid Build Coastguard Worker 
429*4d7e907cSAndroid Build Coastguard Worker     /*
430*4d7e907cSAndroid Build Coastguard Worker      * parse camera information; this needs to be done before reading system
431*4d7e907cSAndroid Build Coastguard Worker      * information
432*4d7e907cSAndroid Build Coastguard Worker      */
433*4d7e907cSAndroid Build Coastguard Worker     readCameraInfo(rootElem->FirstChildElement("camera"));
434*4d7e907cSAndroid Build Coastguard Worker 
435*4d7e907cSAndroid Build Coastguard Worker     /* parse system information */
436*4d7e907cSAndroid Build Coastguard Worker     readSystemInfo(rootElem->FirstChildElement("system"));
437*4d7e907cSAndroid Build Coastguard Worker 
438*4d7e907cSAndroid Build Coastguard Worker     /* parse display information */
439*4d7e907cSAndroid Build Coastguard Worker     readDisplayInfo(rootElem->FirstChildElement("display"));
440*4d7e907cSAndroid Build Coastguard Worker 
441*4d7e907cSAndroid Build Coastguard Worker     const int64_t parsingEnd = android::elapsedRealtimeNano();
442*4d7e907cSAndroid Build Coastguard Worker     ALOGI("Parsing configuration file takes %lf (ms)",
443*4d7e907cSAndroid Build Coastguard Worker           (double)(parsingEnd - parsingStart) / 1000000.0);
444*4d7e907cSAndroid Build Coastguard Worker 
445*4d7e907cSAndroid Build Coastguard Worker     return true;
446*4d7e907cSAndroid Build Coastguard Worker }
447*4d7e907cSAndroid Build Coastguard Worker 
Create(const char * path)448*4d7e907cSAndroid Build Coastguard Worker std::unique_ptr<ConfigManager> ConfigManager::Create(const char* path) {
449*4d7e907cSAndroid Build Coastguard Worker     unique_ptr<ConfigManager> cfgMgr(new ConfigManager(path));
450*4d7e907cSAndroid Build Coastguard Worker 
451*4d7e907cSAndroid Build Coastguard Worker     /*
452*4d7e907cSAndroid Build Coastguard Worker      * Read a configuration from XML file
453*4d7e907cSAndroid Build Coastguard Worker      *
454*4d7e907cSAndroid Build Coastguard Worker      * If this is too slow, ConfigManager::readConfigDataFromBinary() and
455*4d7e907cSAndroid Build Coastguard Worker      * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object
456*4d7e907cSAndroid Build Coastguard Worker      * to the filesystem and construct CameraInfo instead; this was
457*4d7e907cSAndroid Build Coastguard Worker      * evaluated as 10x faster.
458*4d7e907cSAndroid Build Coastguard Worker      */
459*4d7e907cSAndroid Build Coastguard Worker     if (!cfgMgr->readConfigDataFromXML()) {
460*4d7e907cSAndroid Build Coastguard Worker         return nullptr;
461*4d7e907cSAndroid Build Coastguard Worker     } else {
462*4d7e907cSAndroid Build Coastguard Worker         return cfgMgr;
463*4d7e907cSAndroid Build Coastguard Worker     }
464*4d7e907cSAndroid Build Coastguard Worker }
465*4d7e907cSAndroid Build Coastguard Worker 
466*4d7e907cSAndroid Build Coastguard Worker }  // namespace android::hardware::automotive::evs::V1_1::implementation
467