Show a patch.

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

{
    "id": 10925,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/10925/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/10925/",
    "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": "<20210121115849.682130-4-naush@raspberrypi.com>",
    "date": "2021-01-21T11:58:48",
    "name": "[libcamera-devel,3/4] ipa: raspberrypi: Pass the maximum allowable shutter speed into the AGC",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "b16f9eb3b6df1dc2213c3391f79c5e94c7e205ef",
    "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/10925/mbox/",
    "series": [
        {
            "id": 1591,
            "url": "https://patchwork.libcamera.org/api/1.1/series/1591/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1591",
            "date": "2021-01-21T11:58:45",
            "name": "Raspberrypi: FrameDurations control refinements",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/1591/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/10925/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/10925/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 4286AC0F2A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 21 Jan 2021 11:59:00 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0CE84681F4;\n\tThu, 21 Jan 2021 12:59:00 +0100 (CET)",
            "from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com\n\t[IPv6:2a00:1450:4864:20::42c])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 344D8681ED\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 21 Jan 2021 12:58:57 +0100 (CET)",
            "by mail-wr1-x42c.google.com with SMTP id a1so1458022wrq.6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 21 Jan 2021 03:58:57 -0800 (PST)",
            "from naushir-VirtualBox.patuck.local ([88.97.76.4])\n\tby smtp.gmail.com with ESMTPSA id\n\th13sm8044930wrm.28.2021.01.21.03.58.55\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tThu, 21 Jan 2021 03:58:55 -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=\"r+cR7WJD\"; 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=vcbJR/GzM1Wv9CIUg93uXumJ7m5L8+WjsRCxsYGlzdA=;\n\tb=r+cR7WJDRzFp0Qf3bbNrWxHyXfd/0Pjo/yBQ8BFoP+MsdloFGGo+EwJQKmN8so1GkP\n\tHSko52aBqu3hzZtQ/O7zW7Qd6wKxi61dyr/+4hq4exKFOJxyJdIw0EebHDSm3oL0gHpD\n\t0Hjtsl9SyaCk4xpWYwNEUChtn7XNVp3KtJW0XQ6J3uVAKKRfScLOASteEsytQCN/W+3k\n\tc4nRzLQ0ov+ieDm2WJ0vY2RWVbHIc7ipueB+oSP4ef3iuumLLHsjVMk+mMgcJL/Q5u+e\n\tOkhnGVrN5YO12a+Uv4xOnt57eH71/Xj14FTj047n+yo+zjyMmDGD63fdUqAIb6xMBInV\n\trNRw==",
        "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=vcbJR/GzM1Wv9CIUg93uXumJ7m5L8+WjsRCxsYGlzdA=;\n\tb=Ft9+Pl8u74Z+IUPM5FiVBpsZNNaKYSyeA6QbUM02VaRl9fIjxiv/3Xy1yOLMrt2jLv\n\twL61di4opCodtCjxBhTjURx2QPtK9J3A8NtkYToo9bgQ9IsJAQHGRbI1uLvrYu0OHW8w\n\t4uIUWysgl4gS+a//1wRF6H8apEK8Kjp294h/N/x37wNG34+AjOcsIh8lEtucJY1pkRaL\n\tDjc0RQpLklVoTGd1i1ZMR3MBoHLOPP51pQxN5lLBhyb2PHcMPKnLK+A0r2xMNUjT5bRJ\n\tFtYrC4Re4trisjJH58pFV8Nejc8i6gOzMIWpm0qR32vGh0Cg6qE3I7AHwm8P8Urkbx/d\n\t9QfA==",
        "X-Gm-Message-State": "AOAM530urbCI0h8aMKM2hwHuQjL2z+coqS7xbeFo/JUXAe4VBgFk2Mdz\n\tjX8H2wiTqVEicA3Aqy1epss5YgL+ONULPA==",
        "X-Google-Smtp-Source": "ABdhPJxidI9RVQgXoqisi5lUfoeT23hZL95LU7tfnbKO/wCIVLuN619mtBCGfJiPvRVR28wfNz99KQ==",
        "X-Received": "by 2002:a5d:4a11:: with SMTP id m17mr5881838wrq.39.1611230336505;\n\tThu, 21 Jan 2021 03:58:56 -0800 (PST)",
        "From": "Naushir Patuck <naush@raspberrypi.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Thu, 21 Jan 2021 11:58:48 +0000",
        "Message-Id": "<20210121115849.682130-4-naush@raspberrypi.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20210121115849.682130-1-naush@raspberrypi.com>",
        "References": "<20210121115849.682130-1-naush@raspberrypi.com>",
        "MIME-Version": "1.0",
        "Subject": "[libcamera-devel] [PATCH 3/4] 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 AgcAlgorihtm 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>\n---\n .../raspberrypi/controller/agc_algorithm.hpp  |  1 +\n src/ipa/raspberrypi/controller/rpi/agc.cpp    | 49 +++++++++++++------\n src/ipa/raspberrypi/controller/rpi/agc.hpp    |  2 +\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..937bb70ece67 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,23 @@ void Agc::SetFlickerPeriod(double flicker_period)\n \tflicker_period_ = flicker_period;\n }\n \n+static double clip_shutter(double shutter, double max_shutter)\n+{\n+\tif (max_shutter)\n+\t\tshutter = std::min(shutter, max_shutter);\n+\treturn shutter;\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 = clip_shutter(fixed_shutter_, max_shutter_);\n }\n \n void Agc::SetFixedAnalogueGain(double fixed_analogue_gain)\n@@ -261,7 +273,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 = clip_shutter(fixed_shutter_, max_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 +282,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 +303,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 +416,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 = clip_shutter(fixed_shutter_, max_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 +596,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 = clip_shutter(max_shutter, 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 +687,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 = clip_shutter(shutter_time, max_shutter_);\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 +695,16 @@ 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\tclip_shutter(exposure_mode_->shutter[stage],\n+\t\t\t\t\t\t     max_shutter_);\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] *\ndiff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp\nindex 05c334e4a1de..2ce3b1a1700a 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@@ -126,6 +127,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 9e6e030c4997..2b71efc63f10 100644\n--- a/src/ipa/raspberrypi/raspberrypi.cpp\n+++ b/src/ipa/raspberrypi/raspberrypi.cpp\n@@ -1008,6 +1008,18 @@ void IPARPi::applyFrameDurations(double min, double max)\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",
        "3/4"
    ]
}