Home | History | Annotate | Download | only in src
      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