summaryrefslogtreecommitdiff
path: root/src/ipa/rpi
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipa/rpi')
-rw-r--r--src/ipa/rpi/cam_helper/cam_helper.cpp12
-rw-r--r--src/ipa/rpi/cam_helper/cam_helper.h9
-rw-r--r--src/ipa/rpi/cam_helper/cam_helper_imx283.cpp12
-rw-r--r--src/ipa/rpi/cam_helper/cam_helper_imx290.cpp11
-rw-r--r--src/ipa/rpi/cam_helper/cam_helper_imx296.cpp11
-rw-r--r--src/ipa/rpi/cam_helper/cam_helper_imx415.cpp64
-rw-r--r--src/ipa/rpi/cam_helper/cam_helper_imx477.cpp11
-rw-r--r--src/ipa/rpi/cam_helper/cam_helper_imx519.cpp11
-rw-r--r--src/ipa/rpi/cam_helper/cam_helper_imx708.cpp13
-rw-r--r--src/ipa/rpi/cam_helper/cam_helper_ov5647.cpp15
-rw-r--r--src/ipa/rpi/cam_helper/cam_helper_ov64a40.cpp12
-rw-r--r--src/ipa/rpi/cam_helper/cam_helper_ov7251.cpp12
-rw-r--r--src/ipa/rpi/cam_helper/cam_helper_ov9281.cpp12
-rw-r--r--src/ipa/rpi/cam_helper/meson.build1
-rw-r--r--src/ipa/rpi/common/ipa_base.cpp139
-rw-r--r--src/ipa/rpi/controller/agc_algorithm.h8
-rw-r--r--src/ipa/rpi/controller/awb_algorithm.h1
-rw-r--r--src/ipa/rpi/controller/controller.cpp2
-rw-r--r--src/ipa/rpi/controller/controller.h1
-rw-r--r--src/ipa/rpi/controller/metadata.h23
-rw-r--r--src/ipa/rpi/controller/rpi/agc.cpp52
-rw-r--r--src/ipa/rpi/controller/rpi/agc.h8
-rw-r--r--src/ipa/rpi/controller/rpi/agc_channel.cpp24
-rw-r--r--src/ipa/rpi/controller/rpi/agc_channel.h8
-rw-r--r--src/ipa/rpi/controller/rpi/awb.cpp18
-rw-r--r--src/ipa/rpi/controller/rpi/awb.h1
-rwxr-xr-xsrc/ipa/rpi/vc4/data/imx415.json413
-rw-r--r--src/ipa/rpi/vc4/data/meson.build1
28 files changed, 718 insertions, 187 deletions
diff --git a/src/ipa/rpi/cam_helper/cam_helper.cpp b/src/ipa/rpi/cam_helper/cam_helper.cpp
index 6493e882..a78db9c1 100644
--- a/src/ipa/rpi/cam_helper/cam_helper.cpp
+++ b/src/ipa/rpi/cam_helper/cam_helper.cpp
@@ -156,17 +156,9 @@ void CamHelper::setCameraMode(const CameraMode &mode)
}
}
-void CamHelper::getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const
+void CamHelper::setHwConfig(const Controller::HardwareConfig &hwConfig)
{
- /*
- * These values are correct for many sensors. Other sensors will
- * need to over-ride this function.
- */
- exposureDelay = 2;
- gainDelay = 1;
- vblankDelay = 2;
- hblankDelay = 2;
+ hwConfig_ = hwConfig;
}
bool CamHelper::sensorEmbeddedDataPresent() const
diff --git a/src/ipa/rpi/cam_helper/cam_helper.h b/src/ipa/rpi/cam_helper/cam_helper.h
index 4a4ab5e6..4a826690 100644
--- a/src/ipa/rpi/cam_helper/cam_helper.h
+++ b/src/ipa/rpi/cam_helper/cam_helper.h
@@ -36,11 +36,6 @@ namespace RPiController {
* exposure time, and to convert between the sensor's gain codes and actual
* gains.
*
- * A function to return the number of frames of delay between updating exposure,
- * analogue gain and vblanking, and for the changes to take effect. For many
- * sensors these take the values 2, 1 and 2 respectively, but sensors that are
- * different will need to over-ride the default function provided.
- *
* A function to query if the sensor outputs embedded data that can be parsed.
*
* A function to return the sensitivity of a given camera mode.
@@ -76,6 +71,7 @@ public:
CamHelper(std::unique_ptr<MdParser> parser, unsigned int frameIntegrationDiff);
virtual ~CamHelper();
void setCameraMode(const CameraMode &mode);
+ void setHwConfig(const Controller::HardwareConfig &hwConfig);
virtual void prepare(libcamera::Span<const uint8_t> buffer,
Metadata &metadata);
virtual void process(StatisticsPtr &stats, Metadata &metadata);
@@ -91,8 +87,6 @@ public:
libcamera::utils::Duration lineLengthPckToDuration(uint32_t lineLengthPck) const;
virtual uint32_t gainCode(double gain) const = 0;
virtual double gain(uint32_t gainCode) const = 0;
- virtual void getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const;
virtual bool sensorEmbeddedDataPresent() const;
virtual double getModeSensitivity(const CameraMode &mode) const;
virtual unsigned int hideFramesStartup() const;
@@ -108,6 +102,7 @@ protected:
std::unique_ptr<MdParser> parser_;
CameraMode mode_;
+ Controller::HardwareConfig hwConfig_;
private:
/*
diff --git a/src/ipa/rpi/cam_helper/cam_helper_imx283.cpp b/src/ipa/rpi/cam_helper/cam_helper_imx283.cpp
index cb0be72a..efc03193 100644
--- a/src/ipa/rpi/cam_helper/cam_helper_imx283.cpp
+++ b/src/ipa/rpi/cam_helper/cam_helper_imx283.cpp
@@ -17,8 +17,6 @@ public:
CamHelperImx283();
uint32_t gainCode(double gain) const override;
double gain(uint32_t gainCode) const override;
- void getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const override;
unsigned int hideFramesModeSwitch() const override;
private:
@@ -49,16 +47,6 @@ double CamHelperImx283::gain(uint32_t gainCode) const
return static_cast<double>(2048.0 / (2048 - gainCode));
}
-void CamHelperImx283::getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const
-{
- /* The driver appears to behave as follows: */
- exposureDelay = 2;
- gainDelay = 2;
- vblankDelay = 2;
- hblankDelay = 2;
-}
-
unsigned int CamHelperImx283::hideFramesModeSwitch() const
{
/* After a mode switch, we seem to get 1 bad frame. */
diff --git a/src/ipa/rpi/cam_helper/cam_helper_imx290.cpp b/src/ipa/rpi/cam_helper/cam_helper_imx290.cpp
index 3b87751e..c1aa8528 100644
--- a/src/ipa/rpi/cam_helper/cam_helper_imx290.cpp
+++ b/src/ipa/rpi/cam_helper/cam_helper_imx290.cpp
@@ -17,8 +17,6 @@ public:
CamHelperImx290();
uint32_t gainCode(double gain) const override;
double gain(uint32_t gainCode) const override;
- void getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const override;
unsigned int hideFramesStartup() const override;
unsigned int hideFramesModeSwitch() const override;
@@ -46,15 +44,6 @@ double CamHelperImx290::gain(uint32_t gainCode) const
return std::pow(10, 0.015 * gainCode);
}
-void CamHelperImx290::getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const
-{
- exposureDelay = 2;
- gainDelay = 2;
- vblankDelay = 2;
- hblankDelay = 2;
-}
-
unsigned int CamHelperImx290::hideFramesStartup() const
{
/* On startup, we seem to get 1 bad frame. */
diff --git a/src/ipa/rpi/cam_helper/cam_helper_imx296.cpp b/src/ipa/rpi/cam_helper/cam_helper_imx296.cpp
index d4a4fa79..ac7ee2ea 100644
--- a/src/ipa/rpi/cam_helper/cam_helper_imx296.cpp
+++ b/src/ipa/rpi/cam_helper/cam_helper_imx296.cpp
@@ -23,8 +23,6 @@ public:
double gain(uint32_t gainCode) const override;
uint32_t exposureLines(const Duration exposure, const Duration lineLength) const override;
Duration exposure(uint32_t exposureLines, const Duration lineLength) const override;
- void getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const override;
private:
static constexpr uint32_t minExposureLines = 1;
@@ -66,15 +64,6 @@ Duration CamHelperImx296::exposure(uint32_t exposureLines,
return std::max<uint32_t>(minExposureLines, exposureLines) * timePerLine + 14.26us;
}
-void CamHelperImx296::getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const
-{
- exposureDelay = 2;
- gainDelay = 2;
- vblankDelay = 2;
- hblankDelay = 2;
-}
-
static CamHelper *create()
{
return new CamHelperImx296();
diff --git a/src/ipa/rpi/cam_helper/cam_helper_imx415.cpp b/src/ipa/rpi/cam_helper/cam_helper_imx415.cpp
new file mode 100644
index 00000000..c0a09eee
--- /dev/null
+++ b/src/ipa/rpi/cam_helper/cam_helper_imx415.cpp
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2025, Raspberry Pi Ltd
+ *
+ * camera helper for imx415 sensor
+ */
+
+#include <cmath>
+
+#include "cam_helper.h"
+
+using namespace RPiController;
+
+class CamHelperImx415 : public CamHelper
+{
+public:
+ CamHelperImx415();
+ uint32_t gainCode(double gain) const override;
+ double gain(uint32_t gainCode) const override;
+ unsigned int hideFramesStartup() const override;
+ unsigned int hideFramesModeSwitch() const override;
+
+private:
+ /*
+ * Smallest difference between the frame length and integration time,
+ * in units of lines.
+ */
+ static constexpr int frameIntegrationDiff = 8;
+};
+
+CamHelperImx415::CamHelperImx415()
+ : CamHelper({}, frameIntegrationDiff)
+{
+}
+
+uint32_t CamHelperImx415::gainCode(double gain) const
+{
+ int code = 66.6667 * std::log10(gain);
+ return std::max(0, std::min(code, 0xf0));
+}
+
+double CamHelperImx415::gain(uint32_t gainCode) const
+{
+ return std::pow(10, 0.015 * gainCode);
+}
+
+unsigned int CamHelperImx415::hideFramesStartup() const
+{
+ /* On startup, we seem to get 1 bad frame. */
+ return 1;
+}
+
+unsigned int CamHelperImx415::hideFramesModeSwitch() const
+{
+ /* After a mode switch, we seem to get 1 bad frame. */
+ return 1;
+}
+
+static CamHelper *create()
+{
+ return new CamHelperImx415();
+}
+
+static RegisterCamHelper reg("imx415", &create);
diff --git a/src/ipa/rpi/cam_helper/cam_helper_imx477.cpp b/src/ipa/rpi/cam_helper/cam_helper_imx477.cpp
index a53c40cd..a72ac67d 100644
--- a/src/ipa/rpi/cam_helper/cam_helper_imx477.cpp
+++ b/src/ipa/rpi/cam_helper/cam_helper_imx477.cpp
@@ -51,8 +51,6 @@ public:
void prepare(libcamera::Span<const uint8_t> buffer, Metadata &metadata) override;
std::pair<uint32_t, uint32_t> getBlanking(Duration &exposure, Duration minFrameDuration,
Duration maxFrameDuration) const override;
- void getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const override;
bool sensorEmbeddedDataPresent() const override;
private:
@@ -159,15 +157,6 @@ std::pair<uint32_t, uint32_t> CamHelperImx477::getBlanking(Duration &exposure,
return { frameLength - mode_.height, hblank };
}
-void CamHelperImx477::getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const
-{
- exposureDelay = 2;
- gainDelay = 2;
- vblankDelay = 3;
- hblankDelay = 3;
-}
-
bool CamHelperImx477::sensorEmbeddedDataPresent() const
{
return true;
diff --git a/src/ipa/rpi/cam_helper/cam_helper_imx519.cpp b/src/ipa/rpi/cam_helper/cam_helper_imx519.cpp
index 2ff08653..10cbea48 100644
--- a/src/ipa/rpi/cam_helper/cam_helper_imx519.cpp
+++ b/src/ipa/rpi/cam_helper/cam_helper_imx519.cpp
@@ -51,8 +51,6 @@ public:
void prepare(libcamera::Span<const uint8_t> buffer, Metadata &metadata) override;
std::pair<uint32_t, uint32_t> getBlanking(Duration &exposure, Duration minFrameDuration,
Duration maxFrameDuration) const override;
- void getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const override;
bool sensorEmbeddedDataPresent() const override;
private:
@@ -159,15 +157,6 @@ std::pair<uint32_t, uint32_t> CamHelperImx519::getBlanking(Duration &exposure,
return { frameLength - mode_.height, hblank };
}
-void CamHelperImx519::getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const
-{
- exposureDelay = 2;
- gainDelay = 2;
- vblankDelay = 3;
- hblankDelay = 3;
-}
-
bool CamHelperImx519::sensorEmbeddedDataPresent() const
{
return true;
diff --git a/src/ipa/rpi/cam_helper/cam_helper_imx708.cpp b/src/ipa/rpi/cam_helper/cam_helper_imx708.cpp
index ec83d9fd..6150909c 100644
--- a/src/ipa/rpi/cam_helper/cam_helper_imx708.cpp
+++ b/src/ipa/rpi/cam_helper/cam_helper_imx708.cpp
@@ -54,8 +54,6 @@ public:
void process(StatisticsPtr &stats, Metadata &metadata) override;
std::pair<uint32_t, uint32_t> getBlanking(Duration &exposure, Duration minFrameDuration,
Duration maxFrameDuration) const override;
- void getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const override;
bool sensorEmbeddedDataPresent() const override;
double getModeSensitivity(const CameraMode &mode) const override;
unsigned int hideFramesModeSwitch() const override;
@@ -66,7 +64,7 @@ private:
* Smallest difference between the frame length and integration time,
* in units of lines.
*/
- static constexpr int frameIntegrationDiff = 22;
+ static constexpr int frameIntegrationDiff = 48;
/* Maximum frame length allowable for long exposure calculations. */
static constexpr int frameLengthMax = 0xffdc;
/* Largest long exposure scale factor given as a left shift on the frame length. */
@@ -208,15 +206,6 @@ std::pair<uint32_t, uint32_t> CamHelperImx708::getBlanking(Duration &exposure,
return { frameLength - mode_.height, hblank };
}
-void CamHelperImx708::getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const
-{
- exposureDelay = 2;
- gainDelay = 2;
- vblankDelay = 3;
- hblankDelay = 3;
-}
-
bool CamHelperImx708::sensorEmbeddedDataPresent() const
{
return true;
diff --git a/src/ipa/rpi/cam_helper/cam_helper_ov5647.cpp b/src/ipa/rpi/cam_helper/cam_helper_ov5647.cpp
index c30b017c..40d6b6d7 100644
--- a/src/ipa/rpi/cam_helper/cam_helper_ov5647.cpp
+++ b/src/ipa/rpi/cam_helper/cam_helper_ov5647.cpp
@@ -17,8 +17,6 @@ public:
CamHelperOv5647();
uint32_t gainCode(double gain) const override;
double gain(uint32_t gainCode) const override;
- void getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const override;
unsigned int hideFramesStartup() const override;
unsigned int hideFramesModeSwitch() const override;
unsigned int mistrustFramesStartup() const override;
@@ -52,19 +50,6 @@ double CamHelperOv5647::gain(uint32_t gainCode) const
return static_cast<double>(gainCode) / 16.0;
}
-void CamHelperOv5647::getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const
-{
- /*
- * We run this sensor in a mode where the gain delay is bumped up to
- * 2. It seems to be the only way to make the delays "predictable".
- */
- exposureDelay = 2;
- gainDelay = 2;
- vblankDelay = 2;
- hblankDelay = 2;
-}
-
unsigned int CamHelperOv5647::hideFramesStartup() const
{
/*
diff --git a/src/ipa/rpi/cam_helper/cam_helper_ov64a40.cpp b/src/ipa/rpi/cam_helper/cam_helper_ov64a40.cpp
index a8efd389..980495a8 100644
--- a/src/ipa/rpi/cam_helper/cam_helper_ov64a40.cpp
+++ b/src/ipa/rpi/cam_helper/cam_helper_ov64a40.cpp
@@ -18,8 +18,6 @@ public:
CamHelperOv64a40();
uint32_t gainCode(double gain) const override;
double gain(uint32_t gainCode) const override;
- void getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const override;
double getModeSensitivity(const CameraMode &mode) const override;
private:
@@ -45,16 +43,6 @@ double CamHelperOv64a40::gain(uint32_t gainCode) const
return static_cast<double>(gainCode) / 128.0;
}
-void CamHelperOv64a40::getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const
-{
- /* The driver appears to behave as follows: */
- exposureDelay = 2;
- gainDelay = 2;
- vblankDelay = 2;
- hblankDelay = 2;
-}
-
double CamHelperOv64a40::getModeSensitivity(const CameraMode &mode) const
{
if (mode.binX >= 2 && mode.scaleX >= 4) {
diff --git a/src/ipa/rpi/cam_helper/cam_helper_ov7251.cpp b/src/ipa/rpi/cam_helper/cam_helper_ov7251.cpp
index 7b12c445..fc7b999f 100644
--- a/src/ipa/rpi/cam_helper/cam_helper_ov7251.cpp
+++ b/src/ipa/rpi/cam_helper/cam_helper_ov7251.cpp
@@ -17,8 +17,6 @@ public:
CamHelperOv7251();
uint32_t gainCode(double gain) const override;
double gain(uint32_t gainCode) const override;
- void getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const override;
private:
/*
@@ -48,16 +46,6 @@ double CamHelperOv7251::gain(uint32_t gainCode) const
return static_cast<double>(gainCode) / 16.0;
}
-void CamHelperOv7251::getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const
-{
- /* The driver appears to behave as follows: */
- exposureDelay = 2;
- gainDelay = 2;
- vblankDelay = 2;
- hblankDelay = 2;
-}
-
static CamHelper *create()
{
return new CamHelperOv7251();
diff --git a/src/ipa/rpi/cam_helper/cam_helper_ov9281.cpp b/src/ipa/rpi/cam_helper/cam_helper_ov9281.cpp
index 96f7fff4..e93a4691 100644
--- a/src/ipa/rpi/cam_helper/cam_helper_ov9281.cpp
+++ b/src/ipa/rpi/cam_helper/cam_helper_ov9281.cpp
@@ -17,8 +17,6 @@ public:
CamHelperOv9281();
uint32_t gainCode(double gain) const override;
double gain(uint32_t gainCode) const override;
- void getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const override;
private:
/*
@@ -48,16 +46,6 @@ double CamHelperOv9281::gain(uint32_t gainCode) const
return static_cast<double>(gainCode) / 16.0;
}
-void CamHelperOv9281::getDelays(int &exposureDelay, int &gainDelay,
- int &vblankDelay, int &hblankDelay) const
-{
- /* The driver appears to behave as follows: */
- exposureDelay = 2;
- gainDelay = 2;
- vblankDelay = 2;
- hblankDelay = 2;
-}
-
static CamHelper *create()
{
return new CamHelperOv9281();
diff --git a/src/ipa/rpi/cam_helper/meson.build b/src/ipa/rpi/cam_helper/meson.build
index 03e88fe0..abf02147 100644
--- a/src/ipa/rpi/cam_helper/meson.build
+++ b/src/ipa/rpi/cam_helper/meson.build
@@ -7,6 +7,7 @@ rpi_ipa_cam_helper_sources = files([
'cam_helper_imx283.cpp',
'cam_helper_imx290.cpp',
'cam_helper_imx296.cpp',
+ 'cam_helper_imx415.cpp',
'cam_helper_imx477.cpp',
'cam_helper_imx519.cpp',
'cam_helper_imx708.cpp',
diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp
index 5fce17e6..bd3c2200 100644
--- a/src/ipa/rpi/common/ipa_base.cpp
+++ b/src/ipa/rpi/common/ipa_base.cpp
@@ -55,8 +55,17 @@ constexpr Duration controllerMinFrameDuration = 1.0s / 30.0;
/* List of controls handled by the Raspberry Pi IPA */
const ControlInfoMap::Map ipaControls{
- { &controls::AeEnable, ControlInfo(false, true) },
+ /* \todo Move this to the Camera class */
+ { &controls::AeEnable, ControlInfo(false, true, true) },
+ { &controls::ExposureTimeMode,
+ ControlInfo(static_cast<int32_t>(controls::ExposureTimeModeAuto),
+ static_cast<int32_t>(controls::ExposureTimeModeManual),
+ static_cast<int32_t>(controls::ExposureTimeModeAuto)) },
{ &controls::ExposureTime, ControlInfo(0, 66666) },
+ { &controls::AnalogueGainMode,
+ ControlInfo(static_cast<int32_t>(controls::AnalogueGainModeAuto),
+ static_cast<int32_t>(controls::AnalogueGainModeManual),
+ static_cast<int32_t>(controls::AnalogueGainModeAuto)) },
{ &controls::AnalogueGain, ControlInfo(1.0f, 16.0f) },
{ &controls::AeMeteringMode, ControlInfo(controls::AeMeteringModeValues) },
{ &controls::AeConstraintMode, ControlInfo(controls::AeConstraintModeValues) },
@@ -81,6 +90,7 @@ const ControlInfoMap::Map ipaColourControls{
{ &controls::AwbEnable, ControlInfo(false, true) },
{ &controls::AwbMode, ControlInfo(controls::AwbModeValues) },
{ &controls::ColourGains, ControlInfo(0.0f, 32.0f) },
+ { &controls::ColourTemperature, ControlInfo(100, 100000) },
{ &controls::Saturation, ControlInfo(0.0f, 32.0f, 1.0f) },
};
@@ -134,18 +144,8 @@ int32_t IpaBase::init(const IPASettings &settings, const InitParams &params, Ini
return -EINVAL;
}
- /*
- * Pass out the sensor config to the pipeline handler in order
- * to setup the staggered writer class.
- */
- int gainDelay, exposureDelay, vblankDelay, hblankDelay, sensorMetadata;
- helper_->getDelays(exposureDelay, gainDelay, vblankDelay, hblankDelay);
- sensorMetadata = helper_->sensorEmbeddedDataPresent();
-
- result->sensorConfig.gainDelay = gainDelay;
- result->sensorConfig.exposureDelay = exposureDelay;
- result->sensorConfig.vblankDelay = vblankDelay;
- result->sensorConfig.hblankDelay = hblankDelay;
+ /* Pass out the sensor metadata to the pipeline handler */
+ int sensorMetadata = helper_->sensorEmbeddedDataPresent();
result->sensorConfig.sensorMetadata = sensorMetadata;
/* Load the tuning file for this sensor. */
@@ -160,6 +160,7 @@ int32_t IpaBase::init(const IPASettings &settings, const InitParams &params, Ini
lensPresent_ = params.lensPresent;
controller_.initialise();
+ helper_->setHwConfig(controller_.getHardwareConfig());
/* Return the controls handled by the IPA */
ControlInfoMap::Map ctrlMap = ipaControls;
@@ -757,6 +758,42 @@ void IpaBase::applyControls(const ControlList &controls)
af->setMode(mode->second);
}
+ /*
+ * Because some AE controls are mode-specific, handle the AE-related
+ * mode changes first.
+ */
+ const auto analogueGainMode = controls.get(controls::AnalogueGainMode);
+ const auto exposureTimeMode = controls.get(controls::ExposureTimeMode);
+
+ if (analogueGainMode || exposureTimeMode) {
+ RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
+ controller_.getAlgorithm("agc"));
+ if (agc) {
+ if (analogueGainMode) {
+ if (*analogueGainMode == controls::AnalogueGainModeManual)
+ agc->disableAutoGain();
+ else
+ agc->enableAutoGain();
+
+ libcameraMetadata_.set(controls::AnalogueGainMode,
+ *analogueGainMode);
+ }
+
+ if (exposureTimeMode) {
+ if (*exposureTimeMode == controls::ExposureTimeModeManual)
+ agc->disableAutoExposure();
+ else
+ agc->enableAutoExposure();
+
+ libcameraMetadata_.set(controls::ExposureTimeMode,
+ *exposureTimeMode);
+ }
+ } else {
+ LOG(IPARPI, Warning)
+ << "Could not set AnalogueGainMode or ExposureTimeMode - no AGC algorithm";
+ }
+ }
+
/* Iterate over controls */
for (auto const &ctrl : controls) {
LOG(IPARPI, Debug) << "Request ctrl: "
@@ -764,23 +801,8 @@ void IpaBase::applyControls(const ControlList &controls)
<< " = " << ctrl.second.toString();
switch (ctrl.first) {
- case controls::AE_ENABLE: {
- RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
- controller_.getAlgorithm("agc"));
- if (!agc) {
- LOG(IPARPI, Warning)
- << "Could not set AE_ENABLE - no AGC algorithm";
- break;
- }
-
- if (ctrl.second.get<bool>() == false)
- agc->disableAuto();
- else
- agc->enableAuto();
-
- libcameraMetadata_.set(controls::AeEnable, ctrl.second.get<bool>());
- break;
- }
+ case controls::EXPOSURE_TIME_MODE:
+ break; /* We already handled this one above */
case controls::EXPOSURE_TIME: {
RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
@@ -791,6 +813,13 @@ void IpaBase::applyControls(const ControlList &controls)
break;
}
+ /*
+ * Ignore manual exposure time when the auto exposure
+ * algorithm is running.
+ */
+ if (agc->autoExposureEnabled())
+ break;
+
/* The control provides units of microseconds. */
agc->setFixedExposureTime(0, ctrl.second.get<int32_t>() * 1.0us);
@@ -798,6 +827,9 @@ void IpaBase::applyControls(const ControlList &controls)
break;
}
+ case controls::ANALOGUE_GAIN_MODE:
+ break; /* We already handled this one above */
+
case controls::ANALOGUE_GAIN: {
RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
controller_.getAlgorithm("agc"));
@@ -807,6 +839,13 @@ void IpaBase::applyControls(const ControlList &controls)
break;
}
+ /*
+ * Ignore manual analogue gain value when the auto gain
+ * algorithm is running.
+ */
+ if (agc->autoGainEnabled())
+ break;
+
agc->setFixedAnalogueGain(0, ctrl.second.get<float>());
libcameraMetadata_.set(controls::AnalogueGain,
@@ -863,6 +902,13 @@ void IpaBase::applyControls(const ControlList &controls)
break;
}
+ /*
+ * Ignore AE_EXPOSURE_MODE if the shutter or the gain
+ * are in auto mode.
+ */
+ if (agc->autoExposureEnabled() || agc->autoGainEnabled())
+ break;
+
int32_t idx = ctrl.second.get<int32_t>();
if (ExposureModeTable.count(idx)) {
agc->setExposureMode(ExposureModeTable.at(idx));
@@ -1021,6 +1067,25 @@ void IpaBase::applyControls(const ControlList &controls)
break;
}
+ case controls::COLOUR_TEMPERATURE: {
+ /* Silently ignore this control for a mono sensor. */
+ if (monoSensor_)
+ break;
+
+ auto temperatureK = ctrl.second.get<int32_t>();
+ RPiController::AwbAlgorithm *awb = dynamic_cast<RPiController::AwbAlgorithm *>(
+ controller_.getAlgorithm("awb"));
+ if (!awb) {
+ LOG(IPARPI, Warning)
+ << "Could not set COLOUR_TEMPERATURE - no AWB algorithm";
+ break;
+ }
+
+ awb->setColourTemperature(temperatureK);
+ /* This metadata will get reported back automatically. */
+ break;
+ }
+
case controls::BRIGHTNESS: {
RPiController::ContrastAlgorithm *contrast = dynamic_cast<RPiController::ContrastAlgorithm *>(
controller_.getAlgorithm("contrast"));
@@ -1323,9 +1388,19 @@ void IpaBase::reportMetadata(unsigned int ipaContext)
}
AgcPrepareStatus *agcPrepareStatus = rpiMetadata.getLocked<AgcPrepareStatus>("agc.prepare_status");
- if (agcPrepareStatus) {
- libcameraMetadata_.set(controls::AeLocked, agcPrepareStatus->locked);
+ if (agcPrepareStatus)
libcameraMetadata_.set(controls::DigitalGain, agcPrepareStatus->digitalGain);
+
+ RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
+ controller_.getAlgorithm("agc"));
+ if (agc) {
+ if (!agc->autoExposureEnabled() && !agc->autoGainEnabled())
+ libcameraMetadata_.set(controls::AeState, controls::AeStateIdle);
+ else if (agcPrepareStatus)
+ libcameraMetadata_.set(controls::AeState,
+ agcPrepareStatus->locked
+ ? controls::AeStateConverged
+ : controls::AeStateSearching);
}
LuxStatus *luxStatus = rpiMetadata.getLocked<LuxStatus>("lux.status");
diff --git a/src/ipa/rpi/controller/agc_algorithm.h b/src/ipa/rpi/controller/agc_algorithm.h
index c9782857..fdaa10e6 100644
--- a/src/ipa/rpi/controller/agc_algorithm.h
+++ b/src/ipa/rpi/controller/agc_algorithm.h
@@ -30,8 +30,12 @@ public:
virtual void setMeteringMode(std::string const &meteringModeName) = 0;
virtual void setExposureMode(std::string const &exposureModeName) = 0;
virtual void setConstraintMode(std::string const &contraintModeName) = 0;
- virtual void enableAuto() = 0;
- virtual void disableAuto() = 0;
+ virtual void enableAutoExposure() = 0;
+ virtual void disableAutoExposure() = 0;
+ virtual bool autoExposureEnabled() const = 0;
+ virtual void enableAutoGain() = 0;
+ virtual void disableAutoGain() = 0;
+ virtual bool autoGainEnabled() const = 0;
virtual void setActiveChannels(const std::vector<unsigned int> &activeChannels) = 0;
};
diff --git a/src/ipa/rpi/controller/awb_algorithm.h b/src/ipa/rpi/controller/awb_algorithm.h
index 1779b050..d941ed4e 100644
--- a/src/ipa/rpi/controller/awb_algorithm.h
+++ b/src/ipa/rpi/controller/awb_algorithm.h
@@ -19,6 +19,7 @@ public:
virtual void initialValues(double &gainR, double &gainB) = 0;
virtual void setMode(std::string const &modeName) = 0;
virtual void setManualGains(double manualR, double manualB) = 0;
+ virtual void setColourTemperature(double temperatureK) = 0;
virtual void enableAuto() = 0;
virtual void disableAuto() = 0;
};
diff --git a/src/ipa/rpi/controller/controller.cpp b/src/ipa/rpi/controller/controller.cpp
index e0131018..651fff63 100644
--- a/src/ipa/rpi/controller/controller.cpp
+++ b/src/ipa/rpi/controller/controller.cpp
@@ -39,6 +39,7 @@ static const std::map<std::string, Controller::HardwareConfig> HardwareConfigMap
.pipelineWidth = 13,
.statsInline = false,
.minPixelProcessingTime = 0s,
+ .dataBufferStrided = true,
}
},
{
@@ -71,6 +72,7 @@ static const std::map<std::string, Controller::HardwareConfig> HardwareConfigMap
* frames wider than ~16,000 pixels.
*/
.minPixelProcessingTime = 1.0us / 380,
+ .dataBufferStrided = false,
}
},
};
diff --git a/src/ipa/rpi/controller/controller.h b/src/ipa/rpi/controller/controller.h
index eff520bd..fdb46557 100644
--- a/src/ipa/rpi/controller/controller.h
+++ b/src/ipa/rpi/controller/controller.h
@@ -49,6 +49,7 @@ public:
unsigned int pipelineWidth;
bool statsInline;
libcamera::utils::Duration minPixelProcessingTime;
+ bool dataBufferStrided;
};
Controller();
diff --git a/src/ipa/rpi/controller/metadata.h b/src/ipa/rpi/controller/metadata.h
index b4650d25..77d3b074 100644
--- a/src/ipa/rpi/controller/metadata.h
+++ b/src/ipa/rpi/controller/metadata.h
@@ -12,6 +12,7 @@
#include <map>
#include <mutex>
#include <string>
+#include <utility>
#include <libcamera/base/thread_annotations.h>
@@ -36,10 +37,10 @@ public:
}
template<typename T>
- void set(std::string const &tag, T const &value)
+ void set(std::string const &tag, T &&value)
{
std::scoped_lock lock(mutex_);
- data_[tag] = value;
+ data_[tag] = std::forward<T>(value);
}
template<typename T>
@@ -90,6 +91,12 @@ public:
data_.insert(other.data_.begin(), other.data_.end());
}
+ void erase(std::string const &tag)
+ {
+ std::scoped_lock lock(mutex_);
+ eraseLocked(tag);
+ }
+
template<typename T>
T *getLocked(std::string const &tag)
{
@@ -104,10 +111,18 @@ public:
}
template<typename T>
- void setLocked(std::string const &tag, T const &value)
+ void setLocked(std::string const &tag, T &&value)
{
/* Use this only if you're holding the lock yourself. */
- data_[tag] = value;
+ data_[tag] = std::forward<T>(value);
+ }
+
+ void eraseLocked(std::string const &tag)
+ {
+ auto it = data_.find(tag);
+ if (it == data_.end())
+ return;
+ data_.erase(it);
}
/*
diff --git a/src/ipa/rpi/controller/rpi/agc.cpp b/src/ipa/rpi/controller/rpi/agc.cpp
index c48fdf15..02bfdb4a 100644
--- a/src/ipa/rpi/controller/rpi/agc.cpp
+++ b/src/ipa/rpi/controller/rpi/agc.cpp
@@ -74,22 +74,62 @@ int Agc::checkChannel(unsigned int channelIndex) const
return 0;
}
-void Agc::disableAuto()
+void Agc::disableAutoExposure()
{
- LOG(RPiAgc, Debug) << "disableAuto";
+ LOG(RPiAgc, Debug) << "disableAutoExposure";
/* All channels are enabled/disabled together. */
for (auto &data : channelData_)
- data.channel.disableAuto();
+ data.channel.disableAutoExposure();
}
-void Agc::enableAuto()
+void Agc::enableAutoExposure()
{
- LOG(RPiAgc, Debug) << "enableAuto";
+ LOG(RPiAgc, Debug) << "enableAutoExposure";
/* All channels are enabled/disabled together. */
for (auto &data : channelData_)
- data.channel.enableAuto();
+ data.channel.enableAutoExposure();
+}
+
+bool Agc::autoExposureEnabled() const
+{
+ LOG(RPiAgc, Debug) << "autoExposureEnabled";
+
+ /*
+ * We always have at least one channel, and since all channels are
+ * enabled and disabled together we can simply check the first one.
+ */
+ return channelData_[0].channel.autoExposureEnabled();
+}
+
+void Agc::disableAutoGain()
+{
+ LOG(RPiAgc, Debug) << "disableAutoGain";
+
+ /* All channels are enabled/disabled together. */
+ for (auto &data : channelData_)
+ data.channel.disableAutoGain();
+}
+
+void Agc::enableAutoGain()
+{
+ LOG(RPiAgc, Debug) << "enableAutoGain";
+
+ /* All channels are enabled/disabled together. */
+ for (auto &data : channelData_)
+ data.channel.enableAutoGain();
+}
+
+bool Agc::autoGainEnabled() const
+{
+ LOG(RPiAgc, Debug) << "autoGainEnabled";
+
+ /*
+ * We always have at least one channel, and since all channels are
+ * enabled and disabled together we can simply check the first one.
+ */
+ return channelData_[0].channel.autoGainEnabled();
}
unsigned int Agc::getConvergenceFrames() const
diff --git a/src/ipa/rpi/controller/rpi/agc.h b/src/ipa/rpi/controller/rpi/agc.h
index 3aca000b..c3a940bf 100644
--- a/src/ipa/rpi/controller/rpi/agc.h
+++ b/src/ipa/rpi/controller/rpi/agc.h
@@ -40,8 +40,12 @@ public:
void setMeteringMode(std::string const &meteringModeName) override;
void setExposureMode(std::string const &exposureModeName) override;
void setConstraintMode(std::string const &contraintModeName) override;
- void enableAuto() override;
- void disableAuto() override;
+ void enableAutoExposure() override;
+ void disableAutoExposure() override;
+ bool autoExposureEnabled() const override;
+ void enableAutoGain() override;
+ void disableAutoGain() override;
+ bool autoGainEnabled() const override;
void switchMode(CameraMode const &cameraMode, Metadata *metadata) override;
void prepare(Metadata *imageMetadata) override;
void process(StatisticsPtr &stats, Metadata *imageMetadata) override;
diff --git a/src/ipa/rpi/controller/rpi/agc_channel.cpp b/src/ipa/rpi/controller/rpi/agc_channel.cpp
index 79c45973..e79184b7 100644
--- a/src/ipa/rpi/controller/rpi/agc_channel.cpp
+++ b/src/ipa/rpi/controller/rpi/agc_channel.cpp
@@ -319,18 +319,36 @@ int AgcChannel::read(const libcamera::YamlObject &params,
return 0;
}
-void AgcChannel::disableAuto()
+void AgcChannel::disableAutoExposure()
{
fixedExposureTime_ = status_.exposureTime;
- fixedAnalogueGain_ = status_.analogueGain;
}
-void AgcChannel::enableAuto()
+void AgcChannel::enableAutoExposure()
{
fixedExposureTime_ = 0s;
+}
+
+bool AgcChannel::autoExposureEnabled() const
+{
+ return fixedExposureTime_ == 0s;
+}
+
+void AgcChannel::disableAutoGain()
+{
+ fixedAnalogueGain_ = status_.analogueGain;
+}
+
+void AgcChannel::enableAutoGain()
+{
fixedAnalogueGain_ = 0;
}
+bool AgcChannel::autoGainEnabled() const
+{
+ return fixedAnalogueGain_ == 0;
+}
+
unsigned int AgcChannel::getConvergenceFrames() const
{
/*
diff --git a/src/ipa/rpi/controller/rpi/agc_channel.h b/src/ipa/rpi/controller/rpi/agc_channel.h
index 734e5efd..fa697e6f 100644
--- a/src/ipa/rpi/controller/rpi/agc_channel.h
+++ b/src/ipa/rpi/controller/rpi/agc_channel.h
@@ -96,8 +96,12 @@ public:
void setMeteringMode(std::string const &meteringModeName);
void setExposureMode(std::string const &exposureModeName);
void setConstraintMode(std::string const &contraintModeName);
- void enableAuto();
- void disableAuto();
+ void enableAutoExposure();
+ void disableAutoExposure();
+ bool autoExposureEnabled() const;
+ void enableAutoGain();
+ void disableAutoGain();
+ bool autoGainEnabled() const;
void switchMode(CameraMode const &cameraMode, Metadata *metadata);
void prepare(Metadata *imageMetadata);
void process(StatisticsPtr &stats, DeviceStatus const &deviceStatus, Metadata *imageMetadata,
diff --git a/src/ipa/rpi/controller/rpi/awb.cpp b/src/ipa/rpi/controller/rpi/awb.cpp
index c277a176..8479ae40 100644
--- a/src/ipa/rpi/controller/rpi/awb.cpp
+++ b/src/ipa/rpi/controller/rpi/awb.cpp
@@ -293,6 +293,24 @@ void Awb::setManualGains(double manualR, double manualB)
}
}
+void Awb::setColourTemperature(double temperatureK)
+{
+ if (!config_.bayes) {
+ LOG(RPiAwb, Warning) << "AWB uncalibrated - cannot set colour temperature";
+ return;
+ }
+
+ temperatureK = config_.ctR.domain().clamp(temperatureK);
+ manualR_ = 1 / config_.ctR.eval(temperatureK);
+ manualB_ = 1 / config_.ctB.eval(temperatureK);
+
+ syncResults_.temperatureK = temperatureK;
+ syncResults_.gainR = manualR_;
+ syncResults_.gainG = 1.0;
+ syncResults_.gainB = manualB_;
+ prevSyncResults_ = syncResults_;
+}
+
void Awb::switchMode([[maybe_unused]] CameraMode const &cameraMode,
Metadata *metadata)
{
diff --git a/src/ipa/rpi/controller/rpi/awb.h b/src/ipa/rpi/controller/rpi/awb.h
index 5d628b47..86640f8f 100644
--- a/src/ipa/rpi/controller/rpi/awb.h
+++ b/src/ipa/rpi/controller/rpi/awb.h
@@ -105,6 +105,7 @@ public:
void initialValues(double &gainR, double &gainB) override;
void setMode(std::string const &name) override;
void setManualGains(double manualR, double manualB) override;
+ void setColourTemperature(double temperatureK) override;
void enableAuto() override;
void disableAuto() override;
void switchMode(CameraMode const &cameraMode, Metadata *metadata) override;
diff --git a/src/ipa/rpi/vc4/data/imx415.json b/src/ipa/rpi/vc4/data/imx415.json
new file mode 100755
index 00000000..6ed16b17
--- /dev/null
+++ b/src/ipa/rpi/vc4/data/imx415.json
@@ -0,0 +1,413 @@
+{
+ "version": 2.0,
+ "target": "bcm2835",
+ "algorithms": [
+ {
+ "rpi.black_level":
+ {
+ "black_level": 3840
+ }
+ },
+ {
+ "rpi.dpc": { }
+ },
+ {
+ "rpi.lux":
+ {
+ "reference_shutter_speed": 19230,
+ "reference_gain": 1.0,
+ "reference_aperture": 1.0,
+ "reference_lux": 1198,
+ "reference_Y": 14876
+ }
+ },
+ {
+ "rpi.noise":
+ {
+ "reference_constant": 17,
+ "reference_slope": 3.439
+ }
+ },
+ {
+ "rpi.geq":
+ {
+ "offset": 193,
+ "slope": 0.00902
+ }
+ },
+ {
+ "rpi.sdn": { }
+ },
+ {
+ "rpi.awb":
+ {
+ "priors": [
+ {
+ "lux": 0,
+ "prior":
+ [
+ 2000, 1.0,
+ 3000, 0.0,
+ 13000, 0.0
+ ]
+ },
+ {
+ "lux": 800,
+ "prior":
+ [
+ 2000, 0.0,
+ 6000, 2.0,
+ 13000, 2.0
+ ]
+ },
+ {
+ "lux": 1500,
+ "prior":
+ [
+ 2000, 0.0,
+ 4000, 1.0,
+ 6000, 6.0,
+ 6500, 7.0,
+ 7000, 1.0,
+ 13000, 1.0
+ ]
+ }
+ ],
+ "modes":
+ {
+ "auto":
+ {
+ "lo": 2500,
+ "hi": 8000
+ },
+ "incandescent":
+ {
+ "lo": 2500,
+ "hi": 3000
+ },
+ "tungsten":
+ {
+ "lo": 3000,
+ "hi": 3500
+ },
+ "fluorescent":
+ {
+ "lo": 4000,
+ "hi": 4700
+ },
+ "indoor":
+ {
+ "lo": 3000,
+ "hi": 5000
+ },
+ "daylight":
+ {
+ "lo": 5500,
+ "hi": 6500
+ },
+ "cloudy":
+ {
+ "lo": 7000,
+ "hi": 8600
+ }
+ },
+ "bayes": 1,
+ "ct_curve":
+ [
+ 2698.0, 0.7681, 0.2026,
+ 2930.0, 0.7515, 0.2116,
+ 3643.0, 0.6355, 0.2858,
+ 4605.0, 0.4992, 0.4041,
+ 5658.0, 0.4498, 0.4574
+ ],
+ "sensitivity_r": 1.0,
+ "sensitivity_b": 1.0,
+ "transverse_pos": 0.0112,
+ "transverse_neg": 0.01424
+ }
+ },
+ {
+ "rpi.agc":
+ {
+ "metering_modes":
+ {
+ "centre-weighted":
+ {
+ "weights":
+ [
+ 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0
+ ]
+ },
+ "spot":
+ {
+ "weights":
+ [
+ 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ ]
+ },
+ "matrix":
+ {
+ "weights":
+ [
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+ ]
+ }
+ },
+ "exposure_modes":
+ {
+ "normal":
+ {
+ "shutter": [ 100, 10000, 30000, 60000, 120000 ],
+ "gain": [ 1.0, 2.0, 4.0, 6.0, 6.0 ]
+ },
+ "short":
+ {
+ "shutter": [ 100, 5000, 10000, 20000, 120000 ],
+ "gain": [ 1.0, 2.0, 4.0, 6.0, 6.0 ]
+ }
+ },
+ "constraint_modes":
+ {
+ "normal": [
+ {
+ "bound": "LOWER",
+ "q_lo": 0.98,
+ "q_hi": 1.0,
+ "y_target":
+ [
+ 0, 0.5,
+ 1000, 0.5
+ ]
+ }
+ ],
+ "highlight": [
+ {
+ "bound": "LOWER",
+ "q_lo": 0.98,
+ "q_hi": 1.0,
+ "y_target":
+ [
+ 0, 0.5,
+ 1000, 0.5
+ ]
+ },
+ {
+ "bound": "UPPER",
+ "q_lo": 0.98,
+ "q_hi": 1.0,
+ "y_target":
+ [
+ 0, 0.8,
+ 1000, 0.8
+ ]
+ }
+ ]
+ },
+ "y_target":
+ [
+ 0, 0.16,
+ 1000, 0.165,
+ 10000, 0.17
+ ]
+ }
+ },
+ {
+ "rpi.alsc":
+ {
+ "omega": 1.3,
+ "n_iter": 100,
+ "luminance_strength": 0.8,
+ "calibrations_Cr": [
+ {
+ "ct": 3000,
+ "table":
+ [
+ 1.025, 1.016, 1.013, 1.011, 1.008, 1.005, 1.003, 1.001, 1.003, 1.005, 1.008, 1.011, 1.014, 1.019, 1.027, 1.035,
+ 1.025, 1.017, 1.013, 1.011, 1.008, 1.005, 1.003, 1.003, 1.004, 1.005, 1.009, 1.012, 1.017, 1.023, 1.029, 1.035,
+ 1.022, 1.017, 1.013, 1.009, 1.007, 1.005, 1.003, 1.003, 1.004, 1.006, 1.009, 1.012, 1.017, 1.023, 1.029, 1.035,
+ 1.019, 1.015, 1.011, 1.007, 1.005, 1.003, 1.001, 1.001, 1.003, 1.004, 1.007, 1.009, 1.015, 1.022, 1.028, 1.035,
+ 1.018, 1.014, 1.009, 1.006, 1.004, 1.002, 1.001, 1.001, 1.001, 1.003, 1.006, 1.009, 1.015, 1.021, 1.028, 1.035,
+ 1.018, 1.013, 1.011, 1.006, 1.003, 1.002, 1.001, 1.001, 1.001, 1.003, 1.006, 1.009, 1.015, 1.022, 1.028, 1.036,
+ 1.018, 1.014, 1.011, 1.007, 1.004, 1.002, 1.001, 1.001, 1.001, 1.004, 1.007, 1.009, 1.015, 1.023, 1.029, 1.036,
+ 1.019, 1.014, 1.012, 1.008, 1.005, 1.003, 1.002, 1.001, 1.003, 1.005, 1.008, 1.012, 1.016, 1.024, 1.031, 1.037,
+ 1.021, 1.016, 1.013, 1.009, 1.008, 1.005, 1.003, 1.003, 1.005, 1.008, 1.011, 1.014, 1.019, 1.026, 1.033, 1.039,
+ 1.025, 1.021, 1.016, 1.013, 1.009, 1.008, 1.006, 1.006, 1.008, 1.011, 1.014, 1.019, 1.024, 1.031, 1.038, 1.046,
+ 1.029, 1.025, 1.021, 1.018, 1.014, 1.013, 1.011, 1.011, 1.012, 1.015, 1.019, 1.023, 1.028, 1.035, 1.046, 1.051,
+ 1.032, 1.029, 1.023, 1.021, 1.018, 1.015, 1.014, 1.014, 1.015, 1.018, 1.022, 1.027, 1.033, 1.041, 1.051, 1.054
+ ]
+ },
+ {
+ "ct": 5000,
+ "table":
+ [
+ 1.025, 1.011, 1.009, 1.005, 1.004, 1.003, 1.001, 1.001, 1.002, 1.006, 1.009, 1.012, 1.016, 1.021, 1.031, 1.041,
+ 1.025, 1.014, 1.009, 1.007, 1.005, 1.004, 1.003, 1.003, 1.004, 1.007, 1.009, 1.013, 1.021, 1.028, 1.037, 1.041,
+ 1.023, 1.014, 1.009, 1.007, 1.005, 1.004, 1.003, 1.003, 1.005, 1.007, 1.011, 1.014, 1.021, 1.028, 1.037, 1.048,
+ 1.022, 1.012, 1.007, 1.005, 1.002, 1.001, 1.001, 1.001, 1.003, 1.005, 1.009, 1.014, 1.019, 1.028, 1.039, 1.048,
+ 1.022, 1.011, 1.006, 1.003, 1.001, 1.001, 1.001, 1.001, 1.002, 1.005, 1.009, 1.014, 1.021, 1.029, 1.039, 1.051,
+ 1.022, 1.012, 1.007, 1.003, 1.002, 1.001, 1.001, 1.001, 1.002, 1.005, 1.009, 1.015, 1.021, 1.031, 1.041, 1.053,
+ 1.023, 1.013, 1.009, 1.005, 1.003, 1.003, 1.001, 1.002, 1.004, 1.006, 1.011, 1.015, 1.022, 1.031, 1.042, 1.056,
+ 1.024, 1.015, 1.012, 1.008, 1.005, 1.004, 1.004, 1.004, 1.006, 1.009, 1.013, 1.018, 1.024, 1.034, 1.045, 1.057,
+ 1.027, 1.017, 1.015, 1.012, 1.009, 1.007, 1.007, 1.008, 1.009, 1.013, 1.018, 1.023, 1.029, 1.038, 1.051, 1.061,
+ 1.029, 1.023, 1.017, 1.015, 1.014, 1.012, 1.011, 1.011, 1.014, 1.018, 1.024, 1.029, 1.036, 1.044, 1.056, 1.066,
+ 1.034, 1.028, 1.023, 1.022, 1.019, 1.019, 1.018, 1.018, 1.021, 1.025, 1.031, 1.035, 1.042, 1.053, 1.066, 1.074,
+ 1.041, 1.034, 1.027, 1.025, 1.025, 1.023, 1.023, 1.023, 1.025, 1.031, 1.035, 1.041, 1.049, 1.059, 1.074, 1.079
+ ]
+ }
+ ],
+ "calibrations_Cb": [
+ {
+ "ct": 3000,
+ "table":
+ [
+ 1.001, 1.001, 1.007, 1.015, 1.027, 1.034, 1.038, 1.041, 1.042, 1.043, 1.043, 1.043, 1.041, 1.039, 1.049, 1.054,
+ 1.011, 1.011, 1.013, 1.023, 1.032, 1.039, 1.044, 1.047, 1.052, 1.056, 1.059, 1.059, 1.055, 1.051, 1.054, 1.056,
+ 1.015, 1.015, 1.019, 1.032, 1.039, 1.044, 1.047, 1.052, 1.055, 1.059, 1.061, 1.066, 1.063, 1.058, 1.061, 1.064,
+ 1.016, 1.017, 1.023, 1.032, 1.041, 1.045, 1.048, 1.053, 1.056, 1.061, 1.066, 1.069, 1.067, 1.064, 1.065, 1.068,
+ 1.018, 1.019, 1.025, 1.033, 1.042, 1.045, 1.049, 1.054, 1.058, 1.063, 1.071, 1.072, 1.071, 1.068, 1.069, 1.071,
+ 1.023, 1.024, 1.029, 1.035, 1.043, 1.048, 1.052, 1.057, 1.061, 1.065, 1.074, 1.075, 1.075, 1.072, 1.072, 1.075,
+ 1.027, 1.028, 1.031, 1.038, 1.045, 1.051, 1.054, 1.059, 1.064, 1.068, 1.075, 1.079, 1.078, 1.075, 1.076, 1.081,
+ 1.029, 1.031, 1.033, 1.044, 1.048, 1.054, 1.059, 1.064, 1.067, 1.073, 1.079, 1.082, 1.082, 1.079, 1.081, 1.085,
+ 1.033, 1.033, 1.035, 1.047, 1.053, 1.058, 1.064, 1.067, 1.073, 1.079, 1.084, 1.086, 1.086, 1.084, 1.089, 1.091,
+ 1.037, 1.037, 1.038, 1.049, 1.057, 1.062, 1.068, 1.073, 1.079, 1.084, 1.089, 1.092, 1.092, 1.092, 1.096, 1.104,
+ 1.041, 1.041, 1.043, 1.051, 1.061, 1.068, 1.073, 1.079, 1.083, 1.089, 1.092, 1.094, 1.097, 1.099, 1.105, 1.115,
+ 1.048, 1.044, 1.044, 1.051, 1.063, 1.071, 1.076, 1.082, 1.088, 1.091, 1.094, 1.097, 1.099, 1.104, 1.115, 1.126
+ ]
+ },
+ {
+ "ct": 5000,
+ "table":
+ [
+ 1.001, 1.001, 1.005, 1.011, 1.014, 1.018, 1.019, 1.019, 1.019, 1.021, 1.021, 1.021, 1.019, 1.017, 1.014, 1.014,
+ 1.009, 1.009, 1.011, 1.014, 1.019, 1.024, 1.026, 1.029, 1.031, 1.032, 1.032, 1.031, 1.027, 1.023, 1.022, 1.022,
+ 1.011, 1.012, 1.015, 1.018, 1.024, 1.026, 1.029, 1.032, 1.035, 1.036, 1.036, 1.034, 1.031, 1.027, 1.025, 1.025,
+ 1.012, 1.013, 1.015, 1.019, 1.025, 1.029, 1.032, 1.035, 1.036, 1.038, 1.038, 1.036, 1.034, 1.029, 1.026, 1.026,
+ 1.013, 1.014, 1.016, 1.019, 1.027, 1.031, 1.034, 1.037, 1.039, 1.039, 1.041, 1.039, 1.036, 1.031, 1.028, 1.027,
+ 1.014, 1.014, 1.017, 1.021, 1.027, 1.033, 1.037, 1.039, 1.041, 1.041, 1.042, 1.042, 1.039, 1.033, 1.029, 1.028,
+ 1.015, 1.015, 1.018, 1.021, 1.027, 1.033, 1.037, 1.041, 1.041, 1.042, 1.042, 1.042, 1.039, 1.034, 1.029, 1.029,
+ 1.015, 1.016, 1.018, 1.022, 1.027, 1.033, 1.037, 1.041, 1.041, 1.042, 1.043, 1.043, 1.041, 1.035, 1.031, 1.031,
+ 1.015, 1.016, 1.018, 1.022, 1.027, 1.032, 1.037, 1.041, 1.042, 1.042, 1.044, 1.043, 1.041, 1.036, 1.034, 1.033,
+ 1.016, 1.017, 1.017, 1.022, 1.027, 1.032, 1.036, 1.039, 1.042, 1.042, 1.043, 1.043, 1.041, 1.039, 1.036, 1.034,
+ 1.017, 1.017, 1.018, 1.022, 1.027, 1.031, 1.035, 1.039, 1.041, 1.042, 1.042, 1.042, 1.042, 1.039, 1.039, 1.039,
+ 1.018, 1.017, 1.017, 1.021, 1.027, 1.031, 1.033, 1.038, 1.041, 1.041, 1.042, 1.042, 1.041, 1.041, 1.041, 1.041
+ ]
+ }
+ ],
+ "luminance_lut":
+ [
+ 2.102, 1.903, 1.658, 1.483, 1.358, 1.267, 1.202, 1.202, 1.202, 1.242, 1.323, 1.431, 1.585, 1.797, 2.096, 2.351,
+ 1.996, 1.776, 1.549, 1.385, 1.273, 1.204, 1.138, 1.133, 1.133, 1.185, 1.252, 1.343, 1.484, 1.679, 1.954, 2.228,
+ 1.923, 1.689, 1.474, 1.318, 1.204, 1.138, 1.079, 1.071, 1.071, 1.133, 1.185, 1.284, 1.415, 1.597, 1.854, 2.146,
+ 1.881, 1.631, 1.423, 1.272, 1.159, 1.079, 1.051, 1.026, 1.046, 1.071, 1.144, 1.245, 1.369, 1.543, 1.801, 2.095,
+ 1.867, 1.595, 1.391, 1.242, 1.131, 1.051, 1.013, 1.002, 1.013, 1.046, 1.121, 1.219, 1.343, 1.511, 1.752, 2.079,
+ 1.867, 1.589, 1.385, 1.236, 1.125, 1.048, 1.001, 1.001, 1.003, 1.045, 1.118, 1.217, 1.342, 1.511, 1.746, 2.079,
+ 1.867, 1.589, 1.385, 1.236, 1.125, 1.048, 1.011, 1.003, 1.011, 1.046, 1.118, 1.217, 1.343, 1.511, 1.746, 2.079,
+ 1.884, 1.621, 1.411, 1.261, 1.149, 1.071, 1.048, 1.024, 1.046, 1.069, 1.141, 1.239, 1.369, 1.541, 1.781, 2.093,
+ 1.913, 1.675, 1.459, 1.304, 1.191, 1.125, 1.071, 1.065, 1.069, 1.124, 1.181, 1.278, 1.413, 1.592, 1.842, 2.133,
+ 1.981, 1.755, 1.529, 1.368, 1.251, 1.191, 1.125, 1.124, 1.124, 1.181, 1.242, 1.337, 1.479, 1.669, 1.935, 2.207,
+ 2.078, 1.867, 1.625, 1.453, 1.344, 1.251, 1.202, 1.201, 1.201, 1.242, 1.333, 1.418, 1.571, 1.776, 2.063, 2.321,
+ 2.217, 2.011, 1.747, 1.562, 1.431, 1.331, 1.278, 1.278, 1.278, 1.313, 1.407, 1.523, 1.686, 1.911, 2.226, 2.484
+ ],
+ "sigma": 0.00135,
+ "sigma_Cb": 0.00279
+ }
+ },
+ {
+ "rpi.contrast":
+ {
+ "ce_enable": 1,
+ "gamma_curve":
+ [
+ 0, 0,
+ 1024, 5040,
+ 2048, 9338,
+ 3072, 12356,
+ 4096, 15312,
+ 5120, 18051,
+ 6144, 20790,
+ 7168, 23193,
+ 8192, 25744,
+ 9216, 27942,
+ 10240, 30035,
+ 11264, 32005,
+ 12288, 33975,
+ 13312, 35815,
+ 14336, 37600,
+ 15360, 39168,
+ 16384, 40642,
+ 18432, 43379,
+ 20480, 45749,
+ 22528, 47753,
+ 24576, 49621,
+ 26624, 51253,
+ 28672, 52698,
+ 30720, 53796,
+ 32768, 54876,
+ 36864, 57012,
+ 40960, 58656,
+ 45056, 59954,
+ 49152, 61183,
+ 53248, 62355,
+ 57344, 63419,
+ 61440, 64476,
+ 65535, 65535
+ ]
+ }
+ },
+ {
+ "rpi.ccm":
+ {
+ "ccms": [
+ {
+ "ct": 2698,
+ "ccm":
+ [
+ 1.57227, -0.32596, -0.24631,
+ -0.61264, 1.70791, -0.09526,
+ -0.43254, 0.48489, 0.94765
+ ]
+ },
+ {
+ "ct": 2930,
+ "ccm":
+ [
+ 1.69455, -0.52724, -0.16731,
+ -0.67131, 1.78468, -0.11338,
+ -0.41609, 0.54693, 0.86916
+ ]
+ },
+ {
+ "ct": 3643,
+ "ccm":
+ [
+ 1.74041, -0.77553, 0.03512,
+ -0.44073, 1.34131, 0.09943,
+ -0.11035, -0.93919, 2.04954
+ ]
+ },
+ {
+ "ct": 4605,
+ "ccm":
+ [
+ 1.49865, -0.41638, -0.08227,
+ -0.39445, 1.70114, -0.30669,
+ 0.01319, -0.88009, 1.86689
+ ]
+ },
+ {
+ "ct": 5658,
+ "ccm":
+ [
+ 1.38601, -0.23128, -0.15472,
+ -0.37641, 1.70444, -0.32803,
+ -0.01575, -0.71466, 1.73041
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "rpi.sharpen": { }
+ }
+ ]
+}
diff --git a/src/ipa/rpi/vc4/data/meson.build b/src/ipa/rpi/vc4/data/meson.build
index 94c0ee6e..7a8001ee 100644
--- a/src/ipa/rpi/vc4/data/meson.build
+++ b/src/ipa/rpi/vc4/data/meson.build
@@ -9,6 +9,7 @@ conf_files = files([
'imx296_mono.json',
'imx327.json',
'imx378.json',
+ 'imx415.json',
'imx462.json',
'imx477.json',
'imx477_noir.json',