/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2022, Theobroma Systems * * af.cpp - RkISP1 AF hill climbing based control algorithm */ #include "af.h" /** * \file af.h */ namespace libcamera::ipa::rkisp1::algorithms { /** * \class Af * \brief AF control algorithm */ LOG_DEFINE_CATEGORY(RkISP1Af) static rkisp1_cif_isp_window rectangleToIspWindow(const Rectangle &rectangle) { rkisp1_cif_isp_window ispwindow; ispwindow.h_offs = rectangle.x; ispwindow.v_offs = rectangle.y; ispwindow.h_size = rectangle.width; ispwindow.v_size = rectangle.height; return ispwindow; } /** * \copydoc libcamera::ipa::Algorithm::configure */ int Af::configure([[maybe_unused]] IPAContext &context, const IPACameraSensorInfo &configInfo) { /* Default AF window of 3/4 size of the screen placed at the center */ defaultWindow_ = Rectangle(configInfo.outputSize.width / 8, configInfo.outputSize.height / 8, 3 * configInfo.outputSize.width / 4, 3 * configInfo.outputSize.height / 4); updateCurrentWindow(defaultWindow_); return 0; } /** * \copydoc libcamera::ipa::Algorithm::prepare */ void Af::prepare([[maybe_unused]] IPAContext &context, rkisp1_params_cfg *params) { if (updateAfwindow_) { params->meas.afc_config.num_afm_win = 1; params->meas.afc_config.thres = 128; params->meas.afc_config.var_shift = 4; /* \todo Allow setting thres and var_shift in tuning file */ params->meas.afc_config.afm_win[0] = rectangleToIspWindow(currentWindow_); params->module_cfg_update |= RKISP1_CIF_ISP_MODULE_AFC; params->module_ens |= RKISP1_CIF_ISP_MODULE_AFC; params->module_en_update |= RKISP1_CIF_ISP_MODULE_AFC; updateAfwindow_ = false; } } /** * \copydoc libcamera::ipa::Algorithm::process */ void Af::process(IPAContext &context, [[maybe_unused]] IPAFrameContext *frameCtx, const rkisp1_stat_buffer *stats) { uint32_t sharpness = stats->params.af.window[0].sum; uint32_t luminance = stats->params.af.window[0].lum; LOG(RkISP1Af, Debug) << "lensPosition: " << context.frameContext.af.focus << ", Sharpness: " << sharpness << ", Luminance: " << luminance; uint32_t lensPosition = processAutofocus(sharpness); context.frameContext.af.focus = lensPosition; } void Af::setMetering(controls::AfMeteringEnum metering) { if (metering == meteringMode_) return; if (metering == controls::AfMeteringWindows) { updateCurrentWindow(userWindow_); } else { updateCurrentWindow(defaultWindow_); } meteringMode_ = metering; } void Af::setWindows(Span windows) { if (windows.size() != 1) { LOG(RkISP1Af, Error) << "Only one AF window is supported"; return; } /* \todo Check if window size is valid for ISP */ LOG(RkISP1Af, Debug) << "setWindows: " << userWindow_; userWindow_ = windows[0]; if (meteringMode_ == controls::AfMeteringWindows) { updateCurrentWindow(userWindow_); } } void Af::updateCurrentWindow(const Rectangle &window) { currentWindow_ = window; updateAfwindow_ = true; } REGISTER_IPA_ALGORITHM(Af, "Af") } /* namespace libcamera::ipa::rkisp1::algorithms */