[libcamera-devel,RFC,7/7,DNI] libcamera: pipeline: simple: enable use of SoftwareISP and Soft IPA
diff mbox series

Message ID 20231204001013.404720-8-andrey.konovalov@linaro.org
State Superseded
Headers show
Series
  • libcamera: introduce Software ISP and Software IPA
Related show

Commit Message

Andrey Konovalov Dec. 4, 2023, 12:10 a.m. UTC
Some quick changes to make SoftwareISP and Soft IPA usable
in the cases when the pipeline doesn't use Converter.

Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>
---
 src/libcamera/pipeline/simple/simple.cpp | 134 +++++++++++++++++++----
 1 file changed, 111 insertions(+), 23 deletions(-)

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 878794f6..8c119a98 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -25,6 +25,8 @@ 
 
 #include <libcamera/camera.h>
 #include <libcamera/control_ids.h>
+#include <libcamera/ipa/soft_ipa_interface.h>
+#include <libcamera/ipa/soft_ipa_proxy.h>
 #include <libcamera/request.h>
 #include <libcamera/stream.h>
 
@@ -32,12 +34,14 @@ 
 #include "libcamera/internal/camera_sensor.h"
 #include "libcamera/internal/converter.h"
 #include "libcamera/internal/device_enumerator.h"
+#include "libcamera/internal/ipa_manager.h"
 #include "libcamera/internal/media_device.h"
 #include "libcamera/internal/pipeline_handler.h"
+#include "libcamera/internal/software_isp.h"
+#include "libcamera/internal/software_isp/swisp_linaro.h"
 #include "libcamera/internal/v4l2_subdevice.h"
 #include "libcamera/internal/v4l2_videodevice.h"
 
-
 namespace libcamera {
 
 LOG_DEFINE_CATEGORY(SimplePipeline)
@@ -274,6 +278,8 @@  public:
 	bool useConversion_;
 
 	std::unique_ptr<Converter> converter_;
+	std::unique_ptr<SoftwareIsp> swIsp_;
+	std::unique_ptr<ipa::soft::IPAProxySoft> ipa_;
 
 private:
 	void tryPipeline(unsigned int code, const Size &size);
@@ -281,6 +287,9 @@  private:
 
 	void conversionInputDone(FrameBuffer *buffer);
 	void conversionOutputDone(FrameBuffer *buffer);
+
+	void ispStatsReady(int dummy);
+	void setSensorControls(const ControlList &sensorControls);
 };
 
 class SimpleCameraConfiguration : public CameraConfiguration
@@ -509,6 +518,38 @@  int SimpleCameraData::init()
 		}
 	}
 
+	/*
+	 * Create Linaro's implementation of SoftwareIsp unconditionally if no converter is used
+	 * - to be revisited
+	 */
+	if (!converter_) {
+		swIsp_ = std::make_unique<SwIspLinaro>("linaro");
+		if (!swIsp_) {
+			LOG(SimplePipeline, Warning)
+				<< "Failed to create software ISP, disabling software debayering";
+			swIsp_.reset();
+		}
+		swIsp_->inputBufferReady.connect(this, &SimpleCameraData::conversionInputDone);
+		swIsp_->outputBufferReady.connect(this, &SimpleCameraData::conversionOutputDone);
+		swIsp_->ispStatsReady.connect(this, &SimpleCameraData::ispStatsReady);
+
+		/* Create Linaro's IPA for the SoftwareIsp - to be revisited */
+		ipa_ = IPAManager::createIPA<ipa::soft::IPAProxySoft>(pipe, 0, 0);
+		if (!ipa_) {
+			LOG(SimplePipeline, Warning) << "Creating IPA for software ISP failed";
+			return -ENOENT;
+		}
+		ret = ipa_->init(IPASettings{ "No cfg file", "No sensor model" },
+				 swIsp_->getStatsFD(),
+				 sensor_->controls());
+		if (ret) {
+			LOG(SimplePipeline, Warning) << "IPA init failed";
+			return ret;
+		}
+		ipa_->setSensorControls.connect(this, &SimpleCameraData::setSensorControls);
+		ipa_->configure(sensor_->controls());
+	}
+
 	video_ = pipe->video(entities_.back().entity);
 	ASSERT(video_);
 
@@ -599,12 +640,15 @@  void SimpleCameraData::tryPipeline(unsigned int code, const Size &size)
 		config.captureFormat = pixelFormat;
 		config.captureSize = format.size;
 
-		if (!converter_) {
-			config.outputFormats = { pixelFormat };
-			config.outputSizes = config.captureSize;
-		} else {
+		if (converter_) {
 			config.outputFormats = converter_->formats(pixelFormat);
 			config.outputSizes = converter_->sizes(format.size);
+		} else if (swIsp_) {
+			config.outputFormats = swIsp_->formats(pixelFormat);
+			config.outputSizes = swIsp_->sizes(pixelFormat, format.size);
+		} else {
+			config.outputFormats = { pixelFormat };
+			config.outputSizes = config.captureSize;
 		}
 
 		configs_.push_back(config);
@@ -750,9 +794,9 @@  void SimpleCameraData::bufferReady(FrameBuffer *buffer)
 		}
 
 		/*
-		 * The converter is in use. Requeue the internal buffer for
-		 * capture (unless the stream is being stopped), and complete
-		 * the request with all the user-facing buffers.
+		 * The converter or Software ISP is in use. Requeue the internal
+		 * buffer for capture (unless the stream is being stopped), and
+		 * complete the request with all the user-facing buffers.
 		 */
 		if (buffer->metadata().status != FrameMetadata::FrameCancelled)
 			video_->queueBuffer(buffer);
