summaryrefslogtreecommitdiff
path: root/src/apps/cam
diff options
context:
space:
mode:
Diffstat (limited to 'src/apps/cam')
-rw-r--r--src/apps/cam/camera_session.cpp66
-rw-r--r--src/apps/cam/capture_script.cpp36
-rw-r--r--src/apps/cam/file_sink.cpp64
-rw-r--r--src/apps/cam/file_sink.h19
-rw-r--r--src/apps/cam/main.cpp3
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;