summaryrefslogtreecommitdiff
path: root/src/ipa/ipu3/algorithms/awb.h
blob: a16dd68dcdb12104c6c8763d7b8b29a745561efc (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
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2021, Ideas On Board
 *
 * awb.h - IPU3 AWB control algorithm
 */
#ifndef __LIBCAMERA_IPU3_ALGORITHMS_AWB_H__
#define __LIBCAMERA_IPU3_ALGORITHMS_AWB_H__

#include <vector>

#include <linux/intel-ipu3.h>

#include <libcamera/geometry.h>

#include "algorithm.h"

namespace libcamera {

namespace ipa::ipu3::algorithms {

/* Region size for the statistics generation algorithm */
static constexpr uint32_t kAwbStatsSizeX = 16;
static constexpr uint32_t kAwbStatsSizeY = 12;

class Awb : public Algorithm
{
public:
	Awb();
	~Awb();

	void prepare(IPAContext &context, ipu3_uapi_params *params) override;
	void process(IPAContext &context, const ipu3_uapi_stats_3a *stats) override;

	struct Ipu3AwbCell {
		unsigned char greenRedAvg;
		unsigned char redAvg;
		unsigned char blueAvg;
		unsigned char greenBlueAvg;
		unsigned char satRatio;
		unsigned char padding[3];
	} __attribute__((packed));

	/* \todo Make these three structs available to all the ISPs ? */
	struct RGB {
		RGB(double _R = 0, double _G = 0, double _B = 0)
			: R(_R), G(_G), B(_B)
		{
		}
		double R, G, B;
		RGB &operator+=(RGB const &other)
		{
			R += other.R, G += other.G, B += other.B;
			return *this;
		}
	};

	struct IspStatsRegion {
		unsigned int counted;
		unsigned int uncounted;
		unsigned long long rSum;
		unsigned long long gSum;
		unsigned long long bSum;
	};

	struct AwbStatus {
		double temperatureK;
		double redGain;
		double greenGain;
		double blueGain;
	};

private:
	void calculateWBGains(const ipu3_uapi_stats_3a *stats,
			      const ipu3_uapi_grid_config &grid);
	void generateZones(std::vector<RGB> &zones);
	void generateAwbStats(const ipu3_uapi_stats_3a *stats,
			      const ipu3_uapi_grid_config &grid);
	void clearAwbStats();
	void awbGreyWorld();
	uint32_t estimateCCT(double red, double green, double blue);

	std::vector<RGB> zones_;
	IspStatsRegion awbStats_[kAwbStatsSizeX * kAwbStatsSizeY];
	AwbStatus asyncResults_;
};

} /* namespace ipa::ipu3::algorithms */

} /* namespace libcamera*/
#endif /* __LIBCAMERA_IPU3_ALGORITHMS_AWB_H__ */
lass="hl com"> * private to the plugin. */ enum { PROP_DEVICE_NAME = 1, }; #define GST_TYPE_LIBCAMERA_DEVICE gst_libcamera_device_get_type() G_DECLARE_FINAL_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_LIBCAMERA, DEVICE, GstDevice); struct _GstLibcameraDevice { GstDevice parent; gchar *name; }; G_DEFINE_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_TYPE_DEVICE); static GstElement * gst_libcamera_device_create_element(GstDevice *device, const gchar *name) { GstElement *source = gst_element_factory_make("libcamerasrc", name); /* * Provider and source lives in the same plugin, so making the source * should never fail. */ g_assert(source); g_object_set(source, "camera-name", GST_LIBCAMERA_DEVICE(device)->name, nullptr); return source; } static gboolean gst_libcamera_device_reconfigure_element(GstDevice *device, GstElement *element) { if (!GST_LIBCAMERA_IS_SRC(element)) return FALSE; g_object_set(element, "camera-name", GST_LIBCAMERA_DEVICE(device)->name, nullptr); return TRUE; } static void gst_libcamera_device_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstLibcameraDevice *device = GST_LIBCAMERA_DEVICE(object); switch (prop_id) { case PROP_DEVICE_NAME: device->name = g_value_dup_string(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void gst_libcamera_device_init(GstLibcameraDevice *self) { } static void gst_libcamera_device_finalize(GObject *object) { GstLibcameraDevice *self = GST_LIBCAMERA_DEVICE(object); gpointer klass = gst_libcamera_device_parent_class; g_free(self->name); G_OBJECT_GET_CLASS(klass)->finalize(object); } static void gst_libcamera_device_class_init(GstLibcameraDeviceClass *klass) { GstDeviceClass *device_class = GST_DEVICE_CLASS(klass); GObjectClass *object_class = G_OBJECT_CLASS(klass); device_class->create_element = gst_libcamera_device_create_element; device_class->reconfigure_element = gst_libcamera_device_reconfigure_element; object_class->set_property = gst_libcamera_device_set_property; object_class->finalize = gst_libcamera_device_finalize; GParamSpec *pspec = g_param_spec_string("name", "Name", "The name of the camera device", "", (GParamFlags)(G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property(object_class, PROP_DEVICE_NAME, pspec); } static GstDevice * gst_libcamera_device_new(const std::shared_ptr<Camera> &camera) { g_autoptr(GstCaps) caps = gst_caps_new_empty(); const gchar *name = camera->name().c_str(); StreamRoles roles; roles.push_back(StreamRole::VideoRecording); std::unique_ptr<CameraConfiguration> config = camera->generateConfiguration(roles); for (const StreamConfiguration &stream_cfg : *config) { GstCaps *sub_caps = gst_libcamera_stream_formats_to_caps(stream_cfg.formats()); if (sub_caps) gst_caps_append(caps, sub_caps); } return GST_DEVICE(g_object_new(GST_TYPE_LIBCAMERA_DEVICE, /* \todo Use a unique identifier instead of camera name. */ "name", name, "display-name", name, "caps", caps, "device-class", "Source/Video", nullptr)); } /** * \struct _GstLibcameraProvider * \brief libcamera GstDeviceProvider implementation * * This GstFeature is used by GstDeviceMonitor to probe the available * libcamera devices. The implementation is private to the plugin. */ struct _GstLibcameraProvider { GstDeviceProvider parent; CameraManager *cm; }; G_DEFINE_TYPE_WITH_CODE(GstLibcameraProvider, gst_libcamera_provider, GST_TYPE_DEVICE_PROVIDER, GST_DEBUG_CATEGORY_INIT(provider_debug, "libcamera-provider", 0, "libcamera Device Provider")); static GList * gst_libcamera_provider_probe(GstDeviceProvider *provider) { GstLibcameraProvider *self = GST_LIBCAMERA_PROVIDER(provider); CameraManager *cm = self->cm; GList *devices = nullptr; gint ret; GST_INFO_OBJECT(self, "Probing cameras using libcamera"); /* \todo Move the CameraMananger start()/stop() calls into * GstDeviceProvider start()/stop() virtual function when CameraMananger * gains monitoring support. Meanwhile we need to cycle start()/stop() * to ensure every probe() calls return the latest list. */ ret = cm->start(); if (ret) { GST_ERROR_OBJECT(self, "Failed to retrieve device list: %s", g_strerror(-ret)); return nullptr; } for (const std::shared_ptr<Camera> &camera : cm->cameras()) { GST_INFO_OBJECT(self, "Found camera '%s'", camera->name().c_str()); devices = g_list_append(devices, g_object_ref_sink(gst_libcamera_device_new(camera))); } cm->stop(); return devices; } static void gst_libcamera_provider_init(GstLibcameraProvider *self) { GstDeviceProvider *provider = GST_DEVICE_PROVIDER(self); self->cm = new CameraManager(); /* Avoid devices being duplicated. */ gst_device_provider_hide_provider(provider, "v4l2deviceprovider"); } static void gst_libcamera_provider_finalize(GObject *object) { GstLibcameraProvider *self = GST_LIBCAMERA_PROVIDER(object); gpointer klass = gst_libcamera_provider_parent_class; delete self->cm; return G_OBJECT_GET_CLASS(klass)->finalize(object); } static void gst_libcamera_provider_class_init(GstLibcameraProviderClass *klass) { GstDeviceProviderClass *provider_class = GST_DEVICE_PROVIDER_CLASS(klass); GObjectClass *object_class = G_OBJECT_CLASS(klass); provider_class->probe = gst_libcamera_provider_probe; object_class->finalize = gst_libcamera_provider_finalize; gst_device_provider_class_set_metadata(provider_class, "libcamera Device Provider", "Source/Video", "List camera device using libcamera", "Nicolas Dufresne <nicolas.dufresne@collabora.com>"); }