Message ID | 20241004120517.3572281-3-paul.elder@ideasonboard.com |
---|---|
State | New |
Headers | show |
Series |
|
Related | show |
Hi Paul, Thank you for the patch. On Fri, Oct 04, 2024 at 09:05:17PM +0900, Paul Elder wrote: > Add support to the cam application for loading the camera configuration > from a capture script. These can be written manually, or dumped from a > capture session 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 <paul.elder@ideasonboard.com> > > --- > Changes in v2: > - clean up code > --- > src/apps/cam/camera_session.cpp | 26 +++-- > src/apps/cam/capture_script.cpp | 163 ++++++++++++++++++++++++++++++++ > src/apps/cam/capture_script.h | 9 ++ > src/apps/cam/main.cpp | 4 +- > 4 files changed, 191 insertions(+), 11 deletions(-) > > diff --git a/src/apps/cam/camera_session.cpp b/src/apps/cam/camera_session.cpp > index edc49b875450..695b313c3779 100644 > --- a/src/apps/cam/camera_session.cpp > +++ b/src/apps/cam/camera_session.cpp > @@ -70,6 +70,22 @@ CameraSession::CameraSession(CameraManager *cm, > return; > } > > + /* > + * Parse the capture script first to populate the configuration, and > + * let command line arguments take precedence. > + */ > + if (options_.isSet(OptCaptureScript)) { > + std::string scriptName = options_[OptCaptureScript].toString(); > + script_ = std::make_unique<CaptureScript>(camera_, scriptName); > + if (!script_->valid()) { > + std::cerr << "Invalid capture script '" << scriptName > + << "'" << std::endl; > + return; > + } > + > + script_->populateConfiguration(*config); > + } > + > if (options_.isSet(OptOrientation)) { > std::string orientOpt = options_[OptOrientation].toString(); > static const std::map<std::string, libcamera::Orientation> orientations{ > @@ -119,16 +135,6 @@ CameraSession::CameraSession(CameraManager *cm, > } > #endif > > - if (options_.isSet(OptCaptureScript)) { > - std::string scriptName = options_[OptCaptureScript].toString(); > - script_ = std::make_unique<CaptureScript>(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 fc1dfa75f2d4..a4298f99c4d8 100644 > --- a/src/apps/cam/capture_script.cpp > +++ b/src/apps/cam/capture_script.cpp > @@ -7,6 +7,7 @@ > > #include "capture_script.h" > > +#include <algorithm> > #include <iostream> > #include <stdio.h> > #include <stdlib.h> > @@ -158,6 +159,10 @@ int CaptureScript::parseScript(FILE *script) > ret = parseProperties(); > if (ret) > return ret; > + } else if (section == "configuration") { > + ret = parseConfiguration(); > + if (ret) > + return ret; > } else if (section == "frames") { > ret = parseFrames(); > if (ret) > @@ -229,6 +234,156 @@ int CaptureScript::parseProperties() > 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 */ \todo > + 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; > +} > + > +int CaptureScript::parseOrientation(EventPtr event) > +{ > + static const std::map<std::string, libcamera::Orientation> 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::parseStreams(EventPtr event) > +{ > + int ret; > + > + 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) { > + if ((ret = parseStream(std::move(event), index++)) < 0) int ret = parseStream(std::move(event), index++)); if (ret < 0) > + return ret; > + } else { > + std::cerr << "Unknown type" << std::endl; > + return -EINVAL; > + } Please also see my last reply on v1. Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > + } > + > + 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); > + > + std::string value = parseScalar(); > + if (value.empty()) > + return -EINVAL; > + > + 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::parseFrames() > { > EventPtr event = nextEvent(YAML_SEQUENCE_START_EVENT); > @@ -322,6 +477,14 @@ int CaptureScript::parseControl(EventPtr event, ControlList &controls) > return 0; > } > > +void CaptureScript::populateConfiguration(CameraConfiguration &configuration) const > +{ > + 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 294b920363ba..4fa3447d156f 100644 > --- a/src/apps/cam/capture_script.h > +++ b/src/apps/cam/capture_script.h > @@ -26,6 +26,8 @@ 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 +45,9 @@ private: > unsigned int loop_; > bool valid_; > > + libcamera::Orientation orientation_; > + std::vector<libcamera::StreamConfiguration> 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); > @@ -52,6 +57,10 @@ private: > > int parseProperties(); > int parseProperty(); > + int parseConfiguration(); > + int parseOrientation(EventPtr event); > + int parseStreams(EventPtr event); > + int parseStream(EventPtr event, unsigned int index); > int parseFrames(); > int parseFrame(EventPtr event); > int parseControl(EventPtr event, libcamera::ControlList &controls); > diff --git a/src/apps/cam/main.cpp b/src/apps/cam/main.cpp > index 460dbc813060..4291b64e250d 100644 > --- a/src/apps/cam/main.cpp > +++ b/src/apps/cam/main.cpp > @@ -175,7 +175,9 @@ int CamApp::parseOptions(int argc, char *argv[]) > "metadata", ArgumentNone, nullptr, false, > OptCamera); > parser.addOption(OptCaptureScript, OptionString, > - "Load a capture session configuration script from a file", > + "Load a capture session configuration script from a file.\n" > + "Configuration options specified in the capture script will be\n" > + "overwritten by --stream and --orientation.", > "script", ArgumentRequired, "script", false, > OptCamera); >
diff --git a/src/apps/cam/camera_session.cpp b/src/apps/cam/camera_session.cpp index edc49b875450..695b313c3779 100644 --- a/src/apps/cam/camera_session.cpp +++ b/src/apps/cam/camera_session.cpp @@ -70,6 +70,22 @@ CameraSession::CameraSession(CameraManager *cm, return; } + /* + * Parse the capture script first to populate the configuration, and + * let command line arguments take precedence. + */ + if (options_.isSet(OptCaptureScript)) { + std::string scriptName = options_[OptCaptureScript].toString(); + script_ = std::make_unique<CaptureScript>(camera_, scriptName); + if (!script_->valid()) { + std::cerr << "Invalid capture script '" << scriptName + << "'" << std::endl; + return; + } + + script_->populateConfiguration(*config); + } + if (options_.isSet(OptOrientation)) { std::string orientOpt = options_[OptOrientation].toString(); static const std::map<std::string, libcamera::Orientation> orientations{ @@ -119,16 +135,6 @@ CameraSession::CameraSession(CameraManager *cm, } #endif - if (options_.isSet(OptCaptureScript)) { - std::string scriptName = options_[OptCaptureScript].toString(); - script_ = std::make_unique<CaptureScript>(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 fc1dfa75f2d4..a4298f99c4d8 100644 --- a/src/apps/cam/capture_script.cpp +++ b/src/apps/cam/capture_script.cpp @@ -7,6 +7,7 @@ #include "capture_script.h" +#include <algorithm> #include <iostream> #include <stdio.h> #include <stdlib.h> @@ -158,6 +159,10 @@ int CaptureScript::parseScript(FILE *script) ret = parseProperties(); if (ret) return ret; + } else if (section == "configuration") { + ret = parseConfiguration(); + if (ret) + return ret; } else if (section == "frames") { ret = parseFrames(); if (ret) @@ -229,6 +234,156 @@ int CaptureScript::parseProperties() 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; +} + +int CaptureScript::parseOrientation(EventPtr event) +{ + static const std::map<std::string, libcamera::Orientation> 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::parseStreams(EventPtr event) +{ + int ret; + + 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) { + if ((ret = parseStream(std::move(event), index++)) < 0) + return ret; + } else { + std::cerr << "Unknown type" << std::endl; + return -EINVAL; + } + } + + 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); + + std::string value = parseScalar(); + if (value.empty()) + return -EINVAL; + + 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::parseFrames() { EventPtr event = nextEvent(YAML_SEQUENCE_START_EVENT); @@ -322,6 +477,14 @@ int CaptureScript::parseControl(EventPtr event, ControlList &controls) return 0; } +void CaptureScript::populateConfiguration(CameraConfiguration &configuration) const +{ + 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 294b920363ba..4fa3447d156f 100644 --- a/src/apps/cam/capture_script.h +++ b/src/apps/cam/capture_script.h @@ -26,6 +26,8 @@ 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 +45,9 @@ private: unsigned int loop_; bool valid_; + libcamera::Orientation orientation_; + std::vector<libcamera::StreamConfiguration> 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); @@ -52,6 +57,10 @@ private: int parseProperties(); int parseProperty(); + int parseConfiguration(); + int parseOrientation(EventPtr event); + int parseStreams(EventPtr event); + int parseStream(EventPtr event, unsigned int index); int parseFrames(); int parseFrame(EventPtr event); int parseControl(EventPtr event, libcamera::ControlList &controls); diff --git a/src/apps/cam/main.cpp b/src/apps/cam/main.cpp index 460dbc813060..4291b64e250d 100644 --- a/src/apps/cam/main.cpp +++ b/src/apps/cam/main.cpp @@ -175,7 +175,9 @@ int CamApp::parseOptions(int argc, char *argv[]) "metadata", ArgumentNone, nullptr, false, OptCamera); parser.addOption(OptCaptureScript, OptionString, - "Load a capture session configuration script from a file", + "Load a capture session configuration script from a file.\n" + "Configuration options specified in the capture script will be\n" + "overwritten by --stream and --orientation.", "script", ArgumentRequired, "script", false, OptCamera);
Add support to the cam application for loading the camera configuration from a capture script. These can be written manually, or dumped from a capture session 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 <paul.elder@ideasonboard.com> --- Changes in v2: - clean up code --- src/apps/cam/camera_session.cpp | 26 +++-- src/apps/cam/capture_script.cpp | 163 ++++++++++++++++++++++++++++++++ src/apps/cam/capture_script.h | 9 ++ src/apps/cam/main.cpp | 4 +- 4 files changed, 191 insertions(+), 11 deletions(-)