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 76 CameraCharacteristics::CameraCharacteristics() { 77 } 78 79 CameraCharacteristics::~CameraCharacteristics() { 80 } 81 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 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 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 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