| Message ID | 20260827104108.1432632-7-barnabas.pocze@ideasonboard.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
Hi Jacopo, hi Barnabás, Quoting Barnabás Pőcze (2026-08-27 12:41:06) > From: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > > There is a margin between the maximum achievable shutter time and the frame > length. The value is sensor-dependent and should be used to adjust the > maximum achievable exposure time whenever the frame length changes. > > Introduce in the CameraSensorHelper the notion of exposureMargin_ as the > minimum difference in number of lines between the current frame length and > the maximum exposure time. > > This feature is already implemented in the RPi CamHelper class hierarchy > with the name of frameIntegrationDiff. > > Populate the CameraSensorHelper instances with an exposureMargin_. The > value of the exposure margin comes from the mainline driver version of each > sensor, and it has been compared with the frameIntegrationDiff_ value in > the rpi camera helpers. > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> > --- > src/ipa/libipa/camera_sensor_helper.cpp | 59 +++++++++++++++++++++++++ > src/ipa/libipa/camera_sensor_helper.h | 2 + > 2 files changed, 61 insertions(+) > > diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp > index 1a90343c00..3da69bf17b 100644 > --- a/src/ipa/libipa/camera_sensor_helper.cpp > +++ b/src/ipa/libipa/camera_sensor_helper.cpp > @@ -76,6 +76,16 @@ namespace ipa { > * \return The black level of the sensor, or std::nullopt if not known > */ > > +/** > + * \fn CameraSensorHelper::exposureMargin() > + * \brief Fetch the exposure margin of the sensor > + * > + * This function returns the exposure margin of the sensor, in lines, which > + * is the minimum difference between the integration time and frame length. > + * > + * \return The exposure margin of the sensor, or std::nullopt if not know s/know/known/ I'm not a big fan of hardcoding these inside libcamera. But I guess querying the sensor for that is difficult/impossible? If the answer is "Yes, difficult/impossible": Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> Best regards, Stefan > + */ > + > /** > * \brief Compute gain code from the analogue gain absolute value > * \param[in] gain The real gain to pass > @@ -229,6 +239,12 @@ double CameraSensorHelper::quantizeGain(double _gain, double *quantizationGain) > * sensor specific. Use this variable to store the values at init time. > */ > > +/** > + * \var CameraSensorHelper::exposureMargin_ > + * \brief The smallest margin between the integration time and the frame length > + * in lines > + */ > + > /** > * \class CameraSensorHelperFactoryBase > * \brief Base class for camera sensor helper factories > @@ -385,6 +401,7 @@ public: > { > /* Power-on default value: 168 at 12bits. */ > blackLevel_ = 2688; > + exposureMargin_ = 4; > } > > uint32_t gainCode(double gain) const override > @@ -474,6 +491,11 @@ REGISTER_CAMERA_SENSOR_HELPER("ar0144", CameraSensorHelperAr0144) > class CameraSensorHelperAr0521 : public CameraSensorHelper > { > public: > + CameraSensorHelperAr0521() > + { > + exposureMargin_ = 4; > + } > + > uint32_t gainCode(double gain) const override > { > gain = std::clamp(gain, 1.0, 15.5); > @@ -504,6 +526,7 @@ public: > /* From datasheet: 64 at 10bits. */ > blackLevel_ = 4096; > gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 }; > + exposureMargin_ = 4; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("gc05a2", CameraSensorHelperGc05a2) > @@ -516,6 +539,7 @@ public: > /* From datasheet: 64 at 10bits. */ > blackLevel_ = 4096; > gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 }; > + exposureMargin_ = 16; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("gc08a3", CameraSensorHelperGc08a3) > @@ -526,6 +550,7 @@ public: > CameraSensorHelperHm1246() > { > gain_ = AnalogueGainLinear{ 1, 16, 0, 16 }; > + exposureMargin_ = 2; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("hm1246", CameraSensorHelperHm1246) > @@ -538,6 +563,7 @@ public: > /* From datasheet: 64 at 10bits. */ > blackLevel_ = 4096; > gain_ = AnalogueGainLinear{ 0, 512, -1, 512 }; > + exposureMargin_ = 10; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("imx214", CameraSensorHelperImx214) > @@ -550,6 +576,7 @@ public: > /* From datasheet: 64 at 10bits. */ > blackLevel_ = 4096; > gain_ = AnalogueGainLinear{ 0, 256, -1, 256 }; > + exposureMargin_ = 4; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("imx219", CameraSensorHelperImx219) > @@ -562,6 +589,7 @@ public: > /* From datasheet: 0x40 at 10bits. */ > blackLevel_ = 4096; > gain_ = AnalogueGainLinear{ 0, 512, -1, 512 }; > + exposureMargin_ = 10; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("imx258", CameraSensorHelperImx258) > @@ -574,6 +602,7 @@ public: > /* From datasheet: 0x32 at 10bits. */ > blackLevel_ = 3200; > gain_ = AnalogueGainLinear{ 0, 2048, -1, 2048 }; > + exposureMargin_ = 4; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("imx283", CameraSensorHelperImx283) > @@ -586,6 +615,7 @@ public: > /* From datasheet: 0xf0 at 12bits. */ > blackLevel_ = 3840; > gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; > + exposureMargin_ = 2; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("imx290", CameraSensorHelperImx290) > @@ -596,6 +626,11 @@ public: > CameraSensorHelperImx296() > { > gain_ = AnalogueGainExp{ 1.0, expGainDb(0.1) }; > + /* > + * The driver doesn't apply any margin. Use the value > + * in RPi's CamHelper. > + */ > + exposureMargin_ = 4; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("imx296", CameraSensorHelperImx296) > @@ -613,6 +648,7 @@ public: > /* From datasheet: 0x32 at 10bits. */ > blackLevel_ = 3200; > gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; > + exposureMargin_ = 9; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("imx335", CameraSensorHelperImx335) > @@ -635,6 +671,7 @@ public: > CameraSensorHelperImx415() > { > gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; > + exposureMargin_ = 8; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("imx415", CameraSensorHelperImx415) > @@ -663,6 +700,7 @@ public: > CameraSensorHelperImx477() > { > gain_ = AnalogueGainLinear{ 0, 1024, -1, 1024 }; > + exposureMargin_ = 22; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("imx477", CameraSensorHelperImx477) > @@ -762,6 +800,7 @@ public: > * This has been validated with some empirical testing only. > */ > gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > + exposureMargin_ = 4; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("ov2685", CameraSensorHelperOv2685) > @@ -774,6 +813,7 @@ public: > /* From Linux kernel driver: 0x40 at 10bits. */ > blackLevel_ = 4096; > gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > + exposureMargin_ = 8; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("ov2740", CameraSensorHelperOv2740) > @@ -786,6 +826,7 @@ public: > /* From datasheet: 0x40 at 12bits. */ > blackLevel_ = 1024; > gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > + exposureMargin_ = 4; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("ov4689", CameraSensorHelperOv4689) > @@ -798,6 +839,14 @@ public: > /* From datasheet: 0x10 at 10bits. */ > blackLevel_ = 1024; > gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; > + /* > + * Very convoluted in the driver that however applies a margin > + * of 4 lines when setting vts. > + * > + * cap_vts = cap_shutter + 4; > + * ret = ov5640_set_vts(sensor, cap_vts); > + */ > + exposureMargin_ = 4; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("ov5640", CameraSensorHelperOv5640) > @@ -808,6 +857,7 @@ public: > CameraSensorHelperOv5647() > { > gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; > + exposureMargin_ = 4; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("ov5647", CameraSensorHelperOv5647) > @@ -818,6 +868,7 @@ public: > CameraSensorHelperOv5670() > { > gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > + exposureMargin_ = 8; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670) > @@ -830,6 +881,7 @@ public: > /* From Linux kernel driver: 0x40 at 10bits. */ > blackLevel_ = 4096; > gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > + exposureMargin_ = 4; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("ov5675", CameraSensorHelperOv5675) > @@ -841,6 +893,7 @@ public: > { > blackLevel_ = 1024; > gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; > + exposureMargin_ = 8; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693) > @@ -851,6 +904,7 @@ public: > CameraSensorHelperOv64a40() > { > gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > + exposureMargin_ = 32; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("ov64a40", CameraSensorHelperOv64a40) > @@ -867,6 +921,7 @@ public: > * See: https://patchwork.linuxtv.org/project/linux-media/patch/20221106171129.166892-2-nicholas@rothemail.net/#142267 > */ > gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > + exposureMargin_ = 4; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("ov8858", CameraSensorHelperOv8858) > @@ -877,6 +932,7 @@ public: > CameraSensorHelperOv8865() > { > gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > + exposureMargin_ = 8; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("ov8865", CameraSensorHelperOv8865) > @@ -887,6 +943,7 @@ public: > CameraSensorHelperOv13858() > { > gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > + exposureMargin_ = 8; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("ov13858", CameraSensorHelperOv13858) > @@ -899,6 +956,7 @@ public: > /* From datasheet: 0x40 at 10bits. */ > blackLevel_ = 4096; > gain_ = AnalogueGainLinear{ 0, 32, -1, 32 }; > + exposureMargin_ = 64; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("vd55g1", CameraSensorHelperVd55g1) > @@ -911,6 +969,7 @@ public: > /* From datasheet: 0x40 at 10bits. */ > blackLevel_ = 4096; > gain_ = AnalogueGainLinear{ 0, 32, -1, 32 }; > + exposureMargin_ = 75; > } > }; > REGISTER_CAMERA_SENSOR_HELPER("vd56g3", CameraSensorHelperVd56g3) > diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h > index bd3d0beec7..a9e55c832d 100644 > --- a/src/ipa/libipa/camera_sensor_helper.h > +++ b/src/ipa/libipa/camera_sensor_helper.h > @@ -27,6 +27,7 @@ public: > virtual ~CameraSensorHelper() = default; > > std::optional<int16_t> blackLevel() const { return blackLevel_; } > + std::optional<uint32_t> exposureMargin() const { return exposureMargin_; } > virtual uint32_t gainCode(double gain) const; > virtual double gain(uint32_t gainCode) const; > double quantizeGain(double gain, double *quantizationGain) const; > @@ -46,6 +47,7 @@ protected: > > std::optional<int16_t> blackLevel_; > std::variant<std::monostate, AnalogueGainLinear, AnalogueGainExp> gain_; > + std::optional<uint32_t> exposureMargin_; > > private: > LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorHelper) > -- > 2.55.0 >
2026. 08. 27. 15:52 keltezéssel, Stefan Klug írta: > Hi Jacopo, hi Barnabás, > > Quoting Barnabás Pőcze (2026-08-27 12:41:06) >> From: Jacopo Mondi <jacopo.mondi@ideasonboard.com> >> >> There is a margin between the maximum achievable shutter time and the frame >> length. The value is sensor-dependent and should be used to adjust the >> maximum achievable exposure time whenever the frame length changes. >> >> Introduce in the CameraSensorHelper the notion of exposureMargin_ as the >> minimum difference in number of lines between the current frame length and >> the maximum exposure time. >> >> This feature is already implemented in the RPi CamHelper class hierarchy >> with the name of frameIntegrationDiff. >> >> Populate the CameraSensorHelper instances with an exposureMargin_. The >> value of the exposure margin comes from the mainline driver version of each >> sensor, and it has been compared with the frameIntegrationDiff_ value in >> the rpi camera helpers. >> >> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> >> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> >> --- >> src/ipa/libipa/camera_sensor_helper.cpp | 59 +++++++++++++++++++++++++ >> src/ipa/libipa/camera_sensor_helper.h | 2 + >> 2 files changed, 61 insertions(+) >> >> diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp >> index 1a90343c00..3da69bf17b 100644 >> --- a/src/ipa/libipa/camera_sensor_helper.cpp >> +++ b/src/ipa/libipa/camera_sensor_helper.cpp >> @@ -76,6 +76,16 @@ namespace ipa { >> * \return The black level of the sensor, or std::nullopt if not known >> */ >> >> +/** >> + * \fn CameraSensorHelper::exposureMargin() >> + * \brief Fetch the exposure margin of the sensor >> + * >> + * This function returns the exposure margin of the sensor, in lines, which >> + * is the minimum difference between the integration time and frame length. >> + * >> + * \return The exposure margin of the sensor, or std::nullopt if not know > > s/know/known/ > > I'm not a big fan of hardcoding these inside libcamera. But I guess > querying the sensor for that is difficult/impossible? Well, a new v4l2 control is possible, I think. Other than that, maybe libcamera could check the max exposure for the min and max vblank values. I think that should be enough to derive a safe margin for any sensor where it is a monotonic function of the vblank. Then that could maybe be provided in `IPACameraSensorInfo`. Thoughts? > > If the answer is "Yes, difficult/impossible": > > Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> > > Best regards, > Stefan > >> + */ >> + >> /** >> * \brief Compute gain code from the analogue gain absolute value >> * \param[in] gain The real gain to pass >> @@ -229,6 +239,12 @@ double CameraSensorHelper::quantizeGain(double _gain, double *quantizationGain) >> * sensor specific. Use this variable to store the values at init time. >> */ >> >> +/** >> + * \var CameraSensorHelper::exposureMargin_ >> + * \brief The smallest margin between the integration time and the frame length >> + * in lines >> + */ >> + >> /** >> * \class CameraSensorHelperFactoryBase >> * \brief Base class for camera sensor helper factories >> @@ -385,6 +401,7 @@ public: >> { >> /* Power-on default value: 168 at 12bits. */ >> blackLevel_ = 2688; >> + exposureMargin_ = 4; >> } >> >> uint32_t gainCode(double gain) const override >> @@ -474,6 +491,11 @@ REGISTER_CAMERA_SENSOR_HELPER("ar0144", CameraSensorHelperAr0144) >> class CameraSensorHelperAr0521 : public CameraSensorHelper >> { >> public: >> + CameraSensorHelperAr0521() >> + { >> + exposureMargin_ = 4; >> + } >> + >> uint32_t gainCode(double gain) const override >> { >> gain = std::clamp(gain, 1.0, 15.5); >> @@ -504,6 +526,7 @@ public: >> /* From datasheet: 64 at 10bits. */ >> blackLevel_ = 4096; >> gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 }; >> + exposureMargin_ = 4; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("gc05a2", CameraSensorHelperGc05a2) >> @@ -516,6 +539,7 @@ public: >> /* From datasheet: 64 at 10bits. */ >> blackLevel_ = 4096; >> gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 }; >> + exposureMargin_ = 16; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("gc08a3", CameraSensorHelperGc08a3) >> @@ -526,6 +550,7 @@ public: >> CameraSensorHelperHm1246() >> { >> gain_ = AnalogueGainLinear{ 1, 16, 0, 16 }; >> + exposureMargin_ = 2; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("hm1246", CameraSensorHelperHm1246) >> @@ -538,6 +563,7 @@ public: >> /* From datasheet: 64 at 10bits. */ >> blackLevel_ = 4096; >> gain_ = AnalogueGainLinear{ 0, 512, -1, 512 }; >> + exposureMargin_ = 10; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("imx214", CameraSensorHelperImx214) >> @@ -550,6 +576,7 @@ public: >> /* From datasheet: 64 at 10bits. */ >> blackLevel_ = 4096; >> gain_ = AnalogueGainLinear{ 0, 256, -1, 256 }; >> + exposureMargin_ = 4; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("imx219", CameraSensorHelperImx219) >> @@ -562,6 +589,7 @@ public: >> /* From datasheet: 0x40 at 10bits. */ >> blackLevel_ = 4096; >> gain_ = AnalogueGainLinear{ 0, 512, -1, 512 }; >> + exposureMargin_ = 10; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("imx258", CameraSensorHelperImx258) >> @@ -574,6 +602,7 @@ public: >> /* From datasheet: 0x32 at 10bits. */ >> blackLevel_ = 3200; >> gain_ = AnalogueGainLinear{ 0, 2048, -1, 2048 }; >> + exposureMargin_ = 4; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("imx283", CameraSensorHelperImx283) >> @@ -586,6 +615,7 @@ public: >> /* From datasheet: 0xf0 at 12bits. */ >> blackLevel_ = 3840; >> gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; >> + exposureMargin_ = 2; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("imx290", CameraSensorHelperImx290) >> @@ -596,6 +626,11 @@ public: >> CameraSensorHelperImx296() >> { >> gain_ = AnalogueGainExp{ 1.0, expGainDb(0.1) }; >> + /* >> + * The driver doesn't apply any margin. Use the value >> + * in RPi's CamHelper. >> + */ >> + exposureMargin_ = 4; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("imx296", CameraSensorHelperImx296) >> @@ -613,6 +648,7 @@ public: >> /* From datasheet: 0x32 at 10bits. */ >> blackLevel_ = 3200; >> gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; >> + exposureMargin_ = 9; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("imx335", CameraSensorHelperImx335) >> @@ -635,6 +671,7 @@ public: >> CameraSensorHelperImx415() >> { >> gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; >> + exposureMargin_ = 8; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("imx415", CameraSensorHelperImx415) >> @@ -663,6 +700,7 @@ public: >> CameraSensorHelperImx477() >> { >> gain_ = AnalogueGainLinear{ 0, 1024, -1, 1024 }; >> + exposureMargin_ = 22; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("imx477", CameraSensorHelperImx477) >> @@ -762,6 +800,7 @@ public: >> * This has been validated with some empirical testing only. >> */ >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >> + exposureMargin_ = 4; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("ov2685", CameraSensorHelperOv2685) >> @@ -774,6 +813,7 @@ public: >> /* From Linux kernel driver: 0x40 at 10bits. */ >> blackLevel_ = 4096; >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >> + exposureMargin_ = 8; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("ov2740", CameraSensorHelperOv2740) >> @@ -786,6 +826,7 @@ public: >> /* From datasheet: 0x40 at 12bits. */ >> blackLevel_ = 1024; >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >> + exposureMargin_ = 4; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("ov4689", CameraSensorHelperOv4689) >> @@ -798,6 +839,14 @@ public: >> /* From datasheet: 0x10 at 10bits. */ >> blackLevel_ = 1024; >> gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; >> + /* >> + * Very convoluted in the driver that however applies a margin >> + * of 4 lines when setting vts. >> + * >> + * cap_vts = cap_shutter + 4; >> + * ret = ov5640_set_vts(sensor, cap_vts); >> + */ >> + exposureMargin_ = 4; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("ov5640", CameraSensorHelperOv5640) >> @@ -808,6 +857,7 @@ public: >> CameraSensorHelperOv5647() >> { >> gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; >> + exposureMargin_ = 4; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("ov5647", CameraSensorHelperOv5647) >> @@ -818,6 +868,7 @@ public: >> CameraSensorHelperOv5670() >> { >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >> + exposureMargin_ = 8; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670) >> @@ -830,6 +881,7 @@ public: >> /* From Linux kernel driver: 0x40 at 10bits. */ >> blackLevel_ = 4096; >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >> + exposureMargin_ = 4; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("ov5675", CameraSensorHelperOv5675) >> @@ -841,6 +893,7 @@ public: >> { >> blackLevel_ = 1024; >> gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; >> + exposureMargin_ = 8; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693) >> @@ -851,6 +904,7 @@ public: >> CameraSensorHelperOv64a40() >> { >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >> + exposureMargin_ = 32; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("ov64a40", CameraSensorHelperOv64a40) >> @@ -867,6 +921,7 @@ public: >> * See: https://patchwork.linuxtv.org/project/linux-media/patch/20221106171129.166892-2-nicholas@rothemail.net/#142267 >> */ >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >> + exposureMargin_ = 4; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("ov8858", CameraSensorHelperOv8858) >> @@ -877,6 +932,7 @@ public: >> CameraSensorHelperOv8865() >> { >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >> + exposureMargin_ = 8; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("ov8865", CameraSensorHelperOv8865) >> @@ -887,6 +943,7 @@ public: >> CameraSensorHelperOv13858() >> { >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >> + exposureMargin_ = 8; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("ov13858", CameraSensorHelperOv13858) >> @@ -899,6 +956,7 @@ public: >> /* From datasheet: 0x40 at 10bits. */ >> blackLevel_ = 4096; >> gain_ = AnalogueGainLinear{ 0, 32, -1, 32 }; >> + exposureMargin_ = 64; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("vd55g1", CameraSensorHelperVd55g1) >> @@ -911,6 +969,7 @@ public: >> /* From datasheet: 0x40 at 10bits. */ >> blackLevel_ = 4096; >> gain_ = AnalogueGainLinear{ 0, 32, -1, 32 }; >> + exposureMargin_ = 75; >> } >> }; >> REGISTER_CAMERA_SENSOR_HELPER("vd56g3", CameraSensorHelperVd56g3) >> diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h >> index bd3d0beec7..a9e55c832d 100644 >> --- a/src/ipa/libipa/camera_sensor_helper.h >> +++ b/src/ipa/libipa/camera_sensor_helper.h >> @@ -27,6 +27,7 @@ public: >> virtual ~CameraSensorHelper() = default; >> >> std::optional<int16_t> blackLevel() const { return blackLevel_; } >> + std::optional<uint32_t> exposureMargin() const { return exposureMargin_; } >> virtual uint32_t gainCode(double gain) const; >> virtual double gain(uint32_t gainCode) const; >> double quantizeGain(double gain, double *quantizationGain) const; >> @@ -46,6 +47,7 @@ protected: >> >> std::optional<int16_t> blackLevel_; >> std::variant<std::monostate, AnalogueGainLinear, AnalogueGainExp> gain_; >> + std::optional<uint32_t> exposureMargin_; >> >> private: >> LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorHelper) >> -- >> 2.55.0 >>
Hi, On Thu, 27 Aug 2026 at 14:59, Barnabás Pőcze <barnabas.pocze@ideasonboard.com> wrote: > > 2026. 08. 27. 15:52 keltezéssel, Stefan Klug írta: > > Hi Jacopo, hi Barnabás, > > > > Quoting Barnabás Pőcze (2026-08-27 12:41:06) > >> From: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > >> > >> There is a margin between the maximum achievable shutter time and the frame > >> length. The value is sensor-dependent and should be used to adjust the > >> maximum achievable exposure time whenever the frame length changes. > >> > >> Introduce in the CameraSensorHelper the notion of exposureMargin_ as the > >> minimum difference in number of lines between the current frame length and > >> the maximum exposure time. > >> > >> This feature is already implemented in the RPi CamHelper class hierarchy > >> with the name of frameIntegrationDiff. > >> > >> Populate the CameraSensorHelper instances with an exposureMargin_. The > >> value of the exposure margin comes from the mainline driver version of each > >> sensor, and it has been compared with the frameIntegrationDiff_ value in > >> the rpi camera helpers. > >> > >> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> > >> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> > >> --- > >> src/ipa/libipa/camera_sensor_helper.cpp | 59 +++++++++++++++++++++++++ > >> src/ipa/libipa/camera_sensor_helper.h | 2 + > >> 2 files changed, 61 insertions(+) > >> > >> diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp > >> index 1a90343c00..3da69bf17b 100644 > >> --- a/src/ipa/libipa/camera_sensor_helper.cpp > >> +++ b/src/ipa/libipa/camera_sensor_helper.cpp > >> @@ -76,6 +76,16 @@ namespace ipa { > >> * \return The black level of the sensor, or std::nullopt if not known > >> */ > >> > >> +/** > >> + * \fn CameraSensorHelper::exposureMargin() > >> + * \brief Fetch the exposure margin of the sensor > >> + * > >> + * This function returns the exposure margin of the sensor, in lines, which > >> + * is the minimum difference between the integration time and frame length. > >> + * > >> + * \return The exposure margin of the sensor, or std::nullopt if not know > > > > s/know/known/ > > > > I'm not a big fan of hardcoding these inside libcamera. But I guess > > querying the sensor for that is difficult/impossible? > > Well, a new v4l2 control is possible, I think. Other than that, maybe libcamera > could check the max exposure for the min and max vblank values. I think that should > be enough to derive a safe margin for any sensor where it is a monotonic function of > the vblank. Then that could maybe be provided in `IPACameraSensorInfo`. Thoughts? This was what we (RPi) originally intended to do in our implementation. However, we found that many drivers did not account for the frame integration difference and the effective value would end up at 0. There are also cases where the difference is just plain wrong. Of course the fix is to correct the driver, but having an easily accessible lever in userland has been really nice and convenient for testing. Regards, Naush > > > > > > If the answer is "Yes, difficult/impossible": > > > > Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> > > > > Best regards, > > Stefan > > > >> + */ > >> + > >> /** > >> * \brief Compute gain code from the analogue gain absolute value > >> * \param[in] gain The real gain to pass > >> @@ -229,6 +239,12 @@ double CameraSensorHelper::quantizeGain(double _gain, double *quantizationGain) > >> * sensor specific. Use this variable to store the values at init time. > >> */ > >> > >> +/** > >> + * \var CameraSensorHelper::exposureMargin_ > >> + * \brief The smallest margin between the integration time and the frame length > >> + * in lines > >> + */ > >> + > >> /** > >> * \class CameraSensorHelperFactoryBase > >> * \brief Base class for camera sensor helper factories > >> @@ -385,6 +401,7 @@ public: > >> { > >> /* Power-on default value: 168 at 12bits. */ > >> blackLevel_ = 2688; > >> + exposureMargin_ = 4; > >> } > >> > >> uint32_t gainCode(double gain) const override > >> @@ -474,6 +491,11 @@ REGISTER_CAMERA_SENSOR_HELPER("ar0144", CameraSensorHelperAr0144) > >> class CameraSensorHelperAr0521 : public CameraSensorHelper > >> { > >> public: > >> + CameraSensorHelperAr0521() > >> + { > >> + exposureMargin_ = 4; > >> + } > >> + > >> uint32_t gainCode(double gain) const override > >> { > >> gain = std::clamp(gain, 1.0, 15.5); > >> @@ -504,6 +526,7 @@ public: > >> /* From datasheet: 64 at 10bits. */ > >> blackLevel_ = 4096; > >> gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 }; > >> + exposureMargin_ = 4; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("gc05a2", CameraSensorHelperGc05a2) > >> @@ -516,6 +539,7 @@ public: > >> /* From datasheet: 64 at 10bits. */ > >> blackLevel_ = 4096; > >> gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 }; > >> + exposureMargin_ = 16; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("gc08a3", CameraSensorHelperGc08a3) > >> @@ -526,6 +550,7 @@ public: > >> CameraSensorHelperHm1246() > >> { > >> gain_ = AnalogueGainLinear{ 1, 16, 0, 16 }; > >> + exposureMargin_ = 2; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("hm1246", CameraSensorHelperHm1246) > >> @@ -538,6 +563,7 @@ public: > >> /* From datasheet: 64 at 10bits. */ > >> blackLevel_ = 4096; > >> gain_ = AnalogueGainLinear{ 0, 512, -1, 512 }; > >> + exposureMargin_ = 10; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("imx214", CameraSensorHelperImx214) > >> @@ -550,6 +576,7 @@ public: > >> /* From datasheet: 64 at 10bits. */ > >> blackLevel_ = 4096; > >> gain_ = AnalogueGainLinear{ 0, 256, -1, 256 }; > >> + exposureMargin_ = 4; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("imx219", CameraSensorHelperImx219) > >> @@ -562,6 +589,7 @@ public: > >> /* From datasheet: 0x40 at 10bits. */ > >> blackLevel_ = 4096; > >> gain_ = AnalogueGainLinear{ 0, 512, -1, 512 }; > >> + exposureMargin_ = 10; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("imx258", CameraSensorHelperImx258) > >> @@ -574,6 +602,7 @@ public: > >> /* From datasheet: 0x32 at 10bits. */ > >> blackLevel_ = 3200; > >> gain_ = AnalogueGainLinear{ 0, 2048, -1, 2048 }; > >> + exposureMargin_ = 4; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("imx283", CameraSensorHelperImx283) > >> @@ -586,6 +615,7 @@ public: > >> /* From datasheet: 0xf0 at 12bits. */ > >> blackLevel_ = 3840; > >> gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; > >> + exposureMargin_ = 2; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("imx290", CameraSensorHelperImx290) > >> @@ -596,6 +626,11 @@ public: > >> CameraSensorHelperImx296() > >> { > >> gain_ = AnalogueGainExp{ 1.0, expGainDb(0.1) }; > >> + /* > >> + * The driver doesn't apply any margin. Use the value > >> + * in RPi's CamHelper. > >> + */ > >> + exposureMargin_ = 4; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("imx296", CameraSensorHelperImx296) > >> @@ -613,6 +648,7 @@ public: > >> /* From datasheet: 0x32 at 10bits. */ > >> blackLevel_ = 3200; > >> gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; > >> + exposureMargin_ = 9; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("imx335", CameraSensorHelperImx335) > >> @@ -635,6 +671,7 @@ public: > >> CameraSensorHelperImx415() > >> { > >> gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; > >> + exposureMargin_ = 8; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("imx415", CameraSensorHelperImx415) > >> @@ -663,6 +700,7 @@ public: > >> CameraSensorHelperImx477() > >> { > >> gain_ = AnalogueGainLinear{ 0, 1024, -1, 1024 }; > >> + exposureMargin_ = 22; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("imx477", CameraSensorHelperImx477) > >> @@ -762,6 +800,7 @@ public: > >> * This has been validated with some empirical testing only. > >> */ > >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > >> + exposureMargin_ = 4; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("ov2685", CameraSensorHelperOv2685) > >> @@ -774,6 +813,7 @@ public: > >> /* From Linux kernel driver: 0x40 at 10bits. */ > >> blackLevel_ = 4096; > >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > >> + exposureMargin_ = 8; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("ov2740", CameraSensorHelperOv2740) > >> @@ -786,6 +826,7 @@ public: > >> /* From datasheet: 0x40 at 12bits. */ > >> blackLevel_ = 1024; > >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > >> + exposureMargin_ = 4; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("ov4689", CameraSensorHelperOv4689) > >> @@ -798,6 +839,14 @@ public: > >> /* From datasheet: 0x10 at 10bits. */ > >> blackLevel_ = 1024; > >> gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; > >> + /* > >> + * Very convoluted in the driver that however applies a margin > >> + * of 4 lines when setting vts. > >> + * > >> + * cap_vts = cap_shutter + 4; > >> + * ret = ov5640_set_vts(sensor, cap_vts); > >> + */ > >> + exposureMargin_ = 4; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("ov5640", CameraSensorHelperOv5640) > >> @@ -808,6 +857,7 @@ public: > >> CameraSensorHelperOv5647() > >> { > >> gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; > >> + exposureMargin_ = 4; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("ov5647", CameraSensorHelperOv5647) > >> @@ -818,6 +868,7 @@ public: > >> CameraSensorHelperOv5670() > >> { > >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > >> + exposureMargin_ = 8; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670) > >> @@ -830,6 +881,7 @@ public: > >> /* From Linux kernel driver: 0x40 at 10bits. */ > >> blackLevel_ = 4096; > >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > >> + exposureMargin_ = 4; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("ov5675", CameraSensorHelperOv5675) > >> @@ -841,6 +893,7 @@ public: > >> { > >> blackLevel_ = 1024; > >> gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; > >> + exposureMargin_ = 8; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693) > >> @@ -851,6 +904,7 @@ public: > >> CameraSensorHelperOv64a40() > >> { > >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > >> + exposureMargin_ = 32; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("ov64a40", CameraSensorHelperOv64a40) > >> @@ -867,6 +921,7 @@ public: > >> * See: https://patchwork.linuxtv.org/project/linux-media/patch/20221106171129.166892-2-nicholas@rothemail.net/#142267 > >> */ > >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > >> + exposureMargin_ = 4; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("ov8858", CameraSensorHelperOv8858) > >> @@ -877,6 +932,7 @@ public: > >> CameraSensorHelperOv8865() > >> { > >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > >> + exposureMargin_ = 8; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("ov8865", CameraSensorHelperOv8865) > >> @@ -887,6 +943,7 @@ public: > >> CameraSensorHelperOv13858() > >> { > >> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; > >> + exposureMargin_ = 8; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("ov13858", CameraSensorHelperOv13858) > >> @@ -899,6 +956,7 @@ public: > >> /* From datasheet: 0x40 at 10bits. */ > >> blackLevel_ = 4096; > >> gain_ = AnalogueGainLinear{ 0, 32, -1, 32 }; > >> + exposureMargin_ = 64; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("vd55g1", CameraSensorHelperVd55g1) > >> @@ -911,6 +969,7 @@ public: > >> /* From datasheet: 0x40 at 10bits. */ > >> blackLevel_ = 4096; > >> gain_ = AnalogueGainLinear{ 0, 32, -1, 32 }; > >> + exposureMargin_ = 75; > >> } > >> }; > >> REGISTER_CAMERA_SENSOR_HELPER("vd56g3", CameraSensorHelperVd56g3) > >> diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h > >> index bd3d0beec7..a9e55c832d 100644 > >> --- a/src/ipa/libipa/camera_sensor_helper.h > >> +++ b/src/ipa/libipa/camera_sensor_helper.h > >> @@ -27,6 +27,7 @@ public: > >> virtual ~CameraSensorHelper() = default; > >> > >> std::optional<int16_t> blackLevel() const { return blackLevel_; } > >> + std::optional<uint32_t> exposureMargin() const { return exposureMargin_; } > >> virtual uint32_t gainCode(double gain) const; > >> virtual double gain(uint32_t gainCode) const; > >> double quantizeGain(double gain, double *quantizationGain) const; > >> @@ -46,6 +47,7 @@ protected: > >> > >> std::optional<int16_t> blackLevel_; > >> std::variant<std::monostate, AnalogueGainLinear, AnalogueGainExp> gain_; > >> + std::optional<uint32_t> exposureMargin_; > >> > >> private: > >> LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorHelper) > >> -- > >> 2.55.0 > >> >
2026. 09. 01. 9:05 keltezéssel, Naushir Patuck írta: > Hi, > > On Thu, 27 Aug 2026 at 14:59, Barnabás Pőcze > <barnabas.pocze@ideasonboard.com> wrote: >> >> 2026. 08. 27. 15:52 keltezéssel, Stefan Klug írta: >>> Hi Jacopo, hi Barnabás, >>> >>> Quoting Barnabás Pőcze (2026-08-27 12:41:06) >>>> From: Jacopo Mondi <jacopo.mondi@ideasonboard.com> >>>> >>>> There is a margin between the maximum achievable shutter time and the frame >>>> length. The value is sensor-dependent and should be used to adjust the >>>> maximum achievable exposure time whenever the frame length changes. >>>> >>>> Introduce in the CameraSensorHelper the notion of exposureMargin_ as the >>>> minimum difference in number of lines between the current frame length and >>>> the maximum exposure time. >>>> >>>> This feature is already implemented in the RPi CamHelper class hierarchy >>>> with the name of frameIntegrationDiff. >>>> >>>> Populate the CameraSensorHelper instances with an exposureMargin_. The >>>> value of the exposure margin comes from the mainline driver version of each >>>> sensor, and it has been compared with the frameIntegrationDiff_ value in >>>> the rpi camera helpers. >>>> >>>> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> >>>> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> >>>> --- >>>> src/ipa/libipa/camera_sensor_helper.cpp | 59 +++++++++++++++++++++++++ >>>> src/ipa/libipa/camera_sensor_helper.h | 2 + >>>> 2 files changed, 61 insertions(+) >>>> >>>> diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp >>>> index 1a90343c00..3da69bf17b 100644 >>>> --- a/src/ipa/libipa/camera_sensor_helper.cpp >>>> +++ b/src/ipa/libipa/camera_sensor_helper.cpp >>>> @@ -76,6 +76,16 @@ namespace ipa { >>>> * \return The black level of the sensor, or std::nullopt if not known >>>> */ >>>> >>>> +/** >>>> + * \fn CameraSensorHelper::exposureMargin() >>>> + * \brief Fetch the exposure margin of the sensor >>>> + * >>>> + * This function returns the exposure margin of the sensor, in lines, which >>>> + * is the minimum difference between the integration time and frame length. >>>> + * >>>> + * \return The exposure margin of the sensor, or std::nullopt if not know >>> >>> s/know/known/ >>> >>> I'm not a big fan of hardcoding these inside libcamera. But I guess >>> querying the sensor for that is difficult/impossible? >> >> Well, a new v4l2 control is possible, I think. Other than that, maybe libcamera >> could check the max exposure for the min and max vblank values. I think that should >> be enough to derive a safe margin for any sensor where it is a monotonic function of >> the vblank. Then that could maybe be provided in `IPACameraSensorInfo`. Thoughts? > > This was what we (RPi) originally intended to do in our > implementation. However, we found that many drivers did not account > for the frame integration difference and the effective value would end > up at 0. There are also cases where the difference is just plain > wrong. Thanks for the info. But that is very sad to hear. :( Maybe there is some value in implementing that in any case as in some scenarios no sensor helper is available (e.g. softisp), and it might be better than the hard-coded 4 that is used in this changeset. (As far as I can see rpi does not run without a sensor helper, so there are no such concerns there.) > > Of course the fix is to correct the driver, but having an easily > accessible lever in userland has been really nice and convenient for > testing. > > Regards, > Naush > >> >> >>> >>> If the answer is "Yes, difficult/impossible": >>> >>> Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> >>> >>> Best regards, >>> Stefan >>> >>>> + */ >>>> + >>>> /** >>>> * \brief Compute gain code from the analogue gain absolute value >>>> * \param[in] gain The real gain to pass >>>> @@ -229,6 +239,12 @@ double CameraSensorHelper::quantizeGain(double _gain, double *quantizationGain) >>>> * sensor specific. Use this variable to store the values at init time. >>>> */ >>>> >>>> +/** >>>> + * \var CameraSensorHelper::exposureMargin_ >>>> + * \brief The smallest margin between the integration time and the frame length >>>> + * in lines >>>> + */ >>>> + >>>> /** >>>> * \class CameraSensorHelperFactoryBase >>>> * \brief Base class for camera sensor helper factories >>>> @@ -385,6 +401,7 @@ public: >>>> { >>>> /* Power-on default value: 168 at 12bits. */ >>>> blackLevel_ = 2688; >>>> + exposureMargin_ = 4; >>>> } >>>> >>>> uint32_t gainCode(double gain) const override >>>> @@ -474,6 +491,11 @@ REGISTER_CAMERA_SENSOR_HELPER("ar0144", CameraSensorHelperAr0144) >>>> class CameraSensorHelperAr0521 : public CameraSensorHelper >>>> { >>>> public: >>>> + CameraSensorHelperAr0521() >>>> + { >>>> + exposureMargin_ = 4; >>>> + } >>>> + >>>> uint32_t gainCode(double gain) const override >>>> { >>>> gain = std::clamp(gain, 1.0, 15.5); >>>> @@ -504,6 +526,7 @@ public: >>>> /* From datasheet: 64 at 10bits. */ >>>> blackLevel_ = 4096; >>>> gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 }; >>>> + exposureMargin_ = 4; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("gc05a2", CameraSensorHelperGc05a2) >>>> @@ -516,6 +539,7 @@ public: >>>> /* From datasheet: 64 at 10bits. */ >>>> blackLevel_ = 4096; >>>> gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 }; >>>> + exposureMargin_ = 16; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("gc08a3", CameraSensorHelperGc08a3) >>>> @@ -526,6 +550,7 @@ public: >>>> CameraSensorHelperHm1246() >>>> { >>>> gain_ = AnalogueGainLinear{ 1, 16, 0, 16 }; >>>> + exposureMargin_ = 2; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("hm1246", CameraSensorHelperHm1246) >>>> @@ -538,6 +563,7 @@ public: >>>> /* From datasheet: 64 at 10bits. */ >>>> blackLevel_ = 4096; >>>> gain_ = AnalogueGainLinear{ 0, 512, -1, 512 }; >>>> + exposureMargin_ = 10; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("imx214", CameraSensorHelperImx214) >>>> @@ -550,6 +576,7 @@ public: >>>> /* From datasheet: 64 at 10bits. */ >>>> blackLevel_ = 4096; >>>> gain_ = AnalogueGainLinear{ 0, 256, -1, 256 }; >>>> + exposureMargin_ = 4; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("imx219", CameraSensorHelperImx219) >>>> @@ -562,6 +589,7 @@ public: >>>> /* From datasheet: 0x40 at 10bits. */ >>>> blackLevel_ = 4096; >>>> gain_ = AnalogueGainLinear{ 0, 512, -1, 512 }; >>>> + exposureMargin_ = 10; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("imx258", CameraSensorHelperImx258) >>>> @@ -574,6 +602,7 @@ public: >>>> /* From datasheet: 0x32 at 10bits. */ >>>> blackLevel_ = 3200; >>>> gain_ = AnalogueGainLinear{ 0, 2048, -1, 2048 }; >>>> + exposureMargin_ = 4; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("imx283", CameraSensorHelperImx283) >>>> @@ -586,6 +615,7 @@ public: >>>> /* From datasheet: 0xf0 at 12bits. */ >>>> blackLevel_ = 3840; >>>> gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; >>>> + exposureMargin_ = 2; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("imx290", CameraSensorHelperImx290) >>>> @@ -596,6 +626,11 @@ public: >>>> CameraSensorHelperImx296() >>>> { >>>> gain_ = AnalogueGainExp{ 1.0, expGainDb(0.1) }; >>>> + /* >>>> + * The driver doesn't apply any margin. Use the value >>>> + * in RPi's CamHelper. >>>> + */ >>>> + exposureMargin_ = 4; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("imx296", CameraSensorHelperImx296) >>>> @@ -613,6 +648,7 @@ public: >>>> /* From datasheet: 0x32 at 10bits. */ >>>> blackLevel_ = 3200; >>>> gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; >>>> + exposureMargin_ = 9; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("imx335", CameraSensorHelperImx335) >>>> @@ -635,6 +671,7 @@ public: >>>> CameraSensorHelperImx415() >>>> { >>>> gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; >>>> + exposureMargin_ = 8; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("imx415", CameraSensorHelperImx415) >>>> @@ -663,6 +700,7 @@ public: >>>> CameraSensorHelperImx477() >>>> { >>>> gain_ = AnalogueGainLinear{ 0, 1024, -1, 1024 }; >>>> + exposureMargin_ = 22; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("imx477", CameraSensorHelperImx477) >>>> @@ -762,6 +800,7 @@ public: >>>> * This has been validated with some empirical testing only. >>>> */ >>>> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >>>> + exposureMargin_ = 4; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("ov2685", CameraSensorHelperOv2685) >>>> @@ -774,6 +813,7 @@ public: >>>> /* From Linux kernel driver: 0x40 at 10bits. */ >>>> blackLevel_ = 4096; >>>> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >>>> + exposureMargin_ = 8; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("ov2740", CameraSensorHelperOv2740) >>>> @@ -786,6 +826,7 @@ public: >>>> /* From datasheet: 0x40 at 12bits. */ >>>> blackLevel_ = 1024; >>>> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >>>> + exposureMargin_ = 4; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("ov4689", CameraSensorHelperOv4689) >>>> @@ -798,6 +839,14 @@ public: >>>> /* From datasheet: 0x10 at 10bits. */ >>>> blackLevel_ = 1024; >>>> gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; >>>> + /* >>>> + * Very convoluted in the driver that however applies a margin >>>> + * of 4 lines when setting vts. >>>> + * >>>> + * cap_vts = cap_shutter + 4; >>>> + * ret = ov5640_set_vts(sensor, cap_vts); >>>> + */ >>>> + exposureMargin_ = 4; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("ov5640", CameraSensorHelperOv5640) >>>> @@ -808,6 +857,7 @@ public: >>>> CameraSensorHelperOv5647() >>>> { >>>> gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; >>>> + exposureMargin_ = 4; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("ov5647", CameraSensorHelperOv5647) >>>> @@ -818,6 +868,7 @@ public: >>>> CameraSensorHelperOv5670() >>>> { >>>> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >>>> + exposureMargin_ = 8; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670) >>>> @@ -830,6 +881,7 @@ public: >>>> /* From Linux kernel driver: 0x40 at 10bits. */ >>>> blackLevel_ = 4096; >>>> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >>>> + exposureMargin_ = 4; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("ov5675", CameraSensorHelperOv5675) >>>> @@ -841,6 +893,7 @@ public: >>>> { >>>> blackLevel_ = 1024; >>>> gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; >>>> + exposureMargin_ = 8; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693) >>>> @@ -851,6 +904,7 @@ public: >>>> CameraSensorHelperOv64a40() >>>> { >>>> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >>>> + exposureMargin_ = 32; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("ov64a40", CameraSensorHelperOv64a40) >>>> @@ -867,6 +921,7 @@ public: >>>> * See: https://patchwork.linuxtv.org/project/linux-media/patch/20221106171129.166892-2-nicholas@rothemail.net/#142267 >>>> */ >>>> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >>>> + exposureMargin_ = 4; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("ov8858", CameraSensorHelperOv8858) >>>> @@ -877,6 +932,7 @@ public: >>>> CameraSensorHelperOv8865() >>>> { >>>> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >>>> + exposureMargin_ = 8; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("ov8865", CameraSensorHelperOv8865) >>>> @@ -887,6 +943,7 @@ public: >>>> CameraSensorHelperOv13858() >>>> { >>>> gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; >>>> + exposureMargin_ = 8; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("ov13858", CameraSensorHelperOv13858) >>>> @@ -899,6 +956,7 @@ public: >>>> /* From datasheet: 0x40 at 10bits. */ >>>> blackLevel_ = 4096; >>>> gain_ = AnalogueGainLinear{ 0, 32, -1, 32 }; >>>> + exposureMargin_ = 64; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("vd55g1", CameraSensorHelperVd55g1) >>>> @@ -911,6 +969,7 @@ public: >>>> /* From datasheet: 0x40 at 10bits. */ >>>> blackLevel_ = 4096; >>>> gain_ = AnalogueGainLinear{ 0, 32, -1, 32 }; >>>> + exposureMargin_ = 75; >>>> } >>>> }; >>>> REGISTER_CAMERA_SENSOR_HELPER("vd56g3", CameraSensorHelperVd56g3) >>>> diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h >>>> index bd3d0beec7..a9e55c832d 100644 >>>> --- a/src/ipa/libipa/camera_sensor_helper.h >>>> +++ b/src/ipa/libipa/camera_sensor_helper.h >>>> @@ -27,6 +27,7 @@ public: >>>> virtual ~CameraSensorHelper() = default; >>>> >>>> std::optional<int16_t> blackLevel() const { return blackLevel_; } >>>> + std::optional<uint32_t> exposureMargin() const { return exposureMargin_; } >>>> virtual uint32_t gainCode(double gain) const; >>>> virtual double gain(uint32_t gainCode) const; >>>> double quantizeGain(double gain, double *quantizationGain) const; >>>> @@ -46,6 +47,7 @@ protected: >>>> >>>> std::optional<int16_t> blackLevel_; >>>> std::variant<std::monostate, AnalogueGainLinear, AnalogueGainExp> gain_; >>>> + std::optional<uint32_t> exposureMargin_; >>>> >>>> private: >>>> LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorHelper) >>>> -- >>>> 2.55.0 >>>> >>
diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp index 1a90343c00..3da69bf17b 100644 --- a/src/ipa/libipa/camera_sensor_helper.cpp +++ b/src/ipa/libipa/camera_sensor_helper.cpp @@ -76,6 +76,16 @@ namespace ipa { * \return The black level of the sensor, or std::nullopt if not known */ +/** + * \fn CameraSensorHelper::exposureMargin() + * \brief Fetch the exposure margin of the sensor + * + * This function returns the exposure margin of the sensor, in lines, which + * is the minimum difference between the integration time and frame length. + * + * \return The exposure margin of the sensor, or std::nullopt if not know + */ + /** * \brief Compute gain code from the analogue gain absolute value * \param[in] gain The real gain to pass @@ -229,6 +239,12 @@ double CameraSensorHelper::quantizeGain(double _gain, double *quantizationGain) * sensor specific. Use this variable to store the values at init time. */ +/** + * \var CameraSensorHelper::exposureMargin_ + * \brief The smallest margin between the integration time and the frame length + * in lines + */ + /** * \class CameraSensorHelperFactoryBase * \brief Base class for camera sensor helper factories @@ -385,6 +401,7 @@ public: { /* Power-on default value: 168 at 12bits. */ blackLevel_ = 2688; + exposureMargin_ = 4; } uint32_t gainCode(double gain) const override @@ -474,6 +491,11 @@ REGISTER_CAMERA_SENSOR_HELPER("ar0144", CameraSensorHelperAr0144) class CameraSensorHelperAr0521 : public CameraSensorHelper { public: + CameraSensorHelperAr0521() + { + exposureMargin_ = 4; + } + uint32_t gainCode(double gain) const override { gain = std::clamp(gain, 1.0, 15.5); @@ -504,6 +526,7 @@ public: /* From datasheet: 64 at 10bits. */ blackLevel_ = 4096; gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 }; + exposureMargin_ = 4; } }; REGISTER_CAMERA_SENSOR_HELPER("gc05a2", CameraSensorHelperGc05a2) @@ -516,6 +539,7 @@ public: /* From datasheet: 64 at 10bits. */ blackLevel_ = 4096; gain_ = AnalogueGainLinear{ 100, 0, 0, 1024 }; + exposureMargin_ = 16; } }; REGISTER_CAMERA_SENSOR_HELPER("gc08a3", CameraSensorHelperGc08a3) @@ -526,6 +550,7 @@ public: CameraSensorHelperHm1246() { gain_ = AnalogueGainLinear{ 1, 16, 0, 16 }; + exposureMargin_ = 2; } }; REGISTER_CAMERA_SENSOR_HELPER("hm1246", CameraSensorHelperHm1246) @@ -538,6 +563,7 @@ public: /* From datasheet: 64 at 10bits. */ blackLevel_ = 4096; gain_ = AnalogueGainLinear{ 0, 512, -1, 512 }; + exposureMargin_ = 10; } }; REGISTER_CAMERA_SENSOR_HELPER("imx214", CameraSensorHelperImx214) @@ -550,6 +576,7 @@ public: /* From datasheet: 64 at 10bits. */ blackLevel_ = 4096; gain_ = AnalogueGainLinear{ 0, 256, -1, 256 }; + exposureMargin_ = 4; } }; REGISTER_CAMERA_SENSOR_HELPER("imx219", CameraSensorHelperImx219) @@ -562,6 +589,7 @@ public: /* From datasheet: 0x40 at 10bits. */ blackLevel_ = 4096; gain_ = AnalogueGainLinear{ 0, 512, -1, 512 }; + exposureMargin_ = 10; } }; REGISTER_CAMERA_SENSOR_HELPER("imx258", CameraSensorHelperImx258) @@ -574,6 +602,7 @@ public: /* From datasheet: 0x32 at 10bits. */ blackLevel_ = 3200; gain_ = AnalogueGainLinear{ 0, 2048, -1, 2048 }; + exposureMargin_ = 4; } }; REGISTER_CAMERA_SENSOR_HELPER("imx283", CameraSensorHelperImx283) @@ -586,6 +615,7 @@ public: /* From datasheet: 0xf0 at 12bits. */ blackLevel_ = 3840; gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; + exposureMargin_ = 2; } }; REGISTER_CAMERA_SENSOR_HELPER("imx290", CameraSensorHelperImx290) @@ -596,6 +626,11 @@ public: CameraSensorHelperImx296() { gain_ = AnalogueGainExp{ 1.0, expGainDb(0.1) }; + /* + * The driver doesn't apply any margin. Use the value + * in RPi's CamHelper. + */ + exposureMargin_ = 4; } }; REGISTER_CAMERA_SENSOR_HELPER("imx296", CameraSensorHelperImx296) @@ -613,6 +648,7 @@ public: /* From datasheet: 0x32 at 10bits. */ blackLevel_ = 3200; gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; + exposureMargin_ = 9; } }; REGISTER_CAMERA_SENSOR_HELPER("imx335", CameraSensorHelperImx335) @@ -635,6 +671,7 @@ public: CameraSensorHelperImx415() { gain_ = AnalogueGainExp{ 1.0, expGainDb(0.3) }; + exposureMargin_ = 8; } }; REGISTER_CAMERA_SENSOR_HELPER("imx415", CameraSensorHelperImx415) @@ -663,6 +700,7 @@ public: CameraSensorHelperImx477() { gain_ = AnalogueGainLinear{ 0, 1024, -1, 1024 }; + exposureMargin_ = 22; } }; REGISTER_CAMERA_SENSOR_HELPER("imx477", CameraSensorHelperImx477) @@ -762,6 +800,7 @@ public: * This has been validated with some empirical testing only. */ gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; + exposureMargin_ = 4; } }; REGISTER_CAMERA_SENSOR_HELPER("ov2685", CameraSensorHelperOv2685) @@ -774,6 +813,7 @@ public: /* From Linux kernel driver: 0x40 at 10bits. */ blackLevel_ = 4096; gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; + exposureMargin_ = 8; } }; REGISTER_CAMERA_SENSOR_HELPER("ov2740", CameraSensorHelperOv2740) @@ -786,6 +826,7 @@ public: /* From datasheet: 0x40 at 12bits. */ blackLevel_ = 1024; gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; + exposureMargin_ = 4; } }; REGISTER_CAMERA_SENSOR_HELPER("ov4689", CameraSensorHelperOv4689) @@ -798,6 +839,14 @@ public: /* From datasheet: 0x10 at 10bits. */ blackLevel_ = 1024; gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; + /* + * Very convoluted in the driver that however applies a margin + * of 4 lines when setting vts. + * + * cap_vts = cap_shutter + 4; + * ret = ov5640_set_vts(sensor, cap_vts); + */ + exposureMargin_ = 4; } }; REGISTER_CAMERA_SENSOR_HELPER("ov5640", CameraSensorHelperOv5640) @@ -808,6 +857,7 @@ public: CameraSensorHelperOv5647() { gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; + exposureMargin_ = 4; } }; REGISTER_CAMERA_SENSOR_HELPER("ov5647", CameraSensorHelperOv5647) @@ -818,6 +868,7 @@ public: CameraSensorHelperOv5670() { gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; + exposureMargin_ = 8; } }; REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670) @@ -830,6 +881,7 @@ public: /* From Linux kernel driver: 0x40 at 10bits. */ blackLevel_ = 4096; gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; + exposureMargin_ = 4; } }; REGISTER_CAMERA_SENSOR_HELPER("ov5675", CameraSensorHelperOv5675) @@ -841,6 +893,7 @@ public: { blackLevel_ = 1024; gain_ = AnalogueGainLinear{ 1, 0, 0, 16 }; + exposureMargin_ = 8; } }; REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693) @@ -851,6 +904,7 @@ public: CameraSensorHelperOv64a40() { gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; + exposureMargin_ = 32; } }; REGISTER_CAMERA_SENSOR_HELPER("ov64a40", CameraSensorHelperOv64a40) @@ -867,6 +921,7 @@ public: * See: https://patchwork.linuxtv.org/project/linux-media/patch/20221106171129.166892-2-nicholas@rothemail.net/#142267 */ gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; + exposureMargin_ = 4; } }; REGISTER_CAMERA_SENSOR_HELPER("ov8858", CameraSensorHelperOv8858) @@ -877,6 +932,7 @@ public: CameraSensorHelperOv8865() { gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; + exposureMargin_ = 8; } }; REGISTER_CAMERA_SENSOR_HELPER("ov8865", CameraSensorHelperOv8865) @@ -887,6 +943,7 @@ public: CameraSensorHelperOv13858() { gain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; + exposureMargin_ = 8; } }; REGISTER_CAMERA_SENSOR_HELPER("ov13858", CameraSensorHelperOv13858) @@ -899,6 +956,7 @@ public: /* From datasheet: 0x40 at 10bits. */ blackLevel_ = 4096; gain_ = AnalogueGainLinear{ 0, 32, -1, 32 }; + exposureMargin_ = 64; } }; REGISTER_CAMERA_SENSOR_HELPER("vd55g1", CameraSensorHelperVd55g1) @@ -911,6 +969,7 @@ public: /* From datasheet: 0x40 at 10bits. */ blackLevel_ = 4096; gain_ = AnalogueGainLinear{ 0, 32, -1, 32 }; + exposureMargin_ = 75; } }; REGISTER_CAMERA_SENSOR_HELPER("vd56g3", CameraSensorHelperVd56g3) diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h index bd3d0beec7..a9e55c832d 100644 --- a/src/ipa/libipa/camera_sensor_helper.h +++ b/src/ipa/libipa/camera_sensor_helper.h @@ -27,6 +27,7 @@ public: virtual ~CameraSensorHelper() = default; std::optional<int16_t> blackLevel() const { return blackLevel_; } + std::optional<uint32_t> exposureMargin() const { return exposureMargin_; } virtual uint32_t gainCode(double gain) const; virtual double gain(uint32_t gainCode) const; double quantizeGain(double gain, double *quantizationGain) const; @@ -46,6 +47,7 @@ protected: std::optional<int16_t> blackLevel_; std::variant<std::monostate, AnalogueGainLinear, AnalogueGainExp> gain_; + std::optional<uint32_t> exposureMargin_; private: LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorHelper)