From patchwork Wed Aug 4 12:43:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13198 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id CBE91C3236 for ; Wed, 4 Aug 2021 12:43:35 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5291568864; Wed, 4 Aug 2021 14:43:33 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="rxWQV+tH"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D9B376880F for ; Wed, 4 Aug 2021 14:43:30 +0200 (CEST) Received: from pendragon.lan (62-78-145-57.bb.dnainternet.fi [62.78.145.57]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7F603891 for ; Wed, 4 Aug 2021 14:43:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1628081010; bh=jnIVCh/flwUzBTO2THYqGdu5Q93/IXVv6jILDZLUldA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=rxWQV+tHS4nmQEaiLOBK2Brr3jd33lxLZ+RNmRh1IJqNB0yv6VCzFYmJl9Q3Ns4Dw eUr8LRZ9hEdJrqpp74+LjMxHmu5qt1bXZD+MI4fqEcVRIafD3ob4bvvUl6FIXMHyxQ pwvWm9u9V6vVzWesVolC9QRbITZdlhJwZP9uSlLk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 4 Aug 2021 15:43:09 +0300 Message-Id: <20210804124314.8044-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210804124314.8044-1-laurent.pinchart@ideasonboard.com> References: <20210804124314.8044-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" 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 Reviewed-by: Niklas Söderlund Reviewed-by: Kieran Bingham Reviewed-by: Umang Jain Reviewed-by: Paul Elder --- Changes since v2: - Write all buffers - Fix errno printing in writeBuffer() Changes since v1: - Print message if the file can't be opened --- src/cam/buffer_writer.cpp | 39 +++++++++++++++++++---- src/cam/buffer_writer.h | 17 +++++++--- src/cam/camera_session.cpp | 64 ++++++++++++++++++++++++++++++++------ src/cam/camera_session.h | 6 ++-- 4 files changed, 104 insertions(+), 22 deletions(-) diff --git a/src/cam/buffer_writer.cpp b/src/cam/buffer_writer.cpp index a7648a92fc92..2f4b2b02d3cb 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,15 @@ void BufferWriter::mapBuffer(FrameBuffer *buffer) } } -int BufferWriter::write(FrameBuffer *buffer, const std::string &streamName) +bool BufferWriter::processRequest(Request *request) +{ + for (auto [stream, buffer] : request->buffers()) + writeBuffer(stream, buffer); + + return true; +} + +void BufferWriter::writeBuffer(const Stream *stream, FrameBuffer *buffer) { std::string filename; size_t pos; @@ -58,7 +83,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()); } @@ -66,8 +91,12 @@ int BufferWriter::write(FrameBuffer *buffer, const std::string &streamName) fd = open(filename.c_str(), O_CREAT | O_WRONLY | (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; + if (fd == -1) { + ret = -errno; + std::cerr << "failed to open file " << filename << ": " + << strerror(-ret) << std::endl; + return; + } for (unsigned int i = 0; i < buffer->planes().size(); ++i) { const FrameBuffer::Plane &plane = buffer->planes()[i]; @@ -96,6 +125,4 @@ int BufferWriter::write(FrameBuffer *buffer, const std::string &streamName) } close(fd); - - return ret; } diff --git a/src/cam/buffer_writer.h b/src/cam/buffer_writer.h index 7626de42d369..32bb6ed5e045 100644 --- a/src/cam/buffer_writer.h +++ b/src/cam/buffer_writer.h @@ -10,20 +10,27 @@ #include #include -#include +#include -class BufferWriter +#include "frame_sink.h" + +class BufferWriter : public FrameSink { public: BufferWriter(const std::string &pattern = ""); ~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 processRequest(libcamera::Request *request) override; private: + void writeBuffer(const libcamera::Stream *stream, + libcamera::FrameBuffer *buffer); + + std::map streamNames_; std::string pattern_; std::map> mappedBuffers_; }; diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp index 0d49fc1ade83..f91b5234a082 100644 --- a/src/cam/camera_session.cpp +++ b/src/cam/camera_session.cpp @@ -13,6 +13,7 @@ #include #include +#include "buffer_writer.h" #include "camera_session.h" #include "event_loop.h" #include "main.h" @@ -162,9 +163,20 @@ int CameraSession::start() if (options_.isSet(OptFile)) { if (!options_[OptFile].toString().empty()) - writer_ = std::make_unique(options_[OptFile]); + sink_ = std::make_unique(options_[OptFile]); else - writer_ = std::make_unique(); + sink_ = std::make_unique(); + } + + if (sink_) { + ret = sink_->configure(*config_); + if (ret < 0) { + std::cout << "Failed to configure frame sink" + << std::endl; + return ret; + } + + sink_->requestProcessed.connect(this, &CameraSession::sinkRelease); } allocator_ = std::make_unique(camera_); @@ -178,7 +190,13 @@ void CameraSession::stop() if (ret) std::cout << "Failed to stop capture" << std::endl; - writer_.reset(); + if (sink_) { + ret = sink_->stop(); + if (ret) + std::cout << "Failed to stop frame sink" << std::endl; + } + + sink_.reset(); requests_.clear(); @@ -227,16 +245,26 @@ int CameraSession::startCapture() return ret; } - if (writer_) - writer_->mapBuffer(buffer.get()); + if (sink_) + sink_->mapBuffer(buffer.get()); } requests_.push_back(std::move(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; } @@ -245,6 +273,8 @@ int CameraSession::startCapture() if (ret < 0) { std::cerr << "Can't queue request" << std::endl; camera_->stop(); + if (sink_) + sink_->stop(); return ret; } } @@ -296,6 +326,8 @@ void CameraSession::processRequest(Request *request) fps = last_ != 0 && fps ? 1000000000.0 / fps : 0.0; last_ = ts; + bool requeue = true; + std::stringstream info; info << ts / 1000000000 << "." << std::setw(6) << std::setfill('0') << ts / 1000 % 1000000 @@ -304,11 +336,10 @@ void CameraSession::processRequest(Request *request) 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 + info << " " << streamName_[stream] << " seq: " << std::setw(6) << std::setfill('0') << metadata.sequence << " bytesused: "; @@ -318,9 +349,11 @@ void CameraSession::processRequest(Request *request) if (++nplane < metadata.planes.size()) info << "/"; } + } - if (writer_) - writer_->write(buffer, name); + if (sink_) { + if (!sink_->processRequest(request)) + requeue = false; } std::cout << info.str() << std::endl; @@ -340,6 +373,19 @@ void CameraSession::processRequest(Request *request) return; } + /* + * If the frame sink holds on the request, we'll requeue it later in the + * complete handler. + */ + if (!requeue) + return; + + request->reuse(Request::ReuseBuffers); + camera_->queueRequest(request); +} + +void CameraSession::sinkRelease(Request *request) +{ request->reuse(Request::ReuseBuffers); queueRequest(request); } diff --git a/src/cam/camera_session.h b/src/cam/camera_session.h index b0f50e7f998e..2ccc71977a99 100644 --- a/src/cam/camera_session.h +++ b/src/cam/camera_session.h @@ -21,9 +21,10 @@ #include #include -#include "buffer_writer.h" #include "options.h" +class FrameSink; + class CameraSession { public: @@ -53,13 +54,14 @@ private: int queueRequest(libcamera::Request *request); void requestComplete(libcamera::Request *request); void processRequest(libcamera::Request *request); + void sinkRelease(libcamera::Request *request); const OptionsParser::Options &options_; std::shared_ptr camera_; std::unique_ptr config_; std::map streamName_; - std::unique_ptr writer_; + std::unique_ptr sink_; unsigned int cameraIndex_; uint64_t last_;