From patchwork Wed Aug 28 01:17:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1877 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id E0D6661580 for ; Wed, 28 Aug 2019 03:17:54 +0200 (CEST) X-Halon-ID: 9fc85ab8-c931-11e9-bdc3-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [95.195.154.80]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9fc85ab8-c931-11e9-bdc3-005056917a89; Wed, 28 Aug 2019 03:17:39 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 28 Aug 2019 03:17:09 +0200 Message-Id: <20190828011710.32128-13-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.22.1 In-Reply-To: <20190828011710.32128-1-niklas.soderlund@ragnatech.se> References: <20190828011710.32128-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 12/13] libcamera: ipa: rkisp1: Add basic control of auto exposure X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 28 Aug 2019 01:17:55 -0000 Add an IPA which controls the exposure time and analog gain for a sensor connected to the rkisp1 pipeline. The IPA supports turning AE on and off but lacks the support to inform the camera of the status of the AE control loop. Signed-off-by: Niklas Söderlund --- src/ipa/ipa_rkisp1.cpp | 165 +++++++++++++++++++++++++++++++++++++++++ src/ipa/meson.build | 1 + 2 files changed, 166 insertions(+) create mode 100644 src/ipa/ipa_rkisp1.cpp diff --git a/src/ipa/ipa_rkisp1.cpp b/src/ipa/ipa_rkisp1.cpp new file mode 100644 index 0000000000000000..950efb244cfe7879 --- /dev/null +++ b/src/ipa/ipa_rkisp1.cpp @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * ipa_rkisp1.cpp - RkISP1 Image Processing Algorithms + */ + +#include +#include + +#include + +#include +#include +#include +#include + +#include "log.h" +#include "utils.h" + +namespace libcamera { + +LOG_DEFINE_CATEGORY(IPARkISP1) + +class IPARkISP1 : public IPAInterface +{ +public: + int initSensor(const V4L2ControlInfoMap &controls) override; + void processRequest(const void *cookie, const ControlList &controls, + Buffer ¶meters) override; + void updateStatistics(const void *cookie, Buffer &statistics) override; + +private: + void setControls(); + + uint64_t statFrame_; + + /* Camera sensor controls. */ + bool autoExposure_; + uint64_t exposure_; + uint64_t minExposure_; + uint64_t maxExposure_; + uint64_t gain_; + uint64_t minGain_; + uint64_t maxGain_; +}; + +int IPARkISP1::initSensor(const V4L2ControlInfoMap &controls) +{ + statFrame_ = 0; + + const auto itExp = controls.find(V4L2_CID_EXPOSURE); + if (itExp == controls.end()) + return -ENODEV; + + const auto itGain = controls.find(V4L2_CID_ANALOGUE_GAIN); + if (itGain == controls.end()) + return -ENODEV; + + autoExposure_ = true; + + minExposure_ = std::max(itExp->second.min(), 1); + maxExposure_ = itExp->second.max(); + exposure_ = minExposure_; + + minGain_ = std::max(itGain->second.min(), 1); + maxGain_ = itGain->second.max(); + gain_ = minGain_; + + LOG(IPARkISP1, Info) + << "Exposure: " << minExposure_ << "-" << maxExposure_ + << " Gain: " << minGain_ << "-" << maxGain_; + + setControls(); + + return 0; +} + +void IPARkISP1::setControls() +{ + V4L2ControlList ctrls; + ctrls.add(V4L2_CID_EXPOSURE); + ctrls.add(V4L2_CID_ANALOGUE_GAIN); + ctrls[V4L2_CID_EXPOSURE]->setValue(exposure_); + ctrls[V4L2_CID_ANALOGUE_GAIN]->setValue(gain_); + + updateSensor.emit(ctrls); +} + +void IPARkISP1::processRequest(const void *cookie, const ControlList &controls, + Buffer ¶meters) +{ + rkisp1_isp_params_cfg *params = + static_cast(parameters.mem()->planes()[0].mem()); + + memset(params, 0, sizeof(*params)); + + /* Auto Exposure on/off*/ + if (controls.contains(AeEnable)) { + autoExposure_ = controls[AeEnable].getBool(); + if (autoExposure_) + params->module_ens = CIFISP_MODULE_AEC; + + params->module_en_update = CIFISP_MODULE_AEC; + } + + queueRequest.emit(cookie); +} + +void IPARkISP1::updateStatistics(const void *cookie, Buffer &statistics) +{ + const rkisp1_stat_buffer *stats = + static_cast(statistics.mem()->planes()[0].mem()); + const cifisp_stat *params = &stats->params; + + if ((stats->meas_type & CIFISP_STAT_AUTOEXP) && (statFrame_ % 2 == 0)) { + const cifisp_ae_stat *ae = ¶ms->ae; + + const unsigned int target = 60; + + unsigned int value = 0; + unsigned int num = 0; + for (int i = 0; i < CIFISP_AE_MEAN_MAX; i++) { + if (ae->exp_mean[i] > 15) { + value += ae->exp_mean[i]; + num++; + } + } + value /= num; + + double factor = (double)target / value; + double tmp; + + tmp = factor * exposure_ * gain_ / minGain_; + exposure_ = utils::clamp((uint64_t)tmp, minExposure_, maxExposure_); + + tmp = tmp / exposure_ * minGain_; + gain_ = utils::clamp((uint64_t)tmp, minGain_, maxGain_); + + setControls(); + } + + statFrame_++; +} + +/* + * External IPA module interface + */ + +extern "C" { +const struct IPAModuleInfo ipaModuleInfo = { + IPA_MODULE_API_VERSION, + 1, + "PipelineHandlerRkISP1", + "RkISP1 IPA", + "LGPL-2.1-or-later", +}; + +IPAInterface *ipaCreate() +{ + return new IPARkISP1(); +} +}; + +}; /* namespace libcamera */ diff --git a/src/ipa/meson.build b/src/ipa/meson.build index dca7a9461385b68d..16592a71e03990ce 100644 --- a/src/ipa/meson.build +++ b/src/ipa/meson.build @@ -1,6 +1,7 @@ ipa_dummy_sources = [ ['ipa_dummy', 'ipa_dummy.cpp'], ['ipa_dummy_isolate', 'ipa_dummy_isolate.cpp'], + ['ipa_rkisp1', 'ipa_rkisp1.cpp'], ] ipa_install_dir = join_paths(get_option('libdir'), 'libcamera')