Message ID | 20200907071604.8355-5-david.plowman@raspberrypi.com |
---|---|
State | Accepted |
Headers | show |
Series |
|
Related | show |
Hi David, Thank you for the patch. On Mon, Sep 07, 2020 at 08:15:59AM +0100, David Plowman wrote: > This type encodes BayerFormats in an explicit way, that makes them > easier to use than some of the other more opaque type formats. This > makes the BayerFormat useful for editing or manipulating Bayer types > more easily. > > Signed-off-by: David Plowman <david.plowman@raspberrypi.com> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > --- > include/libcamera/internal/bayer_format.h | 61 +++++ > src/libcamera/bayer_format.cpp | 268 ++++++++++++++++++++++ > src/libcamera/meson.build | 1 + > 3 files changed, 330 insertions(+) > create mode 100644 include/libcamera/internal/bayer_format.h > create mode 100644 src/libcamera/bayer_format.cpp > > diff --git a/include/libcamera/internal/bayer_format.h b/include/libcamera/internal/bayer_format.h > new file mode 100644 > index 0000000..4280b76 > --- /dev/null > +++ b/include/libcamera/internal/bayer_format.h > @@ -0,0 +1,61 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2020, Raspberry Pi (Trading) Ltd. > + * > + * bayer_format.h - Bayer Pixel Format > + */ > +#ifndef __LIBCAMERA_INTERNAL_BAYER_FORMAT_H__ > +#define __LIBCAMERA_INTERNAL_BAYER_FORMAT_H__ > + > +#include <stdint.h> > +#include <string> > + > +#include "libcamera/internal/v4l2_pixelformat.h" > + > +namespace libcamera { > + > +enum class Transform; > + > +class BayerFormat > +{ > +public: > + enum Order : uint8_t { > + BGGR = 0, > + GBRG = 1, > + GRBG = 2, > + RGGB = 3 > + }; > + > + enum Packing : uint16_t { > + None = 0, > + CSI2Packed = 1, > + IPU3Packed = 2, > + }; > + > + constexpr BayerFormat() > + : order(Order::BGGR), bitDepth(0), packing(Packing::None) > + { > + } > + > + constexpr BayerFormat(Order o, uint8_t b, Packing p) > + : order(o), bitDepth(b), packing(p) > + { > + } > + > + explicit BayerFormat(V4L2PixelFormat v4l2Format); > + bool isValid() const { return bitDepth != 0; } > + > + std::string toString() const; > + > + V4L2PixelFormat toV4L2PixelFormat() const; > + BayerFormat transform(Transform t) const; > + > + Order order; > + uint8_t bitDepth; > + > + Packing packing; > +}; > + > +} /* namespace libcamera */ > + > +#endif /* __LIBCAMERA_INTERNAL_BAYER_FORMAT_H__ */ > diff --git a/src/libcamera/bayer_format.cpp b/src/libcamera/bayer_format.cpp > new file mode 100644 > index 0000000..c7e4f22 > --- /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 } /* namespace */ With this small issue fixed, Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > + > +/** > + * \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 edec55e..86c225f 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',
diff --git a/include/libcamera/internal/bayer_format.h b/include/libcamera/internal/bayer_format.h new file mode 100644 index 0000000..4280b76 --- /dev/null +++ b/include/libcamera/internal/bayer_format.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020, Raspberry Pi (Trading) Ltd. + * + * bayer_format.h - Bayer Pixel Format + */ +#ifndef __LIBCAMERA_INTERNAL_BAYER_FORMAT_H__ +#define __LIBCAMERA_INTERNAL_BAYER_FORMAT_H__ + +#include <stdint.h> +#include <string> + +#include "libcamera/internal/v4l2_pixelformat.h" + +namespace libcamera { + +enum class Transform; + +class BayerFormat +{ +public: + enum Order : uint8_t { + BGGR = 0, + GBRG = 1, + GRBG = 2, + RGGB = 3 + }; + + enum Packing : uint16_t { + None = 0, + CSI2Packed = 1, + IPU3Packed = 2, + }; + + constexpr BayerFormat() + : order(Order::BGGR), bitDepth(0), packing(Packing::None) + { + } + + constexpr BayerFormat(Order o, uint8_t b, Packing p) + : order(o), bitDepth(b), packing(p) + { + } + + explicit BayerFormat(V4L2PixelFormat v4l2Format); + bool isValid() const { return bitDepth != 0; } + + std::string toString() const; + + V4L2PixelFormat toV4L2PixelFormat() const; + BayerFormat transform(Transform t) const; + + Order order; + uint8_t bitDepth; + + Packing packing; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_INTERNAL_BAYER_FORMAT_H__ */ diff --git a/src/libcamera/bayer_format.cpp b/src/libcamera/bayer_format.cpp new file mode 100644 index 0000000..c7e4f22 --- /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 edec55e..86c225f 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',