Show a patch.

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

{
    "id": 12334,
    "url": "https://patchwork.libcamera.org/api/patches/12334/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/12334/",
    "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": "<20210521080530.37591-3-naush@raspberrypi.com>",
    "date": "2021-05-21T08:05:28",
    "name": "[libcamera-devel,v3,2/4] ipa: raspberrypi: Switch ipa and cam_helper to use utils::Duration",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "6a4e91b241b2b5a0db030cf2426d9e380505bb95",
    "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/12334/mbox/",
    "series": [
        {
            "id": 2040,
            "url": "https://patchwork.libcamera.org/api/series/2040/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=2040",
            "date": "2021-05-21T08:05:26",
            "name": "Switch RaspberryPi IPA to use std::chrono::duration",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/2040/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/12334/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/12334/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 33AACC31FB\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 21 May 2021 08:05:41 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A18296891D;\n\tFri, 21 May 2021 10:05:40 +0200 (CEST)",
            "from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com\n\t[IPv6:2a00:1450:4864:20::42a])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A437368918\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 21 May 2021 10:05:38 +0200 (CEST)",
            "by mail-wr1-x42a.google.com with SMTP id j14so18358441wrq.5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 21 May 2021 01:05:38 -0700 (PDT)",
            "from naush-laptop.pitowers.org\n\t([2a00:1098:3142:14:de31:dc1f:6be5:f58e])\n\tby smtp.gmail.com with ESMTPSA id\n\tq186sm5159176wme.20.2021.05.21.01.05.37\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tFri, 21 May 2021 01:05:37 -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=\"qK9TG0xW\"; 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=3WCddC6zsX8KlZiNW6g1AWGkuJB7QNaNyf+pcoYdXEE=;\n\tb=qK9TG0xW+MPhWfnaIWMY+1E+mktkdb3rijVuWn+4QOODq8AGI1SqE5+oxLgmxRDGx+\n\tff0q3luCBffEAl+270SdZnm9jp4qVe13Bztn6pve+tBAzNdyhDDFXQ3Am/qQIAZsGvb6\n\tbnYvwpZVR9LS3RTBfN+d3eFLYOS8EES53aQtL1IBwqHgcliV7ZCZ98rThnhuLUMQVEq/\n\tzQEcxtcFdppsbwH0qRCHiW7WplMOUjLy6XHsxpGpVho13dGIFU3CA/tEG/VJYOLs+1TF\n\tGErqRE4v0WSjzfcTsisWYRKdrcnCHHm9yX5whPt3/KCWi6iHnKUGDcUqgljk3ONJZ7Ik\n\t74pw==",
        "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=3WCddC6zsX8KlZiNW6g1AWGkuJB7QNaNyf+pcoYdXEE=;\n\tb=kEHcb0lKJngq9qTF9vTV8mD7dClBDcUubKsrTBs4FkwnVXkeTlVV/PD0ONu+POnZs6\n\tuLx2hM6AZbWUdcor4mOW632IXLiOVZ2PkfXF9TfvRNlvuM94G1LVU2yhOgbjD7hXOo4d\n\t8q+s31lY2VajD5AFJmIhRFtDL8Cr404QsbtUzvGV5qwllz0gZAokaSCqiWu2uJ2Q9d5v\n\tRLBZGLY8WJGkdjhy0ioSo0UHVtCKrjoOkygCiDWtE5Ei9fzSO+hHwT18m7bq+XUAmX66\n\tm0/nHmTXyD9I9a++OwWfQ3QmTF8/9toBH+Luqest+gkXaQYBAZ4jYlNTJuLdXNrjT2xV\n\t7bTg==",
        "X-Gm-Message-State": "AOAM531+yskTyCTzPiLLNVkhrL0yH3zjYcw3eEzrhnG/WbymOMfbWHpv\n\ta3nnWYRokzFBWgWa1dHzjaVv2ns+kbb8OQ==",
        "X-Google-Smtp-Source": "ABdhPJzfy1Ym/EO7FRTd+kCWyRF5wdMGghMcnqbgA5LM9iWyD+T8CS9MRUuu/d/K/uTQld8Kh6hd6g==",
        "X-Received": "by 2002:adf:ea0d:: with SMTP id\n\tq13mr8320020wrm.161.1621584338006; \n\tFri, 21 May 2021 01:05:38 -0700 (PDT)",
        "From": "Naushir Patuck <naush@raspberrypi.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Fri, 21 May 2021 09:05:28 +0100",
        "Message-Id": "<20210521080530.37591-3-naush@raspberrypi.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20210521080530.37591-1-naush@raspberrypi.com>",
        "References": "<20210521080530.37591-1-naush@raspberrypi.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH v3 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>\n---\n src/ipa/raspberrypi/cam_helper.cpp           | 19 +++---\n src/ipa/raspberrypi/cam_helper.hpp           | 12 ++--\n src/ipa/raspberrypi/controller/camera_mode.h |  6 +-\n src/ipa/raspberrypi/raspberrypi.cpp          | 65 +++++++++++---------\n 4 files changed, 57 insertions(+), 45 deletions(-)",
    "diff": "diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp\nindex 09917f3cc079..feb02d1806b2 100644\n--- a/src/ipa/raspberrypi/cam_helper.cpp\n+++ b/src/ipa/raspberrypi/cam_helper.cpp\n@@ -61,20 +61,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 const Duration &minFrameDuration,\n+\t\t\t\t const Duration &maxFrameDuration) const\n {\n \tuint32_t frameLengthMin, frameLengthMax, vblank;\n \tuint32_t exposureLines = ExposureLines(exposure);\n@@ -85,8 +86,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 +183,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..71ee15463a71 100644\n--- a/src/ipa/raspberrypi/cam_helper.hpp\n+++ b/src/ipa/raspberrypi/cam_helper.hpp\n@@ -15,10 +15,13 @@\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 \n+using libcamera::utils::Duration;\n+\n // The CamHelper class provides a number of facilities that anyone trying\n // to drive a camera will need to know, but which are not provided by the\n // standard driver framework. Specifically, it provides:\n@@ -72,10 +75,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(const Duration &exposure) const;\n+\tDuration Exposure(uint32_t exposure_lines) const;\n+\tvirtual uint32_t GetVBlanking(Duration &exposure,\n+\t\t\t\t      const Duration &minFrameDuration,\n+\t\t\t\t      const 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 52d91db282ea..e5d4c92a8e01 100644\n--- a/src/ipa/raspberrypi/raspberrypi.cpp\n+++ b/src/ipa/raspberrypi/raspberrypi.cpp\n@@ -55,19 +55,23 @@\n \n namespace libcamera {\n \n+using namespace std::literals::chrono_literals;\n+using utils::Duration;\n+using utils::operator<<;\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@@ -111,7 +115,8 @@ 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(const Duration &minFrameDuration,\n+\t\t\t\t const 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@@ -167,9 +172,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@@ -311,10 +316,10 @@ void IPARPi::setMode(const CameraSensorInfo &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@@ -387,7 +392,7 @@ int IPARPi::configure(const CameraSensorInfo &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@@ -862,7 +867,7 @@ void IPARPi::queueRequest(const ControlList &controls)\n \n \t\tcase controls::FRAME_DURATIONS: {\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@@ -937,9 +942,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@@ -1012,7 +1017,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@@ -1057,10 +1062,11 @@ 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(const Duration &minFrameDuration,\n+\t\t\t\t const 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@@ -1076,20 +1082,20 @@ void IPARPi::applyFrameDurations(double minFrameDuration, double maxFrameDuratio\n \n \t/* Return the validated limits via metadata. */\n \tlibcameraMetadata_.set(controls::FrameDurations,\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@@ -1097,9 +1103,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",
        "v3",
        "2/4"
    ]
}