[libcamera-devel,v3,10/14] libcamera: pipeline: vimc: Add controls support

Message ID 20190630233817.10130-11-laurent.pinchart@ideasonboard.com
State Superseded
Headers show
Series
  • libcamera Controls
Related show

Commit Message

Laurent Pinchart June 30, 2019, 11:38 p.m. UTC
Implement control support in the VIMC pipeline handler by dynamically
querying the V4L2 device for the supported V4L2 controls and populating
the list of camera controls accordingly.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/libcamera/pipeline/vimc.cpp | 105 ++++++++++++++++++++++++++++++--
 1 file changed, 100 insertions(+), 5 deletions(-)

Comments

Jacopo Mondi July 1, 2019, 5:04 p.m. UTC | #1
Hi Laurent,

On Mon, Jul 01, 2019 at 02:38:13AM +0300, Laurent Pinchart wrote:
> Implement control support in the VIMC pipeline handler by dynamically
> querying the V4L2 device for the supported V4L2 controls and populating
> the list of camera controls accordingly.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Same comments as the UVC pipeline handler.

Thanks
   j

> ---
>  src/libcamera/pipeline/vimc.cpp | 105 ++++++++++++++++++++++++++++++--
>  1 file changed, 100 insertions(+), 5 deletions(-)
>
> diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp
> index 6833213650dc..fb073f2d078e 100644
> --- a/src/libcamera/pipeline/vimc.cpp
> +++ b/src/libcamera/pipeline/vimc.cpp
> @@ -7,19 +7,24 @@
>
>  #include <algorithm>
>  #include <array>
> +#include <iomanip>
> +#include <tuple>
>
>  #include <libcamera/camera.h>
> +#include <libcamera/controls.h>
>  #include <libcamera/ipa/ipa_interface.h>
>  #include <libcamera/ipa/ipa_module_info.h>
>  #include <libcamera/request.h>
>  #include <libcamera/stream.h>
>
> +#include "camera_sensor.h"
>  #include "device_enumerator.h"
>  #include "ipa_manager.h"
>  #include "log.h"
>  #include "media_device.h"
>  #include "pipeline_handler.h"
>  #include "utils.h"
> +#include "v4l2_controls.h"
>  #include "v4l2_videodevice.h"
>
>  namespace libcamera {
> @@ -36,12 +41,15 @@ public:
>
>  	~VimcCameraData()
>  	{
> +		delete sensor_;
>  		delete video_;
>  	}
>
> +	int init(MediaDevice *media);
>  	void bufferReady(Buffer *buffer);
>
>  	V4L2VideoDevice *video_;
> +	CameraSensor *sensor_;
>  	Stream stream_;
>  };
>
> @@ -75,6 +83,8 @@ public:
>  	bool match(DeviceEnumerator *enumerator) override;
>
>  private:
> +	int processControls(VimcCameraData *data, Request *request);
> +
>  	VimcCameraData *cameraData(const Camera *camera)
>  	{
>  		return static_cast<VimcCameraData *>(
> @@ -215,6 +225,45 @@ void PipelineHandlerVimc::stop(Camera *camera)
>  	PipelineHandler::stop(camera);
>  }
>
> +int PipelineHandlerVimc::processControls(VimcCameraData *data, Request *request)
> +{
> +	V4L2ControlList controls;
> +
> +	for (auto it : request->controls()) {
> +		const ControlInfo *ci = it.first;
> +		ControlValue &value = it.second;
> +
> +		switch (ci->id()) {
> +		case Brightness:
> +			controls.add(V4L2_CID_BRIGHTNESS, value.getInt());
> +			break;
> +
> +		case Contrast:
> +			controls.add(V4L2_CID_CONTRAST, value.getInt());
> +			break;
> +
> +		case Saturation:
> +			controls.add(V4L2_CID_SATURATION, value.getInt());
> +			break;
> +
> +		default:
> +			break;
> +		}
> +	}
> +
> +	for (const V4L2Control &ctrl : controls)
> +		LOG(VIMC, Debug)
> +			<< "Setting control 0x"
> +			<< std::hex << std::setw(8) << ctrl.id() << std::dec
> +			<< " to " << ctrl.value();
> +
> +	int ret = data->sensor_->setControls(&controls);
> +	if (ret)
> +		LOG(VIMC, Error) << "Failed to set controls";
> +
> +	return ret;
> +}
> +
>  int PipelineHandlerVimc::queueRequest(Camera *camera, Request *request)
>  {
>  	VimcCameraData *data = cameraData(camera);
> @@ -226,7 +275,11 @@ int PipelineHandlerVimc::queueRequest(Camera *camera, Request *request)
>  		return -ENOENT;
>  	}
>
> -	int ret = data->video_->queueBuffer(buffer);
> +	int ret = processControls(data, request);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = data->video_->queueBuffer(buffer);
>  	if (ret < 0)
>  		return ret;
>
> @@ -262,12 +315,9 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)
>  	std::unique_ptr<VimcCameraData> data = utils::make_unique<VimcCameraData>(this);
>
>  	/* Locate and open the capture video node. */
> -	data->video_ = new V4L2VideoDevice(media->getEntityByName("Raw Capture 1"));
> -	if (data->video_->open())
> +	if (data->init(media))
>  		return false;
>
> -	data->video_->bufferReady.connect(data.get(), &VimcCameraData::bufferReady);
> -
>  	/* Create and register the camera. */
>  	std::set<Stream *> streams{ &data->stream_ };
>  	std::shared_ptr<Camera> camera = Camera::create(this, "VIMC Sensor B",
> @@ -277,6 +327,51 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)
>  	return true;
>  }
>
> +int VimcCameraData::init(MediaDevice *media)
> +{
> +	int ret;
> +
> +	/* Create and open the video device and the camera sensor. */
> +	video_ = new V4L2VideoDevice(media->getEntityByName("Raw Capture 1"));
> +	if (video_->open())
> +		return -ENODEV;
> +
> +	video_->bufferReady.connect(this, &VimcCameraData::bufferReady);
> +
> +	sensor_ = new CameraSensor(media->getEntityByName("Sensor B"));
> +	ret = sensor_->init();
> +	if (ret)
> +		return ret;
> +
> +	/* Initialise the supported controls. */
> +	const V4L2ControlInfoMap &controls = sensor_->controls();
> +	for (const auto &ctrl : controls) {
> +		unsigned int v4l2Id = ctrl.first;
> +		const V4L2ControlInfo &info = ctrl.second;
> +		ControlId id;
> +
> +		switch (v4l2Id) {
> +		case V4L2_CID_BRIGHTNESS:
> +			id = Brightness;
> +			break;
> +		case V4L2_CID_CONTRAST:
> +			id = Contrast;
> +			break;
> +		case V4L2_CID_SATURATION:
> +			id = Saturation;
> +			break;
> +		default:
> +			continue;
> +		}
> +
> +		controlInfo_.emplace(std::piecewise_construct,
> +				     std::forward_as_tuple(id),
> +				     std::forward_as_tuple(id, info.min(), info.max()));
> +	}
> +
> +	return 0;
> +}
> +
>  void VimcCameraData::bufferReady(Buffer *buffer)
>  {
>  	Request *request = queuedRequests_.front();
> --
> Regards,
>
> Laurent Pinchart
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel

Patch

diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp
index 6833213650dc..fb073f2d078e 100644
--- a/src/libcamera/pipeline/vimc.cpp
+++ b/src/libcamera/pipeline/vimc.cpp
@@ -7,19 +7,24 @@ 
 
 #include <algorithm>
 #include <array>
+#include <iomanip>
+#include <tuple>
 
 #include <libcamera/camera.h>
+#include <libcamera/controls.h>
 #include <libcamera/ipa/ipa_interface.h>
 #include <libcamera/ipa/ipa_module_info.h>
 #include <libcamera/request.h>
 #include <libcamera/stream.h>
 
+#include "camera_sensor.h"
 #include "device_enumerator.h"
 #include "ipa_manager.h"
 #include "log.h"
 #include "media_device.h"
 #include "pipeline_handler.h"
 #include "utils.h"
+#include "v4l2_controls.h"
 #include "v4l2_videodevice.h"
 
 namespace libcamera {
@@ -36,12 +41,15 @@  public:
 
 	~VimcCameraData()
 	{
+		delete sensor_;
 		delete video_;
 	}
 
+	int init(MediaDevice *media);
 	void bufferReady(Buffer *buffer);
 
 	V4L2VideoDevice *video_;
+	CameraSensor *sensor_;
 	Stream stream_;
 };
 
@@ -75,6 +83,8 @@  public:
 	bool match(DeviceEnumerator *enumerator) override;
 
 private:
+	int processControls(VimcCameraData *data, Request *request);
+
 	VimcCameraData *cameraData(const Camera *camera)
 	{
 		return static_cast<VimcCameraData *>(
@@ -215,6 +225,45 @@  void PipelineHandlerVimc::stop(Camera *camera)
 	PipelineHandler::stop(camera);
 }
 
+int PipelineHandlerVimc::processControls(VimcCameraData *data, Request *request)
+{
+	V4L2ControlList controls;
+
+	for (auto it : request->controls()) {
+		const ControlInfo *ci = it.first;
+		ControlValue &value = it.second;
+
+		switch (ci->id()) {
+		case Brightness:
+			controls.add(V4L2_CID_BRIGHTNESS, value.getInt());
+			break;
+
+		case Contrast:
+			controls.add(V4L2_CID_CONTRAST, value.getInt());
+			break;
+
+		case Saturation:
+			controls.add(V4L2_CID_SATURATION, value.getInt());
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	for (const V4L2Control &ctrl : controls)
+		LOG(VIMC, Debug)
+			<< "Setting control 0x"
+			<< std::hex << std::setw(8) << ctrl.id() << std::dec
+			<< " to " << ctrl.value();
+
+	int ret = data->sensor_->setControls(&controls);
+	if (ret)
+		LOG(VIMC, Error) << "Failed to set controls";
+
+	return ret;
+}
+
 int PipelineHandlerVimc::queueRequest(Camera *camera, Request *request)
 {
 	VimcCameraData *data = cameraData(camera);
@@ -226,7 +275,11 @@  int PipelineHandlerVimc::queueRequest(Camera *camera, Request *request)
 		return -ENOENT;
 	}
 
-	int ret = data->video_->queueBuffer(buffer);
+	int ret = processControls(data, request);
+	if (ret < 0)
+		return ret;
+
+	ret = data->video_->queueBuffer(buffer);
 	if (ret < 0)
 		return ret;
 
@@ -262,12 +315,9 @@  bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)
 	std::unique_ptr<VimcCameraData> data = utils::make_unique<VimcCameraData>(this);
 
 	/* Locate and open the capture video node. */
-	data->video_ = new V4L2VideoDevice(media->getEntityByName("Raw Capture 1"));
-	if (data->video_->open())
+	if (data->init(media))
 		return false;
 
-	data->video_->bufferReady.connect(data.get(), &VimcCameraData::bufferReady);
-
 	/* Create and register the camera. */
 	std::set<Stream *> streams{ &data->stream_ };
 	std::shared_ptr<Camera> camera = Camera::create(this, "VIMC Sensor B",
@@ -277,6 +327,51 @@  bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)
 	return true;
 }
 
+int VimcCameraData::init(MediaDevice *media)
+{
+	int ret;
+
+	/* Create and open the video device and the camera sensor. */
+	video_ = new V4L2VideoDevice(media->getEntityByName("Raw Capture 1"));
+	if (video_->open())
+		return -ENODEV;
+
+	video_->bufferReady.connect(this, &VimcCameraData::bufferReady);
+
+	sensor_ = new CameraSensor(media->getEntityByName("Sensor B"));
+	ret = sensor_->init();
+	if (ret)
+		return ret;
+
+	/* Initialise the supported controls. */
+	const V4L2ControlInfoMap &controls = sensor_->controls();
+	for (const auto &ctrl : controls) {
+		unsigned int v4l2Id = ctrl.first;
+		const V4L2ControlInfo &info = ctrl.second;
+		ControlId id;
+
+		switch (v4l2Id) {
+		case V4L2_CID_BRIGHTNESS:
+			id = Brightness;
+			break;
+		case V4L2_CID_CONTRAST:
+			id = Contrast;
+			break;
+		case V4L2_CID_SATURATION:
+			id = Saturation;
+			break;
+		default:
+			continue;
+		}
+
+		controlInfo_.emplace(std::piecewise_construct,
+				     std::forward_as_tuple(id),
+				     std::forward_as_tuple(id, info.min(), info.max()));
+	}
+
+	return 0;
+}
+
 void VimcCameraData::bufferReady(Buffer *buffer)
 {
 	Request *request = queuedRequests_.front();