9948eb64d1
Refresh them with the patches from https://patchwork.libcamera.org/cover/19663/. This is still based off v0.2.0. Change-Id: I875fd64e3bb71a95c92af1108a23d27c0f3494e0 Reviewed-on: https://cl.tvl.fyi/c/depot/+/11179 Tested-by: BuildkiteCI Reviewed-by: flokli <flokli@flokli.de> Autosubmit: flokli <flokli@flokli.de>
239 lines
9.4 KiB
Diff
239 lines
9.4 KiB
Diff
From b0c07674abecb05dc0af93a4b749971f057bc3c6 Mon Sep 17 00:00:00 2001
|
|
From: Andrei Konovalov <andrey.konovalov.ynk@gmail.com>
|
|
Date: Mon, 11 Mar 2024 15:15:22 +0100
|
|
Subject: [PATCH 19/21] libcamera: Soft IPA: use CameraSensorHelper for
|
|
analogue gain
|
|
|
|
Use CameraSensorHelper to convert the analogue gain code read from the
|
|
camera sensor into real analogue gain value. In the future this makes
|
|
it possible to use faster AE/AGC algorithm. For now the same AE/AGC
|
|
algorithm is used, but even then the CameraSensorHelper lets us use the
|
|
full range of analogue gain values.
|
|
|
|
If there is no CameraSensorHelper for the camera sensor in use, a
|
|
warning log message is printed, and the AE/AGC works exactly as before
|
|
this change.
|
|
|
|
Signed-off-by: Andrei Konovalov <andrey.konovalov.ynk@gmail.com>
|
|
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
|
|
---
|
|
.../internal/software_isp/software_isp.h | 3 +-
|
|
src/ipa/simple/soft_simple.cpp | 77 ++++++++++++-------
|
|
src/libcamera/pipeline/simple/simple.cpp | 2 +-
|
|
src/libcamera/software_isp/software_isp.cpp | 8 +-
|
|
4 files changed, 57 insertions(+), 33 deletions(-)
|
|
|
|
diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h
|
|
index 8d25e979..2a6db7ba 100644
|
|
--- a/include/libcamera/internal/software_isp/software_isp.h
|
|
+++ b/include/libcamera/internal/software_isp/software_isp.h
|
|
@@ -26,6 +26,7 @@
|
|
#include <libcamera/ipa/soft_ipa_interface.h>
|
|
#include <libcamera/ipa/soft_ipa_proxy.h>
|
|
|
|
+#include "libcamera/internal/camera_sensor.h"
|
|
#include "libcamera/internal/dma_heaps.h"
|
|
#include "libcamera/internal/pipeline_handler.h"
|
|
#include "libcamera/internal/shared_mem_object.h"
|
|
@@ -43,7 +44,7 @@ LOG_DECLARE_CATEGORY(SoftwareIsp)
|
|
class SoftwareIsp
|
|
{
|
|
public:
|
|
- SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorControls);
|
|
+ SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor);
|
|
~SoftwareIsp();
|
|
|
|
int loadConfiguration([[maybe_unused]] const std::string &filename) { return 0; }
|
|
diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp
|
|
index ac027568..e4d64762 100644
|
|
--- a/src/ipa/simple/soft_simple.cpp
|
|
+++ b/src/ipa/simple/soft_simple.cpp
|
|
@@ -22,6 +22,8 @@
|
|
#include "libcamera/internal/software_isp/debayer_params.h"
|
|
#include "libcamera/internal/software_isp/swisp_stats.h"
|
|
|
|
+#include "libipa/camera_sensor_helper.h"
|
|
+
|
|
#include "black_level.h"
|
|
|
|
namespace libcamera {
|
|
@@ -67,18 +69,27 @@ private:
|
|
DebayerParams *params_;
|
|
SwIspStats *stats_;
|
|
BlackLevel blackLevel_;
|
|
+ std::unique_ptr<CameraSensorHelper> camHelper_;
|
|
|
|
int32_t exposure_min_, exposure_max_;
|
|
- int32_t again_min_, again_max_;
|
|
- int32_t again_, exposure_;
|
|
+ int32_t exposure_;
|
|
+ double again_min_, again_max_, againMinStep_;
|
|
+ double again_;
|
|
unsigned int ignore_updates_;
|
|
};
|
|
|
|
-int IPASoftSimple::init([[maybe_unused]] const IPASettings &settings,
|
|
+int IPASoftSimple::init(const IPASettings &settings,
|
|
const SharedFD &fdStats,
|
|
const SharedFD &fdParams,
|
|
const ControlInfoMap &sensorInfoMap)
|
|
{
|
|
+ camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel);
|
|
+ if (camHelper_ == nullptr) {
|
|
+ LOG(IPASoft, Warning)
|
|
+ << "Failed to create camera sensor helper for "
|
|
+ << settings.sensorModel;
|
|
+ }
|
|
+
|
|
fdStats_ = fdStats;
|
|
if (!fdStats_.isValid()) {
|
|
LOG(IPASoft, Error) << "Invalid Statistics handle";
|
|
@@ -132,25 +143,35 @@ int IPASoftSimple::configure(const ControlInfoMap &sensorInfoMap)
|
|
exposure_min_ = 1;
|
|
}
|
|
|
|
- again_min_ = gain_info.min().get<int32_t>();
|
|
- again_max_ = gain_info.max().get<int32_t>();
|
|
- /*
|
|
- * The camera sensor gain (g) is usually not equal to the value written
|
|
- * into the gain register (x). But the way how the AGC algorithm changes
|
|
- * the gain value to make the total exposure closer to the optimum assumes
|
|
- * that g(x) is not too far from linear function. If the minimal gain is 0,
|
|
- * the g(x) is likely to be far from the linear, like g(x) = a / (b * x + c).
|
|
- * To avoid unexpected changes to the gain by the AGC algorithm (abrupt near
|
|
- * one edge, and very small near the other) we limit the range of the gain
|
|
- * values used.
|
|
- */
|
|
- if (!again_min_) {
|
|
- LOG(IPASoft, Warning) << "Minimum gain is zero, that can't be linear";
|
|
- again_min_ = std::min(100, again_min_ / 2 + again_max_ / 2);
|
|
+ int32_t again_min = gain_info.min().get<int32_t>();
|
|
+ int32_t again_max = gain_info.max().get<int32_t>();
|
|
+
|
|
+ if (camHelper_) {
|
|
+ again_min_ = camHelper_->gain(again_min);
|
|
+ again_max_ = camHelper_->gain(again_max);
|
|
+ againMinStep_ = (again_max_ - again_min_) / 100.0;
|
|
+ } else {
|
|
+ /*
|
|
+ * The camera sensor gain (g) is usually not equal to the value written
|
|
+ * into the gain register (x). But the way how the AGC algorithm changes
|
|
+ * the gain value to make the total exposure closer to the optimum assumes
|
|
+ * that g(x) is not too far from linear function. If the minimal gain is 0,
|
|
+ * the g(x) is likely to be far from the linear, like g(x) = a / (b * x + c).
|
|
+ * To avoid unexpected changes to the gain by the AGC algorithm (abrupt near
|
|
+ * one edge, and very small near the other) we limit the range of the gain
|
|
+ * values used.
|
|
+ */
|
|
+ again_max_ = again_max;
|
|
+ if (!again_min) {
|
|
+ LOG(IPASoft, Warning) << "Minimum gain is zero, that can't be linear";
|
|
+ again_min_ = std::min(100, again_min / 2 + again_max / 2);
|
|
+ }
|
|
+ againMinStep_ = 1.0;
|
|
}
|
|
|
|
LOG(IPASoft, Info) << "Exposure " << exposure_min_ << "-" << exposure_max_
|
|
- << ", gain " << again_min_ << "-" << again_max_;
|
|
+ << ", gain " << again_min_ << "-" << again_max_
|
|
+ << " (" << againMinStep_ << ")";
|
|
|
|
return 0;
|
|
}
|
|
@@ -252,12 +273,14 @@ void IPASoftSimple::processStats(const ControlList &sensorControls)
|
|
ControlList ctrls(sensorControls);
|
|
|
|
exposure_ = ctrls.get(V4L2_CID_EXPOSURE).get<int32_t>();
|
|
- again_ = ctrls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();
|
|
+ int32_t again = ctrls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();
|
|
+ again_ = camHelper_ ? camHelper_->gain(again) : again;
|
|
|
|
updateExposure(exposureMSV);
|
|
|
|
ctrls.set(V4L2_CID_EXPOSURE, exposure_);
|
|
- ctrls.set(V4L2_CID_ANALOGUE_GAIN, again_);
|
|
+ ctrls.set(V4L2_CID_ANALOGUE_GAIN,
|
|
+ static_cast<int32_t>(camHelper_ ? camHelper_->gainCode(again_) : again_));
|
|
|
|
ignore_updates_ = 2;
|
|
|
|
@@ -276,7 +299,7 @@ void IPASoftSimple::updateExposure(double exposureMSV)
|
|
static constexpr uint8_t kExpNumeratorUp = kExpDenominator + 1;
|
|
static constexpr uint8_t kExpNumeratorDown = kExpDenominator - 1;
|
|
|
|
- int next;
|
|
+ double next;
|
|
|
|
if (exposureMSV < kExposureOptimal - kExposureSatisfactory) {
|
|
next = exposure_ * kExpNumeratorUp / kExpDenominator;
|
|
@@ -286,18 +309,18 @@ void IPASoftSimple::updateExposure(double exposureMSV)
|
|
exposure_ = next;
|
|
if (exposure_ >= exposure_max_) {
|
|
next = again_ * kExpNumeratorUp / kExpDenominator;
|
|
- if (next - again_ < 1)
|
|
- again_ += 1;
|
|
+ if (next - again_ < againMinStep_)
|
|
+ again_ += againMinStep_;
|
|
else
|
|
again_ = next;
|
|
}
|
|
}
|
|
|
|
if (exposureMSV > kExposureOptimal + kExposureSatisfactory) {
|
|
- if (exposure_ == exposure_max_ && again_ != again_min_) {
|
|
+ if (exposure_ == exposure_max_ && again_ > again_min_) {
|
|
next = again_ * kExpNumeratorDown / kExpDenominator;
|
|
- if (again_ - next < 1)
|
|
- again_ -= 1;
|
|
+ if (again_ - next < againMinStep_)
|
|
+ again_ -= againMinStep_;
|
|
else
|
|
again_ = next;
|
|
} else {
|
|
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
|
|
index c3ebb7b7..7e932a14 100644
|
|
--- a/src/libcamera/pipeline/simple/simple.cpp
|
|
+++ b/src/libcamera/pipeline/simple/simple.cpp
|
|
@@ -525,7 +525,7 @@ int SimpleCameraData::init()
|
|
* Instantiate Soft ISP if this is enabled for the given driver and no converter is used.
|
|
*/
|
|
if (!converter_ && pipe->swIspEnabled()) {
|
|
- swIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_->controls());
|
|
+ swIsp_ = std::make_unique<SoftwareIsp>(pipe, sensor_.get());
|
|
if (!swIsp_->isValid()) {
|
|
LOG(SimplePipeline, Warning)
|
|
<< "Failed to create software ISP, disabling software debayering";
|
|
diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp
|
|
index 9b49be41..ea4d96e4 100644
|
|
--- a/src/libcamera/software_isp/software_isp.cpp
|
|
+++ b/src/libcamera/software_isp/software_isp.cpp
|
|
@@ -60,9 +60,9 @@ LOG_DEFINE_CATEGORY(SoftwareIsp)
|
|
/**
|
|
* \brief Constructs SoftwareIsp object
|
|
* \param[in] pipe The pipeline handler in use
|
|
- * \param[in] sensorControls ControlInfoMap describing the controls supported by the sensor
|
|
+ * \param[in] sensor Pointer to the CameraSensor instance owned by the pipeline handler
|
|
*/
|
|
-SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorControls)
|
|
+SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const CameraSensor *sensor)
|
|
: debayer_(nullptr),
|
|
debayerParams_{ DebayerParams::kGain10, DebayerParams::kGain10, DebayerParams::kGain10, 0.5f, 0 },
|
|
dmaHeap_(DmaHeap::DmaHeapFlag::Cma | DmaHeap::DmaHeapFlag::System)
|
|
@@ -97,10 +97,10 @@ SoftwareIsp::SoftwareIsp(PipelineHandler *pipe, const ControlInfoMap &sensorCont
|
|
return;
|
|
}
|
|
|
|
- int ret = ipa_->init(IPASettings{ "No cfg file", "No sensor model" },
|
|
+ int ret = ipa_->init(IPASettings{ "No cfg file", sensor->model() },
|
|
debayer_->getStatsFD(),
|
|
sharedParams_.fd(),
|
|
- sensorControls);
|
|
+ sensor->controls());
|
|
if (ret) {
|
|
LOG(SoftwareIsp, Error) << "IPA init failed";
|
|
debayer_.reset();
|
|
--
|
|
2.43.2
|
|
|