@@ -46,6 +46,7 @@ file structure:
supported_devices:
- driver: # driver name, e.g. `mxc-isi`
software_isp: # true/false
+ enable_raw_ipa: # true/false
software_isp:
copy_input_buffer: # true/false
measure:
@@ -81,6 +82,7 @@ Configuration file example
supported_devices:
- driver: mxc-isi
software_isp: true
+ enable_raw_ipa: true
software_isp:
copy_input_buffer: false
measure:
@@ -157,6 +159,14 @@ pipelines.simple.supported_devices.driver, pipelines.simple.supported_devices.so
Example `software_isp` value: ``true``
+pipelines.simple.enable_raw_ipa
+ Whether image processing algorithms are enabled also with raw-only
+ output. When enabled, statistics is gathered for raw-only output,
+ image processing algorithms are run on it, metadata is produced and
+ exposure is adjusted.
+
+ Example value: ``true``
+
software_isp.copy_input_buffer
Define whether input buffers should be copied into standard (cached)
memory in software ISP. This is done by default to prevent very slow
@@ -67,7 +67,8 @@ public:
int configure(const StreamConfiguration &inputCfg,
const std::vector<std::reference_wrapper<const StreamConfiguration>> &outputCfgs,
const ipa::softisp::IPAConfigInfo &configInfo,
- ControlInfoMap *ipaControls);
+ ControlInfoMap *ipaControls,
+ bool debayerEnabled);
int exportBuffers(const Stream *stream, unsigned int count,
std::vector<std::unique_ptr<FrameBuffer>> *buffers);
@@ -427,6 +427,7 @@ public:
V4L2Subdevice *subdev(const MediaEntity *entity);
std::shared_ptr<MediaDevice> converter() { return converter_; }
bool swIspEnabled() const { return swIspEnabled_; }
+ bool rawIpaEnabled() const { return rawIpaEnabled_; }
protected:
int queueRequestDevice(Camera *camera, Request *request) override;
@@ -460,6 +461,7 @@ private:
std::shared_ptr<MediaDevice> converter_;
bool swIspEnabled_;
+ bool rawIpaEnabled_ = true;
};
/* -----------------------------------------------------------------------------
@@ -968,6 +970,11 @@ void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)
conversionQueue_.pop();
return;
+ } else if (pipe->rawIpaEnabled()) {
+ /* \todo Make the processing asynchronous? */
+ swIsp_->process(request->sequence(), buffer, nullptr);
+ pipe->completeBuffer(request, buffer);
+ return;
}
/* Otherwise simply complete the request. */
@@ -1591,7 +1598,8 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
data->rawStream_ = &data->streams_[i];
}
- if (outputCfgs.empty())
+ if (outputCfgs.empty() &&
+ (data->converter_ || !data->rawStream_ || !rawIpaEnabled_))
return 0;
StreamConfiguration inputCfg;
@@ -1605,7 +1613,12 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
} else {
ipa::softisp::IPAConfigInfo configInfo;
configInfo.sensorControls = data->sensor_->controls();
- return data->swIsp_->configure(inputCfg, outputCfgs, configInfo, &data->controlInfo_);
+ return data->swIsp_->configure(
+ inputCfg,
+ outputCfgs,
+ configInfo,
+ &data->controlInfo_,
+ data->useConversion_);
}
}
@@ -1698,6 +1711,12 @@ int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL
if (!data->rawStream_)
for (std::unique_ptr<FrameBuffer> &buffer : data->conversionBuffers_)
video->queueBuffer(buffer.get());
+ } else if (data->swIsp_) {
+ ret = data->swIsp_->startIpa();
+ if (ret < 0) {
+ stop(camera);
+ return ret;
+ }
}
return 0;
@@ -1720,6 +1739,8 @@ void SimplePipelineHandler::stopDevice(Camera *camera)
data->converter_->stop();
else if (data->swIsp_)
data->swIsp_->stop();
+ } else if (data->swIsp_) {
+ data->swIsp_->stopIpa();
}
video->streamOff();
@@ -1763,6 +1784,8 @@ int SimplePipelineHandler::queueRequestDevice(Camera *camera, Request *request)
data->conversionQueue_.push({ request, std::move(buffers) });
if (data->swIsp_)
data->swIsp_->queueRequest(request->sequence(), request->controls());
+ } else if (data->swIsp_ && rawIpaEnabled_) {
+ data->swIsp_->queueRequest(request->sequence(), request->controls());
}
return 0;
@@ -1882,9 +1905,8 @@ bool SimplePipelineHandler::matchDevice(std::shared_ptr<MediaDevice> media,
swIspEnabled_ = info.swIspEnabled;
const GlobalConfiguration &configuration = cameraManager()->_d()->configuration();
- for (const ValueNode &entry :
- configuration.configuration()["pipelines"]["simple"]["supported_devices"]
- .asList()) {
+ auto &simpleConfiguration = configuration.configuration()["pipelines"]["simple"];
+ for (const ValueNode &entry : simpleConfiguration["supported_devices"].asList()) {
auto name = entry["driver"].get<std::string>();
if (name == info.driver) {
swIspEnabled_ = entry["software_isp"].get<bool>().value_or(swIspEnabled_);
@@ -1903,6 +1925,10 @@ bool SimplePipelineHandler::matchDevice(std::shared_ptr<MediaDevice> media,
*/
ASSERT(!converter_);
numStreams = 2;
+
+ auto enableRawIpa = simpleConfiguration["enable_raw_ipa"].get<bool>();
+ if (enableRawIpa)
+ rawIpaEnabled_ = enableRawIpa.value();
}
/* Locate the sensors. */
@@ -25,6 +25,7 @@
#include "libcamera/internal/bayer_format.h"
#include "libcamera/internal/framebuffer.h"
+#include "libcamera/internal/mapped_framebuffer.h"
#include "libcamera/internal/software_isp/debayer_params.h"
#include "debayer_cpu.h"
@@ -280,19 +281,34 @@ uint32_t SoftwareIsp::preferredInputStride(const PixelFormat &inputFormat, const
* \param[in] outputCfgs The output configurations
* \param[in] configInfo The IPA configuration data, received from the pipeline handler
* \param[out] ipaControls The IPA controls to update
+ * \param[in] debayerEnabled Whether debayering should be performed in addition
+ * to stats and IPA processing
* \return 0 on success, a negative errno on failure
*/
int SoftwareIsp::configure(const StreamConfiguration &inputCfg,
const std::vector<std::reference_wrapper<const StreamConfiguration>> &outputCfgs,
const ipa::softisp::IPAConfigInfo &configInfo,
- ControlInfoMap *ipaControls)
+ ControlInfoMap *ipaControls,
+ bool debayerEnabled)
{
- ASSERT(ipa_ && debayer_);
+ ASSERT(ipa_ && (!debayerEnabled || debayer_));
+
+ int ret;
+ if (!debayerEnabled) {
+ ret = stats_->configure(inputCfg);
+ if (ret < 0)
+ return ret;
+ stats_->setWindow(Rectangle(inputCfg.size));
+ }
- int ret = ipa_->configure(configInfo, ipaControls);
+ ret = ipa_->configure(configInfo, ipaControls);
if (ret < 0)
return ret;
+ if (!debayerEnabled) {
+ return 0;
+ }
+
ret = debayer_->configure(inputCfg, outputCfgs, ccmEnabled_);
if (ret < 0)
return ret;
@@ -452,13 +468,25 @@ void SoftwareIsp::stopIpa()
* \brief Passes the input framebuffer to the ISP worker to process
* \param[in] frame The frame number
* \param[in] input The input framebuffer
- * \param[out] output The framebuffer to write the processed frame to
+ * \param[out] output The framebuffer to write the processed frame to; if
+ * nullptr then debayering is skipped and stats are processed synchronously
*/
void SoftwareIsp::process(uint32_t frame, FrameBuffer *input, FrameBuffer *output)
{
ipa_->computeParams(frame);
- debayer_->invokeMethod(&Debayer::process,
- ConnectionTypeQueued, frame, input, output, debayerParams_);
+
+ if (output) {
+ debayer_->invokeMethod(&Debayer::process,
+ ConnectionTypeQueued, frame, input, output, debayerParams_);
+ } else {
+ /* Compute stats, which are otherwise computed in debayering */
+ if (frame % SwStatsCpu::kStatPerNumFrames) {
+ stats_->finishFrame(frame, 0);
+ } else {
+ MappedFrameBuffer inputMapped(input, MappedFrameBuffer::MapFlag::Read);
+ stats_->processFrame(frame, 0, inputMapped);
+ }
+ }
}
void SoftwareIsp::saveIspParams([[maybe_unused]] uint32_t frame)
`simple' pipeline can basically pass raw buffers from V4L2 to the output. While the raw data is untouched, we may still want to: - Gather statistics from it. - Run IPA on the images (without modifying the images). - Provide metadata from the IPA. - Adjust exposure/gain. This patch implements all of that. Since this imposes some overhead, a new configuration option pipelines.simple.enable_raw_ipa is added. The option is on by default as at least the metadata and exposure adjustments may be useful. Using a configuration option rather than a runtime-adjustable option is not perfect, but I don't know what better mechanism to use. The patch attempts to fit into the current structure as close as possible, with minimum changes. Future enhancements might include computing the stats asynchronously or even splitting `simple' pipeline into separate components (debayering, converter, raw output). Signed-off-by: Milan Zamazal <mzamazal@redhat.com> --- Documentation/runtime_configuration.rst | 10 +++++ .../internal/software_isp/software_isp.h | 3 +- src/libcamera/pipeline/simple/simple.cpp | 36 ++++++++++++++--- src/libcamera/software_isp/software_isp.cpp | 40 ++++++++++++++++--- 4 files changed, 77 insertions(+), 12 deletions(-)