1 /*
2 * Copyright 2016 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7 #include "camera_characteristics.h"
8
9 #include <ctype.h>
10
11 #include <ios>
12 #include <sstream>
13
14 #include <base/files/file_util.h>
15 #include <base/logging.h>
16
17 // /etc/camera/camera_characteristics.conf contains camera information which
18 // driver cannot provide.
19 static const char kCameraCharacteristicsConfigFile[] =
20 "/etc/camera/camera_characteristics.conf";
21
22 /* Common parameters */
23 static const char kLensFacing[] = "lens_facing";
24 static const char kSensorOrientation[] = "sensor_orientation";
25 static const char kUsbVidPid[] = "usb_vid_pid";
26 static const char kLensInfoAvailableFocalLengths[] =
27 "lens_info_available_focal_lengths";
28 static const char kLensInfoMinimumFocusDistance[] =
29 "lens_info_minimum_focus_distance";
30 static const char kLensInfoOptimalFocusDistance[] =
31 "lens_info_optimal_focus_distance";
32
33 /* HAL v1 parameters */
34 static const char kHorizontalViewAngle_16_9[] = "horizontal_view_angle_16_9";
35 static const char kHorizontalViewAngle_4_3[] = "horizontal_view_angle_4_3";
36 static const char kVerticalViewAngle_16_9[] = "vertical_view_angle_16_9";
37 static const char kVerticalViewAngle_4_3[] = "vertical_view_angle_4_3";
38
39 /* HAL v3 parameters */
40 static const char kLensInfoAvailableApertures[] =
41 "lens_info_available_apertures";
42 static const char kSensorInfoPhysicalSize[] = "sensor_info_physical_size";
43 static const char kSensorInfoPixelArraySize[] = "sensor_info_pixel_array_size";
44
45 /* Special parameters */
46 static const char kFramesToSkipAfterStreamon[] =
47 "frames_to_skip_after_streamon";
48 static const char kResolution1280x960Unsupported[] =
49 "resolution_1280x960_unsupported";
50 static const char kResolution1600x1200Unsupported[] =
51 "resolution_1600x1200_unsupported";
52 static const char kConstantFramerateUnsupported[] =
53 "constant_framerate_unsupported";
54
55 static const struct DeviceInfo kDefaultCharacteristics = {
56 "", // device_path
57 "", // usb_vid
58 "", // usb_pid
59 0, // lens_facing
60 0, // sensor_orientation
61 0, // frames_to_skip_after_streamon
62 66.5, // horizontal_view_angle_16_9
63 0.0, // horizontal_view_angle_4_3
64 {1.6}, // lens_info_available_focal_lengths
65 0.3, // lens_info_minimum_focus_distance
66 0.5, // lens_info_optimal_focus_distance
67 42.5, // vertical_view_angle_16_9
68 0.0, // vertical_view_angle_4_3
69 false, // resolution_1280x960_unsupported
70 false, // resolution_1600x1200_unsupported
71 false, // constant_framerate_unsupported
72 0, // sensor_info_pixel_array_size_width
73 0 // sensor_info_pixel_array_size_height
74 };
75
CameraCharacteristics()76 CameraCharacteristics::CameraCharacteristics() {
77 }
78
~CameraCharacteristics()79 CameraCharacteristics::~CameraCharacteristics() {
80 }
81
GetCharacteristicsFromFile(const std::unordered_map<std::string,std::string> & devices)82 const DeviceInfos CameraCharacteristics::GetCharacteristicsFromFile(
83 const std::unordered_map<std::string, std::string>& devices) {
84 const base::FilePath path(kCameraCharacteristicsConfigFile);
85 FILE* file = base::OpenFile(path, "r");
86 if (!file) {
87 LOG(INFO) << __func__ << ": Can't open file "
88 << kCameraCharacteristicsConfigFile;
89 return DeviceInfos();
90 }
91
92 DeviceInfos tmp_device_infos;
93 char buffer[256], key[256], value[256];
94 uint32_t camera_id;
95 uint32_t module_id = -1;
96 std::string vid, pid;
97 while (fgets(buffer, sizeof(buffer), file)) {
98 // Skip comments and empty lines.
99 if (buffer[0] == '#' || buffer[0] == '\n') {
100 continue;
101 }
102
103 if (sscanf(buffer, "%[^=]=%s", key, value) != 2) {
104 LOG(ERROR) << __func__ << ": Illegal format: " << buffer;
105 continue;
106 }
107 std::vector<char*> sub_keys;
108 char* sub_key = strtok(key, ".");
109 while (sub_key) {
110 sub_keys.push_back(sub_key);
111 sub_key = strtok(NULL, ".");
112 }
113
114 if (sscanf(sub_keys[0], "camera%u", &camera_id) != 1) {
115 LOG(ERROR) << __func__ << ": Illegal format: " << sub_keys[0];
116 continue;
117 }
118 if (camera_id > tmp_device_infos.size()) {
119 // Camera id should be ascending by one.
120 LOG(ERROR) << __func__ << ": Invalid camera id: " << camera_id;
121 continue;
122 } else if (camera_id == tmp_device_infos.size()) {
123 tmp_device_infos.push_back(kDefaultCharacteristics);
124 }
125
126 uint32_t tmp_module_id;
127 // Convert value to lower case.
128 for (char* p = value; *p; ++p) *p = tolower(*p);
129
130 if (sscanf(sub_keys[1], "module%u", &tmp_module_id) != 1) {
131 AddPerCameraCharacteristic(
132 camera_id, sub_keys[1], value, &tmp_device_infos);
133 } else {
134 if (tmp_module_id != module_id) {
135 vid.clear();
136 pid.clear();
137 module_id = tmp_module_id;
138 }
139 if (strcmp(sub_keys[2], kUsbVidPid) == 0) {
140 char tmp_vid[256], tmp_pid[256];
141 if (sscanf(value, "%[0-9a-z]:%[0-9a-z]", tmp_vid, tmp_pid) != 2) {
142 LOG(ERROR) << __func__ << ": Invalid format: " << sub_keys[2];
143 continue;
144 }
145 vid = tmp_vid;
146 pid = tmp_pid;
147 const auto& device = devices.find(value);
148 if (device != devices.end()) {
149 tmp_device_infos[camera_id].usb_vid = vid;
150 tmp_device_infos[camera_id].usb_pid = pid;
151 tmp_device_infos[camera_id].device_path = device->second;
152 }
153
154 VLOG(1) << __func__ << ": Camera" << camera_id << " "
155 << kUsbVidPid << ": " << value;
156 } else if (!vid.empty() && !pid.empty()) {
157 // Some characteristics are module-specific, so only matched ones are
158 // selected.
159 if (tmp_device_infos[camera_id].usb_vid != vid ||
160 tmp_device_infos[camera_id].usb_pid != pid) {
161 VLOG(1) << __func__ << ": Mismatched module: "
162 << "vid: " << vid << " pid: " << pid;
163 continue;
164 }
165 AddPerModuleCharacteristic(
166 camera_id, sub_keys[2], value, &tmp_device_infos);
167 } else {
168 // Characteristic usb_vid_pid should come before other module-specific
169 // characteristics.
170 LOG(ERROR) << __func__ << ": Illegal format."
171 << " usb_vid_pid should come before: " << buffer;
172 }
173 }
174 }
175 base::CloseFile(file);
176
177 DeviceInfos device_infos;
178 // Some devices use the same camera_characteristics.conf and have different
179 // number of cameras.
180 for (size_t id = 0; id < tmp_device_infos.size(); ++id) {
181 if (tmp_device_infos[id].device_path.empty()) {
182 LOG(INFO) << __func__ << ": No matching module for camera" << id;
183 } else {
184 device_infos.push_back(tmp_device_infos[id]);
185 }
186 }
187
188 // Check sensor array size to decide supported resolutions.
189 for (size_t id = 0; id < device_infos.size(); ++id) {
190 if (device_infos[id].sensor_info_pixel_array_size_width < 1280 ||
191 device_infos[id].sensor_info_pixel_array_size_height < 960) {
192 device_infos[id].resolution_1280x960_unsupported = true;
193 }
194 if (device_infos[id].sensor_info_pixel_array_size_width < 1600 ||
195 device_infos[id].sensor_info_pixel_array_size_height < 1200) {
196 device_infos[id].resolution_1600x1200_unsupported = true;
197 }
198 }
199 return device_infos;
200 }
201
AddPerCameraCharacteristic(uint32_t camera_id,const char * characteristic,const char * value,DeviceInfos * device_infos)202 void CameraCharacteristics::AddPerCameraCharacteristic(
203 uint32_t camera_id, const char* characteristic, const char* value,
204 DeviceInfos* device_infos) {
205 VLOG(1) << __func__ << ": " << characteristic << ": " << value;
206 if (strcmp(characteristic, kLensFacing) == 0) {
207 (*device_infos)[camera_id].lens_facing = strtol(value, NULL, 10);
208 } else if (strcmp(characteristic, kSensorOrientation) == 0) {
209 (*device_infos)[camera_id].sensor_orientation = strtol(value, NULL, 10);
210 } else {
211 LOG(ERROR) << __func__ << ": Unknown characteristic: " << characteristic
212 << " value: " << value;
213 }
214 }
215
AddPerModuleCharacteristic(uint32_t camera_id,const char * characteristic,const char * value,DeviceInfos * device_infos)216 void CameraCharacteristics::AddPerModuleCharacteristic(
217 uint32_t camera_id, const char* characteristic, const char* value,
218 DeviceInfos* device_infos) {
219 if (strcmp(characteristic, kFramesToSkipAfterStreamon) == 0) {
220 VLOG(1) << __func__ << ": " << characteristic << ": " << value;
221 (*device_infos)[camera_id].frames_to_skip_after_streamon =
222 strtol(value, NULL, 10);
223 } else if (strcmp(characteristic, kHorizontalViewAngle_16_9) == 0) {
224 AddFloatValue(value, kHorizontalViewAngle_16_9,
225 &(*device_infos)[camera_id].horizontal_view_angle_16_9);
226 } else if (strcmp(characteristic, kHorizontalViewAngle_4_3) == 0) {
227 AddFloatValue(value, kHorizontalViewAngle_4_3,
228 &(*device_infos)[camera_id].horizontal_view_angle_4_3);
229 } else if (strcmp(characteristic, kLensInfoAvailableFocalLengths) == 0) {
230 (*device_infos)[camera_id].lens_info_available_focal_lengths.clear();
231 char tmp_value[256];
232 strcpy(tmp_value, value);
233 char* focal_length = strtok(tmp_value, ",");
234 while (focal_length) {
235 float tmp_focal_length = strtof(focal_length, NULL);
236 if (tmp_focal_length != 0.0) {
237 VLOG(1) << __func__ << ": " << characteristic << ": "
238 << tmp_focal_length;
239 (*device_infos)[camera_id].lens_info_available_focal_lengths.push_back(
240 tmp_focal_length);
241 } else {
242 LOG(ERROR) << __func__ << ": Invalid " << characteristic << ": "
243 << value;
244 (*device_infos)[camera_id].lens_info_available_focal_lengths.clear();
245 (*device_infos)[camera_id].lens_info_available_focal_lengths.push_back(
246 kDefaultCharacteristics.lens_info_available_focal_lengths[0]);
247 break;
248 }
249 focal_length = strtok(NULL, ",");
250 }
251 } else if (strcmp(characteristic, kLensInfoMinimumFocusDistance) == 0) {
252 AddFloatValue(value, kLensInfoMinimumFocusDistance,
253 &(*device_infos)[camera_id].lens_info_minimum_focus_distance);
254 } else if (strcmp(characteristic, kLensInfoOptimalFocusDistance) == 0) {
255 AddFloatValue(value, kLensInfoOptimalFocusDistance,
256 &(*device_infos)[camera_id].lens_info_optimal_focus_distance);
257 } else if (strcmp(characteristic, kVerticalViewAngle_16_9) == 0) {
258 AddFloatValue(value, kVerticalViewAngle_16_9,
259 &(*device_infos)[camera_id].vertical_view_angle_16_9);
260 } else if (strcmp(characteristic, kVerticalViewAngle_4_3) == 0) {
261 AddFloatValue(value, kVerticalViewAngle_4_3,
262 &(*device_infos)[camera_id].vertical_view_angle_4_3);
263 } else if (strcmp(characteristic, kLensInfoAvailableApertures) == 0) {
264 /* Do nothing. This is for hal v3 */
265 } else if (strcmp(characteristic, kSensorInfoPhysicalSize) == 0) {
266 /* Do nothing. This is for hal v3 */
267 } else if (strcmp(characteristic, kSensorInfoPixelArraySize) == 0) {
268 int width, height;
269 if (sscanf(value, "%dx%d", &width, &height) != 2) {
270 LOG(ERROR) << __func__ << ": Illegal array size format: " << value;
271 return;
272 }
273 VLOG(1) << __func__ << ": " << characteristic << ": " << width
274 << "x" << height;
275 (*device_infos)[camera_id].sensor_info_pixel_array_size_width = width;
276 (*device_infos)[camera_id].sensor_info_pixel_array_size_height = height;
277 } else if (strcmp(characteristic, kResolution1280x960Unsupported) == 0) {
278 VLOG(1) << __func__ << ": " << characteristic << ": " << value;
279 std::istringstream is(value);
280 is >> std::boolalpha
281 >> (*device_infos)[camera_id].resolution_1280x960_unsupported;
282 } else if (strcmp(characteristic, kResolution1600x1200Unsupported) == 0) {
283 VLOG(1) << __func__ << ": " << characteristic << ": " << value;
284 std::istringstream is(value);
285 is >> std::boolalpha
286 >> (*device_infos)[camera_id].resolution_1600x1200_unsupported;
287 } else if (strcmp(characteristic, kConstantFramerateUnsupported) == 0) {
288 VLOG(1) << __func__ << ": " << characteristic << ": " << value;
289 std::istringstream is(value);
290 is >> std::boolalpha
291 >> (*device_infos)[camera_id].constant_framerate_unsupported;
292 } else {
293 LOG(ERROR) << __func__ << ": Unknown characteristic: " << characteristic
294 << " value: " << value;
295 }
296 }
297
AddFloatValue(const char * value,const char * characteristic_name,float * characteristic)298 void CameraCharacteristics::AddFloatValue(const char* value,
299 const char* characteristic_name,
300 float* characteristic) {
301 float tmp_value = strtof(value, NULL);
302 if (tmp_value != 0.0) {
303 VLOG(1) << __func__ << ": " << characteristic_name << ": " << value;
304 *characteristic = tmp_value;
305 } else {
306 LOG(ERROR) << __func__ << ": Invalid " << characteristic_name
307 << ": " << value;
308 }
309 }
310