@@ -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();
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(-)