From 1accca05b5027ec30c5d6dbfea89a51fdcd1b969 Mon Sep 17 00:00:00 2001 From: Paul Elder Date: Tue, 1 Oct 2024 02:09:07 +0900 Subject: apps: cam: Add support for loading configuration from capture script Add support to the cam application for loading the camera configuration from a capture script. These are not expected to be written by hand, but rather dumped via the LIBCAMERA_DUMP_CAPTURE_SCRIPT environment variable. If any configuration options are specified by command line parameters, those will take precedence. Signed-off-by: Paul Elder --- src/apps/cam/camera_session.cpp | 22 +++--- src/apps/cam/capture_script.cpp | 164 ++++++++++++++++++++++++++++++++++++++++ src/apps/cam/capture_script.h | 8 ++ 3 files changed, 184 insertions(+), 10 deletions(-) diff --git a/src/apps/cam/camera_session.cpp b/src/apps/cam/camera_session.cpp index edc49b87..6f1d8b58 100644 --- a/src/apps/cam/camera_session.cpp +++ b/src/apps/cam/camera_session.cpp @@ -70,6 +70,18 @@ CameraSession::CameraSession(CameraManager *cm, return; } + if (options_.isSet(OptCaptureScript)) { + std::string scriptName = options_[OptCaptureScript].toString(); + script_ = std::make_unique(camera_, scriptName); + if (!script_->valid()) { + std::cerr << "Invalid capture script '" << scriptName + << "'" << std::endl; + return; + } + + script_->populateConfiguration(config.get()); + } + if (options_.isSet(OptOrientation)) { std::string orientOpt = options_[OptOrientation].toString(); static const std::map orientations{ @@ -119,16 +131,6 @@ CameraSession::CameraSession(CameraManager *cm, } #endif - if (options_.isSet(OptCaptureScript)) { - std::string scriptName = options_[OptCaptureScript].toString(); - script_ = std::make_unique(camera_, scriptName); - if (!script_->valid()) { - std::cerr << "Invalid capture script '" << scriptName - << "'" << std::endl; - return; - } - } - switch (config->validate()) { case CameraConfiguration::Valid: break; diff --git a/src/apps/cam/capture_script.cpp b/src/apps/cam/capture_script.cpp index fc1dfa75..7f166f45 100644 --- a/src/apps/cam/capture_script.cpp +++ b/src/apps/cam/capture_script.cpp @@ -7,6 +7,7 @@ #include "capture_script.h" +#include #include #include #include @@ -162,6 +163,10 @@ int CaptureScript::parseScript(FILE *script) ret = parseFrames(); if (ret) return ret; + } else if (section == "configuration") { + ret = parseConfiguration(); + if (ret) + return ret; } else { std::cerr << "Unsupported section '" << section << "'" << std::endl; @@ -322,6 +327,165 @@ int CaptureScript::parseControl(EventPtr event, ControlList &controls) return 0; } +int CaptureScript::parseOrientation(EventPtr event) +{ + static const std::map orientations{ + { "Rotate0", libcamera::Orientation::Rotate0 }, + { "Rotate0Mirror", libcamera::Orientation::Rotate0Mirror }, + { "Rotate180", libcamera::Orientation::Rotate180 }, + { "Rotate180Mirror", libcamera::Orientation::Rotate180Mirror }, + { "Rotate90Mirror", libcamera::Orientation::Rotate90Mirror }, + { "Rotate270", libcamera::Orientation::Rotate270 }, + { "Rotate270Mirror", libcamera::Orientation::Rotate270Mirror }, + { "Rotate90", libcamera::Orientation::Rotate90 }, + }; + + std::string orientation = eventScalarValue(event); + + auto it = orientations.find(orientation); + if (it == orientations.end()) { + std::cerr << "Invalid orientation '" << orientation + << "' in capture script" << std::endl; + return -EINVAL; + } + + orientation_ = it->second; + + return 0; +} + +int CaptureScript::parseStream(EventPtr event, unsigned int index) +{ + if (!checkEvent(event, YAML_MAPPING_START_EVENT)) + return -EINVAL; + + StreamConfiguration config; + while (1) { + event = nextEvent(); + if (!event) + return -EINVAL; + if (event->type == YAML_MAPPING_END_EVENT) + break; + + std::string key = eventScalarValue(event); + + event = nextEvent(); + if (!event) + return -EINVAL; + if (event->type == YAML_MAPPING_END_EVENT) + break; + + std::string value = eventScalarValue(event); + + if (key == "pixelFormat") { + config.pixelFormat = libcamera::PixelFormat::fromString(value); + } else if (key == "size") { + unsigned int split = value.find("x"); + if (split == std::string::npos) { + std::cerr << "Invalid size '" << value + << "' in stream configuration " + << index << std::endl; + } + + std::string width = value.substr(0, split); + std::string height = value.substr(split + 1); + config.size = Size(std::stoi(width), std::stoi(height)); + } else if (key == "stride") { + config.stride = std::stoi(value); + } else if (key == "frameSize") { + config.frameSize = std::stoi(value); + } else if (key == "bufferCount") { + config.bufferCount = std::stoi(value); + } else if (key == "colorSpace") { + config.colorSpace = libcamera::ColorSpace::fromString(value); + } else { + std::cerr << "Unknown key-value pair '" + << key << "': '" << value + << "' in stream configuration " + << index << std::endl; + return -EINVAL; + } + } + + streamConfigs_.push_back(config); + + return 0; +} + +int CaptureScript::parseStreams(EventPtr event) +{ + if (!checkEvent(event, YAML_SEQUENCE_START_EVENT)) + return -EINVAL; + + unsigned int index = 0; + while (1) { + event = nextEvent(); + if (!event) + return -EINVAL; + if (event->type == YAML_SEQUENCE_END_EVENT) + return 0; + + if (event->type == YAML_MAPPING_START_EVENT) { + parseStream(std::move(event), index++); + continue; + } else { + std::cerr << "UNKNOWN TYPE" << std::endl; + return -EINVAL; + } + } + + return 0; +} + +int CaptureScript::parseConfiguration() +{ + int ret; + + EventPtr event = nextEvent(YAML_MAPPING_START_EVENT); + if (!event) + return -EINVAL; + + while (1) { + event = nextEvent(); + if (!event) + return -EINVAL; + if (event->type == YAML_MAPPING_END_EVENT) + break; + + std::string key = eventScalarValue(event); + + event = nextEvent(); + if (!event) + return -EINVAL; + if (event->type == YAML_MAPPING_END_EVENT) + break; + + /* TODO Load sensor configuration */ + if (key == "orientation") { + ret = parseOrientation(std::move(event)); + if (ret) + return ret; + } else if (key == "streams") { + ret = parseStreams(std::move(event)); + if (ret) + return ret; + } + } + + return 0; +} + +void CaptureScript::populateConfiguration(CameraConfiguration *configuration) const +{ + if (!configuration) + return; + + configuration->orientation = orientation_; + + for (unsigned int i = 0; i < streamConfigs_.size(); i++) + (*configuration)[i] = streamConfigs_[i]; +} + std::string CaptureScript::parseScalar() { EventPtr event = nextEvent(YAML_SCALAR_EVENT); diff --git a/src/apps/cam/capture_script.h b/src/apps/cam/capture_script.h index 294b9203..4ba862d7 100644 --- a/src/apps/cam/capture_script.h +++ b/src/apps/cam/capture_script.h @@ -26,6 +26,7 @@ public: const libcamera::ControlList &frameControls(unsigned int frame); + void populateConfiguration(libcamera::CameraConfiguration *configuration) const; private: struct EventDeleter { void operator()(yaml_event_t *event) const @@ -43,6 +44,9 @@ private: unsigned int loop_; bool valid_; + libcamera::Orientation orientation_; + std::vector streamConfigs_; + EventPtr nextEvent(yaml_event_type_t expectedType = YAML_NO_EVENT); bool checkEvent(const EventPtr &event, yaml_event_type_t expectedType) const; static std::string eventScalarValue(const EventPtr &event); @@ -55,6 +59,10 @@ private: int parseFrames(); int parseFrame(EventPtr event); int parseControl(EventPtr event, libcamera::ControlList &controls); + int parseConfiguration(); + int parseOrientation(EventPtr event); + int parseStreams(EventPtr event); + int parseStream(EventPtr event, unsigned int index); libcamera::ControlValue parseScalarControl(const libcamera::ControlId *id, const std::string repr); -- cgit v1.2.1