From patchwork Tue May 19 03:25:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3814 X-Patchwork-Delegate: laurent.pinchart@ideasonboard.com Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8C15660E4B for ; Tue, 19 May 2020 05:25:19 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="uUE7DOw9"; dkim-atps=neutral Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2872A9CD for ; Tue, 19 May 2020 05:25:19 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1589858719; bh=bbo2GZaNhzdqroS5K4iCIOQID0bTa3t6YBlyQNjWN48=; h=From:To:Subject:Date:In-Reply-To:References:From; b=uUE7DOw9yGPR53o2YFJjaNGiJAAUyNJ7JvDSis7cCnArip2LbSO6/8vfayVr9CxMd qwiZoK6NtsdwH+6/vwu8zJEJjkSdy3NfXvFujQbRSwA2fTLbobXgrnY7BAK3ItFusA VtU9tVWvaH37/y7qH1TGt5CFLZB5RZF4TmAI8s3U= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Tue, 19 May 2020 06:25:00 +0300 Message-Id: <20200519032505.17307-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200519032505.17307-1-laurent.pinchart@ideasonboard.com> References: <20200519032505.17307-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 3/8] cam: Turn BufferWriter into a FrameSink X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 19 May 2020 03:25:21 -0000 Make the BufferWriter class inherit from FrameSink, and use the FrameSink API to manage it. This makes the code more generic, and will allow usage of other sinks. Signed-off-by: Laurent Pinchart --- src/cam/buffer_writer.cpp | 25 ++++++++++--- src/cam/buffer_writer.h | 13 ++++--- src/cam/capture.cpp | 76 ++++++++++++++++++++++++++++++++------- src/cam/capture.h | 6 ++-- 4 files changed, 97 insertions(+), 23 deletions(-) diff --git a/src/cam/buffer_writer.cpp b/src/cam/buffer_writer.cpp index c5a5eb46224a..2bec4b132155 100644 --- a/src/cam/buffer_writer.cpp +++ b/src/cam/buffer_writer.cpp @@ -13,6 +13,8 @@ #include #include +#include + #include "buffer_writer.h" using namespace libcamera; @@ -32,6 +34,21 @@ BufferWriter::~BufferWriter() mappedBuffers_.clear(); } +int BufferWriter::configure(const libcamera::CameraConfiguration &config) +{ + int ret = FrameSink::configure(config); + if (ret < 0) + return ret; + + streamNames_.clear(); + for (unsigned int index = 0; index < config.size(); ++index) { + const StreamConfiguration &cfg = config.at(index); + streamNames_[cfg.stream()] = "stream" + std::to_string(index); + } + + return 0; +} + void BufferWriter::mapBuffer(FrameBuffer *buffer) { for (const FrameBuffer::Plane &plane : buffer->planes()) { @@ -43,7 +60,7 @@ void BufferWriter::mapBuffer(FrameBuffer *buffer) } } -int BufferWriter::write(FrameBuffer *buffer, const std::string &streamName) +bool BufferWriter::consumeBuffer(const Stream *stream, FrameBuffer *buffer) { std::string filename; size_t pos; @@ -53,7 +70,7 @@ int BufferWriter::write(FrameBuffer *buffer, const std::string &streamName) pos = filename.find_first_of('#'); if (pos != std::string::npos) { std::stringstream ss; - ss << streamName << "-" << std::setw(6) + ss << streamNames_[stream] << "-" << std::setw(6) << std::setfill('0') << buffer->metadata().sequence; filename.replace(pos, 1, ss.str()); } @@ -62,7 +79,7 @@ int BufferWriter::write(FrameBuffer *buffer, const std::string &streamName) (pos == std::string::npos ? O_APPEND : O_TRUNC), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (fd == -1) - return -errno; + return true; for (const FrameBuffer::Plane &plane : buffer->planes()) { void *data = mappedBuffers_[plane.fd.fd()].first; @@ -84,5 +101,5 @@ int BufferWriter::write(FrameBuffer *buffer, const std::string &streamName) close(fd); - return ret; + return true; } diff --git a/src/cam/buffer_writer.h b/src/cam/buffer_writer.h index 47e26103e13e..5a5b176f73d8 100644 --- a/src/cam/buffer_writer.h +++ b/src/cam/buffer_writer.h @@ -12,18 +12,23 @@ #include -class BufferWriter +#include "frame_sink.h" + +class BufferWriter : public FrameSink { public: BufferWriter(const std::string &pattern = "frame-#.bin"); ~BufferWriter(); - void mapBuffer(libcamera::FrameBuffer *buffer); + int configure(const libcamera::CameraConfiguration &config) override; - int write(libcamera::FrameBuffer *buffer, - const std::string &streamName); + void mapBuffer(libcamera::FrameBuffer *buffer) override; + + bool consumeBuffer(const libcamera::Stream *stream, + libcamera::FrameBuffer *buffer) override; private: + std::map streamNames_; std::string pattern_; std::map> mappedBuffers_; }; diff --git a/src/cam/capture.cpp b/src/cam/capture.cpp index b7e06bcc9463..7fc9cba48892 100644 --- a/src/cam/capture.cpp +++ b/src/cam/capture.cpp @@ -11,6 +11,7 @@ #include #include +#include "buffer_writer.h" #include "capture.h" #include "main.h" @@ -18,7 +19,7 @@ using namespace libcamera; Capture::Capture(std::shared_ptr camera, CameraConfiguration *config, const StreamRoles &roles) - : camera_(camera), config_(config), roles_(roles), writer_(nullptr) + : camera_(camera), config_(config), roles_(roles), sink_(nullptr) { } @@ -47,20 +48,28 @@ int Capture::run(EventLoop *loop, const OptionsParser::Options &options) if (options.isSet(OptFile)) { if (!options[OptFile].toString().empty()) - writer_ = new BufferWriter(options[OptFile]); + sink_ = new BufferWriter(options[OptFile]); else - writer_ = new BufferWriter(); + sink_ = new BufferWriter(); } + if (sink_) { + ret = sink_->configure(*config_); + if (ret < 0) { + std::cout << "Failed to configure frame sink" + << std::endl; + return ret; + } + + sink_->bufferReleased.connect(this, &Capture::sinkRelease); + } FrameBufferAllocator *allocator = new FrameBufferAllocator(camera_); ret = capture(loop, allocator); - if (options.isSet(OptFile)) { - delete writer_; - writer_ = nullptr; - } + delete sink_; + sink_ = nullptr; delete allocator; @@ -110,16 +119,26 @@ int Capture::capture(EventLoop *loop, FrameBufferAllocator *allocator) return ret; } - if (writer_) - writer_->mapBuffer(buffer.get()); + if (sink_) + sink_->mapBuffer(buffer.get()); } requests.push_back(request); } + if (sink_) { + ret = sink_->start(); + if (ret) { + std::cout << "Failed to start frame sink" << std::endl; + return ret; + } + } + ret = camera_->start(); if (ret) { std::cout << "Failed to start capture" << std::endl; + if (sink_) + sink_->stop(); return ret; } @@ -128,6 +147,8 @@ int Capture::capture(EventLoop *loop, FrameBufferAllocator *allocator) if (ret < 0) { std::cerr << "Can't queue request" << std::endl; camera_->stop(); + if (sink_) + sink_->stop(); return ret; } } @@ -141,6 +162,12 @@ int Capture::capture(EventLoop *loop, FrameBufferAllocator *allocator) if (ret) std::cout << "Failed to stop capture" << std::endl; + if (sink_) { + ret = sink_->stop(); + if (ret) + std::cout << "Failed to stop frame sink" << std::endl; + } + return ret; } @@ -157,17 +184,18 @@ void Capture::requestComplete(Request *request) ? 1000.0 / fps : 0.0; last_ = now; + bool requeue = true; + std::stringstream info; info << "fps: " << std::fixed << std::setprecision(2) << fps; for (auto it = buffers.begin(); it != buffers.end(); ++it) { Stream *stream = it->first; FrameBuffer *buffer = it->second; - const std::string &name = streamName_[stream]; const FrameMetadata &metadata = buffer->metadata(); - info << " " << name + info << " " << streamName_[stream] << " seq: " << std::setw(6) << std::setfill('0') << metadata.sequence << " bytesused: "; @@ -178,12 +206,21 @@ void Capture::requestComplete(Request *request) info << "/"; } - if (writer_) - writer_->write(buffer, name); + if (sink_) { + if (!sink_->consumeBuffer(stream, buffer)) + requeue = false; + } } std::cout << info.str() << std::endl; + /* + * If the frame sink holds on the buffer, we'll requeue it later in the + * complete handler. + */ + if (!requeue) + return; + /* * Create a new request and populate it with one buffer for each * stream. @@ -203,3 +240,16 @@ void Capture::requestComplete(Request *request) camera_->queueRequest(request); } + +void Capture::sinkRelease(libcamera::FrameBuffer *buffer) +{ + Request *request = camera_->createRequest(); + if (!request) { + std::cerr << "Can't create request" << std::endl; + return; + } + + request->addBuffer(config_->at(0).stream(), buffer); + + camera_->queueRequest(request); +} diff --git a/src/cam/capture.h b/src/cam/capture.h index c0e697b831fb..3be1d98e4d3e 100644 --- a/src/cam/capture.h +++ b/src/cam/capture.h @@ -16,10 +16,11 @@ #include #include -#include "buffer_writer.h" #include "event_loop.h" #include "options.h" +class FrameSink; + class Capture { public: @@ -33,13 +34,14 @@ private: libcamera::FrameBufferAllocator *allocator); void requestComplete(libcamera::Request *request); + void sinkRelease(libcamera::FrameBuffer *buffer); std::shared_ptr camera_; libcamera::CameraConfiguration *config_; libcamera::StreamRoles roles_; std::map streamName_; - BufferWriter *writer_; + FrameSink *sink_; std::chrono::steady_clock::time_point last_; };