ipa: mali-c55: Add BLC Algorithm

Add a Black Level Correction algorithm.

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Acked-by: Nayden Kanchev  <nayden.kanchev@arm.com>
Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
This commit is contained in:
Jacopo Mondi 2024-11-15 12:25:37 +00:00 committed by Daniel Scally
parent e8cae247e8
commit fbea6a4c02
5 changed files with 194 additions and 0 deletions

View file

@ -0,0 +1,140 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2024, Ideas On Board
*
* Mali-C55 sensor offset (black level) correction
*/
#include "blc.h"
#include <libcamera/base/log.h>
#include <libcamera/control_ids.h>
#include "libcamera/internal/yaml_parser.h"
/**
* \file blc.h
*/
namespace libcamera {
namespace ipa::mali_c55::algorithms {
/**
* \class BlackLevelCorrection
* \brief MaliC55 Black Level Correction control
*/
LOG_DEFINE_CATEGORY(MaliC55Blc)
BlackLevelCorrection::BlackLevelCorrection()
: tuningParameters_(false)
{
}
/**
* \copydoc libcamera::ipa::Algorithm::init
*/
int BlackLevelCorrection::init([[maybe_unused]] IPAContext &context,
const YamlObject &tuningData)
{
offset00 = tuningData["offset00"].get<uint32_t>(0);
offset01 = tuningData["offset01"].get<uint32_t>(0);
offset10 = tuningData["offset10"].get<uint32_t>(0);
offset11 = tuningData["offset11"].get<uint32_t>(0);
if (offset00 > kMaxOffset || offset01 > kMaxOffset ||
offset10 > kMaxOffset || offset11 > kMaxOffset) {
LOG(MaliC55Blc, Error) << "Invalid black level offsets";
return -EINVAL;
}
tuningParameters_ = true;
LOG(MaliC55Blc, Debug)
<< "Black levels: 00 " << offset00 << ", 01 " << offset01
<< ", 10 " << offset10 << ", 11 " << offset11;
return 0;
}
/**
* \copydoc libcamera::ipa::Algorithm::configure
*/
int BlackLevelCorrection::configure(IPAContext &context,
[[maybe_unused]] const IPACameraSensorInfo &configInfo)
{
/*
* If no Black Levels were passed in through tuning data then we could
* use the value from the CameraSensorHelper if one is available.
*/
if (context.configuration.sensor.blackLevel &&
!(offset00 + offset01 + offset10 + offset11)) {
offset00 = context.configuration.sensor.blackLevel;
offset01 = context.configuration.sensor.blackLevel;
offset10 = context.configuration.sensor.blackLevel;
offset11 = context.configuration.sensor.blackLevel;
}
return 0;
}
/**
* \copydoc libcamera::ipa::Algorithm::prepare
*/
void BlackLevelCorrection::prepare([[maybe_unused]] IPAContext &context,
const uint32_t frame,
[[maybe_unused]] IPAFrameContext &frameContext,
mali_c55_params_buffer *params)
{
mali_c55_params_block block;
block.data = &params->data[params->total_size];
if (frame > 0)
return;
if (!tuningParameters_)
return;
block.header->type = MALI_C55_PARAM_BLOCK_SENSOR_OFFS;
block.header->flags = MALI_C55_PARAM_BLOCK_FL_NONE;
block.header->size = sizeof(mali_c55_params_sensor_off_preshading);
block.sensor_offs->chan00 = offset00;
block.sensor_offs->chan01 = offset01;
block.sensor_offs->chan10 = offset10;
block.sensor_offs->chan11 = offset11;
params->total_size += block.header->size;
}
void BlackLevelCorrection::process([[maybe_unused]] IPAContext &context,
[[maybe_unused]] const uint32_t frame,
[[maybe_unused]] IPAFrameContext &frameContext,
[[maybe_unused]] const mali_c55_stats_buffer *stats,
ControlList &metadata)
{
/*
* Black Level Offsets in tuning data need to be 20-bit, whereas the
* metadata expects values from a 16-bit range. Right-shift to remove
* the 4 least significant bits.
*
* The black levels should be reported in the order R, Gr, Gb, B. We
* ignore that here given we're using matching values so far, but it
* would be safer to check the sensor's bayer order.
*
* \todo Account for bayer order.
*/
metadata.set(controls::SensorBlackLevels, {
static_cast<int32_t>(offset00 >> 4),
static_cast<int32_t>(offset01 >> 4),
static_cast<int32_t>(offset10 >> 4),
static_cast<int32_t>(offset11 >> 4),
});
}
REGISTER_IPA_ALGORITHM(BlackLevelCorrection, "BlackLevelCorrection")
} /* namespace ipa::mali_c55::algorithms */
} /* namespace libcamera */

View file

@ -0,0 +1,42 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2024, Ideas On Board
*
* Mali-C55 sensor offset (black level) correction
*/
#include "algorithm.h"
namespace libcamera {
namespace ipa::mali_c55::algorithms {
class BlackLevelCorrection : public Algorithm
{
public:
BlackLevelCorrection();
~BlackLevelCorrection() = default;
int init(IPAContext &context, const YamlObject &tuningData) override;
int configure(IPAContext &context,
const IPACameraSensorInfo &configInfo) override;
void prepare(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext,
mali_c55_params_buffer *params) override;
void process(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext,
const mali_c55_stats_buffer *stats,
ControlList &metadata) override;
private:
static constexpr uint32_t kMaxOffset = 0xfffff;
bool tuningParameters_;
uint32_t offset00;
uint32_t offset01;
uint32_t offset10;
uint32_t offset11;
};
} /* namespace ipa::mali_c55::algorithms */
} /* namespace libcamera */

View file

@ -2,4 +2,5 @@
mali_c55_ipa_algorithms = files([
'agc.cpp',
'blc.cpp',
])

View file

@ -30,6 +30,7 @@ struct IPASessionConfiguration {
struct {
BayerFormat::Order bayerOrder;
utils::Duration lineDuration;
uint32_t blackLevel;
} sensor;
};

View file

@ -193,6 +193,16 @@ void IPAMaliC55::updateSessionConfiguration(const IPACameraSensorInfo &info,
context_.configuration.agc.defaultExposure = defExposure;
context_.configuration.agc.minAnalogueGain = camHelper_->gain(minGain);
context_.configuration.agc.maxAnalogueGain = camHelper_->gain(maxGain);
if (camHelper_->blackLevel().has_value()) {
/*
* The black level from CameraSensorHelper is a 16-bit value.
* The Mali-C55 ISP expects 20-bit settings, so we shift it to
* the appropriate width
*/
context_.configuration.sensor.blackLevel =
camHelper_->blackLevel().value() << 4;
}
}
void IPAMaliC55::updateControls(const IPACameraSensorInfo &sensorInfo,