diff options
Diffstat (limited to 'src/apps/cam')
-rw-r--r-- | src/apps/cam/camera_session.cpp | 66 | ||||
-rw-r--r-- | src/apps/cam/capture_script.cpp | 36 | ||||
-rw-r--r-- | src/apps/cam/file_sink.cpp | 64 | ||||
-rw-r--r-- | src/apps/cam/file_sink.h | 19 | ||||
-rw-r--r-- | src/apps/cam/main.cpp | 3 |
5 files changed, 128 insertions, 60 deletions
diff --git a/src/apps/cam/camera_session.cpp b/src/apps/cam/camera_session.cpp index 097dc479..97c1ae44 100644 --- a/src/apps/cam/camera_session.cpp +++ b/src/apps/cam/camera_session.cpp @@ -5,9 +5,12 @@ * Camera capture session */ +#include "camera_session.h" + #include <iomanip> #include <iostream> #include <limits.h> +#include <optional> #include <sstream> #include <libcamera/control_ids.h> @@ -16,7 +19,6 @@ #include "../common/event_loop.h" #include "../common/stream_options.h" -#include "camera_session.h" #include "capture_script.h" #include "file_sink.h" #ifdef HAVE_KMS @@ -159,8 +161,51 @@ CameraSession::~CameraSession() void CameraSession::listControls() const { for (const auto &[id, info] : camera_->controls()) { - std::cout << "Control: " << id->name() << ": " - << info.toString() << std::endl; + std::stringstream io; + io << "[" + << (id->isInput() ? "in" : " ") + << (id->isOutput() ? "out" : " ") + << "] "; + + if (info.values().empty()) { + std::cout << "Control: " << io.str() + << id->vendor() << "::" << id->name() << ": " + << info.toString() << std::endl; + } else { + std::cout << "Control: " << io.str() + << id->vendor() << "::" << id->name() << ":" + << std::endl; + + std::optional<int32_t> def; + if (!info.def().isNone()) + def = info.def().get<int32_t>(); + + for (const auto &value : info.values()) { + int32_t val = value.get<int32_t>(); + const auto &it = id->enumerators().find(val); + + std::cout << " - "; + if (it == id->enumerators().end()) + std::cout << "UNKNOWN"; + else + std::cout << it->second; + + std::cout << " (" << val << ")" + << (val == def ? " [default]" : "") + << std::endl; + } + } + + if (id->isArray()) { + std::size_t size = id->size(); + + std::cout << " Size: "; + if (size == std::numeric_limits<std::size_t>::max()) + std::cout << "n"; + else + std::cout << std::to_string(size); + std::cout << std::endl; + } } } @@ -230,11 +275,16 @@ int CameraSession::start() #endif if (options_.isSet(OptFile)) { - if (!options_[OptFile].toString().empty()) - sink_ = std::make_unique<FileSink>(camera_.get(), streamNames_, - options_[OptFile]); - else - sink_ = std::make_unique<FileSink>(camera_.get(), streamNames_); + std::unique_ptr<FileSink> sink = + std::make_unique<FileSink>(camera_.get(), streamNames_); + + if (!options_[OptFile].toString().empty()) { + ret = sink->setFilePattern(options_[OptFile]); + if (ret) + return ret; + } + + sink_ = std::move(sink); } if (sink_) { diff --git a/src/apps/cam/capture_script.cpp b/src/apps/cam/capture_script.cpp index fc1dfa75..e7e69960 100644 --- a/src/apps/cam/capture_script.cpp +++ b/src/apps/cam/capture_script.cpp @@ -8,6 +8,7 @@ #include "capture_script.h" #include <iostream> +#include <memory> #include <stdio.h> #include <stdlib.h> @@ -521,45 +522,22 @@ ControlValue CaptureScript::parseArrayControl(const ControlId *id, case ControlTypeNone: break; case ControlTypeBool: { - /* - * This is unpleasant, but we cannot use an std::vector<> as its - * boolean type overload does not allow to access the raw data, - * as boolean values are stored in a bitmask for efficiency. - * - * As we need a contiguous memory region to wrap in a Span<>, - * use an array instead but be strict about not overflowing it - * by limiting the number of controls we can store. - * - * Be loud but do not fail, as the issue would present at - * runtime and it's not fatal. - */ - static constexpr unsigned int kMaxNumBooleanControls = 1024; - std::array<bool, kMaxNumBooleanControls> values; - unsigned int idx = 0; + auto values = std::make_unique<bool[]>(repr.size()); - for (const std::string &s : repr) { - bool val; + for (std::size_t i = 0; i < repr.size(); i++) { + const auto &s = repr[i]; if (s == "true") { - val = true; + values[i] = true; } else if (s == "false") { - val = false; + values[i] = false; } else { unpackFailure(id, s); return value; } - - if (idx == kMaxNumBooleanControls) { - std::cerr << "Cannot parse more than " - << kMaxNumBooleanControls - << " boolean controls" << std::endl; - break; - } - - values[idx++] = val; } - value = Span<bool>(values.data(), idx); + value = Span<bool>(values.get(), repr.size()); break; } case ControlTypeByte: { diff --git a/src/apps/cam/file_sink.cpp b/src/apps/cam/file_sink.cpp index 3e000d2f..65794a2f 100644 --- a/src/apps/cam/file_sink.cpp +++ b/src/apps/cam/file_sink.cpp @@ -5,6 +5,9 @@ * File Sink */ +#include "file_sink.h" + +#include <array> #include <assert.h> #include <fcntl.h> #include <iomanip> @@ -12,6 +15,7 @@ #include <sstream> #include <string.h> #include <unistd.h> +#include <utility> #include <libcamera/camera.h> @@ -19,18 +23,16 @@ #include "../common/image.h" #include "../common/ppm_writer.h" -#include "file_sink.h" - using namespace libcamera; FileSink::FileSink([[maybe_unused]] const libcamera::Camera *camera, - const std::map<const libcamera::Stream *, std::string> &streamNames, - const std::string &pattern) + const std::map<const libcamera::Stream *, std::string> &streamNames) : #ifdef HAVE_TIFF camera_(camera), #endif - streamNames_(streamNames), pattern_(pattern) + pattern_(kDefaultFilePattern), fileType_(FileType::Binary), + streamNames_(streamNames) { } @@ -38,6 +40,41 @@ FileSink::~FileSink() { } +int FileSink::setFilePattern(const std::string &pattern) +{ + static const std::array<std::pair<std::string, FileType>, 2> types{{ + { ".dng", FileType::Dng }, + { ".ppm", FileType::Ppm }, + }}; + + pattern_ = pattern; + + if (pattern_.empty() || pattern_.back() == '/') + pattern_ += kDefaultFilePattern; + + fileType_ = FileType::Binary; + + for (const auto &type : types) { + if (pattern_.size() < type.first.size()) + continue; + + if (pattern_.find(type.first, pattern_.size() - type.first.size()) != + std::string::npos) { + fileType_ = type.second; + break; + } + } + +#ifndef HAVE_TIFF + if (fileType_ == FileType::Dng) { + std::cerr << "DNG support not available" << std::endl; + return -EINVAL; + } +#endif /* HAVE_TIFF */ + + return 0; +} + int FileSink::configure(const libcamera::CameraConfiguration &config) { int ret = FrameSink::configure(config); @@ -67,21 +104,10 @@ bool FileSink::processRequest(Request *request) void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer, [[maybe_unused]] const ControlList &metadata) { - std::string filename; + std::string filename = pattern_; size_t pos; int fd, ret = 0; - if (!pattern_.empty()) - filename = pattern_; - -#ifdef HAVE_TIFF - bool dng = filename.find(".dng", filename.size() - 4) != std::string::npos; -#endif /* HAVE_TIFF */ - bool ppm = filename.find(".ppm", filename.size() - 4) != std::string::npos; - - if (filename.empty() || filename.back() == '/') - filename += "frame-#.bin"; - pos = filename.find_first_of('#'); if (pos != std::string::npos) { std::stringstream ss; @@ -93,7 +119,7 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer, Image *image = mappedBuffers_[buffer].get(); #ifdef HAVE_TIFF - if (dng) { + if (fileType_ == FileType::Dng) { ret = DNGWriter::write(filename.c_str(), camera_, stream->configuration(), metadata, buffer, image->data(0).data()); @@ -104,7 +130,7 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer, return; } #endif /* HAVE_TIFF */ - if (ppm) { + if (fileType_ == FileType::Ppm) { ret = PPMWriter::write(filename.c_str(), stream->configuration(), image->data(0)); if (ret < 0) diff --git a/src/apps/cam/file_sink.h b/src/apps/cam/file_sink.h index 9d560783..26cd61b3 100644 --- a/src/apps/cam/file_sink.h +++ b/src/apps/cam/file_sink.h @@ -11,6 +11,7 @@ #include <memory> #include <string> +#include <libcamera/controls.h> #include <libcamera/stream.h> #include "frame_sink.h" @@ -21,10 +22,11 @@ class FileSink : public FrameSink { public: FileSink(const libcamera::Camera *camera, - const std::map<const libcamera::Stream *, std::string> &streamNames, - const std::string &pattern = ""); + const std::map<const libcamera::Stream *, std::string> &streamNames); ~FileSink(); + int setFilePattern(const std::string &pattern); + int configure(const libcamera::CameraConfiguration &config) override; void mapBuffer(libcamera::FrameBuffer *buffer) override; @@ -32,6 +34,14 @@ public: bool processRequest(libcamera::Request *request) override; private: + static constexpr const char *kDefaultFilePattern = "frame-#.bin"; + + enum class FileType { + Binary, + Dng, + Ppm, + }; + void writeBuffer(const libcamera::Stream *stream, libcamera::FrameBuffer *buffer, const libcamera::ControlList &metadata); @@ -39,7 +49,10 @@ private: #ifdef HAVE_TIFF const libcamera::Camera *camera_; #endif - std::map<const libcamera::Stream *, std::string> streamNames_; + std::string pattern_; + FileType fileType_; + + std::map<const libcamera::Stream *, std::string> streamNames_; std::map<libcamera::FrameBuffer *, std::unique_ptr<Image>> mappedBuffers_; }; diff --git a/src/apps/cam/main.cpp b/src/apps/cam/main.cpp index 460dbc81..fa266eca 100644 --- a/src/apps/cam/main.cpp +++ b/src/apps/cam/main.cpp @@ -5,6 +5,8 @@ * cam - The libcamera swiss army knife */ +#include "main.h" + #include <atomic> #include <iomanip> #include <iostream> @@ -19,7 +21,6 @@ #include "../common/stream_options.h" #include "camera_session.h" -#include "main.h" using namespace libcamera; |