summaryrefslogtreecommitdiff
path: root/src/ipa/rpi/controller/rpi/agc_channel.h
blob: 4cf7233eef2503ae04c921504f6e951853a6b342 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* SPDX-License-Identifier: BSD-2-Clause */
/*
 * Copyright (C) 2023, Raspberry Pi Ltd
 *
 * agc_channel.h - AGC/AEC control algorithm
 */
#pragma once

#include <map>
#include <string>
#include <vector>

#include <libcamera/base/utils.h>

#include "../agc_status.h"
#include "../awb_status.h"
#include "../controller.h"
#include "../pwl.h"

/* This is our implementation of AGC. */

namespace RPiController {

using AgcChannelTotalExposures = std::vector<libcamera::utils::Duration>;

struct AgcMeteringMode {
	std::vector<double> weights;
	int read(const libcamera::YamlObject &params);
};

struct AgcExposureMode {
	std::vector<libcamera::utils::Duration> shutter;
	std::vector<double> gain;
	int read(const libcamera::YamlObject &params);
};

struct AgcConstraint {
	enum class Bound { LOWER = 0,
			   UPPER = 1 };
	Bound bound;
	double qLo;
	double qHi;
	Pwl yTarget;
	int read(const libcamera::YamlObject &params);
};

typedef std::vector<AgcConstraint> AgcConstraintMode;

struct AgcChannelConstraint {
	enum class Bound { LOWER = 0,
			   UPPER = 1 };
	Bound bound;
	unsigned int channel;
	double factor;
	int read(const libcamera::YamlObject &params);
};

struct AgcConfig {
	int read(const libcamera::YamlObject &params);
	std::map<std::string, AgcMeteringMode> meteringModes;
	std::map<std::string, AgcExposureMode> exposureModes;
	std::map<std::string, AgcConstraintMode> constraintModes;
	std::vector<AgcChannelConstraint> channelConstraints;
	Pwl yTarget;
	double speed;
	uint16_t startupFrames;
	unsigned int convergenceFrames;
	double maxChange;
	double minChange;
	double fastReduceThreshold;
	double speedUpThreshold;
	std::string defaultMeteringMode;
	std::string defaultExposureMode;
	std::string defaultConstraintMode;
	double baseEv;
	libcamera::utils::Duration defaultExposureTime;
	double defaultAnalogueGain;
	double stableRegion;
	bool desaturate;
};

class AgcChannel
{
public:
	AgcChannel();
	int read(const libcamera::YamlObject &params,
		 const Controller::HardwareConfig &hardwareConfig);
	unsigned int getConvergenceFrames() const;
	std::vector<double> const &getWeights() const;
	void setEv(double ev);
	void setFlickerPeriod(libcamera::utils::Duration flickerPeriod);
	void setMaxShutter(libcamera::utils::Duration maxShutter);
	void setFixedShutter(libcamera::utils::Duration fixedShutter);
	void setFixedAnalogueGain(double fixedAnalogueGain);
	void setMeteringMode(std::string const &meteringModeName);
	void setExposureMode(std::string const &exposureModeName);
	void setConstraintMode(std::string const &contraintModeName);
	void enableAuto();
	void disableAuto();
	void switchMode(CameraMode const &cameraMode, Metadata *metadata);
	void prepare(Metadata *imageMetadata);
	void process(StatisticsPtr &stats, DeviceStatus const &deviceStatus, Metadata *imageMetadata,
		     const AgcChannelTotalExposures &channelTotalExposures);

private:
	bool updateLockStatus(DeviceStatus const &deviceStatus);
	AgcConfig config_;
	void housekeepConfig();
	void fetchCurrentExposure(DeviceStatus const &deviceStatus);
	void fetchAwbStatus(Metadata *imageMetadata);
	void computeGain(StatisticsPtr &statistics, Metadata *imageMetadata,
			 double &gain, double &targetY);
	void computeTargetExposure(double gain);
	void filterExposure();
	bool applyChannelConstraints(const AgcChannelTotalExposures &channelTotalExposures);
	bool applyDigitalGain(double gain, double targetY, bool channelBound);
	void divideUpExposure();
	void writeAndFinish(Metadata *imageMetadata, bool desaturate);
	libcamera::utils::Duration limitShutter(libcamera::utils::Duration shutter);
	double limitGain(double gain) const;
	AgcMeteringMode *meteringMode_;
	AgcExposureMode *exposureMode_;
	AgcConstraintMode *constraintMode_;
	CameraMode mode_;
	uint64_t frameCount_;
	AwbStatus awb_;
	struct ExposureValues {
		ExposureValues();

		libcamera::utils::Duration shutter;
		double analogueGain;
		libcamera::utils::Duration totalExposure;
		libcamera::utils::Duration totalExposureNoDG; /* without digital gain */
	};
	ExposureValues current_; /* values for the current frame */
	ExposureValues target_; /* calculate the values we want here */
	ExposureValues filtered_; /* these values are filtered towards target */
	AgcStatus status_;
	int lockCount_;
	DeviceStatus lastDeviceStatus_;
	libcamera::utils::Duration lastTargetExposure_;
	/* Below here the "settings" that applications can change. */
	std::string meteringModeName_;
	std::string exposureModeName_;
	std::string constraintModeName_;
	double ev_;
	libcamera::utils::Duration flickerPeriod_;
	libcamera::utils::Duration maxShutter_;
	libcamera::utils::Duration fixedShutter_;
	double fixedAnalogueGain_;
};

} /* namespace RPiController */