summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcamera/bayer_format.cpp268
-rw-r--r--src/libcamera/meson.build1
2 files changed, 269 insertions, 0 deletions
diff --git a/src/libcamera/bayer_format.cpp b/src/libcamera/bayer_format.cpp
new file mode 100644
index 00000000..c42792ff
--- /dev/null
+++ b/src/libcamera/bayer_format.cpp
@@ -0,0 +1,268 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2020, Raspberry Pi (Trading) Limited
+ *
+ * bayer_format.cpp - Class to represent Bayer formats
+ */
+
+#include "libcamera/internal/bayer_format.h"
+
+#include <map>
+
+#include <libcamera/transform.h>
+
+/**
+ * \file bayer_format.h
+ * \brief Class to represent Bayer formats and manipulate them
+ */
+
+namespace libcamera {
+
+/**
+ * \class BayerFormat
+ * \brief Class to represent a raw image Bayer format
+ *
+ * This class encodes the different Bayer formats in such a way that they can
+ * be easily manipulated. For example, the bit depth or Bayer order can be
+ * easily altered - the Bayer order can even be "transformed" in the same
+ * manner as happens in many sensors when their horizontal or vertical "flip"
+ * controls are set.
+ */
+
+/**
+ * \enum BayerFormat::Order
+ * \brief The order of the colour channels in the Bayer pattern
+ *
+ * \var BayerFormat::BGGR
+ * \brief B then G on the first row, G then R on the second row.
+ * \var BayerFormat::GBRG
+ * \brief G then B on the first row, R then G on the second row.
+ * \var BayerFormat::GRBG
+ * \brief G then R on the first row, B then G on the second row.
+ * \var BayerFormat::RGGB
+ * \brief R then G on the first row, G then B on the second row.
+ */
+
+/**
+ * \enum BayerFormat::Packing
+ * \brief Different types of packing that can be applied to a BayerFormat
+ *
+ * \var BayerFormat::None
+ * \brief No packing
+ * \var BayerFormat::CSI2Packed
+ * \brief Format uses MIPI CSI-2 style packing
+ * \var BayerFormat::IPU3Packed
+ * \brief Format uses IPU3 style packing
+ */
+
+namespace {
+
+const std::map<V4L2PixelFormat, BayerFormat> v4l2ToBayer{
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR8), { BayerFormat::BGGR, 8, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG8), { BayerFormat::GBRG, 8, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG8), { BayerFormat::GRBG, 8, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB8), { BayerFormat::RGGB, 8, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10), { BayerFormat::BGGR, 10, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10), { BayerFormat::GBRG, 10, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10), { BayerFormat::GRBG, 10, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10), { BayerFormat::RGGB, 10, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10P), { BayerFormat::BGGR, 10, BayerFormat::CSI2Packed } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10P), { BayerFormat::GBRG, 10, BayerFormat::CSI2Packed } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10P), { BayerFormat::GRBG, 10, BayerFormat::CSI2Packed } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P), { BayerFormat::RGGB, 10, BayerFormat::CSI2Packed } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SBGGR10), { BayerFormat::BGGR, 10, BayerFormat::IPU3Packed } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGBRG10), { BayerFormat::GBRG, 10, BayerFormat::IPU3Packed } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGRBG10), { BayerFormat::GRBG, 10, BayerFormat::IPU3Packed } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SRGGB10), { BayerFormat::RGGB, 10, BayerFormat::IPU3Packed } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12), { BayerFormat::BGGR, 12, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12), { BayerFormat::GBRG, 12, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12), { BayerFormat::GRBG, 12, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12), { BayerFormat::RGGB, 12, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12P), { BayerFormat::BGGR, 12, BayerFormat::CSI2Packed } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12P), { BayerFormat::GBRG, 12, BayerFormat::CSI2Packed } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12P), { BayerFormat::GRBG, 12, BayerFormat::CSI2Packed } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12P), { BayerFormat::RGGB, 12, BayerFormat::CSI2Packed } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR16), { BayerFormat::BGGR, 16, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG16), { BayerFormat::GBRG, 16, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG16), { BayerFormat::GRBG, 16, BayerFormat::None } },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB16), { BayerFormat::RGGB, 16, BayerFormat::None } },
+};
+
+/* Define a slightly arbitrary ordering so that we can use a std::map. */
+struct BayerFormatComparator {
+ constexpr bool operator()(const BayerFormat &lhs, const BayerFormat &rhs) const
+ {
+ if (lhs.bitDepth < rhs.bitDepth)
+ return true;
+ else if (lhs.bitDepth > rhs.bitDepth)
+ return false;
+
+ if (lhs.order < rhs.order)
+ return true;
+ else if (lhs.order > rhs.order)
+ return false;
+
+ if (lhs.packing < rhs.packing)
+ return true;
+ else
+ return false;
+ }
+};
+
+const std::map<BayerFormat, V4L2PixelFormat, BayerFormatComparator> bayerToV4l2{
+ { { BayerFormat::BGGR, 8, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR8) },
+ { { BayerFormat::GBRG, 8, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG8) },
+ { { BayerFormat::GRBG, 8, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG8) },
+ { { BayerFormat::RGGB, 8, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB8) },
+ { { BayerFormat::BGGR, 10, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10) },
+ { { BayerFormat::GBRG, 10, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10) },
+ { { BayerFormat::GRBG, 10, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10) },
+ { { BayerFormat::RGGB, 10, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10) },
+ { { BayerFormat::BGGR, 10, BayerFormat::CSI2Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10P) },
+ { { BayerFormat::GBRG, 10, BayerFormat::CSI2Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10P) },
+ { { BayerFormat::GRBG, 10, BayerFormat::CSI2Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10P) },
+ { { BayerFormat::RGGB, 10, BayerFormat::CSI2Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P) },
+ { { BayerFormat::BGGR, 10, BayerFormat::IPU3Packed }, V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SBGGR10) },
+ { { BayerFormat::GBRG, 10, BayerFormat::IPU3Packed }, V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGBRG10) },
+ { { BayerFormat::GRBG, 10, BayerFormat::IPU3Packed }, V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGRBG10) },
+ { { BayerFormat::RGGB, 10, BayerFormat::IPU3Packed }, V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SRGGB10) },
+ { { BayerFormat::BGGR, 12, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12) },
+ { { BayerFormat::GBRG, 12, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12) },
+ { { BayerFormat::GRBG, 12, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12) },
+ { { BayerFormat::RGGB, 12, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12) },
+ { { BayerFormat::BGGR, 12, BayerFormat::CSI2Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12P) },
+ { { BayerFormat::GBRG, 12, BayerFormat::CSI2Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12P) },
+ { { BayerFormat::GRBG, 12, BayerFormat::CSI2Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12P) },
+ { { BayerFormat::RGGB, 12, BayerFormat::CSI2Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12P) },
+ { { BayerFormat::BGGR, 16, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR16) },
+ { { BayerFormat::GBRG, 16, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG16) },
+ { { BayerFormat::GRBG, 16, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG16) },
+ { { BayerFormat::RGGB, 16, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB16) },
+};
+
+} /* namespace */
+
+/**
+ * \fn BayerFormat::BayerFormat()
+ * \brief Construct an empty (and invalid) BayerFormat
+ */
+
+/**
+ * \fn BayerFormat::BayerFormat(Order o, uint8_t b, Packing p)
+ * \brief Construct a BayerFormat from explicit values
+ * \param[in] o The order of the Bayer pattern
+ * \param[in] b The bit depth of the Bayer samples
+ * \param[in] p The type of packing applied to the pixel values
+ */
+
+/**
+ * \brief Construct a BayerFormat from a V4L2PixelFormat
+ * \param[in] v4l2Format The raw format to convert into a BayerFormat
+ */
+BayerFormat::BayerFormat(V4L2PixelFormat v4l2Format)
+ : order(BGGR), packing(None)
+{
+ const auto it = v4l2ToBayer.find(v4l2Format);
+ if (it == v4l2ToBayer.end())
+ bitDepth = 0;
+ else
+ *this = it->second;
+}
+
+/**
+ * \fn BayerFormat::isValid()
+ * \brief Return whether a BayerFormat is valid
+ */
+
+/**
+ * \brief Assemble and return a readable string representation of the
+ * BayerFormat
+ * \return A string describing the BayerFormat
+ */
+std::string BayerFormat::toString() const
+{
+ std::string result;
+
+ static const char *orderStrings[] = {
+ "BGGR",
+ "GBRG",
+ "GRBG",
+ "RGGB"
+ };
+ if (isValid() && order <= RGGB)
+ result = orderStrings[order];
+ else
+ return "INVALID";
+
+ result += "-" + std::to_string(bitDepth);
+
+ if (packing == CSI2Packed)
+ result += "-CSI2P";
+ else if (packing == IPU3Packed)
+ result += "-IPU3P";
+
+ return result;
+}
+
+/**
+ * \brief Convert a BayerFormat into the corresponding V4L2PixelFormat
+ * \return The V4L2PixelFormat corresponding to this BayerFormat
+ */
+V4L2PixelFormat BayerFormat::toV4L2PixelFormat() const
+{
+ const auto it = bayerToV4l2.find(*this);
+ if (it != bayerToV4l2.end())
+ return it->second;
+
+ return V4L2PixelFormat();
+}
+
+/**
+ * \brief Apply a transform to this BayerFormat
+ * \param[in] t The transform to apply
+ *
+ * Appplying a transform to an image stored in a Bayer format affects the Bayer
+ * order. For example, performing a horizontal flip on the Bayer pattern
+ * RGGB causes the RG rows of pixels to become GR, and the GB rows to become BG.
+ * The transformed image would have a GRBG order. The bit depth and modifiers
+ * are not affected.
+ *
+ * Note that transpositions are ignored as the order of a transpose with
+ * respect to the flips would have to be defined, and sensors are not expected
+ * to support transposition.
+ *
+ * \return The transformed Bayer format
+ */
+BayerFormat BayerFormat::transform(Transform t) const
+{
+ BayerFormat result = *this;
+
+ /*
+ * Observe that flipping bit 0 of the Order enum performs a horizontal
+ * mirror on the Bayer pattern (e.g. RGGB goes to GRBG). Similarly,
+ * flipping bit 1 performs a vertical mirror operation on it. Hence:
+ */
+ if (!!(t & Transform::HFlip))
+ result.order = static_cast<Order>(result.order ^ 1);
+ if (!!(t & Transform::VFlip))
+ result.order = static_cast<Order>(result.order ^ 2);
+
+ return result;
+}
+
+/**
+ * \var BayerFormat::order
+ * \brief The order of the colour channels in the Bayer pattern
+ */
+
+/**
+ * \var BayerFormat::bitDepth
+ * \brief The bit depth of the samples in the Bayer pattern
+ */
+
+/**
+ * \var BayerFormat::packing
+ * \brief Any packing scheme applied to this BayerFormat
+ */
+
+} /* namespace libcamera */
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index 1351dbba..07711b5f 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: CC0-1.0
libcamera_sources = files([
+ 'bayer_format.cpp',
'bound_method.cpp',
'buffer.cpp',
'byte_stream_buffer.cpp',