[libcamera-devel,v3,08/23] libcamera: camera_sensor: Initialize controls
diff mbox series

Message ID 20220630133902.321099-9-jacopo@jmondi.org
State Not Applicable, archived
Headers show
Series
  • Internal controls, sensor delays and IPA rework
Related show

Commit Message

Jacopo Mondi June 30, 2022, 1:38 p.m. UTC
Initialize the control interface of the CameraSensor class by
registering the control limits for controls::internal::ExposureTime,
controls::internal::FrameDuration and controls::internal::AnalogueGain.

Update the CameraSensor controls in the CameraSensor::updateControlInfo()
function after having updated the subdevice V4L2 controls.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 include/libcamera/internal/camera_sensor.h    |  3 +
 src/libcamera/camera_sensor/camera_sensor.cpp | 90 +++++++++++++++++++
 2 files changed, 93 insertions(+)

Comments

Kieran Bingham June 30, 2022, 10:57 p.m. UTC | #1
Quoting Jacopo Mondi via libcamera-devel (2022-06-30 14:38:47)
> Initialize the control interface of the CameraSensor class by
> registering the control limits for controls::internal::ExposureTime,
> controls::internal::FrameDuration and controls::internal::AnalogueGain.
> 
> Update the CameraSensor controls in the CameraSensor::updateControlInfo()
> function after having updated the subdevice V4L2 controls.
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>  include/libcamera/internal/camera_sensor.h    |  3 +
>  src/libcamera/camera_sensor/camera_sensor.cpp | 90 +++++++++++++++++++
>  2 files changed, 93 insertions(+)
> 
> diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h
> index 2a850dedc0aa..1eab5e9d53f0 100644
> --- a/include/libcamera/internal/camera_sensor.h
> +++ b/include/libcamera/internal/camera_sensor.h
> @@ -63,6 +63,7 @@ public:
>         V4L2Subdevice *device() { return subdev_.get(); }
>  
>         const ControlList &properties() const { return properties_; }
> +       const ControlInfoMap &controls() const { return controls_; }
>         int sensorInfo(IPACameraSensorInfo *info) const;
>  
>         void updateControlInfo();
> @@ -81,6 +82,7 @@ private:
>         void initStaticProperties();
>         void initTestPatternModes();
>         int initProperties();
> +       int updateControls();
>         int applyTestPatternMode(controls::draft::TestPatternModeEnum mode);
>         int discoverAncillaryDevices();
>  
> @@ -104,6 +106,7 @@ private:
>         const BayerFormat *bayerFormat_;
>  
>         ControlList properties_;
> +       ControlInfoMap controls_;
>  
>         std::unique_ptr<CameraLens> focusLens_;
>         std::unique_ptr<CameraSensorHelper> helper_;
> diff --git a/src/libcamera/camera_sensor/camera_sensor.cpp b/src/libcamera/camera_sensor/camera_sensor.cpp
> index 26cfa7d0f65a..976d34aaf876 100644
> --- a/src/libcamera/camera_sensor/camera_sensor.cpp
> +++ b/src/libcamera/camera_sensor/camera_sensor.cpp
> @@ -22,6 +22,7 @@
>  #include "libcamera/internal/bayer_format.h"
>  #include "libcamera/internal/camera_lens.h"
>  #include "libcamera/internal/camera_sensor_properties.h"
> +#include "libcamera/internal/control_ids.h"
>  #include "libcamera/internal/formats.h"
>  #include "libcamera/internal/sysfs.h"
>  
> @@ -180,6 +181,10 @@ int CameraSensor::init()
>                 return -ENODEV;
>         }
>  
> +       ret = updateControls();
> +       if (ret)
> +               return ret;
> +
>         ret = discoverAncillaryDevices();
>         if (ret)
>                 return ret;
> @@ -455,6 +460,84 @@ int CameraSensor::initProperties()
>         return 0;
>  }
>  
> +int CameraSensor::updateControls()
> +{
> +       if (!bayerFormat_)
> +               return 0;
> +
> +       ControlInfoMap::Map controlsMap;
> +
> +       /* The subdev driver has been validate already, the controls are there! */

/validate/validated/

> +       ControlList subdevControls = subdev_->getControls({ V4L2_CID_PIXEL_RATE,
> +                                                           V4L2_CID_HBLANK });
> +       uint64_t pixelRate = subdevControls.get(V4L2_CID_PIXEL_RATE).get<int64_t>();
> +       uint32_t hblank = subdevControls.get(V4L2_CID_HBLANK).get<int32_t>();
> +
> +       /*  Assume the sensor has a single source pad #0. */

/*  Assume/* Assume/
double space can be single.

> +       V4L2SubdeviceFormat subdevFormat;
> +       subdev_->getFormat(0, &subdevFormat);
> +
> +       const ControlInfoMap &subdevControlsInfo = subdev_->controls();
> +
> +       /*
> +        * Compute controls::ExposureTime limits by using line length and pixel
> +        * rate converted to microseconds. Use the V4L2_CID_EXPOSURE control to
> +        * get exposure min, max and default and convert it from lines to
> +        * microseconds.
> +        */
> +       uint32_t lineLength = subdevFormat.size.width + hblank;
> +       double lineDuration = lineLength / (pixelRate / 1000000.0F);
> +       const ControlInfo &v4l2Exposure = subdevControlsInfo.at(V4L2_CID_EXPOSURE);
> +       int32_t minExposure = v4l2Exposure.min().get<int32_t>() * lineDuration;
> +       int32_t maxExposure = v4l2Exposure.max().get<int32_t>() * lineDuration;
> +       int32_t defExposure = v4l2Exposure.def().get<int32_t>() * lineDuration;
> +
> +       controlsMap[&controls::internal::ExposureTime] =
> +               ControlInfo(minExposure, maxExposure, defExposure);
> +
> +       /*
> +        * Compute the frame duration limits.
> +        *
> +        * The frame length is computed assuming a fixed line length combined
> +        * with the vertical frame sizes.
> +        */
> +       const ControlInfo &v4l2VBlank = subdevControlsInfo.at(V4L2_CID_VBLANK);

Does this need to be refreshed from the subdev?

> +       std::array<uint32_t, 3> frameHeights{
> +               v4l2VBlank.min().get<int32_t>() + subdevFormat.size.height,
> +               v4l2VBlank.max().get<int32_t>() + subdevFormat.size.height,
> +               v4l2VBlank.def().get<int32_t>() + subdevFormat.size.height,
> +       };
> +
> +       std::array<int64_t, 3> frameDurations;
> +       for (unsigned int i = 0; i < frameHeights.size(); ++i) {
> +               uint64_t frameSize = lineLength * frameHeights[i];
> +               frameDurations[i] = frameSize / (pixelRate / 1000000.0F);
> +       }
> +
> +       controlsMap[&controls::internal::FrameDuration] =
> +               ControlInfo(frameDurations[0], frameDurations[1], frameDurations[2]);
> +
> +       /*
> +        * Analogue gain values.
> +        *
> +        * Translate the V4L2 analogue gain, expressed in sensor-specific
> +        * gain codes, and translate them to analogue gain values.
> +        *
> +        * \todo: CameraSensorHelper returns a double; there's no ControlValue
> +        * overload for the double type.
> +        */
> +       const ControlInfo &v4l2AGain = subdevControlsInfo.at(V4L2_CID_ANALOGUE_GAIN);
> +       controlsMap[&controls::internal::AnalogueGain] =
> +               ControlInfo(static_cast<float>(helper_->gain(v4l2AGain.min().get<int32_t>())),
> +                           static_cast<float>(helper_->gain(v4l2AGain.max().get<int32_t>())),
> +                           static_cast<float>(helper_->gain(v4l2AGain.def().get<int32_t>())));
> +
> +       controls_ = ControlInfoMap(std::move(controlsMap),
> +                                  controls::internal::controls);
> +
> +       return 0;
> +}
> +
>  /**
>   * \brief Check for and initialise any ancillary devices
>   *
> @@ -815,6 +898,12 @@ int CameraSensor::setV4L2Controls(ControlList *ctrls)
>   * \return The list of camera sensor properties
>   */
>  
> +/**
> + * \fn CameraSensor::controls()
> + * \brief Retrieve the map of the camera sensor controls limits
> + * \return The map of camera sensor control information
> + */
> +
>  /**
>   * \brief Assemble and return the camera sensor info
>   * \param[out] info The camera sensor info
> @@ -910,6 +999,7 @@ int CameraSensor::sensorInfo(IPACameraSensorInfo *info) const
>  void CameraSensor::updateControlInfo()
>  {
>         subdev_->updateControlInfo();
> +       updateControls();

Aha - that answers my vblank question I think...

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

>  }
>  
>  /**
> -- 
> 2.36.1
>

Patch
diff mbox series

diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h
index 2a850dedc0aa..1eab5e9d53f0 100644
--- a/include/libcamera/internal/camera_sensor.h
+++ b/include/libcamera/internal/camera_sensor.h
@@ -63,6 +63,7 @@  public:
 	V4L2Subdevice *device() { return subdev_.get(); }
 
 	const ControlList &properties() const { return properties_; }
+	const ControlInfoMap &controls() const { return controls_; }
 	int sensorInfo(IPACameraSensorInfo *info) const;
 
 	void updateControlInfo();
@@ -81,6 +82,7 @@  private:
 	void initStaticProperties();
 	void initTestPatternModes();
 	int initProperties();
+	int updateControls();
 	int applyTestPatternMode(controls::draft::TestPatternModeEnum mode);
 	int discoverAncillaryDevices();
 
@@ -104,6 +106,7 @@  private:
 	const BayerFormat *bayerFormat_;
 
 	ControlList properties_;
+	ControlInfoMap controls_;
 
 	std::unique_ptr<CameraLens> focusLens_;
 	std::unique_ptr<CameraSensorHelper> helper_;
diff --git a/src/libcamera/camera_sensor/camera_sensor.cpp b/src/libcamera/camera_sensor/camera_sensor.cpp
index 26cfa7d0f65a..976d34aaf876 100644
--- a/src/libcamera/camera_sensor/camera_sensor.cpp
+++ b/src/libcamera/camera_sensor/camera_sensor.cpp
@@ -22,6 +22,7 @@ 
 #include "libcamera/internal/bayer_format.h"
 #include "libcamera/internal/camera_lens.h"
 #include "libcamera/internal/camera_sensor_properties.h"
+#include "libcamera/internal/control_ids.h"
 #include "libcamera/internal/formats.h"
 #include "libcamera/internal/sysfs.h"
 
@@ -180,6 +181,10 @@  int CameraSensor::init()
 		return -ENODEV;
 	}
 
+	ret = updateControls();
+	if (ret)
+		return ret;
+
 	ret = discoverAncillaryDevices();
 	if (ret)
 		return ret;
@@ -455,6 +460,84 @@  int CameraSensor::initProperties()
 	return 0;
 }
 
+int CameraSensor::updateControls()
+{
+	if (!bayerFormat_)
+		return 0;
+
+	ControlInfoMap::Map controlsMap;
+
+	/* The subdev driver has been validate already, the controls are there! */
+	ControlList subdevControls = subdev_->getControls({ V4L2_CID_PIXEL_RATE,
+							    V4L2_CID_HBLANK });
+	uint64_t pixelRate = subdevControls.get(V4L2_CID_PIXEL_RATE).get<int64_t>();
+	uint32_t hblank = subdevControls.get(V4L2_CID_HBLANK).get<int32_t>();
+
+	/*  Assume the sensor has a single source pad #0. */
+	V4L2SubdeviceFormat subdevFormat;
+	subdev_->getFormat(0, &subdevFormat);
+
+	const ControlInfoMap &subdevControlsInfo = subdev_->controls();
+
+	/*
+	 * Compute controls::ExposureTime limits by using line length and pixel
+	 * rate converted to microseconds. Use the V4L2_CID_EXPOSURE control to
+	 * get exposure min, max and default and convert it from lines to
+	 * microseconds.
+	 */
+	uint32_t lineLength = subdevFormat.size.width + hblank;
+	double lineDuration = lineLength / (pixelRate / 1000000.0F);
+	const ControlInfo &v4l2Exposure = subdevControlsInfo.at(V4L2_CID_EXPOSURE);
+	int32_t minExposure = v4l2Exposure.min().get<int32_t>() * lineDuration;
+	int32_t maxExposure = v4l2Exposure.max().get<int32_t>() * lineDuration;
+	int32_t defExposure = v4l2Exposure.def().get<int32_t>() * lineDuration;
+
+	controlsMap[&controls::internal::ExposureTime] =
+		ControlInfo(minExposure, maxExposure, defExposure);
+
+	/*
+	 * Compute the frame duration limits.
+	 *
+	 * The frame length is computed assuming a fixed line length combined
+	 * with the vertical frame sizes.
+	 */
+	const ControlInfo &v4l2VBlank = subdevControlsInfo.at(V4L2_CID_VBLANK);
+	std::array<uint32_t, 3> frameHeights{
+		v4l2VBlank.min().get<int32_t>() + subdevFormat.size.height,
+		v4l2VBlank.max().get<int32_t>() + subdevFormat.size.height,
+		v4l2VBlank.def().get<int32_t>() + subdevFormat.size.height,
+	};
+
+	std::array<int64_t, 3> frameDurations;
+	for (unsigned int i = 0; i < frameHeights.size(); ++i) {
+		uint64_t frameSize = lineLength * frameHeights[i];
+		frameDurations[i] = frameSize / (pixelRate / 1000000.0F);
+	}
+
+	controlsMap[&controls::internal::FrameDuration] =
+		ControlInfo(frameDurations[0], frameDurations[1], frameDurations[2]);
+
+	/*
+	 * Analogue gain values.
+	 *
+	 * Translate the V4L2 analogue gain, expressed in sensor-specific
+	 * gain codes, and translate them to analogue gain values.
+	 *
+	 * \todo: CameraSensorHelper returns a double; there's no ControlValue
+	 * overload for the double type.
+	 */
+	const ControlInfo &v4l2AGain = subdevControlsInfo.at(V4L2_CID_ANALOGUE_GAIN);
+	controlsMap[&controls::internal::AnalogueGain] =
+		ControlInfo(static_cast<float>(helper_->gain(v4l2AGain.min().get<int32_t>())),
+			    static_cast<float>(helper_->gain(v4l2AGain.max().get<int32_t>())),
+			    static_cast<float>(helper_->gain(v4l2AGain.def().get<int32_t>())));
+
+	controls_ = ControlInfoMap(std::move(controlsMap),
+				   controls::internal::controls);
+
+	return 0;
+}
+
 /**
  * \brief Check for and initialise any ancillary devices
  *
@@ -815,6 +898,12 @@  int CameraSensor::setV4L2Controls(ControlList *ctrls)
  * \return The list of camera sensor properties
  */
 
+/**
+ * \fn CameraSensor::controls()
+ * \brief Retrieve the map of the camera sensor controls limits
+ * \return The map of camera sensor control information
+ */
+
 /**
  * \brief Assemble and return the camera sensor info
  * \param[out] info The camera sensor info
@@ -910,6 +999,7 @@  int CameraSensor::sensorInfo(IPACameraSensorInfo *info) const
 void CameraSensor::updateControlInfo()
 {
 	subdev_->updateControlInfo();
+	updateControls();
 }
 
 /**