Show a patch.

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

{
    "id": 12516,
    "url": "https://patchwork.libcamera.org/api/patches/12516/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/12516/",
    "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": "<20210608110335.4078551-3-naush@raspberrypi.com>",
    "date": "2021-06-08T11:03:33",
    "name": "[libcamera-devel,v6,2/4] ipa: raspberrypi: Switch ipa and cam_helper to use utils::Duration",
    "commit_ref": "caa753179c039a0ecbfef595c3179aac4bf044d5",
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "2c005c283672b6823a1248b25aee6619469e7dc6",
    "submitter": {
        "id": 34,
        "url": "https://patchwork.libcamera.org/api/people/34/?format=api",
        "name": "Naushir Patuck",
        "email": "naush@raspberrypi.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/12516/mbox/",
    "series": [
        {
            "id": 2110,
            "url": "https://patchwork.libcamera.org/api/series/2110/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=2110",
            "date": "2021-06-08T11:03:31",
            "name": "Switch RaspberryPi IPA to use std::chrono::duration",
            "version": 6,
            "mbox": "https://patchwork.libcamera.org/series/2110/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/12516/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/12516/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 97380BD22E\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  8 Jun 2021 11:03:46 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 599F96892E;\n\tTue,  8 Jun 2021 13:03:46 +0200 (CEST)",
            "from mail-wr1-x433.google.com (mail-wr1-x433.google.com\n\t[IPv6:2a00:1450:4864:20::433])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C584168930\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  8 Jun 2021 13:03:41 +0200 (CEST)",
            "by mail-wr1-x433.google.com with SMTP id r9so4394908wrz.10\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 08 Jun 2021 04:03:41 -0700 (PDT)",
            "from naush-laptop.pitowers.org\n\t([2a00:1098:3142:14:5aef:f665:51b0:d8c0])\n\tby smtp.gmail.com with ESMTPSA id\n\to129sm2639350wmo.22.2021.06.08.04.03.39\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 08 Jun 2021 04:03:40 -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=\"CeE0ZA1F\"; 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=yME5FCrCg19JnvRxSTvNgwfjfmnjYTDgYXpLunm2vv8=;\n\tb=CeE0ZA1FguQ6qXS0F/V3odVMFn1icFYvUccLM/s45oupHN+aLljVdIGGqwc/TPkmgd\n\tC4IRvtvUU8oB94kvNHQso1KzJirz8SPM/yQgH/NxKw4pMzQ0vIHS5CE3wrLZ/DSFEMVz\n\toMlzQ1rctOzdIBRlSMBAHi2Ag0KU9acMy+rjSBTKooDNwjou4kXFSAdq8WY5BrmplZFl\n\t2GQZIWbIC24yWMKKmFoh8bEhvTox99cL/knYHjAadL2d7w40lAIlCufQKG7UbjipYqqz\n\tbPp/3qrc7RanLonW16r1Rf2zqDFhcgIhmuwDULp5HGGfA7b2q1IadllKrNvSZwMaLssB\n\tE17g==",
        "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=yME5FCrCg19JnvRxSTvNgwfjfmnjYTDgYXpLunm2vv8=;\n\tb=Qw0FgCi/CRB0R6EOBeEoXlvcKZo1QUWRydBEKnOQE02YBqfiADMeCpyU0qZSxGUGIU\n\tcbX8LcOHL1Hid6dtuekVCvxBtmvsPLJZwnWWEM5B29QPB/wqeQKHMK8wNm+1e1sj0O7I\n\tIQ1b5meev7cSWNQ6Wgc+7bStFku9rKnZeAsH4Tmjxjeq0U2LaptunXRVhBK15diSHj5v\n\t0Rbxt+CNMEqjRj431QPkt/z8/G2bpHflCns4oHsapQ3xY2iCtWNT1SD3lUHZysSDiUfV\n\thBaROYnNfVXj5wt+mh2H9FGKca2HCzmJk/8UXgeDG12asR47LdaxuTP0n9BNJNKaiPis\n\tvOcg==",
        "X-Gm-Message-State": "AOAM533gJh1LPhMa5v7gAB3ttrmEZyeP/jsJeQwV6WifhXcTPAGbH8A9\n\tI0STtRUaOKN8wQMOOnULPCda2AdtkaGPLg==",
        "X-Google-Smtp-Source": "ABdhPJyA5WPC4XhgUz2IvCdTjIYWAfB2aYGe5yuR/r8v/db8YHADkLrY4OL39w6Y7JszIWIIOR1jrw==",
        "X-Received": "by 2002:a05:6000:551:: with SMTP id\n\tb17mr21855722wrf.32.1623150220749; \n\tTue, 08 Jun 2021 04:03:40 -0700 (PDT)",
        "From": "Naushir Patuck <naush@raspberrypi.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Tue,  8 Jun 2021 12:03:33 +0100",
        "Message-Id": "<20210608110335.4078551-3-naush@raspberrypi.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20210608110335.4078551-1-naush@raspberrypi.com>",
        "References": "<20210608110335.4078551-1-naush@raspberrypi.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH v6 2/4] ipa: raspberrypi: Switch ipa and\n\tcam_helper to use utils::Duration",
        "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>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Switch the ipa and cam_helper code to use libcamera::utils::Duration for\nall time based variables. This improves code readability and avoids\npossible errors when converting between time bases.\n\nSigned-off-by: Naushir Patuck <naush@raspberrypi.com>\nReviewed-by: David Plowman <david.plowman@raspberrypi.com>\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n src/ipa/raspberrypi/cam_helper.cpp           | 20 ++++---\n src/ipa/raspberrypi/cam_helper.hpp           | 10 ++--\n src/ipa/raspberrypi/controller/camera_mode.h |  6 +-\n src/ipa/raspberrypi/raspberrypi.cpp          | 62 ++++++++++----------\n 4 files changed, 53 insertions(+), 45 deletions(-)",
    "diff": "diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp\nindex 09917f3cc079..92a38007f038 100644\n--- a/src/ipa/raspberrypi/cam_helper.cpp\n+++ b/src/ipa/raspberrypi/cam_helper.cpp\n@@ -18,6 +18,7 @@\n \n using namespace RPiController;\n using namespace libcamera;\n+using libcamera::utils::Duration;\n \n namespace libcamera {\n LOG_DECLARE_CATEGORY(IPARPI)\n@@ -61,20 +62,21 @@ void CamHelper::Process([[maybe_unused]] StatisticsPtr &stats,\n {\n }\n \n-uint32_t CamHelper::ExposureLines(double exposure_us) const\n+uint32_t CamHelper::ExposureLines(const Duration exposure) const\n {\n \tassert(initialized_);\n-\treturn exposure_us * 1000.0 / mode_.line_length;\n+\treturn exposure / mode_.line_length;\n }\n \n-double CamHelper::Exposure(uint32_t exposure_lines) const\n+Duration CamHelper::Exposure(uint32_t exposure_lines) const\n {\n \tassert(initialized_);\n-\treturn exposure_lines * mode_.line_length / 1000.0;\n+\treturn exposure_lines * mode_.line_length;\n }\n \n-uint32_t CamHelper::GetVBlanking(double &exposure, double minFrameDuration,\n-\t\t\t\t double maxFrameDuration) const\n+uint32_t CamHelper::GetVBlanking(Duration &exposure,\n+\t\t\t\t Duration minFrameDuration,\n+\t\t\t\t Duration maxFrameDuration) const\n {\n \tuint32_t frameLengthMin, frameLengthMax, vblank;\n \tuint32_t exposureLines = ExposureLines(exposure);\n@@ -85,8 +87,8 @@ uint32_t CamHelper::GetVBlanking(double &exposure, double minFrameDuration,\n \t * minFrameDuration and maxFrameDuration are clamped by the caller\n \t * based on the limits for the active sensor mode.\n \t */\n-\tframeLengthMin = 1e3 * minFrameDuration / mode_.line_length;\n-\tframeLengthMax = 1e3 * maxFrameDuration / mode_.line_length;\n+\tframeLengthMin = minFrameDuration / mode_.line_length;\n+\tframeLengthMax = maxFrameDuration / mode_.line_length;\n \n \t/*\n \t * Limit the exposure to the maximum frame duration requested, and\n@@ -182,7 +184,7 @@ void CamHelper::parseEmbeddedData(Span<const uint8_t> buffer,\n \t\treturn;\n \t}\n \n-\tdeviceStatus.shutter_speed = Exposure(exposureLines);\n+\tdeviceStatus.shutter_speed = Exposure(exposureLines).get<std::micro>();\n \tdeviceStatus.analogue_gain = Gain(gainCode);\n \n \tLOG(IPARPI, Debug) << \"Metadata updated - Exposure : \"\ndiff --git a/src/ipa/raspberrypi/cam_helper.hpp b/src/ipa/raspberrypi/cam_helper.hpp\nindex a52f3f0b583c..f53f5c39b01c 100644\n--- a/src/ipa/raspberrypi/cam_helper.hpp\n+++ b/src/ipa/raspberrypi/cam_helper.hpp\n@@ -15,6 +15,7 @@\n #include \"controller/metadata.hpp\"\n #include \"md_parser.hpp\"\n \n+#include \"libcamera/internal/utils.h\"\n #include \"libcamera/internal/v4l2_videodevice.h\"\n \n namespace RPiController {\n@@ -72,10 +73,11 @@ public:\n \tvirtual void Prepare(libcamera::Span<const 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-\t\t\t\t      double maxFrameDuration) const;\n+\tuint32_t ExposureLines(libcamera::utils::Duration exposure) const;\n+\tlibcamera::utils::Duration Exposure(uint32_t exposure_lines) const;\n+\tvirtual uint32_t GetVBlanking(libcamera::utils::Duration &exposure,\n+\t\t\t\t      libcamera::utils::Duration minFrameDuration,\n+\t\t\t\t      libcamera::utils::Duration maxFrameDuration) const;\n \tvirtual uint32_t GainCode(double gain) const = 0;\n \tvirtual double Gain(uint32_t gain_code) const = 0;\n \tvirtual void GetDelays(int &exposure_delay, int &gain_delay,\ndiff --git a/src/ipa/raspberrypi/controller/camera_mode.h b/src/ipa/raspberrypi/controller/camera_mode.h\nindex 256438c931d9..2aa2335dcf90 100644\n--- a/src/ipa/raspberrypi/controller/camera_mode.h\n+++ b/src/ipa/raspberrypi/controller/camera_mode.h\n@@ -8,6 +8,8 @@\n \n #include <libcamera/transform.h>\n \n+#include \"libcamera/internal/utils.h\"\n+\n // Description of a \"camera mode\", holding enough information for control\n // algorithms to adapt their behaviour to the different modes of the camera,\n // including binning, scaling, cropping etc.\n@@ -33,8 +35,8 @@ struct CameraMode {\n \tdouble scale_x, scale_y;\n \t// scaling of the noise compared to the native sensor mode\n \tdouble noise_factor;\n-\t// line time in nanoseconds\n-\tdouble line_length;\n+\t// line time\n+\tlibcamera::utils::Duration line_length;\n \t// any camera transform *not* reflected already in the camera tuning\n \tlibcamera::Transform transform;\n \t// minimum and maximum fame lengths in units of lines\ndiff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp\nindex 0c4752ecffb6..33b316b90d16 100644\n--- a/src/ipa/raspberrypi/raspberrypi.cpp\n+++ b/src/ipa/raspberrypi/raspberrypi.cpp\n@@ -54,19 +54,22 @@\n \n namespace libcamera {\n \n+using namespace std::literals::chrono_literals;\n+using utils::Duration;\n+\n /* Configure the sensor with these values initially. */\n constexpr double DefaultAnalogueGain = 1.0;\n-constexpr unsigned int DefaultExposureTime = 20000;\n-constexpr double defaultMinFrameDuration = 1e6 / 30.0;\n-constexpr double defaultMaxFrameDuration = 1e6 / 0.01;\n+constexpr Duration DefaultExposureTime = 20.0ms;\n+constexpr Duration defaultMinFrameDuration = 1.0s / 30.0;\n+constexpr Duration defaultMaxFrameDuration = 100.0s;\n \n /*\n- * Determine the minimum allowable inter-frame duration (in us) to run the\n- * controller algorithms. If the pipeline handler provider frames at a rate\n- * higher than this, we rate-limit the controller Prepare() and Process() calls\n- * to lower than or equal to this rate.\n+ * Determine the minimum allowable inter-frame duration to run the controller\n+ * algorithms. If the pipeline handler provider frames at a rate higher than this,\n+ * we rate-limit the controller Prepare() and Process() calls to lower than or\n+ * equal to this rate.\n  */\n-constexpr double controllerMinFrameDuration = 1e6 / 60.0;\n+constexpr Duration controllerMinFrameDuration = 1.0s / 60.0;\n \n LOG_DEFINE_CATEGORY(IPARPI)\n \n@@ -110,7 +113,7 @@ private:\n \tvoid reportMetadata();\n \tvoid fillDeviceStatus(const ControlList &sensorControls);\n \tvoid processStats(unsigned int bufferId);\n-\tvoid applyFrameDurations(double minFrameDuration, double maxFrameDuration);\n+\tvoid applyFrameDurations(Duration minFrameDuration, Duration maxFrameDuration);\n \tvoid applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls);\n \tvoid applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls);\n \tvoid applyDG(const struct AgcStatus *dgStatus, ControlList &ctrls);\n@@ -166,9 +169,9 @@ private:\n \t/* Distinguish the first camera start from others. */\n \tbool firstStart_;\n \n-\t/* Frame duration (1/fps) limits, given in microseconds. */\n-\tdouble minFrameDuration_;\n-\tdouble maxFrameDuration_;\n+\t/* Frame duration (1/fps) limits. */\n+\tDuration minFrameDuration_;\n+\tDuration maxFrameDuration_;\n };\n \n int IPARPi::init(const IPASettings &settings, ipa::RPi::SensorConfig *sensorConfig)\n@@ -310,10 +313,10 @@ void IPARPi::setMode(const IPACameraSensorInfo &sensorInfo)\n \tmode_.noise_factor = sqrt(mode_.bin_x * mode_.bin_y);\n \n \t/*\n-\t * Calculate the line length in nanoseconds as the ratio between\n-\t * the line length in pixels and the pixel rate.\n+\t * Calculate the line length as the ratio between the line length in\n+\t * pixels and the pixel rate.\n \t */\n-\tmode_.line_length = 1e9 * sensorInfo.lineLength / sensorInfo.pixelRate;\n+\tmode_.line_length = sensorInfo.lineLength * (1.0s / sensorInfo.pixelRate);\n \n \t/*\n \t * Set the frame length limits for the mode to ensure exposure and\n@@ -386,7 +389,7 @@ int IPARPi::configure(const IPACameraSensorInfo &sensorInfo,\n \t\t/* Supply initial values for gain and exposure. */\n \t\tControlList ctrls(sensorCtrls_);\n \t\tAgcStatus agcStatus;\n-\t\tagcStatus.shutter_time = DefaultExposureTime;\n+\t\tagcStatus.shutter_time = DefaultExposureTime.get<std::micro>();\n \t\tagcStatus.analogue_gain = DefaultAnalogueGain;\n \t\tapplyAGC(&agcStatus, ctrls);\n \n@@ -861,7 +864,7 @@ void IPARPi::queueRequest(const ControlList &controls)\n \n \t\tcase controls::FRAME_DURATION_LIMITS: {\n \t\t\tauto frameDurations = ctrl.second.get<Span<const int64_t>>();\n-\t\t\tapplyFrameDurations(frameDurations[0], frameDurations[1]);\n+\t\t\tapplyFrameDurations(frameDurations[0] * 1.0us, frameDurations[1] * 1.0us);\n \t\t\tbreak;\n \t\t}\n \n@@ -936,9 +939,9 @@ void IPARPi::prepareISP(const ipa::RPi::ISPConfig &data)\n \t\treturnEmbeddedBuffer(data.embeddedBufferId);\n \n \t/* Allow a 10% margin on the comparison below. */\n-\tconstexpr double eps = controllerMinFrameDuration * 1e3 * 0.1;\n+\tDuration delta = (frameTimestamp - lastRunTimestamp_) * 1.0ns;\n \tif (lastRunTimestamp_ && frameCount_ > dropFrameCount_ &&\n-\t    frameTimestamp - lastRunTimestamp_ + eps < controllerMinFrameDuration * 1e3) {\n+\t    delta < controllerMinFrameDuration * 0.9) {\n \t\t/*\n \t\t * Ensure we merge the previous frame's metadata with the current\n \t\t * frame. This will not overwrite exposure/gain values for the\n@@ -1011,7 +1014,7 @@ void IPARPi::fillDeviceStatus(const ControlList &sensorControls)\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-\tdeviceStatus.shutter_speed = helper_->Exposure(exposureLines);\n+\tdeviceStatus.shutter_speed = helper_->Exposure(exposureLines).get<std::micro>();\n \tdeviceStatus.analogue_gain = helper_->Gain(gainCode);\n \n \tLOG(IPARPI, Debug) << \"Metadata - Exposure : \"\n@@ -1056,10 +1059,10 @@ void IPARPi::applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls)\n \t\t  static_cast<int32_t>(awbStatus->gain_b * 1000));\n }\n \n-void IPARPi::applyFrameDurations(double minFrameDuration, double maxFrameDuration)\n+void IPARPi::applyFrameDurations(Duration minFrameDuration, Duration maxFrameDuration)\n {\n-\tconst double minSensorFrameDuration = 1e-3 * mode_.min_frame_length * mode_.line_length;\n-\tconst double maxSensorFrameDuration = 1e-3 * mode_.max_frame_length * mode_.line_length;\n+\tconst Duration minSensorFrameDuration = mode_.min_frame_length * mode_.line_length;\n+\tconst Duration maxSensorFrameDuration = mode_.max_frame_length * mode_.line_length;\n \n \t/*\n \t * This will only be applied once AGC recalculations occur.\n@@ -1075,20 +1078,20 @@ void IPARPi::applyFrameDurations(double minFrameDuration, double maxFrameDuratio\n \n \t/* Return the validated limits via metadata. */\n \tlibcameraMetadata_.set(controls::FrameDurationLimits,\n-\t\t\t       { static_cast<int64_t>(minFrameDuration_),\n-\t\t\t\t static_cast<int64_t>(maxFrameDuration_) });\n+\t\t\t       { static_cast<int64_t>(minFrameDuration_.get<std::micro>()),\n+\t\t\t\t static_cast<int64_t>(maxFrameDuration_.get<std::micro>()) });\n \n \t/*\n \t * Calculate the maximum exposure time possible for the AGC to use.\n \t * GetVBlanking() will update maxShutter with the largest exposure\n \t * value possible.\n \t */\n-\tdouble maxShutter = std::numeric_limits<double>::max();\n+\tDuration maxShutter = Duration::max();\n \thelper_->GetVBlanking(maxShutter, minFrameDuration_, maxFrameDuration_);\n \n \tRPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n \t\tcontroller_.GetAlgorithm(\"agc\"));\n-\tagc->SetMaxShutter(maxShutter);\n+\tagc->SetMaxShutter(maxShutter.get<std::micro>());\n }\n \n void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)\n@@ -1096,9 +1099,8 @@ void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)\n \tint32_t gainCode = helper_->GainCode(agcStatus->analogue_gain);\n \n \t/* GetVBlanking might clip exposure time to the fps limits. */\n-\tdouble exposure = agcStatus->shutter_time;\n-\tint32_t vblanking = helper_->GetVBlanking(exposure, minFrameDuration_,\n-\t\t\t\t\t\t  maxFrameDuration_);\n+\tDuration exposure = agcStatus->shutter_time * 1.0us;\n+\tint32_t vblanking = helper_->GetVBlanking(exposure, minFrameDuration_, maxFrameDuration_);\n \tint32_t exposureLines = helper_->ExposureLines(exposure);\n \n \tLOG(IPARPI, Debug) << \"Applying AGC Exposure: \" << exposure\n",
    "prefixes": [
        "libcamera-devel",
        "v6",
        "2/4"
    ]
}