Patch Detail
Show a patch.
GET /api/1.1/patches/12517/?format=api
{ "id": 12517, "url": "https://patchwork.libcamera.org/api/1.1/patches/12517/?format=api", "web_url": "https://patchwork.libcamera.org/patch/12517/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/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-5-naush@raspberrypi.com>", "date": "2021-06-08T11:03:35", "name": "[libcamera-devel,v6,4/4] ipa: raspberrypi: Switch the AGC/Lux code to use utils::Duration", "commit_ref": "6914fc487f6a861fcce295f37ffe8a5079921b0d", "pull_url": null, "state": "accepted", "archived": false, "hash": "91e859a3058eb299b6f785fc858c38b03f58df1c", "submitter": { "id": 34, "url": "https://patchwork.libcamera.org/api/1.1/people/34/?format=api", "name": "Naushir Patuck", "email": "naush@raspberrypi.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/12517/mbox/", "series": [ { "id": 2110, "url": "https://patchwork.libcamera.org/api/1.1/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/12517/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/12517/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 15646C320B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 8 Jun 2021 11:03:47 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id BD933602A7;\n\tTue, 8 Jun 2021 13:03:46 +0200 (CEST)", "from mail-wr1-x435.google.com (mail-wr1-x435.google.com\n\t[IPv6:2a00:1450:4864:20::435])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 05554602A1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 8 Jun 2021 13:03:43 +0200 (CEST)", "by mail-wr1-x435.google.com with SMTP id o3so2707753wri.8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 08 Jun 2021 04:03:43 -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.41\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tTue, 08 Jun 2021 04:03:41 -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=\"Hcd5BWqO\"; 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=P+wTgJIbLFrWSOSfwmz0uzLj+lv+deYhjU5AKmwm3M8=;\n\tb=Hcd5BWqOjylP2MNtXePGcTnuTaOv1In3XQvRIwQ3kftlz2l5CF3zpLnEleSrEF/uLa\n\tdqNsXXs1dCXsKTlvV7lPGo3hSH1BoFBvuhDNcztmS+f34VPzZBU+ZljXaZI4iU6DUCPd\n\tsv/x/ppfCkCaQZUyICwhtLuySI0tmAz9kAkZqcTgSAwYHOwvUgWXY7jCoEX885Q8GE53\n\tsUj7aQusMV6i0ExYs1VV5+b6QHhISCVOp9dLjwjKNyb3NH1nc8sI3+E1oJxUTjmX/gTa\n\t6FcxCFQ34eYwntcgzJ14Otep/VPFTZiFC2oaFJLgzrjnJ70u0kGNsDonVixgsXxLli1/\n\tIrsA==", "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=P+wTgJIbLFrWSOSfwmz0uzLj+lv+deYhjU5AKmwm3M8=;\n\tb=cOB5OcWkx87nYAzR3LrNGiQKlor0nnyjLUFWGxxCeuZV+FspyVCTo6IYynFvVDU6cm\n\t5sk4r9+EgBQnyT/IfCDl4CZtjot+LI75O/Ct97hUy5vx5Ck8CaHmbqrXg1HBXULJK1b5\n\tz27KfmiE6kTlFfrNJZ61y7v5Sco+1pPEV0aiVfcBc5yAX9akKdf316ob9fVGQIDDSVIX\n\tX7ukwW9dP13ixuKocLXVoKN3CblKoaFzM2Gt3S+1MHpxplSxPkFsbuhQVEiZCPiA2eMn\n\tdc8uG3XobzKybN0Wmnbrrauxh3VtwFIXhAYHhLHa7PD4yvHhJOOTL3/HGFOSL6sDocXX\n\tSXWw==", "X-Gm-Message-State": "AOAM531kaeOrQdKMKpp3EOrFDoc3jZAyDVBHoP1+OePE0D91SopLOzQ4\n\tyKVccYwpWPzyia11S5LDHeQXksbaWbNGtQ==", "X-Google-Smtp-Source": "ABdhPJz4tbycgOA8QTg734yYABOSdsA5MGKYcARxY6fgPHv01Nnwrce2NUk5Wzz8MLc+pWZaZaVBRg==", "X-Received": "by 2002:a05:6000:110e:: with SMTP id\n\tz14mr22476434wrw.235.1623150222228; \n\tTue, 08 Jun 2021 04:03:42 -0700 (PDT)", "From": "Naushir Patuck <naush@raspberrypi.com>", "To": "libcamera-devel@lists.libcamera.org", "Date": "Tue, 8 Jun 2021 12:03:35 +0100", "Message-Id": "<20210608110335.4078551-5-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 4/4] ipa: raspberrypi: Switch the\n\tAGC/Lux code 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": "Convert the core AGC and Lux controller code to use\nutils::Duration for all exposure time related variables and\ncalculations.\n\nConvert the exposure/shutter time fields in AgcStatus and DeviceStatus\nto use utils::Duration.\n\nSigned-off-by: Naushir Patuck <naush@raspberrypi.com>\nReviewed-by: David Plowman <david.plowman@raspberrypi.com>\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n---\n src/ipa/raspberrypi/cam_helper.cpp | 2 +-\n src/ipa/raspberrypi/controller/agc_status.h | 12 +--\n .../raspberrypi/controller/device_status.h | 6 +-\n src/ipa/raspberrypi/controller/rpi/agc.cpp | 82 ++++++++++---------\n src/ipa/raspberrypi/controller/rpi/agc.hpp | 28 ++++---\n src/ipa/raspberrypi/controller/rpi/lux.cpp | 19 +++--\n src/ipa/raspberrypi/controller/rpi/lux.hpp | 4 +-\n src/ipa/raspberrypi/raspberrypi.cpp | 13 +--\n 8 files changed, 93 insertions(+), 73 deletions(-)", "diff": "diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp\nindex 92a38007f038..062e94c4fef3 100644\n--- a/src/ipa/raspberrypi/cam_helper.cpp\n+++ b/src/ipa/raspberrypi/cam_helper.cpp\n@@ -184,7 +184,7 @@ void CamHelper::parseEmbeddedData(Span<const uint8_t> buffer,\n \t\treturn;\n \t}\n \n-\tdeviceStatus.shutter_speed = Exposure(exposureLines).get<std::micro>();\n+\tdeviceStatus.shutter_speed = Exposure(exposureLines);\n \tdeviceStatus.analogue_gain = Gain(gainCode);\n \n \tLOG(IPARPI, Debug) << \"Metadata updated - Exposure : \"\ndiff --git a/src/ipa/raspberrypi/controller/agc_status.h b/src/ipa/raspberrypi/controller/agc_status.h\nindex 10381c90a313..5d50e177f0dc 100644\n--- a/src/ipa/raspberrypi/controller/agc_status.h\n+++ b/src/ipa/raspberrypi/controller/agc_status.h\n@@ -6,6 +6,8 @@\n */\n #pragma once\n \n+#include \"libcamera/internal/utils.h\"\n+\n // The AGC algorithm should post the following structure into the image's\n // \"agc.status\" metadata.\n \n@@ -18,17 +20,17 @@ extern \"C\" {\n // ignored until then.\n \n struct AgcStatus {\n-\tdouble total_exposure_value; // value for all exposure and gain for this image\n-\tdouble target_exposure_value; // (unfiltered) target total exposure AGC is aiming for\n-\tdouble shutter_time;\n+\tlibcamera::utils::Duration total_exposure_value; // value for all exposure and gain for this image\n+\tlibcamera::utils::Duration target_exposure_value; // (unfiltered) target total exposure AGC is aiming for\n+\tlibcamera::utils::Duration shutter_time;\n \tdouble analogue_gain;\n \tchar exposure_mode[32];\n \tchar constraint_mode[32];\n \tchar metering_mode[32];\n \tdouble ev;\n-\tdouble flicker_period;\n+\tlibcamera::utils::Duration flicker_period;\n \tint floating_region_enable;\n-\tdouble fixed_shutter;\n+\tlibcamera::utils::Duration fixed_shutter;\n \tdouble fixed_analogue_gain;\n \tdouble digital_gain;\n \tint locked;\ndiff --git a/src/ipa/raspberrypi/controller/device_status.h b/src/ipa/raspberrypi/controller/device_status.h\nindex aa08608b5d40..131b4cd344ee 100644\n--- a/src/ipa/raspberrypi/controller/device_status.h\n+++ b/src/ipa/raspberrypi/controller/device_status.h\n@@ -6,6 +6,8 @@\n */\n #pragma once\n \n+#include \"libcamera/internal/utils.h\"\n+\n // Definition of \"device metadata\" which stores things like shutter time and\n // analogue gain that downstream control algorithms will want to know.\n \n@@ -14,8 +16,8 @@ extern \"C\" {\n #endif\n \n struct DeviceStatus {\n-\t// time shutter is open, in microseconds\n-\tdouble shutter_speed;\n+\t// time shutter is open\n+\tlibcamera::utils::Duration shutter_speed;\n \tdouble analogue_gain;\n \t// 1.0/distance-in-metres, or 0 if unknown\n \tdouble lens_position;\ndiff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp\nindex fd3359a77958..55e80ac74ae1 100644\n--- a/src/ipa/raspberrypi/controller/rpi/agc.cpp\n+++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp\n@@ -56,19 +56,26 @@ read_metering_modes(std::map<std::string, AgcMeteringMode> &metering_modes,\n \treturn first;\n }\n \n-static int read_double_list(std::vector<double> &list,\n-\t\t\t boost::property_tree::ptree const ¶ms)\n+static int read_list(std::vector<double> &list,\n+\t\t boost::property_tree::ptree const ¶ms)\n {\n \tfor (auto &p : params)\n \t\tlist.push_back(p.second.get_value<double>());\n \treturn list.size();\n }\n \n+static int read_list(std::vector<Duration> &list,\n+\t\t boost::property_tree::ptree const ¶ms)\n+{\n+\tfor (auto &p : params)\n+\t\tlist.push_back(p.second.get_value<double>() * 1us);\n+\treturn list.size();\n+}\n+\n void AgcExposureMode::Read(boost::property_tree::ptree const ¶ms)\n {\n-\tint num_shutters =\n-\t\tread_double_list(shutter, params.get_child(\"shutter\"));\n-\tint num_ags = read_double_list(gain, params.get_child(\"gain\"));\n+\tint num_shutters = read_list(shutter, params.get_child(\"shutter\"));\n+\tint num_ags = read_list(gain, params.get_child(\"gain\"));\n \tif (num_shutters < 2 || num_ags < 2)\n \t\tthrow std::runtime_error(\n \t\t\t\"AgcConfig: must have at least two entries in exposure profile\");\n@@ -148,7 +155,7 @@ void AgcConfig::Read(boost::property_tree::ptree const ¶ms)\n \t\tparams.get<double>(\"fast_reduce_threshold\", 0.4);\n \tbase_ev = params.get<double>(\"base_ev\", 1.0);\n \t// Start with quite a low value as ramping up is easier than ramping down.\n-\tdefault_exposure_time = params.get<double>(\"default_exposure_time\", 1000);\n+\tdefault_exposure_time = params.get<double>(\"default_exposure_time\", 1000) * 1us;\n \tdefault_analogue_gain = params.get<double>(\"default_analogue_gain\", 1.0);\n }\n \n@@ -156,9 +163,9 @@ Agc::Agc(Controller *controller)\n \t: AgcAlgorithm(controller), metering_mode_(nullptr),\n \t exposure_mode_(nullptr), constraint_mode_(nullptr),\n \t frame_count_(0), lock_count_(0),\n-\t last_target_exposure_(0.0),\n-\t ev_(1.0), flicker_period_(0.0),\n-\t max_shutter_(0), fixed_shutter_(0), fixed_analogue_gain_(0.0)\n+\t last_target_exposure_(0s),\n+\t ev_(1.0), flicker_period_(0s),\n+\t max_shutter_(0s), fixed_shutter_(0s), fixed_analogue_gain_(0.0)\n {\n \tmemset(&awb_, 0, sizeof(awb_));\n \t// Setting status_.total_exposure_value_ to zero initially tells us\n@@ -204,7 +211,7 @@ void Agc::Pause()\n \n void Agc::Resume()\n {\n-\tfixed_shutter_ = 0;\n+\tfixed_shutter_ = 0s;\n \tfixed_analogue_gain_ = 0;\n }\n \n@@ -225,17 +232,17 @@ void Agc::SetEv(double ev)\n \n void Agc::SetFlickerPeriod(Duration flicker_period)\n {\n-\tflicker_period_ = flicker_period.get<std::micro>();\n+\tflicker_period_ = flicker_period;\n }\n \n void Agc::SetMaxShutter(Duration max_shutter)\n {\n-\tmax_shutter_ = max_shutter.get<std::micro>();\n+\tmax_shutter_ = max_shutter;\n }\n \n void Agc::SetFixedShutter(Duration fixed_shutter)\n {\n-\tfixed_shutter_ = fixed_shutter.get<std::micro>();\n+\tfixed_shutter_ = fixed_shutter;\n \t// Set this in case someone calls Pause() straight after.\n \tstatus_.shutter_time = clipShutter(fixed_shutter_);\n }\n@@ -267,8 +274,8 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,\n {\n \thousekeepConfig();\n \n-\tdouble fixed_shutter = clipShutter(fixed_shutter_);\n-\tif (fixed_shutter != 0.0 && fixed_analogue_gain_ != 0.0) {\n+\tDuration fixed_shutter = clipShutter(fixed_shutter_);\n+\tif (fixed_shutter && fixed_analogue_gain_) {\n \t\t// We're going to reset the algorithm here with these fixed values.\n \n \t\tfetchAwbStatus(metadata);\n@@ -313,8 +320,8 @@ void Agc::Prepare(Metadata *image_metadata)\n \t\t// Process has run, so we have meaningful values.\n \t\tDeviceStatus device_status;\n \t\tif (image_metadata->Get(\"device.status\", device_status) == 0) {\n-\t\t\tdouble actual_exposure = device_status.shutter_speed *\n-\t\t\t\t\t\t device_status.analogue_gain;\n+\t\t\tDuration actual_exposure = device_status.shutter_speed *\n+\t\t\t\t\t\t device_status.analogue_gain;\n \t\t\tif (actual_exposure) {\n \t\t\t\tstatus_.digital_gain =\n \t\t\t\t\tstatus_.total_exposure_value /\n@@ -327,7 +334,8 @@ void Agc::Prepare(Metadata *image_metadata)\n \t\t\t\t\tstd::min(status_.digital_gain, 4.0));\n \t\t\t\tLOG(RPiAgc, Debug) << \"Actual exposure \" << actual_exposure;\n \t\t\t\tLOG(RPiAgc, Debug) << \"Use digital_gain \" << status_.digital_gain;\n-\t\t\t\tLOG(RPiAgc, Debug) << \"Effective exposure \" << actual_exposure * status_.digital_gain;\n+\t\t\t\tLOG(RPiAgc, Debug) << \"Effective exposure \"\n+\t\t\t\t\t\t << actual_exposure * status_.digital_gain;\n \t\t\t\t// Decide whether AEC/AGC has converged.\n \t\t\t\tupdateLockStatus(device_status);\n \t\t\t}\n@@ -371,9 +379,9 @@ void Agc::updateLockStatus(DeviceStatus const &device_status)\n \tconst double RESET_MARGIN = 1.5;\n \n \t// Add 200us to the exposure time error to allow for line quantisation.\n-\tdouble exposure_error = last_device_status_.shutter_speed * ERROR_FACTOR + 200;\n+\tDuration exposure_error = last_device_status_.shutter_speed * ERROR_FACTOR + 200us;\n \tdouble gain_error = last_device_status_.analogue_gain * ERROR_FACTOR;\n-\tdouble target_error = last_target_exposure_ * ERROR_FACTOR;\n+\tDuration target_error = last_target_exposure_ * ERROR_FACTOR;\n \n \t// Note that we don't know the exposure/gain limits of the sensor, so\n \t// the values we keep requesting may be unachievable. For this reason\n@@ -463,7 +471,7 @@ void Agc::fetchCurrentExposure(Metadata *image_metadata)\n \tcurrent_.analogue_gain = device_status->analogue_gain;\n \tAgcStatus *agc_status =\n \t\timage_metadata->GetLocked<AgcStatus>(\"agc.status\");\n-\tcurrent_.total_exposure = agc_status ? agc_status->total_exposure_value : 0;\n+\tcurrent_.total_exposure = agc_status ? agc_status->total_exposure_value : 0s;\n \tcurrent_.total_exposure_no_dg = current_.shutter * current_.analogue_gain;\n }\n \n@@ -574,7 +582,7 @@ void Agc::computeGain(bcm2835_isp_stats *statistics, Metadata *image_metadata,\n \n void Agc::computeTargetExposure(double gain)\n {\n-\tif (status_.fixed_shutter != 0.0 && status_.fixed_analogue_gain != 0.0) {\n+\tif (status_.fixed_shutter && status_.fixed_analogue_gain) {\n \t\t// When ag and shutter are both fixed, we need to drive the\n \t\t// total exposure so that we end up with a digital gain of at least\n \t\t// 1/min_colour_gain. Otherwise we'd desaturate channels causing\n@@ -589,11 +597,11 @@ void Agc::computeTargetExposure(double gain)\n \t\ttarget_.total_exposure = current_.total_exposure_no_dg * gain;\n \t\t// The final target exposure is also limited to what the exposure\n \t\t// mode allows.\n-\t\tdouble max_shutter = status_.fixed_shutter != 0.0\n+\t\tDuration max_shutter = status_.fixed_shutter\n \t\t\t\t ? status_.fixed_shutter\n \t\t\t\t : exposure_mode_->shutter.back();\n \t\tmax_shutter = clipShutter(max_shutter);\n-\t\tdouble max_total_exposure =\n+\t\tDuration max_total_exposure =\n \t\t\tmax_shutter *\n \t\t\t(status_.fixed_analogue_gain != 0.0\n \t\t\t\t ? status_.fixed_analogue_gain\n@@ -638,7 +646,7 @@ void Agc::filterExposure(bool desaturate)\n \tif ((status_.fixed_shutter && status_.fixed_analogue_gain) ||\n \t frame_count_ <= config_.startup_frames)\n \t\tspeed = 1.0;\n-\tif (filtered_.total_exposure == 0.0) {\n+\tif (!filtered_.total_exposure) {\n \t\tfiltered_.total_exposure = target_.total_exposure;\n \t\tfiltered_.total_exposure_no_dg = target_.total_exposure_no_dg;\n \t} else {\n@@ -675,9 +683,10 @@ void Agc::divideUpExposure()\n \t// Sending the fixed shutter/gain cases through the same code may seem\n \t// unnecessary, but it will make more sense when extend this to cover\n \t// variable aperture.\n-\tdouble exposure_value = filtered_.total_exposure_no_dg;\n-\tdouble shutter_time, analogue_gain;\n-\tshutter_time = status_.fixed_shutter != 0.0\n+\tDuration exposure_value = filtered_.total_exposure_no_dg;\n+\tDuration shutter_time;\n+\tdouble analogue_gain;\n+\tshutter_time = status_.fixed_shutter\n \t\t\t ? status_.fixed_shutter\n \t\t\t : exposure_mode_->shutter[0];\n \tshutter_time = clipShutter(shutter_time);\n@@ -687,8 +696,8 @@ void Agc::divideUpExposure()\n \tif (shutter_time * analogue_gain < exposure_value) {\n \t\tfor (unsigned int stage = 1;\n \t\t stage < exposure_mode_->gain.size(); stage++) {\n-\t\t\tif (status_.fixed_shutter == 0.0) {\n-\t\t\t\tdouble stage_shutter =\n+\t\t\tif (!status_.fixed_shutter) {\n+\t\t\t\tDuration stage_shutter =\n \t\t\t\t\tclipShutter(exposure_mode_->shutter[stage]);\n \t\t\t\tif (stage_shutter * analogue_gain >=\n \t\t\t\t exposure_value) {\n@@ -714,12 +723,11 @@ void Agc::divideUpExposure()\n \t\t\t << analogue_gain;\n \t// Finally adjust shutter time for flicker avoidance (require both\n \t// shutter and gain not to be fixed).\n-\tif (status_.fixed_shutter == 0.0 &&\n-\t status_.fixed_analogue_gain == 0.0 &&\n-\t status_.flicker_period != 0.0) {\n+\tif (!status_.fixed_shutter && !status_.fixed_analogue_gain &&\n+\t status_.flicker_period) {\n \t\tint flicker_periods = shutter_time / status_.flicker_period;\n-\t\tif (flicker_periods > 0) {\n-\t\t\tdouble new_shutter_time = flicker_periods * status_.flicker_period;\n+\t\tif (flicker_periods) {\n+\t\t\tDuration new_shutter_time = flicker_periods * status_.flicker_period;\n \t\t\tanalogue_gain *= shutter_time / new_shutter_time;\n \t\t\t// We should still not allow the ag to go over the\n \t\t\t// largest value in the exposure mode. Note that this\n@@ -739,7 +747,7 @@ void Agc::divideUpExposure()\n void Agc::writeAndFinish(Metadata *image_metadata, bool desaturate)\n {\n \tstatus_.total_exposure_value = filtered_.total_exposure;\n-\tstatus_.target_exposure_value = desaturate ? 0 : target_.total_exposure_no_dg;\n+\tstatus_.target_exposure_value = desaturate ? 0s : target_.total_exposure_no_dg;\n \tstatus_.shutter_time = filtered_.shutter;\n \tstatus_.analogue_gain = filtered_.analogue_gain;\n \t// Write to metadata as well, in case anyone wants to update the camera\n@@ -751,7 +759,7 @@ void Agc::writeAndFinish(Metadata *image_metadata, bool desaturate)\n \t\t\t << \" analogue gain \" << filtered_.analogue_gain;\n }\n \n-double Agc::clipShutter(double shutter)\n+Duration Agc::clipShutter(Duration shutter)\n {\n \tif (max_shutter_)\n \t\tshutter = std::min(shutter, max_shutter_);\ndiff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp\nindex b52aaa23d51c..750789482b49 100644\n--- a/src/ipa/raspberrypi/controller/rpi/agc.hpp\n+++ b/src/ipa/raspberrypi/controller/rpi/agc.hpp\n@@ -9,6 +9,8 @@\n #include <vector>\n #include <mutex>\n \n+#include \"libcamera/internal/utils.h\"\n+\n #include \"../agc_algorithm.hpp\"\n #include \"../agc_status.h\"\n #include \"../pwl.hpp\"\n@@ -22,13 +24,15 @@\n \n namespace RPiController {\n \n+using namespace std::literals::chrono_literals;\n+\n struct AgcMeteringMode {\n \tdouble weights[AGC_STATS_SIZE];\n \tvoid Read(boost::property_tree::ptree const ¶ms);\n };\n \n struct AgcExposureMode {\n-\tstd::vector<double> shutter;\n+\tstd::vector<libcamera::utils::Duration> shutter;\n \tstd::vector<double> gain;\n \tvoid Read(boost::property_tree::ptree const ¶ms);\n };\n@@ -61,7 +65,7 @@ struct AgcConfig {\n \tstd::string default_exposure_mode;\n \tstd::string default_constraint_mode;\n \tdouble base_ev;\n-\tdouble default_exposure_time;\n+\tlibcamera::utils::Duration default_exposure_time;\n \tdouble default_analogue_gain;\n };\n \n@@ -101,19 +105,19 @@ private:\n \tvoid filterExposure(bool desaturate);\n \tvoid divideUpExposure();\n \tvoid writeAndFinish(Metadata *image_metadata, bool desaturate);\n-\tdouble clipShutter(double shutter);\n+\tlibcamera::utils::Duration clipShutter(libcamera::utils::Duration shutter);\n \tAgcMeteringMode *metering_mode_;\n \tAgcExposureMode *exposure_mode_;\n \tAgcConstraintMode *constraint_mode_;\n \tuint64_t frame_count_;\n \tAwbStatus awb_;\n \tstruct ExposureValues {\n-\t\tExposureValues() : shutter(0), analogue_gain(0),\n-\t\t\t\t total_exposure(0), total_exposure_no_dg(0) {}\n-\t\tdouble shutter;\n+\t\tExposureValues() : shutter(0s), analogue_gain(0),\n+\t\t\t\t total_exposure(0s), total_exposure_no_dg(0s) {}\n+\t\tlibcamera::utils::Duration shutter;\n \t\tdouble analogue_gain;\n-\t\tdouble total_exposure;\n-\t\tdouble total_exposure_no_dg; // without digital gain\n+\t\tlibcamera::utils::Duration total_exposure;\n+\t\tlibcamera::utils::Duration total_exposure_no_dg; // without digital gain\n \t};\n \tExposureValues current_; // values for the current frame\n \tExposureValues target_; // calculate the values we want here\n@@ -121,15 +125,15 @@ private:\n \tAgcStatus status_;\n \tint lock_count_;\n \tDeviceStatus last_device_status_;\n-\tdouble last_target_exposure_;\n+\tlibcamera::utils::Duration last_target_exposure_;\n \t// Below here the \"settings\" that applications can change.\n \tstd::string metering_mode_name_;\n \tstd::string exposure_mode_name_;\n \tstd::string constraint_mode_name_;\n \tdouble ev_;\n-\tdouble flicker_period_;\n-\tdouble max_shutter_;\n-\tdouble fixed_shutter_;\n+\tlibcamera::utils::Duration flicker_period_;\n+\tlibcamera::utils::Duration max_shutter_;\n+\tlibcamera::utils::Duration fixed_shutter_;\n \tdouble fixed_analogue_gain_;\n };\n \ndiff --git a/src/ipa/raspberrypi/controller/rpi/lux.cpp b/src/ipa/raspberrypi/controller/rpi/lux.cpp\nindex f74381cab2b4..258e44f4dcce 100644\n--- a/src/ipa/raspberrypi/controller/rpi/lux.cpp\n+++ b/src/ipa/raspberrypi/controller/rpi/lux.cpp\n@@ -16,6 +16,7 @@\n \n using namespace RPiController;\n using namespace libcamera;\n+using namespace std::literals::chrono_literals;\n \n LOG_DEFINE_CATEGORY(RPiLux)\n \n@@ -38,7 +39,7 @@ char const *Lux::Name() const\n void Lux::Read(boost::property_tree::ptree const ¶ms)\n {\n \treference_shutter_speed_ =\n-\t\tparams.get<double>(\"reference_shutter_speed\");\n+\t\tparams.get<double>(\"reference_shutter_speed\") * 1.0us;\n \treference_gain_ = params.get<double>(\"reference_gain\");\n \treference_aperture_ = params.get<double>(\"reference_aperture\", 1.0);\n \treference_Y_ = params.get<double>(\"reference_Y\");\n@@ -60,15 +61,15 @@ void Lux::Prepare(Metadata *image_metadata)\n void Lux::Process(StatisticsPtr &stats, Metadata *image_metadata)\n {\n \t// set some initial values to shut the compiler up\n-\tDeviceStatus device_status =\n-\t\t{ .shutter_speed = 1.0,\n-\t\t .analogue_gain = 1.0,\n-\t\t .lens_position = 0.0,\n-\t\t .aperture = 0.0,\n-\t\t .flash_intensity = 0.0 };\n+\tDeviceStatus device_status = {\n+\t\t.shutter_speed = 1.0ms,\n+\t\t.analogue_gain = 1.0,\n+\t\t.lens_position = 0.0,\n+\t\t.aperture = 0.0,\n+\t\t.flash_intensity = 0.0\n+\t};\n \tif (image_metadata->Get(\"device.status\", device_status) == 0) {\n \t\tdouble current_gain = device_status.analogue_gain;\n-\t\tdouble current_shutter_speed = device_status.shutter_speed;\n \t\tdouble current_aperture = device_status.aperture;\n \t\tif (current_aperture == 0)\n \t\t\tcurrent_aperture = current_aperture_;\n@@ -83,7 +84,7 @@ void Lux::Process(StatisticsPtr &stats, Metadata *image_metadata)\n \t\tdouble current_Y = sum / (double)num + .5;\n \t\tdouble gain_ratio = reference_gain_ / current_gain;\n \t\tdouble shutter_speed_ratio =\n-\t\t\treference_shutter_speed_ / current_shutter_speed;\n+\t\t\treference_shutter_speed_ / device_status.shutter_speed;\n \t\tdouble aperture_ratio = reference_aperture_ / current_aperture;\n \t\tdouble Y_ratio = current_Y * (65536 / num_bins) / reference_Y_;\n \t\tdouble estimated_lux = shutter_speed_ratio * gain_ratio *\ndiff --git a/src/ipa/raspberrypi/controller/rpi/lux.hpp b/src/ipa/raspberrypi/controller/rpi/lux.hpp\nindex f9090484a136..45c844393e62 100644\n--- a/src/ipa/raspberrypi/controller/rpi/lux.hpp\n+++ b/src/ipa/raspberrypi/controller/rpi/lux.hpp\n@@ -8,6 +8,8 @@\n \n #include <mutex>\n \n+#include \"libcamera/internal/utils.h\"\n+\n #include \"../lux_status.h\"\n #include \"../algorithm.hpp\"\n \n@@ -28,7 +30,7 @@ public:\n private:\n \t// These values define the conditions of the reference image, against\n \t// which we compare the new image.\n-\tdouble reference_shutter_speed_; // in micro-seconds\n+\tlibcamera::utils::Duration reference_shutter_speed_;\n \tdouble reference_gain_;\n \tdouble reference_aperture_; // units of 1/f\n \tdouble reference_Y_; // out of 65536\ndiff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp\nindex 4aa8ccaa985a..1c1e802a2cdc 100644\n--- a/src/ipa/raspberrypi/raspberrypi.cpp\n+++ b/src/ipa/raspberrypi/raspberrypi.cpp\n@@ -222,11 +222,11 @@ void IPARPi::start(const ControlList &controls, ipa::RPi::StartConfig *startConf\n \n \t/* SwitchMode may supply updated exposure/gain values to use. */\n \tAgcStatus agcStatus;\n-\tagcStatus.shutter_time = 0.0;\n+\tagcStatus.shutter_time = 0.0s;\n \tagcStatus.analogue_gain = 0.0;\n \n \tmetadata.Get(\"agc.status\", agcStatus);\n-\tif (agcStatus.shutter_time != 0.0 && agcStatus.analogue_gain != 0.0) {\n+\tif (agcStatus.shutter_time && agcStatus.analogue_gain) {\n \t\tControlList ctrls(sensorCtrls_);\n \t\tapplyAGC(&agcStatus, ctrls);\n \t\tstartConfig->controls = std::move(ctrls);\n@@ -389,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.get<std::micro>();\n+\t\tagcStatus.shutter_time = DefaultExposureTime;\n \t\tagcStatus.analogue_gain = DefaultAnalogueGain;\n \t\tapplyAGC(&agcStatus, ctrls);\n \n@@ -461,7 +461,8 @@ void IPARPi::reportMetadata()\n \t */\n \tDeviceStatus *deviceStatus = rpiMetadata_.GetLocked<DeviceStatus>(\"device.status\");\n \tif (deviceStatus) {\n-\t\tlibcameraMetadata_.set(controls::ExposureTime, deviceStatus->shutter_speed);\n+\t\tlibcameraMetadata_.set(controls::ExposureTime,\n+\t\t\t\t deviceStatus->shutter_speed.get<std::micro>());\n \t\tlibcameraMetadata_.set(controls::AnalogueGain, deviceStatus->analogue_gain);\n \t}\n \n@@ -1014,7 +1015,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).get<std::micro>();\n+\tdeviceStatus.shutter_speed = helper_->Exposure(exposureLines);\n \tdeviceStatus.analogue_gain = helper_->Gain(gainCode);\n \n \tLOG(IPARPI, Debug) << \"Metadata - Exposure : \"\n@@ -1099,7 +1100,7 @@ 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-\tDuration exposure = agcStatus->shutter_time * 1.0us;\n+\tDuration exposure = agcStatus->shutter_time;\n \tint32_t vblanking = helper_->GetVBlanking(exposure, minFrameDuration_, maxFrameDuration_);\n \tint32_t exposureLines = helper_->ExposureLines(exposure);\n \n", "prefixes": [ "libcamera-devel", "v6", "4/4" ] }