Show a patch.

GET /api/patches/11730/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 11730,
    "url": "https://patchwork.libcamera.org/api/patches/11730/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/11730/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20210326124321.28617-2-david.plowman@raspberrypi.com>",
    "date": "2021-03-26T12:43:21",
    "name": "[libcamera-devel,v2,1/1] ipa: raspberrypi: Use CamHelpers to generalise sensor metadata parsing",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "01ec1e0e20382c9890562cee3d849350c67d24ab",
    "submitter": {
        "id": 42,
        "url": "https://patchwork.libcamera.org/api/people/42/?format=api",
        "name": "David Plowman",
        "email": "david.plowman@raspberrypi.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/11730/mbox/",
    "series": [
        {
            "id": 1839,
            "url": "https://patchwork.libcamera.org/api/series/1839/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1839",
            "date": "2021-03-26T12:43:20",
            "name": "Raspberry Pi generalised sensor metadata parsing",
            "version": 2,
            "mbox": "https://patchwork.libcamera.org/series/1839/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/11730/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/11730/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 6DA49C32EA\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 26 Mar 2021 12:43:27 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 61E3868D47;\n\tFri, 26 Mar 2021 13:43:26 +0100 (CET)",
            "from mail-ed1-x532.google.com (mail-ed1-x532.google.com\n\t[IPv6:2a00:1450:4864:20::532])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D5F0E602D7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 26 Mar 2021 13:43:24 +0100 (CET)",
            "by mail-ed1-x532.google.com with SMTP id z1so6148525edb.8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 26 Mar 2021 05:43:24 -0700 (PDT)",
            "from pi4-davidp.lan (plowpeople3.plus.com. [80.229.223.72])\n\tby smtp.gmail.com with ESMTPSA id\n\thy13sm3825296ejc.32.2021.03.26.05.43.23\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tFri, 26 Mar 2021 05:43:23 -0700 (PDT)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"G24WDFoA\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:mime-version:content-transfer-encoding;\n\tbh=KcM6dU6Xj5wKECPapYDSRGiokBguHzZjMrCTyytH2G0=;\n\tb=G24WDFoAG1Yp7bI8o1cbFuI/7Fvl1ZLW7KZVP+UzmFWpHIlBYEXo5AmLwuuecUo66w\n\tSCsWTKhCYqpDDvFHEnwJAX/TgfQYpi0BGoJ8QnucgeXWjCDBxmW077+x9ZJRb923gicC\n\tyfQ+tJtW5AOLfaIVBZFi9We7uPKO7ilBk3f/5PJp814fLvd0emWpMbHkFZ6ehiDiPlV9\n\t1Z6kMkhlZjVx/ECUiAGCxVuSUw9Bipq0MzrdpgIaYwzSw6zkBEtp8ZD6QyrHUYqoLm8N\n\tOGLPz0yhr0mJkrv2FYVjlSm39Iw6cYFmE2v/iWA1XWq87aZOQy1p30wsHbT4mkQkBxPN\n\t1zxA==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references:mime-version:content-transfer-encoding;\n\tbh=KcM6dU6Xj5wKECPapYDSRGiokBguHzZjMrCTyytH2G0=;\n\tb=fID3XRIYySn/MYcVsuujTz7sttTyxli/vziYixu55HTCU2IKaQN0KgMlKfCWD0+SIX\n\tLT6zU2E6JynQFXlPEQb4YdLajj6KGVob3uLkvlwXSR4uC5bwCfmBTW/wVX1DwIzrPcgL\n\tmPM2e992p6sM/q9caWX0WRFXmqKVWun7oSiulrWWvpigl7iHh+Nep/clZ0Go+dNg9rxA\n\tkY1iN/vN4pO+fW/MlNih2GhSaQkL0Q3o6E/UuGt8uUpHZ5C5kMcxEpwEcbaOLXWf9Am2\n\tP7YqJAeWqO7wiPqfNTPHZm1mWi8DTwjLHUuvBXa5BgaPDUor0kTh4z4He9OtnvnuTQdq\n\tL6BQ==",
        "X-Gm-Message-State": "AOAM531LV7zkd90THv14t6bJlJ0kOoZE8eOpTQHenNeLQ4GmylitnhmO\n\tH0nSyCc42FGbP+sJdBmLoi0XCo3uIY29Og==",
        "X-Google-Smtp-Source": "ABdhPJzk7QOWK9GWfO/0/xdaNeK4Rk8HFDDEFDbe5FVQQ82sAe8pSSjOPxKG6KrpHSG4IQCZMvUyRw==",
        "X-Received": "by 2002:a05:6402:440d:: with SMTP id\n\ty13mr15005115eda.316.1616762604159; \n\tFri, 26 Mar 2021 05:43:24 -0700 (PDT)",
        "From": "David Plowman <david.plowman@raspberrypi.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Fri, 26 Mar 2021 12:43:21 +0000",
        "Message-Id": "<20210326124321.28617-2-david.plowman@raspberrypi.com>",
        "X-Mailer": "git-send-email 2.20.1",
        "In-Reply-To": "<20210326124321.28617-1-david.plowman@raspberrypi.com>",
        "References": "<20210326124321.28617-1-david.plowman@raspberrypi.com>",
        "MIME-Version": "1.0",
        "Subject": "[libcamera-devel] [PATCH v2 1/1] ipa: raspberrypi: Use CamHelpers\n\tto generalise sensor metadata parsing",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "CamHelpers get virtual Prepare() and Process() methods, running just\nbefore and just after the ISP, just like Raspberry Pi Algorithms.\n\nThe Prepare() method is able to parse the register dumps in embedded\ndata buffers, and can be specialised to perform custom processing when\nnecessary.\n\nThe IPA itself only needs to call the new Prepare() and Process()\nmethods. It must fill in the DeviceStatus from the controls first, in\ncase the Prepare() method does not supply its own values.\n\nSigned-off-by: David Plowman <david.plowman@raspberrypi.com>\n---\n src/ipa/raspberrypi/cam_helper.cpp  | 51 ++++++++++++++++++\n src/ipa/raspberrypi/cam_helper.hpp  | 11 +++-\n src/ipa/raspberrypi/raspberrypi.cpp | 80 ++++++++++-------------------\n 3 files changed, 87 insertions(+), 55 deletions(-)",
    "diff": "diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp\nindex 0ae0baa0..5af73c9c 100644\n--- a/src/ipa/raspberrypi/cam_helper.cpp\n+++ b/src/ipa/raspberrypi/cam_helper.cpp\n@@ -17,6 +17,11 @@\n #include \"md_parser.hpp\"\n \n using namespace RPiController;\n+using namespace libcamera;\n+\n+namespace libcamera {\n+LOG_DECLARE_CATEGORY(IPARPI)\n+}\n \n static std::map<std::string, CamHelperCreateFunc> cam_helpers;\n \n@@ -45,6 +50,17 @@ CamHelper::~CamHelper()\n \tdelete parser_;\n }\n \n+void CamHelper::Prepare(const Span<uint8_t> &buffer,\n+\t\t\tMetadata &metadata)\n+{\n+\tparseEmbeddedData(buffer, metadata);\n+}\n+\n+void CamHelper::Process([[maybe_unused]] StatisticsPtr &stats,\n+\t\t\t[[maybe_unused]] Metadata &metadata)\n+{\n+}\n+\n uint32_t CamHelper::ExposureLines(double exposure_us) const\n {\n \tassert(initialized_);\n@@ -139,6 +155,41 @@ unsigned int CamHelper::MistrustFramesModeSwitch() const\n \treturn 0;\n }\n \n+void CamHelper::parseEmbeddedData(const Span<uint8_t> &buffer,\n+\t\t\t\t  Metadata &metadata)\n+{\n+\tif (buffer.size()) {\n+\t\tbool success = false;\n+\t\tuint32_t exposureLines, gainCode;\n+\n+\t\tparser_->SetBufferSize(buffer.size());\n+\t\tsuccess = parser_->Parse(buffer.data()) == MdParser::Status::OK &&\n+\t\t\t  parser_->GetExposureLines(exposureLines) == MdParser::Status::OK &&\n+\t\t\t  parser_->GetGainCode(gainCode) == MdParser::Status::OK;\n+\n+\t\t/*\n+\t\t * Overwrite the exposure/gain values in the DeviceStatus, as\n+\t\t * we know better. Fetch it first in case any other fields were\n+\t\t * set meaningfully.\n+\t\t */\n+\t\tstruct DeviceStatus deviceStatus;\n+\n+\t\tif (success &&\n+\t\t    metadata.Get(\"device.status\", deviceStatus) == 0) {\n+\t\t\tdeviceStatus.shutter_speed = Exposure(exposureLines);\n+\t\t\tdeviceStatus.analogue_gain = Gain(gainCode);\n+\n+\t\t\tLOG(IPARPI, Debug) << \"Metadata updated - Exposure : \"\n+\t\t\t\t\t   << deviceStatus.shutter_speed\n+\t\t\t\t\t   << \" Gain : \"\n+\t\t\t\t\t   << deviceStatus.analogue_gain;\n+\n+\t\t\tmetadata.Set(\"device.status\", deviceStatus);\n+\t\t} else\n+\t\t\tLOG(IPARPI, Error) << \"Embedded buffer parsing failed\";\n+\t}\n+}\n+\n RegisterCamHelper::RegisterCamHelper(char const *cam_name,\n \t\t\t\t     CamHelperCreateFunc create_func)\n {\ndiff --git a/src/ipa/raspberrypi/cam_helper.hpp b/src/ipa/raspberrypi/cam_helper.hpp\nindex 1b2d6eec..930ea39a 100644\n--- a/src/ipa/raspberrypi/cam_helper.hpp\n+++ b/src/ipa/raspberrypi/cam_helper.hpp\n@@ -8,7 +8,11 @@\n \n #include <string>\n \n+#include <libcamera/span.h>\n+\n #include \"camera_mode.h\"\n+#include \"controller/controller.hpp\"\n+#include \"controller/metadata.hpp\"\n #include \"md_parser.hpp\"\n \n #include \"libcamera/internal/v4l2_videodevice.h\"\n@@ -65,7 +69,9 @@ public:\n \tCamHelper(MdParser *parser, unsigned int frameIntegrationDiff);\n \tvirtual ~CamHelper();\n \tvoid SetCameraMode(const CameraMode &mode);\n-\tMdParser &Parser() const { return *parser_; }\n+\tvirtual void Prepare(const libcamera::Span<uint8_t> &buffer,\n+\t\t\t     Metadata &metadata);\n+\tvirtual void Process(StatisticsPtr &stats, Metadata &metadata);\n \tuint32_t ExposureLines(double exposure_us) const;\n \tdouble Exposure(uint32_t exposure_lines) const; // in us\n \tvirtual uint32_t GetVBlanking(double &exposure_us, double minFrameDuration,\n@@ -81,6 +87,9 @@ public:\n \tvirtual unsigned int MistrustFramesModeSwitch() const;\n \n protected:\n+\tvoid parseEmbeddedData(const libcamera::Span<uint8_t> &buffer,\n+\t\t\t       Metadata &metadata);\n+\n \tMdParser *parser_;\n \tCameraMode mode_;\n \ndiff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp\nindex 1c928b72..32ecbdcd 100644\n--- a/src/ipa/raspberrypi/raspberrypi.cpp\n+++ b/src/ipa/raspberrypi/raspberrypi.cpp\n@@ -101,9 +101,7 @@ private:\n \tvoid returnEmbeddedBuffer(unsigned int bufferId);\n \tvoid prepareISP(const ipa::RPi::ISPConfig &data);\n \tvoid reportMetadata();\n-\tbool parseEmbeddedData(unsigned int bufferId, struct DeviceStatus &deviceStatus);\n-\tvoid fillDeviceStatus(uint32_t exposureLines, uint32_t gainCode,\n-\t\t\t      struct DeviceStatus &deviceStatus);\n+\tvoid fillDeviceStatus(const ControlList &sensorControls);\n \tvoid processStats(unsigned int bufferId);\n \tvoid applyFrameDurations(double minFrameDuration, double maxFrameDuration);\n \tvoid applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls);\n@@ -895,35 +893,34 @@ void IPARPi::returnEmbeddedBuffer(unsigned int bufferId)\n \n void IPARPi::prepareISP(const ipa::RPi::ISPConfig &data)\n {\n-\tstruct DeviceStatus deviceStatus = {};\n-\tbool success = false;\n+\tSpan<uint8_t> embeddedBuffer;\n+\n+\trpiMetadata_.Clear();\n+\n+\tfillDeviceStatus(data.controls);\n \n \tif (data.embeddedBufferPresent) {\n \t\t/*\n \t\t * Pipeline handler has supplied us with an embedded data buffer,\n-\t\t * so parse it and extract the exposure and gain.\n+\t\t * we must pass it to the CamHelper for parsing.\n \t\t */\n-\t\tsuccess = parseEmbeddedData(data.embeddedBufferId, deviceStatus);\n-\n-\t\t/* Done with embedded data now, return to pipeline handler asap. */\n-\t\treturnEmbeddedBuffer(data.embeddedBufferId);\n+\t\tauto it = buffers_.find(data.embeddedBufferId);\n+\t\tASSERT(it != buffers_.end());\n+\t\tembeddedBuffer = it->second.maps()[0];\n \t}\n \n-\tif (!success) {\n-\t\t/*\n-\t\t * Pipeline handler has not supplied an embedded data buffer,\n-\t\t * or embedded data buffer parsing has failed for some reason,\n-\t\t * so pull the exposure and gain values from the control list.\n-\t\t */\n-\t\tint32_t exposureLines = data.controls.get(V4L2_CID_EXPOSURE).get<int32_t>();\n-\t\tint32_t gainCode = data.controls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();\n-\t\tfillDeviceStatus(exposureLines, gainCode, deviceStatus);\n-\t}\n+\t/*\n+\t * This may overwrite the DeviceStatus using values from the sensor\n+\t * metadata, and may also do additional custom processing.\n+\t */\n+\thelper_->Prepare(embeddedBuffer, rpiMetadata_);\n+\n+\t/* Done with embedded data now, return to pipeline handler asap. */\n+\tif (data.embeddedBufferPresent)\n+\t\treturnEmbeddedBuffer(data.embeddedBufferId);\n \n \tControlList ctrls(ispCtrls_);\n \n-\trpiMetadata_.Clear();\n-\trpiMetadata_.Set(\"device.status\", deviceStatus);\n \tcontroller_.Prepare(&rpiMetadata_);\n \n \t/* Lock the metadata buffer to avoid constant locks/unlocks. */\n@@ -973,41 +970,13 @@ void IPARPi::prepareISP(const ipa::RPi::ISPConfig &data)\n \t\tsetIspControls.emit(ctrls);\n }\n \n-bool IPARPi::parseEmbeddedData(unsigned int bufferId, struct DeviceStatus &deviceStatus)\n+void IPARPi::fillDeviceStatus(const ControlList &sensorControls)\n {\n-\tauto it = buffers_.find(bufferId);\n-\tif (it == buffers_.end()) {\n-\t\tLOG(IPARPI, Error) << \"Could not find embedded buffer!\";\n-\t\treturn false;\n-\t}\n-\n-\tSpan<uint8_t> mem = it->second.maps()[0];\n-\thelper_->Parser().SetBufferSize(mem.size());\n-\tRPiController::MdParser::Status status = helper_->Parser().Parse(mem.data());\n-\tif (status != RPiController::MdParser::Status::OK) {\n-\t\tLOG(IPARPI, Error) << \"Embedded Buffer parsing failed, error \" << status;\n-\t\treturn false;\n-\t} else {\n-\t\tuint32_t exposureLines, gainCode;\n-\t\tif (helper_->Parser().GetExposureLines(exposureLines) != RPiController::MdParser::Status::OK) {\n-\t\t\tLOG(IPARPI, Error) << \"Exposure time failed\";\n-\t\t\treturn false;\n-\t\t}\n-\n-\t\tif (helper_->Parser().GetGainCode(gainCode) != RPiController::MdParser::Status::OK) {\n-\t\t\tLOG(IPARPI, Error) << \"Gain failed\";\n-\t\t\treturn false;\n-\t\t}\n-\n-\t\tfillDeviceStatus(exposureLines, gainCode, deviceStatus);\n-\t}\n+\tstruct DeviceStatus deviceStatus = {};\n \n-\treturn true;\n-}\n+\tint32_t exposureLines = sensorControls.get(V4L2_CID_EXPOSURE).get<int32_t>();\n+\tint32_t gainCode = sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();\n \n-void IPARPi::fillDeviceStatus(uint32_t exposureLines, uint32_t gainCode,\n-\t\t\t      struct DeviceStatus &deviceStatus)\n-{\n \tdeviceStatus.shutter_speed = helper_->Exposure(exposureLines);\n \tdeviceStatus.analogue_gain = helper_->Gain(gainCode);\n \n@@ -1015,6 +984,8 @@ void IPARPi::fillDeviceStatus(uint32_t exposureLines, uint32_t gainCode,\n \t\t\t   << deviceStatus.shutter_speed\n \t\t\t   << \" Gain : \"\n \t\t\t   << deviceStatus.analogue_gain;\n+\n+\trpiMetadata_.Set(\"device.status\", deviceStatus);\n }\n \n void IPARPi::processStats(unsigned int bufferId)\n@@ -1028,6 +999,7 @@ void IPARPi::processStats(unsigned int bufferId)\n \tSpan<uint8_t> mem = it->second.maps()[0];\n \tbcm2835_isp_stats *stats = reinterpret_cast<bcm2835_isp_stats *>(mem.data());\n \tRPiController::StatisticsPtr statistics = std::make_shared<bcm2835_isp_stats>(*stats);\n+\thelper_->Process(statistics, rpiMetadata_);\n \tcontroller_.Process(statistics, &rpiMetadata_);\n \n \tstruct AgcStatus agcStatus;\n",
    "prefixes": [
        "libcamera-devel",
        "v2",
        "1/1"
    ]
}