[RFC PATCH 1/2] libcamera: bitdepth: Add BitDepth implementation
Isaac Scott
isaac.scott at ideasonboard.com
Wed Nov 27 15:46:54 CET 2024
Add a class template that simplifies bit depth conversion. This
functionality allows users to avoid having to perform inline bitshifting
to convert values of one bit depth to another.
For example, this makes it easier to input values from datasheets, where
a value may be expressed in a certain bit depth. It also removes the
potential for human errors when making these conversions manually, and
in a lot of cases makes bit depth conversions more readable.
Signed-off-by: Isaac Scott <isaac.scott at ideasonboard.com>
---
src/ipa/libipa/bitdepth.h | 86 ++++++++++++++++++++++++++++
test/ipa/libipa/bitdepth.cpp | 107 +++++++++++++++++++++++++++++++++++
2 files changed, 193 insertions(+)
create mode 100644 src/ipa/libipa/bitdepth.h
create mode 100644 test/ipa/libipa/bitdepth.cpp
diff --git a/src/ipa/libipa/bitdepth.h b/src/ipa/libipa/bitdepth.h
new file mode 100644
index 00000000..145ee093
--- /dev/null
+++ b/src/ipa/libipa/bitdepth.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024 Ideas On Board Oy.
+ *
+ * BitDepth class to abstract bit shift operations
+ */
+
+#pragma once
+
+template<unsigned int BitDepth>
+class BitDepthValue
+{
+public:
+ static_assert(BitDepth > 0, "Bit depth must be positive");
+
+ BitDepthValue()
+ : value_(0) {}
+
+ BitDepthValue(int value)
+ : value_(value) {}
+
+ BitDepthValue(unsigned int value)
+ : value_(value) {}
+
+ template<unsigned int TargetBitDepth>
+ BitDepthValue<TargetBitDepth> convert() const
+ {
+ static_assert(TargetBitDepth > 0, "Bit depth must be positive");
+
+ unsigned int shift;
+
+ if constexpr (BitDepth > TargetBitDepth) {
+ shift = BitDepth - TargetBitDepth;
+ return BitDepthValue<TargetBitDepth>(value_ >> shift);
+ } else if constexpr (BitDepth < TargetBitDepth) {
+ shift = TargetBitDepth - BitDepth;
+ return BitDepthValue<TargetBitDepth>(value_ << shift);
+ } else {
+ return BitDepthValue<TargetBitDepth>(value_);
+ }
+ }
+
+ unsigned int value() const
+ {
+ return value_;
+ }
+
+ template<unsigned int TargetBitDepth>
+ operator BitDepthValue<TargetBitDepth>() const
+ {
+ return convert<TargetBitDepth>();
+ }
+
+ operator unsigned int() const
+ {
+ return value_;
+ }
+
+private:
+ unsigned int value_;
+};
+
+inline BitDepthValue<8> operator"" _8bit(unsigned long long value)
+{
+ return BitDepthValue<8>(static_cast<unsigned int>(value));
+}
+
+inline BitDepthValue<10> operator"" _10bit(unsigned long long value)
+{
+ return BitDepthValue<10>(static_cast<unsigned int>(value));
+}
+
+inline BitDepthValue<12> operator"" _12bit(unsigned long long value)
+{
+ return BitDepthValue<12>(static_cast<unsigned int>(value));
+}
+
+inline BitDepthValue<14> operator"" _14bit(unsigned long long value)
+{
+ return BitDepthValue<14>(static_cast<unsigned int>(value));
+}
+
+inline BitDepthValue<16> operator"" _16bit(unsigned long long value)
+{
+ return BitDepthValue<16>(static_cast<unsigned int>(value));
+}
diff --git a/test/ipa/libipa/bitdepth.cpp b/test/ipa/libipa/bitdepth.cpp
new file mode 100644
index 00000000..d854637d
--- /dev/null
+++ b/test/ipa/libipa/bitdepth.cpp
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2024 Ideas On Board Oy.
+ *
+ * BitDepth converter tests
+ */
+
+#include "../../../src/ipa/libipa/bitdepth.h"
+
+#include <cmath>
+#include <iostream>
+#include <map>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <libcamera/base/log.h>
+
+#include "../../libtest/test.h"
+using namespace std;
+
+#define ASSERT_EQ(a, b) \
+ if ((a) != (b)) { \
+ printf(#a " != " #b "\n"); \
+ return TestFail; \
+ }
+
+class BitDepthConverterTest : public Test
+{
+protected:
+ int run()
+ {
+ /* 10-bit to 16-bit conversion */
+ BitDepthValue<10> value10bit = 64_10bit;
+ BitDepthValue<16> value16bit = value10bit.convert<16>();
+ ASSERT_EQ(value16bit.value(), 4096);
+
+ /* Convert implicitly from another BitDepthValue */
+ value10bit = BitDepthValue<8>(16);
+ ASSERT_EQ(value10bit.value(), 64);
+ value10bit = 1_8bit;
+ ASSERT_EQ(value10bit.value(), 4);
+
+ /* Read value explicity and implicitly */
+ value10bit = BitDepthValue<10>(64);
+ ASSERT_EQ(value10bit.value(), 64);
+ ASSERT_EQ(value10bit, 64);
+
+ /* 12-bit to 8-bit conversion */
+ BitDepthValue<12> value12bit = 4096_12bit;
+ BitDepthValue<8> value8bit = value12bit.convert<8>();
+ ASSERT_EQ(value8bit.value(), 256);
+
+ /* Explicit bit depth assignment and conversion */
+ value16bit = 32768_16bit;
+ value12bit = value16bit.convert<12>();
+ ASSERT_EQ(value12bit.value(), 2048);
+
+ /* Test hex conversion */
+ value8bit = 0xFF_8bit;
+ ASSERT_EQ(value8bit, 255);
+
+ /* Test conversion to same bit depth makes no difference */
+ value16bit = 255_16bit;
+ value16bit = value16bit.convert<16>();
+ ASSERT_EQ(value16bit, 255);
+
+ /* Implicit bit depth assignment */
+ value12bit = 10;
+ ASSERT_EQ(value12bit.value(), 10);
+
+ /* 8-bit to 12-bit conversion */
+ value8bit = 128_8bit;
+ value12bit = value8bit.convert<12>();
+ ASSERT_EQ(value12bit.value(), 2048);
+
+ /* 16-bit to 8-bit conversion */
+ value16bit = 65535_16bit;
+ value8bit = value16bit.convert<8>();
+ ASSERT_EQ(value8bit.value(), 255);
+
+ /* Implicit assignment with int */
+ value8bit = 200;
+ ASSERT_EQ(value8bit.value(), 200);
+
+ /* 8-bit to 16-bit and back again */
+ value8bit = 150_8bit;
+ value16bit = value8bit.convert<16>();
+ value8bit = value16bit.convert<8>();
+ ASSERT_EQ(value8bit.value(), 150);
+
+ /* 12-bit to 16-bit and back again */
+ value12bit = 3000_12bit;
+ value16bit = value12bit.convert<16>();
+ ASSERT_EQ(value12bit, 3000);
+ ASSERT_EQ(value16bit, 48000)
+ value12bit = value16bit.convert<12>();
+ ASSERT_EQ(value12bit.value(), 3000);
+
+ /* Test negatives fail */
+ //value12bit = BitDepthValue<-1>;
+
+ return TestPass;
+ }
+};
+
+TEST_REGISTER(BitDepthConverterTest)
--
2.43.0
More information about the libcamera-devel
mailing list