[{"id":14848,"web_url":"https://patchwork.libcamera.org/comment/14848/","msgid":"<20210129092430.zolplp5kzawthiiw@uno.localdomain>","date":"2021-01-29T09:24:30","subject":"Re: [libcamera-devel] [PATCH v3 3/5] ipa: raspberrypi: Limit the\n\tcalculated vblank based on the sensor mode","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Naush,\n\nOn Thu, Jan 28, 2021 at 09:10:48AM +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> ---\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..3e17255737b2 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 will have been clamped to the\n\ns/will//\n\n> +\t * maximum allowable values in the sensor for this 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\nCan maxFrameDuration == 0 ? I see you call this function either with\nthe defaults or when you handle the FRAME_DURATIONS: control\n\nThe rest of the series looks good\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n\nThanks\n   j\n\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> +\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);\n> --\n> 2.25.1\n>\n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","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 76909BD808\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 29 Jan 2021 09:24:12 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id D8FC368398;\n\tFri, 29 Jan 2021 10:24:11 +0100 (CET)","from relay10.mail.gandi.net (relay10.mail.gandi.net\n\t[217.70.178.230])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3E794682F2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 29 Jan 2021 10:24:10 +0100 (CET)","from uno.localdomain (93-34-118-233.ip49.fastwebnet.it\n\t[93.34.118.233]) (Authenticated sender: jacopo@jmondi.org)\n\tby relay10.mail.gandi.net (Postfix) with ESMTPSA id BEF75240015;\n\tFri, 29 Jan 2021 09:24:09 +0000 (UTC)"],"Date":"Fri, 29 Jan 2021 10:24:30 +0100","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Naushir Patuck <naush@raspberrypi.com>","Message-ID":"<20210129092430.zolplp5kzawthiiw@uno.localdomain>","References":"<20210128091050.881815-1-naush@raspberrypi.com>\n\t<20210128091050.881815-4-naush@raspberrypi.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20210128091050.881815-4-naush@raspberrypi.com>","Subject":"Re: [libcamera-devel] [PATCH v3 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":14849,"web_url":"https://patchwork.libcamera.org/comment/14849/","msgid":"<CAEmqJPphezq7wqtmhp6FQ1hbhS8sF_c7VZpHT1d06SKrFXPF-Q@mail.gmail.com>","date":"2021-01-29T09:41:18","subject":"Re: [libcamera-devel] [PATCH v3 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 Jacopo,\n\nThank you for your review feedback.\n\nOn Fri, 29 Jan 2021 at 09:24, Jacopo Mondi <jacopo@jmondi.org> wrote:\n\n> Hi Naush,\n>\n> On Thu, Jan 28, 2021 at 09:10:48AM +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> > ---\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..3e17255737b2 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 will have been clamped to\n> the\n>\n> s/will//\n>\n\nI will update this sentence to use Laurent's suggested wording here:\n\n\"minFrameDuration and maxFrameDuration are clamped by the caller\nbased on the limits for the active sensor mode\"\n\n\n\n>\n> > +      * maximum allowable values in the sensor for this 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>\n> Can maxFrameDuration == 0 ? I see you call this function either with\n> the defaults or when you handle the FRAME_DURATIONS: control\n\n\nYes, it can. If for whatever reason (unlikely), the application decides it\nwants to \"reset\" max frame duration back to some defaults, it will pass in\na 0 in the control.  It will never be 0 when setting the defaults of\ncourse.\n\n\n>\n> The rest of the series looks good\n> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n>\n\nThanks!\n\nNaush\n\n\n>\n> Thanks\n>    j\n>\n> > +     minFrameDuration_ = std::clamp(minFrameDuration_,\n> > +                                    minSensorFrameDuration,\n> maxSensorFrameDuration);\n> > +     maxFrameDuration_ = std::clamp(maxFrameDuration_,\n> > +                                    minSensorFrameDuration,\n> maxSensorFrameDuration);\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> > 2.25.1\n> >\n> > _______________________________________________\n> > libcamera-devel mailing list\n> > libcamera-devel@lists.libcamera.org\n> > https://lists.libcamera.org/listinfo/libcamera-devel\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 711E8C33BB\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 29 Jan 2021 09:41:39 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id E8A446839D;\n\tFri, 29 Jan 2021 10:41:38 +0100 (CET)","from mail-lj1-x236.google.com (mail-lj1-x236.google.com\n\t[IPv6:2a00:1450:4864:20::236])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 30B28682F2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 29 Jan 2021 10:41:36 +0100 (CET)","by mail-lj1-x236.google.com with SMTP id f11so9712721ljm.8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 29 Jan 2021 01:41:36 -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=\"pASupcZF\"; 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=jQk2KGSGQFmT4nbb1VL1eXq8+bP2A2U6IqQGobE6m80=;\n\tb=pASupcZFRq6omXwfV7LMtj/yygw8fspLBkoWArvXhFmc1/IHZfIqwpMIV0Opd2Wvmc\n\tXJidBfi19RokrNCegLWeIxB8l2e+m98krrTHtaoIhmGxfJmRmKZzVM3tMvvO4/LI0yf/\n\tlquWDjUQ+yGHAk1l+eSP/xXyfvTnZuzk1GVcwKNEoZ10wh+4JoNOSwboub2WBTTRjBFj\n\tHZjNsi+InSPNyvKss9aOnJS12EPTobxR469NTUUiwK//f2tm6rZn0xdLOX7iGT8u22zD\n\tCAjRqQZTMIY1nxLlmJ4myrfi2qL1L/R8wIdnLf1iIHpuEZLJ2srC5ROTxV+Ss58EqCGA\n\tJI+A==","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=jQk2KGSGQFmT4nbb1VL1eXq8+bP2A2U6IqQGobE6m80=;\n\tb=Z31tliRqtuzF5D3y7NGIYoP7XzmCHWjkyRrcVmtLSPePtNRZJWETk+/kHCjMtAMss4\n\tvLaMQVGsxTKk76Ku5KidV7EN3Qh5LX5iQYchjkAGnUXg7VdLrpqNLb+wSRIUOFTdgt2z\n\tJU30IooDtzjNfaRmkuuNifoFjkB6BfntP1EFRB8mhmbssAWkjTBeQEO2JwMxecJFrO0A\n\t61JZJY59/l/aAjYUPVTYHOcQIi4gmV20UTrJ1nsHYEDQuBNwAKM48iJ9ojLF4neOtTxN\n\th/1iTZjgXaZL4siaeQrsdeV83JeFEcC7MCun1lluThvup4xnUD12Bf47oo6U8rXD6kFy\n\toDpA==","X-Gm-Message-State":"AOAM531dgL4o6GqPyVrDGgTevem2/srQILQThUJ8HUyGQOfWYFMIQTml\n\txE/CiacpSSdwDX9jocykGfq+Y+dsELL/T4bbTFjS+A==","X-Google-Smtp-Source":"ABdhPJx109GteoNAqyY39Goiqaiyu9g8+gcPis3+b7P8ATeOOxi8wftb26ZY5xYXXDPMM5E2jKmf5l+hQaW8sJLs0lY=","X-Received":"by 2002:a2e:7605:: with SMTP id r5mr1857858ljc.299.1611913295273;\n\tFri, 29 Jan 2021 01:41:35 -0800 (PST)","MIME-Version":"1.0","References":"<20210128091050.881815-1-naush@raspberrypi.com>\n\t<20210128091050.881815-4-naush@raspberrypi.com>\n\t<20210129092430.zolplp5kzawthiiw@uno.localdomain>","In-Reply-To":"<20210129092430.zolplp5kzawthiiw@uno.localdomain>","From":"Naushir Patuck <naush@raspberrypi.com>","Date":"Fri, 29 Jan 2021 09:41:18 +0000","Message-ID":"<CAEmqJPphezq7wqtmhp6FQ1hbhS8sF_c7VZpHT1d06SKrFXPF-Q@mail.gmail.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Subject":"Re: [libcamera-devel] [PATCH v3 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=\"===============8631445079192089138==\"","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]