| /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
| /* |
| * Copyright (C) 2021, Google Inc. |
| * |
| * camera_hal_config.cpp - Camera HAL configuration file manager |
| */ |
| #include "camera_hal_config.h" |
| |
| #include <stdlib.h> |
| #include <string> |
| |
| #include <libcamera/base/file.h> |
| #include <libcamera/base/log.h> |
| |
| #include "libcamera/internal/yaml_parser.h" |
| |
| #include <hardware/camera3.h> |
| |
| using namespace libcamera; |
| |
| LOG_DEFINE_CATEGORY(HALConfig) |
| |
| class CameraHalConfig::Private : public Extensible::Private |
| { |
| LIBCAMERA_DECLARE_PUBLIC(CameraHalConfig) |
| |
| public: |
| Private(); |
| |
| int parseConfigFile(File &file, std::map<std::string, CameraConfigData> *cameras); |
| |
| private: |
| int parseCameraConfigData(const std::string &cameraId, const YamlObject &); |
| int parseLocation(const YamlObject &, CameraConfigData &cameraConfigData); |
| int parseRotation(const YamlObject &, CameraConfigData &cameraConfigData); |
| |
| std::map<std::string, CameraConfigData> *cameras_; |
| }; |
| |
| CameraHalConfig::Private::Private() |
| { |
| } |
| |
| int CameraHalConfig::Private::parseConfigFile(File &file, |
| std::map<std::string, CameraConfigData> *cameras) |
| { |
| /* |
| * Parse the HAL properties. |
| * |
| * Each camera properties block is a list of properties associated |
| * with the ID (as assembled by CameraSensor::generateId()) of the |
| * camera they refer to. |
| * |
| * cameras: |
| * "camera0 id": |
| * location: value |
| * rotation: value |
| * ... |
| * |
| * "camera1 id": |
| * location: value |
| * rotation: value |
| * ... |
| */ |
| |
| cameras_ = cameras; |
| |
| std::unique_ptr<YamlObject> root = YamlParser::parse(file); |
| if (!root) |
| return -EINVAL; |
| |
| if (!root->isDictionary()) |
| return -EINVAL; |
| |
| /* Parse property "cameras" */ |
| if (!root->contains("cameras")) |
| return -EINVAL; |
| |
| const YamlObject &yamlObjectCameras = (*root)["cameras"]; |
| |
| if (!yamlObjectCameras.isDictionary()) |
| return -EINVAL; |
| |
| for (const auto &[cameraId, configData] : yamlObjectCameras.asDict()) { |
| if (parseCameraConfigData(cameraId, configData)) |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| int CameraHalConfig::Private::parseCameraConfigData(const std::string &cameraId, |
| const YamlObject &cameraObject) |
| |
| { |
| if (!cameraObject.isDictionary()) |
| return -EINVAL; |
| |
| CameraConfigData &cameraConfigData = (*cameras_)[cameraId]; |
| |
| /* Parse property "location" */ |
| if (parseLocation(cameraObject, cameraConfigData)) |
| return -EINVAL; |
| |
| /* Parse property "rotation" */ |
| if (parseRotation(cameraObject, cameraConfigData)) |
| return -EINVAL; |
| |
| return 0; |
| } |
| |
| int CameraHalConfig::Private::parseLocation(const YamlObject &cameraObject, |
| CameraConfigData &cameraConfigData) |
| { |
| if (!cameraObject.contains("location")) |
| return -EINVAL; |
| |
| std::string location = cameraObject["location"].get<std::string>(""); |
| |
| if (location == "front") |
| cameraConfigData.facing = CAMERA_FACING_FRONT; |
| else if (location == "back") |
| cameraConfigData.facing = CAMERA_FACING_BACK; |
| else |
| return -EINVAL; |
| |
| return 0; |
| } |
| |
| int CameraHalConfig::Private::parseRotation(const YamlObject &cameraObject, |
| CameraConfigData &cameraConfigData) |
| { |
| if (!cameraObject.contains("rotation")) |
| return -EINVAL; |
| |
| int32_t rotation = cameraObject["rotation"].get<int32_t>(-1); |
| |
| if (rotation < 0 || rotation >= 360) { |
| LOG(HALConfig, Error) |
| << "Unknown rotation: " << rotation; |
| return -EINVAL; |
| } |
| |
| cameraConfigData.rotation = rotation; |
| return 0; |
| } |
| |
| CameraHalConfig::CameraHalConfig() |
| : Extensible(std::make_unique<Private>()), exists_(false), valid_(false) |
| { |
| parseConfigurationFile(); |
| } |
| |
| /* |
| * Open the HAL configuration file and validate its content. |
| * Return 0 on success, a negative error code otherwise |
| * retval -ENOENT The configuration file is not available |
| * retval -EINVAL The configuration file is available but not valid |
| */ |
| int CameraHalConfig::parseConfigurationFile() |
| { |
| std::string filePath = LIBCAMERA_SYSCONF_DIR "/camera_hal.yaml"; |
| |
| File file(filePath); |
| if (!file.exists()) { |
| LOG(HALConfig, Debug) |
| << "Configuration file: \"" << filePath << "\" not found"; |
| return -ENOENT; |
| } |
| |
| if (!file.open(File::OpenModeFlag::ReadOnly)) { |
| int ret = file.error(); |
| LOG(HALConfig, Error) << "Failed to open configuration file " |
| << filePath << ": " << strerror(-ret); |
| return ret; |
| } |
| |
| exists_ = true; |
| |
| int ret = _d()->parseConfigFile(file, &cameras_); |
| if (ret) |
| return -EINVAL; |
| |
| valid_ = true; |
| |
| for (const auto &c : cameras_) { |
| const std::string &cameraId = c.first; |
| const CameraConfigData &camera = c.second; |
| LOG(HALConfig, Debug) << "'" << cameraId << "' " |
| << "(" << camera.facing << ")[" |
| << camera.rotation << "]"; |
| } |
| |
| return 0; |
| } |
| |
| const CameraConfigData *CameraHalConfig::cameraConfigData(const std::string &cameraId) const |
| { |
| const auto &it = cameras_.find(cameraId); |
| if (it == cameras_.end()) { |
| LOG(HALConfig, Error) |
| << "Camera '" << cameraId |
| << "' not described in the HAL configuration file"; |
| return nullptr; |
| } |
| |
| return &it->second; |
| } |