@@ -34,6 +34,7 @@
#include "libcamera/internal/device_enumerator.h"
#include "libcamera/internal/media_device.h"
#include "libcamera/internal/pipeline_handler.h"
+#include "libcamera/internal/software_isp.h"
#include "libcamera/internal/v4l2_subdevice.h"
#include "libcamera/internal/v4l2_videodevice.h"
@@ -274,6 +275,7 @@ public:
bool useConversion_;
std::unique_ptr<Converter> converter_;
+ std::unique_ptr<SoftwareIsp> swIsp_;
private:
void tryPipeline(unsigned int code, const Size &size);
@@ -281,6 +283,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 +514,25 @@ int SimpleCameraData::init()
}
}
+ /*
+ * Create SoftwareIsp unconditionally if no converter is used
+ * - to be revisited
+ */
+ if (!converter_) {
+ swIsp_ = SoftwareIspFactoryBase::create(pipe, sensor_->controls());
+ if (!swIsp_) {
+ LOG(SimplePipeline, Warning)
+ << "Failed to create software ISP, disabling software debayering";
+ swIsp_.reset();
+ } else {
+ swIsp_->inputBufferReady.connect(this, &SimpleCameraData::conversionInputDone);
+ swIsp_->outputBufferReady.connect(this, &SimpleCameraData::conversionOutputDone);
+ swIsp_->ispStatsReady.connect(this, &SimpleCameraData::ispStatsReady);
+
+ swIsp_->getSignalSetSensorControls().connect(this, &SimpleCameraData::setSensorControls);
+ }
+ }
+
video_ = pipe->video(entities_.back().entity);
ASSERT(video_);
@@ -599,12 +623,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 +777,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 +825,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 +835,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 +865,18 @@ void SimpleCameraData::conversionOutputDone(FrameBuffer *buffer)
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)
{
@@ -1013,8 +1056,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 +1222,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 +1237,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 +1285,18 @@ 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->swIsp_->start();
+ if (ret < 0) {
+ stop(camera);
+ return ret;
+ }
}
/* Queue all internal buffers for capture. */
@@ -1256,8 +1312,13 @@ 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();
+ }
+ }
video->streamOff();
video->releaseBuffers();