From patchwork Thu Aug 29 23:26:52 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: 1900 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 B72FF60C37 for ; Fri, 30 Aug 2019 01:27:38 +0200 (CEST) X-Halon-ID: 937f8e65-cab4-11e9-837a-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [79.202.45.17]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 937f8e65-cab4-11e9-837a-0050569116f7; Fri, 30 Aug 2019 01:27:33 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Fri, 30 Aug 2019 01:26:52 +0200 Message-Id: <20190829232653.13214-14-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.22.1 In-Reply-To: <20190829232653.13214-1-niklas.soderlund@ragnatech.se> References: <20190829232653.13214-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 13/14] 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: Thu, 29 Aug 2019 23:27:39 -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 | 5 +- 2 files changed, 168 insertions(+), 2 deletions(-) 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..063b075d8358c30d --- /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..59311e6adae90ada 100644 --- a/src/ipa/meson.build +++ b/src/ipa/meson.build @@ -1,11 +1,12 @@ -ipa_dummy_sources = [ +ipa_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') -foreach t : ipa_dummy_sources +foreach t : ipa_sources ipa = shared_module(t[0], t[1], name_prefix : '',