[libcamera-devel] [PATCH v6 4/8] libcamera: Add BayerFormat type
Kieran Bingham
kieran.bingham at ideasonboard.com
Wed Sep 2 13:49:01 CEST 2020
Hi David,
On 02/09/2020 11:44, 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.
I sort of got excited reading about this in the cover letter.
Sounds like a good way to deal with all of this!
>
> Signed-off-by: David Plowman <david.plowman at raspberrypi.com>
Looks like only minor comments below, therefore:
Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
> ---
> include/libcamera/internal/bayer_format.h | 63 ++++++
> src/libcamera/bayer_format.cpp | 223 ++++++++++++++++++++++
> src/libcamera/meson.build | 1 +
> 3 files changed, 287 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..3a0f5cb
> --- /dev/null
> +++ b/include/libcamera/internal/bayer_format.h
> @@ -0,0 +1,63 @@
> +/* 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 Modifier : uint16_t {
> + None = 0,
> + Packed = 1,
> + };
> +
> + constexpr BayerFormat()
> + : order(Order::BGGR), bitDepth(0), modifiers(Modifier::None)
> + {
> + }
> +
> + constexpr BayerFormat(Order o, uint8_t b, Modifier m)
> + : order(o), bitDepth(b), modifiers(m)
> + {
> + }
> +
> + 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;
> +
> + Modifier modifiers;
Hrm ... a newline between 'every' entry looks a bit odd - I think I've
asked to keep things distinct before - but I think newlines should only
be where it makes sense.
I'd probably group these more like this:
> + 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;
> + Modifier modifiers;
> +};
> +
> +} /* 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..cc8ed66
> --- /dev/null
> +++ b/src/libcamera/bayer_format.cpp
> @@ -0,0 +1,223 @@
> +/* 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 T then G on the first row, G then B on the second row.
> + */
> +
> +/**
> + * \enum BayerFormat::Modifier
> + * \brief Modifiers that can apply to a BayerFormat
> + *
> + * \var BayerFormat::None
> + * \brief No modifiers
> + * \var BayerFormat::Packed
> + * \brief Format uses MIPI CSI-2 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::Packed } },
> + { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10P), { BayerFormat::GBRG, 10, BayerFormat::Packed } },
> + { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10P), { BayerFormat::GRBG, 10, BayerFormat::Packed } },
> + { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P), { BayerFormat::RGGB, 10, BayerFormat::Packed } },
> + { 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::Packed } },
> + { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12P), { BayerFormat::GBRG, 12, BayerFormat::Packed } },
> + { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12P), { BayerFormat::GRBG, 12, BayerFormat::Packed } },
> + { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12P), { BayerFormat::RGGB, 12, BayerFormat::Packed } },
> + { 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 {
> + bool operator()(const BayerFormat &left, const BayerFormat &right) const
> + {
> + return left.bitDepth > right.bitDepth ||
> + (left.bitDepth == right.bitDepth && left.order > right.order) ||
> + (left.bitDepth == right.bitDepth && left.order == right.order &&
> + left.modifiers > right.modifiers);
> + }
> +};
> +
> +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::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10P) },
> + { { BayerFormat::GBRG, 10, BayerFormat::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10P) },
> + { { BayerFormat::GRBG, 10, BayerFormat::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10P) },
> + { { BayerFormat::RGGB, 10, BayerFormat::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P) },
> + { { 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::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12P) },
> + { { BayerFormat::GBRG, 12, BayerFormat::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12P) },
> + { { BayerFormat::GRBG, 12, BayerFormat::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12P) },
> + { { BayerFormat::RGGB, 12, BayerFormat::Packed }, 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) },
I always wished we could generate V4L2 (or DRM?) pixelformats in an
explicit manner such as this 'BayerFormat::RGGB, 16, BayerFormat::None'
rather than the tables of enums/defines ;-)
> +};
> +
> +} // namespace
> +
> +/**
> + * \fn BayerFormat::BayerFormat()
> + * \brief Construct an empty (and invalid) BayerFormat
> + */
> +
> +/**
> + * \fn BayerFormat::BayerFormat(Order o, uint8_t b, Modifier m)
> + * \brief Construct a BayerFormat from explicit values
> + */
> +
> +/**
> + * \brief Construct a BayerFormat from a V4L2PixelFormat
> + * \param[in] v4l2Format The raw format to convert into a BayerFormat
> + */
> +BayerFormat::BayerFormat(V4L2PixelFormat v4l2Format)
> +{
> + 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 Returns a readable string representation of the BayerFormat
> + */
> +std::string BayerFormat::toString() const
> +{
> + std::string result;
> +
> + static const char *orderStrings[] = {
> + "BGGR",
> + "GBRG",
> + "GRBG",
> + "RGGB"
> + };
> + if (order <= RGGB)
> + result = orderStrings[order];
> + else
> + result = "unknown";
> +
> + result += "-" + std::to_string(bitDepth);
> +
> + if (modifiers & Packed)
> + result += "-P";
> +
> + return result;
> +}
Nice ;-)
> +
> +/**
> + * \brief Convert a BayerFormat into the corresponding V4L2PixelFormat
> + */
> +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
> + */
> +BayerFormat BayerFormat::transform(Transform t) const
> +{
> + BayerFormat result = *this;
> +
> + /* The order encoding is chosen to behave like this: */
I'm not sure I fully understand that comment, could you expand a little
perhaps please?
> + if (!!(t & Transform::HFlip))
> + result.order = static_cast<Order>(result.order ^ 1);
> + if (!!(t & Transform::VFlip))
> + result.order = static_cast<Order>(result.order ^ 2);
Presumably you mean the ordering is specific to the '1' and '2' values
used there...
> +
> + 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::modifiers
> + * \brief Any modifier flags 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',
>
--
Regards
--
Kieran
More information about the libcamera-devel
mailing list