diff --git a/core/libcamera_app.cpp b/core/libcamera_app.cpp index 3d3c181a..86a6d705 100644 --- a/core/libcamera_app.cpp +++ b/core/libcamera_app.cpp @@ -137,6 +137,8 @@ LibcameraApp::LibcameraApp(std::unique_ptr opts) if (!options_) options_ = std::make_unique(); + options_->SetApp(this); + set_pipeline_configuration(platform); } @@ -151,6 +153,15 @@ LibcameraApp::~LibcameraApp() CloseCamera(); } +void LibcameraApp::initCameraManager() +{ + camera_manager_.reset(); + camera_manager_ = std::make_unique(); + int ret = camera_manager_->start(); + if (ret) + throw std::runtime_error("camera manager failed to start, code " + std::to_string(-ret)); +} + std::string const &LibcameraApp::CameraId() const { return camera_->id(); @@ -170,14 +181,13 @@ void LibcameraApp::OpenCamera() LOG(2, "Opening camera..."); - camera_manager_ = std::make_unique(); - int ret = camera_manager_->start(); - if (ret) - throw std::runtime_error("camera manager failed to start, code " + std::to_string(-ret)); + if (!camera_manager_) + initCameraManager(); std::vector> cameras = GetCameras(); if (cameras.size() == 0) throw std::runtime_error("no cameras available"); + if (options_->camera >= cameras.size()) throw std::runtime_error("selected camera is not available"); diff --git a/core/libcamera_app.hpp b/core/libcamera_app.hpp index 1bdd2de1..5e8492af 100644 --- a/core/libcamera_app.hpp +++ b/core/libcamera_app.hpp @@ -179,6 +179,7 @@ class LibcameraApp friend class BufferWriteSync; friend class BufferReadSync; + friend struct Options; protected: std::unique_ptr options_; @@ -229,6 +230,7 @@ class LibcameraApp Stream *stream; }; + void initCameraManager(); void setupCapture(); void makeRequests(); void queueRequest(CompletedRequest *completed_request); @@ -241,6 +243,7 @@ class LibcameraApp Mode selectMode(const Mode &mode) const; std::unique_ptr camera_manager_; + std::vector> cameras_; std::shared_ptr camera_; bool camera_acquired_ = false; std::unique_ptr configuration_; diff --git a/core/options.cpp b/core/options.cpp index 52587a84..0cc474ed 100644 --- a/core/options.cpp +++ b/core/options.cpp @@ -104,8 +104,9 @@ static int xioctl(int fd, unsigned long ctl, void *arg) return ret; } -static void set_subdev_hdr_ctrl(int en) +static bool set_subdev_hdr_ctrl(int en) { + bool changed = false; // Currently this does not exist in libcamera, so go directly to V4L2 // XXX it's not obvious which v4l2-subdev to use for which camera! for (int i = 0; i < 8; i++) @@ -117,9 +118,15 @@ static void set_subdev_hdr_ctrl(int en) continue; v4l2_control ctrl { V4L2_CID_WIDE_DYNAMIC_RANGE, en }; - xioctl(fd, VIDIOC_S_CTRL, &ctrl); + if (!xioctl(fd, VIDIOC_G_CTRL, &ctrl) && ctrl.value != en) + { + ctrl.value = en; + if (!xioctl(fd, VIDIOC_S_CTRL, &ctrl)) + changed = true; + } close(fd); } + return changed; } bool Options::Parse(int argc, char *argv[]) @@ -164,70 +171,55 @@ bool Options::Parse(int argc, char *argv[]) shutter.set(shutter_); flicker_period.set(flicker_period_); + if (help) + { + std::cout << options_; + return false; + } + + if (version) + { + std::cout << "libcamera-apps build: " << LibcameraAppsVersion() << std::endl; + std::cout << "libcamera build: " << libcamera::CameraManager::version() << std::endl; + return false; + } + if (hdr != "off" && hdr != "single-exp" && hdr != "sensor" && hdr != "auto") throw std::runtime_error("Invalid HDR option provided: " + hdr); - logSetTarget(LoggingTargetNone); + if (!verbose || list_cameras) + libcamera::logSetTarget(libcamera::LoggingTargetNone); // HDR control. Set the sensor control before opening or listing any cameras. - // Start by disabling HDR unconditionally. + // Start by disabling HDR unconditionally. Reset the camera manager if we have + // actually switched the value of the control. set_subdev_hdr_ctrl(0); + app_->initCameraManager(); - std::unique_ptr cm = std::make_unique(); - int ret = cm->start(); - if (ret) - throw std::runtime_error("camera manager failed to start, code " + std::to_string(-ret)); + // Unconditionally disable libcamera logging for a bit. + libcamera::logSetTarget(libcamera::LoggingTargetNone); - std::vector> cameras = LibcameraApp::GetCameras(cm.get()); - std::string const &cam_id = *cameras[camera]->properties().get(libcamera::properties::Model); - cameras.clear(); - cm->stop(); - cm.reset(); + std::vector> cameras = app_->GetCameras(); + const std::string cam_id = *cameras[camera]->properties().get(libcamera::properties::Model); if ((hdr == "sensor" || hdr == "auto") && cam_id == "imx708") { - set_subdev_hdr_ctrl(1); + // Turn on sensor HDR. Reset the camera manager if we have switched the value of the control. + if (set_subdev_hdr_ctrl(1)) + { + cameras.clear(); + app_->initCameraManager(); + cameras = app_->GetCameras(); + } hdr = "sensor"; } - logSetTarget(LoggingTargetStream); - - // We have to pass the tuning file name through an environment variable. - // Note that we only overwrite the variable if the option was given. - if (tuning_file != "-") - setenv("LIBCAMERA_RPI_TUNING_FILE", tuning_file.c_str(), 1); - - // Set the verbosity - LibcameraApp::verbosity = verbose; - - if (verbose == 0) - libcamera::logSetTarget(libcamera::LoggingTargetNone); - - if (help) - { - std::cout << options_; - return false; - } - - if (version) - { - std::cout << "libcamera-apps build: " << LibcameraAppsVersion() << std::endl; - std::cout << "libcamera build: " << libcamera::CameraManager::version() << std::endl; - return false; - } - if (list_cameras) { // Disable any libcamera logging for this bit. logSetTarget(LoggingTargetNone); LibcameraApp::verbosity = 1; - std::unique_ptr cm = std::make_unique(); - int ret = cm->start(); - if (ret) - throw std::runtime_error("camera manager failed to start, code " + std::to_string(-ret)); - - std::vector> cameras = LibcameraApp::GetCameras(cm.get()); if (cameras.size() != 0) { unsigned int idx = 0; @@ -341,11 +333,21 @@ bool Options::Parse(int argc, char *argv[]) std::cout << "No cameras available!" << std::endl; verbose = 1; - cameras.clear(); - cm->stop(); return false; } + // Reset verbosity to the user request. + if (verbose) + libcamera::logSetTarget(libcamera::LoggingTargetStream); + + // Set the verbosity + LibcameraApp::verbosity = verbose; + + // We have to pass the tuning file name through an environment variable. + // Note that we only overwrite the variable if the option was given. + if (tuning_file != "-") + setenv("LIBCAMERA_RPI_TUNING_FILE", tuning_file.c_str(), 1); + if (sscanf(preview.c_str(), "%u,%u,%u,%u", &preview_x, &preview_y, &preview_width, &preview_height) != 4) preview_x = preview_y = preview_width = preview_height = 0; // use default window diff --git a/core/options.hpp b/core/options.hpp index b0daff39..4869055a 100644 --- a/core/options.hpp +++ b/core/options.hpp @@ -94,7 +94,8 @@ struct TimeVal struct Options { - Options() : set_default_lens_position(false), af_on_capture(false), options_("Valid options are", 120, 80) + Options() + : set_default_lens_position(false), af_on_capture(false), options_("Valid options are", 120, 80), app_(nullptr) { using namespace boost::program_options; // clang-format off @@ -290,6 +291,8 @@ struct Options virtual bool Parse(int argc, char *argv[]); virtual void Print() const; + void SetApp(LibcameraApp *app) { app_ = app; } + protected: boost::program_options::options_description options_; @@ -302,4 +305,5 @@ struct Options std::string timeout_; std::string shutter_; std::string flicker_period_; + LibcameraApp *app_; };