[libcamera-devel] [PATCH v2 2/4] ipa: raspberrypi: Limit the calculated vblank based on the sensor mode

Jacopo Mondi jacopo at jmondi.org
Tue Jan 26 15:39:29 CET 2021


Hi Naush,

On Tue, Jan 26, 2021 at 02:26:59PM +0000, Naushir Patuck wrote:
> Hi Jacopo,
>
> On Tue, 26 Jan 2021 at 14:21, Jacopo Mondi <jacopo at jmondi.org> wrote:
>
> > Hi Naush,
> >
> > On Tue, Jan 26, 2021 at 02:12:50PM +0000, Naushir Patuck wrote:
> > > Hi Jacopo,
> > >
> > > On Tue, 26 Jan 2021 at 13:44, Jacopo Mondi <jacopo at jmondi.org> wrote:
> > >
> >
> > [snip]
> >
> > > > > > > +      */
> > > > > > > +     const auto itVblank = sensorCtrls_.find(V4L2_CID_VBLANK);
> > > > > > > +     mode_.vblank_min = itVblank->second.min().get<int32_t>();
> > > > > > > +     mode_.vblank_max = itVblank->second.max().get<int32_t>();
> > > > > >
> > > > > > The trouble here is that sensorCtrls_ will not be updated after the
> > > > > > sensor configuration has changed. It comes from the
> > > > > > V4L2Device::controls() call in RPiCameraData::configureIPA(), and
> > that
> > > > > > function returns a cached copy.
> > > > > >
> > > > >
> > > > > I don't exactly know all of this in very much detail, so apologies
> > if the
> > > > > following statements sound basic, or don't make much sense :-)
> > > > >
> > > > > In  RPiCameraData::configureIPA(), would it be possible to "update"
> > the
> > > > > cached values of V4L2Device::controls_ by
> > > > > calling V4L2Device::listControls(), or maybe a new method such
> > > > > as V4L2Device::updateControls().  This only needs to be called once
> > > > > in PipelineHandlerRPi::configure(), after the sensor mode has been
> > set.
> > > > > This way, the VBLANK control will have up-to-date numbers for the
> > IPA to
> > > > > use.
> > > > >
> > > > > Alternatively, CameraSensorInfo gets populated in
> > > > > RPiCameraData::configureIPA() with a  call
> > > > > to CameraSensor::sensorInfo(). Looks like this directly queries the
> > > > device
> > > > > for controls via V4L2Device::getControls().  Perhaps we should
> > re-visit
> > > > > Jacopo's suggestion and add the min/max vblank values to the mode?
> > > > >
> > > > >
> > > > > >
> > > > > > I really dislike the fact that V4L2 provides us with a control
> > whose
> > > > > > limits change when the analog crop rectangle height changes, while
> > the
> > > > > > sensors usually have a fixed vertical total size limit. Wouldn't
> > it be
> > > > > > better to base the code on the vertical total size limit in
> > libcamera,
> > > > > > instead of vertical blanking ?
> > > > >
> > > > >
> > > > > By vertical total size limit, I assume you mean what sensors
> > generally
> > > > call
> > > > > vts or frame length?  If so, then yes, it does make sense.  In fact,
> > you
> > > > > can see from my patch, the first thing I do is convert from vblank to
> > > > frame
> > > > > length for all of my calculations.
> > > > >
> > > > >
> > > >
> > > > Let me summarize your understandings:
> > > > - You need the VBLANK limits to clamp frame durations in the sensor
> > > >   limits
> > > > - VBLANK min and max are combined with the current mode height and
> > > >   line length to get the min and max frame sizes, from where the min
> > > >   and max frame duration limits are calculated
> > > > - min frame size = (mode_.height + frameIntegrationDiff) *
> > > > mode_.line_length
> > > > - max frame size = (mode_.height + max vblank) * mode_.line_length
> > > >
> > > > From the CameraSensorInfo you already know the visibile height and the
> > > > line_length. Wouldn't be enough to add to that structure
> > > >         - maxFrameHeight = (mode_.height + max vblank)
> > > >         - frameIntegrationDiff
> > > >           This is sensor property and will be made available in the
> > > >           sensor database. You can keep it in the IPA as long as no
> > > >           sensor database is available
> > > >
> > > > To sum it up: is it enough for you to pass to the IPA the maximum
> > > > frame length (mode_.height + max vblank) in the CameraSensorClass ?
> > > >
> > >
> > > This is *mostly* correct.  max frame size as calculated above is fine.
> > > However, I do also need min frame size.  Your calculation above assumes
> > > min_vblank = 0.  This may not be the case always, so min frame size must
> > be
> > > computed and presented in CameraSensorInfo.
> >
> > Correct, I had assumed min_vblank = frameIntegrationDiff, which might
> > not always be the case.
> >
> > Considering the requirement for 'updates' and the fact the
> > CameraSensorInfo is guaranteed to be fresh at IPA::Configure() time,
> > I would be happy to see minFrameSize (or Height) and maxFrameSize (or
> > Height) added there an computed once for all IPAs in the CameraSensor
> > class.
> >
>
> Great, I can put together a change for this and submit for review as part
> of this series.  One question, what name would you and Laurent prefer for
> this field - maxFrameSize or maxFrameLength (and equivalent for min)?
> Generally, I think sensors prefer using frame length in their terminology,
> but v4l2 probably prefers frame size.  I am ok with either.
>

