[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:22:05 CET 2021


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.

>
>
>
> >
> >
> > > > 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