From patchwork Mon Mar 22 16:01: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: 11642 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 94C35BD80C for ; Mon, 22 Mar 2021 16:01:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 15B6768D68; Mon, 22 Mar 2021 17:01:56 +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="OawSeLyM"; dkim-atps=neutral Received: from mail-ed1-x52d.google.com (mail-ed1-x52d.google.com [IPv6:2a00:1450:4864:20::52d]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A822D68D50 for ; Mon, 22 Mar 2021 17:01:54 +0100 (CET) Received: by mail-ed1-x52d.google.com with SMTP id w18so20043001edc.0 for ; Mon, 22 Mar 2021 09:01:54 -0700 (PDT) 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=pD/RaFltnJBk6qmI17FVeiIDOTuKBqzE34+A60oi21o=; b=OawSeLyMK+CBHvMieV+INSvNFUxYmLTApNTQV9lbFvncGodFozQEiHop7AgsK2JvnD bmyP/71xxZ80/hOUQ9FWvxqhVkRO6GBfVRgnfYCeiZlZz79izEER/2zXhD6wr5eYIkML opNTx3G2m27oMF3iH4QQ7fF48FlstZ1bUaT2oaVTj8m2HNwaT5ykPwNKiWYzxWH/yMpf yV+mML7Z0uWm3bUvLIM8LU3tVnaWA4VrraxXaUhktnB9d/Mu2jhjFfT55Tou0tni5x02 SNaumKPqHzLj68ZsBitbQO0Syk3iHmshBUJKGmlCNeUCnjia+AxAOVC9g4F7c540nqDa FXew== 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=pD/RaFltnJBk6qmI17FVeiIDOTuKBqzE34+A60oi21o=; b=V5ppznz7OQblG1WsubMfyZlvuMuNOwPqLzyWiClu1ahOoS8U0LO5O7WdrmiZDFja8k 3UUdP9sfR/FoRGBMuYXt/+O8/KZaZkrv/hTx3DoLdon2mlybFROQctRXaA7NAaq65ybY o2D/rTXlD/AV7CJ8FRvVwq3FT1ln/ypVkDbyMCtwb5y5E4e/QsncR76uJSZgx/3+8eHF UNr8hsfwMHMKelcmSitUZGH20aLmOofNOBleRyx96KhIQmE+XBBb1qL5Gi85oQL9CyaO 9V9SSv74YNVEJQRBFel3DFRdkfpHBvtw+GfQ/YUr2de5gDNvSjeVGineHcZqABD+gBOn 3rYA== X-Gm-Message-State: AOAM533xiw5oaRXr+msXrF9g+inz6qqUXqA0z4X8NyevSxCDVOzScCrB O6+cN2JF6GqtrdVJNcaTj5BX0OQ0mDSCGQ== X-Google-Smtp-Source: ABdhPJzeIeE+IJC5vNYz7bvDTFHIuDxbdlaGXbn1VWZdhuJEkWC5pADX0zrD7Bg5Cf2dj+gqZR3iMA== X-Received: by 2002:a50:cdd1:: with SMTP id h17mr275692edj.178.1616428913990; Mon, 22 Mar 2021 09:01:53 -0700 (PDT) Received: from pi4-davidp.lan (plowpeople3.plus.com. [80.229.223.72]) by smtp.gmail.com with ESMTPSA id h17sm11554502eds.26.2021.03.22.09.01.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Mar 2021 09:01:53 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Date: Mon, 22 Mar 2021 16:01:48 +0000 Message-Id: <20210322160148.32291-2-david.plowman@raspberrypi.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210322160148.32291-1-david.plowman@raspberrypi.com> References: <20210322160148.32291-1-david.plowman@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 1/1] ipa: raspberrypi: Use CamHelpers to generalise sensor metadata 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 only needs to call the new Prepare() and Process() methods, and to supply exposure/gain values from the controls when the CamHelper does not. Signed-off-by: David Plowman Reviewed-by: Naushir Patuck --- src/ipa/raspberrypi/cam_helper.cpp | 44 +++++++++++++++ src/ipa/raspberrypi/cam_helper.hpp | 11 +++- src/ipa/raspberrypi/raspberrypi.cpp | 83 ++++++++++------------------- 3 files changed, 83 insertions(+), 55 deletions(-) diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp index 0ae0baa0..ce6482ba 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, + Metadata &metadata) +{ + parseEmbeddedData(buffer, 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,34 @@ unsigned int CamHelper::MistrustFramesModeSwitch() const return 0; } +void CamHelper::parseEmbeddedData(const Span &buffer, + Metadata &metadata) +{ + if (buffer.size()) { + struct DeviceStatus deviceStatus = {}; + bool success = false; + uint32_t exposureLines, gainCode; + + 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) { + 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); + } else + LOG(IPARPI, Error) << "Embedded buffer parsing failed"; + } +} + 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..930ea39a 100644 --- a/src/ipa/raspberrypi/cam_helper.hpp +++ b/src/ipa/raspberrypi/cam_helper.hpp @@ -8,7 +8,11 @@ #include +#include + #include "camera_mode.h" +#include "controller/controller.hpp" +#include "controller/metadata.hpp" #include "md_parser.hpp" #include "libcamera/internal/v4l2_videodevice.h" @@ -65,7 +69,9 @@ 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, + 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 +87,9 @@ public: virtual unsigned int MistrustFramesModeSwitch() const; protected: + void parseEmbeddedData(const libcamera::Span &buffer, + Metadata &metadata); + MdParser *parser_; CameraMode mode_; diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp index 7904225a..e08b47c0 100644 --- a/src/ipa/raspberrypi/raspberrypi.cpp +++ b/src/ipa/raspberrypi/raspberrypi.cpp @@ -103,8 +103,7 @@ 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, + void fillDeviceStatus(const ControlList &sensorControls, struct DeviceStatus &deviceStatus); void processStats(unsigned int bufferId); void applyFrameDurations(double minFrameDuration, double maxFrameDuration); @@ -913,35 +912,37 @@ void IPARPi::returnEmbeddedBuffer(unsigned int bufferId) void IPARPi::prepareISP(const ipa::RPi::ISPConfig &data) { - struct DeviceStatus deviceStatus = {}; - bool success = false; + Span embeddedBuffer; + + 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); + ASSERT(it != buffers_.end()); + embeddedBuffer = it->second.maps()[0]; } - 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 may add the DeviceStatus to the metadata, and depending on the + * sensor, may do additional custom processing. + */ + helper_->Prepare(embeddedBuffer, rpiMetadata_); + + /* Add DeviceStatus metadata if helper_->Prepare() didn't. */ + DeviceStatus deviceStatus = {}; + if (rpiMetadata_.Get("device.status", deviceStatus)) + fillDeviceStatus(data.controls, deviceStatus); + + /* Done with embedded data now, return to pipeline handler asap. */ + if (data.embeddedBufferPresent) + 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,41 +992,12 @@ 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, +void IPARPi::fillDeviceStatus(const ControlList &sensorControls, struct DeviceStatus &deviceStatus) { + int32_t exposureLines = sensorControls.get(V4L2_CID_EXPOSURE).get(); + int32_t gainCode = sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get(); + deviceStatus.shutter_speed = helper_->Exposure(exposureLines); deviceStatus.analogue_gain = helper_->Gain(gainCode); @@ -1033,6 +1005,8 @@ void IPARPi::fillDeviceStatus(uint32_t exposureLines, uint32_t gainCode, << deviceStatus.shutter_speed << " Gain : " << deviceStatus.analogue_gain; + + rpiMetadata_.Set("device.status", deviceStatus); } void IPARPi::processStats(unsigned int bufferId) @@ -1046,6 +1020,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;