summaryrefslogtreecommitdiff
path: root/src/ipa/raspberrypi/controller/rpi/geq.cpp
blob: b6c984141732320a53830ad420408ac10851f9bc (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
/* SPDX-License-Identifier: BSD-2-Clause */
/*
 * Copyright (C) 2019, Raspberry Pi (Trading) Limited
 *
 * geq.cpp - GEQ (green equalisation) control algorithm
 */

#include "../device_status.h"
#include "../logging.hpp"
#include "../lux_status.h"
#include "../pwl.hpp"

#include "geq.hpp"

using namespace RPiController;

// We use the lux status so that we can apply stronger settings in darkness (if
// necessary).

#define NAME "rpi.geq"

Geq::Geq(Controller *controller)
	: Algorithm(controller)
{
}

char const *Geq::Name() const
{
	return NAME;
}

void Geq::Read(boost::property_tree::ptree const &params)
{
	config_.offset = params.get<uint16_t>("offset", 0);
	config_.slope = params.get<double>("slope", 0.0);
	if (config_.slope < 0.0 || config_.slope >= 1.0)
		throw std::runtime_error("Geq: bad slope value");
	if (params.get_child_optional("strength"))
		config_.strength.Read(params.get_child("strength"));
}

void Geq::Prepare(Metadata *image_metadata)
{
	LuxStatus lux_status = {};
	lux_status.lux = 400;
	if (image_metadata->Get("lux.status", lux_status))
		RPI_WARN("Geq: no lux data found");
	DeviceStatus device_status = {};
	device_status.analogue_gain = 1.0; // in case not found
	if (image_metadata->Get("device.status", device_status))
		RPI_WARN("Geq: no device metadata - use analogue gain of 1x");
	GeqStatus geq_status = {};
	double strength =
		config_.strength.Empty()
			? 1.0
			: config_.strength.Eval(config_.strength.Domain().Clip(
				  lux_status.lux));
	strength *= device_status.analogue_gain;
	double offset = config_.offset * strength;
	double slope = config_.slope * strength;
	geq_status.offset = std::min(65535.0, std::max(0.0, offset));
	geq_status.slope = std::min(.99999, std::max(0.0, slope));
	RPI_LOG("Geq: offset " << geq_status.offset << " slope "
			       << geq_status.slope << " (analogue gain "
			       << device_status.analogue_gain << " lux "
			       << lux_status.lux << ")");
	image_metadata->Set("geq.status", geq_status);
}

// Register algorithm with the system.
static Algorithm *Create(Controller *controller)
{
	return (Algorithm *)new Geq(controller);
}
static RegisterAlgorithm reg(NAME, &Create);
> 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; case PROP_AUTO_FOCUS_MODE: device->auto_focus_mode = static_cast<controls::AfModeEnum>(g_value_get_enum(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void gst_libcamera_device_init([[maybe_unused]] 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_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); pspec = g_param_spec_enum("auto-focus-mode", "Set auto-focus mode", "Available options: AfModeManual, " "AfModeAuto or AfModeContinuous.", gst_libcamera_auto_focus_get_type(), static_cast<gint>(controls::AfModeManual), G_PARAM_WRITABLE); g_object_class_install_property(object_class, PROP_AUTO_FOCUS_MODE, pspec); } static GstDevice * gst_libcamera_device_new(const std::shared_ptr<Camera> &camera) { static const std::array roles{ StreamRole::VideoRecording }; g_autoptr(GstCaps) caps = gst_caps_new_empty(); const gchar *name = camera->id().c_str(); std::unique_ptr<CameraConfiguration> config = camera->generateConfiguration(roles); if (!config || config->size() != roles.size()) { GST_ERROR("Failed to generate a default configuration for %s", name); return nullptr; } 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; }; 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); std::shared_ptr<CameraManager> 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. */ cm = gst_libcamera_get_camera_manager(ret); 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->id().c_str()); GstDevice *dev = gst_libcamera_device_new(camera); if (!dev) { GST_ERROR_OBJECT(self, "Failed to add camera '%s'", camera->id().c_str()); return nullptr; } devices = g_list_append(devices, g_object_ref_sink(dev)); } return devices; } static void gst_libcamera_provider_init(GstLibcameraProvider *self) { GstDeviceProvider *provider = GST_DEVICE_PROVIDER(self); /* Avoid devices being duplicated. */ gst_device_provider_hide_provider(provider, "v4l2deviceprovider"); } static void gst_libcamera_provider_class_init(GstLibcameraProviderClass *klass) { GstDeviceProviderClass *provider_class = GST_DEVICE_PROVIDER_CLASS(klass); provider_class->probe = gst_libcamera_provider_probe; gst_device_provider_class_set_metadata(provider_class, "libcamera Device Provider", "Source/Video", "List camera device using libcamera", "Nicolas Dufresne <nicolas.dufresne@collabora.com>"); }