Add tool for parsing camera config file in camera_V4L2
The three files are copied from arc-camera-service.
Only remove namespace and add constructor of SupportedFormat.
BUG=chromium:708396
TEST=test_that -b ${BOARD} ${IP} camera_V4L2
Change-Id: I3c9017289975358d8a61b3a329f0b0ebd5e68d10
Reviewed-on: https://chromium-review.googlesource.com/477734
Commit-Ready: Heng-ruey Hsu <henryhsu@google.com>
Tested-by: Heng-ruey Hsu <henryhsu@google.com>
Reviewed-by: Heng-ruey Hsu <henryhsu@google.com>
diff --git a/client/site_tests/camera_V4L2/src/Makefile b/client/site_tests/camera_V4L2/src/Makefile
index c44cc80..d3c88fa 100644
--- a/client/site_tests/camera_V4L2/src/Makefile
+++ b/client/site_tests/camera_V4L2/src/Makefile
@@ -2,20 +2,31 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-LDFLAGS = -lrt -ldl
+PKG_CONFIG ?= pkg-config
+DEP_LIBS = libchrome-$(BASE_VER)
+CXXFLAGS += $(shell $(PKG_CONFIG) --cflags $(DEP_LIBS))
-LDFLAGS_UNITTEST = -lrt
+LDFLAGS = -lrt -ldl -std=c++11
+LDFLAGS += $(shell $(PKG_CONFIG) --libs $(DEP_LIBS))
+
+LDFLAGS_UNITTEST = -lrt -std=c++11
+LDFLAGS_UNITTEST += $(shell $(PKG_CONFIG) --libs $(DEP_LIBS))
LDFLAGS_HELPER = -lrt
-SRC = media_v4l2_device.cc \
- media_v4l2_test.cc
+SRC = \
+ camera_characteristics.cc \
+ media_v4l2_device.cc \
+ media_v4l2_test.cc
-SRC_UNITTEST = media_v4l2_device.cc \
- media_v4l2_unittest.cc
+SRC_UNITTEST = \
+ camera_characteristics.cc \
+ media_v4l2_device.cc \
+ media_v4l2_unittest.cc
-SRC_HELPER = media_v4l2_device.cc \
- media_v4l2_is_capture_device.cc
+SRC_HELPER = \
+ media_v4l2_device.cc \
+ media_v4l2_is_capture_device.cc
TARGET = ../media_v4l2_test
diff --git a/client/site_tests/camera_V4L2/src/camera_characteristics.cc b/client/site_tests/camera_V4L2/src/camera_characteristics.cc
new file mode 100644
index 0000000..fa8eec0
--- /dev/null
+++ b/client/site_tests/camera_V4L2/src/camera_characteristics.cc
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "camera_characteristics.h"
+
+#include <ctype.h>
+
+#include <ios>
+#include <sstream>
+
+#include <base/files/file_util.h>
+#include <base/logging.h>
+
+// /etc/camera/camera_characteristics.conf contains camera information which
+// driver cannot provide.
+static const char kCameraCharacteristicsConfigFile[] =
+ "/etc/camera/camera_characteristics.conf";
+
+/* Common parameters */
+static const char kLensFacing[] = "lens_facing";
+static const char kSensorOrientation[] = "sensor_orientation";
+static const char kUsbVidPid[] = "usb_vid_pid";
+static const char kLensInfoAvailableFocalLengths[] =
+ "lens_info_available_focal_lengths";
+static const char kLensInfoMinimumFocusDistance[] =
+ "lens_info_minimum_focus_distance";
+static const char kLensInfoOptimalFocusDistance[] =
+ "lens_info_optimal_focus_distance";
+
+/* HAL v1 parameters */
+static const char kHorizontalViewAngle_16_9[] = "horizontal_view_angle_16_9";
+static const char kHorizontalViewAngle_4_3[] = "horizontal_view_angle_4_3";
+static const char kVerticalViewAngle_16_9[] = "vertical_view_angle_16_9";
+static const char kVerticalViewAngle_4_3[] = "vertical_view_angle_4_3";
+
+/* HAL v3 parameters */
+static const char kLensInfoAvailableApertures[] =
+ "lens_info_available_apertures";
+static const char kSensorInfoPhysicalSize[] = "sensor_info_physical_size";
+static const char kSensorInfoPixelArraySize[] = "sensor_info_pixel_array_size";
+
+/* Special parameters */
+static const char kFramesToSkipAfterStreamon[] =
+ "frames_to_skip_after_streamon";
+static const char kResolution1280x960Unsupported[] =
+ "resolution_1280x960_unsupported";
+static const char kConstantFramerateUnsupported[] =
+ "constant_framerate_unsupported";
+
+static const struct DeviceInfo kDefaultCharacteristics = {
+ "", // device_path
+ "", // usb_vid
+ "", // usb_pid
+ 0, // lens_facing
+ 0, // sensor_orientation
+ 0, // frames_to_skip_after_streamon
+ 66.5, // horizontal_view_angle_16_9
+ 0.0, // horizontal_view_angle_4_3
+ {1.6}, // lens_info_available_focal_lengths
+ 0.3, // lens_info_minimum_focus_distance
+ 0.5, // lens_info_optimal_focus_distance
+ 42.5, // vertical_view_angle_16_9
+ 0.0, // vertical_view_angle_4_3
+ false, // resolution_1280x960_unsupported
+ false // constant_framerate_unsupported
+};
+
+CameraCharacteristics::CameraCharacteristics() {
+}
+
+CameraCharacteristics::~CameraCharacteristics() {
+}
+
+const DeviceInfos CameraCharacteristics::GetCharacteristicsFromFile(
+ const std::unordered_map<std::string, std::string>& devices) {
+ const base::FilePath path(kCameraCharacteristicsConfigFile);
+ FILE* file = base::OpenFile(path, "r");
+ if (!file) {
+ LOG(ERROR) << __func__ << ": Can't open file "
+ << kCameraCharacteristicsConfigFile
+ << ". Use default characteristics instead";
+ DeviceInfos device_infos;
+ for (const auto& device : devices) {
+ device_infos.push_back(kDefaultCharacteristics);
+ size_t pos = device.first.find(":");
+ if (pos != std::string::npos) {
+ // If configuration file doesn't exist, the two attributes should be
+ // true.
+ device_infos.back().resolution_1280x960_unsupported = true;
+ device_infos.back().constant_framerate_unsupported = true;
+
+ device_infos.back().device_path = device.second;
+ device_infos.back().usb_vid = device.first.substr(0, pos - 1);
+ device_infos.back().usb_pid = device.first.substr(pos + 1);
+ } else {
+ LOG(ERROR) << __func__ << ": Invalid device: " << device.first;
+ }
+ }
+ return device_infos;
+ }
+
+ DeviceInfos tmp_device_infos;
+ char buffer[256], key[256], value[256];
+ uint32_t camera_id;
+ uint32_t module_id = -1;
+ std::string vid, pid;
+ while (fgets(buffer, sizeof(buffer), file)) {
+ // Skip comments and empty lines.
+ if (buffer[0] == '#' || buffer[0] == '\n') {
+ continue;
+ }
+
+ if (sscanf(buffer, "%[^=]=%s", key, value) != 2) {
+ LOG(ERROR) << __func__ << ": Illegal format: " << buffer;
+ continue;
+ }
+ std::vector<char*> sub_keys;
+ char* sub_key = strtok(key, ".");
+ while (sub_key) {
+ sub_keys.push_back(sub_key);
+ sub_key = strtok(NULL, ".");
+ }
+
+ if (sscanf(sub_keys[0], "camera%u", &camera_id) != 1) {
+ LOG(ERROR) << __func__ << ": Illegal format: " << sub_keys[0];
+ continue;
+ }
+ if (camera_id > tmp_device_infos.size()) {
+ // Camera id should be ascending by one.
+ LOG(ERROR) << __func__ << ": Invalid camera id: " << camera_id;
+ continue;
+ } else if (camera_id == tmp_device_infos.size()) {
+ tmp_device_infos.push_back(kDefaultCharacteristics);
+ }
+
+ uint32_t tmp_module_id;
+ // Convert value to lower case.
+ for (char* p = value; *p; ++p) *p = tolower(*p);
+
+ if (sscanf(sub_keys[1], "module%u", &tmp_module_id) != 1) {
+ AddPerCameraCharacteristic(
+ camera_id, sub_keys[1], value, &tmp_device_infos);
+ } else {
+ if (tmp_module_id != module_id) {
+ vid.clear();
+ pid.clear();
+ module_id = tmp_module_id;
+ }
+ if (strcmp(sub_keys[2], kUsbVidPid) == 0) {
+ char tmp_vid[256], tmp_pid[256];
+ if (sscanf(value, "%[0-9a-z]:%[0-9a-z]", tmp_vid, tmp_pid) != 2) {
+ LOG(ERROR) << __func__ << ": Invalid format: " << sub_keys[2];
+ continue;
+ }
+ vid = tmp_vid;
+ pid = tmp_pid;
+ const auto& device = devices.find(value);
+ if (device != devices.end()) {
+ tmp_device_infos[camera_id].usb_vid = vid;
+ tmp_device_infos[camera_id].usb_pid = pid;
+ tmp_device_infos[camera_id].device_path = device->second;
+ }
+
+ VLOG(1) << __func__ << ": Camera" << camera_id << " "
+ << kUsbVidPid << ": " << value;
+ } else if (!vid.empty() && !pid.empty()) {
+ // Some characteristics are module-specific, so only matched ones are
+ // selected.
+ if (tmp_device_infos[camera_id].usb_vid != vid ||
+ tmp_device_infos[camera_id].usb_pid != pid) {
+ VLOG(1) << __func__ << ": Mismatched module: "
+ << "vid: " << vid << " pid: " << pid;
+ continue;
+ }
+ AddPerModuleCharacteristic(
+ camera_id, sub_keys[2], value, &tmp_device_infos);
+ } else {
+ // Characteristic usb_vid_pid should come before other module-specific
+ // characteristics.
+ LOG(ERROR) << __func__ << ": Illegal format."
+ << " usb_vid_pid should come before: " << buffer;
+ }
+ }
+ }
+ base::CloseFile(file);
+
+ DeviceInfos device_infos;
+ // Some devices use the same camera_characteristics.conf and have different
+ // number of cameras.
+ for (size_t id = 0; id < tmp_device_infos.size(); ++id) {
+ if (tmp_device_infos[id].device_path.empty()) {
+ LOG(INFO) << __func__ << ": No matching module for camera" << id;
+ } else {
+ device_infos.push_back(tmp_device_infos[id]);
+ }
+ }
+ return device_infos;
+}
+
+void CameraCharacteristics::AddPerCameraCharacteristic(
+ uint32_t camera_id, const char* characteristic, const char* value,
+ DeviceInfos* device_infos) {
+ VLOG(1) << __func__ << ": " << characteristic << ": " << value;
+ if (strcmp(characteristic, kLensFacing) == 0) {
+ (*device_infos)[camera_id].lens_facing = strtol(value, NULL, 10);
+ } else if (strcmp(characteristic, kSensorOrientation) == 0) {
+ (*device_infos)[camera_id].sensor_orientation = strtol(value, NULL, 10);
+ } else if (strcmp(characteristic, kResolution1280x960Unsupported) == 0) {
+ std::istringstream is(value);
+ is >> std::boolalpha
+ >> (*device_infos)[camera_id].resolution_1280x960_unsupported;
+ } else if (strcmp(characteristic, kConstantFramerateUnsupported) == 0) {
+ std::istringstream is(value);
+ is >> std::boolalpha
+ >> (*device_infos)[camera_id].constant_framerate_unsupported;
+ } else {
+ LOG(ERROR) << __func__ << ": Unknown characteristic: " << characteristic
+ << " value: " << value;
+ }
+}
+
+void CameraCharacteristics::AddPerModuleCharacteristic(
+ uint32_t camera_id, const char* characteristic, const char* value,
+ DeviceInfos* device_infos) {
+ if (strcmp(characteristic, kFramesToSkipAfterStreamon) == 0) {
+ VLOG(1) << __func__ << ": " << characteristic << ": " << value;
+ (*device_infos)[camera_id].frames_to_skip_after_streamon =
+ strtol(value, NULL, 10);
+ } else if (strcmp(characteristic, kHorizontalViewAngle_16_9) == 0) {
+ AddFloatValue(value, kHorizontalViewAngle_16_9,
+ &(*device_infos)[camera_id].horizontal_view_angle_16_9);
+ } else if (strcmp(characteristic, kHorizontalViewAngle_4_3) == 0) {
+ AddFloatValue(value, kHorizontalViewAngle_4_3,
+ &(*device_infos)[camera_id].horizontal_view_angle_4_3);
+ } else if (strcmp(characteristic, kLensInfoAvailableFocalLengths) == 0) {
+ (*device_infos)[camera_id].lens_info_available_focal_lengths.clear();
+ char tmp_value[256];
+ strcpy(tmp_value, value);
+ char* focal_length = strtok(tmp_value, ",");
+ while (focal_length) {
+ float tmp_focal_length = strtof(focal_length, NULL);
+ if (tmp_focal_length != 0.0) {
+ VLOG(1) << __func__ << ": " << characteristic << ": "
+ << tmp_focal_length;
+ (*device_infos)[camera_id].lens_info_available_focal_lengths.push_back(
+ tmp_focal_length);
+ } else {
+ LOG(ERROR) << __func__ << ": Invalid " << characteristic << ": "
+ << value;
+ (*device_infos)[camera_id].lens_info_available_focal_lengths.clear();
+ (*device_infos)[camera_id].lens_info_available_focal_lengths.push_back(
+ kDefaultCharacteristics.lens_info_available_focal_lengths[0]);
+ break;
+ }
+ focal_length = strtok(NULL, ",");
+ }
+ } else if (strcmp(characteristic, kLensInfoMinimumFocusDistance) == 0) {
+ AddFloatValue(value, kLensInfoMinimumFocusDistance,
+ &(*device_infos)[camera_id].lens_info_minimum_focus_distance);
+ } else if (strcmp(characteristic, kLensInfoOptimalFocusDistance) == 0) {
+ AddFloatValue(value, kLensInfoOptimalFocusDistance,
+ &(*device_infos)[camera_id].lens_info_optimal_focus_distance);
+ } else if (strcmp(characteristic, kVerticalViewAngle_16_9) == 0) {
+ AddFloatValue(value, kVerticalViewAngle_16_9,
+ &(*device_infos)[camera_id].vertical_view_angle_16_9);
+ } else if (strcmp(characteristic, kVerticalViewAngle_4_3) == 0) {
+ AddFloatValue(value, kVerticalViewAngle_4_3,
+ &(*device_infos)[camera_id].vertical_view_angle_4_3);
+ } else if (strcmp(characteristic, kLensInfoAvailableApertures) == 0) {
+ /* Do nothing. This is for hal v3 */
+ } else if (strcmp(characteristic, kSensorInfoPhysicalSize) == 0) {
+ /* Do nothing. This is for hal v3 */
+ } else if (strcmp(characteristic, kSensorInfoPixelArraySize) == 0) {
+ /* Do nothing. This is for hal v3 */
+ } else {
+ LOG(ERROR) << __func__ << ": Unknown characteristic: " << characteristic
+ << " value: " << value;
+ }
+}
+
+void CameraCharacteristics::AddFloatValue(const char* value,
+ const char* characteristic_name,
+ float* characteristic) {
+ float tmp_value = strtof(value, NULL);
+ if (tmp_value != 0.0) {
+ VLOG(1) << __func__ << ": " << characteristic_name << ": " << value;
+ *characteristic = tmp_value;
+ } else {
+ LOG(ERROR) << __func__ << ": Invalid " << characteristic_name
+ << ": " << value;
+ }
+}
diff --git a/client/site_tests/camera_V4L2/src/camera_characteristics.h b/client/site_tests/camera_V4L2/src/camera_characteristics.h
new file mode 100644
index 0000000..3d2310b
--- /dev/null
+++ b/client/site_tests/camera_V4L2/src/camera_characteristics.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef CAMERA_CHARACTERISTICS_H_
+#define CAMERA_CHARACTERISTICS_H_
+
+#include "common_types.h"
+
+#include <unordered_map>
+
+#include <base/macros.h>
+
+// CameraCharacteristics reads the file /etc/camera/camera_characteristics.conf.
+// There are several assumptions of the config file:
+// 1. Each line should be at most 256 characters long.
+// 2. camera id should be in ascending order (i.e., 0, 1, 2, ...).
+// 3. usb_vid_pid should be the first subkey.
+// 4. All configs of a module should be put together.
+//
+// Example of the config file:
+// camera0.lens_facing=0
+// camera0.sensor_orientation=0
+// camera0.module0.usb_vid_pid=0123:4567
+// camera0.module0.horizontal_view_angle=68.4
+// camera0.module0.lens_info_available_focal_lengths=1.64
+// camera0.module0.lens_info_minimum_focus_distance=0.22
+// camera0.module0.lens_info_optimal_focus_distance=0.5
+// camera0.module0.vertical_view_angle=41.6
+// camera0.module1.usb_vid_pid=89ab:cdef
+// camera0.module1.lens_info_available_focal_lengths=1.69,2
+// camera1.lens_facing=1
+// camera1.sensor_orientation=180
+class CameraCharacteristics {
+ public:
+ CameraCharacteristics();
+ ~CameraCharacteristics();
+
+ // Parses /etc/camera/camera_characteristics.conf.
+ // Returns DeviceInfos with default characteristics if the config file doesn't
+ // exist.
+ const DeviceInfos GetCharacteristicsFromFile(
+ const std::unordered_map<std::string, std::string>& devices);
+
+ private:
+ void AddPerCameraCharacteristic(
+ uint32_t camera_id, const char* characteristic, const char* value,
+ DeviceInfos* device_infos);
+ void AddPerModuleCharacteristic(
+ uint32_t camera_id, const char* characteristic, const char* value,
+ DeviceInfos* device_infos);
+ void AddFloatValue(const char* value, const char* characteristic_name,
+ float* characteristic);
+
+ DISALLOW_COPY_AND_ASSIGN(CameraCharacteristics);
+};
+
+#endif // CAMERA_CHARACTERISTICS_H_
diff --git a/client/site_tests/camera_V4L2/src/common_types.h b/client/site_tests/camera_V4L2/src/common_types.h
new file mode 100644
index 0000000..f16d143
--- /dev/null
+++ b/client/site_tests/camera_V4L2/src/common_types.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef COMMON_TYPES_H_
+#define COMMON_TYPES_H_
+
+#include <string>
+#include <vector>
+
+// The types in this file should match Android camera HAL.
+
+struct DeviceInfo {
+ std::string device_path;
+ std::string usb_vid; // USB vender id
+ std::string usb_pid; // USB product id
+ uint32_t lens_facing; // Direction the camera faces relative to device screen.
+ // Clockwise angle through which the output image needs to be rotated to be
+ // upright on the device screen in its native orientation.
+ int32_t sensor_orientation;
+ uint32_t frames_to_skip_after_streamon;
+ float horizontal_view_angle_16_9;
+ float horizontal_view_angle_4_3;
+ std::vector<float> lens_info_available_focal_lengths;
+ float lens_info_minimum_focus_distance;
+ float lens_info_optimal_focus_distance;
+ float vertical_view_angle_16_9;
+ float vertical_view_angle_4_3;
+ // The camera doesn't support 1280x960 resolution when the maximum resolution
+ // of the camear is larger than 1080p.
+ bool resolution_1280x960_unsupported;
+ // The camera doesn't support constant frame rate. That means HAL cannot set
+ // V4L2_CID_EXPOSURE_AUTO_PRIORITY to 0 to have constant frame rate in low
+ // light environment.
+ bool constant_framerate_unsupported;
+};
+
+typedef std::vector<DeviceInfo> DeviceInfos;
+
+struct SupportedFormat {
+ SupportedFormat() {}
+ SupportedFormat(uint32_t w, uint32_t h, uint32_t fmt, uint32_t fps)
+ : width(w), height(h), fourcc(fmt) {
+ frame_rates.push_back(fps);
+ }
+ uint32_t width;
+ uint32_t height;
+ uint32_t fourcc;
+ // All the supported frame rates in fps with given width, height, and
+ // pixelformat. This is not sorted. For example, suppose width, height, and
+ // fourcc are 640x480 YUYV. If frameRates are 15.0 and 30.0, the camera
+ // supports outputting 640X480 YUYV in 15fps or 30fps.
+ std::vector<uint32_t> frame_rates;
+};
+
+typedef std::vector<SupportedFormat> SupportedFormats;
+
+#endif