[{"id":14985,"web_url":"https://patchwork.libcamera.org/comment/14985/","msgid":"<YBxWtBH9fxEc4TDW@pendragon.ideasonboard.com>","date":"2021-02-04T20:19:00","subject":"Re: [libcamera-devel] [PATCH v4 3/5] ipa: raspberrypi: Limit the\n\tcalculated vblank based on the sensor mode","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Naush,\n\nThank you for the patch.\n\nOn Fri, Jan 29, 2021 at 11:16:14AM +0000, Naushir Patuck wrote:\n> The existing framerate/vblank calculations did not account for the \n> sensor mode limits. This commit extracts vblank limits from the sensor\n> v4l2 controls, and stores it in the camera modes structure.\n> \n> Exposure and vblank value calculations now use values clamped to the\n> sensor mode limits. The libcamera::controls::FrameDurations metadata\n> return values now reflect the minimum and maximum after clamping.\n> \n> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>\n> Reviewed-by: David Plowman <david.plowman@raspberrypi.com>\n> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> ---\n>  src/ipa/raspberrypi/cam_helper.cpp           | 16 +++----\n>  src/ipa/raspberrypi/cam_helper.hpp           |  5 +-\n>  src/ipa/raspberrypi/cam_helper_imx219.cpp    |  6 +--\n>  src/ipa/raspberrypi/cam_helper_imx477.cpp    |  4 +-\n>  src/ipa/raspberrypi/cam_helper_ov5647.cpp    |  4 +-\n>  src/ipa/raspberrypi/controller/camera_mode.h |  2 +\n>  src/ipa/raspberrypi/raspberrypi.cpp          | 49 +++++++++++++-------\n>  7 files changed, 47 insertions(+), 39 deletions(-)\n> \n> diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp\n> index b7b8faf09c69..93d1b7b0296a 100644\n> --- a/src/ipa/raspberrypi/cam_helper.cpp\n> +++ b/src/ipa/raspberrypi/cam_helper.cpp\n> @@ -34,9 +34,8 @@ CamHelper *CamHelper::Create(std::string const &cam_name)\n>  \treturn nullptr;\n>  }\n>  \n> -CamHelper::CamHelper(MdParser *parser, unsigned int maxFrameLength,\n> -\t\t     unsigned int frameIntegrationDiff)\n> -\t: parser_(parser), initialized_(false), maxFrameLength_(maxFrameLength),\n> +CamHelper::CamHelper(MdParser *parser, unsigned int frameIntegrationDiff)\n> +\t: parser_(parser), initialized_(false),\n>  \t  frameIntegrationDiff_(frameIntegrationDiff)\n>  {\n>  }\n> @@ -67,13 +66,12 @@ uint32_t CamHelper::GetVBlanking(double &exposure, double minFrameDuration,\n>  \tassert(initialized_);\n>  \n>  \t/*\n> -\t * Clamp frame length by the frame duration range and the maximum allowable\n> -\t * value in the sensor, given by maxFrameLength_.\n> +\t * minFrameDuration and maxFrameDuration are clamped by the caller\n> +\t * based on the limits for the active sensor mode.\n>  \t */\n> -\tframeLengthMin = std::clamp<uint32_t>(1e3 * minFrameDuration / mode_.line_length,\n> -\t\t\t\t\t      mode_.height, maxFrameLength_);\n> -\tframeLengthMax = std::clamp<uint32_t>(1e3 * maxFrameDuration / mode_.line_length,\n> -\t\t\t\t\t      mode_.height, maxFrameLength_);\n> +\tframeLengthMin = 1e3 * minFrameDuration / mode_.line_length;\n> +\tframeLengthMax = 1e3 * maxFrameDuration / mode_.line_length;\n> +\n>  \t/*\n>  \t * Limit the exposure to the maximum frame duration requested, and\n>  \t * re-calculate if it has been clipped.\n> diff --git a/src/ipa/raspberrypi/cam_helper.hpp b/src/ipa/raspberrypi/cam_helper.hpp\n> index b1739a57e342..14d70112cb62 100644\n> --- a/src/ipa/raspberrypi/cam_helper.hpp\n> +++ b/src/ipa/raspberrypi/cam_helper.hpp\n> @@ -62,8 +62,7 @@ class CamHelper\n>  {\n>  public:\n>  \tstatic CamHelper *Create(std::string const &cam_name);\n> -\tCamHelper(MdParser *parser, unsigned int maxFrameLength,\n> -\t\t  unsigned int frameIntegrationDiff);\n> +\tCamHelper(MdParser *parser, unsigned int frameIntegrationDiff);\n>  \tvirtual ~CamHelper();\n>  \tvoid SetCameraMode(const CameraMode &mode);\n>  \tMdParser &Parser() const { return *parser_; }\n> @@ -86,8 +85,6 @@ protected:\n>  \n>  private:\n>  \tbool initialized_;\n> -\t/* Largest possible frame length, in units of lines. */\n> -\tunsigned int maxFrameLength_;\n>  \t/*\n>  \t * Smallest difference between the frame length and integration time,\n>  \t * in units of lines.\n> diff --git a/src/ipa/raspberrypi/cam_helper_imx219.cpp b/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> index 8688ec091c44..95b8e698fe3b 100644\n> --- a/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> +++ b/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> @@ -56,15 +56,13 @@ private:\n>  \t * in units of lines.\n>  \t */\n>  \tstatic constexpr int frameIntegrationDiff = 4;\n> -\t/* Largest possible frame length, in units of lines. */\n> -\tstatic constexpr int maxFrameLength = 0xffff;\n>  };\n>  \n>  CamHelperImx219::CamHelperImx219()\n>  #if ENABLE_EMBEDDED_DATA\n> -\t: CamHelper(new MdParserImx219(), maxFrameLength, frameIntegrationDiff)\n> +\t: CamHelper(new MdParserImx219(), frameIntegrationDiff)\n>  #else\n> -\t: CamHelper(new MdParserRPi(), maxFrameLength, frameIntegrationDiff)\n> +\t: CamHelper(new MdParserRPi(), frameIntegrationDiff)\n>  #endif\n>  {\n>  }\n> diff --git a/src/ipa/raspberrypi/cam_helper_imx477.cpp b/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> index 5396131003f1..eaa7be16d20e 100644\n> --- a/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> +++ b/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> @@ -45,12 +45,10 @@ private:\n>  \t * in units of lines.\n>  \t */\n>  \tstatic constexpr int frameIntegrationDiff = 22;\n> -\t/* Largest possible frame length, in units of lines. */\n> -\tstatic constexpr int maxFrameLength = 0xffdc;\n>  };\n>  \n>  CamHelperImx477::CamHelperImx477()\n> -\t: CamHelper(new MdParserImx477(), maxFrameLength, frameIntegrationDiff)\n> +\t: CamHelper(new MdParserImx477(), frameIntegrationDiff)\n>  {\n>  }\n>  \n> diff --git a/src/ipa/raspberrypi/cam_helper_ov5647.cpp b/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> index 2bd8a754f133..a7f417324048 100644\n> --- a/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> +++ b/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> @@ -30,8 +30,6 @@ private:\n>  \t * in units of lines.\n>  \t */\n>  \tstatic constexpr int frameIntegrationDiff = 4;\n> -\t/* Largest possible frame length, in units of lines. */\n> -\tstatic constexpr int maxFrameLength = 0xffff;\n>  };\n>  \n>  /*\n> @@ -40,7 +38,7 @@ private:\n>   */\n>  \n>  CamHelperOv5647::CamHelperOv5647()\n> -\t: CamHelper(new MdParserRPi(), maxFrameLength, frameIntegrationDiff)\n> +\t: CamHelper(new MdParserRPi(), frameIntegrationDiff)\n>  {\n>  }\n>  \n> diff --git a/src/ipa/raspberrypi/controller/camera_mode.h b/src/ipa/raspberrypi/controller/camera_mode.h\n> index 920f11beb0b0..256438c931d9 100644\n> --- a/src/ipa/raspberrypi/controller/camera_mode.h\n> +++ b/src/ipa/raspberrypi/controller/camera_mode.h\n> @@ -37,6 +37,8 @@ struct CameraMode {\n>  \tdouble line_length;\n>  \t// any camera transform *not* reflected already in the camera tuning\n>  \tlibcamera::Transform transform;\n> +\t// minimum and maximum fame lengths in units of lines\n> +\tuint32_t min_frame_length, max_frame_length;\n>  };\n>  \n>  #ifdef __cplusplus\n> diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp\n> index 5ccc7a6551f5..e4911b734e20 100644\n> --- a/src/ipa/raspberrypi/raspberrypi.cpp\n> +++ b/src/ipa/raspberrypi/raspberrypi.cpp\n> @@ -102,6 +102,7 @@ private:\n>  \tvoid reportMetadata();\n>  \tbool parseEmbeddedData(unsigned int bufferId, struct DeviceStatus &deviceStatus);\n>  \tvoid processStats(unsigned int bufferId);\n> +\tvoid applyFrameDurations(double minFrameDuration, double maxFrameDuration);\n>  \tvoid applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls);\n>  \tvoid applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls);\n>  \tvoid applyDG(const struct AgcStatus *dgStatus, ControlList &ctrls);\n> @@ -279,6 +280,13 @@ void IPARPi::setMode(const CameraSensorInfo &sensorInfo)\n>  \t * the line length in pixels and the pixel rate.\n>  \t */\n>  \tmode_.line_length = 1e9 * sensorInfo.lineLength / sensorInfo.pixelRate;\n> +\n> +\t/*\n> +\t * Set the frame length limits for the mode to ensure exposure and\n> +\t * framerate calculations are clipped appropriately.\n> +\t */\n> +\tmode_.min_frame_length = sensorInfo.minFrameLength;\n> +\tmode_.max_frame_length = sensorInfo.maxFrameLength;\n>  }\n>  \n>  void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n> @@ -384,8 +392,8 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n>  \t\tcontroller_.Initialise();\n>  \t\tcontrollerInit_ = true;\n>  \n> -\t\tminFrameDuration_ = defaultMinFrameDuration;\n> -\t\tmaxFrameDuration_ = defaultMaxFrameDuration;\n> +\t\t/* Supply initial values for frame durations. */\n> +\t\tapplyFrameDurations(defaultMinFrameDuration, defaultMaxFrameDuration);\n>  \n>  \t\t/* Supply initial values for gain and exposure. */\n>  \t\tControlList ctrls(sensorCtrls_);\n> @@ -819,20 +827,7 @@ void IPARPi::queueRequest(const ControlList &controls)\n>  \n>  \t\tcase controls::FRAME_DURATIONS: {\n>  \t\t\tauto frameDurations = ctrl.second.get<Span<const int64_t>>();\n> -\n> -\t\t\t/* This will be applied once AGC recalculations occur. */\n> -\t\t\tminFrameDuration_ = frameDurations[0] ? frameDurations[0] : defaultMinFrameDuration;\n> -\t\t\tmaxFrameDuration_ = frameDurations[1] ? frameDurations[1] : defaultMaxFrameDuration;\n> -\t\t\tmaxFrameDuration_ = std::max(maxFrameDuration_, minFrameDuration_);\n> -\n> -\t\t\t/*\n> -\t\t\t * \\todo The values returned in the metadata below must be\n> -\t\t\t * correctly clipped by what the sensor mode supports and\n> -\t\t\t * what the AGC exposure mode or manual shutter speed limits\n> -\t\t\t */\n> -\t\t\tlibcameraMetadata_.set(controls::FrameDurations,\n> -\t\t\t\t\t       { static_cast<int64_t>(minFrameDuration_),\n> -\t\t\t\t\t\t static_cast<int64_t>(maxFrameDuration_) });\n> +\t\t\tapplyFrameDurations(frameDurations[0], frameDurations[1]);\n>  \t\t\tbreak;\n>  \t\t}\n>  \n> @@ -991,6 +986,28 @@ void IPARPi::applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls)\n>  \t\t  static_cast<int32_t>(awbStatus->gain_b * 1000));\n>  }\n>  \n> +void IPARPi::applyFrameDurations(double minFrameDuration, double maxFrameDuration)\n> +{\n> +\tconst double minSensorFrameDuration = 1e-3 * mode_.min_frame_length * mode_.line_length;\n> +\tconst double maxSensorFrameDuration = 1e-3 * mode_.max_frame_length * mode_.line_length;\n> +\n> +\t/*\n> +\t * This will only be applied once AGC recalculations occur.\n> +\t * The values may be clamped based on the sensor mode capabilities as well.\n> +\t */\n> +\tminFrameDuration_ = minFrameDuration ? minFrameDuration : defaultMaxFrameDuration;\n> +\tmaxFrameDuration_ = maxFrameDuration ? maxFrameDuration : defaultMinFrameDuration;\n> +\tminFrameDuration_ = std::clamp(minFrameDuration_,\n> +\t\t\t\t       minSensorFrameDuration, maxSensorFrameDuration);\n> +\tmaxFrameDuration_ = std::clamp(maxFrameDuration_,\n> +\t\t\t\t       minSensorFrameDuration, maxSensorFrameDuration);\n\nDo we need to keep\n\n\tmaxFrameDuration_ = std::max(maxFrameDuration_, minFrameDuration_);\n\nin case the user passes a minimum higher than the maximum ? Apart from\nthat (which I can fix when applying if needed),\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> +\n> +\t/* Return the validated limits out though metadata. */\n> +\tlibcameraMetadata_.set(controls::FrameDurations,\n> +\t\t\t       { static_cast<int64_t>(minFrameDuration_),\n> +\t\t\t\t static_cast<int64_t>(maxFrameDuration_) });\n> +}\n> +\n>  void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)\n>  {\n>  \tint32_t gainCode = helper_->GainCode(agcStatus->analogue_gain);","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 58897BD162\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  4 Feb 2021 20:19:25 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B711E61461;\n\tThu,  4 Feb 2021 21:19:24 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E04A461430\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  4 Feb 2021 21:19:22 +0100 (CET)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 4E2DC45D;\n\tThu,  4 Feb 2021 21:19:22 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"S8oqqGaD\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1612469962;\n\tbh=FyWaGFUA5AWSktI1UkL1Q/77nRXIRrj602ieRvz2Acg=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=S8oqqGaD3Bd3R76tkUrE5TDhAVVWAoT3OZ8iNKVC9kJcAE2OfqgfWARyToPTnb1vw\n\tdoPvENMCKRD+T7lJB3KDYohBlEYwArAEOuUXNYL0NJL+1m1Pe+kvLn5gcwdqL8depp\n\tmUaxozAHxM1dMVTnlL/OLqjaWc2HsmUa0fFffV/g=","Date":"Thu, 4 Feb 2021 22:19:00 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Naushir Patuck <naush@raspberrypi.com>","Message-ID":"<YBxWtBH9fxEc4TDW@pendragon.ideasonboard.com>","References":"<20210129111616.1047483-1-naush@raspberrypi.com>\n\t<20210129111616.1047483-4-naush@raspberrypi.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20210129111616.1047483-4-naush@raspberrypi.com>","Subject":"Re: [libcamera-devel] [PATCH v4 3/5] ipa: raspberrypi: Limit the\n\tcalculated vblank based on the sensor mode","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>","Cc":"libcamera-devel@lists.libcamera.org","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>"}},{"id":15009,"web_url":"https://patchwork.libcamera.org/comment/15009/","msgid":"<CAEmqJPq=WfhL=vg134kDHt91Rf1ahXO7JMeb-WZBE8b5isS-zw@mail.gmail.com>","date":"2021-02-04T22:19:07","subject":"Re: [libcamera-devel] [PATCH v4 3/5] ipa: raspberrypi: Limit the\n\tcalculated vblank based on the sensor mode","submitter":{"id":34,"url":"https://patchwork.libcamera.org/api/people/34/","name":"Naushir Patuck","email":"naush@raspberrypi.com"},"content":"Hi Laurent,\n\nThank you for your review feedback.\n\nOn Thu, 4 Feb 2021 at 20:19, Laurent Pinchart <\nlaurent.pinchart@ideasonboard.com> wrote:\n\n> Hi Naush,\n>\n> Thank you for the patch.\n>\n> On Fri, Jan 29, 2021 at 11:16:14AM +0000, Naushir Patuck wrote:\n> > The existing framerate/vblank calculations did not account for the\n> > sensor mode limits. This commit extracts vblank limits from the sensor\n> > v4l2 controls, and stores it in the camera modes structure.\n> >\n> > Exposure and vblank value calculations now use values clamped to the\n> > sensor mode limits. The libcamera::controls::FrameDurations metadata\n> > return values now reflect the minimum and maximum after clamping.\n> >\n> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>\n> > Reviewed-by: David Plowman <david.plowman@raspberrypi.com>\n> > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> > ---\n> >  src/ipa/raspberrypi/cam_helper.cpp           | 16 +++----\n> >  src/ipa/raspberrypi/cam_helper.hpp           |  5 +-\n> >  src/ipa/raspberrypi/cam_helper_imx219.cpp    |  6 +--\n> >  src/ipa/raspberrypi/cam_helper_imx477.cpp    |  4 +-\n> >  src/ipa/raspberrypi/cam_helper_ov5647.cpp    |  4 +-\n> >  src/ipa/raspberrypi/controller/camera_mode.h |  2 +\n> >  src/ipa/raspberrypi/raspberrypi.cpp          | 49 +++++++++++++-------\n> >  7 files changed, 47 insertions(+), 39 deletions(-)\n> >\n> > diff --git a/src/ipa/raspberrypi/cam_helper.cpp\n> b/src/ipa/raspberrypi/cam_helper.cpp\n> > index b7b8faf09c69..93d1b7b0296a 100644\n> > --- a/src/ipa/raspberrypi/cam_helper.cpp\n> > +++ b/src/ipa/raspberrypi/cam_helper.cpp\n> > @@ -34,9 +34,8 @@ CamHelper *CamHelper::Create(std::string const\n> &cam_name)\n> >       return nullptr;\n> >  }\n> >\n> > -CamHelper::CamHelper(MdParser *parser, unsigned int maxFrameLength,\n> > -                  unsigned int frameIntegrationDiff)\n> > -     : parser_(parser), initialized_(false),\n> maxFrameLength_(maxFrameLength),\n> > +CamHelper::CamHelper(MdParser *parser, unsigned int\n> frameIntegrationDiff)\n> > +     : parser_(parser), initialized_(false),\n> >         frameIntegrationDiff_(frameIntegrationDiff)\n> >  {\n> >  }\n> > @@ -67,13 +66,12 @@ uint32_t CamHelper::GetVBlanking(double &exposure,\n> double minFrameDuration,\n> >       assert(initialized_);\n> >\n> >       /*\n> > -      * Clamp frame length by the frame duration range and the maximum\n> allowable\n> > -      * value in the sensor, given by maxFrameLength_.\n> > +      * minFrameDuration and maxFrameDuration are clamped by the caller\n> > +      * based on the limits for the active sensor mode.\n> >        */\n> > -     frameLengthMin = std::clamp<uint32_t>(1e3 * minFrameDuration /\n> mode_.line_length,\n> > -                                           mode_.height,\n> maxFrameLength_);\n> > -     frameLengthMax = std::clamp<uint32_t>(1e3 * maxFrameDuration /\n> mode_.line_length,\n> > -                                           mode_.height,\n> maxFrameLength_);\n> > +     frameLengthMin = 1e3 * minFrameDuration / mode_.line_length;\n> > +     frameLengthMax = 1e3 * maxFrameDuration / mode_.line_length;\n> > +\n> >       /*\n> >        * Limit the exposure to the maximum frame duration requested, and\n> >        * re-calculate if it has been clipped.\n> > diff --git a/src/ipa/raspberrypi/cam_helper.hpp\n> b/src/ipa/raspberrypi/cam_helper.hpp\n> > index b1739a57e342..14d70112cb62 100644\n> > --- a/src/ipa/raspberrypi/cam_helper.hpp\n> > +++ b/src/ipa/raspberrypi/cam_helper.hpp\n> > @@ -62,8 +62,7 @@ class CamHelper\n> >  {\n> >  public:\n> >       static CamHelper *Create(std::string const &cam_name);\n> > -     CamHelper(MdParser *parser, unsigned int maxFrameLength,\n> > -               unsigned int frameIntegrationDiff);\n> > +     CamHelper(MdParser *parser, unsigned int frameIntegrationDiff);\n> >       virtual ~CamHelper();\n> >       void SetCameraMode(const CameraMode &mode);\n> >       MdParser &Parser() const { return *parser_; }\n> > @@ -86,8 +85,6 @@ protected:\n> >\n> >  private:\n> >       bool initialized_;\n> > -     /* Largest possible frame length, in units of lines. */\n> > -     unsigned int maxFrameLength_;\n> >       /*\n> >        * Smallest difference between the frame length and integration\n> time,\n> >        * in units of lines.\n> > diff --git a/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> b/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> > index 8688ec091c44..95b8e698fe3b 100644\n> > --- a/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> > +++ b/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> > @@ -56,15 +56,13 @@ private:\n> >        * in units of lines.\n> >        */\n> >       static constexpr int frameIntegrationDiff = 4;\n> > -     /* Largest possible frame length, in units of lines. */\n> > -     static constexpr int maxFrameLength = 0xffff;\n> >  };\n> >\n> >  CamHelperImx219::CamHelperImx219()\n> >  #if ENABLE_EMBEDDED_DATA\n> > -     : CamHelper(new MdParserImx219(), maxFrameLength,\n> frameIntegrationDiff)\n> > +     : CamHelper(new MdParserImx219(), frameIntegrationDiff)\n> >  #else\n> > -     : CamHelper(new MdParserRPi(), maxFrameLength,\n> frameIntegrationDiff)\n> > +     : CamHelper(new MdParserRPi(), frameIntegrationDiff)\n> >  #endif\n> >  {\n> >  }\n> > diff --git a/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> b/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> > index 5396131003f1..eaa7be16d20e 100644\n> > --- a/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> > +++ b/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> > @@ -45,12 +45,10 @@ private:\n> >        * in units of lines.\n> >        */\n> >       static constexpr int frameIntegrationDiff = 22;\n> > -     /* Largest possible frame length, in units of lines. */\n> > -     static constexpr int maxFrameLength = 0xffdc;\n> >  };\n> >\n> >  CamHelperImx477::CamHelperImx477()\n> > -     : CamHelper(new MdParserImx477(), maxFrameLength,\n> frameIntegrationDiff)\n> > +     : CamHelper(new MdParserImx477(), frameIntegrationDiff)\n> >  {\n> >  }\n> >\n> > diff --git a/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> b/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> > index 2bd8a754f133..a7f417324048 100644\n> > --- a/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> > +++ b/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> > @@ -30,8 +30,6 @@ private:\n> >        * in units of lines.\n> >        */\n> >       static constexpr int frameIntegrationDiff = 4;\n> > -     /* Largest possible frame length, in units of lines. */\n> > -     static constexpr int maxFrameLength = 0xffff;\n> >  };\n> >\n> >  /*\n> > @@ -40,7 +38,7 @@ private:\n> >   */\n> >\n> >  CamHelperOv5647::CamHelperOv5647()\n> > -     : CamHelper(new MdParserRPi(), maxFrameLength,\n> frameIntegrationDiff)\n> > +     : CamHelper(new MdParserRPi(), frameIntegrationDiff)\n> >  {\n> >  }\n> >\n> > diff --git a/src/ipa/raspberrypi/controller/camera_mode.h\n> b/src/ipa/raspberrypi/controller/camera_mode.h\n> > index 920f11beb0b0..256438c931d9 100644\n> > --- a/src/ipa/raspberrypi/controller/camera_mode.h\n> > +++ b/src/ipa/raspberrypi/controller/camera_mode.h\n> > @@ -37,6 +37,8 @@ struct CameraMode {\n> >       double line_length;\n> >       // any camera transform *not* reflected already in the camera\n> tuning\n> >       libcamera::Transform transform;\n> > +     // minimum and maximum fame lengths in units of lines\n> > +     uint32_t min_frame_length, max_frame_length;\n> >  };\n> >\n> >  #ifdef __cplusplus\n> > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp\n> b/src/ipa/raspberrypi/raspberrypi.cpp\n> > index 5ccc7a6551f5..e4911b734e20 100644\n> > --- a/src/ipa/raspberrypi/raspberrypi.cpp\n> > +++ b/src/ipa/raspberrypi/raspberrypi.cpp\n> > @@ -102,6 +102,7 @@ private:\n> >       void reportMetadata();\n> >       bool parseEmbeddedData(unsigned int bufferId, struct DeviceStatus\n> &deviceStatus);\n> >       void processStats(unsigned int bufferId);\n> > +     void applyFrameDurations(double minFrameDuration, double\n> maxFrameDuration);\n> >       void applyAGC(const struct AgcStatus *agcStatus, ControlList\n> &ctrls);\n> >       void applyAWB(const struct AwbStatus *awbStatus, ControlList\n> &ctrls);\n> >       void applyDG(const struct AgcStatus *dgStatus, ControlList &ctrls);\n> > @@ -279,6 +280,13 @@ void IPARPi::setMode(const CameraSensorInfo\n> &sensorInfo)\n> >        * the line length in pixels and the pixel rate.\n> >        */\n> >       mode_.line_length = 1e9 * sensorInfo.lineLength /\n> sensorInfo.pixelRate;\n> > +\n> > +     /*\n> > +      * Set the frame length limits for the mode to ensure exposure and\n> > +      * framerate calculations are clipped appropriately.\n> > +      */\n> > +     mode_.min_frame_length = sensorInfo.minFrameLength;\n> > +     mode_.max_frame_length = sensorInfo.maxFrameLength;\n> >  }\n> >\n> >  void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n> > @@ -384,8 +392,8 @@ void IPARPi::configure(const CameraSensorInfo\n> &sensorInfo,\n> >               controller_.Initialise();\n> >               controllerInit_ = true;\n> >\n> > -             minFrameDuration_ = defaultMinFrameDuration;\n> > -             maxFrameDuration_ = defaultMaxFrameDuration;\n> > +             /* Supply initial values for frame durations. */\n> > +             applyFrameDurations(defaultMinFrameDuration,\n> defaultMaxFrameDuration);\n> >\n> >               /* Supply initial values for gain and exposure. */\n> >               ControlList ctrls(sensorCtrls_);\n> > @@ -819,20 +827,7 @@ void IPARPi::queueRequest(const ControlList\n> &controls)\n> >\n> >               case controls::FRAME_DURATIONS: {\n> >                       auto frameDurations = ctrl.second.get<Span<const\n> int64_t>>();\n> > -\n> > -                     /* This will be applied once AGC recalculations\n> occur. */\n> > -                     minFrameDuration_ = frameDurations[0] ?\n> frameDurations[0] : defaultMinFrameDuration;\n> > -                     maxFrameDuration_ = frameDurations[1] ?\n> frameDurations[1] : defaultMaxFrameDuration;\n> > -                     maxFrameDuration_ = std::max(maxFrameDuration_,\n> minFrameDuration_);\n> > -\n> > -                     /*\n> > -                      * \\todo The values returned in the metadata below\n> must be\n> > -                      * correctly clipped by what the sensor mode\n> supports and\n> > -                      * what the AGC exposure mode or manual shutter\n> speed limits\n> > -                      */\n> > -                     libcameraMetadata_.set(controls::FrameDurations,\n> > -                                            {\n> static_cast<int64_t>(minFrameDuration_),\n> > -\n> static_cast<int64_t>(maxFrameDuration_) });\n> > +                     applyFrameDurations(frameDurations[0],\n> frameDurations[1]);\n> >                       break;\n> >               }\n> >\n> > @@ -991,6 +986,28 @@ void IPARPi::applyAWB(const struct AwbStatus\n> *awbStatus, ControlList &ctrls)\n> >                 static_cast<int32_t>(awbStatus->gain_b * 1000));\n> >  }\n> >\n> > +void IPARPi::applyFrameDurations(double minFrameDuration, double\n> maxFrameDuration)\n> > +{\n> > +     const double minSensorFrameDuration = 1e-3 *\n> mode_.min_frame_length * mode_.line_length;\n> > +     const double maxSensorFrameDuration = 1e-3 *\n> mode_.max_frame_length * mode_.line_length;\n> > +\n> > +     /*\n> > +      * This will only be applied once AGC recalculations occur.\n> > +      * The values may be clamped based on the sensor mode capabilities\n> as well.\n> > +      */\n> > +     minFrameDuration_ = minFrameDuration ? minFrameDuration :\n> defaultMaxFrameDuration;\n> > +     maxFrameDuration_ = maxFrameDuration ? maxFrameDuration :\n> defaultMinFrameDuration;\n> > +     minFrameDuration_ = std::clamp(minFrameDuration_,\n> > +                                    minSensorFrameDuration,\n> maxSensorFrameDuration);\n> > +     maxFrameDuration_ = std::clamp(maxFrameDuration_,\n> > +                                    minSensorFrameDuration,\n> maxSensorFrameDuration);\n>\n> Do we need to keep\n>\n>         maxFrameDuration_ = std::max(maxFrameDuration_, minFrameDuration_);\n>\n> in case the user passes a minimum higher than the maximum ? Apart from\n> that (which I can fix when applying if needed),\n>\n\nPlease correct me if I am wrong, but having the *FrameDuration_ values\nclamped by the *SensorFrameDurations would assure that max >= min, so I\nremoved that statement.  This is assuming that the sensor driver reports\nmax vblank >= min vblank - which it should.\n\nRegards,\nNaush\n\n\n>\n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n>\n> > +\n> > +     /* Return the validated limits out though metadata. */\n> > +     libcameraMetadata_.set(controls::FrameDurations,\n> > +                            { static_cast<int64_t>(minFrameDuration_),\n> > +                              static_cast<int64_t>(maxFrameDuration_)\n> });\n> > +}\n> > +\n> >  void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList\n> &ctrls)\n> >  {\n> >       int32_t gainCode = helper_->GainCode(agcStatus->analogue_gain);\n>\n> --\n> Regards,\n>\n> Laurent Pinchart\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 80155BD162\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  4 Feb 2021 22:19:26 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D7C586148D;\n\tThu,  4 Feb 2021 23:19:25 +0100 (CET)","from mail-lj1-x230.google.com (mail-lj1-x230.google.com\n\t[IPv6:2a00:1450:4864:20::230])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E484B61430\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  4 Feb 2021 23:19:24 +0100 (CET)","by mail-lj1-x230.google.com with SMTP id m22so5381355ljj.4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 04 Feb 2021 14:19:24 -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=\"WwIba2z9\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google;\n\th=mime-version:references:in-reply-to:from:date:message-id:subject:to\n\t:cc; bh=AUhKxAmHww6RLbq+/o4MQTAEsd16jv05ioQPOqQQBDM=;\n\tb=WwIba2z9TMqJ+TaVm0FQYblRmv71V8VZTpsd9mqOV1ua269Dp77JjqMh6STpJc8MWJ\n\tmu4rIMICR0Oj8td7Bu6Kl9MZRjd8sjC9MnvtNgIgFY65F07aln5oosXu3GQTclq0op/I\n\t+GR2ukpgnv+4j8g+I5AkeW/o+IzZKcjftG1hAZbqzEbyrB8uIcz1IuraVUx4q3zMx+C/\n\toAi8lKIspiKsTBt6NJ3plvr9mAvRwm4/gzxFJIRk/VjCAXMzzPUaUEwFYuN0H7kiP2Bk\n\tVQEumfL0eJRMBEn3tLXswBch35ra9/3MiRgR2iUGVrNnd9RMkrYzb5Tr/Z2hQpHE+2As\n\tuqPg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:references:in-reply-to:from:date\n\t:message-id:subject:to:cc;\n\tbh=AUhKxAmHww6RLbq+/o4MQTAEsd16jv05ioQPOqQQBDM=;\n\tb=W3CUyBKiFeDytQ79t3RqEA65aEXeMKPzAAVDq65vQnz/JoVzbhuuhjv6thVlGxmPGH\n\tw6cmcm9mHE4jM6T1QDjK5b2oDztRpZuftrBEmG5BFdDdfMbkmUmcvZmFBvq1tNHy/pUS\n\t54WtfkVviw3dQiKiQ7j275ZPdTkNdDZdT1FvO0Zd9BT8ZbsCEJ6EKTd66xmYJAp1BxRx\n\tEgNqtyy3GW/WIM5mZ5N5tjqq63rF6K+2HVafdDwGcj7JMKb9WFuCmXqyp5wPz8iy1ug1\n\tjAP4GFBESJMhSq09Bt5blLXHYjqmuAvAxc0sdn0n3PRbAJgGo1LZE00N8G/YrtaVIcM7\n\tu1xQ==","X-Gm-Message-State":"AOAM532S57IE4tP9Y12SZ3IHxEZcZvaezYRd9vAM+3wzt2kesuBx7LTL\n\t3WvuT7ia68KsXHZLvhN//wp1OmMPVw4do+RzCvyjIe6Xsz6/iQ==","X-Google-Smtp-Source":"ABdhPJyC/24jsFghrnWks5n3Q1ohOnToYYx0m4JxWYJN7cxJVGh6jWpEO/a+z59ARhiA7NIxchAaBWwsy4vg2ODzbPg=","X-Received":"by 2002:a2e:7605:: with SMTP id r5mr801635ljc.299.1612477163903; \n\tThu, 04 Feb 2021 14:19:23 -0800 (PST)","MIME-Version":"1.0","References":"<20210129111616.1047483-1-naush@raspberrypi.com>\n\t<20210129111616.1047483-4-naush@raspberrypi.com>\n\t<YBxWtBH9fxEc4TDW@pendragon.ideasonboard.com>","In-Reply-To":"<YBxWtBH9fxEc4TDW@pendragon.ideasonboard.com>","From":"Naushir Patuck <naush@raspberrypi.com>","Date":"Thu, 4 Feb 2021 22:19:07 +0000","Message-ID":"<CAEmqJPq=WfhL=vg134kDHt91Rf1ahXO7JMeb-WZBE8b5isS-zw@mail.gmail.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v4 3/5] ipa: raspberrypi: Limit the\n\tcalculated vblank based on the sensor mode","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>","Cc":"libcamera devel <libcamera-devel@lists.libcamera.org>","Content-Type":"multipart/mixed;\n\tboundary=\"===============4381835472606735086==\"","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":15012,"web_url":"https://patchwork.libcamera.org/comment/15012/","msgid":"<YBx0ITiSgNb3n4sp@pendragon.ideasonboard.com>","date":"2021-02-04T22:24:33","subject":"Re: [libcamera-devel] [PATCH v4 3/5] ipa: raspberrypi: Limit the\n\tcalculated vblank based on the sensor mode","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Naush,\n\nOn Thu, Feb 04, 2021 at 10:19:07PM +0000, Naushir Patuck wrote:\n> On Thu, 4 Feb 2021 at 20:19, Laurent Pinchart wrote:\n> > On Fri, Jan 29, 2021 at 11:16:14AM +0000, Naushir Patuck wrote:\n> > > The existing framerate/vblank calculations did not account for the\n> > > sensor mode limits. This commit extracts vblank limits from the sensor\n> > > v4l2 controls, and stores it in the camera modes structure.\n> > >\n> > > Exposure and vblank value calculations now use values clamped to the\n> > > sensor mode limits. The libcamera::controls::FrameDurations metadata\n> > > return values now reflect the minimum and maximum after clamping.\n> > >\n> > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>\n> > > Reviewed-by: David Plowman <david.plowman@raspberrypi.com>\n> > > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> > > ---\n> > >  src/ipa/raspberrypi/cam_helper.cpp           | 16 +++----\n> > >  src/ipa/raspberrypi/cam_helper.hpp           |  5 +-\n> > >  src/ipa/raspberrypi/cam_helper_imx219.cpp    |  6 +--\n> > >  src/ipa/raspberrypi/cam_helper_imx477.cpp    |  4 +-\n> > >  src/ipa/raspberrypi/cam_helper_ov5647.cpp    |  4 +-\n> > >  src/ipa/raspberrypi/controller/camera_mode.h |  2 +\n> > >  src/ipa/raspberrypi/raspberrypi.cpp          | 49 +++++++++++++-------\n> > >  7 files changed, 47 insertions(+), 39 deletions(-)\n> > >\n> > > diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp\n> > > index b7b8faf09c69..93d1b7b0296a 100644\n> > > --- a/src/ipa/raspberrypi/cam_helper.cpp\n> > > +++ b/src/ipa/raspberrypi/cam_helper.cpp\n> > > @@ -34,9 +34,8 @@ CamHelper *CamHelper::Create(std::string const &cam_name)\n> > >       return nullptr;\n> > >  }\n> > >\n> > > -CamHelper::CamHelper(MdParser *parser, unsigned int maxFrameLength,\n> > > -                  unsigned int frameIntegrationDiff)\n> > > -     : parser_(parser), initialized_(false), maxFrameLength_(maxFrameLength),\n> > > +CamHelper::CamHelper(MdParser *parser, unsigned int frameIntegrationDiff)\n> > > +     : parser_(parser), initialized_(false),\n> > >         frameIntegrationDiff_(frameIntegrationDiff)\n> > >  {\n> > >  }\n> > > @@ -67,13 +66,12 @@ uint32_t CamHelper::GetVBlanking(double &exposure, double minFrameDuration,\n> > >       assert(initialized_);\n> > >\n> > >       /*\n> > > -      * Clamp frame length by the frame duration range and the maximum allowable\n> > > -      * value in the sensor, given by maxFrameLength_.\n> > > +      * minFrameDuration and maxFrameDuration are clamped by the caller\n> > > +      * based on the limits for the active sensor mode.\n> > >        */\n> > > -     frameLengthMin = std::clamp<uint32_t>(1e3 * minFrameDuration / mode_.line_length,\n> > > -                                           mode_.height, maxFrameLength_);\n> > > -     frameLengthMax = std::clamp<uint32_t>(1e3 * maxFrameDuration / mode_.line_length,\n> > > -                                           mode_.height, maxFrameLength_);\n> > > +     frameLengthMin = 1e3 * minFrameDuration / mode_.line_length;\n> > > +     frameLengthMax = 1e3 * maxFrameDuration / mode_.line_length;\n> > > +\n> > >       /*\n> > >        * Limit the exposure to the maximum frame duration requested, and\n> > >        * re-calculate if it has been clipped.\n> > > diff --git a/src/ipa/raspberrypi/cam_helper.hpp b/src/ipa/raspberrypi/cam_helper.hpp\n> > > index b1739a57e342..14d70112cb62 100644\n> > > --- a/src/ipa/raspberrypi/cam_helper.hpp\n> > > +++ b/src/ipa/raspberrypi/cam_helper.hpp\n> > > @@ -62,8 +62,7 @@ class CamHelper\n> > >  {\n> > >  public:\n> > >       static CamHelper *Create(std::string const &cam_name);\n> > > -     CamHelper(MdParser *parser, unsigned int maxFrameLength,\n> > > -               unsigned int frameIntegrationDiff);\n> > > +     CamHelper(MdParser *parser, unsigned int frameIntegrationDiff);\n> > >       virtual ~CamHelper();\n> > >       void SetCameraMode(const CameraMode &mode);\n> > >       MdParser &Parser() const { return *parser_; }\n> > > @@ -86,8 +85,6 @@ protected:\n> > >\n> > >  private:\n> > >       bool initialized_;\n> > > -     /* Largest possible frame length, in units of lines. */\n> > > -     unsigned int maxFrameLength_;\n> > >       /*\n> > >        * Smallest difference between the frame length and integration time,\n> > >        * in units of lines.\n> > > diff --git a/src/ipa/raspberrypi/cam_helper_imx219.cpp b/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> > > index 8688ec091c44..95b8e698fe3b 100644\n> > > --- a/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> > > +++ b/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> > > @@ -56,15 +56,13 @@ private:\n> > >        * in units of lines.\n> > >        */\n> > >       static constexpr int frameIntegrationDiff = 4;\n> > > -     /* Largest possible frame length, in units of lines. */\n> > > -     static constexpr int maxFrameLength = 0xffff;\n> > >  };\n> > >\n> > >  CamHelperImx219::CamHelperImx219()\n> > >  #if ENABLE_EMBEDDED_DATA\n> > > -     : CamHelper(new MdParserImx219(), maxFrameLength, frameIntegrationDiff)\n> > > +     : CamHelper(new MdParserImx219(), frameIntegrationDiff)\n> > >  #else\n> > > -     : CamHelper(new MdParserRPi(), maxFrameLength, frameIntegrationDiff)\n> > > +     : CamHelper(new MdParserRPi(), frameIntegrationDiff)\n> > >  #endif\n> > >  {\n> > >  }\n> > > diff --git a/src/ipa/raspberrypi/cam_helper_imx477.cpp b/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> > > index 5396131003f1..eaa7be16d20e 100644\n> > > --- a/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> > > +++ b/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> > > @@ -45,12 +45,10 @@ private:\n> > >        * in units of lines.\n> > >        */\n> > >       static constexpr int frameIntegrationDiff = 22;\n> > > -     /* Largest possible frame length, in units of lines. */\n> > > -     static constexpr int maxFrameLength = 0xffdc;\n> > >  };\n> > >\n> > >  CamHelperImx477::CamHelperImx477()\n> > > -     : CamHelper(new MdParserImx477(), maxFrameLength, frameIntegrationDiff)\n> > > +     : CamHelper(new MdParserImx477(), frameIntegrationDiff)\n> > >  {\n> > >  }\n> > >\n> > > diff --git a/src/ipa/raspberrypi/cam_helper_ov5647.cpp b/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> > > index 2bd8a754f133..a7f417324048 100644\n> > > --- a/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> > > +++ b/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> > > @@ -30,8 +30,6 @@ private:\n> > >        * in units of lines.\n> > >        */\n> > >       static constexpr int frameIntegrationDiff = 4;\n> > > -     /* Largest possible frame length, in units of lines. */\n> > > -     static constexpr int maxFrameLength = 0xffff;\n> > >  };\n> > >\n> > >  /*\n> > > @@ -40,7 +38,7 @@ private:\n> > >   */\n> > >\n> > >  CamHelperOv5647::CamHelperOv5647()\n> > > -     : CamHelper(new MdParserRPi(), maxFrameLength, frameIntegrationDiff)\n> > > +     : CamHelper(new MdParserRPi(), frameIntegrationDiff)\n> > >  {\n> > >  }\n> > >\n> > > diff --git a/src/ipa/raspberrypi/controller/camera_mode.h b/src/ipa/raspberrypi/controller/camera_mode.h\n> > > index 920f11beb0b0..256438c931d9 100644\n> > > --- a/src/ipa/raspberrypi/controller/camera_mode.h\n> > > +++ b/src/ipa/raspberrypi/controller/camera_mode.h\n> > > @@ -37,6 +37,8 @@ struct CameraMode {\n> > >       double line_length;\n> > >       // any camera transform *not* reflected already in the camera tuning\n> > >       libcamera::Transform transform;\n> > > +     // minimum and maximum fame lengths in units of lines\n> > > +     uint32_t min_frame_length, max_frame_length;\n> > >  };\n> > >\n> > >  #ifdef __cplusplus\n> > > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp\n> > > index 5ccc7a6551f5..e4911b734e20 100644\n> > > --- a/src/ipa/raspberrypi/raspberrypi.cpp\n> > > +++ b/src/ipa/raspberrypi/raspberrypi.cpp\n> > > @@ -102,6 +102,7 @@ private:\n> > >       void reportMetadata();\n> > >       bool parseEmbeddedData(unsigned int bufferId, struct DeviceStatus &deviceStatus);\n> > >       void processStats(unsigned int bufferId);\n> > > +     void applyFrameDurations(double minFrameDuration, double maxFrameDuration);\n> > >       void applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls);\n> > >       void applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls);\n> > >       void applyDG(const struct AgcStatus *dgStatus, ControlList &ctrls);\n> > > @@ -279,6 +280,13 @@ void IPARPi::setMode(const CameraSensorInfo &sensorInfo)\n> > >        * the line length in pixels and the pixel rate.\n> > >        */\n> > >       mode_.line_length = 1e9 * sensorInfo.lineLength / sensorInfo.pixelRate;\n> > > +\n> > > +     /*\n> > > +      * Set the frame length limits for the mode to ensure exposure and\n> > > +      * framerate calculations are clipped appropriately.\n> > > +      */\n> > > +     mode_.min_frame_length = sensorInfo.minFrameLength;\n> > > +     mode_.max_frame_length = sensorInfo.maxFrameLength;\n> > >  }\n> > >\n> > >  void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n> > > @@ -384,8 +392,8 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n> > >               controller_.Initialise();\n> > >               controllerInit_ = true;\n> > >\n> > > -             minFrameDuration_ = defaultMinFrameDuration;\n> > > -             maxFrameDuration_ = defaultMaxFrameDuration;\n> > > +             /* Supply initial values for frame durations. */\n> > > +             applyFrameDurations(defaultMinFrameDuration, defaultMaxFrameDuration);\n> > >\n> > >               /* Supply initial values for gain and exposure. */\n> > >               ControlList ctrls(sensorCtrls_);\n> > > @@ -819,20 +827,7 @@ void IPARPi::queueRequest(const ControlList &controls)\n> > >\n> > >               case controls::FRAME_DURATIONS: {\n> > >                       auto frameDurations = ctrl.second.get<Span<const int64_t>>();\n> > > -\n> > > -                     /* This will be applied once AGC recalculations occur. */\n> > > -                     minFrameDuration_ = frameDurations[0] ? frameDurations[0] : defaultMinFrameDuration;\n> > > -                     maxFrameDuration_ = frameDurations[1] ? frameDurations[1] : defaultMaxFrameDuration;\n> > > -                     maxFrameDuration_ = std::max(maxFrameDuration_, minFrameDuration_);\n> > > -\n> > > -                     /*\n> > > -                      * \\todo The values returned in the metadata below must be\n> > > -                      * correctly clipped by what the sensor mode supports and\n> > > -                      * what the AGC exposure mode or manual shutter speed limits\n> > > -                      */\n> > > -                     libcameraMetadata_.set(controls::FrameDurations,\n> > > -                                            { static_cast<int64_t>(minFrameDuration_),\n> > > - static_cast<int64_t>(maxFrameDuration_) });\n> > > +                     applyFrameDurations(frameDurations[0], frameDurations[1]);\n> > >                       break;\n> > >               }\n> > >\n> > > @@ -991,6 +986,28 @@ void IPARPi::applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls)\n> > >                 static_cast<int32_t>(awbStatus->gain_b * 1000));\n> > >  }\n> > >\n> > > +void IPARPi::applyFrameDurations(double minFrameDuration, double maxFrameDuration)\n> > > +{\n> > > +     const double minSensorFrameDuration = 1e-3 * mode_.min_frame_length * mode_.line_length;\n> > > +     const double maxSensorFrameDuration = 1e-3 * mode_.max_frame_length * mode_.line_length;\n> > > +\n> > > +     /*\n> > > +      * This will only be applied once AGC recalculations occur.\n> > > +      * The values may be clamped based on the sensor mode capabilities as well.\n> > > +      */\n> > > +     minFrameDuration_ = minFrameDuration ? minFrameDuration : defaultMaxFrameDuration;\n> > > +     maxFrameDuration_ = maxFrameDuration ? maxFrameDuration : defaultMinFrameDuration;\n> > > +     minFrameDuration_ = std::clamp(minFrameDuration_,\n> > > +                                    minSensorFrameDuration, maxSensorFrameDuration);\n> > > +     maxFrameDuration_ = std::clamp(maxFrameDuration_,\n> > > +                                    minSensorFrameDuration, maxSensorFrameDuration);\n> >\n> > Do we need to keep\n> >\n> >         maxFrameDuration_ = std::max(maxFrameDuration_, minFrameDuration_);\n> >\n> > in case the user passes a minimum higher than the maximum ? Apart from\n> > that (which I can fix when applying if needed),\n> \n> Please correct me if I am wrong, but having the *FrameDuration_ values\n> clamped by the *SensorFrameDurations would assure that max >= min, so I\n> removed that statement.  This is assuming that the sensor driver reports\n> max vblank >= min vblank - which it should.\n\nLet's assume\n\n- minSensorFrameDuration = 1000\n- maxSensorFrameDuration = 5000\n- minFrameDuration = 2000\n- maxFrameDuration = 1500\n\nAfter clamping the minFrameDuration and maxFrameDuration values are not\nchanged, and minFrameDuration is still > maxFrameDuration. Am I missing\nsomething ?\n\n> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> >\n> > > +\n> > > +     /* Return the validated limits out though metadata. */\n> > > +     libcameraMetadata_.set(controls::FrameDurations,\n> > > +                            { static_cast<int64_t>(minFrameDuration_),\n> > > +                              static_cast<int64_t>(maxFrameDuration_) });\n> > > +}\n> > > +\n> > >  void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)\n> > >  {\n> > >       int32_t gainCode = helper_->GainCode(agcStatus->analogue_gain);","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 6C274BD160\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  4 Feb 2021 22:24:59 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id EB85461491;\n\tThu,  4 Feb 2021 23:24:58 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 09CB161489\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  4 Feb 2021 23:24:57 +0100 (CET)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 7243E45D;\n\tThu,  4 Feb 2021 23:24:56 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"nX4udMPj\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1612477496;\n\tbh=Xgpaf1JGKwLZWd2ye+FJgeKdtQU5/bmcujGRZk8kmP0=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=nX4udMPjLBxXMOr44f42O+6e4Ztn0fLhMWI3AXCS+sKzpQvd6/PwlIIuXSES52Q3V\n\taOXgWEiHa0poMgFEVhhylWoSx91TyAGO66JG+9hbWe0epsN/bp1uMNdRrGsQ6pReAx\n\tvQQ440GgmvGILCHSVHi1EvWqvfINAdAqyHeph0qw=","Date":"Fri, 5 Feb 2021 00:24:33 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Naushir Patuck <naush@raspberrypi.com>","Message-ID":"<YBx0ITiSgNb3n4sp@pendragon.ideasonboard.com>","References":"<20210129111616.1047483-1-naush@raspberrypi.com>\n\t<20210129111616.1047483-4-naush@raspberrypi.com>\n\t<YBxWtBH9fxEc4TDW@pendragon.ideasonboard.com>\n\t<CAEmqJPq=WfhL=vg134kDHt91Rf1ahXO7JMeb-WZBE8b5isS-zw@mail.gmail.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<CAEmqJPq=WfhL=vg134kDHt91Rf1ahXO7JMeb-WZBE8b5isS-zw@mail.gmail.com>","Subject":"Re: [libcamera-devel] [PATCH v4 3/5] ipa: raspberrypi: Limit the\n\tcalculated vblank based on the sensor mode","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>","Cc":"libcamera devel <libcamera-devel@lists.libcamera.org>","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>"}},{"id":15013,"web_url":"https://patchwork.libcamera.org/comment/15013/","msgid":"<CAEmqJPpSYY03gVL-oq8DuRZhvXRTQZL8usOjOugZN8jvfu0nfw@mail.gmail.com>","date":"2021-02-04T22:30:11","subject":"Re: [libcamera-devel] [PATCH v4 3/5] ipa: raspberrypi: Limit the\n\tcalculated vblank based on the sensor mode","submitter":{"id":34,"url":"https://patchwork.libcamera.org/api/people/34/","name":"Naushir Patuck","email":"naush@raspberrypi.com"},"content":"Hi Laurent,\n\nOn Thu, 4 Feb 2021 at 22:24, Laurent Pinchart <\nlaurent.pinchart@ideasonboard.com> wrote:\n\n> Hi Naush,\n>\n> On Thu, Feb 04, 2021 at 10:19:07PM +0000, Naushir Patuck wrote:\n> > On Thu, 4 Feb 2021 at 20:19, Laurent Pinchart wrote:\n> > > On Fri, Jan 29, 2021 at 11:16:14AM +0000, Naushir Patuck wrote:\n> > > > The existing framerate/vblank calculations did not account for the\n> > > > sensor mode limits. This commit extracts vblank limits from the\n> sensor\n> > > > v4l2 controls, and stores it in the camera modes structure.\n> > > >\n> > > > Exposure and vblank value calculations now use values clamped to the\n> > > > sensor mode limits. The libcamera::controls::FrameDurations metadata\n> > > > return values now reflect the minimum and maximum after clamping.\n> > > >\n> > > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>\n> > > > Reviewed-by: David Plowman <david.plowman@raspberrypi.com>\n> > > > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> > > > ---\n> > > >  src/ipa/raspberrypi/cam_helper.cpp           | 16 +++----\n> > > >  src/ipa/raspberrypi/cam_helper.hpp           |  5 +-\n> > > >  src/ipa/raspberrypi/cam_helper_imx219.cpp    |  6 +--\n> > > >  src/ipa/raspberrypi/cam_helper_imx477.cpp    |  4 +-\n> > > >  src/ipa/raspberrypi/cam_helper_ov5647.cpp    |  4 +-\n> > > >  src/ipa/raspberrypi/controller/camera_mode.h |  2 +\n> > > >  src/ipa/raspberrypi/raspberrypi.cpp          | 49\n> +++++++++++++-------\n> > > >  7 files changed, 47 insertions(+), 39 deletions(-)\n> > > >\n> > > > diff --git a/src/ipa/raspberrypi/cam_helper.cpp\n> b/src/ipa/raspberrypi/cam_helper.cpp\n> > > > index b7b8faf09c69..93d1b7b0296a 100644\n> > > > --- a/src/ipa/raspberrypi/cam_helper.cpp\n> > > > +++ b/src/ipa/raspberrypi/cam_helper.cpp\n> > > > @@ -34,9 +34,8 @@ CamHelper *CamHelper::Create(std::string const\n> &cam_name)\n> > > >       return nullptr;\n> > > >  }\n> > > >\n> > > > -CamHelper::CamHelper(MdParser *parser, unsigned int maxFrameLength,\n> > > > -                  unsigned int frameIntegrationDiff)\n> > > > -     : parser_(parser), initialized_(false),\n> maxFrameLength_(maxFrameLength),\n> > > > +CamHelper::CamHelper(MdParser *parser, unsigned int\n> frameIntegrationDiff)\n> > > > +     : parser_(parser), initialized_(false),\n> > > >         frameIntegrationDiff_(frameIntegrationDiff)\n> > > >  {\n> > > >  }\n> > > > @@ -67,13 +66,12 @@ uint32_t CamHelper::GetVBlanking(double\n> &exposure, double minFrameDuration,\n> > > >       assert(initialized_);\n> > > >\n> > > >       /*\n> > > > -      * Clamp frame length by the frame duration range and the\n> maximum allowable\n> > > > -      * value in the sensor, given by maxFrameLength_.\n> > > > +      * minFrameDuration and maxFrameDuration are clamped by the\n> caller\n> > > > +      * based on the limits for the active sensor mode.\n> > > >        */\n> > > > -     frameLengthMin = std::clamp<uint32_t>(1e3 * minFrameDuration /\n> mode_.line_length,\n> > > > -                                           mode_.height,\n> maxFrameLength_);\n> > > > -     frameLengthMax = std::clamp<uint32_t>(1e3 * maxFrameDuration /\n> mode_.line_length,\n> > > > -                                           mode_.height,\n> maxFrameLength_);\n> > > > +     frameLengthMin = 1e3 * minFrameDuration / mode_.line_length;\n> > > > +     frameLengthMax = 1e3 * maxFrameDuration / mode_.line_length;\n> > > > +\n> > > >       /*\n> > > >        * Limit the exposure to the maximum frame duration requested,\n> and\n> > > >        * re-calculate if it has been clipped.\n> > > > diff --git a/src/ipa/raspberrypi/cam_helper.hpp\n> b/src/ipa/raspberrypi/cam_helper.hpp\n> > > > index b1739a57e342..14d70112cb62 100644\n> > > > --- a/src/ipa/raspberrypi/cam_helper.hpp\n> > > > +++ b/src/ipa/raspberrypi/cam_helper.hpp\n> > > > @@ -62,8 +62,7 @@ class CamHelper\n> > > >  {\n> > > >  public:\n> > > >       static CamHelper *Create(std::string const &cam_name);\n> > > > -     CamHelper(MdParser *parser, unsigned int maxFrameLength,\n> > > > -               unsigned int frameIntegrationDiff);\n> > > > +     CamHelper(MdParser *parser, unsigned int frameIntegrationDiff);\n> > > >       virtual ~CamHelper();\n> > > >       void SetCameraMode(const CameraMode &mode);\n> > > >       MdParser &Parser() const { return *parser_; }\n> > > > @@ -86,8 +85,6 @@ protected:\n> > > >\n> > > >  private:\n> > > >       bool initialized_;\n> > > > -     /* Largest possible frame length, in units of lines. */\n> > > > -     unsigned int maxFrameLength_;\n> > > >       /*\n> > > >        * Smallest difference between the frame length and\n> integration time,\n> > > >        * in units of lines.\n> > > > diff --git a/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> b/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> > > > index 8688ec091c44..95b8e698fe3b 100644\n> > > > --- a/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> > > > +++ b/src/ipa/raspberrypi/cam_helper_imx219.cpp\n> > > > @@ -56,15 +56,13 @@ private:\n> > > >        * in units of lines.\n> > > >        */\n> > > >       static constexpr int frameIntegrationDiff = 4;\n> > > > -     /* Largest possible frame length, in units of lines. */\n> > > > -     static constexpr int maxFrameLength = 0xffff;\n> > > >  };\n> > > >\n> > > >  CamHelperImx219::CamHelperImx219()\n> > > >  #if ENABLE_EMBEDDED_DATA\n> > > > -     : CamHelper(new MdParserImx219(), maxFrameLength,\n> frameIntegrationDiff)\n> > > > +     : CamHelper(new MdParserImx219(), frameIntegrationDiff)\n> > > >  #else\n> > > > -     : CamHelper(new MdParserRPi(), maxFrameLength,\n> frameIntegrationDiff)\n> > > > +     : CamHelper(new MdParserRPi(), frameIntegrationDiff)\n> > > >  #endif\n> > > >  {\n> > > >  }\n> > > > diff --git a/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> b/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> > > > index 5396131003f1..eaa7be16d20e 100644\n> > > > --- a/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> > > > +++ b/src/ipa/raspberrypi/cam_helper_imx477.cpp\n> > > > @@ -45,12 +45,10 @@ private:\n> > > >        * in units of lines.\n> > > >        */\n> > > >       static constexpr int frameIntegrationDiff = 22;\n> > > > -     /* Largest possible frame length, in units of lines. */\n> > > > -     static constexpr int maxFrameLength = 0xffdc;\n> > > >  };\n> > > >\n> > > >  CamHelperImx477::CamHelperImx477()\n> > > > -     : CamHelper(new MdParserImx477(), maxFrameLength,\n> frameIntegrationDiff)\n> > > > +     : CamHelper(new MdParserImx477(), frameIntegrationDiff)\n> > > >  {\n> > > >  }\n> > > >\n> > > > diff --git a/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> b/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> > > > index 2bd8a754f133..a7f417324048 100644\n> > > > --- a/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> > > > +++ b/src/ipa/raspberrypi/cam_helper_ov5647.cpp\n> > > > @@ -30,8 +30,6 @@ private:\n> > > >        * in units of lines.\n> > > >        */\n> > > >       static constexpr int frameIntegrationDiff = 4;\n> > > > -     /* Largest possible frame length, in units of lines. */\n> > > > -     static constexpr int maxFrameLength = 0xffff;\n> > > >  };\n> > > >\n> > > >  /*\n> > > > @@ -40,7 +38,7 @@ private:\n> > > >   */\n> > > >\n> > > >  CamHelperOv5647::CamHelperOv5647()\n> > > > -     : CamHelper(new MdParserRPi(), maxFrameLength,\n> frameIntegrationDiff)\n> > > > +     : CamHelper(new MdParserRPi(), frameIntegrationDiff)\n> > > >  {\n> > > >  }\n> > > >\n> > > > diff --git a/src/ipa/raspberrypi/controller/camera_mode.h\n> b/src/ipa/raspberrypi/controller/camera_mode.h\n> > > > index 920f11beb0b0..256438c931d9 100644\n> > > > --- a/src/ipa/raspberrypi/controller/camera_mode.h\n> > > > +++ b/src/ipa/raspberrypi/controller/camera_mode.h\n> > > > @@ -37,6 +37,8 @@ struct CameraMode {\n> > > >       double line_length;\n> > > >       // any camera transform *not* reflected already in the camera\n> tuning\n> > > >       libcamera::Transform transform;\n> > > > +     // minimum and maximum fame lengths in units of lines\n> > > > +     uint32_t min_frame_length, max_frame_length;\n> > > >  };\n> > > >\n> > > >  #ifdef __cplusplus\n> > > > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp\n> b/src/ipa/raspberrypi/raspberrypi.cpp\n> > > > index 5ccc7a6551f5..e4911b734e20 100644\n> > > > --- a/src/ipa/raspberrypi/raspberrypi.cpp\n> > > > +++ b/src/ipa/raspberrypi/raspberrypi.cpp\n> > > > @@ -102,6 +102,7 @@ private:\n> > > >       void reportMetadata();\n> > > >       bool parseEmbeddedData(unsigned int bufferId, struct\n> DeviceStatus &deviceStatus);\n> > > >       void processStats(unsigned int bufferId);\n> > > > +     void applyFrameDurations(double minFrameDuration, double\n> maxFrameDuration);\n> > > >       void applyAGC(const struct AgcStatus *agcStatus, ControlList\n> &ctrls);\n> > > >       void applyAWB(const struct AwbStatus *awbStatus, ControlList\n> &ctrls);\n> > > >       void applyDG(const struct AgcStatus *dgStatus, ControlList\n> &ctrls);\n> > > > @@ -279,6 +280,13 @@ void IPARPi::setMode(const CameraSensorInfo\n> &sensorInfo)\n> > > >        * the line length in pixels and the pixel rate.\n> > > >        */\n> > > >       mode_.line_length = 1e9 * sensorInfo.lineLength /\n> sensorInfo.pixelRate;\n> > > > +\n> > > > +     /*\n> > > > +      * Set the frame length limits for the mode to ensure exposure\n> and\n> > > > +      * framerate calculations are clipped appropriately.\n> > > > +      */\n> > > > +     mode_.min_frame_length = sensorInfo.minFrameLength;\n> > > > +     mode_.max_frame_length = sensorInfo.maxFrameLength;\n> > > >  }\n> > > >\n> > > >  void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n> > > > @@ -384,8 +392,8 @@ void IPARPi::configure(const CameraSensorInfo\n> &sensorInfo,\n> > > >               controller_.Initialise();\n> > > >               controllerInit_ = true;\n> > > >\n> > > > -             minFrameDuration_ = defaultMinFrameDuration;\n> > > > -             maxFrameDuration_ = defaultMaxFrameDuration;\n> > > > +             /* Supply initial values for frame durations. */\n> > > > +             applyFrameDurations(defaultMinFrameDuration,\n> defaultMaxFrameDuration);\n> > > >\n> > > >               /* Supply initial values for gain and exposure. */\n> > > >               ControlList ctrls(sensorCtrls_);\n> > > > @@ -819,20 +827,7 @@ void IPARPi::queueRequest(const ControlList\n> &controls)\n> > > >\n> > > >               case controls::FRAME_DURATIONS: {\n> > > >                       auto frameDurations =\n> ctrl.second.get<Span<const int64_t>>();\n> > > > -\n> > > > -                     /* This will be applied once AGC\n> recalculations occur. */\n> > > > -                     minFrameDuration_ = frameDurations[0] ?\n> frameDurations[0] : defaultMinFrameDuration;\n> > > > -                     maxFrameDuration_ = frameDurations[1] ?\n> frameDurations[1] : defaultMaxFrameDuration;\n> > > > -                     maxFrameDuration_ =\n> std::max(maxFrameDuration_, minFrameDuration_);\n> > > > -\n> > > > -                     /*\n> > > > -                      * \\todo The values returned in the metadata\n> below must be\n> > > > -                      * correctly clipped by what the sensor mode\n> supports and\n> > > > -                      * what the AGC exposure mode or manual\n> shutter speed limits\n> > > > -                      */\n> > > > -\n>  libcameraMetadata_.set(controls::FrameDurations,\n> > > > -                                            {\n> static_cast<int64_t>(minFrameDuration_),\n> > > > - static_cast<int64_t>(maxFrameDuration_) });\n> > > > +                     applyFrameDurations(frameDurations[0],\n> frameDurations[1]);\n> > > >                       break;\n> > > >               }\n> > > >\n> > > > @@ -991,6 +986,28 @@ void IPARPi::applyAWB(const struct AwbStatus\n> *awbStatus, ControlList &ctrls)\n> > > >                 static_cast<int32_t>(awbStatus->gain_b * 1000));\n> > > >  }\n> > > >\n> > > > +void IPARPi::applyFrameDurations(double minFrameDuration, double\n> maxFrameDuration)\n> > > > +{\n> > > > +     const double minSensorFrameDuration = 1e-3 *\n> mode_.min_frame_length * mode_.line_length;\n> > > > +     const double maxSensorFrameDuration = 1e-3 *\n> mode_.max_frame_length * mode_.line_length;\n> > > > +\n> > > > +     /*\n> > > > +      * This will only be applied once AGC recalculations occur.\n> > > > +      * The values may be clamped based on the sensor mode\n> capabilities as well.\n> > > > +      */\n> > > > +     minFrameDuration_ = minFrameDuration ? minFrameDuration :\n> defaultMaxFrameDuration;\n> > > > +     maxFrameDuration_ = maxFrameDuration ? maxFrameDuration :\n> defaultMinFrameDuration;\n> > > > +     minFrameDuration_ = std::clamp(minFrameDuration_,\n> > > > +                                    minSensorFrameDuration,\n> maxSensorFrameDuration);\n> > > > +     maxFrameDuration_ = std::clamp(maxFrameDuration_,\n> > > > +                                    minSensorFrameDuration,\n> maxSensorFrameDuration);\n> > >\n> > > Do we need to keep\n> > >\n> > >         maxFrameDuration_ = std::max(maxFrameDuration_,\n> minFrameDuration_);\n> > >\n> > > in case the user passes a minimum higher than the maximum ? Apart from\n> > > that (which I can fix when applying if needed),\n> >\n> > Please correct me if I am wrong, but having the *FrameDuration_ values\n> > clamped by the *SensorFrameDurations would assure that max >= min, so I\n> > removed that statement.  This is assuming that the sensor driver reports\n> > max vblank >= min vblank - which it should.\n>\n> Let's assume\n>\n> - minSensorFrameDuration = 1000\n> - maxSensorFrameDuration = 5000\n> - minFrameDuration = 2000\n> - maxFrameDuration = 1500\n>\n> After clamping the minFrameDuration and maxFrameDuration values are not\n> changed, and minFrameDuration is still > maxFrameDuration. Am I missing\n> something ?\n>\n>\nYou are entirely correct, it was me who was missing something :-)\nPlease do re-introduce that line when merging.\n\nThanks!\nNaush\n\n\n> > > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > >\n> > > > +\n> > > > +     /* Return the validated limits out though metadata. */\n> > > > +     libcameraMetadata_.set(controls::FrameDurations,\n> > > > +                            {\n> static_cast<int64_t>(minFrameDuration_),\n> > > > +\n> static_cast<int64_t>(maxFrameDuration_) });\n> > > > +}\n> > > > +\n> > > >  void IPARPi::applyAGC(const struct AgcStatus *agcStatus,\n> ControlList &ctrls)\n> > > >  {\n> > > >       int32_t gainCode = helper_->GainCode(agcStatus->analogue_gain);\n>\n> --\n> Regards,\n>\n> Laurent Pinchart\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 41F98BD162\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  4 Feb 2021 22:30:30 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B7E736149B;\n\tThu,  4 Feb 2021 23:30:29 +0100 (CET)","from mail-lj1-x22c.google.com (mail-lj1-x22c.google.com\n\t[IPv6:2a00:1450:4864:20::22c])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id CD07461489\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  4 Feb 2021 23:30:28 +0100 (CET)","by mail-lj1-x22c.google.com with SMTP id u4so5400141ljh.6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 04 Feb 2021 14:30:28 -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=\"ZC+9L6RR\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google;\n\th=mime-version:references:in-reply-to:from:date:message-id:subject:to\n\t:cc; bh=TcBOmG5oxPvDDYW79MdAEb6wrXuR7hk8xp+tSWVRhkg=;\n\tb=ZC+9L6RRRqUeQlXXh+2IXszdwxUqLHGbvjIwipVpFEsNPk94Yxy3fjPTXCaTOX5Fwr\n\tkEBNOAu+28pSEDjMZ5pHA1NlKSF4Z3LbumyQeH1VhVNG3BLpiDPuV+0W9KlxAFQK5DWI\n\tTT9z3xJulh3x+CNobvfCWF0BS0gQIIrjahLgPcc0JMoZOSjNuKQxMP9BOetIMILHo4Gy\n\tqVmjzubjSa1x7IXMH8g1aWNJVsK4DhcLUFLfG0dNvNYcW4PTIfD0QRmBZMHdPt89BolK\n\tl+QSz0j41k3YzK658+4kFaJi89hX3DOxQrRjPK6HG3QtZnIcbBbq0FOq0f7B280+fltY\n\tuyXA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:references:in-reply-to:from:date\n\t:message-id:subject:to:cc;\n\tbh=TcBOmG5oxPvDDYW79MdAEb6wrXuR7hk8xp+tSWVRhkg=;\n\tb=tfH8e86nhmK8KO0PebV+4GWrrbarZHvqwvMeOOZscul4Wpbm03YUJ7Ot8tr7agsb+I\n\tacONF7S1+0x5Iwv5q5sXpvvb76PYTHqF2qXlxXbUrFw3irrfyhtCHgX7nQnvLzwhFO8a\n\tKKk2ve8TALb8nTGPB+0Ut6GMEyveI5fFI9CPhW/EgPk/sK7ztKw93gf3JyVmIz5hF1uc\n\tl8cwdGodhdhD2nbjHSwJ+Fwt6aDlz+d+fGCbqao19rie0MWNg42PbePg6s5oiU+xDi/F\n\tx2VlKqVvkg3z22WBqmK8IMv1cIGgTyCj9Dqu2mZ4ZmLe5E6KQonH1BcCjcZa9zIdGvMu\n\tCfbQ==","X-Gm-Message-State":"AOAM533SHJp+wll6FHJI15Ia+NRBQYMUxhfEO44B+4HADhaKWqQRud7m\n\tnUX7Meu8zIiCt2I5MZzHk8TTny9ci0adwmaDuwXwBA==","X-Google-Smtp-Source":"ABdhPJwRuPakRUwgq/fb4in1AAATUzpjWfFKVTMHSo2IMdV/5mbczGNTZBAJTEKIkR0z4l2HxE1FrYjFrzRqP2Rwrt4=","X-Received":"by 2002:a05:651c:544:: with SMTP id\n\tq4mr839147ljp.253.1612477828162; \n\tThu, 04 Feb 2021 14:30:28 -0800 (PST)","MIME-Version":"1.0","References":"<20210129111616.1047483-1-naush@raspberrypi.com>\n\t<20210129111616.1047483-4-naush@raspberrypi.com>\n\t<YBxWtBH9fxEc4TDW@pendragon.ideasonboard.com>\n\t<CAEmqJPq=WfhL=vg134kDHt91Rf1ahXO7JMeb-WZBE8b5isS-zw@mail.gmail.com>\n\t<YBx0ITiSgNb3n4sp@pendragon.ideasonboard.com>","In-Reply-To":"<YBx0ITiSgNb3n4sp@pendragon.ideasonboard.com>","From":"Naushir Patuck <naush@raspberrypi.com>","Date":"Thu, 4 Feb 2021 22:30:11 +0000","Message-ID":"<CAEmqJPpSYY03gVL-oq8DuRZhvXRTQZL8usOjOugZN8jvfu0nfw@mail.gmail.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v4 3/5] ipa: raspberrypi: Limit the\n\tcalculated vblank based on the sensor mode","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>","Cc":"libcamera devel <libcamera-devel@lists.libcamera.org>","Content-Type":"multipart/mixed;\n\tboundary=\"===============7130706801593750609==\"","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]