From 94d828d880492617c936434a5ca93ee83366a31b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 5 Jul 2021 06:40:19 +0300 Subject: cam: Rename Capture to CameraSession Rename the Capture class to CameraSession, to prepare for multi-camera support that will gather more camera-related operations than capture in that class. While at it, remove an unneeded blank line. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/cam/camera_session.cpp | 240 ++++++++++++++++++++++++++++++++++++++++++++ src/cam/camera_session.h | 55 +++++++++++ src/cam/capture.cpp | 241 --------------------------------------------- src/cam/capture.h | 55 ----------- src/cam/main.cpp | 6 +- src/cam/meson.build | 2 +- 6 files changed, 299 insertions(+), 300 deletions(-) create mode 100644 src/cam/camera_session.cpp create mode 100644 src/cam/camera_session.h delete mode 100644 src/cam/capture.cpp delete mode 100644 src/cam/capture.h diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp new file mode 100644 index 00000000..439dcdb2 --- /dev/null +++ b/src/cam/camera_session.cpp @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * camera_session.cpp - Camera capture session + */ + +#include +#include +#include +#include + +#include + +#include "camera_session.h" +#include "main.h" + +using namespace libcamera; + +CameraSession::CameraSession(std::shared_ptr camera, + CameraConfiguration *config, EventLoop *loop) + : camera_(camera), config_(config), writer_(nullptr), last_(0), loop_(loop), + queueCount_(0), captureCount_(0), captureLimit_(0), + printMetadata_(false) +{ +} + +int CameraSession::run(const OptionsParser::Options &options) +{ + int ret; + + queueCount_ = 0; + captureCount_ = 0; + captureLimit_ = options[OptCapture].toInteger(); + printMetadata_ = options.isSet(OptMetadata); + + if (!camera_) { + std::cout << "Can't capture without a camera" << std::endl; + return -ENODEV; + } + + ret = camera_->configure(config_); + if (ret < 0) { + std::cout << "Failed to configure camera" << std::endl; + return ret; + } + + streamName_.clear(); + for (unsigned int index = 0; index < config_->size(); ++index) { + StreamConfiguration &cfg = config_->at(index); + streamName_[cfg.stream()] = "stream" + std::to_string(index); + } + + camera_->requestCompleted.connect(this, &CameraSession::requestComplete); + + if (options.isSet(OptFile)) { + if (!options[OptFile].toString().empty()) + writer_ = new BufferWriter(options[OptFile]); + else + writer_ = new BufferWriter(); + } + + FrameBufferAllocator *allocator = new FrameBufferAllocator(camera_); + + ret = capture(allocator); + + if (options.isSet(OptFile)) { + delete writer_; + writer_ = nullptr; + } + + requests_.clear(); + + delete allocator; + + return ret; +} + +int CameraSession::capture(FrameBufferAllocator *allocator) +{ + int ret; + + /* Identify the stream with the least number of buffers. */ + unsigned int nbuffers = UINT_MAX; + for (StreamConfiguration &cfg : *config_) { + ret = allocator->allocate(cfg.stream()); + if (ret < 0) { + std::cerr << "Can't allocate buffers" << std::endl; + return -ENOMEM; + } + + unsigned int allocated = allocator->buffers(cfg.stream()).size(); + nbuffers = std::min(nbuffers, allocated); + } + + /* + * TODO: make cam tool smarter to support still capture by for + * example pushing a button. For now run all streams all the time. + */ + + for (unsigned int i = 0; i < nbuffers; i++) { + std::unique_ptr request = camera_->createRequest(); + if (!request) { + std::cerr << "Can't create request" << std::endl; + return -ENOMEM; + } + + for (StreamConfiguration &cfg : *config_) { + Stream *stream = cfg.stream(); + const std::vector> &buffers = + allocator->buffers(stream); + const std::unique_ptr &buffer = buffers[i]; + + ret = request->addBuffer(stream, buffer.get()); + if (ret < 0) { + std::cerr << "Can't set buffer for request" + << std::endl; + return ret; + } + + if (writer_) + writer_->mapBuffer(buffer.get()); + } + + requests_.push_back(std::move(request)); + } + + ret = camera_->start(); + if (ret) { + std::cout << "Failed to start capture" << std::endl; + return ret; + } + + for (std::unique_ptr &request : requests_) { + ret = queueRequest(request.get()); + if (ret < 0) { + std::cerr << "Can't queue request" << std::endl; + camera_->stop(); + return ret; + } + } + + if (captureLimit_) + std::cout << "Capture " << captureLimit_ << " frames" << std::endl; + else + std::cout << "Capture until user interrupts by SIGINT" << std::endl; + + ret = loop_->exec(); + if (ret) + std::cout << "Failed to run capture loop" << std::endl; + + ret = camera_->stop(); + if (ret) + std::cout << "Failed to stop capture" << std::endl; + + return ret; +} + +int CameraSession::queueRequest(Request *request) +{ + if (captureLimit_ && queueCount_ >= captureLimit_) + return 0; + + queueCount_++; + + return camera_->queueRequest(request); +} + +void CameraSession::requestComplete(Request *request) +{ + if (request->status() == Request::RequestCancelled) + return; + + /* + * Defer processing of the completed request to the event loop, to avoid + * blocking the camera manager thread. + */ + loop_->callLater([=]() { processRequest(request); }); +} + +void CameraSession::processRequest(Request *request) +{ + const Request::BufferMap &buffers = request->buffers(); + + /* + * Compute the frame rate. The timestamp is arbitrarily retrieved from + * the first buffer, as all buffers should have matching timestamps. + */ + uint64_t ts = buffers.begin()->second->metadata().timestamp; + double fps = ts - last_; + fps = last_ != 0 && fps ? 1000000000.0 / fps : 0.0; + last_ = ts; + + std::stringstream info; + info << ts / 1000000000 << "." + << std::setw(6) << std::setfill('0') << ts / 1000 % 1000000 + << " (" << std::fixed << std::setprecision(2) << fps << " fps)"; + + for (auto it = buffers.begin(); it != buffers.end(); ++it) { + const Stream *stream = it->first; + FrameBuffer *buffer = it->second; + const std::string &name = streamName_[stream]; + + const FrameMetadata &metadata = buffer->metadata(); + + info << " " << name + << " seq: " << std::setw(6) << std::setfill('0') << metadata.sequence + << " bytesused: "; + + unsigned int nplane = 0; + for (const FrameMetadata::Plane &plane : metadata.planes) { + info << plane.bytesused; + if (++nplane < metadata.planes.size()) + info << "/"; + } + + if (writer_) + writer_->write(buffer, name); + } + + std::cout << info.str() << std::endl; + + if (printMetadata_) { + const ControlList &requestMetadata = request->metadata(); + for (const auto &ctrl : requestMetadata) { + const ControlId *id = controls::controls.at(ctrl.first); + std::cout << "\t" << id->name() << " = " + << ctrl.second.toString() << std::endl; + } + } + + captureCount_++; + if (captureLimit_ && captureCount_ >= captureLimit_) { + loop_->exit(0); + return; + } + + request->reuse(Request::ReuseBuffers); + queueRequest(request); +} diff --git a/src/cam/camera_session.h b/src/cam/camera_session.h new file mode 100644 index 00000000..ef8a11c3 --- /dev/null +++ b/src/cam/camera_session.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * camera_session.h - Camera capture session + */ +#ifndef __CAM_CAMERA_SESSION_H__ +#define __CAM_CAMERA_SESSION_H__ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "buffer_writer.h" +#include "event_loop.h" +#include "options.h" + +class CameraSession +{ +public: + CameraSession(std::shared_ptr camera, + libcamera::CameraConfiguration *config, + EventLoop *loop); + + int run(const OptionsParser::Options &options); +private: + int capture(libcamera::FrameBufferAllocator *allocator); + + int queueRequest(libcamera::Request *request); + void requestComplete(libcamera::Request *request); + void processRequest(libcamera::Request *request); + + std::shared_ptr camera_; + libcamera::CameraConfiguration *config_; + + std::map streamName_; + BufferWriter *writer_; + uint64_t last_; + + EventLoop *loop_; + unsigned int queueCount_; + unsigned int captureCount_; + unsigned int captureLimit_; + bool printMetadata_; + + std::vector> requests_; +}; + +#endif /* __CAM_CAMERA_SESSION_H__ */ diff --git a/src/cam/capture.cpp b/src/cam/capture.cpp deleted file mode 100644 index 3c3e3a53..00000000 --- a/src/cam/capture.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2019, Google Inc. - * - * capture.cpp - Cam capture - */ - -#include -#include -#include -#include - -#include - -#include "capture.h" -#include "main.h" - -using namespace libcamera; - -Capture::Capture(std::shared_ptr camera, CameraConfiguration *config, - EventLoop *loop) - : camera_(camera), config_(config), writer_(nullptr), last_(0), loop_(loop), - queueCount_(0), captureCount_(0), captureLimit_(0), - printMetadata_(false) -{ -} - -int Capture::run(const OptionsParser::Options &options) -{ - int ret; - - queueCount_ = 0; - captureCount_ = 0; - captureLimit_ = options[OptCapture].toInteger(); - printMetadata_ = options.isSet(OptMetadata); - - if (!camera_) { - std::cout << "Can't capture without a camera" << std::endl; - return -ENODEV; - } - - ret = camera_->configure(config_); - if (ret < 0) { - std::cout << "Failed to configure camera" << std::endl; - return ret; - } - - streamName_.clear(); - for (unsigned int index = 0; index < config_->size(); ++index) { - StreamConfiguration &cfg = config_->at(index); - streamName_[cfg.stream()] = "stream" + std::to_string(index); - } - - camera_->requestCompleted.connect(this, &Capture::requestComplete); - - if (options.isSet(OptFile)) { - if (!options[OptFile].toString().empty()) - writer_ = new BufferWriter(options[OptFile]); - else - writer_ = new BufferWriter(); - } - - - FrameBufferAllocator *allocator = new FrameBufferAllocator(camera_); - - ret = capture(allocator); - - if (options.isSet(OptFile)) { - delete writer_; - writer_ = nullptr; - } - - requests_.clear(); - - delete allocator; - - return ret; -} - -int Capture::capture(FrameBufferAllocator *allocator) -{ - int ret; - - /* Identify the stream with the least number of buffers. */ - unsigned int nbuffers = UINT_MAX; - for (StreamConfiguration &cfg : *config_) { - ret = allocator->allocate(cfg.stream()); - if (ret < 0) { - std::cerr << "Can't allocate buffers" << std::endl; - return -ENOMEM; - } - - unsigned int allocated = allocator->buffers(cfg.stream()).size(); - nbuffers = std::min(nbuffers, allocated); - } - - /* - * TODO: make cam tool smarter to support still capture by for - * example pushing a button. For now run all streams all the time. - */ - - for (unsigned int i = 0; i < nbuffers; i++) { - std::unique_ptr request = camera_->createRequest(); - if (!request) { - std::cerr << "Can't create request" << std::endl; - return -ENOMEM; - } - - for (StreamConfiguration &cfg : *config_) { - Stream *stream = cfg.stream(); - const std::vector> &buffers = - allocator->buffers(stream); - const std::unique_ptr &buffer = buffers[i]; - - ret = request->addBuffer(stream, buffer.get()); - if (ret < 0) { - std::cerr << "Can't set buffer for request" - << std::endl; - return ret; - } - - if (writer_) - writer_->mapBuffer(buffer.get()); - } - - requests_.push_back(std::move(request)); - } - - ret = camera_->start(); - if (ret) { - std::cout << "Failed to start capture" << std::endl; - return ret; - } - - for (std::unique_ptr &request : requests_) { - ret = queueRequest(request.get()); - if (ret < 0) { - std::cerr << "Can't queue request" << std::endl; - camera_->stop(); - return ret; - } - } - - if (captureLimit_) - std::cout << "Capture " << captureLimit_ << " frames" << std::endl; - else - std::cout << "Capture until user interrupts by SIGINT" << std::endl; - - ret = loop_->exec(); - if (ret) - std::cout << "Failed to run capture loop" << std::endl; - - ret = camera_->stop(); - if (ret) - std::cout << "Failed to stop capture" << std::endl; - - return ret; -} - -int Capture::queueRequest(Request *request) -{ - if (captureLimit_ && queueCount_ >= captureLimit_) - return 0; - - queueCount_++; - - return camera_->queueRequest(request); -} - -void Capture::requestComplete(Request *request) -{ - if (request->status() == Request::RequestCancelled) - return; - - /* - * Defer processing of the completed request to the event loop, to avoid - * blocking the camera manager thread. - */ - loop_->callLater([=]() { processRequest(request); }); -} - -void Capture::processRequest(Request *request) -{ - const Request::BufferMap &buffers = request->buffers(); - - /* - * Compute the frame rate. The timestamp is arbitrarily retrieved from - * the first buffer, as all buffers should have matching timestamps. - */ - uint64_t ts = buffers.begin()->second->metadata().timestamp; - double fps = ts - last_; - fps = last_ != 0 && fps ? 1000000000.0 / fps : 0.0; - last_ = ts; - - std::stringstream info; - info << ts / 1000000000 << "." - << std::setw(6) << std::setfill('0') << ts / 1000 % 1000000 - << " (" << std::fixed << std::setprecision(2) << fps << " fps)"; - - for (auto it = buffers.begin(); it != buffers.end(); ++it) { - const Stream *stream = it->first; - FrameBuffer *buffer = it->second; - const std::string &name = streamName_[stream]; - - const FrameMetadata &metadata = buffer->metadata(); - - info << " " << name - << " seq: " << std::setw(6) << std::setfill('0') << metadata.sequence - << " bytesused: "; - - unsigned int nplane = 0; - for (const FrameMetadata::Plane &plane : metadata.planes) { - info << plane.bytesused; - if (++nplane < metadata.planes.size()) - info << "/"; - } - - if (writer_) - writer_->write(buffer, name); - } - - std::cout << info.str() << std::endl; - - if (printMetadata_) { - const ControlList &requestMetadata = request->metadata(); - for (const auto &ctrl : requestMetadata) { - const ControlId *id = controls::controls.at(ctrl.first); - std::cout << "\t" << id->name() << " = " - << ctrl.second.toString() << std::endl; - } - } - - captureCount_++; - if (captureLimit_ && captureCount_ >= captureLimit_) { - loop_->exit(0); - return; - } - - request->reuse(Request::ReuseBuffers); - queueRequest(request); -} diff --git a/src/cam/capture.h b/src/cam/capture.h deleted file mode 100644 index de478c98..00000000 --- a/src/cam/capture.h +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2019, Google Inc. - * - * capture.h - Cam capture - */ -#ifndef __CAM_CAPTURE_H__ -#define __CAM_CAPTURE_H__ - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "buffer_writer.h" -#include "event_loop.h" -#include "options.h" - -class Capture -{ -public: - Capture(std::shared_ptr camera, - libcamera::CameraConfiguration *config, - EventLoop *loop); - - int run(const OptionsParser::Options &options); -private: - int capture(libcamera::FrameBufferAllocator *allocator); - - int queueRequest(libcamera::Request *request); - void requestComplete(libcamera::Request *request); - void processRequest(libcamera::Request *request); - - std::shared_ptr camera_; - libcamera::CameraConfiguration *config_; - - std::map streamName_; - BufferWriter *writer_; - uint64_t last_; - - EventLoop *loop_; - unsigned int queueCount_; - unsigned int captureCount_; - unsigned int captureLimit_; - bool printMetadata_; - - std::vector> requests_; -}; - -#endif /* __CAM_CAPTURE_H__ */ diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 70e9f62c..f71b65a2 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -13,7 +13,7 @@ #include #include -#include "capture.h" +#include "camera_session.h" #include "event_loop.h" #include "main.h" #include "options.h" @@ -363,8 +363,8 @@ int CamApp::run() } if (options_.isSet(OptCapture)) { - Capture capture(camera_, config_.get(), &loop_); - return capture.run(options_); + CameraSession session(camera_, config_.get(), &loop_); + return session.run(options_); } if (options_.isSet(OptMonitor)) { diff --git a/src/cam/meson.build b/src/cam/meson.build index 6234ed0a..1e90ee52 100644 --- a/src/cam/meson.build +++ b/src/cam/meson.build @@ -11,7 +11,7 @@ cam_enabled = true cam_sources = files([ 'buffer_writer.cpp', - 'capture.cpp', + 'camera_session.cpp', 'event_loop.cpp', 'main.cpp', 'options.cpp', -- cgit v1.2.1