From patchwork Mon May 4 09:16:47 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Max Bretschneider X-Patchwork-Id: 26611 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 3F88EBDCB5 for ; Mon, 4 May 2026 09:16:53 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CB95963022; Mon, 4 May 2026 11:16:52 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=protonmail.com header.i=@protonmail.com header.b="SpCQyyQo"; dkim-atps=neutral Received: from mail-106104.protonmail.ch (mail-106104.protonmail.ch [79.135.106.104]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AA0A96301E for ; Mon, 4 May 2026 11:16:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; s=protonmail3; t=1777886209; x=1778145409; bh=fWWbMJxjuZVJPSG3I7OlCAMGN5MOvg3IzMT15kbxeCw=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=SpCQyyQoUwxILNlkUC5MykBiGYeoiSoJ6WutWbB3neJ57BdgO9LgyhwcHQztcqU9U u6bjSogM1u94Zr+MD0OEZqCuJjoxvrsRFNZmbjHjgujhND96/5B38oQu/lwQzGm4Ts VmOaMVTuIf2BChoA30CrgK7TUEMROGzmterdNCKPFYpRQNf3ea6Ho+9U1VMNfa8Lnx A1VWQe8brP9ktj7A9JaMWWPSAmzUIkorpQQz/1jNeb3MrlBv4BJkD0grqb/5E3hh5t 2b9iO7ZEne10ZSE3gmJoSVF8V/QzT8H2oR5iGfsvwnatk5AYUibU/3qtZojP6KBJnD 9pqT+pMgRYsjA== Date: Mon, 04 May 2026 09:16:47 +0000 To: libcamera-devel@lists.libcamera.org From: maxbretschneider@protonmail.com Cc: Max Bretschneider Subject: [PATCH 1/2] libcamera: pipeline: virtual: Add RawFrameGenerator Message-ID: <20260504091623.3354474-2-maxbretschneider@protonmail.com> In-Reply-To: <20260504091623.3354474-1-maxbretschneider@protonmail.com> References: <20260501105137.439519-1-maxbretschneider@protonmail.com> <20260504091623.3354474-1-maxbretschneider@protonmail.com> Feedback-ID: 122687743:user:proton X-Pm-Message-ID: f253ce13c6bdcce8634068b20fc26ded0f63eb82 MIME-Version: 1.0 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" From: Max Bretschneider Added a new FrameGenerator subclass which reads plain binary raw Bayer files from disk and copies them into the output FrameBuffers unchanged. No format conversion is performed. Input files must be plain binary sensor dumps without a header, and they must match the declared bayer_order and bit_depht. Modelled on ImageFrameGenerator. Signed-off-by: Max Bretschneider --- src/libcamera/pipeline/virtual/meson.build | 1 + .../pipeline/virtual/raw_frame_generator.cpp | 131 ++++++++++++++++++ .../pipeline/virtual/raw_frame_generator.h | 47 +++++++ 3 files changed, 179 insertions(+) create mode 100644 src/libcamera/pipeline/virtual/raw_frame_generator.cpp create mode 100644 src/libcamera/pipeline/virtual/raw_frame_generator.h diff --git a/src/libcamera/pipeline/virtual/meson.build b/src/libcamera/pipeline/virtual/meson.build index c8434593..c6576142 100644 --- a/src/libcamera/pipeline/virtual/meson.build +++ b/src/libcamera/pipeline/virtual/meson.build @@ -3,6 +3,7 @@ libcamera_internal_sources += files([ 'config_parser.cpp', 'image_frame_generator.cpp', + 'raw_frame_generator.cpp', 'test_pattern_generator.cpp', 'virtual.cpp', ]) diff --git a/src/libcamera/pipeline/virtual/raw_frame_generator.cpp b/src/libcamera/pipeline/virtual/raw_frame_generator.cpp new file mode 100644 index 00000000..e0be28cf --- /dev/null +++ b/src/libcamera/pipeline/virtual/raw_frame_generator.cpp @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2026, max.bretschneider@leica-geosystems.com + * + * Derived class of FrameGenerator for generating raw Bayer frames + */ + +#include "raw_frame_generator.h" + +#include +#include + +#include +#include + +#include + +#include "libcamera/internal/mapped_framebuffer.h" + +namespace libcamera { + +LOG_DECLARE_CATEGORY(Virtual) + +/* + * Factory function to create a RawFrameGenerator object. + * Read the raw Bayer frames from disk and store them in memory. + */ +std::unique_ptr +RawFrameGenerator::create(RawFrames &rawFrames) +{ + std::unique_ptr rawFrameGenerator = + std::make_unique(); + + /* + * For each file in the directory, load the raw frame + * and store it. No format conversion is performed, but + * raw Bayer bytes are stored as-is. + */ + for (const auto &path : rawFrames.files) { + File file(path); + if (!file.open(File::OpenModeFlag::ReadOnly)) { + LOG(Virtual, Error) << "Failed to open raw frame file " + << file.fileName() + << ": " << strerror(file.error()); + return nullptr; + } + + auto fileSize = file.size(); + auto buffer = std::make_unique(fileSize); + if (file.read({ buffer.get(), static_cast(fileSize) }) != fileSize) { + LOG(Virtual, Error) << "Failed to read raw frame file " + << file.fileName() + << ": " << strerror(file.error()); + return nullptr; + } + + rawFrameGenerator->framesDatas_.emplace_back( + RawFrameData{ std::move(buffer), static_cast(fileSize) }); + } + + ASSERT(!rawFrameGenerator->framesDatas_.empty()); + + return rawFrameGenerator; +} + +void RawFrameGenerator::configure(const Size & /*size*/) +{ + /* + * Raw frames cannot be scaled, the configured size is not used for + * processing but mismatches are caught in generateFrame(). + */ + frameIndex_ = 0; + parameter_ = 0; +} + +int RawFrameGenerator::generateFrame(const Size & /*size*/, const FrameBuffer *buffer) +{ + ASSERT(!framesDatas_.empty()); + + MappedFrameBuffer mappedFrameBuffer(buffer, + MappedFrameBuffer::MapFlag::Write); + + const auto &planes = mappedFrameBuffer.planes(); + + /* Loop only around the number of frames available */ + frameIndex_ %= framesDatas_.size(); + + const auto &frame = framesDatas_[frameIndex_]; + + /* + * Raw Bayer frames must exactly match the configured output size. + * They cannot be scaled to fit. + */ + if (frame.size != planes[0].size()) { + LOG(Virtual, Error) << "Raw frame size mismatch: file has " + << frame.size << " bytes, buffer expects " + << planes[0].size() << " bytes"; + return -EINVAL; + } + + memcpy(planes[0].data(), frame.data.get(), frame.size); + + /* Proceed to the next frame on every request */ + parameter_++; + if (parameter_ % frameRepeat == 0) { + frameIndex_++; + } + + return 0; +} + +/* + * \var RawFrameGenerator::frameRepeat + * \brief Number of frames to repeat before proceeding to the next frame + */ + +/* + * \var RawFrameGenerator::framesDatas_ + * \brief List of raw Bayer frame buffers loaded from disk + */ + +/* \var RawFrameGenerator::frameIndex_ + * \brief Index of the current frame in framesDatas_ + */ + +/* + * \var RawFrameGenerator::parameter_ + * \brief Counter used to implement frameRepeat behaviour + */ + +} /* namespace libcamera */ diff --git a/src/libcamera/pipeline/virtual/raw_frame_generator.h b/src/libcamera/pipeline/virtual/raw_frame_generator.h new file mode 100644 index 00000000..d711a47d --- /dev/null +++ b/src/libcamera/pipeline/virtual/raw_frame_generator.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2026, max.bretschneider@leica-geosystems.com + * + * Raw Bayer frame generator for the virtual pipeline handler + */ + +#pragma once + +#include +#include +#include +#include + +#include "frame_generator.h" + +namespace libcamera { + +/* Frame configuration provided by the config file */ +struct RawFrames { + std::vector files; + uint32_t cfaPattern; + unsigned int bitDepth; +}; + +class RawFrameGenerator : public FrameGenerator +{ +public: + static std::unique_ptr create(RawFrames &rawFrames); + +private: + static constexpr unsigned int frameRepeat = 1; /*advance every frame*/ + + struct RawFrameData { + std::unique_ptr data; + size_t size; + }; + + void configure(const Size &size) override; + int generateFrame(const Size &size, const FrameBuffer *buffer) override; + + std::vector framesDatas_; + unsigned int frameIndex_; + unsigned int parameter_; +}; + +} /* namespace libcamera */