[{"id":33083,"web_url":"https://patchwork.libcamera.org/comment/33083/","msgid":"<CAEmqJPoYm8TJwkYPWDWnz1Lw5RZBu_-NqPg3f+vu3f3=c+OEeQ@mail.gmail.com>","date":"2025-01-15T08:55:31","subject":"Re: [PATCH v8.1 05/12] ipa: raspberry: Port to the new AEGC controls","submitter":{"id":34,"url":"https://patchwork.libcamera.org/api/people/34/","name":"Naushir Patuck","email":"naush@raspberrypi.com"},"content":"Hi Paul,\n\nOn Tue, 14 Jan 2025 at 21:36, Paul Elder <paul.elder@ideasonboard.com> wrote:\n>\n> From: Jacopo Mondi <jacopo@jmondi.org>\n>\n> The newly introduced controls to drive the AEGC algorithm allow\n> to control the computation of the exposure time and analogue gain\n> separately.\n>\n> The RPi AEGC implementation already computes the shutter and gain\n> values separately but does not expose separate functions to control\n> them.\n>\n> Augment the AgcAlgorithm interface to allow pausing/resuming the shutter\n> and gain automatic computations separately and plumb them to the newly\n> introduced controls.\n>\n> Add safety checks to ignore ExposureTime and AnalogueGain values if the\n> algorithms are not paused, and report the correct AeState value by\n> checking if both algorithms have been paused or if they have converged.\n>\n> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n> Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>\n>\n\nThanks for the update, this looks much better!\n\nReviewed-by: Naushir Patuck <naush@raspberrypi.com>\n\nBefore merging, I would like an ack by @David Plowman if he's fine with this.\n\n> ---\n> Changes in v8.1:\n> - fix the racy check in handling the auto/manual controls and the manual\n>   control value control\n>\n> Changes in v8:\n> - add auto as default value for ExposureMode and AnalogueGainMode\n> - add todo for control processing order\n>\n> No change in v7\n>\n> No change in v6\n>\n> No change in v5\n>\n> Changes in v4:\n> - s/shutter/exposure/\n>\n> Changes in v3:\n> - recovered from 2-year-old bitrot\n> ---\n>  src/ipa/rpi/common/ipa_base.cpp            | 106 +++++++++++++++++----\n>  src/ipa/rpi/controller/agc_algorithm.h     |   8 +-\n>  src/ipa/rpi/controller/rpi/agc.cpp         |  52 ++++++++--\n>  src/ipa/rpi/controller/rpi/agc.h           |   8 +-\n>  src/ipa/rpi/controller/rpi/agc_channel.cpp |  24 ++++-\n>  src/ipa/rpi/controller/rpi/agc_channel.h   |   8 +-\n>  6 files changed, 171 insertions(+), 35 deletions(-)\n>\n> diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp\n> index 6ff1e22b1..78206bb4a 100644\n> --- a/src/ipa/rpi/common/ipa_base.cpp\n> +++ b/src/ipa/rpi/common/ipa_base.cpp\n> @@ -55,8 +55,15 @@ constexpr Duration controllerMinFrameDuration = 1.0s / 30.0;\n>\n>  /* List of controls handled by the Raspberry Pi IPA */\n>  const ControlInfoMap::Map ipaControls{\n> -       { &controls::AeEnable, ControlInfo(false, true) },\n> +       { &controls::ExposureTimeMode,\n> +         ControlInfo(static_cast<int32_t>(controls::ExposureTimeModeAuto),\n> +                     static_cast<int32_t>(controls::ExposureTimeModeManual),\n> +                     static_cast<int32_t>(controls::ExposureTimeModeAuto)) },\n>         { &controls::ExposureTime, ControlInfo(0, 66666) },\n> +       { &controls::AnalogueGainMode,\n> +         ControlInfo(static_cast<int32_t>(controls::AnalogueGainModeAuto),\n> +                     static_cast<int32_t>(controls::AnalogueGainModeManual),\n> +                     static_cast<int32_t>(controls::AnalogueGainModeAuto)) },\n>         { &controls::AnalogueGain, ControlInfo(1.0f, 16.0f) },\n>         { &controls::AeMeteringMode, ControlInfo(controls::AeMeteringModeValues) },\n>         { &controls::AeConstraintMode, ControlInfo(controls::AeConstraintModeValues) },\n> @@ -749,6 +756,46 @@ void IpaBase::applyControls(const ControlList &controls)\n>                         af->setMode(mode->second);\n>         }\n>\n> +       /*\n> +        * Because some AE controls are mode-specific, handle the AE-related\n> +        * mode changes first.\n> +        */\n> +       if (controls.contains(controls::EXPOSURE_TIME_MODE)) {\n> +               RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n> +                       controller_.getAlgorithm(\"agc\"));\n> +               if (!agc) {\n> +                       LOG(IPARPI, Warning)\n> +                               << \"Could not set EXPOSURE_TIME_MODE - no AGC algorithm\";\n> +                       break;\n> +               }\n> +\n> +               if (ctrl.second.get<int32_t>() == controls::ExposureTimeModeManual)\n> +                       agc->disableAutoExposure();\n> +               else\n> +                       agc->enableAutoExposure();\n> +\n> +               libcameraMetadata_.set(controls::ExposureTimeMode,\n> +                                      ctrl.second.get<int32_t>());\n> +       }\n> +\n> +       if (controls.contains(controls::ANALOGUE_GAIN_MODE)) {\n> +               RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n> +                       controller_.getAlgorithm(\"agc\"));\n> +               if (!agc) {\n> +                       LOG(IPARPI, Warning)\n> +                               << \"Could not set ANALOGUE_GAIN_MODE - no AGC algorithm\";\n> +                       break;\n> +               }\n> +\n> +               if (ctrl.second.get<int32_t>() == controls::AnalogueGainModeManual)\n> +                       agc->disableAutoGain();\n> +               else\n> +                       agc->enableAutoGain();\n> +\n> +               libcameraMetadata_.set(controls::AnalogueGainMode,\n> +                                      ctrl.second.get<int32_t>());\n> +       }\n> +\n>         /* Iterate over controls */\n>         for (auto const &ctrl : controls) {\n>                 LOG(IPARPI, Debug) << \"Request ctrl: \"\n> @@ -756,23 +803,8 @@ void IpaBase::applyControls(const ControlList &controls)\n>                                    << \" = \" << ctrl.second.toString();\n>\n>                 switch (ctrl.first) {\n> -               case controls::AE_ENABLE: {\n> -                       RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n> -                               controller_.getAlgorithm(\"agc\"));\n> -                       if (!agc) {\n> -                               LOG(IPARPI, Warning)\n> -                                       << \"Could not set AE_ENABLE - no AGC algorithm\";\n> -                               break;\n> -                       }\n> -\n> -                       if (ctrl.second.get<bool>() == false)\n> -                               agc->disableAuto();\n> -                       else\n> -                               agc->enableAuto();\n> -\n> -                       libcameraMetadata_.set(controls::AeEnable, ctrl.second.get<bool>());\n> -                       break;\n> -               }\n> +               case controls::EXPOSURE_TIME_MODE:\n> +                       break; /* We already handled this one above */\n>\n>                 case controls::EXPOSURE_TIME: {\n>                         RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n> @@ -783,6 +815,13 @@ void IpaBase::applyControls(const ControlList &controls)\n>                                 break;\n>                         }\n>\n> +                       /*\n> +                        * Ignore manual exposure time when the auto exposure\n> +                        * algorithm is running.\n> +                        */\n> +                       if (agc->autoExposureEnabled())\n> +                               break;\n> +\n>                         /* The control provides units of microseconds. */\n>                         agc->setFixedExposureTime(0, ctrl.second.get<int32_t>() * 1.0us);\n>\n> @@ -790,6 +829,9 @@ void IpaBase::applyControls(const ControlList &controls)\n>                         break;\n>                 }\n>\n> +               case controls::ANALOGUE_GAIN_MODE:\n> +                       break; /* We already handled this one above */\n> +\n>                 case controls::ANALOGUE_GAIN: {\n>                         RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n>                                 controller_.getAlgorithm(\"agc\"));\n> @@ -799,6 +841,13 @@ void IpaBase::applyControls(const ControlList &controls)\n>                                 break;\n>                         }\n>\n> +                       /*\n> +                        * Ignore manual analogue gain value when the auto gain\n> +                        * algorithm is running.\n> +                        */\n> +                       if (agc->autoGainEnabled())\n> +                               break;\n> +\n>                         agc->setFixedAnalogueGain(0, ctrl.second.get<float>());\n>\n>                         libcameraMetadata_.set(controls::AnalogueGain,\n> @@ -855,6 +904,13 @@ void IpaBase::applyControls(const ControlList &controls)\n>                                 break;\n>                         }\n>\n> +                       /*\n> +                        * Ignore AE_EXPOSURE_MODE if the shutter or the gain\n> +                        * are in auto mode.\n> +                        */\n> +                       if (agc->autoExposureEnabled() || agc->autoGainEnabled())\n> +                               break;\n> +\n>                         int32_t idx = ctrl.second.get<int32_t>();\n>                         if (ExposureModeTable.count(idx)) {\n>                                 agc->setExposureMode(ExposureModeTable.at(idx));\n> @@ -1334,9 +1390,19 @@ void IpaBase::reportMetadata(unsigned int ipaContext)\n>         }\n>\n>         AgcPrepareStatus *agcPrepareStatus = rpiMetadata.getLocked<AgcPrepareStatus>(\"agc.prepare_status\");\n> -       if (agcPrepareStatus) {\n> -               libcameraMetadata_.set(controls::AeLocked, agcPrepareStatus->locked);\n> +       if (agcPrepareStatus)\n>                 libcameraMetadata_.set(controls::DigitalGain, agcPrepareStatus->digitalGain);\n> +\n> +       RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n> +               controller_.getAlgorithm(\"agc\"));\n> +       if (agc) {\n> +               if (!agc->autoExposureEnabled() && !agc->autoGainEnabled())\n> +                       libcameraMetadata_.set(controls::AeState, controls::AeStateIdle);\n> +               else if (agcPrepareStatus)\n> +                       libcameraMetadata_.set(controls::AeState,\n> +                                              agcPrepareStatus->locked\n> +                                                      ? controls::AeStateConverged\n> +                                                      : controls::AeStateSearching);\n>         }\n>\n>         LuxStatus *luxStatus = rpiMetadata.getLocked<LuxStatus>(\"lux.status\");\n> diff --git a/src/ipa/rpi/controller/agc_algorithm.h b/src/ipa/rpi/controller/agc_algorithm.h\n> index c97828577..fdaa10e6c 100644\n> --- a/src/ipa/rpi/controller/agc_algorithm.h\n> +++ b/src/ipa/rpi/controller/agc_algorithm.h\n> @@ -30,8 +30,12 @@ public:\n>         virtual void setMeteringMode(std::string const &meteringModeName) = 0;\n>         virtual void setExposureMode(std::string const &exposureModeName) = 0;\n>         virtual void setConstraintMode(std::string const &contraintModeName) = 0;\n> -       virtual void enableAuto() = 0;\n> -       virtual void disableAuto() = 0;\n> +       virtual void enableAutoExposure() = 0;\n> +       virtual void disableAutoExposure() = 0;\n> +       virtual bool autoExposureEnabled() const = 0;\n> +       virtual void enableAutoGain() = 0;\n> +       virtual void disableAutoGain() = 0;\n> +       virtual bool autoGainEnabled() const = 0;\n>         virtual void setActiveChannels(const std::vector<unsigned int> &activeChannels) = 0;\n>  };\n>\n> diff --git a/src/ipa/rpi/controller/rpi/agc.cpp b/src/ipa/rpi/controller/rpi/agc.cpp\n> index c48fdf156..02bfdb4a5 100644\n> --- a/src/ipa/rpi/controller/rpi/agc.cpp\n> +++ b/src/ipa/rpi/controller/rpi/agc.cpp\n> @@ -74,22 +74,62 @@ int Agc::checkChannel(unsigned int channelIndex) const\n>         return 0;\n>  }\n>\n> -void Agc::disableAuto()\n> +void Agc::disableAutoExposure()\n>  {\n> -       LOG(RPiAgc, Debug) << \"disableAuto\";\n> +       LOG(RPiAgc, Debug) << \"disableAutoExposure\";\n>\n>         /* All channels are enabled/disabled together. */\n>         for (auto &data : channelData_)\n> -               data.channel.disableAuto();\n> +               data.channel.disableAutoExposure();\n>  }\n>\n> -void Agc::enableAuto()\n> +void Agc::enableAutoExposure()\n>  {\n> -       LOG(RPiAgc, Debug) << \"enableAuto\";\n> +       LOG(RPiAgc, Debug) << \"enableAutoExposure\";\n>\n>         /* All channels are enabled/disabled together. */\n>         for (auto &data : channelData_)\n> -               data.channel.enableAuto();\n> +               data.channel.enableAutoExposure();\n> +}\n> +\n> +bool Agc::autoExposureEnabled() const\n> +{\n> +       LOG(RPiAgc, Debug) << \"autoExposureEnabled\";\n> +\n> +       /*\n> +        * We always have at least one channel, and since all channels are\n> +        * enabled and disabled together we can simply check the first one.\n> +        */\n> +       return channelData_[0].channel.autoExposureEnabled();\n> +}\n> +\n> +void Agc::disableAutoGain()\n> +{\n> +       LOG(RPiAgc, Debug) << \"disableAutoGain\";\n> +\n> +       /* All channels are enabled/disabled together. */\n> +       for (auto &data : channelData_)\n> +               data.channel.disableAutoGain();\n> +}\n> +\n> +void Agc::enableAutoGain()\n> +{\n> +       LOG(RPiAgc, Debug) << \"enableAutoGain\";\n> +\n> +       /* All channels are enabled/disabled together. */\n> +       for (auto &data : channelData_)\n> +               data.channel.enableAutoGain();\n> +}\n> +\n> +bool Agc::autoGainEnabled() const\n> +{\n> +       LOG(RPiAgc, Debug) << \"autoGainEnabled\";\n> +\n> +       /*\n> +        * We always have at least one channel, and since all channels are\n> +        * enabled and disabled together we can simply check the first one.\n> +        */\n> +       return channelData_[0].channel.autoGainEnabled();\n>  }\n>\n>  unsigned int Agc::getConvergenceFrames() const\n> diff --git a/src/ipa/rpi/controller/rpi/agc.h b/src/ipa/rpi/controller/rpi/agc.h\n> index 3aca000bb..c3a940bf6 100644\n> --- a/src/ipa/rpi/controller/rpi/agc.h\n> +++ b/src/ipa/rpi/controller/rpi/agc.h\n> @@ -40,8 +40,12 @@ public:\n>         void setMeteringMode(std::string const &meteringModeName) override;\n>         void setExposureMode(std::string const &exposureModeName) override;\n>         void setConstraintMode(std::string const &contraintModeName) override;\n> -       void enableAuto() override;\n> -       void disableAuto() override;\n> +       void enableAutoExposure() override;\n> +       void disableAutoExposure() override;\n> +       bool autoExposureEnabled() const override;\n> +       void enableAutoGain() override;\n> +       void disableAutoGain() override;\n> +       bool autoGainEnabled() const override;\n>         void switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n>         void prepare(Metadata *imageMetadata) override;\n>         void process(StatisticsPtr &stats, Metadata *imageMetadata) override;\n> diff --git a/src/ipa/rpi/controller/rpi/agc_channel.cpp b/src/ipa/rpi/controller/rpi/agc_channel.cpp\n> index 79c459735..e79184b7a 100644\n> --- a/src/ipa/rpi/controller/rpi/agc_channel.cpp\n> +++ b/src/ipa/rpi/controller/rpi/agc_channel.cpp\n> @@ -319,18 +319,36 @@ int AgcChannel::read(const libcamera::YamlObject &params,\n>         return 0;\n>  }\n>\n> -void AgcChannel::disableAuto()\n> +void AgcChannel::disableAutoExposure()\n>  {\n>         fixedExposureTime_ = status_.exposureTime;\n> -       fixedAnalogueGain_ = status_.analogueGain;\n>  }\n>\n> -void AgcChannel::enableAuto()\n> +void AgcChannel::enableAutoExposure()\n>  {\n>         fixedExposureTime_ = 0s;\n> +}\n> +\n> +bool AgcChannel::autoExposureEnabled() const\n> +{\n> +       return fixedExposureTime_ == 0s;\n> +}\n> +\n> +void AgcChannel::disableAutoGain()\n> +{\n> +       fixedAnalogueGain_ = status_.analogueGain;\n> +}\n> +\n> +void AgcChannel::enableAutoGain()\n> +{\n>         fixedAnalogueGain_ = 0;\n>  }\n>\n> +bool AgcChannel::autoGainEnabled() const\n> +{\n> +       return fixedAnalogueGain_ == 0;\n> +}\n> +\n>  unsigned int AgcChannel::getConvergenceFrames() const\n>  {\n>         /*\n> diff --git a/src/ipa/rpi/controller/rpi/agc_channel.h b/src/ipa/rpi/controller/rpi/agc_channel.h\n> index 734e5efd3..fa697e6fa 100644\n> --- a/src/ipa/rpi/controller/rpi/agc_channel.h\n> +++ b/src/ipa/rpi/controller/rpi/agc_channel.h\n> @@ -96,8 +96,12 @@ public:\n>         void setMeteringMode(std::string const &meteringModeName);\n>         void setExposureMode(std::string const &exposureModeName);\n>         void setConstraintMode(std::string const &contraintModeName);\n> -       void enableAuto();\n> -       void disableAuto();\n> +       void enableAutoExposure();\n> +       void disableAutoExposure();\n> +       bool autoExposureEnabled() const;\n> +       void enableAutoGain();\n> +       void disableAutoGain();\n> +       bool autoGainEnabled() const;\n>         void switchMode(CameraMode const &cameraMode, Metadata *metadata);\n>         void prepare(Metadata *imageMetadata);\n>         void process(StatisticsPtr &stats, DeviceStatus const &deviceStatus, Metadata *imageMetadata,\n> --\n> 2.39.2\n>","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 64421C32FE\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 15 Jan 2025 08:56:11 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7B3BC68521;\n\tWed, 15 Jan 2025 09:56:10 +0100 (CET)","from mail-yb1-xb33.google.com (mail-yb1-xb33.google.com\n\t[IPv6:2607:f8b0:4864:20::b33])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id ECC8E60887\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 15 Jan 2025 09:56:07 +0100 (CET)","by mail-yb1-xb33.google.com with SMTP id\n\t3f1490d57ef6-e39a1af8379so1015225276.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 15 Jan 2025 00:56:07 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"IXUbsDPf\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1736931367; x=1737536167;\n\tdarn=lists.libcamera.org; \n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:from:to:cc:subject:date:message-id:reply-to;\n\tbh=BcKA1gNoUqWSi5LpN9nlDaPFG+6MqjAXBuFIn8tcoYw=;\n\tb=IXUbsDPfMqO/CJYrxsU5BbmW1aN/1K4Q5lXQpcIAUQjAZIFEiMjzlzv7PmWRaJxlCa\n\t+rTKlgS/HVgb9L69YoHvr45VdDDh5Njp9BW7fpei7tY4fPW/HBA6ckddhMGHWpH/e8oe\n\tD6EPhfyfU0NcGnmZ01mJfhOxN3LbG9dhjgDXMHnnY3X3gLte8jfL+7/tjhKn2En3u/fA\n\tCOBWemo1D1ARPe/yiq+Rjg3fsxpmfjEWGZ64NIhNfIDG8EkbsUhIobynjMhIQzm2PQsb\n\tvjqVO8NbWeEuKADqusMso2eN3E2fH2DhUvLz3ZJPK5rsbCOXKfMIBXy2Xgk9fpVgwqag\n\tDIUg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1736931367; x=1737536167;\n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:x-gm-message-state:from:to:cc:subject:date:message-id\n\t:reply-to;\n\tbh=BcKA1gNoUqWSi5LpN9nlDaPFG+6MqjAXBuFIn8tcoYw=;\n\tb=DAKUxs00L3RqFouliQ6XZ55Uv9D8/QHz2qNG41ZkWY1SXZviO03o3KmIyG3SkwlaOG\n\t78zlUZ8cBWg2+aJ1HbPQuXKf8Q1xjM4zov/zVg5OWsq7z3ZAhdYrsjQglbGnQ61RGsGQ\n\tSTccQpB3gevJqBOhjfqr83M9dvsrvOfYS2HbNnoLZFRKOLujLgS4slmNM0sFxSeJPFjK\n\tkotqTC98Wf009Dj5QhLB7ukvENq7gvCgYLq3D5iyiBApCh2sE32Ta5+tZJtKcH+O9TP4\n\tGLu0RsQZTppeHJAGJrutvGUk4CH15hGIDB8n3SngyOgYIT5euSE2VB/uH59IYR62M/wK\n\tKV6Q==","X-Forwarded-Encrypted":"i=1;\n\tAJvYcCVYJ4gR/UbVB0/iW+HSRAkxXzsRg3xBg8ziDTdeW7n7IYILMwg5zoLEpYIKQzkXmRAHO0p7f1xM8dHQyru6seE=@lists.libcamera.org","X-Gm-Message-State":"AOJu0Ywv1M/+ANSZ8vgtJOKink+h/uc8Hgz1WdfZn0TWXltv5rgg1kU/\n\tAxBqr2tWVMuSub7mykHgX26bkMWprWV0QmvtVNvn1R3Ns40r81VrpNOY2AQKL67R3K3LjL9FTv9\n\twT1hTuOScExEuW0BafA/YzYZLuW6Wi2BTwXzbig==","X-Gm-Gg":"ASbGncsT9FSCtmMPQEH9lTaWuL8SQFdHKn+quBqX2/UR7Z8hdAWrf9J+Fmt9aV01SL+\n\tevYcThrdvA9DJpxwGWQUiDJZg+QpFeanOhNCbM4+OgKrOeDYcma/6ipik/wOQkb8C+tddhg==","X-Google-Smtp-Source":"AGHT+IFkWhX0+aRzq9YQauzQ8KCIJSngSxIhtc1V4Vg03zmtFZBtcHkyXTIkrRN0IqJfRKBqZWDpzekIjehqwXhhDZQ=","X-Received":"by 2002:a05:6902:e82:b0:e4d:6e39:ce19 with SMTP id\n\t3f1490d57ef6-e54edf400d7mr8622593276.4.1736931366564; Wed, 15 Jan 2025\n\t00:56:06 -0800 (PST)","MIME-Version":"1.0","References":"<CAEmqJPrgoom80AKgzikQdzJkKyuf7FbyRb1p9ftMmkbEzgambA@mail.gmail.com>\n\t<20250114213337.926578-1-paul.elder@ideasonboard.com>","In-Reply-To":"<20250114213337.926578-1-paul.elder@ideasonboard.com>","From":"Naushir Patuck <naush@raspberrypi.com>","Date":"Wed, 15 Jan 2025 08:55:31 +0000","X-Gm-Features":"AbW1kvbk8qTppbvO5qIkWhtZ2T5nInCQ0z3Wxxd6s0rIgVHxb_VWQXcGg6FXqX0","Message-ID":"<CAEmqJPoYm8TJwkYPWDWnz1Lw5RZBu_-NqPg3f+vu3f3=c+OEeQ@mail.gmail.com>","Subject":"Re: [PATCH v8.1 05/12] ipa: raspberry: Port to the new AEGC controls","To":"Paul Elder <paul.elder@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo@jmondi.org>, libcamera-devel@lists.libcamera.org, \n\tlaurent.pinchart@ideasonboard.com, stefan.klug@ideasonboard.com, \n\tdavid.plowman@raspberrypi.com","Content-Type":"text/plain; charset=\"UTF-8\"","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>"}},{"id":33103,"web_url":"https://patchwork.libcamera.org/comment/33103/","msgid":"<CAHW6GYKPs0CE5JDNh23oM0Ore+__y8CR1wipiSxVZi5pjtQXOw@mail.gmail.com>","date":"2025-01-20T14:08:12","subject":"Re: [PATCH v8.1 05/12] ipa: raspberry: Port to the new AEGC controls","submitter":{"id":42,"url":"https://patchwork.libcamera.org/api/people/42/","name":"David Plowman","email":"david.plowman@raspberrypi.com"},"content":"Hi everyone\n\nThanks for all the work and posting a revised version.\n\nOn Wed, 15 Jan 2025 at 08:56, Naushir Patuck <naush@raspberrypi.com> wrote:\n>\n> Hi Paul,\n>\n> On Tue, 14 Jan 2025 at 21:36, Paul Elder <paul.elder@ideasonboard.com> wrote:\n> >\n> > From: Jacopo Mondi <jacopo@jmondi.org>\n> >\n> > The newly introduced controls to drive the AEGC algorithm allow\n> > to control the computation of the exposure time and analogue gain\n> > separately.\n> >\n> > The RPi AEGC implementation already computes the shutter and gain\n> > values separately but does not expose separate functions to control\n> > them.\n> >\n> > Augment the AgcAlgorithm interface to allow pausing/resuming the shutter\n> > and gain automatic computations separately and plumb them to the newly\n> > introduced controls.\n> >\n> > Add safety checks to ignore ExposureTime and AnalogueGain values if the\n> > algorithms are not paused, and report the correct AeState value by\n> > checking if both algorithms have been paused or if they have converged.\n> >\n> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> > Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n> > Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com>\n> >\n>\n> Thanks for the update, this looks much better!\n>\n> Reviewed-by: Naushir Patuck <naush@raspberrypi.com>\n>\n> Before merging, I would like an ack by @David Plowman if he's fine with this.\n\nAs we discussed the other week, I think this file is now in a state\nwhere it needs a bit of work. The plan will be to add explicit\n\"exposure time mode\" and \"analogue gain mode\" fields, indicating\nwhether each is manual or auto. Manual exposure/gain values can then\nbe \"remembered\" until they take effect (which is how control values\nwork more usually), and the careful ordering of control applications\nwill no longer matter.\n\nUntil that happens I wouldn't recommend anyone to use this code, as\nthe external API it presents, while nominally working, is in an \"in\nbetween\" state. However, I think this is fine given that we don't\ndistribute it to our users, and I will get round to making these\nupdates at some point, hopefully quite soon! As such:\n\nAcked-by: David Plowman <david.plowman@raspberrypi.com>\n\nThanks!\nDavid\n\n>\n> > ---\n> > Changes in v8.1:\n> > - fix the racy check in handling the auto/manual controls and the manual\n> >   control value control\n> >\n> > Changes in v8:\n> > - add auto as default value for ExposureMode and AnalogueGainMode\n> > - add todo for control processing order\n> >\n> > No change in v7\n> >\n> > No change in v6\n> >\n> > No change in v5\n> >\n> > Changes in v4:\n> > - s/shutter/exposure/\n> >\n> > Changes in v3:\n> > - recovered from 2-year-old bitrot\n> > ---\n> >  src/ipa/rpi/common/ipa_base.cpp            | 106 +++++++++++++++++----\n> >  src/ipa/rpi/controller/agc_algorithm.h     |   8 +-\n> >  src/ipa/rpi/controller/rpi/agc.cpp         |  52 ++++++++--\n> >  src/ipa/rpi/controller/rpi/agc.h           |   8 +-\n> >  src/ipa/rpi/controller/rpi/agc_channel.cpp |  24 ++++-\n> >  src/ipa/rpi/controller/rpi/agc_channel.h   |   8 +-\n> >  6 files changed, 171 insertions(+), 35 deletions(-)\n> >\n> > diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp\n> > index 6ff1e22b1..78206bb4a 100644\n> > --- a/src/ipa/rpi/common/ipa_base.cpp\n> > +++ b/src/ipa/rpi/common/ipa_base.cpp\n> > @@ -55,8 +55,15 @@ constexpr Duration controllerMinFrameDuration = 1.0s / 30.0;\n> >\n> >  /* List of controls handled by the Raspberry Pi IPA */\n> >  const ControlInfoMap::Map ipaControls{\n> > -       { &controls::AeEnable, ControlInfo(false, true) },\n> > +       { &controls::ExposureTimeMode,\n> > +         ControlInfo(static_cast<int32_t>(controls::ExposureTimeModeAuto),\n> > +                     static_cast<int32_t>(controls::ExposureTimeModeManual),\n> > +                     static_cast<int32_t>(controls::ExposureTimeModeAuto)) },\n> >         { &controls::ExposureTime, ControlInfo(0, 66666) },\n> > +       { &controls::AnalogueGainMode,\n> > +         ControlInfo(static_cast<int32_t>(controls::AnalogueGainModeAuto),\n> > +                     static_cast<int32_t>(controls::AnalogueGainModeManual),\n> > +                     static_cast<int32_t>(controls::AnalogueGainModeAuto)) },\n> >         { &controls::AnalogueGain, ControlInfo(1.0f, 16.0f) },\n> >         { &controls::AeMeteringMode, ControlInfo(controls::AeMeteringModeValues) },\n> >         { &controls::AeConstraintMode, ControlInfo(controls::AeConstraintModeValues) },\n> > @@ -749,6 +756,46 @@ void IpaBase::applyControls(const ControlList &controls)\n> >                         af->setMode(mode->second);\n> >         }\n> >\n> > +       /*\n> > +        * Because some AE controls are mode-specific, handle the AE-related\n> > +        * mode changes first.\n> > +        */\n> > +       if (controls.contains(controls::EXPOSURE_TIME_MODE)) {\n> > +               RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n> > +                       controller_.getAlgorithm(\"agc\"));\n> > +               if (!agc) {\n> > +                       LOG(IPARPI, Warning)\n> > +                               << \"Could not set EXPOSURE_TIME_MODE - no AGC algorithm\";\n> > +                       break;\n> > +               }\n> > +\n> > +               if (ctrl.second.get<int32_t>() == controls::ExposureTimeModeManual)\n> > +                       agc->disableAutoExposure();\n> > +               else\n> > +                       agc->enableAutoExposure();\n> > +\n> > +               libcameraMetadata_.set(controls::ExposureTimeMode,\n> > +                                      ctrl.second.get<int32_t>());\n> > +       }\n> > +\n> > +       if (controls.contains(controls::ANALOGUE_GAIN_MODE)) {\n> > +               RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n> > +                       controller_.getAlgorithm(\"agc\"));\n> > +               if (!agc) {\n> > +                       LOG(IPARPI, Warning)\n> > +                               << \"Could not set ANALOGUE_GAIN_MODE - no AGC algorithm\";\n> > +                       break;\n> > +               }\n> > +\n> > +               if (ctrl.second.get<int32_t>() == controls::AnalogueGainModeManual)\n> > +                       agc->disableAutoGain();\n> > +               else\n> > +                       agc->enableAutoGain();\n> > +\n> > +               libcameraMetadata_.set(controls::AnalogueGainMode,\n> > +                                      ctrl.second.get<int32_t>());\n> > +       }\n> > +\n> >         /* Iterate over controls */\n> >         for (auto const &ctrl : controls) {\n> >                 LOG(IPARPI, Debug) << \"Request ctrl: \"\n> > @@ -756,23 +803,8 @@ void IpaBase::applyControls(const ControlList &controls)\n> >                                    << \" = \" << ctrl.second.toString();\n> >\n> >                 switch (ctrl.first) {\n> > -               case controls::AE_ENABLE: {\n> > -                       RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n> > -                               controller_.getAlgorithm(\"agc\"));\n> > -                       if (!agc) {\n> > -                               LOG(IPARPI, Warning)\n> > -                                       << \"Could not set AE_ENABLE - no AGC algorithm\";\n> > -                               break;\n> > -                       }\n> > -\n> > -                       if (ctrl.second.get<bool>() == false)\n> > -                               agc->disableAuto();\n> > -                       else\n> > -                               agc->enableAuto();\n> > -\n> > -                       libcameraMetadata_.set(controls::AeEnable, ctrl.second.get<bool>());\n> > -                       break;\n> > -               }\n> > +               case controls::EXPOSURE_TIME_MODE:\n> > +                       break; /* We already handled this one above */\n> >\n> >                 case controls::EXPOSURE_TIME: {\n> >                         RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n> > @@ -783,6 +815,13 @@ void IpaBase::applyControls(const ControlList &controls)\n> >                                 break;\n> >                         }\n> >\n> > +                       /*\n> > +                        * Ignore manual exposure time when the auto exposure\n> > +                        * algorithm is running.\n> > +                        */\n> > +                       if (agc->autoExposureEnabled())\n> > +                               break;\n> > +\n> >                         /* The control provides units of microseconds. */\n> >                         agc->setFixedExposureTime(0, ctrl.second.get<int32_t>() * 1.0us);\n> >\n> > @@ -790,6 +829,9 @@ void IpaBase::applyControls(const ControlList &controls)\n> >                         break;\n> >                 }\n> >\n> > +               case controls::ANALOGUE_GAIN_MODE:\n> > +                       break; /* We already handled this one above */\n> > +\n> >                 case controls::ANALOGUE_GAIN: {\n> >                         RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n> >                                 controller_.getAlgorithm(\"agc\"));\n> > @@ -799,6 +841,13 @@ void IpaBase::applyControls(const ControlList &controls)\n> >                                 break;\n> >                         }\n> >\n> > +                       /*\n> > +                        * Ignore manual analogue gain value when the auto gain\n> > +                        * algorithm is running.\n> > +                        */\n> > +                       if (agc->autoGainEnabled())\n> > +                               break;\n> > +\n> >                         agc->setFixedAnalogueGain(0, ctrl.second.get<float>());\n> >\n> >                         libcameraMetadata_.set(controls::AnalogueGain,\n> > @@ -855,6 +904,13 @@ void IpaBase::applyControls(const ControlList &controls)\n> >                                 break;\n> >                         }\n> >\n> > +                       /*\n> > +                        * Ignore AE_EXPOSURE_MODE if the shutter or the gain\n> > +                        * are in auto mode.\n> > +                        */\n> > +                       if (agc->autoExposureEnabled() || agc->autoGainEnabled())\n> > +                               break;\n> > +\n> >                         int32_t idx = ctrl.second.get<int32_t>();\n> >                         if (ExposureModeTable.count(idx)) {\n> >                                 agc->setExposureMode(ExposureModeTable.at(idx));\n> > @@ -1334,9 +1390,19 @@ void IpaBase::reportMetadata(unsigned int ipaContext)\n> >         }\n> >\n> >         AgcPrepareStatus *agcPrepareStatus = rpiMetadata.getLocked<AgcPrepareStatus>(\"agc.prepare_status\");\n> > -       if (agcPrepareStatus) {\n> > -               libcameraMetadata_.set(controls::AeLocked, agcPrepareStatus->locked);\n> > +       if (agcPrepareStatus)\n> >                 libcameraMetadata_.set(controls::DigitalGain, agcPrepareStatus->digitalGain);\n> > +\n> > +       RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(\n> > +               controller_.getAlgorithm(\"agc\"));\n> > +       if (agc) {\n> > +               if (!agc->autoExposureEnabled() && !agc->autoGainEnabled())\n> > +                       libcameraMetadata_.set(controls::AeState, controls::AeStateIdle);\n> > +               else if (agcPrepareStatus)\n> > +                       libcameraMetadata_.set(controls::AeState,\n> > +                                              agcPrepareStatus->locked\n> > +                                                      ? controls::AeStateConverged\n> > +                                                      : controls::AeStateSearching);\n> >         }\n> >\n> >         LuxStatus *luxStatus = rpiMetadata.getLocked<LuxStatus>(\"lux.status\");\n> > diff --git a/src/ipa/rpi/controller/agc_algorithm.h b/src/ipa/rpi/controller/agc_algorithm.h\n> > index c97828577..fdaa10e6c 100644\n> > --- a/src/ipa/rpi/controller/agc_algorithm.h\n> > +++ b/src/ipa/rpi/controller/agc_algorithm.h\n> > @@ -30,8 +30,12 @@ public:\n> >         virtual void setMeteringMode(std::string const &meteringModeName) = 0;\n> >         virtual void setExposureMode(std::string const &exposureModeName) = 0;\n> >         virtual void setConstraintMode(std::string const &contraintModeName) = 0;\n> > -       virtual void enableAuto() = 0;\n> > -       virtual void disableAuto() = 0;\n> > +       virtual void enableAutoExposure() = 0;\n> > +       virtual void disableAutoExposure() = 0;\n> > +       virtual bool autoExposureEnabled() const = 0;\n> > +       virtual void enableAutoGain() = 0;\n> > +       virtual void disableAutoGain() = 0;\n> > +       virtual bool autoGainEnabled() const = 0;\n> >         virtual void setActiveChannels(const std::vector<unsigned int> &activeChannels) = 0;\n> >  };\n> >\n> > diff --git a/src/ipa/rpi/controller/rpi/agc.cpp b/src/ipa/rpi/controller/rpi/agc.cpp\n> > index c48fdf156..02bfdb4a5 100644\n> > --- a/src/ipa/rpi/controller/rpi/agc.cpp\n> > +++ b/src/ipa/rpi/controller/rpi/agc.cpp\n> > @@ -74,22 +74,62 @@ int Agc::checkChannel(unsigned int channelIndex) const\n> >         return 0;\n> >  }\n> >\n> > -void Agc::disableAuto()\n> > +void Agc::disableAutoExposure()\n> >  {\n> > -       LOG(RPiAgc, Debug) << \"disableAuto\";\n> > +       LOG(RPiAgc, Debug) << \"disableAutoExposure\";\n> >\n> >         /* All channels are enabled/disabled together. */\n> >         for (auto &data : channelData_)\n> > -               data.channel.disableAuto();\n> > +               data.channel.disableAutoExposure();\n> >  }\n> >\n> > -void Agc::enableAuto()\n> > +void Agc::enableAutoExposure()\n> >  {\n> > -       LOG(RPiAgc, Debug) << \"enableAuto\";\n> > +       LOG(RPiAgc, Debug) << \"enableAutoExposure\";\n> >\n> >         /* All channels are enabled/disabled together. */\n> >         for (auto &data : channelData_)\n> > -               data.channel.enableAuto();\n> > +               data.channel.enableAutoExposure();\n> > +}\n> > +\n> > +bool Agc::autoExposureEnabled() const\n> > +{\n> > +       LOG(RPiAgc, Debug) << \"autoExposureEnabled\";\n> > +\n> > +       /*\n> > +        * We always have at least one channel, and since all channels are\n> > +        * enabled and disabled together we can simply check the first one.\n> > +        */\n> > +       return channelData_[0].channel.autoExposureEnabled();\n> > +}\n> > +\n> > +void Agc::disableAutoGain()\n> > +{\n> > +       LOG(RPiAgc, Debug) << \"disableAutoGain\";\n> > +\n> > +       /* All channels are enabled/disabled together. */\n> > +       for (auto &data : channelData_)\n> > +               data.channel.disableAutoGain();\n> > +}\n> > +\n> > +void Agc::enableAutoGain()\n> > +{\n> > +       LOG(RPiAgc, Debug) << \"enableAutoGain\";\n> > +\n> > +       /* All channels are enabled/disabled together. */\n> > +       for (auto &data : channelData_)\n> > +               data.channel.enableAutoGain();\n> > +}\n> > +\n> > +bool Agc::autoGainEnabled() const\n> > +{\n> > +       LOG(RPiAgc, Debug) << \"autoGainEnabled\";\n> > +\n> > +       /*\n> > +        * We always have at least one channel, and since all channels are\n> > +        * enabled and disabled together we can simply check the first one.\n> > +        */\n> > +       return channelData_[0].channel.autoGainEnabled();\n> >  }\n> >\n> >  unsigned int Agc::getConvergenceFrames() const\n> > diff --git a/src/ipa/rpi/controller/rpi/agc.h b/src/ipa/rpi/controller/rpi/agc.h\n> > index 3aca000bb..c3a940bf6 100644\n> > --- a/src/ipa/rpi/controller/rpi/agc.h\n> > +++ b/src/ipa/rpi/controller/rpi/agc.h\n> > @@ -40,8 +40,12 @@ public:\n> >         void setMeteringMode(std::string const &meteringModeName) override;\n> >         void setExposureMode(std::string const &exposureModeName) override;\n> >         void setConstraintMode(std::string const &contraintModeName) override;\n> > -       void enableAuto() override;\n> > -       void disableAuto() override;\n> > +       void enableAutoExposure() override;\n> > +       void disableAutoExposure() override;\n> > +       bool autoExposureEnabled() const override;\n> > +       void enableAutoGain() override;\n> > +       void disableAutoGain() override;\n> > +       bool autoGainEnabled() const override;\n> >         void switchMode(CameraMode const &cameraMode, Metadata *metadata) override;\n> >         void prepare(Metadata *imageMetadata) override;\n> >         void process(StatisticsPtr &stats, Metadata *imageMetadata) override;\n> > diff --git a/src/ipa/rpi/controller/rpi/agc_channel.cpp b/src/ipa/rpi/controller/rpi/agc_channel.cpp\n> > index 79c459735..e79184b7a 100644\n> > --- a/src/ipa/rpi/controller/rpi/agc_channel.cpp\n> > +++ b/src/ipa/rpi/controller/rpi/agc_channel.cpp\n> > @@ -319,18 +319,36 @@ int AgcChannel::read(const libcamera::YamlObject &params,\n> >         return 0;\n> >  }\n> >\n> > -void AgcChannel::disableAuto()\n> > +void AgcChannel::disableAutoExposure()\n> >  {\n> >         fixedExposureTime_ = status_.exposureTime;\n> > -       fixedAnalogueGain_ = status_.analogueGain;\n> >  }\n> >\n> > -void AgcChannel::enableAuto()\n> > +void AgcChannel::enableAutoExposure()\n> >  {\n> >         fixedExposureTime_ = 0s;\n> > +}\n> > +\n> > +bool AgcChannel::autoExposureEnabled() const\n> > +{\n> > +       return fixedExposureTime_ == 0s;\n> > +}\n> > +\n> > +void AgcChannel::disableAutoGain()\n> > +{\n> > +       fixedAnalogueGain_ = status_.analogueGain;\n> > +}\n> > +\n> > +void AgcChannel::enableAutoGain()\n> > +{\n> >         fixedAnalogueGain_ = 0;\n> >  }\n> >\n> > +bool AgcChannel::autoGainEnabled() const\n> > +{\n> > +       return fixedAnalogueGain_ == 0;\n> > +}\n> > +\n> >  unsigned int AgcChannel::getConvergenceFrames() const\n> >  {\n> >         /*\n> > diff --git a/src/ipa/rpi/controller/rpi/agc_channel.h b/src/ipa/rpi/controller/rpi/agc_channel.h\n> > index 734e5efd3..fa697e6fa 100644\n> > --- a/src/ipa/rpi/controller/rpi/agc_channel.h\n> > +++ b/src/ipa/rpi/controller/rpi/agc_channel.h\n> > @@ -96,8 +96,12 @@ public:\n> >         void setMeteringMode(std::string const &meteringModeName);\n> >         void setExposureMode(std::string const &exposureModeName);\n> >         void setConstraintMode(std::string const &contraintModeName);\n> > -       void enableAuto();\n> > -       void disableAuto();\n> > +       void enableAutoExposure();\n> > +       void disableAutoExposure();\n> > +       bool autoExposureEnabled() const;\n> > +       void enableAutoGain();\n> > +       void disableAutoGain();\n> > +       bool autoGainEnabled() const;\n> >         void switchMode(CameraMode const &cameraMode, Metadata *metadata);\n> >         void prepare(Metadata *imageMetadata);\n> >         void process(StatisticsPtr &stats, DeviceStatus const &deviceStatus, Metadata *imageMetadata,\n> > --\n> > 2.39.2\n> >","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 F070AC3273\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 20 Jan 2025 14:08:28 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 47CCA6854D;\n\tMon, 20 Jan 2025 15:08:28 +0100 (CET)","from mail-qt1-x834.google.com (mail-qt1-x834.google.com\n\t[IPv6:2607:f8b0:4864:20::834])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 751D860354\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 20 Jan 2025 15:08:26 +0100 (CET)","by mail-qt1-x834.google.com with SMTP id\n\td75a77b69052e-4679eacf2c5so43017231cf.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 20 Jan 2025 06:08:26 -0800 (PST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"WbqrMbZy\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1737382105; x=1737986905;\n\tdarn=lists.libcamera.org; \n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:from:to:cc:subject:date:message-id:reply-to;\n\tbh=F1dmJRhITXbMO6UJs76wD5XrxQTdowjZr3VIq4ZnNjM=;\n\tb=WbqrMbZyRQ2C3cri5EcdSNNHeFWRzKjnEoarG2ZlC/vcCU/6ylXb83JRXic0VCtJ4d\n\tRHBtpNS6n8Ez1k2W/HiRbNfvpgg/vqmro/nV+0NldKhG4GDMqDwWzX2EcFnDZs7qT5dW\n\t6b0hx2dA7fEo+UDmGKrMeIZI3qA6Rp8xR6PywEtYl9fxQ1Vl/9Y3SjE/Cx0EV4ZfIbvV\n\toG7uRvydRay3c/fHxhZkTugmCY3qybA5uyxL3zSz92c+z3Y6Pcva/cOzEBzTri2Lt/l1\n\t9twlnM478ivp2FM+x14vdYOA3an2/9uV3/DIw4W16AfVr2MZ0nrHX8YyK19xLRsQfZJW\n\tmeDg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1737382105; x=1737986905;\n\th=cc:to:subject:message-id:date:from:in-reply-to:references\n\t:mime-version:x-gm-message-state:from:to:cc:subject:date:message-id\n\t:reply-to;\n\tbh=F1dmJRhITXbMO6UJs76wD5XrxQTdowjZr3VIq4ZnNjM=;\n\tb=RBYCCW6BcSmOj2c8/2ksLE8UnozFU6jArQHTZ4xrFKEKbkU2hS4YC3TfAmz8vjhmeB\n\t43KG1AaKojDaS5vdcHEUDEGM6DpODgNss1HneyjXkB0bZAgX6phYEOBxq+tuQtnf5jGo\n\tmyomDfRmV9gPwCm5PD30GXxceqBSnTgPKsI39SUDBHIRcaSziSW7ZVu8Hf9wwQqAulaj\n\trzL7KUv0OYSm3x/Q4V2gltcEXfEYrY3yNt6zl5su4BPxHa0H17U6U1PMYBDRS56Xwu9x\n\tjNq1ea0aq+cW65aEf4CC8W3EPV91/flNQH0fTs5BewYL8LT3EWACGjjqsk/ZxY6/K0NM\n\tW+Gg==","X-Forwarded-Encrypted":"i=1;\n\tAJvYcCV2vzVx2roLHjFKtO9CoHU2yGa8B9+t/i9h475ImQoqO0C6Id8NPitQUzeebdWMx5eKGPp/mw/FwJcxZq9/C2c=@lists.libcamera.org","X-Gm-Message-State":"AOJu0YxK1wjHQhs5DY95RzUK+V0x7JW3I1wIiOmJiIL35rCFG9egO2LA\n\tJbV+WQONqKgPuQ4WY42Y6GgBOq6hfiVg4ut8Om/kdkjyUeQrQDLSUnATA945Zj6Sv8s7t/7QQ0y\n\tZnS13U6n3l8YpKrPznAcZziTkS+IdF7qCYou2Jg==","X-Gm-Gg":"ASbGncvG+Kf37Qukf2TaSZcakkvfAbDTkZzIq7csPX3PeU+0ap1ToRynVbwVGsUsNlQ\n\t1/GdIeIH5amxoa2YXZtLNuUaa5hMgpyAId/eKdjeSLcM6H1YJ+Tml+y3KxQrlZzq0U9eGrtVnAw\n\t3ut7JzpZ8=","X-Google-Smtp-Source":"AGHT+IGUKNW3Sf6sKoj0eGCogbmEgum6GpuOY6lTyqxMPbv+SrPnZvoKztOcCkSO4bHf7LmwmtNm0mlnsmupT2REqsY=","X-Received":"by 2002:a05:6214:c6a:b0:6d8:959b:c307 with SMTP id\n\t6a1803df08f44-6e1b21792d5mr258515296d6.10.1737382103632;\n\tMon, 20 Jan 2025 06:08:23 -0800 (PST)","MIME-Version":"1.0","References":"<CAEmqJPrgoom80AKgzikQdzJkKyuf7FbyRb1p9ftMmkbEzgambA@mail.gmail.com>\n\t<20250114213337.926578-1-paul.elder@ideasonboard.com>\n\t<CAEmqJPoYm8TJwkYPWDWnz1Lw5RZBu_-NqPg3f+vu3f3=c+OEeQ@mail.gmail.com>","In-Reply-To":"<CAEmqJPoYm8TJwkYPWDWnz1Lw5RZBu_-NqPg3f+vu3f3=c+OEeQ@mail.gmail.com>","From":"David Plowman <david.plowman@raspberrypi.com>","Date":"Mon, 20 Jan 2025 14:08:12 +0000","X-Gm-Features":"AbW1kvbMBrHWdAJbIasrswd5w_RRRHL9v137QvQdr20DT6ewlxBxtimfIGIic-Y","Message-ID":"<CAHW6GYKPs0CE5JDNh23oM0Ore+__y8CR1wipiSxVZi5pjtQXOw@mail.gmail.com>","Subject":"Re: [PATCH v8.1 05/12] ipa: raspberry: Port to the new AEGC controls","To":"Naushir Patuck <naush@raspberrypi.com>","Cc":"Paul Elder <paul.elder@ideasonboard.com>,\n\tJacopo Mondi <jacopo@jmondi.org>, \n\tlibcamera-devel@lists.libcamera.org, laurent.pinchart@ideasonboard.com,\n\tstefan.klug@ideasonboard.com","Content-Type":"text/plain; charset=\"UTF-8\"","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>"}}]