/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2019-2023, Raspberry Pi Ltd
*
* Raspberry Pi IPA base class
*/
#include "ipa_base.h"
#include <cmath>
#include <libcamera/base/log.h>
#include <libcamera/base/span.h>
#include <libcamera/control_ids.h>
#include <libcamera/property_ids.h>
#include "controller/af_algorithm.h"
#include "controller/af_status.h"
#include "controller/agc_algorithm.h"
#include "controller/awb_algorithm.h"
#include "controller/awb_status.h"
#include "controller/black_level_status.h"
#include "controller/ccm_algorithm.h"
#include "controller/ccm_status.h"
#include "controller/contrast_algorithm.h"
#include "controller/denoise_algorithm.h"
#include "controller/hdr_algorithm.h"
#include "controller/lux_status.h"
#include "controller/sharpen_algorithm.h"
#include "controller/statistics.h"
namespace libcamera {
using namespace std::literals::chrono_literals;
using utils::Duration;
namespace {
/* Number of frame length times to hold in the queue. */
constexpr unsigned int FrameLengthsQueueSize = 10;
/* Configure the sensor with these values initially. */
constexpr double defaultAnalogueGain = 1.0;
constexpr Duration defaultExposureTime = 20.0ms;
constexpr Duration defaultMinFrameDuration = 1.0s / 30.0;
constexpr Duration defaultMaxFrameDuration = 250.0s;
/*
* Determine the minimum allowable inter-frame duration to run the controller
* algorithms. If the pipeline handler provider frames at a rate higher than this,
* we rate-limit the controller Prepare() and Process() calls to lower than or
* equal to this rate.
*/
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) },
{ &controls::ExposureTime, ControlInfo(0, 66666) },
{ &controls::AnalogueGain, ControlInfo(1.0f, 16.0f) },
{ &controls::AeMeteringMode, ControlInfo(controls::AeMeteringModeValues) },
{ &controls::AeConstraintMode, ControlInfo(controls::AeConstraintModeValues) },
{ &controls::AeExposureMode, ControlInfo(controls::AeExposureModeValues) },
{ &controls::ExposureValue, ControlInfo(-8.0f, 8.0f, 0.0f) },
{ &controls::AeFlickerMode, ControlInfo(static_cast<int>(controls::FlickerOff),
static_cast<int>(controls::FlickerManual),
static_cast<int>(controls::FlickerOff)) },
{ &controls::AeFlickerPeriod, ControlInfo(100, 1000000) },
{ &controls::Brightness, ControlInfo(-1.0f, 1.0f, 0.0f) },
{ &controls::Contrast, ControlInfo(0.0f, 32.0f, 1.0f) },
{ &controls::HdrMode, ControlInfo(controls::HdrModeValues) },
{ &controls::Sharpness, ControlInfo(0.0f, 16.0f, 1.0f) },
{ &controls::ScalerCrop, ControlInfo(Rectangle{}, Rectangle(65535, 65535, 65535, 65535), Rectangle{}) },
{ &controls::FrameDurationLimits, ControlInfo(INT64_C(33333), INT64_C(120000)) },
{ &controls::draft::NoiseReductionMode, ControlInfo(controls::draft::NoiseReductionModeValues) },
{ &controls::rpi::StatsOutputEnable, ControlInfo(false, true, false) },
};
/* IPA controls handled conditionally, if the sensor is not mono */
const ControlInfoMap::Map ipaColourControls{
{ &controls::AwbEnable, ControlInfo(false, true) },
{ &controls::AwbMode, ControlInfo(controls::AwbModeValues) },
{ &controls::ColourGains, ControlInfo(0.0f, 32.0f) },
{ &controls::Saturation, ControlInfo(0.0f, 32.0f, 1.0f) },
};
/* IPA controls handled conditionally, if the lens has a focus control */
const ControlInfoMap::Map ipaAfControls{
{ &controls::AfMode, ControlInfo(controls::AfModeValues) },
{ &controls::AfRange, ControlInfo(controls::AfRangeValues) },
{ &controls::AfSpeed, ControlInfo(controls::AfSpeedValues) },
{ &controls::AfMetering, ControlInfo(controls::AfMeteringValues) },
{ &controls::AfWindows, ControlInfo(Rectangle{}, Rectangle(65535, 65535, 65535, 65535), Rectangle{}) },
{ &controls::AfTrigger, ControlInfo(controls::AfTriggerValues) },
{ &controls::AfPause, ControlInfo(controls::AfPauseValues) },
{ &controls::LensPosition, ControlInfo(0.0f, 32.0f, 1.0f) }
};
/* Platform specific controls */
const std::map<const std::string, ControlInfoMap::Map> platformControls {
{ "pisp", {
{ &controls::rpi::ScalerCrops, ControlInfo(Rectangle{}, Rectangle(65535, 65535, 65535, 65535), Rectangle{}) }
} },
};
} /* namespace */
LOG_DEFINE_CATEGORY(IPARPI)
namespace ipa::RPi {
IpaBase::IpaBase()
: controller_(), frameLengths_(FrameLengthsQueueSize, 0s), statsMetadataOutput_(false),
stitchSwapBuffers_(false), frameCount_(0), mistrustCount_(0), lastRunTimestamp_(0),
firstStart_(true), flickerState_({ 0, 0s })
{
}
IpaBase::~IpaBase()
{
}
int32_t IpaBase::init(const IPASettings &settings, const InitParams ¶ms, InitResult *result)
{
/*
* Load the "helper" for this sensor. This tells us all the device specific stuff
* that the kernel driver doesn't. We only do this the first time; we don't need
* to re-parse the metadata after a simple mode-switch for no reason.
*/
helper_ = std::unique_ptr<RPiController::CamHelper>(RPiController::CamHelper::create(settings.sensorModel));
if (!helper_) {
LOG(IPARPI, Error) << "Could not create camera helper for "
<< settings.sensorModel;
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;
result->sensorConfig.sensorMetadata = sensorMetadata;
/* Load the tuning file for this sensor. */
int ret = controller_.read(settings.configurationFile.c_str());
if (ret) {
LOG(IPARPI, Error)
<< "Failed to load tuning data file "
<< settings.configurationFile;
return ret;
}
lensPresent_ = params.lensPresent;
controller_.initialise();
/* Return the controls handled by the IPA */
ControlInfoMap::Map ctrlMap = ipaControls;
if (lensPresent_)
ctrlMap.merge(ControlInfoMap::Map(ipaAfControls));
auto platformCtrlsIt = platformControls.find(controller_.getTarget());
if (platformCtrlsIt != platformControls.end())
ctrlMap.merge(ControlInfoMap::Map(platformCtrlsIt->second));
monoSensor_ = params.sensorInfo.cfaPattern == properties::draft::ColorFilterArrangementEnum::MONO;
if (!monoSensor_)
ctrlMap.merge(ControlInfoMap::Map(ipaColourControls));
result->controlInfo = ControlInfoMap(std::move(ctrlMap), controls::controls);
return platformInit(params, result);
}
int32_t IpaBase::configure(const IPACameraSensorInfo &sensorInfo, const ConfigParams ¶ms,
ConfigResult *result)
{
sensorCtrls_ = params.sensorControls;
if (!validateSensorControls()) {
LOG(IPARPI, Error) << "Sensor control validation failed.";
return -1;
}
if (lensPresent_) {
lensCtrls_ = params.lensControls;
if (!validateLensControls()) {
LOG(IPARPI, Warning) << "Lens validation failed, "
<< "no lens control will be available.";
lensPresent_ = false;
|