summaryrefslogtreecommitdiff
path: root/src/cam/main.cpp
AgeCommit message (Expand)Author
2021-08-05cam: Add support for viewfinder through DRM/KMSLaurent Pinchart
2021-07-23cam: Initialize CamApp::loopUsers_Laurent Pinchart
2021-07-22cam: Support using multiple cameras concurrentlyLaurent Pinchart
2021-07-22cam: Add camera index to file name of capture framesLaurent Pinchart
2021-07-22cam: Make camera-related options sub-options of OptCameraLaurent Pinchart
2021-07-22cam: Allow specifying directories in the --file optionLaurent Pinchart
2021-07-22cam: Reorganize run() function and merge the two event loopsLaurent Pinchart
2021-07-22cam: Move session_ member variable to a local variable in run() functionLaurent Pinchart
2021-07-22cam: Move printing of camera information to CameraSession classLaurent Pinchart
2021-07-22cam: Move camera session creation and monitoring setup to run()Laurent Pinchart
2021-07-22cam: Make CamApp::cameraName() staticLaurent Pinchart
2021-07-22cam: Drop unneeded error check and messageLaurent Pinchart
2021-07-22cam: Use std::unique_ptr<> to manage CameraManagerLaurent Pinchart
2021-07-22cam: Move camera acquire to the CameraSession classLaurent Pinchart
2021-07-22cam: Move CameraConfiguration creation to CameraSession classLaurent Pinchart
2021-07-22cam: Store camera session pointer in CamApp classLaurent Pinchart
2021-07-22cam: Move event loop execution from CameraSession to CamAppLaurent Pinchart
2021-07-22cam: Move event loop exit from CameraSession to CamAppLaurent Pinchart
2021-07-22cam: camera_session: Access event loop through global instanceLaurent Pinchart
2021-07-22cam: Rename Capture to CameraSessionLaurent Pinchart
2021-05-06cam: Add option to print the Request metadataJacopo Mondi
2021-03-22cam: Do not assume Location is availableJacopo Mondi
2020-11-15cam: Use libevent to implement event loopLaurent Pinchart
2020-10-02cam: Print user-friendly camera namesNiklas Söderlund
2020-08-25meson: Remove -Wno-unused-parameterLaurent Pinchart
2020-08-10cam: Rename cameraName variableNiklas Söderlund
2020-08-05libcamera: camera: Rename name() to id()Niklas Söderlund
2020-08-05cam: Use the common cleanup function on failureNiklas Söderlund
2020-08-03cam: Add --monitor optionUmang Jain
2020-07-27cam: Add optional argument to --capture to specify how many frames to captureNiklas Söderlund
2020-07-27cam: capture: Cache the EventLoop handlerNiklas Söderlund
2020-07-27cam: Add option to disallow adjusting of requested formatsNiklas Söderlund
2020-05-01cam: Make use of StreamKeyValueParserNiklas Söderlund
2020-04-26cam: Add an option to list camera controlsLaurent Pinchart
2020-04-26cam: Rename OptProps to OptListPropertiesLaurent Pinchart
2020-03-27cam: Add option to capture StillCaptureRaw streamNiklas Söderlund
2020-03-24cam: main: Cache lookup of role propertyLaurent Pinchart
2020-03-20cam: Print one property per lineJacopo Mondi
2020-03-18libcamera: PixelFormat: Turn into a classNiklas Söderlund
2020-03-18libcamera: Use PixelFormat instead of unsigned int where appropriateNiklas Söderlund
2020-03-06cam: Add option to list camera propertiesJacopo Mondi
2019-11-20cam: Store camera as shared pointer everywhereNiklas Söderlund
2019-08-19libcamera: camera_manager: Construct CameraManager instances manuallyLaurent Pinchart
2019-06-19cam: Add --info option to print information about stream(s)Niklas Söderlund
2019-06-19cam: Validate camera configurationNiklas Söderlund
2019-06-19cam: Move camera configuration preparation to CamAppNiklas Söderlund
2019-06-18cam: Allow selecting cameras by indexLaurent Pinchart
2019-06-10cam: Fix cam --help crashNiklas Söderlund
2019-05-25cam: Add CamApp classNiklas Söderlund
2019-05-25cam: capture: Break out capture to a new classNiklas Söderlund
_GLIBCXX_RELEASE < 8 #include <experimental/filesystem> namespace std { namespace filesystem = std::experimental::filesystem; } #else #include <filesystem> #endif #include <stdio.h> #include <stdlib.h> #include <string> #include <yaml.h> #include <hardware/camera3.h> #include "libcamera/internal/log.h" using namespace libcamera; LOG_DEFINE_CATEGORY(HALConfig) class CameraHalConfig::Private : public Extensible::Private { LIBCAMERA_DECLARE_PUBLIC(CameraHalConfig) public: Private(CameraHalConfig *halConfig); int parseConfigFile(FILE *fh, std::map<std::string, CameraConfigData> *cameras); private: std::string parseValue(); std::string parseKey(); int parseValueBlock(); int parseCameraLocation(CameraConfigData *cameraConfigData, const std::string &location); int parseCameraConfigData(const std::string &cameraId); int parseCameras(); int parseEntry(); yaml_parser_t parser_; std::map<std::string, CameraConfigData> *cameras_; }; CameraHalConfig::Private::Private(CameraHalConfig *halConfig) : Extensible::Private(halConfig) { } std::string CameraHalConfig::Private::parseValue() { yaml_token_t token; /* Make sure the token type is a value and get its content. */ yaml_parser_scan(&parser_, &token); if (token.type != YAML_VALUE_TOKEN) { yaml_token_delete(&token); return ""; } yaml_token_delete(&token); yaml_parser_scan(&parser_, &token); if (token.type != YAML_SCALAR_TOKEN) { yaml_token_delete(&token); return ""; } std::string value(reinterpret_cast<char *>(token.data.scalar.value), token.data.scalar.length); yaml_token_delete(&token); return value; } std::string CameraHalConfig::Private::parseKey() { yaml_token_t token; /* Make sure the token type is a key and get its value. */ yaml_parser_scan(&parser_, &token); if (token.type != YAML_SCALAR_TOKEN) { yaml_token_delete(&token); return ""; } std::string value(reinterpret_cast<char *>(token.data.scalar.value), token.data.scalar.length); yaml_token_delete(&token); return value; } int CameraHalConfig::Private::parseValueBlock() { yaml_token_t token; /* Make sure the next token are VALUE and BLOCK_MAPPING_START. */ yaml_parser_scan(&parser_, &token); if (token.type != YAML_VALUE_TOKEN) { yaml_token_delete(&token); return -EINVAL; } yaml_token_delete(&token); yaml_parser_scan(&parser_, &token); if (token.type != YAML_BLOCK_MAPPING_START_TOKEN) { yaml_token_delete(&token); return -EINVAL; } yaml_token_delete(&token); return 0; } int CameraHalConfig::Private::parseCameraLocation(CameraConfigData *cameraConfigData, const std::string &location) { if (location == "front") cameraConfigData->facing = CAMERA_FACING_FRONT; else if (location == "back") cameraConfigData->facing = CAMERA_FACING_BACK; else if (location == "external") cameraConfigData->facing = CAMERA_FACING_EXTERNAL; else return -EINVAL; return 0; } int CameraHalConfig::Private::parseCameraConfigData(const std::string &cameraId) { int ret = parseValueBlock(); if (ret) return ret; /* * Parse the camera properties and store them in a cameraConfigData * instance. * * Add a safety counter to make sure we don't loop indefinitely in case * the configuration file is malformed. */ CameraConfigData cameraConfigData; unsigned int sentinel = 100; bool blockEnd = false; yaml_token_t token; do { yaml_parser_scan(&parser_, &token); switch (token.type) { case YAML_KEY_TOKEN: { yaml_token_delete(&token); /* * Parse the camera property key and make sure it is * valid. */ std::string key = parseKey(); std::string value = parseValue(); if (key.empty() || value.empty()) return -EINVAL; if (key == "location") { ret = parseCameraLocation(&cameraConfigData, value); if (ret) { LOG(HALConfig, Error) << "Unknown location: " << value; return -EINVAL; } } else if (key == "rotation") { ret = std::stoi(value); if (ret < 0 || ret >= 360) { LOG(HALConfig, Error) << "Unknown rotation: " << value; return -EINVAL; } cameraConfigData.rotation = ret; } else { LOG(HALConfig, Error) << "Unknown key: " << key; return -EINVAL; } break; } case YAML_BLOCK_END_TOKEN: blockEnd = true; [[fallthrough]]; default: yaml_token_delete(&token); break; } --sentinel; } while (!blockEnd && sentinel); if (!sentinel) return -EINVAL; (*cameras_)[cameraId] = cameraConfigData; return 0; } int CameraHalConfig::Private::parseCameras() { int ret = parseValueBlock(); if (ret) { LOG(HALConfig, Error) << "Configuration file is not valid"; return ret; } /* * Parse the camera 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": * key: value * key: value * ... * * "camera1 id": * key: value * key: value * ... */ bool blockEnd = false; yaml_token_t token; do { yaml_parser_scan(&parser_, &token); switch (token.type) { case YAML_KEY_TOKEN: { yaml_token_delete(&token); /* Parse the camera ID as key of the property list. */ std::string cameraId = parseKey(); if (cameraId.empty()) return -EINVAL; ret = parseCameraConfigData(cameraId); if (ret) return -EINVAL; break; } case YAML_BLOCK_END_TOKEN: blockEnd = true; [[fallthrough]]; default: yaml_token_delete(&token); break; } } while (!blockEnd); return 0; } int CameraHalConfig::Private::parseEntry() { int ret = -EINVAL; /* * Parse each key we find in the file. * * The 'cameras' keys maps to a list of (lists) of camera properties. */ std::string key = parseKey(); if (key.empty()) return ret; if (key == "cameras") ret = parseCameras(); else LOG(HALConfig, Error) << "Unknown key: " << key; return ret; } int CameraHalConfig::Private::parseConfigFile(FILE *fh, std::map<std::string, CameraConfigData> *cameras) { cameras_ = cameras; int ret = yaml_parser_initialize(&parser_); if (!ret) { LOG(HALConfig, Error) << "Failed to initialize yaml parser"; return -EINVAL; } yaml_parser_set_input_file(&parser_, fh); yaml_token_t token; yaml_parser_scan(&parser_, &token); if (token.type != YAML_STREAM_START_TOKEN) { LOG(HALConfig, Error) << "Configuration file is not valid"; yaml_token_delete(&token); yaml_parser_delete(&parser_); return -EINVAL; } yaml_token_delete(&token); yaml_parser_scan(&parser_, &token); if (token.type != YAML_BLOCK_MAPPING_START_TOKEN) { LOG(HALConfig, Error) << "Configuration file is not valid"; yaml_token_delete(&token); yaml_parser_delete(&parser_); return -EINVAL; } yaml_token_delete(&token); /* Parse the file and parse each single key one by one. */ do { yaml_parser_scan(&parser_, &token); switch (token.type) { case YAML_KEY_TOKEN: yaml_token_delete(&token); ret = parseEntry(); break; case YAML_STREAM_END_TOKEN: ret = -ENOENT; [[fallthrough]]; default: yaml_token_delete(&token); break; } } while (ret >= 0); yaml_parser_delete(&parser_); if (ret && ret != -ENOENT) LOG(HALConfig, Error) << "Configuration file is not valid"; return ret == -ENOENT ? 0 : ret; } CameraHalConfig::CameraHalConfig() : Extensible(new Private(this)), 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::filesystem::path filePath = LIBCAMERA_SYSCONF_DIR; filePath /= "camera_hal.yaml"; if (!std::filesystem::is_regular_file(filePath)) { LOG(HALConfig, Debug) << "Configuration file: \"" << filePath << "\" not found"; return -ENOENT; } FILE *fh = fopen(filePath.c_str(), "r"); if (!fh) { int ret = -errno; LOG(HALConfig, Error) << "Failed to open configuration file " << filePath << ": " << strerror(-ret); return ret; } exists_ = true; Private *const d = LIBCAMERA_D_PTR(); int ret = d->parseConfigFile(fh, &cameras_); fclose(fh); 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; }