/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2018, Google Inc. * * utils.cpp - Miscellaneous utility tests */ #include #include #include #include #include #include #include #include #include "test.h" using namespace std; using namespace libcamera; using namespace std::literals::chrono_literals; class UtilsTest : public Test { protected: int testDirname() { static const std::vector paths = { "", "///", "/bin", "/usr/bin", "//etc////", "//tmp//d//", "current_file", "./current_file", "./current_dir/", "current_dir/", }; static const std::vector expected = { ".", "/", "/", "/usr", "/", "//tmp", ".", ".", ".", ".", }; std::vector results; for (const auto &path : paths) results.push_back(utils::dirname(path)); if (results != expected) { cerr << "utils::dirname() tests failed" << endl; cerr << "expected: " << endl; for (const auto &path : expected) cerr << "\t" << path << endl; cerr << "results: " << endl; for (const auto &path : results) cerr << "\t" << path << endl; return TestFail; } return TestPass; } int testEnumerate() { std::vector integers{ 1, 2, 3, 4, 5 }; int i = 0; for (auto [index, value] : utils::enumerate(integers)) { if (index != i || value != i + 1) { cerr << "utils::enumerate() test failed: i=" << i << ", index=" << index << ", value=" << value << std::endl; return TestFail; } /* Verify that we can modify the value. */ --value; ++i; } if (integers != std::vector{ 0, 1, 2, 3, 4 }) { cerr << "Failed to modify container in enumerated range loop" << endl; return TestFail; } Span span{ integers }; i = 0; for (auto [index, value] : utils::enumerate(span)) { if (index != i || value != i) { cerr << "utils::enumerate() test failed: i=" << i << ", index=" << index << ", value=" << value << std::endl; return TestFail; } ++i; } const int array[] = { 0, 2, 4, 6, 8 }; i = 0; for (auto [index, value] : utils::enumerate(array)) { if (index != i || value != i * 2) { cerr << "utils::enumerate() test failed: i=" << i << ", index=" << index << ", value=" << value << std::endl; return TestFail; } ++i; } return TestPass; } int testDuration() { std::ostringstream os; utils::Duration exposure; double ratio; exposure = 25ms + 25ms; if (exposure.get() != 50000.0) { cerr << "utils::Duration failed to return microsecond count"; return TestFail; } exposure = 1.0s / 4; if (exposure != 250ms) { cerr << "utils::Duration failed scalar divide test"; return TestFail; } exposure = 5000.5us; if (!exposure) { cerr << "utils::Duration failed boolean test"; return TestFail; } os << exposure; if (os.str() != "5000.50us") { cerr << "utils::Duration operator << failed"; return TestFail; } exposure = 100ms; ratio = exposure / 25ms; if (ratio != 4.0) { cerr << "utils::Duration failed ratio test"; return TestFail; } return TestPass; } int run() { /* utils::hex() test. */ std::ostringstream os; std::string ref; os << utils::hex(static_cast(0x42)) << " "; ref += "0x00000042 "; os << utils::hex(static_cast(0x42)) << " "; ref += "0x00000042 "; os << utils::hex(static_cast(0x42)) << " "; ref += "0x0000000000000042 "; os << utils::hex(static_cast(0x42)) << " "; ref += "0x0000000000000042 "; os << utils::hex(static_cast(0x42), 4) << " "; ref += "0x0042 "; os << utils::hex(static_cast(0x42), 1) << " "; ref += "0x42 "; os << utils::hex(static_cast(0x42), 4) << " "; ref += "0x0042 "; os << utils::hex(static_cast(0x42), 1) << " "; ref += "0x42 "; std::string s = os.str(); if (s != ref) { cerr << "utils::hex() test failed, expected '" << ref << "', got '" << s << "'"; return TestFail; } /* utils::join() and utils::split() test. */ std::vector elements = { "/bin", "/usr/bin", "", "", }; std::string path; for (const auto &element : elements) path += (path.empty() ? "" : ":") + element; if (path != utils::join(elements, ":")) { cerr << "utils::join() test failed" << endl; return TestFail; } std::vector dirs; for (const auto &dir : utils::split(path, ":")) dirs.push_back(dir); if (dirs != elements) { cerr << "utils::split() test failed" << endl; return TestFail; } /* utils::join() with conversion function test. */ std::vector sizes = { { 0, 0 }, { 100, 100 } }; s = utils::join(sizes, "/", [](const Size &size) { return size.toString(); }); if (s != "0x0/100x100") { cerr << "utils::join() with conversion test failed" << endl; return TestFail; } /* utils::dirname() tests. */ if (TestPass != testDirname()) return TestFail; /* utils::map_keys() test. */ const std::map map{ { "zero", 0 }, { "one", 1 }, { "two", 2 }, }; std::vector expectedKeys{ "zero", "one", "two", }; std::sort(expectedKeys.begin(), expectedKeys.end()); const std::vector keys = utils::map_keys(map); if (keys != expectedKeys) { cerr << "utils::map_keys() test failed" << endl; return TestFail; } /* utils::alignUp() and utils::alignDown() tests. */ if (utils::alignDown(6, 3) != 6 || utils::alignDown(7, 3) != 6) { cerr << "utils::alignDown test failed" << endl; return TestFail; } if (utils::alignUp(6, 3) != 6 || utils::alignU/* SPDX-License-Identifier: BSD-2-Clause */ /* * Copyright (C) 2019, Raspberry Pi (Trading) Limited * * noise.cpp - Noise control algorithm */ #include <math.h> #include "libcamera/internal/log.h" #include "../device_status.h" #include "../noise_status.h" #include "noise.hpp" using namespace RPiController; using namespace libcamera; LOG_DEFINE_CATEGORY(RPiNoise) #define NAME "rpi.noise" Noise::Noise(Controller *controller) : Algorithm(controller), mode_factor_(1.0) { } char const *Noise::Name() const { return NAME; } void Noise::SwitchMode(CameraMode const &camera_mode, [[maybe_unused]] Metadata *metadata) { // For example, we would expect a 2x2 binned mode to have a "noise // factor" of sqrt(2x2) = 2. (can't be less than one, right?) mode_factor_ = std::max(1.0, camera_mode.noise_factor); } void Noise::Read(boost::property_tree::ptree const &params) { reference_constant_ = params.get<double>("reference_constant"); reference_slope_ = params.get<double>("reference_slope"); } void Noise::Prepare(Metadata *image_metadata) { struct DeviceStatus device_status; device_status.analogue_gain = 1.0; // keep compiler calm if (image_metadata->Get("device.status", device_status) == 0) { // There is a slight question as to exactly how the noise // profile, specifically the constant part of it, scales. For // now we assume it all scales the same, and we'll revisit this // if it proves substantially wrong. NOTE: we may also want to // make some adjustments based on the camera mode (such as // binning), if we knew how to discover it... double factor = sqrt(device_status.analogue_gain) / mode_factor_; struct NoiseStatus status; status.noise_constant = reference_constant_ * factor; status.noise_slope = reference_slope_ * factor; image_metadata->Set("noise.status", status); LOG(RPiNoise, Debug) << "constant " << status.noise_constant << " slope " << status.noise_slope; } else LOG(RPiNoise, Warning) << " no metadata"; } // Register algorithm with the system. static Algorithm *Create(Controller *controller) { return new Noise(controller); } static RegisterAlgorithm reg(NAME, &Create);