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