<div dir="ltr"><div dir="ltr">Hi Jacopo,</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, 26 Jan 2021 at 14:21, Jacopo Mondi <<a href="mailto:jacopo@jmondi.org">jacopo@jmondi.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi Naush,<br>
<br>
On Tue, Jan 26, 2021 at 02:12:50PM +0000, Naushir Patuck wrote:<br>
> Hi Jacopo,<br>
><br>
> On Tue, 26 Jan 2021 at 13:44, Jacopo Mondi <<a href="mailto:jacopo@jmondi.org" target="_blank">jacopo@jmondi.org</a>> wrote:<br>
><br>
<br>
[snip]<br>
<br>
> > > > > + */<br>
> > > > > + const auto itVblank = sensorCtrls_.find(V4L2_CID_VBLANK);<br>
> > > > > + mode_.vblank_min = itVblank->second.min().get<int32_t>();<br>
> > > > > + mode_.vblank_max = itVblank->second.max().get<int32_t>();<br>
> > > ><br>
> > > > The trouble here is that sensorCtrls_ will not be updated after the<br>
> > > > sensor configuration has changed. It comes from the<br>
> > > > V4L2Device::controls() call in RPiCameraData::configureIPA(), and that<br>
> > > > function returns a cached copy.<br>
> > > ><br>
> > ><br>
> > > I don't exactly know all of this in very much detail, so apologies if the<br>
> > > following statements sound basic, or don't make much sense :-)<br>
> > ><br>
> > > In RPiCameraData::configureIPA(), would it be possible to "update" the<br>
> > > cached values of V4L2Device::controls_ by<br>
> > > calling V4L2Device::listControls(), or maybe a new method such<br>
> > > as V4L2Device::updateControls(). This only needs to be called once<br>
> > > in PipelineHandlerRPi::configure(), after the sensor mode has been set.<br>
> > > This way, the VBLANK control will have up-to-date numbers for the IPA to<br>
> > > use.<br>
> > ><br>
> > > Alternatively, CameraSensorInfo gets populated in<br>
> > > RPiCameraData::configureIPA() with a call<br>
> > > to CameraSensor::sensorInfo(). Looks like this directly queries the<br>
> > device<br>
> > > for controls via V4L2Device::getControls(). Perhaps we should re-visit<br>
> > > Jacopo's suggestion and add the min/max vblank values to the mode?<br>
> > ><br>
> > ><br>
> > > ><br>
> > > > I really dislike the fact that V4L2 provides us with a control whose<br>
> > > > limits change when the analog crop rectangle height changes, while the<br>
> > > > sensors usually have a fixed vertical total size limit. Wouldn't it be<br>
> > > > better to base the code on the vertical total size limit in libcamera,<br>
> > > > instead of vertical blanking ?<br>
> > ><br>
> > ><br>
> > > By vertical total size limit, I assume you mean what sensors generally<br>
> > call<br>
> > > vts or frame length? If so, then yes, it does make sense. In fact, you<br>
> > > can see from my patch, the first thing I do is convert from vblank to<br>
> > frame<br>
> > > length for all of my calculations.<br>
> > ><br>
> > ><br>
> ><br>
> > Let me summarize your understandings:<br>
> > - You need the VBLANK limits to clamp frame durations in the sensor<br>
> > limits<br>
> > - VBLANK min and max are combined with the current mode height and<br>
> > line length to get the min and max frame sizes, from where the min<br>
> > and max frame duration limits are calculated<br>
> > - min frame size = (mode_.height + frameIntegrationDiff) *<br>
> > mode_.line_length<br>
> > - max frame size = (mode_.height + max vblank) * mode_.line_length<br>
> ><br>
> > From the CameraSensorInfo you already know the visibile height and the<br>
> > line_length. Wouldn't be enough to add to that structure<br>
> > - maxFrameHeight = (mode_.height + max vblank)<br>
> > - frameIntegrationDiff<br>
> > This is sensor property and will be made available in the<br>
> > sensor database. You can keep it in the IPA as long as no<br>
> > sensor database is available<br>
> ><br>
> > To sum it up: is it enough for you to pass to the IPA the maximum<br>
> > frame length (mode_.height + max vblank) in the CameraSensorClass ?<br>
> ><br>
><br>
> This is *mostly* correct. max frame size as calculated above is fine.<br>
> However, I do also need min frame size. Your calculation above assumes<br>
> min_vblank = 0. This may not be the case always, so min frame size must be<br>
> computed and presented in CameraSensorInfo.<br>
<br>
Correct, I had assumed min_vblank = frameIntegrationDiff, which might<br>
not always be the case.<br>
<br>
Considering the requirement for 'updates' and the fact the<br>
CameraSensorInfo is guaranteed to be fresh at IPA::Configure() time,<br>
I would be happy to see minFrameSize (or Height) and maxFrameSize (or<br>
Height) added there an computed once for all IPAs in the CameraSensor<br>
class.<br></blockquote><div><br></div><div>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.</div><div><br></div><div>Regards,</div><div>Naush</div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
><br>
><br>
><br>
> ><br>
> ><br>
> > > > We would still have the issue of<br>
> > > > retrieving this value, and I can see multiple options:<br>
> > > ><br>
> > > > - Compute it once at initialization from vblank limits + analog crop<br>
> > > ><br>
> > ><br>
> > > This is assuming that vblank + crop height is always going to be equal to<br>
> > > frame length? We need to think if that is strictly true for all sensors,<br>
> > > I'm not sure.<br>
> > ><br>
> > ><br>
> > ><br>
> > > > - Extend V4L2 with a new vertical total size control and use it (that<br>
> > > > will be more work as we need to synchronize with the kernel changes)<br>
> > > ><br>
> > ><br>
> > > I expect this would have the longest lead time :-)<br>
> > ><br>
> > ><br>
> > > > - Hardcode the value in a sensor database in libcamera, bypassing the<br>
> > > > kernel completly<br>
> > > ><br>
> > ><br>
> > > This is possible, but...<br>
> > ><br>
> > ><br>
> > > ><br>
> > > > One question that I'm not sure I can answer by myself is whether we can<br>
> > > > rely on the vertical total size limits being constant.<br>
> > > ><br>
> > ><br>
> > > ... I don't think you can assume total vertical size (frame length) is<br>
> > > going to be the same for all modes a sensor advertises. In this case,<br>
> > the<br>
> > > sensor database would have to know about every mode available in the<br>
> > kernel<br>
> > > driver. This is something we moved away from with the Raspberry Pi<br>
> > > CamHelper, so I doubt you want to re-introduce that link.<br>
> > ><br>
> > > My feeling is that we could work something out by forcing a "refresh" of<br>
> > > the cached controls on every configure, and I think that should cover our<br>
> > > (or at least Raspberry Pi's in this particular instance) usage.<br>
> > ><br>
> > > Let me know your thoughts.<br>
> > ><br>
> > > Regards,<br>
> > > Naush<br>
> > ><br>
> > ><br>
> > ><br>
> > > > > }<br>
> > > > ><br>
<br>
[snip]<br>
<br>
> > > > > void IPARPi::configure(const CameraSensorInfo &sensorInfo,<br>
> > > > > @@ -384,8 +393,8 @@ void IPARPi::configure(const CameraSensorInfo<br>
> > > > &sensorInfo,<br>
> > > > > controller_.Initialise();<br>
> > > > > controllerInit_ = true;<br>
> > > > ><br>
> > > > > - minFrameDuration_ = defaultMinFrameDuration;<br>
> > > > > - maxFrameDuration_ = defaultMaxFrameDuration;<br>
> > > > > + /* Supply initial values for frame durations. */<br>
> > > > > + applyFrameDurations(defaultMinFrameDuration,<br>
> > > > defaultMaxFrameDuration);<br>
> > > > ><br>
> > > > > /* Supply initial values for gain and exposure. */<br>
> > > > > ControlList ctrls(sensorCtrls_);<br>
> > > > > @@ -819,20 +828,7 @@ void IPARPi::queueRequest(const ControlList<br>
> > > > &controls)<br>
> > > > ><br>
> > > > > case controls::FRAME_DURATIONS: {<br>
> > > > > auto frameDurations =<br>
> > ctrl.second.get<Span<const<br>
> > > > int64_t>>();<br>
> > > > > -<br>
> > > > > - /* This will be applied once AGC recalculations<br>
> > > > occur. */<br>
> > > > > - minFrameDuration_ = frameDurations[0] ?<br>
> > > > frameDurations[0] : defaultMinFrameDuration;<br>
> > > > > - maxFrameDuration_ = frameDurations[1] ?<br>
> > > > frameDurations[1] : defaultMaxFrameDuration;<br>
> > > > > - maxFrameDuration_ = std::max(maxFrameDuration_,<br>
> > > > minFrameDuration_);<br>
> > > > > -<br>
> > > > > - /*<br>
> > > > > - * \todo The values returned in the metadata<br>
> > below<br>
> > > > must be<br>
> > > > > - * correctly clipped by what the sensor mode<br>
> > > > supports and<br>
> > > > > - * what the AGC exposure mode or manual shutter<br>
> > > > speed limits<br>
> > > > > - */<br>
> > > > > -<br>
> > libcameraMetadata_.set(controls::FrameDurations,<br>
> > > > > - {<br>
> > > > static_cast<int64_t>(minFrameDuration_),<br>
> > > > > -<br>
> > > > static_cast<int64_t>(maxFrameDuration_) });<br>
> > > > > + applyFrameDurations(frameDurations[0],<br>
> > > > frameDurations[1]);<br>
> > > > > break;<br>
> > > > > }<br>
> > > > ><br>
> > > > > @@ -991,6 +987,29 @@ void IPARPi::applyAWB(const struct AwbStatus<br>
> > > > *awbStatus, ControlList &ctrls)<br>
> > > > > static_cast<int32_t>(awbStatus->gain_b * 1000));<br>
> > > > > }<br>
> > > > ><br>
> > > > > +void IPARPi::applyFrameDurations(double minFrameDuration, double<br>
> > > > maxFrameDuration)<br>
> > > > > +{<br>
> > > > > + const double minSensorFrameDuration = 1e-3 * (mode_.vblank_min<br>
> > +<br>
> > > > mode_.height) *<br>
> > > > > + mode_.line_length;<br>
> > > > > + const double maxSensorFrameDuration = 1e-3 * (mode_.vblank_max<br>
> > +<br>
> > > > mode_.height) *<br>
> > > > > + mode_.line_length;<br>
> ><br>
> > To transform the frame size expressed in pixels:<br>
> > (mode_.vblank + mode_.height) * mode_.line_length<br>
> ><br>
> > in a duration expressed in seconds sub-units, don't you need to use<br>
> > the pixel clock (which is available in CameraSensorInfo afair)<br>
> > frameDuration (usec) = frame size (pixels)<br>
> > / pixel rate (pixels/usec)<br>
> ><br>
><br>
> Yes we do. However, mode_.line_length already factors the pixel rate:<br>
> mode_.line_length = 1e9 * sensorInfo.lineLength / sensorInfo.pixelRate<br>
><br>
> So mode_.line_length is already converted into units of time.<br>
<br>
Oh sorry, I assumed CameraMode.line_lenght == CameraSensorInfo.lineLength<br>
<br>
I should have checked.<br>
<br>
Thanks<br>
j<br>
<br>
><br>
> Regards,<br>
> Naush<br>
><br>
><br>
><br>
> ><br>
> > Thanks<br>
> > j<br>
> ><br>
> > > > > + /*<br>
> > > > > + * This will only be applied once AGC recalculations occur.<br>
> > > > > + * The values may be clamped based on the sensor mode<br>
> > capabilities<br>
> > > > as well.<br>
> > > > > + */<br>
> > > > > + minFrameDuration_ = minFrameDuration ? minFrameDuration :<br>
> > > > defaultMaxFrameDuration;<br>
> > > > > + maxFrameDuration_ = maxFrameDuration ? maxFrameDuration :<br>
> > > > defaultMinFrameDuration;<br>
> > > > > + minFrameDuration_ = std::clamp(minFrameDuration_,<br>
> > > > > + minSensorFrameDuration,<br>
> > > > maxSensorFrameDuration);<br>
> > > > > + maxFrameDuration_ = std::clamp(maxFrameDuration_,<br>
> > > > > + minSensorFrameDuration,<br>
> > > > maxSensorFrameDuration);<br>
> > > > > +<br>
> > > > > + /* Return the validated limits out though metadata. */<br>
> > > > > + libcameraMetadata_.set(controls::FrameDurations,<br>
> > > > > + {<br>
> > static_cast<int64_t>(minFrameDuration_),<br>
> > > > > +<br>
> > static_cast<int64_t>(maxFrameDuration_)<br>
> > > > });<br>
> > > > > +}<br>
> > > > > +<br>
> > > > > void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList<br>
> > > > &ctrls)<br>
> > > > > {<br>
> > > > --<br>
> > > > Regards,<br>
> > > ><br>
> > > > Laurent Pinchart<br>
> > > ><br>
> ><br>
> ><br>
> > > _______________________________________________<br>
> > > libcamera-devel mailing list<br>
> > > <a href="mailto:libcamera-devel@lists.libcamera.org" target="_blank">libcamera-devel@lists.libcamera.org</a><br>
> > > <a href="https://lists.libcamera.org/listinfo/libcamera-devel" rel="noreferrer" target="_blank">https://lists.libcamera.org/listinfo/libcamera-devel</a><br>
> ><br>
> ><br>
</blockquote></div></div>