Patch Detail
Show a patch.
GET /api/1.1/patches/11041/?format=api
{ "id": 11041, "url": "https://patchwork.libcamera.org/api/1.1/patches/11041/?format=api", "web_url": "https://patchwork.libcamera.org/patch/11041/", "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": "<20210128091050.881815-5-naush@raspberrypi.com>", "date": "2021-01-28T09:10:49", "name": "[libcamera-devel,v3,4/5] ipa: raspberrypi: Pass the maximum allowable shutter speed into the AGC", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "ba73eb270f75bae2db8a56b3939a3fa2ec12332d", "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/11041/mbox/", "series": [ { "id": 1619, "url": "https://patchwork.libcamera.org/api/1.1/series/1619/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1619", "date": "2021-01-28T09:10:45", "name": "Raspberry Pi: FrameDurations control refinements", "version": 3, "mbox": "https://patchwork.libcamera.org/series/1619/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/11041/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/11041/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 6A799BD808\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 28 Jan 2021 09:11:02 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 011AB68385;\n\tThu, 28 Jan 2021 10:11:02 +0100 (CET)", "from mail-wm1-x331.google.com (mail-wm1-x331.google.com\n\t[IPv6:2a00:1450:4864:20::331])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9DA3368383\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 28 Jan 2021 10:10:58 +0100 (CET)", "by mail-wm1-x331.google.com with SMTP id u14so3942965wmq.4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 28 Jan 2021 01:10:58 -0800 (PST)", "from naushir-VirtualBox.patuck.local ([88.97.76.4])\n\tby smtp.gmail.com with ESMTPSA id\n\tf17sm6517056wrv.0.2021.01.28.01.10.57\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tThu, 28 Jan 2021 01:10:57 -0800 (PST)" ], "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=\"ATAAJXeQ\"; 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=irRZPJbnLcJSSH4oOs1b7hMuxfFXIX3RyNQhx7GBNIY=;\n\tb=ATAAJXeQsOxlYw5xZuA+I9bPx4McfYLjCrzSTdN1vi9QdFiNlp2KRdzXGLLvHx7UzQ\n\tJQjdASB1qb84NhWW+TQZxo5hOAXsWlUZThFy2VCNA9sUrTgpU2mtkzpvspwc8ROOBMJ6\n\tq4XYe1+6iAeOp0dgbYkzPYt6ptQok9EP4hgmR611d8FAR0toroDE1fhd5soKZ2r/K+Wl\n\tdn1CW/dS7b+e26fKkSu/daFEWjbglX3EGP785Y7zJmAU7oRITkNGRIKLZTndCiv4BPoX\n\tDggvjTkvyExQb1/L2deHXNdQOB1clXLDDNBizMl+KfbJ+Kc80WmClI/Ofz8DzlgDcRMv\n\taXDA==", "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=irRZPJbnLcJSSH4oOs1b7hMuxfFXIX3RyNQhx7GBNIY=;\n\tb=Y7GEqSBMsi55noDvUdnZCagJz2qCRA40U6ZrOufoFXZKUyluEUlkk7zRjHDKz0HlBQ\n\tlmqvIDwYmIyUVoE643avBpo9M+4h8hqHj6AtXdfANDtC6cls0j4UO9vWIJSz7aLAcVk+\n\tkGE4svi7gNggxoI5CM873X+539+82G2juaDcC1DpQzlYyNBJnRz1UJZHsztbTj0QjDAN\n\tMgZKdzCxdXTA1ck24vJ2lBCnO5C22FJqirCCgCRoAAPt69U0SstO/rR3M8aEqBt91Cxg\n\t0LJpQ0vHxdstKYKErIhCGyGxNxByRZiXJTy6nfMZrsGRJyMGkmxAJI3Qb9QsARkmunfD\n\t7S4g==", "X-Gm-Message-State": "AOAM531MfoIiwulTg7dmniP3q7mUEq4thOwX8XQlFyxo3t+EhbQpWDai\n\tgU0iEGL2fSW9Rqs75q7lwYcD1UM9pqDHYZh0", "X-Google-Smtp-Source": "ABdhPJzauSEtvjJbm3W5THvYfuB7yAvi7grpR/JQqrI41IKZvNB/wNv9G3gdJfvsszDh4R1Lbiy43Q==", "X-Received": "by 2002:a05:600c:4e92:: with SMTP id\n\tf18mr7668427wmq.126.1611825057779; \n\tThu, 28 Jan 2021 01:10:57 -0800 (PST)", "From": "Naushir Patuck <naush@raspberrypi.com>", "To": "libcamera-devel@lists.libcamera.org", "Date": "Thu, 28 Jan 2021 09:10:49 +0000", "Message-Id": "<20210128091050.881815-5-naush@raspberrypi.com>", "X-Mailer": "git-send-email 2.25.1", "In-Reply-To": "<20210128091050.881815-1-naush@raspberrypi.com>", "References": "<20210128091050.881815-1-naush@raspberrypi.com>", "MIME-Version": "1.0", "Subject": "[libcamera-devel] [PATCH v3 4/5] ipa: raspberrypi: Pass the maximum\n\tallowable shutter speed into the AGC", "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": "In order to provide an optimal split between shutter speed and gain, the\nAGC must know the maximum allowable shutter speed, as limited by the\nmaximum frame duration (either application provided or the default).\n\nAdd a new API function, SetMaxShutter, to the AgcAlgorithm class. The\nIPA provides the the maximum shutter speed for AGC calculations.\nThis applies to both the manual and auto AGC modes.\n\nSigned-off-by: Naushir Patuck <naush@raspberrypi.com>\nReviewed-by: David Plowman <david.plowman@raspberrypi.com>\n---\n .../raspberrypi/controller/agc_algorithm.hpp | 1 +\n src/ipa/raspberrypi/controller/rpi/agc.cpp | 48 +++++++++++++------\n src/ipa/raspberrypi/controller/rpi/agc.hpp | 3 ++\n src/ipa/raspberrypi/raspberrypi.cpp | 12 +++++\n 4 files changed, 49 insertions(+), 15 deletions(-)", "diff": "diff --git a/src/ipa/raspberrypi/controller/agc_algorithm.hpp b/src/ipa/raspberrypi/controller/agc_algorithm.hpp\nindex 981f1de2f0e4..f97deb0fca59 100644\n--- a/src/ipa/raspberrypi/controller/agc_algorithm.hpp\n+++ b/src/ipa/raspberrypi/controller/agc_algorithm.hpp\n@@ -19,6 +19,7 @@ public:\n \tvirtual void SetEv(double ev) = 0;\n \tvirtual void SetFlickerPeriod(double flicker_period) = 0;\n \tvirtual void SetFixedShutter(double fixed_shutter) = 0; // microseconds\n+\tvirtual void SetMaxShutter(double max_shutter) = 0; // microseconds\n \tvirtual void SetFixedAnalogueGain(double fixed_analogue_gain) = 0;\n \tvirtual void SetMeteringMode(std::string const &metering_mode_name) = 0;\n \tvirtual void SetExposureMode(std::string const &exposure_mode_name) = 0;\ndiff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp\nindex eddd1684da12..0023d50029f1 100644\n--- a/src/ipa/raspberrypi/controller/rpi/agc.cpp\n+++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp\n@@ -157,7 +157,7 @@ Agc::Agc(Controller *controller)\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 fixed_shutter_(0), fixed_analogue_gain_(0.0)\n+\t max_shutter_(0), fixed_shutter_(0), 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@@ -227,11 +227,16 @@ void Agc::SetFlickerPeriod(double flicker_period)\n \tflicker_period_ = flicker_period;\n }\n \n+void Agc::SetMaxShutter(double max_shutter)\n+{\n+\tmax_shutter_ = max_shutter;\n+}\n+\n void Agc::SetFixedShutter(double fixed_shutter)\n {\n \tfixed_shutter_ = fixed_shutter;\n \t// Set this in case someone calls Pause() straight after.\n-\tstatus_.shutter_time = fixed_shutter;\n+\tstatus_.shutter_time = clipShutter(fixed_shutter_);\n }\n \n void Agc::SetFixedAnalogueGain(double fixed_analogue_gain)\n@@ -261,7 +266,8 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,\n {\n \thousekeepConfig();\n \n-\tif (fixed_shutter_ != 0.0 && fixed_analogue_gain_ != 0.0) {\n+\tdouble fixed_shutter = clipShutter(fixed_shutter_);\n+\tif (fixed_shutter != 0.0 && fixed_analogue_gain_ != 0.0) {\n \t\t// We're going to reset the algorithm here with these fixed values.\n \n \t\tfetchAwbStatus(metadata);\n@@ -269,14 +275,14 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,\n \t\tASSERT(min_colour_gain != 0.0);\n \n \t\t// This is the equivalent of computeTargetExposure and applyDigitalGain.\n-\t\ttarget_.total_exposure_no_dg = fixed_shutter_ * fixed_analogue_gain_;\n+\t\ttarget_.total_exposure_no_dg = fixed_shutter * fixed_analogue_gain_;\n \t\ttarget_.total_exposure = target_.total_exposure_no_dg / min_colour_gain;\n \n \t\t// Equivalent of filterExposure. This resets any \"history\".\n \t\tfiltered_ = target_;\n \n \t\t// Equivalent of divideUpExposure.\n-\t\tfiltered_.shutter = fixed_shutter_;\n+\t\tfiltered_.shutter = fixed_shutter;\n \t\tfiltered_.analogue_gain = fixed_analogue_gain_;\n \t} else if (status_.total_exposure_value) {\n \t\t// On a mode switch, it's possible the exposure profile could change,\n@@ -290,7 +296,7 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,\n \t\t// for any that weren't set.\n \n \t\t// Equivalent of divideUpExposure.\n-\t\tfiltered_.shutter = fixed_shutter_ ? fixed_shutter_ : config_.default_exposure_time;\n+\t\tfiltered_.shutter = fixed_shutter ? fixed_shutter : config_.default_exposure_time;\n \t\tfiltered_.analogue_gain = fixed_analogue_gain_ ? fixed_analogue_gain_ : config_.default_analogue_gain;\n \t}\n \n@@ -403,7 +409,8 @@ void Agc::housekeepConfig()\n {\n \t// First fetch all the up-to-date settings, so no one else has to do it.\n \tstatus_.ev = ev_;\n-\tstatus_.fixed_shutter = fixed_shutter_;\n+\tdouble fixed_shutter = clipShutter(fixed_shutter_);\n+\tstatus_.fixed_shutter = fixed_shutter;\n \tstatus_.fixed_analogue_gain = fixed_analogue_gain_;\n \tstatus_.flicker_period = flicker_period_;\n \tLOG(RPiAgc, Debug) << \"ev \" << status_.ev << \" fixed_shutter \"\n@@ -582,13 +589,15 @@ 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\t\t\t\t ? status_.fixed_shutter\n+\t\t\t\t\t : exposure_mode_->shutter.back();\n+\t\tmax_shutter = clipShutter(max_shutter);\n \t\tdouble max_total_exposure =\n-\t\t\t(status_.fixed_shutter != 0.0\n-\t\t\t ? status_.fixed_shutter\n-\t\t\t : exposure_mode_->shutter.back()) *\n+\t\t\tmax_shutter *\n \t\t\t(status_.fixed_analogue_gain != 0.0\n-\t\t\t ? status_.fixed_analogue_gain\n-\t\t\t : exposure_mode_->gain.back());\n+\t\t\t\t ? status_.fixed_analogue_gain\n+\t\t\t\t : exposure_mode_->gain.back());\n \t\ttarget_.total_exposure = std::min(target_.total_exposure,\n \t\t\t\t\t\t max_total_exposure);\n \t}\n@@ -671,6 +680,7 @@ void Agc::divideUpExposure()\n \tshutter_time = status_.fixed_shutter != 0.0\n \t\t\t ? status_.fixed_shutter\n \t\t\t : exposure_mode_->shutter[0];\n+\tshutter_time = clipShutter(shutter_time);\n \tanalogue_gain = status_.fixed_analogue_gain != 0.0\n \t\t\t\t? status_.fixed_analogue_gain\n \t\t\t\t: exposure_mode_->gain[0];\n@@ -678,14 +688,15 @@ void Agc::divideUpExposure()\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\tif (exposure_mode_->shutter[stage] *\n-\t\t\t\t\t analogue_gain >=\n+\t\t\t\tdouble 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 \t\t\t\t\tshutter_time =\n \t\t\t\t\t\texposure_value / analogue_gain;\n \t\t\t\t\tbreak;\n \t\t\t\t}\n-\t\t\t\tshutter_time = exposure_mode_->shutter[stage];\n+\t\t\t\tshutter_time = stage_shutter;\n \t\t\t}\n \t\t\tif (status_.fixed_analogue_gain == 0.0) {\n \t\t\t\tif (exposure_mode_->gain[stage] *\n@@ -740,6 +751,13 @@ 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+{\n+\tif (max_shutter_)\n+\t\tshutter = std::min(shutter, max_shutter_);\n+\treturn shutter;\n+}\n+\n // Register algorithm with the system.\n static Algorithm *Create(Controller *controller)\n {\ndiff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp\nindex 05c334e4a1de..0427fb59ec1b 100644\n--- a/src/ipa/raspberrypi/controller/rpi/agc.hpp\n+++ b/src/ipa/raspberrypi/controller/rpi/agc.hpp\n@@ -78,6 +78,7 @@ public:\n \tunsigned int GetConvergenceFrames() const override;\n \tvoid SetEv(double ev) override;\n \tvoid SetFlickerPeriod(double flicker_period) override;\n+\tvoid SetMaxShutter(double max_shutter) override; // microseconds\n \tvoid SetFixedShutter(double fixed_shutter) override; // microseconds\n \tvoid SetFixedAnalogueGain(double fixed_analogue_gain) override;\n \tvoid SetMeteringMode(std::string const &metering_mode_name) override;\n@@ -100,6 +101,7 @@ private:\n \tvoid filterExposure(bool desaturate);\n \tvoid divideUpExposure();\n \tvoid writeAndFinish(Metadata *image_metadata, bool desaturate);\n+\tdouble clipShutter(double shutter);\n \tAgcMeteringMode *metering_mode_;\n \tAgcExposureMode *exposure_mode_;\n \tAgcConstraintMode *constraint_mode_;\n@@ -126,6 +128,7 @@ private:\n \tstd::string constraint_mode_name_;\n \tdouble ev_;\n \tdouble flicker_period_;\n+\tdouble max_shutter_;\n \tdouble fixed_shutter_;\n \tdouble fixed_analogue_gain_;\n };\ndiff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp\nindex e4911b734e20..8c0e699184f6 100644\n--- a/src/ipa/raspberrypi/raspberrypi.cpp\n+++ b/src/ipa/raspberrypi/raspberrypi.cpp\n@@ -1006,6 +1006,18 @@ void IPARPi::applyFrameDurations(double minFrameDuration, double maxFrameDuratio\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+\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+\thelper_->GetVBlanking(maxShutter, minFrameDuration_, maxFrameDuration_);\n+\n+\tRPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n+\t\tcontroller_.GetAlgorithm(\"agc\"));\n+\tagc->SetMaxShutter(maxShutter);\n }\n \n void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)\n", "prefixes": [ "libcamera-devel", "v3", "4/5" ] }