/* 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 #include #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(0); offset01 = tuningData["offset01"].get(0); offset10 = tuningData["offset10"].get(0); offset11 = tuningData["offset11"].get(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 = ¶ms->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(offset00 >> 4), static_cast(offset01 >> 4), static_cast(offset10 >> 4), static_cast(offset11 >> 4), }); } REGISTER_IPA_ALGORITHM(BlackLevelCorrection, "BlackLevelCorrection") } /* namespace ipa::mali_c55::algorithms */ } /* namespace libcamera */