This and also if we want to report only the frame heights limits
and let the IPA compute the frame size, or report the actual frame
size. It's a detail, I know, you can easily get from one to the other
and viceversa..


> Regards,
> Naush
>
>
>
> > >
> > >
> > >
> > > >
> > > >
> > > > > > We would still have the issue of
> > > > > > retrieving this value, and I can see multiple options:
> > > > > >
> > > > > > - Compute it once at initialization from vblank limits + analog
> > crop
> > > > > >
> > > > >
> > > > > This is assuming that vblank + crop height is always going to be
> > equal to
> > > > > frame length?  We need to think if that is strictly true for all
> > sensors,
> > > > > I'm not sure.
> > > > >
> > > > >
> > > > >
> > > > > > - Extend V4L2 with a new vertical total size control and use it
> > (that
> > > > > >   will be more work as we need to synchronize with the kernel
> > changes)
> > > > > >
> > > > >
> > > > > I expect this would have the longest lead time :-)
> > > > >
> > > > >
> > > > > > - Hardcode the value in a sensor database in libcamera, bypassing
> > the
> > > > > >   kernel completly
> > > > > >
> > > > >
> > > > > This is possible, but...
> > > > >
> > > > >
> > > > > >
> > > > > > One question that I'm not sure I can answer by myself is whether
> > we can
> > > > > > rely on the vertical total size limits being constant.
> > > > > >
> > > > >
> > > > > ... I don't think you can assume total vertical size (frame length)
> > is
> > > > > going to be the same for all modes a sensor advertises.  In this
> > case,
> > > > the
> > > > > sensor database would have to know about every mode available in the
> > > > kernel
> > > > > driver.  This is something we moved away from with the Raspberry Pi
> > > > > CamHelper, so I doubt you want to re-introduce that link.
> > > > >
> > > > > My feeling is that we could work something out by forcing a
> > "refresh" of
> > > > > the cached controls on every configure, and I think that should
> > cover our
> > > > > (or at least Raspberry Pi's in this particular instance) usage.
> > > > >
> > > > > Let me know your thoughts.
> > > > >
> > > > > Regards,
> > > > > Naush
> > > > >
> > > > >
> > > > >
> > > > > > >  }
> > > > > > >
> >
> > [snip]
> >
> > > > > > >  void IPARPi::configure(const CameraSensorInfo &sensorInfo,
> > > > > > > @@ -384,8 +393,8 @@ void IPARPi::configure(const CameraSensorInfo
> > > > > > &sensorInfo,
> > > > > > >               controller_.Initialise();
> > > > > > >               controllerInit_ = true;
> > > > > > >
> > > > > > > -             minFrameDuration_ = defaultMinFrameDuration;
> > > > > > > -             maxFrameDuration_ = defaultMaxFrameDuration;
> > > > > > > +             /* Supply initial values for frame durations. */
> > > > > > > +             applyFrameDurations(defaultMinFrameDuration,
> > > > > > defaultMaxFrameDuration);
> > > > > > >
> > > > > > >               /* Supply initial values for gain and exposure. */
> > > > > > >               ControlList ctrls(sensorCtrls_);
> > > > > > > @@ -819,20 +828,7 @@ void IPARPi::queueRequest(const ControlList
> > > > > > &controls)
> > > > > > >
> > > > > > >               case controls::FRAME_DURATIONS: {
> > > > > > >                       auto frameDurations =
> > > > ctrl.second.get<Span<const
> > > > > > int64_t>>();
> > > > > > > -
> > > > > > > -                     /* This will be applied once AGC
> > recalculations
> > > > > > occur. */
> > > > > > > -                     minFrameDuration_ = frameDurations[0] ?
> > > > > > frameDurations[0] : defaultMinFrameDuration;
> > > > > > > -                     maxFrameDuration_ = frameDurations[1] ?
> > > > > > frameDurations[1] : defaultMaxFrameDuration;
> > > > > > > -                     maxFrameDuration_ =
> > std::max(maxFrameDuration_,
> > > > > > minFrameDuration_);
> > > > > > > -
> > > > > > > -                     /*
> > > > > > > -                      * \todo The values returned in the
> > metadata
> > > > below
> > > > > > must be
> > > > > > > -                      * correctly clipped by what the sensor
> > mode
> > > > > > supports and
> > > > > > > -                      * what the AGC exposure mode or manual
> > shutter
> > > > > > speed limits
> > > > > > > -                      */
> > > > > > > -
> > > >  libcameraMetadata_.set(controls::FrameDurations,
> > > > > > > -                                            {
> > > > > > static_cast<int64_t>(minFrameDuration_),
> > > > > > > -
> > > > > > static_cast<int64_t>(maxFrameDuration_) });
> > > > > > > +                     applyFrameDurations(frameDurations[0],
> > > > > > frameDurations[1]);
> > > > > > >                       break;
> > > > > > >               }
> > > > > > >
> > > > > > > @@ -991,6 +987,29 @@ void IPARPi::applyAWB(const struct AwbStatus
> > > > > > *awbStatus, ControlList &ctrls)
> > > > > > >                 static_cast<int32_t>(awbStatus->gain_b * 1000));
> > > > > > >  }
> > > > > > >
> > > > > > > +void IPARPi::applyFrameDurations(double minFrameDuration, double
> > > > > > maxFrameDuration)
> > > > > > > +{
> > > > > > > +     const double minSensorFrameDuration = 1e-3 *
> > (mode_.vblank_min
> > > > +
> > > > > > mode_.height) *
> > > > > > > +                                           mode_.line_length;
> > > > > > > +     const double maxSensorFrameDuration = 1e-3 *
> > (mode_.vblank_max
> > > > +
> > > > > > mode_.height) *
> > > > > > > +                                           mode_.line_length;
> > > >
> > > > To transform the frame size expressed in pixels:
> > > >         (mode_.vblank + mode_.height) * mode_.line_length
> > > >
> > > > in a duration expressed in seconds sub-units, don't you need to use
> > > > the pixel clock (which is available in CameraSensorInfo afair)
> > > >         frameDuration (usec) = frame size (pixels)
> > > >                              / pixel rate (pixels/usec)
> > > >
> > >
> > > Yes we do.  However, mode_.line_length already factors the pixel rate:
> > > mode_.line_length = 1e9 * sensorInfo.lineLength / sensorInfo.pixelRate
> > >
> > > So mode_.line_length is already converted into units of time.
> >
> > Oh sorry, I assumed CameraMode.line_lenght == CameraSensorInfo.lineLength
> >
> > I should have checked.
> >
> > Thanks
> >   j
> >
> > >
> > > Regards,
> > > Naush
> > >
> > >
> > >
> > > >
> > > > Thanks
> > > >    j
> > > >
> > > > > > > +     /*
> > > > > > > +      * This will only be applied once AGC recalculations occur.
> > > > > > > +      * The values may be clamped based on the sensor mode
> > > > capabilities
> > > > > > as well.
> > > > > > > +      */
> > > > > > > +     minFrameDuration_ = minFrameDuration ? minFrameDuration :
> > > > > > defaultMaxFrameDuration;
> > > > > > > +     maxFrameDuration_ = maxFrameDuration ? maxFrameDuration :
> > > > > > defaultMinFrameDuration;
> > > > > > > +     minFrameDuration_ = std::clamp(minFrameDuration_,
> > > > > > > +                                    minSensorFrameDuration,
> > > > > > maxSensorFrameDuration);
> > > > > > > +     maxFrameDuration_ = std::clamp(maxFrameDuration_,
> > > > > > > +                                    minSensorFrameDuration,
> > > > > > maxSensorFrameDuration);
> > > > > > > +
> > > > > > > +     /* Return the validated limits out though metadata. */
> > > > > > > +     libcameraMetadata_.set(controls::FrameDurations,
> > > > > > > +                            {
> > > > static_cast<int64_t>(minFrameDuration_),
> > > > > > > +
> > > > static_cast<int64_t>(maxFrameDuration_)
> > > > > > });
> > > > > > > +}
> > > > > > > +
> > > > > > >  void IPARPi::applyAGC(const struct AgcStatus *agcStatus,
> > ControlList
> > > > > > &ctrls)
> > > > > > >  {
> > > > > > --
> > > > > > Regards,
> > > > > >
> > > > > > Laurent Pinchart
> > > > > >
> > > >
> > > >
> > > > > _______________________________________________
> > > > > libcamera-devel mailing list
> > > > > libcamera-devel at lists.libcamera.org
> > > > > https://lists.libcamera.org/listinfo/libcamera-devel
> > > >
> > > >
> >


More information about the libcamera-devel mailing list