From patchwork Wed Mar 10 17:23:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 11546 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 2C3EDBD80C for ; Wed, 10 Mar 2021 17:23:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id F17C468AA7; Wed, 10 Mar 2021 18:23:54 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="ivpKtaf9"; dkim-atps=neutral Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3186F602E5 for ; Wed, 10 Mar 2021 18:23:53 +0100 (CET) Received: by mail-wm1-x329.google.com with SMTP id l22so7615588wme.1 for ; Wed, 10 Mar 2021 09:23:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=BX+KOMNqKVDvcOli4HMSqDwkdxigcXC2R2RWuWY/8TU=; b=ivpKtaf9MjDfX3HzWDSYtq1sKEjO8lRz5EVy5uXCqoBtx7HTsUT4MWP0iAsP/kwrpd rCfuu/+KnA6vr5EYOahhLAqcvVHSr4htK9ysKrpUYDO938p7RTGIzdMiJKBDu7pzMjJC bI5ClLsiOeHOxEtsrfjYSu82+jNJtf88lJKJq4OXcESHjc0Fuzv9RiMTPepXlLJG99JI 3T209gXAlInEaS5HTYUhQ3aoVcV6dplhB52ra/69+cSFHmCj2tSp3xmqgfXX5UhalOLi 34EPRw/wmfsWSV1PeIfBMfkiQE82tn8B5M2v4uvAqWhtLK5YVnzIKJdUbVzniX9iS3oX /fkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=BX+KOMNqKVDvcOli4HMSqDwkdxigcXC2R2RWuWY/8TU=; b=BcRXExdbWRb3JbnbXYmumI8zyMAdhBfCcC4acfVAYxbOM7CWt6XXFw+TIUfEFZ76co lr351R7jmi6WbyxOxnlfKzowcDcpIJalttklCczgUdHjj5gqfBZDQh2gCvtCdVqhxvnP TadcoQujq1rNZS1b7CuxFlYl3ueb1obUIJRsYTv6sA4TudaAgpJbXFSzsJD98OJlJ9Sn kMOcjksv63xtk5yXqglDjmII43Sz04+FSjAhtFAfvhOpETD56ZClTfP65FPzkQ5wla50 n88QMQ/8jJ2PEbuO4B2Mo9zlFn3+HtefemRpe7lEl29bxjgeDmR4OnyIYlwbmFGY8KZZ V7+Q== X-Gm-Message-State: AOAM532S6XrFU/wYZ2oNdEupWZvnAJsCU+s+RrYD28zbWj6Tja9WL9sb 5OeyXJ8DU52DVAB5iFoxcaVNOBwcBRoZxw== X-Google-Smtp-Source: ABdhPJwzwKMswcn/VySvM6twS0ZmXGei/v/tUXqhM/39u1ntNQginMBfakXCPFGE0RhEC65Az/uX7A== X-Received: by 2002:a05:600c:4ca9:: with SMTP id g41mr4440953wmp.150.1615397032663; Wed, 10 Mar 2021 09:23:52 -0800 (PST) Received: from pi4-davidp.lan (plowpeople3.plus.com. [80.229.223.72]) by smtp.gmail.com with ESMTPSA id i17sm18701599wrp.77.2021.03.10.09.23.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Mar 2021 09:23:52 -0800 (PST) From: David Plowman To: libcamera-devel@lists.libcamera.org Date: Wed, 10 Mar 2021 17:23:48 +0000 Message-Id: <20210310172348.4312-2-david.plowman@raspberrypi.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210310172348.4312-1-david.plowman@raspberrypi.com> References: <20210310172348.4312-1-david.plowman@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 1/1] ipa: raspberrypi: Use CamHelpers to generalise embedded data parsing 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" CamHelpers get virtual Prepare() and Process() methods, running just before and just after the ISP, just like Raspberry Pi Algorithms. The Prepare() method is able to parse the register dumps in embedded data buffers, and can be specialised to perform custom processing when necessary. The IPA itself no longer performs this register parsing, it just has to call the new Prepare() and Process() methods. --- src/ipa/raspberrypi/cam_helper.cpp | 49 ++++++++++++++++ src/ipa/raspberrypi/cam_helper.hpp | 14 ++++- src/ipa/raspberrypi/raspberrypi.cpp | 88 ++++++++--------------------- 3 files changed, 84 insertions(+), 67 deletions(-) diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp index 0ae0baa0..fc69f4cb 100644 --- a/src/ipa/raspberrypi/cam_helper.cpp +++ b/src/ipa/raspberrypi/cam_helper.cpp @@ -17,6 +17,11 @@ #include "md_parser.hpp" using namespace RPiController; +using namespace libcamera; + +namespace libcamera { +LOG_DECLARE_CATEGORY(IPARPI) +} static std::map cam_helpers; @@ -45,6 +50,17 @@ CamHelper::~CamHelper() delete parser_; } +void CamHelper::Prepare(const Span &buffer, + const ControlList &controls, Metadata &metadata) +{ + parseRegisters(buffer, controls, metadata); +} + +void CamHelper::Process([[maybe_unused]] StatisticsPtr &stats, + [[maybe_unused]] Metadata &metadata) +{ +} + uint32_t CamHelper::ExposureLines(double exposure_us) const { assert(initialized_); @@ -139,6 +155,39 @@ unsigned int CamHelper::MistrustFramesModeSwitch() const return 0; } +void CamHelper::parseRegisters(const Span &buffer, + const ControlList &controls, Metadata &metadata) +{ + struct DeviceStatus deviceStatus = {}; + bool success = false; + uint32_t exposureLines, gainCode; + + if (buffer.size()) { + parser_->SetBufferSize(buffer.size()); + success = parser_->Parse(buffer.data()) == MdParser::Status::OK && + parser_->GetExposureLines(exposureLines) == MdParser::Status::OK && + parser_->GetGainCode(gainCode) == MdParser::Status::OK; + + if (!success) + LOG(IPARPI, Error) << "Embedded buffer parsing failed"; + } + + if (!success) { + exposureLines = controls.get(V4L2_CID_EXPOSURE).get(); + gainCode = controls.get(V4L2_CID_ANALOGUE_GAIN).get(); + } + + deviceStatus.shutter_speed = Exposure(exposureLines); + deviceStatus.analogue_gain = Gain(gainCode); + + LOG(IPARPI, Debug) << "Metadata - Exposure : " + << deviceStatus.shutter_speed + << " Gain : " + << deviceStatus.analogue_gain; + + metadata.Set("device.status", deviceStatus); +} + RegisterCamHelper::RegisterCamHelper(char const *cam_name, CamHelperCreateFunc create_func) { diff --git a/src/ipa/raspberrypi/cam_helper.hpp b/src/ipa/raspberrypi/cam_helper.hpp index 1b2d6eec..ce5b82d2 100644 --- a/src/ipa/raspberrypi/cam_helper.hpp +++ b/src/ipa/raspberrypi/cam_helper.hpp @@ -8,8 +8,13 @@ #include +#include +#include + #include "camera_mode.h" +#include "controller/controller.hpp" #include "md_parser.hpp" +#include "controller/metadata.hpp" #include "libcamera/internal/v4l2_videodevice.h" @@ -65,7 +70,10 @@ public: CamHelper(MdParser *parser, unsigned int frameIntegrationDiff); virtual ~CamHelper(); void SetCameraMode(const CameraMode &mode); - MdParser &Parser() const { return *parser_; } + virtual void Prepare(const libcamera::Span &buffer, + const libcamera::ControlList &controls, + Metadata &metadata); + virtual void Process(StatisticsPtr &stats, Metadata &metadata); uint32_t ExposureLines(double exposure_us) const; double Exposure(uint32_t exposure_lines) const; // in us virtual uint32_t GetVBlanking(double &exposure_us, double minFrameDuration, @@ -81,6 +89,10 @@ public: virtual unsigned int MistrustFramesModeSwitch() const; protected: + void parseRegisters(const libcamera::Span &buffer, + const libcamera::ControlList &controls, + Metadata &metadata); + MdParser *parser_; CameraMode mode_; diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp index 7904225a..d699540a 100644 --- a/src/ipa/raspberrypi/raspberrypi.cpp +++ b/src/ipa/raspberrypi/raspberrypi.cpp @@ -103,9 +103,6 @@ private: void returnEmbeddedBuffer(unsigned int bufferId); void prepareISP(const ipa::RPi::ISPConfig &data); void reportMetadata(); - bool parseEmbeddedData(unsigned int bufferId, struct DeviceStatus &deviceStatus); - void fillDeviceStatus(uint32_t exposureLines, uint32_t gainCode, - struct DeviceStatus &deviceStatus); void processStats(unsigned int bufferId); void applyFrameDurations(double minFrameDuration, double maxFrameDuration); void applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls); @@ -913,35 +910,37 @@ void IPARPi::returnEmbeddedBuffer(unsigned int bufferId) void IPARPi::prepareISP(const ipa::RPi::ISPConfig &data) { - struct DeviceStatus deviceStatus = {}; - bool success = false; + Span embeddedBuffer; + bool returnEmbedded = false; + + rpiMetadata_.Clear(); if (data.embeddedBufferPresent) { /* * Pipeline handler has supplied us with an embedded data buffer, - * so parse it and extract the exposure and gain. + * we must pass it to the CamHelper for parsing. */ - success = parseEmbeddedData(data.embeddedBufferId, deviceStatus); - - /* Done with embedded data now, return to pipeline handler asap. */ - returnEmbeddedBuffer(data.embeddedBufferId); + auto it = buffers_.find(data.embeddedBufferId); + if (it == buffers_.end()) + LOG(IPARPI, Error) << "Could not find embedded buffer!"; + else { + embeddedBuffer = it->second.maps()[0]; + returnEmbedded = true; + } } - if (!success) { - /* - * Pipeline handler has not supplied an embedded data buffer, - * or embedded data buffer parsing has failed for some reason, - * so pull the exposure and gain values from the control list. - */ - int32_t exposureLines = data.controls.get(V4L2_CID_EXPOSURE).get(); - int32_t gainCode = data.controls.get(V4L2_CID_ANALOGUE_GAIN).get(); - fillDeviceStatus(exposureLines, gainCode, deviceStatus); - } + /* + * This will add the DeviceStatus to the metadata, and depending on the + * sensor, may do additional custom processing. + */ + helper_->Prepare(embeddedBuffer, data.controls, rpiMetadata_); + + /* Done with embedded data now, return to pipeline handler asap. */ + if (returnEmbedded) + returnEmbeddedBuffer(data.embeddedBufferId); ControlList ctrls(ispCtrls_); - rpiMetadata_.Clear(); - rpiMetadata_.Set("device.status", deviceStatus); controller_.Prepare(&rpiMetadata_); /* Lock the metadata buffer to avoid constant locks/unlocks. */ @@ -991,50 +990,6 @@ void IPARPi::prepareISP(const ipa::RPi::ISPConfig &data) setIspControls.emit(ctrls); } -bool IPARPi::parseEmbeddedData(unsigned int bufferId, struct DeviceStatus &deviceStatus) -{ - auto it = buffers_.find(bufferId); - if (it == buffers_.end()) { - LOG(IPARPI, Error) << "Could not find embedded buffer!"; - return false; - } - - Span mem = it->second.maps()[0]; - helper_->Parser().SetBufferSize(mem.size()); - RPiController::MdParser::Status status = helper_->Parser().Parse(mem.data()); - if (status != RPiController::MdParser::Status::OK) { - LOG(IPARPI, Error) << "Embedded Buffer parsing failed, error " << status; - return false; - } else { - uint32_t exposureLines, gainCode; - if (helper_->Parser().GetExposureLines(exposureLines) != RPiController::MdParser::Status::OK) { - LOG(IPARPI, Error) << "Exposure time failed"; - return false; - } - - if (helper_->Parser().GetGainCode(gainCode) != RPiController::MdParser::Status::OK) { - LOG(IPARPI, Error) << "Gain failed"; - return false; - } - - fillDeviceStatus(exposureLines, gainCode, deviceStatus); - } - - return true; -} - -void IPARPi::fillDeviceStatus(uint32_t exposureLines, uint32_t gainCode, - struct DeviceStatus &deviceStatus) -{ - deviceStatus.shutter_speed = helper_->Exposure(exposureLines); - deviceStatus.analogue_gain = helper_->Gain(gainCode); - - LOG(IPARPI, Debug) << "Metadata - Exposure : " - << deviceStatus.shutter_speed - << " Gain : " - << deviceStatus.analogue_gain; -} - void IPARPi::processStats(unsigned int bufferId) { auto it = buffers_.find(bufferId); @@ -1046,6 +1001,7 @@ void IPARPi::processStats(unsigned int bufferId) Span mem = it->second.maps()[0]; bcm2835_isp_stats *stats = reinterpret_cast(mem.data()); RPiController::StatisticsPtr statistics = std::make_shared(*stats); + helper_->Process(statistics, rpiMetadata_); controller_.Process(statistics, &rpiMetadata_); struct AgcStatus agcStatus;