[libcamera-devel] [PATCH 12/13] libcamera: ipa: rkisp1: Add basic control of auto exposure

Niklas Söderlund niklas.soderlund at ragnatech.se
Wed Aug 28 03:17:09 CEST 2019


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 <niklas.soderlund at ragnatech.se>
---
 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 <algorithm>
+#include <string.h>
+
+#include <linux/rkisp1-config.h>
+
+#include <libcamera/buffer.h>
+#include <libcamera/ipa/ipa_interface.h>
+#include <libcamera/ipa/ipa_module_info.h>
+#include <libcamera/request.h>
+
+#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 &parameters) 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<uint64_t>(itExp->second.min(), 1);
+	maxExposure_ = itExp->second.max();
+	exposure_ = minExposure_;
+
+	minGain_ = std::max<uint64_t>(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 &parameters)
+{
+	rkisp1_isp_params_cfg *params =
+		static_cast<rkisp1_isp_params_cfg *>(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<rkisp1_stat_buffer *>(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 = &params->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>((uint64_t)tmp, minExposure_, maxExposure_);
+
+		tmp = tmp / exposure_ * minGain_;
+		gain_ = utils::clamp<uint64_t>((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')
-- 
2.22.1



More information about the libcamera-devel mailing list