summaryrefslogtreecommitdiff
path: root/src/android/camera_ops.cpp
blob: ecaac5a31c644b36b8399c28bf90a8dc9ce4279b (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
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * Android Camera HAL Operations
 */

#include "camera_ops.h"

#include <system/camera_metadata.h>

#include "camera_device.h"

using namespace libcamera;

/*
 * Translation layer between the Android Camera HAL device operations and the
 * CameraDevice.
 */

static int hal_dev_initialize(const struct camera3_device *dev,
			      const camera3_callback_ops_t *callback_ops)
{
	if (!dev)
		return -EINVAL;

	CameraDevice *camera = reinterpret_cast<CameraDevice *>(dev->priv);
	camera->setCallbacks(callback_ops);

	return 0;
}

static int hal_dev_configure_streams(const struct camera3_device *dev,
				     camera3_stream_configuration_t *stream_list)
{
	if (!dev)
		return -EINVAL;

	CameraDevice *camera = reinterpret_cast<CameraDevice *>(dev->priv);
	return camera->configureStreams(stream_list);
}

static const camera_metadata_t *
hal_dev_construct_default_request_settings(const struct camera3_device *dev,
					   int type)
{
	if (!dev)
		return nullptr;

	CameraDevice *camera = reinterpret_cast<CameraDevice *>(dev->priv);
	return camera->constructDefaultRequestSettings(type);
}

static int hal_dev_process_capture_request(const struct camera3_device *dev,
					   camera3_capture_request_t *request)
{
	if (!dev)
		return -EINVAL;

	CameraDevice *camera = reinterpret_cast<CameraDevice *>(dev->priv);
	return camera->processCaptureRequest(request);
}

static void hal_dev_dump([[maybe_unused]] const struct camera3_device *dev,
			 [[maybe_unused]] int fd)
{
}

static int hal_dev_flush(const struct camera3_device *dev)
{
	if (!dev)
		return -EINVAL;

	CameraDevice *camera = reinterpret_cast<CameraDevice *>(dev->priv);
	camera->flush();

	return 0;
}

int hal_dev_close(hw_device_t *hw_device)
{
	if (!hw_device)
		return -EINVAL;

	camera3_device_t *dev = reinterpret_cast<camera3_device_t *>(hw_device);
	CameraDevice *camera = reinterpret_cast<CameraDevice *>(dev->priv);

	camera->close();

	return 0;
}

camera3_device_ops hal_dev_ops = {
	.initialize = hal_dev_initialize,
	.configure_streams = hal_dev_configure_streams,
	.register_stream_buffers = nullptr,
	.construct_default_request_settings = hal_dev_construct_default_request_settings,
	.process_capture_request = hal_dev_process_capture_request,
	.get_metadata_vendor_tag_ops = nullptr,
	.dump = hal_dev_dump,
	.flush = hal_dev_flush,
	.reserved = { nullptr },
};
;double>("hi_max", 2000); config_.gamma_curve.Read(params.get_child("gamma_curve")); } void Contrast::SetBrightness(double brightness) { brightness_ = brightness; } void Contrast::SetContrast(double contrast) { contrast_ = contrast; } static void fill_in_status(ContrastStatus &status, double brightness, double contrast, Pwl &gamma_curve) { status.brightness = brightness; status.contrast = contrast; for (int i = 0; i < CONTRAST_NUM_POINTS - 1; i++) { int x = i < 16 ? i * 1024 : (i < 24 ? (i - 16) * 2048 + 16384 : (i - 24) * 4096 + 32768); status.points[i].x = x; status.points[i].y = std::min(65535.0, gamma_curve.Eval(x)); } status.points[CONTRAST_NUM_POINTS - 1].x = 65535; status.points[CONTRAST_NUM_POINTS - 1].y = 65535; } void Contrast::Initialise() { // Fill in some default values as Prepare will run before Process gets // called. fill_in_status(status_, brightness_, contrast_, config_.gamma_curve); } void Contrast::Prepare(Metadata *image_metadata) { std::unique_lock<std::mutex> lock(mutex_); image_metadata->Set("contrast.status", status_); } Pwl compute_stretch_curve(Histogram const &histogram, ContrastConfig const &config) { Pwl enhance; enhance.Append(0, 0); // If the start of the histogram is rather empty, try to pull it down a // bit. double hist_lo = histogram.Quantile(config.lo_histogram) * (65536 / NUM_HISTOGRAM_BINS); double level_lo = config.lo_level * 65536; LOG(RPiContrast, Debug) << "Move histogram point " << hist_lo << " to " << level_lo; hist_lo = std::max( level_lo, std::min(65535.0, std::min(hist_lo, level_lo + config.lo_max))); LOG(RPiContrast, Debug) << "Final values " << hist_lo << " -> " << level_lo; enhance.Append(hist_lo, level_lo); // Keep the mid-point (median) in the same place, though, to limit the // apparent amount of global brightness shift. double mid = histogram.Quantile(0.5) * (65536 / NUM_HISTOGRAM_BINS); enhance.Append(mid, mid); // If the top to the histogram is empty, try to pull the pixel values // there up. double hist_hi = histogram.Quantile(config.hi_histogram) * (65536 / NUM_HISTOGRAM_BINS); double level_hi = config.hi_level * 65536; LOG(RPiContrast, Debug) << "Move histogram point " << hist_hi << " to " << level_hi; hist_hi = std::min( level_hi, std::max(0.0, std::max(hist_hi, level_hi - config.hi_max))); LOG(RPiContrast, Debug) << "Final values " << hist_hi << " -> " << level_hi; enhance.Append(hist_hi, level_hi); enhance.Append(65535, 65535); return enhance; } Pwl apply_manual_contrast(Pwl const &gamma_curve, double brightness, double contrast) { Pwl new_gamma_curve; LOG(RPiContrast, Debug) << "Manual brightness " << brightness << " contrast " << contrast; gamma_curve.Map([&](double x, double y) { new_gamma_curve.Append( x, std::max(0.0, std::min(65535.0, (y - 32768) * contrast + 32768 + brightness))); }); return new_gamma_curve; } void Contrast::Process(StatisticsPtr &stats, [[maybe_unused]] Metadata *image_metadata) { Histogram histogram(stats->hist[0].g_hist, NUM_HISTOGRAM_BINS); // We look at the histogram and adjust the gamma curve in the following // ways: 1. Adjust the gamma curve so as to pull the start of the // histogram down, and possibly push the end up. Pwl gamma_curve = config_.gamma_curve; if (config_.ce_enable) { if (config_.lo_max != 0 || config_.hi_max != 0) gamma_curve = compute_stretch_curve(histogram, config_) .Compose(gamma_curve); // We could apply other adjustments (e.g. partial equalisation) // based on the histogram...? } // 2. Finally apply any manually selected brightness/contrast // adjustment. if (brightness_ != 0 || contrast_ != 1.0) gamma_curve = apply_manual_contrast(gamma_curve, brightness_, contrast_); // And fill in the status for output. Use more points towards the bottom // of the curve. ContrastStatus status; fill_in_status(status, brightness_, contrast_, gamma_curve); { std::unique_lock<std::mutex> lock(mutex_); status_ = status; } } // Register algorithm with the system. static Algorithm *Create(Controller *controller) { return (Algorithm *)new Contrast(controller); } static RegisterAlgorithm reg(NAME, &Create);