@@ -798,9 +842,9 @@  void SimpleCameraData::bufferReady(FrameBuffer *buffer)
 					buffer->metadata().timestamp);
 
 	/*
-	 * Queue the captured and the request buffer to the converter if format
-	 * conversion is needed. If there's no queued request, just requeue the
-	 * captured buffer for capture.
+	 * Queue the captured and the request buffer to the converter or Software
+	 * ISP if format conversion is needed. If there's no queued request, just
+	 * requeue the captured buffer for capture.
 	 */
 	if (useConversion_) {
 		if (conversionQueue_.empty()) {
@@ -808,7 +852,11 @@  void SimpleCameraData::bufferReady(FrameBuffer *buffer)
 			return;
 		}
 
-		converter_->queueBuffers(buffer, conversionQueue_.front());
+		if (converter_)
+			converter_->queueBuffers(buffer, conversionQueue_.front());
+		else
+			swIsp_->queueBuffers(buffer, conversionQueue_.front());
+
 		conversionQueue_.pop();
 		return;
 	}
@@ -834,6 +882,21 @@  void SimpleCameraData::conversionOutputDone(FrameBuffer *buffer)
 		pipe->completeRequest(request);
 }
 
+void SimpleCameraData::ispStatsReady([[maybe_unused]] int dummy)
+{
+	if (!ipa_)
+		return;
+
+	ipa_->processStats(sensor_->getControls({ V4L2_CID_ANALOGUE_GAIN,
+						  V4L2_CID_EXPOSURE }));
+}
+
+void SimpleCameraData::setSensorControls(const ControlList &sensorControls)
+{
+	ControlList ctrls(sensorControls);
+	sensor_->setControls(&ctrls);
+}
+
 /* Retrieve all source pads connected to a sink pad through active routes. */
 std::vector<const MediaPad *> SimpleCameraData::routedSourcePads(MediaPad *sink)
 {
@@ -1013,8 +1076,10 @@  CameraConfiguration::Status SimpleCameraConfiguration::validate()
 		/* Set the stride, frameSize and bufferCount. */
 		if (needConversion_) {
 			std::tie(cfg.stride, cfg.frameSize) =
-				data_->converter_->strideAndFrameSize(cfg.pixelFormat,
-								      cfg.size);
+				(data_->converter_) ? data_->converter_->strideAndFrameSize(cfg.pixelFormat,
+											    cfg.size)
+						    : data_->swIsp_->strideAndFrameSize(cfg.pixelFormat,
+											cfg.size);
 			if (cfg.stride == 0)
 				return Invalid;
 		} else {
@@ -1177,7 +1242,8 @@  int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
 	inputCfg.stride = captureFormat.planes[0].bpl;
 	inputCfg.bufferCount = kNumInternalBuffers;
 
-	return data->converter_->configure(inputCfg, outputCfgs);
+	return (data->converter_) ? data->converter_->configure(inputCfg, outputCfgs)
+				  : data->swIsp_->configure(inputCfg, outputCfgs);
 }
 
 int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream,
@@ -1191,8 +1257,10 @@  int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream,
 	 * whether the converter is used or not.
 	 */
 	if (data->useConversion_)
-		return data->converter_->exportBuffers(data->streamIndex(stream),
-						       count, buffers);
+		return (data->converter_) ? data->converter_->exportBuffers(data->streamIndex(stream),
+									    count, buffers)
+					  : data->swIsp_->exportBuffers(data->streamIndex(stream),
+									count, buffers);
 	else
 		return data->video_->exportBuffers(count, buffers);
 }
@@ -1237,10 +1305,24 @@  int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL
 	}
 
 	if (data->useConversion_) {
-		ret = data->converter_->start();
-		if (ret < 0) {
-			stop(camera);
-			return ret;
+		if (data->converter_) {
+			ret = data->converter_->start();
+			if (ret < 0) {
+				stop(camera);
+				return ret;
+			}
+		} else if (data->swIsp_) {
+			ret = data->ipa_->start();
+			if (ret < 0) {
+				stop(camera);
+				return ret;
+			}
+			ret = data->swIsp_->start();
+			if (ret < 0) {
+				data->ipa_->stop();
+				stop(camera);
+				return ret;
+			}
 		}
 
 		/* Queue all internal buffers for capture. */
@@ -1256,8 +1338,14 @@  void SimplePipelineHandler::stopDevice(Camera *camera)
 	SimpleCameraData *data = cameraData(camera);
 	V4L2VideoDevice *video = data->video_;
 
-	if (data->useConversion_)
-		data->converter_->stop();
+	if (data->useConversion_) {
+		if (data->converter_)
+			data->converter_->stop();
+		else if (data->swIsp_) {
+			data->swIsp_->stop();
+			data->ipa_->stop();
+		}
+	}
 
 	video->streamOff();
 	video->releaseBuffers();