2024-03-17 15:11:22 +01:00
|
|
|
From d64b0fca22ef25b8a14d7fc97dfab64eb1c4f21a Mon Sep 17 00:00:00 2001
|
2024-01-30 10:43:15 +01:00
|
|
|
From: Andrey Konovalov <andrey.konovalov@linaro.org>
|
2024-03-17 15:11:22 +01:00
|
|
|
Date: Mon, 11 Mar 2024 15:15:16 +0100
|
|
|
|
Subject: [PATCH 12/21] libcamera: pipeline: simple: enable use of Soft ISP and
|
2024-01-30 10:43:15 +01:00
|
|
|
Soft IPA
|
|
|
|
|
|
|
|
To enable the Simple Soft ISP and Soft IPA for simple pipeline handler
|
|
|
|
configure the build with:
|
2024-03-17 15:11:22 +01:00
|
|
|
-Dpipelines=simple -Dipas=simple
|
|
|
|
|
|
|
|
Also using the Soft ISP for the particular hardware platform must
|
|
|
|
be enabled in the supportedDevices[] table.
|
2024-01-30 10:43:15 +01:00
|
|
|
|
|
|
|
If the pipeline uses Converter, Soft ISP and Soft IPA aren't
|
|
|
|
available.
|
|
|
|
|
|
|
|
Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> # sc8280xp Lenovo x13s
|
|
|
|
Tested-by: Pavel Machek <pavel@ucw.cz>
|
2024-03-17 15:11:22 +01:00
|
|
|
Reviewed-by: Pavel Machek <pavel@ucw.cz>
|
|
|
|
Signed-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>
|
|
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
2024-01-30 10:43:15 +01:00
|
|
|
---
|
2024-03-17 15:11:22 +01:00
|
|
|
src/libcamera/pipeline/simple/simple.cpp | 137 ++++++++++++++++++-----
|
|
|
|
1 file changed, 109 insertions(+), 28 deletions(-)
|
2024-01-30 10:43:15 +01:00
|
|
|
|
|
|
|
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
|
2024-03-17 15:11:22 +01:00
|
|
|
index 78854ef8..c3ebb7b7 100644
|
2024-01-30 10:43:15 +01:00
|
|
|
--- a/src/libcamera/pipeline/simple/simple.cpp
|
|
|
|
+++ b/src/libcamera/pipeline/simple/simple.cpp
|
|
|
|
@@ -34,6 +34,7 @@
|
|
|
|
#include "libcamera/internal/device_enumerator.h"
|
|
|
|
#include "libcamera/internal/media_device.h"
|
|
|
|
#include "libcamera/internal/pipeline_handler.h"
|
2024-03-17 15:11:22 +01:00
|
|
|
+#include "libcamera/internal/software_isp/software_isp.h"
|
2024-01-30 10:43:15 +01:00
|
|
|
#include "libcamera/internal/v4l2_subdevice.h"
|
|
|
|
#include "libcamera/internal/v4l2_videodevice.h"
|
|
|
|
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -185,17 +186,22 @@ struct SimplePipelineInfo {
|
|
|
|
* and the number of streams it supports.
|
|
|
|
*/
|
|
|
|
std::vector<std::pair<const char *, unsigned int>> converters;
|
|
|
|
+ /*
|
|
|
|
+ * Using Software ISP is to be enabled per driver.
|
|
|
|
+ * The Software ISP can't be used together with the converters.
|
|
|
|
+ */
|
|
|
|
+ bool swIspEnabled;
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
static const SimplePipelineInfo supportedDevices[] = {
|
|
|
|
- { "dcmipp", {} },
|
|
|
|
- { "imx7-csi", { { "pxp", 1 } } },
|
|
|
|
- { "j721e-csi2rx", {} },
|
|
|
|
- { "mxc-isi", {} },
|
|
|
|
- { "qcom-camss", {} },
|
|
|
|
- { "sun6i-csi", {} },
|
|
|
|
+ { "dcmipp", {}, false },
|
|
|
|
+ { "imx7-csi", { { "pxp", 1 } }, false },
|
|
|
|
+ { "j721e-csi2rx", {}, false },
|
|
|
|
+ { "mxc-isi", {}, false },
|
|
|
|
+ { "qcom-camss", {}, true },
|
|
|
|
+ { "sun6i-csi", {}, false },
|
|
|
|
};
|
|
|
|
|
|
|
|
} /* namespace */
|
|
|
|
@@ -274,6 +280,7 @@ public:
|
2024-01-30 10:43:15 +01:00
|
|
|
bool useConversion_;
|
|
|
|
|
|
|
|
std::unique_ptr<Converter> converter_;
|
|
|
|
+ std::unique_ptr<SoftwareIsp> swIsp_;
|
|
|
|
|
|
|
|
private:
|
|
|
|
void tryPipeline(unsigned int code, const Size &size);
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -281,6 +288,9 @@ private:
|
2024-01-30 10:43:15 +01:00
|
|
|
|
|
|
|
void conversionInputDone(FrameBuffer *buffer);
|
|
|
|
void conversionOutputDone(FrameBuffer *buffer);
|
|
|
|
+
|
|
|
|
+ void ispStatsReady(int dummy);
|
|
|
|
+ void setSensorControls(const ControlList &sensorControls);
|
|
|
|
};
|
|
|
|
|
|
|
|
class SimpleCameraConfiguration : public CameraConfiguration
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -332,6 +342,7 @@ public:
|
|
|
|
V4L2VideoDevice *video(const MediaEntity *entity);
|
|
|
|
V4L2Subdevice *subdev(const MediaEntity *entity);
|
|
|
|
MediaDevice *converter() { return converter_; }
|
|
|
|
+ bool swIspEnabled() { return swIspEnabled_; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
int queueRequestDevice(Camera *camera, Request *request) override;
|
|
|
|
@@ -360,6 +371,7 @@ private:
|
|
|
|
std::map<const MediaEntity *, EntityData> entities_;
|
|
|
|
|
|
|
|
MediaDevice *converter_;
|
|
|
|
+ bool swIspEnabled_;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
|
|
@@ -509,6 +521,29 @@ int SimpleCameraData::init()
|
2024-01-30 10:43:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
+ /*
|
2024-03-17 15:11:22 +01:00
|
|
|
+ * Instantiate Soft ISP if this is enabled for the given driver and no converter is used.
|
2024-01-30 10:43:15 +01:00
|
|
|
+ */
|
2024-03-17 15:11:22 +01:00
|
|
|
+ if (!converter_ && pipe->swIspEnabled()) {
|
|
|
|
+ swIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_->controls());
|
|
|
|
+ if (!swIsp_->isValid()) {
|
2024-01-30 10:43:15 +01:00
|
|
|
+ LOG(SimplePipeline, Warning)
|
|
|
|
+ << "Failed to create software ISP, disabling software debayering";
|
|
|
|
+ swIsp_.reset();
|
|
|
|
+ } else {
|
2024-03-17 15:11:22 +01:00
|
|
|
+ /*
|
|
|
|
+ * \todo explain why SimpleCameraData::conversionInputDone() can't be directly
|
|
|
|
+ * connected to inputBufferReady signal.
|
|
|
|
+ */
|
|
|
|
+ swIsp_->inputBufferReady.connect(pipe, [this](FrameBuffer *buffer) {
|
|
|
|
+ this->conversionInputDone(buffer);
|
|
|
|
+ });
|
2024-01-30 10:43:15 +01:00
|
|
|
+ swIsp_->outputBufferReady.connect(this, &SimpleCameraData::conversionOutputDone);
|
|
|
|
+ swIsp_->ispStatsReady.connect(this, &SimpleCameraData::ispStatsReady);
|
2024-03-17 15:11:22 +01:00
|
|
|
+ swIsp_->setSensorControls.connect(this, &SimpleCameraData::setSensorControls);
|
2024-01-30 10:43:15 +01:00
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
video_ = pipe->video(entities_.back().entity);
|
|
|
|
ASSERT(video_);
|
|
|
|
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -599,12 +634,21 @@ void SimpleCameraData::tryPipeline(unsigned int code, const Size &size)
|
2024-01-30 10:43:15 +01:00
|
|
|
config.captureFormat = pixelFormat;
|
|
|
|
config.captureSize = format.size;
|
|
|
|
|
|
|
|
- if (!converter_) {
|
2024-03-17 15:11:22 +01:00
|
|
|
+
|
2024-01-30 10:43:15 +01:00
|
|
|
+ if (converter_) {
|
2024-03-17 15:11:22 +01:00
|
|
|
+ config.outputFormats = converter_->formats(pixelFormat);
|
|
|
|
+ config.outputSizes = converter_->sizes(format.size);
|
2024-01-30 10:43:15 +01:00
|
|
|
+ } else if (swIsp_) {
|
|
|
|
+ config.outputFormats = swIsp_->formats(pixelFormat);
|
|
|
|
+ config.outputSizes = swIsp_->sizes(pixelFormat, format.size);
|
|
|
|
+ if (config.outputFormats.empty()) {
|
2024-03-17 15:11:22 +01:00
|
|
|
+ /* Do not use swIsp for unsupported pixelFormat's: */
|
2024-01-30 10:43:15 +01:00
|
|
|
+ config.outputFormats = { pixelFormat };
|
|
|
|
+ config.outputSizes = config.captureSize;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
2024-03-17 15:11:22 +01:00
|
|
|
config.outputFormats = { pixelFormat };
|
|
|
|
config.outputSizes = config.captureSize;
|
|
|
|
- } else {
|
|
|
|
- config.outputFormats = converter_->formats(pixelFormat);
|
|
|
|
- config.outputSizes = converter_->sizes(format.size);
|
2024-01-30 10:43:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
configs_.push_back(config);
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -750,9 +794,9 @@ void SimpleCameraData::bufferReady(FrameBuffer *buffer)
|
2024-01-30 10:43:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
- * 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);
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -798,9 +842,9 @@ void SimpleCameraData::bufferReady(FrameBuffer *buffer)
|
2024-01-30 10:43:15 +01:00
|
|
|
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()) {
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -808,7 +852,11 @@ void SimpleCameraData::bufferReady(FrameBuffer *buffer)
|
2024-01-30 10:43:15 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
- converter_->queueBuffers(buffer, conversionQueue_.front());
|
|
|
|
+ if (converter_)
|
|
|
|
+ converter_->queueBuffers(buffer, conversionQueue_.front());
|
|
|
|
+ else
|
|
|
|
+ swIsp_->queueBuffers(buffer, conversionQueue_.front());
|
|
|
|
+
|
|
|
|
conversionQueue_.pop();
|
|
|
|
return;
|
|
|
|
}
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -834,6 +882,18 @@ void SimpleCameraData::conversionOutputDone(FrameBuffer *buffer)
|
2024-01-30 10:43:15 +01:00
|
|
|
pipe->completeRequest(request);
|
|
|
|
}
|
|
|
|
|
|
|
|
+void SimpleCameraData::ispStatsReady([[maybe_unused]] int dummy)
|
|
|
|
+{
|
|
|
|
+ swIsp_->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)
|
|
|
|
{
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -1046,8 +1106,10 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()
|
2024-01-30 10:43:15 +01:00
|
|
|
/* 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 {
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -1210,7 +1272,9 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
|
2024-01-30 10:43:15 +01:00
|
|
|
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,
|
|
|
|
+ data->sensor_->controls());
|
|
|
|
}
|
|
|
|
|
|
|
|
int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream,
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -1224,8 +1288,10 @@ int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream,
|
2024-01-30 10:43:15 +01:00
|
|
|
* 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);
|
|
|
|
}
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -1270,10 +1336,18 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL
|
2024-01-30 10:43:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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->swIsp_->start();
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ stop(camera);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Queue all internal buffers for capture. */
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -1289,8 +1363,13 @@ void SimplePipelineHandler::stopDevice(Camera *camera)
|
2024-01-30 10:43:15 +01:00
|
|
|
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();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
|
|
video->streamOff();
|
|
|
|
video->releaseBuffers();
|
2024-03-17 15:11:22 +01:00
|
|
|
@@ -1452,6 +1531,8 @@ bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
+ swIspEnabled_ = info->swIspEnabled;
|
|
|
|
+
|
|
|
|
/* Locate the sensors. */
|
|
|
|
std::vector<MediaEntity *> sensors = locateSensors();
|
|
|
|
if (sensors.empty()) {
|
2024-01-30 10:43:15 +01:00
|
|
|
--
|
2024-03-17 15:11:22 +01:00
|
|
|
2.43.2
|
2024-01-30 10:43:15 +01:00
|
|
|
|