/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2019, Google Inc. * * main.cpp - cam - The libcamera swiss army knife */ #include #include #include #include #include #include #include #include "camera_session.h" #include "event_loop.h" #include "main.h" #include "options.h" #include "stream_options.h" using namespace libcamera; class CamApp { public: CamApp(); static CamApp *instance(); int init(int argc, char **argv); void cleanup(); int exec(); void quit(); private: void cameraAdded(std::shared_ptr cam); void cameraRemoved(std::shared_ptr cam); void captureDone(); int parseOptions(int argc, char *argv[]); int run(); static std::string cameraName(const Camera *camera); static CamApp *app_; OptionsParser::Options options_; std::unique_ptr cm_; std::atomic_uint loopUsers_; EventLoop loop_; }; CamApp *CamApp::app_ = nullptr; CamApp::CamApp() : loopUsers_(0) { CamApp::app_ = this; } CamApp *CamApp::instance() { return CamApp::app_; } int CamApp::init(int argc, char **argv) { int ret; ret = parseOptions(argc, argv); if (ret < 0) return ret; cm_ = std::make_unique(); ret = cm_->start(); if (ret) { std::cout << "Failed to start camera manager: " << strerror(-ret) << std::endl; return ret; } return 0; } void CamApp::cleanup() { cm_->stop(); } int CamApp::exec() { int ret; ret = run(); cleanup(); return ret; } void CamApp::quit() { loop_.exit(); } int CamApp::parseOptions(int argc, char *argv[]) { StreamKeyValueParser streamKeyValue; OptionsParser parser; parser.addOption(OptCamera, OptionString, "Specify which camera to operate on, by id or by index", "camera", ArgumentRequired, "camera", true); parser.addOption(OptHelp, OptionNone, "Display this help message", "help"); parser.addOption(OptInfo, OptionNone, "Display information about stream(s)", "info"); parser.addOption(OptList, OptionNone, "List all cameras", "list"); parser.addOption(OptListControls, OptionNone, "List cameras controls", "list-controls"); parser.addOption(OptListProperties, OptionNone, "List cameras properties", "list-properties"); parser.addOption(OptMonitor, OptionNone, "Monitor for hotplug and unplug camera events", "monitor"); /* Sub-options of OptCamera: */ parser.addOption(OptCapture, OptionInteger, "Capture until interrupted by user or until frames captured", "capture", ArgumentOptional, "count", false, OptCamera); #ifdef HAVE_KMS parser.addOption(OptDisplay, OptionString, "Display viewfinder through DRM/KMS on specified connector", "display", ArgumentOptional, "connector", false, OptCamera); #endif parser.addOption(OptFile, OptionString, "Write captured frames to disk\n" "If the file name ends with a '/', it sets the directory in which\n" "to write files, using the default file name. Otherwise it sets the\n" "full file path and name. The first '#' character in the file name\n" "is expanded to the camera index, stream name and frame sequence number.\n" "The default file name is 'frame-#.bin'.", "file", ArgumentOptional, "filename", false, OptCamera); parser.addOption(OptStream, &streamKeyValue, "Set configuration of a camera stream", "stream", true, OptCamera); parser.addOption(OptStrictFormats, OptionNone, "Do not allow requested stream format(s) to be adjusted", "strict-formats", ArgumentNone, nullptr, false, OptCamera); parser.addOption(OptMetadata, OptionNone, "Print the metadata for completed requests", "metadata", ArgumentNone, nullptr, false, OptCamera); options_ = parser.parse(argc, argv); if (!options_.valid()) return -EINVAL; if (options_.empty() || options_.isSet(OptHelp)) { parser.usage(); return options_.empty() ? -EINVAL : -EINTR; } return 0; } void CamApp::cameraAdded(std::shared_ptr cam) { std::cout << "Camera Added: " << cam->id() << std::endl; } void CamApp::cameraRemoved(std::shared_ptr cam) { std::cout << "Camera Removed: " << cam->id() << std::endl; } void CamApp::captureDone() { if (--loopUsers_ == 0) EventLoop::instance()->exit(0); } int CamApp::run() { int ret; /* 1. List all cameras. */ if (options_.isSet(OptList)) { std::cout << "Available cameras:" << std::endl; unsigned int index = 1; for (const std::shared_ptr &cam : cm_->cameras()) { std::cout << index << ": " << cameraName(cam.get()) << std::endl; index++; } } /* 2. Create the camera sessions. */ std::vector> sessions; if (options_.isSet(OptCamera)) { unsigned int index = 0; for (const OptionValue &camera : options_[OptCamera].toArray()) { std::unique_ptr session = std::make_unique(cm_.get(), camera.toString(), index, camera.children()); if (!session->isValid()) { std::cout << "Failed to create camera session" << std::endl; return -EINVAL; } std::cout << "Using camera " << session->camera()->id() << " as cam" << index << std::endl; session->captureDone.connect(this, &CamApp::captureDone); sessions.push_back(std::move(session)); index++; } } /* 3. Print camera information. */ if (options_.isSet(OptListControls) || options_.isSet(OptListProperties) || options_.isSet(OptInfo)) { for (const auto &session : sessions) { if (options_.isSet(OptListControls)) session->listControls(); if (options_.isSet(OptListProperties)) session->listProperties(); if (options_.isSet(OptInfo)) session->infoConfiguration(); } } /* 4. Start capture. */ for (const auto &session : sessions) { if (!session->options().isSet(OptCapture)) continue; ret = session->start(); if (ret) { std::cout << "Failed to start camera session" << std::endl; return ret; } loopUsers_++; } /* 5. Enable hotplug monitoring. */ if (options_.isSet(OptMonitor)) { std::cout << "Monitoring new hotplug and unplug events" << std::endl; std::cout << "Press Ctrl-C to interrupt" << std::endl; cm_->cameraAdded.connect(this, &CamApp::cameraAdded); cm_->cameraRemoved.connect(this, &CamApp::cameraRemoved); loopUsers_++; } if (loopUsers_) loop_.exec(); /* 6. Stop capture. */ for (const auto &session : sessions) { if (!session->options().isSet(OptCapture)) continue; session->stop(); } return 0; } std::string CamApp::cameraName(const Camera *camera) { const ControlList &props = camera->properties(); bool addModel = true; std::string name; /* * Construct the name from the camera location, model and ID. The model * is only used if the location isn't present or is set to External. */ if (props.contains(properties::Location)) { switch (props.get(properties::Location)) { case properties::CameraLocationFront: addModel = false; name = "Internal front camera "; break; case properties::CameraLocationBack: addModel = false; name = "Internal back camera "; break; case properties::CameraLocationExternal: name = "External camera "; break; } } if (addModel &&/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2022, Ideas On Board * * IPA Module */ #include "module.h" /** * \file module.h * \brief IPA Module common interface */ namespace libcamera { LOG_DEFINE_CATEGORY(IPAModuleAlgo) /** * \brief The IPA (Image Processing Algorithm) namespace * * The IPA namespace groups all types specific to IPA modules. It serves as the * top-level namespace for the IPA library libipa, and also contains * module-specific namespaces for IPA modules. */ namespace ipa { /** * \class Module * \brief The base class for all IPA modules * \tparam Context The type of the shared IPA context * \tparam FrameContext The type of the frame context * \tparam Config The type of the IPA configuration data * \tparam Params The type of the ISP specific parameters * \tparam Stats The type of the IPA statistics and ISP results * * The Module class template defines a standard internal interface between IPA * modules and libipa. * * While IPA modules are platform-specific, many of their internal functions are * conceptually similar, even if they take different types of platform-specifc * parameters. For instance, IPA modules could share code that instantiates, * initializes and run algorithms if it wasn't for the fact that the the format * of ISP parameters or statistics passed to the related functions is * device-dependent. * * To enable a shared implementation of those common tasks in libipa, the Module * class template defines a standard internal interface between IPA modules and * libipa. The template parameters specify the types of module-dependent data. * IPA modules shall create a specialization of the Module class template in * their namespace, and use it to specialize other classes of libipa, such as * the Algorithm class. */ /** * \typedef Module::Context * \brief The type of the shared IPA context */ /** * \typedef Module::FrameContext * \brief The type of the frame context */ /** * \typedef Module::Config * \brief The type of the IPA configuration data */ /** * \typedef Module::Params * \brief The type of the ISP specific parameters */ /** * \typedef Module::Stats * \brief The type of the IPA statistics and ISP results */ /** * \fn Module::algorithms() * \brief Retrieve the list of instantiated algorithms * \return The list of instantiated algorithms */ /** * \fn Module::createAlgorithms() * \brief Create algorithms from YAML configuration data * \param[in] context The IPA context * \param[in] algorithms Algorithms configuration data as a parsed YamlObject * * This function iterates over the list of \a algorithms parsed from the YAML * configuration file, and instantiates and initializes the corresponding * algorithms. The configuration data is expected to be correct, any error * causes the function to fail and return immediately. * * \return 0 on success, or a negative error code on failure */ /** * \fn Module::registerAlgorithm() * \brief Add an algorithm factory class to the list of available algorithms * \param[in] factory Factory to use to construct the algorithm * * This function registers an algorithm factory. It is meant to be called by the * AlgorithmFactory constructor only. */ /** * \fn Module::createAlgorithm(const std::string &name) * \brief Create an instance of an Algorithm by name * \param[in] name The algorithm name * * This function is the entry point to algorithm instantiation for the IPA * module. It creates and returns an instance of an algorithm identified by its * \a name. If no such algorithm exists, the function returns nullptr. * * To make an algorithm available to the IPA module, it shall be registered with * the REGISTER_IPA_ALGORITHM() macro. * * \return A new instance of the Algorithm subclass corresponding to the \a name */ } /* namespace ipa */ } /* namespace libcamera */