new file mode 100644
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Ideas on Board Oy
+ *
+ * Bayer Color Filter Array patterns
+ */
+
+#pragma once
+
+#include <optional>
+#include <ostream>
+#include <stdint.h>
+#include <string>
+
+#include "libcamera/internal/v4l2_pixelformat.h"
+
+namespace libcamera {
+
+enum class Transform;
+
+class ColorFilterArray
+{
+public:
+ enum Order : uint8_t {
+ BGGR = 0,
+ GBRG = 1,
+ GRBG = 2,
+ RGGB = 3,
+ MONO = 4
+ };
+
+ constexpr ColorFilterArray() : order(Order::BGGR)
+ {
+ }
+
+ constexpr ColorFilterArray(Order o)
+ : order(o)
+ {
+ }
+
+ static std::optional<ColorFilterArray> fromMbusCode(unsigned int mbusCode);
+ static std::optional<ColorFilterArray> fromV4L2PixelFormat(V4L2PixelFormat v4l2Format);
+ unsigned int toMbusCode(uint8_t bitDepth) const;
+
+ std::string toString() const;
+
+ bool operator==(const ColorFilterArray &other) const {
+ return this->order == other.order;
+ }
+
+ ColorFilterArray transform(Transform t) const;
+
+ Order order;
+};
+
+std::ostream &operator<<(std::ostream &out, const ColorFilterArray &f);
+
+} /* namespace libcamera */
@@ -11,6 +11,7 @@
#include <stdint.h>
#include <string>
+#include <libcamera/color_filter_array.h>
#include <libcamera/pixel_format.h>
#include "libcamera/internal/v4l2_pixelformat.h"
@@ -22,14 +23,6 @@ enum class Transform;
class BayerFormat
{
public:
- enum Order : uint8_t {
- BGGR = 0,
- GBRG = 1,
- GRBG = 2,
- RGGB = 3,
- MONO = 4
- };
-
enum class Packing : uint16_t {
None = 0,
CSI2 = 1,
@@ -39,12 +32,12 @@ public:
};
constexpr BayerFormat()
- : order(Order::BGGR), bitDepth(0), packing(Packing::None)
+ : cfa(ColorFilterArray()), bitDepth(0), packing(Packing::None)
{
}
- constexpr BayerFormat(Order o, uint8_t b, Packing p)
- : order(o), bitDepth(b), packing(p)
+ constexpr BayerFormat(ColorFilterArray c, uint8_t b, Packing p)
+ : cfa(c), bitDepth(b), packing(p)
{
}
@@ -57,9 +50,8 @@ public:
static BayerFormat fromV4L2PixelFormat(V4L2PixelFormat v4l2Format);
PixelFormat toPixelFormat() const;
static BayerFormat fromPixelFormat(PixelFormat format);
- BayerFormat transform(Transform t) const;
- Order order;
+ ColorFilterArray cfa;
uint8_t bitDepth;
Packing packing;
@@ -16,13 +16,13 @@
#include <libcamera/base/class.h>
+#include <libcamera/color_filter_array.h>
#include <libcamera/control_ids.h>
#include <libcamera/controls.h>
#include <libcamera/geometry.h>
#include <libcamera/orientation.h>
#include <libcamera/transform.h>
-#include "libcamera/internal/bayer_format.h"
#include "libcamera/internal/camera_sensor_properties.h"
#include "libcamera/internal/v4l2_subdevice.h"
@@ -72,7 +72,7 @@ public:
virtual const ControlList &properties() const = 0;
virtual int sensorInfo(IPACameraSensorInfo *info) const = 0;
virtual Transform computeTransform(Orientation *orientation) const = 0;
- virtual BayerFormat::Order bayerOrder(Transform t) const = 0;
+ virtual ColorFilterArray bayerOrder(Transform t) const = 0;
virtual Orientation mountingOrientation() const = 0;
virtual const ControlInfoMap &controls() const = 0;
@@ -88,7 +88,7 @@ private:
using statsProcessFn = void (SwStatsCpu::*)(const uint8_t *src[], SwIspStats &stats);
using processFrameFn = void (SwStatsCpu::*)(MappedFrameBuffer &in);
- int setupStandardBayerOrder(BayerFormat::Order order);
+ int setupStandardBayerOrder(ColorFilterArray::Order order);
/* Bayer 8 bpp unpacked */
void statsBGGR8Line0(const uint8_t *src[], SwIspStats &stats);
/* Bayer 10 bpp unpacked */
@@ -5,6 +5,7 @@ libcamera_include_dir = 'libcamera' / 'libcamera'
libcamera_public_headers = files([
'camera.h',
'camera_manager.h',
+ 'color_filter_array.h',
'color_space.h',
'controls.h',
'fence.h',
@@ -54,28 +54,28 @@ uint32_t AgcStatistics::decodeBinValue(uint16_t binVal)
* colour channels would be populated, and they may not be in the same
* planes as calculated here.
*/
-int AgcStatistics::setBayerOrderIndices(BayerFormat::Order bayerOrder)
+int AgcStatistics::setBayerOrderIndices(ColorFilterArray::Order cfaOrder)
{
- switch (bayerOrder) {
- case BayerFormat::Order::RGGB:
+ switch (cfaOrder) {
+ case ColorFilterArray::Order::RGGB:
rIndex_ = 0;
grIndex_ = 1;
gbIndex_ = 2;
bIndex_ = 3;
break;
- case BayerFormat::Order::GRBG:
+ case ColorFilterArray::Order::GRBG:
grIndex_ = 0;
rIndex_ = 1;
bIndex_ = 2;
gbIndex_ = 3;
break;
- case BayerFormat::Order::GBRG:
+ case ColorFilterArray::Order::GBRG:
gbIndex_ = 0;
bIndex_ = 1;
rIndex_ = 2;
grIndex_ = 3;
break;
- case BayerFormat::Order::BGGR:
+ case ColorFilterArray::Order::BGGR:
bIndex_ = 0;
gbIndex_ = 1;
grIndex_ = 2;
@@ -83,7 +83,7 @@ int AgcStatistics::setBayerOrderIndices(BayerFormat::Order bayerOrder)
break;
default:
LOG(MaliC55Agc, Error)
- << "Invalid bayer format " << bayerOrder;
+ << "Invalid bayer format " << cfaOrder;
return -EINVAL;
}
@@ -8,8 +8,7 @@
#pragma once
#include <libcamera/base/utils.h>
-
-#include "libcamera/internal/bayer_format.h"
+#include <libcamera/color_filter_array.h>
#include "libipa/agc.h"
#include "libipa/histogram.h"
@@ -28,7 +27,7 @@ public:
{
}
- int setBayerOrderIndices(BayerFormat::Order bayerOrder);
+ int setBayerOrderIndices(ColorFilterArray::Order cfaOrder);
uint32_t decodeBinValue(uint16_t binVal);
void parseStatistics(const mali_c55_stats_buffer *stats);
@@ -8,12 +8,11 @@
#pragma once
#include <libcamera/base/utils.h>
+#include <libcamera/color_filter_array.h>
#include <libcamera/controls.h>
#include <libcamera/ipa/core_ipa_interface.h>
-#include "libcamera/internal/bayer_format.h"
-
#include <libipa/agc.h>
#include <libipa/camera_sensor_helper.h>
#include <libipa/fc_queue.h>
@@ -31,7 +30,7 @@ struct IPASessionConfiguration {
agc::Session agc;
struct {
- BayerFormat::Order bayerOrder;
+ ColorFilterArray::Order bayerOrder;
uint32_t blackLevel;
} sensor;
};
@@ -17,11 +17,11 @@
#include <libcamera/base/log.h>
#include <libcamera/control_ids.h>
+#include <libcamera/color_filter_array.h>
#include <libcamera/ipa/ipa_interface.h>
#include <libcamera/ipa/ipa_module_info.h>
#include <libcamera/ipa/mali-c55_ipa_interface.h>
-#include "libcamera/internal/bayer_format.h"
#include "libcamera/internal/mapped_framebuffer.h"
#include "libcamera/internal/yaml_parser.h"
@@ -171,7 +171,7 @@ int IPAMaliC55::configure(const IPAConfigInfo &ipaConfig, uint8_t bayerOrder,
const IPACameraSensorInfo &info = ipaConfig.sensorInfo;
- context_.configuration.sensor.bayerOrder = static_cast<BayerFormat::Order>(bayerOrder);
+ context_.configuration.sensor.bayerOrder = static_cast<ColorFilterArray::Order>(bayerOrder);
if (auto bl = context_.camHelper->blackLevel()) {
/*
@@ -14,6 +14,7 @@
#include <linux/media-bus-format.h>
+#include <libcamera/color_filter_array.h>
#include <libcamera/formats.h>
#include <libcamera/transform.h>
@@ -29,26 +30,8 @@ namespace libcamera {
* \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.
- * \var BayerFormat::MONO
- * \brief Monochrome image data, there is no colour filter array.
+ * be easily manipulated. For example the bit depth, packing and color order of
+ * the format transmitted over the bus can be modified and transformed.
*/
/**
@@ -78,9 +61,9 @@ struct BayerFormatComparator {
else if (lhs.bitDepth > rhs.bitDepth)
return false;
- if (lhs.order < rhs.order)
+ if (lhs.cfa.order < rhs.cfa.order)
return true;
- else if (lhs.order > rhs.order)
+ else if (lhs.cfa.order > rhs.cfa.order)
return false;
if (lhs.packing < rhs.packing)
@@ -96,143 +79,143 @@ struct Formats {
};
const std::map<BayerFormat, Formats, BayerFormatComparator> bayerToFormat{
- { { BayerFormat::BGGR, 8, BayerFormat::Packing::None },
+ { { ColorFilterArray::BGGR, 8, BayerFormat::Packing::None },
{ formats::SBGGR8, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR8) } },
- { { BayerFormat::GBRG, 8, BayerFormat::Packing::None },
+ { { ColorFilterArray::GBRG, 8, BayerFormat::Packing::None },
{ formats::SGBRG8, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG8) } },
- { { BayerFormat::GRBG, 8, BayerFormat::Packing::None },
+ { { ColorFilterArray::GRBG, 8, BayerFormat::Packing::None },
{ formats::SGRBG8, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG8) } },
- { { BayerFormat::RGGB, 8, BayerFormat::Packing::None },
+ { { ColorFilterArray::RGGB, 8, BayerFormat::Packing::None },
{ formats::SRGGB8, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB8) } },
- { { BayerFormat::BGGR, 10, BayerFormat::Packing::None },
+ { { ColorFilterArray::BGGR, 10, BayerFormat::Packing::None },
{ formats::SBGGR10, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10) } },
- { { BayerFormat::GBRG, 10, BayerFormat::Packing::None },
+ { { ColorFilterArray::GBRG, 10, BayerFormat::Packing::None },
{ formats::SGBRG10, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10) } },
- { { BayerFormat::GRBG, 10, BayerFormat::Packing::None },
+ { { ColorFilterArray::GRBG, 10, BayerFormat::Packing::None },
{ formats::SGRBG10, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10) } },
- { { BayerFormat::RGGB, 10, BayerFormat::Packing::None },
+ { { ColorFilterArray::RGGB, 10, BayerFormat::Packing::None },
{ formats::SRGGB10, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10) } },
- { { BayerFormat::BGGR, 10, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::BGGR, 10, BayerFormat::Packing::CSI2 },
{ formats::SBGGR10_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10P) } },
- { { BayerFormat::GBRG, 10, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::GBRG, 10, BayerFormat::Packing::CSI2 },
{ formats::SGBRG10_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10P) } },
- { { BayerFormat::GRBG, 10, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::GRBG, 10, BayerFormat::Packing::CSI2 },
{ formats::SGRBG10_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10P) } },
- { { BayerFormat::RGGB, 10, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::RGGB, 10, BayerFormat::Packing::CSI2 },
{ formats::SRGGB10_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P) } },
- { { BayerFormat::BGGR, 10, BayerFormat::Packing::IPU3 },
+ { { ColorFilterArray::BGGR, 10, BayerFormat::Packing::IPU3 },
{ formats::SBGGR10_IPU3, V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SBGGR10) } },
- { { BayerFormat::GBRG, 10, BayerFormat::Packing::IPU3 },
+ { { ColorFilterArray::GBRG, 10, BayerFormat::Packing::IPU3 },
{ formats::SGBRG10_IPU3, V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGBRG10) } },
- { { BayerFormat::GRBG, 10, BayerFormat::Packing::IPU3 },
+ { { ColorFilterArray::GRBG, 10, BayerFormat::Packing::IPU3 },
{ formats::SGRBG10_IPU3, V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGRBG10) } },
- { { BayerFormat::RGGB, 10, BayerFormat::Packing::IPU3 },
+ { { ColorFilterArray::RGGB, 10, BayerFormat::Packing::IPU3 },
{ formats::SRGGB10_IPU3, V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SRGGB10) } },
- { { BayerFormat::BGGR, 12, BayerFormat::Packing::None },
+ { { ColorFilterArray::BGGR, 12, BayerFormat::Packing::None },
{ formats::SBGGR12, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12) } },
- { { BayerFormat::GBRG, 12, BayerFormat::Packing::None },
+ { { ColorFilterArray::GBRG, 12, BayerFormat::Packing::None },
{ formats::SGBRG12, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12) } },
- { { BayerFormat::GRBG, 12, BayerFormat::Packing::None },
+ { { ColorFilterArray::GRBG, 12, BayerFormat::Packing::None },
{ formats::SGRBG12, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12) } },
- { { BayerFormat::RGGB, 12, BayerFormat::Packing::None },
+ { { ColorFilterArray::RGGB, 12, BayerFormat::Packing::None },
{ formats::SRGGB12, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12) } },
- { { BayerFormat::BGGR, 12, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::BGGR, 12, BayerFormat::Packing::CSI2 },
{ formats::SBGGR12_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12P) } },
- { { BayerFormat::GBRG, 12, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::GBRG, 12, BayerFormat::Packing::CSI2 },
{ formats::SGBRG12_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12P) } },
- { { BayerFormat::GRBG, 12, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::GRBG, 12, BayerFormat::Packing::CSI2 },
{ formats::SGRBG12_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12P) } },
- { { BayerFormat::RGGB, 12, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::RGGB, 12, BayerFormat::Packing::CSI2 },
{ formats::SRGGB12_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12P) } },
- { { BayerFormat::BGGR, 14, BayerFormat::Packing::None },
+ { { ColorFilterArray::BGGR, 14, BayerFormat::Packing::None },
{ formats::SBGGR14, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR14) } },
- { { BayerFormat::GBRG, 14, BayerFormat::Packing::None },
+ { { ColorFilterArray::GBRG, 14, BayerFormat::Packing::None },
{ formats::SGBRG14, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG14) } },
- { { BayerFormat::GRBG, 14, BayerFormat::Packing::None },
+ { { ColorFilterArray::GRBG, 14, BayerFormat::Packing::None },
{ formats::SGRBG14, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG14) } },
- { { BayerFormat::RGGB, 14, BayerFormat::Packing::None },
+ { { ColorFilterArray::RGGB, 14, BayerFormat::Packing::None },
{ formats::SRGGB14, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB14) } },
- { { BayerFormat::BGGR, 14, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::BGGR, 14, BayerFormat::Packing::CSI2 },
{ formats::SBGGR14_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR14P) } },
- { { BayerFormat::GBRG, 14, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::GBRG, 14, BayerFormat::Packing::CSI2 },
{ formats::SGBRG14_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG14P) } },
- { { BayerFormat::GRBG, 14, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::GRBG, 14, BayerFormat::Packing::CSI2 },
{ formats::SGRBG14_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG14P) } },
- { { BayerFormat::RGGB, 14, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::RGGB, 14, BayerFormat::Packing::CSI2 },
{ formats::SRGGB14_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB14P) } },
- { { BayerFormat::BGGR, 16, BayerFormat::Packing::None },
+ { { ColorFilterArray::BGGR, 16, BayerFormat::Packing::None },
{ formats::SBGGR16, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR16) } },
- { { BayerFormat::GBRG, 16, BayerFormat::Packing::None },
+ { { ColorFilterArray::GBRG, 16, BayerFormat::Packing::None },
{ formats::SGBRG16, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG16) } },
- { { BayerFormat::GRBG, 16, BayerFormat::Packing::None },
+ { { ColorFilterArray::GRBG, 16, BayerFormat::Packing::None },
{ formats::SGRBG16, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG16) } },
- { { BayerFormat::RGGB, 16, BayerFormat::Packing::None },
+ { { ColorFilterArray::RGGB, 16, BayerFormat::Packing::None },
{ formats::SRGGB16, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB16) } },
- { { BayerFormat::BGGR, 16, BayerFormat::Packing::PISP1 },
+ { { ColorFilterArray::BGGR, 16, BayerFormat::Packing::PISP1 },
{ formats::BGGR_PISP_COMP1, V4L2PixelFormat(V4L2_PIX_FMT_PISP_COMP1_BGGR) } },
- { { BayerFormat::GBRG, 16, BayerFormat::Packing::PISP1 },
+ { { ColorFilterArray::GBRG, 16, BayerFormat::Packing::PISP1 },
{ formats::GBRG_PISP_COMP1, V4L2PixelFormat(V4L2_PIX_FMT_PISP_COMP1_GBRG) } },
- { { BayerFormat::GRBG, 16, BayerFormat::Packing::PISP1 },
+ { { ColorFilterArray::GRBG, 16, BayerFormat::Packing::PISP1 },
{ formats::GRBG_PISP_COMP1, V4L2PixelFormat(V4L2_PIX_FMT_PISP_COMP1_GRBG) } },
- { { BayerFormat::RGGB, 16, BayerFormat::Packing::PISP1 },
+ { { ColorFilterArray::RGGB, 16, BayerFormat::Packing::PISP1 },
{ formats::RGGB_PISP_COMP1, V4L2PixelFormat(V4L2_PIX_FMT_PISP_COMP1_RGGB) } },
- { { BayerFormat::MONO, 8, BayerFormat::Packing::None },
+ { { ColorFilterArray::MONO, 8, BayerFormat::Packing::None },
{ formats::R8, V4L2PixelFormat(V4L2_PIX_FMT_GREY) } },
- { { BayerFormat::MONO, 10, BayerFormat::Packing::None },
+ { { ColorFilterArray::MONO, 10, BayerFormat::Packing::None },
{ formats::R10, V4L2PixelFormat(V4L2_PIX_FMT_Y10) } },
- { { BayerFormat::MONO, 10, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::MONO, 10, BayerFormat::Packing::CSI2 },
{ formats::R10_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_Y10P) } },
- { { BayerFormat::MONO, 12, BayerFormat::Packing::None },
+ { { ColorFilterArray::MONO, 12, BayerFormat::Packing::None },
{ formats::R12, V4L2PixelFormat(V4L2_PIX_FMT_Y12) } },
- { { BayerFormat::MONO, 12, BayerFormat::Packing::CSI2 },
+ { { ColorFilterArray::MONO, 12, BayerFormat::Packing::CSI2 },
{ formats::R12_CSI2P, V4L2PixelFormat(V4L2_PIX_FMT_Y12P) } },
- { { BayerFormat::MONO, 16, BayerFormat::Packing::None },
+ { { ColorFilterArray::MONO, 16, BayerFormat::Packing::None },
{ formats::R16, V4L2PixelFormat(V4L2_PIX_FMT_Y16) } },
- { { BayerFormat::MONO, 16, BayerFormat::Packing::PISP1 },
+ { { ColorFilterArray::MONO, 16, BayerFormat::Packing::PISP1 },
{ formats::MONO_PISP_COMP1, V4L2PixelFormat(V4L2_PIX_FMT_PISP_COMP1_MONO) } },
};
const std::unordered_map<unsigned int, BayerFormat> mbusCodeToBayer{
- { MEDIA_BUS_FMT_SBGGR8_1X8, { BayerFormat::BGGR, 8, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGBRG8_1X8, { BayerFormat::GBRG, 8, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGRBG8_1X8, { BayerFormat::GRBG, 8, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SRGGB8_1X8, { BayerFormat::RGGB, 8, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, { BayerFormat::BGGR, 8, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, { BayerFormat::GBRG, 8, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, { BayerFormat::GRBG, 8, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, { BayerFormat::RGGB, 8, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, { BayerFormat::BGGR, 8, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, { BayerFormat::GBRG, 8, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, { BayerFormat::GRBG, 8, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, { BayerFormat::RGGB, 8, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, { BayerFormat::BGGR, 10, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, { BayerFormat::BGGR, 10, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, { BayerFormat::BGGR, 10, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, { BayerFormat::BGGR, 10, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SBGGR10_1X10, { BayerFormat::BGGR, 10, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGBRG10_1X10, { BayerFormat::GBRG, 10, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGRBG10_1X10, { BayerFormat::GRBG, 10, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SRGGB10_1X10, { BayerFormat::RGGB, 10, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SBGGR12_1X12, { BayerFormat::BGGR, 12, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGBRG12_1X12, { BayerFormat::GBRG, 12, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGRBG12_1X12, { BayerFormat::GRBG, 12, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SRGGB12_1X12, { BayerFormat::RGGB, 12, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SBGGR14_1X14, { BayerFormat::BGGR, 14, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGBRG14_1X14, { BayerFormat::GBRG, 14, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGRBG14_1X14, { BayerFormat::GRBG, 14, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SRGGB14_1X14, { BayerFormat::RGGB, 14, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SBGGR16_1X16, { BayerFormat::BGGR, 16, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGBRG16_1X16, { BayerFormat::GBRG, 16, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGRBG16_1X16, { BayerFormat::GRBG, 16, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SRGGB16_1X16, { BayerFormat::RGGB, 16, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SBGGR20_1X20, { BayerFormat::BGGR, 20, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGBRG20_1X20, { BayerFormat::GBRG, 20, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SGRBG20_1X20, { BayerFormat::GRBG, 20, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_SRGGB20_1X20, { BayerFormat::RGGB, 20, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_Y8_1X8, { BayerFormat::MONO, 8, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_Y10_1X10, { BayerFormat::MONO, 10, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_Y12_1X12, { BayerFormat::MONO, 12, BayerFormat::Packing::None } },
- { MEDIA_BUS_FMT_Y16_1X16, { BayerFormat::MONO, 16, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SBGGR8_1X8, { ColorFilterArray::BGGR, 8, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGBRG8_1X8, { ColorFilterArray::GBRG, 8, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGRBG8_1X8, { ColorFilterArray::GRBG, 8, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SRGGB8_1X8, { ColorFilterArray::RGGB, 8, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, { ColorFilterArray::BGGR, 8, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, { ColorFilterArray::GBRG, 8, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, { ColorFilterArray::GRBG, 8, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, { ColorFilterArray::RGGB, 8, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, { ColorFilterArray::BGGR, 8, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, { ColorFilterArray::GBRG, 8, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, { ColorFilterArray::GRBG, 8, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, { ColorFilterArray::RGGB, 8, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, { ColorFilterArray::BGGR, 10, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, { ColorFilterArray::BGGR, 10, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, { ColorFilterArray::BGGR, 10, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, { ColorFilterArray::BGGR, 10, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SBGGR10_1X10, { ColorFilterArray::BGGR, 10, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGBRG10_1X10, { ColorFilterArray::GBRG, 10, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, { ColorFilterArray::GRBG, 10, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SRGGB10_1X10, { ColorFilterArray::RGGB, 10, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SBGGR12_1X12, { ColorFilterArray::BGGR, 12, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGBRG12_1X12, { ColorFilterArray::GBRG, 12, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGRBG12_1X12, { ColorFilterArray::GRBG, 12, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SRGGB12_1X12, { ColorFilterArray::RGGB, 12, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SBGGR14_1X14, { ColorFilterArray::BGGR, 14, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGBRG14_1X14, { ColorFilterArray::GBRG, 14, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGRBG14_1X14, { ColorFilterArray::GRBG, 14, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SRGGB14_1X14, { ColorFilterArray::RGGB, 14, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SBGGR16_1X16, { ColorFilterArray::BGGR, 16, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGBRG16_1X16, { ColorFilterArray::GBRG, 16, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGRBG16_1X16, { ColorFilterArray::GRBG, 16, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SRGGB16_1X16, { ColorFilterArray::RGGB, 16, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SBGGR20_1X20, { ColorFilterArray::BGGR, 20, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGBRG20_1X20, { ColorFilterArray::GBRG, 20, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SGRBG20_1X20, { ColorFilterArray::GRBG, 20, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_SRGGB20_1X20, { ColorFilterArray::RGGB, 20, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_Y8_1X8, { ColorFilterArray::MONO, 8, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_Y10_1X10, { ColorFilterArray::MONO, 10, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_Y12_1X12, { ColorFilterArray::MONO, 12, BayerFormat::Packing::None } },
+ { MEDIA_BUS_FMT_Y16_1X16, { ColorFilterArray::MONO, 16, BayerFormat::Packing::None } },
};
} /* namespace */
@@ -243,9 +226,9 @@ const std::unordered_map<unsigned int, BayerFormat> mbusCodeToBayer{
*/
/**
- * \fn BayerFormat::BayerFormat(Order o, uint8_t b, Packing p)
+ * \fn BayerFormat::BayerFormat(ColorFilterArray c, uint8_t b, Packing p)
* \brief Construct a BayerFormat from explicit values
- * \param[in] o The order of the Bayer pattern
+ * \param[in] c The color filter array pattern
* \param[in] b The bit depth of the Bayer samples
* \param[in] p The type of packing applied to the pixel values
*/
@@ -291,7 +274,7 @@ std::string BayerFormat::toString() const
*/
bool operator==(const BayerFormat &lhs, const BayerFormat &rhs)
{
- return lhs.order == rhs.order && lhs.bitDepth == rhs.bitDepth &&
+ return lhs.cfa.order == rhs.cfa.order && lhs.bitDepth == rhs.bitDepth &&
lhs.packing == rhs.packing;
}
@@ -303,21 +286,13 @@ bool operator==(const BayerFormat &lhs, const BayerFormat &rhs)
*/
std::ostream &operator<<(std::ostream &out, const BayerFormat &f)
{
- static const char *orderStrings[] = {
- "BGGR-",
- "GBRG-",
- "GRBG-",
- "RGGB-",
- "MONO-"
- };
-
- if (!f.isValid() || f.order > BayerFormat::MONO) {
+ if (!f.isValid() || f.cfa.order > ColorFilterArray::MONO) {
out << "INVALID";
return out;
}
/* The cast is required to avoid bitDepth being interpreted as a char. */
- out << orderStrings[f.order] << static_cast<unsigned int>(f.bitDepth);
+ out << f.cfa << "-" << static_cast<unsigned int>(f.bitDepth);
if (f.packing == BayerFormat::Packing::CSI2)
out << "-CSI2P";
@@ -398,53 +373,8 @@ BayerFormat BayerFormat::fromPixelFormat(PixelFormat format)
}
/**
- * \brief Apply a transform to this BayerFormat
- * \param[in] t The transform to apply
- *
- * Applying 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. Performing a vertical flip on the
- * Bayer pattern RGGB causes the GB rows to come before the RG ones and the
- * transformed image would have GBRG order. Applying both vertical and
- * horizontal flips on the Bayer patter RGGB results in transformed images with
- * BGGR order. The bit depth and modifiers are not affected.
- *
- * Horizontal and vertical flips are applied before transpose.
- *
- * \return The transformed Bayer format
- */
-BayerFormat BayerFormat::transform(Transform t) const
-{
- BayerFormat result = *this;
-
- if (order == MONO)
- return result;
-
- /*
- * Observe that flipping bit 0 of the Order enum performs a horizontal
- * mirror on the Bayer pattern (e.g. RG/GB goes to GR/BG). Similarly,
- * flipping bit 1 performs a vertical mirror operation on it (e.g RG/GB
- * goes to GB/RG). Applying both vertical and horizontal flips
- * combines vertical and horizontal mirroring on the Bayer pattern
- * (e.g. RG/GB goes to BG/GR). 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);
-
- if (!!(t & Transform::Transpose) && result.order == 1)
- result.order = static_cast<Order>(2);
- else if (!!(t & Transform::Transpose) && result.order == 2)
- result.order = static_cast<Order>(1);
-
- return result;
-}
-
-/**
- * \var BayerFormat::order
- * \brief The order of the colour channels in the Bayer pattern
+ * \var BayerFormat::cfa
+ * \brief The color filter array pattern
*/
/**
new file mode 100644
@@ -0,0 +1,334 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Ideas on Board Oy
+ *
+ * Class to represent Bayer Color Filter Array patterns
+ */
+
+#include <libcamera/color_filter_array.h>
+
+#include <optional>
+#include <map>
+#include <sstream>
+#include <unordered_map>
+
+#include <linux/media-bus-format.h>
+
+#include <libcamera/transform.h>
+#include "libcamera/internal/v4l2_pixelformat.h"
+
+/**
+ * \file color_filter_array.cpp
+ * \brief Class to represent and manipulate patterns of the color filter array
+ */
+
+namespace libcamera {
+
+/**
+ * \class ColorFilterArray
+ * \brief Class to represent a color filter array
+ *
+ * This class encodes the different patterns of the color filter array in such
+ * a way that they can be easily manipulated. For example the order can be
+ * "transformed" in the same manner as happens in many sensors when their
+ * horizontal or vertical "flip" controls are set.
+ */
+
+/**
+ * \enum ColorFilterArray::Order
+ * \brief Different ordering of color channels in a filter array
+ *
+ * \var ColorFilterArray::BGGR
+ * \brief B then G on the first row, G then R on the second row.
+ * \var ColorFilterArray::GBRG
+ * \brief G then B on the first row, R then G on the second row.
+ * \var ColorFilterArray::GRBG
+ * \brief G then R on the first row, B then G on the second row.
+ * \var ColorFilterArray::RGGB
+ * \brief R then G on the first row, G then B on the second row.
+ * \var ColorFilterArray::MONO
+ * \brief Monochrome image data, there is no color filter array.
+ */
+
+namespace {
+
+const std::unordered_map<unsigned int, ColorFilterArray> mbusCodeToCFA {
+ { MEDIA_BUS_FMT_SBGGR8_1X8, ColorFilterArray::BGGR },
+ { MEDIA_BUS_FMT_SGBRG8_1X8, ColorFilterArray::GBRG },
+ { MEDIA_BUS_FMT_SGRBG8_1X8, ColorFilterArray::GRBG },
+ { MEDIA_BUS_FMT_SRGGB8_1X8, ColorFilterArray::RGGB },
+ { MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, ColorFilterArray::BGGR },
+ { MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, ColorFilterArray::GBRG },
+ { MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, ColorFilterArray::GRBG },
+ { MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, ColorFilterArray::RGGB },
+ { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, ColorFilterArray::BGGR },
+ { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, ColorFilterArray::GBRG },
+ { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, ColorFilterArray::GRBG },
+ { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, ColorFilterArray::RGGB },
+ { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, ColorFilterArray::BGGR },
+ { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, ColorFilterArray::BGGR },
+ { MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, ColorFilterArray::BGGR },
+ { MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, ColorFilterArray::BGGR },
+ { MEDIA_BUS_FMT_SBGGR10_1X10, ColorFilterArray::BGGR },
+ { MEDIA_BUS_FMT_SGBRG10_1X10, ColorFilterArray::GBRG },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, ColorFilterArray::GRBG },
+ { MEDIA_BUS_FMT_SRGGB10_1X10, ColorFilterArray::RGGB },
+ { MEDIA_BUS_FMT_SBGGR12_1X12, ColorFilterArray::BGGR },
+ { MEDIA_BUS_FMT_SGBRG12_1X12, ColorFilterArray::GBRG },
+ { MEDIA_BUS_FMT_SGRBG12_1X12, ColorFilterArray::GRBG },
+ { MEDIA_BUS_FMT_SRGGB12_1X12, ColorFilterArray::RGGB },
+ { MEDIA_BUS_FMT_SBGGR14_1X14, ColorFilterArray::BGGR },
+ { MEDIA_BUS_FMT_SGBRG14_1X14, ColorFilterArray::GBRG },
+ { MEDIA_BUS_FMT_SGRBG14_1X14, ColorFilterArray::GRBG },
+ { MEDIA_BUS_FMT_SRGGB14_1X14, ColorFilterArray::RGGB },
+ { MEDIA_BUS_FMT_SBGGR16_1X16, ColorFilterArray::BGGR },
+ { MEDIA_BUS_FMT_SGBRG16_1X16, ColorFilterArray::GBRG },
+ { MEDIA_BUS_FMT_SGRBG16_1X16, ColorFilterArray::GRBG },
+ { MEDIA_BUS_FMT_SRGGB16_1X16, ColorFilterArray::RGGB },
+ { MEDIA_BUS_FMT_SBGGR20_1X20, ColorFilterArray::BGGR },
+ { MEDIA_BUS_FMT_SGBRG20_1X20, ColorFilterArray::GBRG },
+ { MEDIA_BUS_FMT_SGRBG20_1X20, ColorFilterArray::GRBG },
+ { MEDIA_BUS_FMT_SRGGB20_1X20, ColorFilterArray::RGGB },
+ { MEDIA_BUS_FMT_Y8_1X8, ColorFilterArray::MONO },
+ { MEDIA_BUS_FMT_Y10_1X10, ColorFilterArray::MONO },
+ { MEDIA_BUS_FMT_Y12_1X12, ColorFilterArray::MONO },
+ { MEDIA_BUS_FMT_Y16_1X16, ColorFilterArray::MONO },
+};
+
+struct CfaMbusEntry {
+ ColorFilterArray cfa;
+ uint8_t bitDepth;
+
+ bool operator<(const CfaMbusEntry& o) const {
+ return std::tie(cfa.order, bitDepth) < std::tie(o.cfa.order, o.bitDepth);
+ }
+};
+
+const std::map<CfaMbusEntry, unsigned int> cfaBitDepthToMbusCode{
+ { { ColorFilterArray::BGGR, 8 }, MEDIA_BUS_FMT_SBGGR8_1X8 },
+ { { ColorFilterArray::BGGR, 10 }, MEDIA_BUS_FMT_SBGGR10_1X10 },
+ { { ColorFilterArray::BGGR, 12 }, MEDIA_BUS_FMT_SBGGR12_1X12 },
+ { { ColorFilterArray::BGGR, 14 }, MEDIA_BUS_FMT_SBGGR14_1X14 },
+ { { ColorFilterArray::BGGR, 16 }, MEDIA_BUS_FMT_SBGGR16_1X16 },
+ { { ColorFilterArray::BGGR, 20 }, MEDIA_BUS_FMT_SBGGR20_1X20 },
+ { { ColorFilterArray::GBRG, 8 }, MEDIA_BUS_FMT_SGBRG8_1X8 },
+ { { ColorFilterArray::GBRG, 10 }, MEDIA_BUS_FMT_SGBRG10_1X10 },
+ { { ColorFilterArray::GBRG, 12 }, MEDIA_BUS_FMT_SGBRG12_1X12 },
+ { { ColorFilterArray::GBRG, 14 }, MEDIA_BUS_FMT_SGBRG14_1X14 },
+ { { ColorFilterArray::GBRG, 16 }, MEDIA_BUS_FMT_SGBRG16_1X16 },
+ { { ColorFilterArray::GBRG, 20 }, MEDIA_BUS_FMT_SGBRG20_1X20 },
+ { { ColorFilterArray::GRBG, 8 }, MEDIA_BUS_FMT_SGRBG8_1X8 },
+ { { ColorFilterArray::GRBG, 10 }, MEDIA_BUS_FMT_SGRBG10_1X10 },
+ { { ColorFilterArray::GRBG, 12 }, MEDIA_BUS_FMT_SGRBG12_1X12 },
+ { { ColorFilterArray::GRBG, 14 }, MEDIA_BUS_FMT_SGRBG14_1X14 },
+ { { ColorFilterArray::GRBG, 16 }, MEDIA_BUS_FMT_SGRBG16_1X16 },
+ { { ColorFilterArray::GRBG, 20 }, MEDIA_BUS_FMT_SGRBG20_1X20 },
+ { { ColorFilterArray::RGGB, 8 }, MEDIA_BUS_FMT_SRGGB8_1X8 },
+ { { ColorFilterArray::RGGB, 10 }, MEDIA_BUS_FMT_SRGGB10_1X10 },
+ { { ColorFilterArray::RGGB, 12 }, MEDIA_BUS_FMT_SRGGB12_1X12 },
+ { { ColorFilterArray::RGGB, 14 }, MEDIA_BUS_FMT_SRGGB14_1X14 },
+ { { ColorFilterArray::RGGB, 16 }, MEDIA_BUS_FMT_SRGGB16_1X16 },
+ { { ColorFilterArray::RGGB, 20 }, MEDIA_BUS_FMT_SRGGB20_1X20 },
+ { { ColorFilterArray::MONO, 8 }, MEDIA_BUS_FMT_Y8_1X8 },
+ { { ColorFilterArray::MONO, 10 }, MEDIA_BUS_FMT_Y10_1X10 },
+ { { ColorFilterArray::MONO, 12 }, MEDIA_BUS_FMT_Y12_1X12 },
+ { { ColorFilterArray::MONO, 16 }, MEDIA_BUS_FMT_Y16_1X16 },
+};
+
+const std::unordered_map<V4L2PixelFormat, ColorFilterArray> v4l2FormatToCFA {
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR8), ColorFilterArray::BGGR },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG8), ColorFilterArray::GBRG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG8), ColorFilterArray::GRBG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB8), ColorFilterArray::RGGB },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10), ColorFilterArray::BGGR },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10), ColorFilterArray::GBRG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10), ColorFilterArray::GRBG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10), ColorFilterArray::RGGB },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10P), ColorFilterArray::BGGR },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10P), ColorFilterArray::GBRG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10P), ColorFilterArray::GRBG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P), ColorFilterArray::RGGB },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12), ColorFilterArray::BGGR },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12), ColorFilterArray::GBRG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12), ColorFilterArray::GRBG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12), ColorFilterArray::RGGB },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12P), ColorFilterArray::BGGR },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12P), ColorFilterArray::GBRG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12P), ColorFilterArray::GRBG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12P), ColorFilterArray::RGGB },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR14), ColorFilterArray::BGGR },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG14), ColorFilterArray::GBRG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG14), ColorFilterArray::GRBG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB14), ColorFilterArray::RGGB },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR14P), ColorFilterArray::BGGR },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG14P), ColorFilterArray::GBRG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG14P), ColorFilterArray::GRBG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB14P), ColorFilterArray::RGGB },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SBGGR16), ColorFilterArray::BGGR },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGBRG16), ColorFilterArray::GBRG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SGRBG16), ColorFilterArray::GRBG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_SRGGB16), ColorFilterArray::RGGB },
+ { V4L2PixelFormat(V4L2_PIX_FMT_PISP_COMP1_BGGR), ColorFilterArray::BGGR },
+ { V4L2PixelFormat(V4L2_PIX_FMT_PISP_COMP1_GBRG), ColorFilterArray::GBRG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_PISP_COMP1_GRBG), ColorFilterArray::GRBG },
+ { V4L2PixelFormat(V4L2_PIX_FMT_PISP_COMP1_RGGB), ColorFilterArray::RGGB },
+ { V4L2PixelFormat(V4L2_PIX_FMT_PISP_COMP1_MONO), ColorFilterArray::MONO },
+ { V4L2PixelFormat(V4L2_PIX_FMT_GREY), ColorFilterArray::MONO },
+ { V4L2PixelFormat(V4L2_PIX_FMT_Y10), ColorFilterArray::MONO },
+ { V4L2PixelFormat(V4L2_PIX_FMT_Y10P), ColorFilterArray::MONO },
+ { V4L2PixelFormat(V4L2_PIX_FMT_Y12), ColorFilterArray::MONO },
+ { V4L2PixelFormat(V4L2_PIX_FMT_Y12P), ColorFilterArray::MONO },
+ { V4L2PixelFormat(V4L2_PIX_FMT_Y16), ColorFilterArray::MONO },
+};
+
+} /* namespace */
+
+/**
+ * \fn ColorFilterArray::ColorFilterArray()
+ * \brief Construct an empty (and invalid) ColorFilterArray
+ */
+
+/**
+ * \fn ColorFilterArray::ColorFilterArray(Order o)
+ * \brief Construct a ColorFilterArray from an explicit order value
+ * \param[in] o The order of color channels in the filter array
+ */
+
+/**
+ * \brief Retrieve the ColorFilterArray associated with a media bus code
+ * \param[in] mbusCode The media bus code to convert into a ColorFilterArray
+ *
+ * The media bus code numeric identifiers are defined by the V4L2 specification.
+ */
+std::optional<ColorFilterArray> ColorFilterArray::fromMbusCode(unsigned int mbusCode)
+{
+ const auto it = mbusCodeToCFA.find(mbusCode);
+
+ if (it == mbusCodeToCFA.end())
+ return std::nullopt;
+ else
+ return it->second;
+}
+
+/**
+ * \brief Retrieve the ColorFilterArray associated with a V4L2PixelFormat
+ * \param[in] v4l2Format The raw format to convert into a ColorFilterArray
+ *
+ * The media bus code numeric identifiers are defined by the V4L2 specification.
+ */
+std::optional<ColorFilterArray> ColorFilterArray::fromV4L2PixelFormat(V4L2PixelFormat v4l2Format)
+{
+ const auto it = v4l2FormatToCFA.find(v4l2Format);
+
+ if (it == v4l2FormatToCFA.end())
+ return std::nullopt;
+ else
+ return it->second;
+}
+
+/**
+ * \brief Retrieve the media bus code for this ColorFilterArray and bit depth
+ * \param[in] bitDepth The bit depth of the samples transmitted over the bus
+ * \return The media bus code, or 0 if no code exists for the combination
+ *
+ * The returned code is the order-specific sensor bus code (e.g.
+ * MEDIA_BUS_FMT_SBGGR10_1X10).
+ */
+unsigned int ColorFilterArray::toMbusCode(uint8_t bitDepth) const
+{
+ const auto it = cfaBitDepthToMbusCode.find({*this, bitDepth});
+
+ if (it == cfaBitDepthToMbusCode.end())
+ return 0;
+ else
+ return it->second;
+}
+
+/**
+ * \brief Assemble and return a readable string representation of the
+ * ColorFilterArray
+ * \return A string describing the ColorFilterArray
+ */
+std::string ColorFilterArray::toString() const
+{
+ std::stringstream ss;
+ ss << *this;
+
+ return ss.str();
+}
+
+/**
+ * \brief Insert a text representation of a ColorFilterArrays into an output stream
+ * \param[in] out The output stream
+ * \param[in] f The ColorFilterArray
+ * \return The output stream \a out
+ */
+std::ostream &operator<<(std::ostream &out, const ColorFilterArray &f)
+{
+ switch (f.order) {
+ case ColorFilterArray::BGGR:
+ return out << "BGGR";
+ case ColorFilterArray::GBRG:
+ return out << "GBRG";
+ case ColorFilterArray::GRBG:
+ return out << "GRBG";
+ case ColorFilterArray::RGGB:
+ return out << "RGGB";
+ case ColorFilterArray::MONO:
+ return out << "MONO";
+ default:
+ return out << "INVALID";
+ }
+}
+
+/**
+ * \brief Apply a transform to this ColorFilterArray
+ * \param[in] t The transform to apply
+ *
+ * Applying a transform to an image captured via a ColorFilterArray affects the
+ * color order. For example, performing a horizontal flip on the pattern 2x2
+ * 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. Performing a vertical
+ * flip on the 2x2 pattern RGGB causes the GB rows to come before the RG ones
+ * and the transformed image would have GBRG order. Applying both vertical and
+ * horizontal flips on the 2x2 pattern RGGB results in transformed images with
+ * BGGR order.
+ *
+ * Horizontal and vertical flips are applied before transpose.
+ *
+ * \return The transformed pattern as a ColorFilterArray
+ */
+ColorFilterArray ColorFilterArray::transform(Transform t) const
+{
+ ColorFilterArray result = *this;
+
+ if (order == MONO)
+ return result;
+
+ /*
+ * Observe that flipping bit 0 of the Order enum performs a horizontal
+ * mirror on the Bayer pattern (e.g. RG/GB goes to GR/BG). Similarly,
+ * flipping bit 1 performs a vertical mirror operation on it (e.g RG/GB
+ * goes to GB/RG). Applying both vertical and horizontal flips
+ * combines vertical and horizontal mirroring on the Bayer pattern
+ * (e.g. RG/GB goes to BG/GR). 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);
+
+ if (!!(t & Transform::Transpose) && result.order == 1)
+ result.order = static_cast<Order>(2);
+ else if (!!(t & Transform::Transpose) && result.order == 2)
+ result.order = static_cast<Order>(1);
+
+ return result;
+}
+
+/**
+ * \var ColorFilterArray::order
+ * \brief The order of the color channels in the filter array
+ */
+
+} /* namespace libcamera */
@@ -22,6 +22,7 @@ libcamera_internal_sources = files([
'camera_controls.cpp',
'camera_lens.cpp',
'clock_recovery.cpp',
+ 'color_filter_array.cpp',
'control_serializer.cpp',
'control_validator.cpp',
'converter.cpp',
@@ -22,6 +22,7 @@
#include <libcamera/base/utils.h>
#include <libcamera/camera.h>
+#include <libcamera/color_filter_array.h>
#include <libcamera/controls.h>
#include <libcamera/formats.h>
#include <libcamera/geometry.h>
@@ -328,7 +329,7 @@ int MaliC55CameraData::pixfmtToMbusCode(const PixelFormat &pixFmt) const
if (!sdBayerFormat.isValid())
continue;
- if (sdBayerFormat.order != bayerFormat.order)
+ if (sdBayerFormat.cfa.order != bayerFormat.cfa.order)
continue;
if (sdBayerFormat.bitDepth > bitDepth) {
@@ -368,7 +369,7 @@ const PixelFormat &MaliC55CameraData::bestRawFormat() const
continue;
BayerFormat bayer = BayerFormat::fromMbusCode(rawCode);
- if (bayer.order == sensorBayer.order)
+ if (bayer.cfa.order == sensorBayer.cfa.order)
return pixFmt;
}
}
@@ -1175,14 +1176,14 @@ int PipelineHandlerMaliC55::configure(Camera *camera,
ipaConfig.sensorControls = data->sensor()->controls();
/*
- * And we also need to tell the IPA the bayerOrder of the data (as
+ * And we also need to tell the IPA the cfaOrder of the data (as
* affected by any flips that we've configured)
*/
const Transform &combinedTransform = maliConfig->combinedTransform();
- BayerFormat::Order bayerOrder = data->sensor()->bayerOrder(combinedTransform);
+ ColorFilterArray::Order cfaOrder = data->sensor()->bayerOrder(combinedTransform);
ControlInfoMap ipaControls;
- ret = data->ipa_->configure(ipaConfig, utils::to_underlying(bayerOrder),
+ ret = data->ipa_->configure(ipaConfig, utils::to_underlying(cfaOrder),
&ipaControls);
if (ret) {
LOG(MaliC55, Error) << "Failed to configure IPA";
@@ -16,6 +16,7 @@
#include <libcamera/base/file.h>
#include <libcamera/base/utils.h>
+#include <libcamera/color_filter_array.h>
#include <libcamera/formats.h>
#include <libcamera/logging.h>
#include <libcamera/property_ids.h>
@@ -75,7 +76,7 @@ bool isMonoSensor(std::unique_ptr<CameraSensor> &sensor)
unsigned int mbusCode = sensor->mbusCodes()[0];
const BayerFormat &bayer = BayerFormat::fromMbusCode(mbusCode);
- return bayer.order == BayerFormat::Order::MONO;
+ return bayer.cfa.order == ColorFilterArray::Order::MONO;
}
const std::vector<ColorSpace> validColorSpaces = {
@@ -256,7 +257,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()
*/
BayerFormat cfgBayer = BayerFormat::fromPixelFormat(rawStream->pixelFormat);
- cfgBayer.order = data_->sensor_->bayerOrder(combinedTransform_);
+ cfgBayer.cfa = data_->sensor_->bayerOrder(combinedTransform_);
if (rawStream->pixelFormat != cfgBayer.toPixelFormat()) {
rawStream->pixelFormat = cfgBayer.toPixelFormat();
@@ -56,32 +56,32 @@ constexpr unsigned int DefaultCompressionOffset = 2048;
constexpr unsigned int DefaultCompressionMode = 1;
const std::vector<std::pair<BayerFormat, unsigned int>> BayerToMbusCodeMap{
- { { BayerFormat::BGGR, 8, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR8_1X8, },
- { { BayerFormat::GBRG, 8, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG8_1X8, },
- { { BayerFormat::GRBG, 8, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG8_1X8, },
- { { BayerFormat::RGGB, 8, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB8_1X8, },
- { { BayerFormat::BGGR, 10, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR10_1X10, },
- { { BayerFormat::GBRG, 10, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG10_1X10, },
- { { BayerFormat::GRBG, 10, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG10_1X10, },
- { { BayerFormat::RGGB, 10, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB10_1X10, },
- { { BayerFormat::BGGR, 12, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR12_1X12, },
- { { BayerFormat::GBRG, 12, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG12_1X12, },
- { { BayerFormat::GRBG, 12, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG12_1X12, },
- { { BayerFormat::RGGB, 12, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB12_1X12, },
- { { BayerFormat::BGGR, 14, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR14_1X14, },
- { { BayerFormat::GBRG, 14, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG14_1X14, },
- { { BayerFormat::GRBG, 14, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG14_1X14, },
- { { BayerFormat::RGGB, 14, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB14_1X14, },
- { { BayerFormat::BGGR, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR16_1X16, },
- { { BayerFormat::GBRG, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG16_1X16, },
- { { BayerFormat::GRBG, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG16_1X16, },
- { { BayerFormat::RGGB, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB16_1X16, },
- { { BayerFormat::BGGR, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_SBGGR16_1X16, },
- { { BayerFormat::GBRG, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_SGBRG16_1X16, },
- { { BayerFormat::GRBG, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_SGRBG16_1X16, },
- { { BayerFormat::RGGB, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_SRGGB16_1X16, },
- { { BayerFormat::MONO, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_Y16_1X16, },
- { { BayerFormat::MONO, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_Y16_1X16, },
+ { { ColorFilterArray::BGGR, 8, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR8_1X8, },
+ { { ColorFilterArray::GBRG, 8, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG8_1X8, },
+ { { ColorFilterArray::GRBG, 8, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG8_1X8, },
+ { { ColorFilterArray::RGGB, 8, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB8_1X8, },
+ { { ColorFilterArray::BGGR, 10, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR10_1X10, },
+ { { ColorFilterArray::GBRG, 10, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG10_1X10, },
+ { { ColorFilterArray::GRBG, 10, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG10_1X10, },
+ { { ColorFilterArray::RGGB, 10, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB10_1X10, },
+ { { ColorFilterArray::BGGR, 12, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR12_1X12, },
+ { { ColorFilterArray::GBRG, 12, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG12_1X12, },
+ { { ColorFilterArray::GRBG, 12, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG12_1X12, },
+ { { ColorFilterArray::RGGB, 12, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB12_1X12, },
+ { { ColorFilterArray::BGGR, 14, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR14_1X14, },
+ { { ColorFilterArray::GBRG, 14, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG14_1X14, },
+ { { ColorFilterArray::GRBG, 14, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG14_1X14, },
+ { { ColorFilterArray::RGGB, 14, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB14_1X14, },
+ { { ColorFilterArray::BGGR, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SBGGR16_1X16, },
+ { { ColorFilterArray::GBRG, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGBRG16_1X16, },
+ { { ColorFilterArray::GRBG, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SGRBG16_1X16, },
+ { { ColorFilterArray::RGGB, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_SRGGB16_1X16, },
+ { { ColorFilterArray::BGGR, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_SBGGR16_1X16, },
+ { { ColorFilterArray::GBRG, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_SGBRG16_1X16, },
+ { { ColorFilterArray::GRBG, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_SGRBG16_1X16, },
+ { { ColorFilterArray::RGGB, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_SRGGB16_1X16, },
+ { { ColorFilterArray::MONO, 16, BayerFormat::Packing::None }, MEDIA_BUS_FMT_Y16_1X16, },
+ { { ColorFilterArray::MONO, 16, BayerFormat::Packing::PISP1 }, MEDIA_BUS_FMT_Y16_1X16, },
};
unsigned int bayerToMbusCode(const BayerFormat &bayer)
@@ -100,7 +100,7 @@ unsigned int bayerToMbusCode(const BayerFormat &bayer)
uint32_t mbusCodeUnpacked16(unsigned int code)
{
BayerFormat bayer = BayerFormat::fromMbusCode(code);
- BayerFormat bayer16(bayer.order, 16, BayerFormat::Packing::None);
+ BayerFormat bayer16(bayer.cfa.order, 16, BayerFormat::Packing::None);
return bayerToMbusCode(bayer16);
}
@@ -109,16 +109,16 @@ uint8_t toPiSPBayerOrder(V4L2PixelFormat format)
{
BayerFormat bayer = BayerFormat::fromV4L2PixelFormat(format);
- switch (bayer.order) {
- case BayerFormat::Order::BGGR:
+ switch (bayer.cfa.order) {
+ case ColorFilterArray::Order::BGGR:
return PISP_BAYER_ORDER_BGGR;
- case BayerFormat::Order::GBRG:
+ case ColorFilterArray::Order::GBRG:
return PISP_BAYER_ORDER_GBRG;
- case BayerFormat::Order::GRBG:
+ case ColorFilterArray::Order::GRBG:
return PISP_BAYER_ORDER_GRBG;
- case BayerFormat::Order::RGGB:
+ case ColorFilterArray::Order::RGGB:
return PISP_BAYER_ORDER_RGGB;
- case BayerFormat::Order::MONO:
+ case ColorFilterArray::Order::MONO:
return PISP_BAYER_ORDER_GREYSCALE;
default:
ASSERT(0);
@@ -32,6 +32,7 @@
#include <libcamera/pixel_format.h>
#include <libcamera/stream.h>
+#include "libcamera/internal/bayer_format.h"
#include "libcamera/internal/camera.h"
#include "libcamera/internal/camera_manager.h"
#include "libcamera/internal/camera_sensor.h"
@@ -1534,7 +1535,7 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
* pattern.
*/
BayerFormat cfgBayer = BayerFormat::fromPixelFormat(pipeConfig->captureFormat);
- cfgBayer.order = data->sensor_->bayerOrder(config->combinedTransform());
+ cfgBayer.cfa.order = data->sensor_->bayerOrder(config->combinedTransform());
videoFormat = cfgBayer.toV4L2PixelFormat();
}
@@ -12,6 +12,7 @@
#include <limits.h>
#include <map>
#include <memory>
+#include <optional>
#include <string.h>
#include <string>
#include <vector>
@@ -21,6 +22,7 @@
#include <libcamera/base/utils.h>
#include <libcamera/camera.h>
+#include <libcamera/color_filter_array.h>
#include <libcamera/control_ids.h>
#include <libcamera/controls.h>
#include <libcamera/geometry.h>
@@ -41,7 +43,6 @@
namespace libcamera {
-class BayerFormat;
class CameraLens;
class MediaEntity;
class SensorConfiguration;
@@ -88,7 +89,7 @@ public:
const ControlList &properties() const override { return properties_; }
int sensorInfo(IPACameraSensorInfo *info) const override;
Transform computeTransform(Orientation *orientation) const override;
- BayerFormat::Order bayerOrder(Transform t) const override;
+ ColorFilterArray bayerOrder(Transform t) const override;
Orientation mountingOrientation() const override { return mountingOrientation_; }
const ControlInfoMap &controls() const override;
@@ -134,7 +135,7 @@ private:
Rectangle pixelArrayArea_;
Rectangle readableArea_;
Rectangle activeArea_;
- const BayerFormat *bayerFormat_;
+ std::optional<ColorFilterArray> cfa_;
bool supportHFlips_;
bool supportVFlips_;
bool flipsAlterBayerOrder_;
@@ -156,7 +157,7 @@ private:
CameraSensorLegacy::CameraSensorLegacy(const MediaEntity *entity)
: entity_(entity), pad_(UINT_MAX), staticProps_(nullptr),
- bayerFormat_(nullptr), supportHFlips_(false), supportVFlips_(false),
+ cfa_(std::nullopt), supportHFlips_(false), supportVFlips_(false),
flipsAlterBayerOrder_(false), properties_(properties::properties)
{
}
@@ -264,9 +265,9 @@ int CameraSensorLegacy::init()
/* Get the color filter array pattern (only for RAW sensors). */
for (unsigned int mbusCode : mbusCodes_) {
- const BayerFormat &bayerFormat = BayerFormat::fromMbusCode(mbusCode);
- if (bayerFormat.isValid()) {
- bayerFormat_ = &bayerFormat;
+ auto cfa = ColorFilterArray::fromMbusCode(mbusCode);
+ if (cfa) {
+ cfa_ = *cfa;
break;
}
}
@@ -445,7 +446,7 @@ int CameraSensorLegacy::validateSensorDriver()
<< "See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information";
}
- if (!bayerFormat_)
+ if (!cfa_)
return 0;
/*
@@ -640,22 +641,22 @@ int CameraSensorLegacy::initProperties()
properties_.set(properties::PixelArrayActiveAreas, { activeArea_ });
/* Color filter array pattern, register only for RAW sensors. */
- if (bayerFormat_) {
+ if (cfa_) {
int32_t cfa;
- switch (bayerFormat_->order) {
- case BayerFormat::BGGR:
+ switch (cfa_->order) {
+ case ColorFilterArray::BGGR:
cfa = properties::draft::BGGR;
break;
- case BayerFormat::GBRG:
+ case ColorFilterArray::GBRG:
cfa = properties::draft::GBRG;
break;
- case BayerFormat::GRBG:
+ case ColorFilterArray::GRBG:
cfa = properties::draft::GRBG;
break;
- case BayerFormat::RGGB:
+ case ColorFilterArray::RGGB:
cfa = properties::draft::RGGB;
break;
- case BayerFormat::MONO:
+ case ColorFilterArray::MONO:
cfa = properties::draft::MONO;
break;
}
@@ -881,7 +882,7 @@ V4L2Subdevice::Stream CameraSensorLegacy::imageStream() const
int CameraSensorLegacy::sensorInfo(IPACameraSensorInfo *info) const
{
- if (!bayerFormat_)
+ if (!cfa_)
return -EINVAL;
info->model = model();
@@ -982,20 +983,20 @@ Transform CameraSensorLegacy::computeTransform(Orientation *orientation) const
return transform;
}
-BayerFormat::Order CameraSensorLegacy::bayerOrder(Transform t) const
+ColorFilterArray CameraSensorLegacy::bayerOrder(Transform t) const
{
/* Return a defined by meaningless value for non-Bayer sensors. */
- if (!bayerFormat_)
- return BayerFormat::Order::BGGR;
+ if (!cfa_)
+ return ColorFilterArray::BGGR;
if (!flipsAlterBayerOrder_)
- return bayerFormat_->order;
+ return *cfa_;
/*
* Apply the transform to the native (i.e. untransformed) Bayer order,
* using the rest of the Bayer format supplied by the caller.
*/
- return bayerFormat_->transform(t).order;
+ return cfa_->transform(t);
}
const ControlInfoMap &CameraSensorLegacy::controls() const
@@ -22,6 +22,7 @@
#include <libcamera/base/utils.h>
#include <libcamera/camera.h>
+#include <libcamera/color_filter_array.h>
#include <libcamera/control_ids.h>
#include <libcamera/controls.h>
#include <libcamera/geometry.h>
@@ -42,7 +43,6 @@
namespace libcamera {
-class BayerFormat;
class CameraLens;
class MediaEntity;
class SensorConfiguration;
@@ -93,7 +93,7 @@ public:
const ControlList &properties() const override { return properties_; }
int sensorInfo(IPACameraSensorInfo *info) const override;
Transform computeTransform(Orientation *orientation) const override;
- BayerFormat::Order bayerOrder(Transform t) const override;
+ ColorFilterArray bayerOrder(Transform t) const override;
Orientation mountingOrientation() const override { return mountingOrientation_; }
const ControlInfoMap &controls() const override;
@@ -144,7 +144,7 @@ private:
Rectangle pixelArrayArea_;
Rectangle readableArea_;
Rectangle activeArea_;
- BayerFormat::Order cfaPattern_;
+ ColorFilterArray cfa_;
bool supportHFlips_;
bool supportVFlips_;
bool flipsAlterBayerOrder_;
@@ -489,16 +489,19 @@ std::optional<int> CameraSensorRaw::init()
switch (cfaPattern) {
case V4L2_CFA_PATTERN_GRBG:
- cfaPattern_ = BayerFormat::GRBG;
+ cfa_ = ColorFilterArray::GRBG;
break;
case V4L2_CFA_PATTERN_RGGB:
- cfaPattern_ = BayerFormat::RGGB;
+ cfa_ = ColorFilterArray::RGGB;
break;
case V4L2_CFA_PATTERN_BGGR:
- cfaPattern_ = BayerFormat::BGGR;
+ cfa_ = ColorFilterArray::BGGR;
break;
case V4L2_CFA_PATTERN_GBRG:
- cfaPattern_ = BayerFormat::GBRG;
+ cfa_ = ColorFilterArray::GBRG;
+ break;
+ case V4L2_CFA_PATTERN_MONO:
+ cfa_ = ColorFilterArray::MONO;
break;
default:
LOG(CameraSensor, Error)
@@ -667,20 +670,20 @@ int CameraSensorRaw::initProperties()
/* Color filter array pattern. */
uint32_t cfa;
- switch (cfaPattern_) {
- case BayerFormat::BGGR:
+ switch (cfa_.order) {
+ case ColorFilterArray::BGGR:
cfa = properties::draft::BGGR;
break;
- case BayerFormat::GBRG:
+ case ColorFilterArray::GBRG:
cfa = properties::draft::GBRG;
break;
- case BayerFormat::GRBG:
+ case ColorFilterArray::GRBG:
cfa = properties::draft::GRBG;
break;
- case BayerFormat::RGGB:
+ case ColorFilterArray::RGGB:
cfa = properties::draft::RGGB;
break;
- case BayerFormat::MONO:
+ case ColorFilterArray::MONO:
default:
cfa = properties::draft::MONO;
break;
@@ -1112,17 +1115,16 @@ Transform CameraSensorRaw::computeTransform(Orientation *orientation) const
return transform;
}
-BayerFormat::Order CameraSensorRaw::bayerOrder(Transform t) const
+ColorFilterArray CameraSensorRaw::bayerOrder(Transform t) const
{
if (!flipsAlterBayerOrder_)
- return cfaPattern_;
+ return cfa_;
/*
* Apply the transform to the native (i.e. untransformed) Bayer order,
* using the rest of the Bayer format supplied by the caller.
*/
- BayerFormat format{ cfaPattern_, 8, BayerFormat::Packing::None };
- return format.transform(t).order;
+ return cfa_.transform(t);
}
const ControlInfoMap &CameraSensorRaw::controls() const
@@ -330,13 +330,13 @@ void Debayer::dmaSyncBegin(std::vector<DmaSyncer> &dmaSyncers, FrameBuffer *inpu
}
/**
- * \fn void Debayer::isStandardBayerOrder(BayerFormat::Order order)
+ * \fn void Debayer::isStandardBayerOrder(ColorFilterArray::Order order)
* \brief Common method to validate standard 2x2 Bayer pattern of 2 Green, 1 Blue, 1 Red pixels
*/
-bool Debayer::isStandardBayerOrder(BayerFormat::Order order)
+bool Debayer::isStandardBayerOrder(ColorFilterArray::Order order)
{
- return order == BayerFormat::BGGR || order == BayerFormat::GBRG ||
- order == BayerFormat::GRBG || order == BayerFormat::RGGB;
+ return order == ColorFilterArray::BGGR || order == ColorFilterArray::GBRG ||
+ order == ColorFilterArray::GRBG || order == ColorFilterArray::RGGB;
}
} /* namespace libcamera */
@@ -87,7 +87,7 @@ private:
protected:
void dmaSyncBegin(std::vector<DmaSyncer> &dmaSyncers, FrameBuffer *input, FrameBuffer *output);
- static bool isStandardBayerOrder(BayerFormat::Order order);
+ static bool isStandardBayerOrder(ColorFilterArray::Order order);
};
} /* namespace libcamera */
@@ -442,7 +442,7 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf
if ((bayerFormat.bitDepth == 8 || bayerFormat.bitDepth == 10 || bayerFormat.bitDepth == 12) &&
bayerFormat.packing == BayerFormat::Packing::None &&
- isStandardBayerOrder(bayerFormat.order)) {
+ isStandardBayerOrder(bayerFormat.cfa.order)) {
config.bpp = (bayerFormat.bitDepth + 7) & ~7;
config.patternSize.width = 2;
config.patternSize.height = 2;
@@ -452,7 +452,7 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf
if (bayerFormat.bitDepth == 10 &&
bayerFormat.packing == BayerFormat::Packing::CSI2 &&
- isStandardBayerOrder(bayerFormat.order)) {
+ isStandardBayerOrder(bayerFormat.cfa.order)) {
config.bpp = 10;
config.patternSize.width = 4; /* 5 bytes per *4* pixels */
config.patternSize.height = 2;
@@ -462,7 +462,7 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf
if (bayerFormat.bitDepth == 12 &&
bayerFormat.packing == BayerFormat::Packing::CSI2 &&
- isStandardBayerOrder(bayerFormat.order)) {
+ isStandardBayerOrder(bayerFormat.cfa.order)) {
config.bpp = 12;
config.patternSize.width = 2; /* 3 bytes per *2* pixels */
config.patternSize.height = 2;
@@ -479,18 +479,18 @@ int DebayerCpu::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf
* Check for standard Bayer orders and set xShift_ and swap debayer0/1, so that
* a single pair of BGGR debayer functions can be used for all 4 standard orders.
*/
-int DebayerCpu::setupStandardBayerOrder(BayerFormat::Order order)
+int DebayerCpu::setupStandardBayerOrder(ColorFilterArray::Order order)
{
switch (order) {
- case BayerFormat::BGGR:
+ case ColorFilterArray::BGGR:
break;
- case BayerFormat::GBRG:
+ case ColorFilterArray::GBRG:
xShift_ = 1; /* BGGR -> GBRG */
break;
- case BayerFormat::GRBG:
+ case ColorFilterArray::GRBG:
std::swap(debayer0_, debayer1_); /* BGGR -> GRBG */
break;
- case BayerFormat::RGGB:
+ case ColorFilterArray::RGGB:
xShift_ = 1; /* BGGR -> GBRG */
std::swap(debayer0_, debayer1_); /* GBRG -> RGGB */
break;
@@ -540,18 +540,18 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat,
/* Swap R and B in bayer order to generate BGR888 instead of RGB888 */
swapRedBlueGains_ = true;
- switch (bayerFormat.order) {
- case BayerFormat::BGGR:
- bayerFormat.order = BayerFormat::RGGB;
+ switch (bayerFormat.cfa.order) {
+ case ColorFilterArray::BGGR:
+ bayerFormat.cfa.order = ColorFilterArray::RGGB;
break;
- case BayerFormat::GBRG:
- bayerFormat.order = BayerFormat::GRBG;
+ case ColorFilterArray::GBRG:
+ bayerFormat.cfa.order = ColorFilterArray::GRBG;
break;
- case BayerFormat::GRBG:
- bayerFormat.order = BayerFormat::GBRG;
+ case ColorFilterArray::GRBG:
+ bayerFormat.cfa.order = ColorFilterArray::GBRG;
break;
- case BayerFormat::RGGB:
- bayerFormat.order = BayerFormat::BGGR;
+ case ColorFilterArray::RGGB:
+ bayerFormat.cfa.order = ColorFilterArray::BGGR;
break;
default:
return invalidFmt();
@@ -563,7 +563,7 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat,
if ((bayerFormat.bitDepth == 8 || bayerFormat.bitDepth == 10 || bayerFormat.bitDepth == 12) &&
bayerFormat.packing == BayerFormat::Packing::None &&
- isStandardBayerOrder(bayerFormat.order)) {
+ isStandardBayerOrder(bayerFormat.cfa.order)) {
switch (bayerFormat.bitDepth) {
case 8:
SET_DEBAYER_METHODS(debayer8_BGBG_BGR888, debayer8_GRGR_BGR888)
@@ -575,23 +575,23 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat,
SET_DEBAYER_METHODS(debayer12_BGBG_BGR888, debayer12_GRGR_BGR888)
break;
}
- setupStandardBayerOrder(bayerFormat.order);
+ setupStandardBayerOrder(bayerFormat.cfa.order);
return 0;
}
if (bayerFormat.bitDepth == 10 &&
bayerFormat.packing == BayerFormat::Packing::CSI2) {
- switch (bayerFormat.order) {
- case BayerFormat::BGGR:
+ switch (bayerFormat.cfa.order) {
+ case ColorFilterArray::BGGR:
SET_DEBAYER_METHODS(debayer10P_BGBG_BGR888, debayer10P_GRGR_BGR888)
return 0;
- case BayerFormat::GBRG:
+ case ColorFilterArray::GBRG:
SET_DEBAYER_METHODS(debayer10P_GBGB_BGR888, debayer10P_RGRG_BGR888)
return 0;
- case BayerFormat::GRBG:
+ case ColorFilterArray::GRBG:
SET_DEBAYER_METHODS(debayer10P_GRGR_BGR888, debayer10P_BGBG_BGR888)
return 0;
- case BayerFormat::RGGB:
+ case ColorFilterArray::RGGB:
SET_DEBAYER_METHODS(debayer10P_RGRG_BGR888, debayer10P_GBGB_BGR888)
return 0;
default:
@@ -601,17 +601,17 @@ int DebayerCpu::setDebayerFunctions(PixelFormat inputFormat,
if (bayerFormat.bitDepth == 12 &&
bayerFormat.packing == BayerFormat::Packing::CSI2) {
- switch (bayerFormat.order) {
- case BayerFormat::BGGR:
+ switch (bayerFormat.cfa.order) {
+ case ColorFilterArray::BGGR:
SET_DEBAYER_METHODS(debayer12P_BGBG_BGR888, debayer12P_GRGR_BGR888)
return 0;
- case BayerFormat::GBRG:
+ case ColorFilterArray::GBRG:
SET_DEBAYER_METHODS(debayer12P_GBGB_BGR888, debayer12P_RGRG_BGR888)
return 0;
- case BayerFormat::GRBG:
+ case ColorFilterArray::GRBG:
SET_DEBAYER_METHODS(debayer12P_GRGR_BGR888, debayer12P_BGBG_BGR888)
return 0;
- case BayerFormat::RGGB:
+ case ColorFilterArray::RGGB:
SET_DEBAYER_METHODS(debayer12P_RGRG_BGR888, debayer12P_GBGB_BGR888)
return 0;
default:
@@ -122,7 +122,7 @@ private:
void debayer12P_RGRG_BGR888(uint8_t *dst, const uint8_t *src[]);
static int getInputConfig(PixelFormat inputFormat, DebayerInputConfig &config);
- int setupStandardBayerOrder(BayerFormat::Order order);
+ int setupStandardBayerOrder(ColorFilterArray::Order order);
int setDebayerFunctions(PixelFormat inputFormat,
PixelFormat outputFormat,
bool ccmEnabled);
@@ -63,7 +63,7 @@ int DebayerEGL::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf
if ((bayerFormat.bitDepth == 8 || bayerFormat.bitDepth == 10) &&
bayerFormat.packing == BayerFormat::Packing::None &&
- isStandardBayerOrder(bayerFormat.order)) {
+ isStandardBayerOrder(bayerFormat.cfa.order)) {
config.bpp = (bayerFormat.bitDepth + 7) & ~7;
config.patternSize.width = 2;
config.patternSize.height = 2;
@@ -73,7 +73,7 @@ int DebayerEGL::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf
if (bayerFormat.bitDepth == 10 &&
bayerFormat.packing == BayerFormat::Packing::CSI2 &&
- isStandardBayerOrder(bayerFormat.order)) {
+ isStandardBayerOrder(bayerFormat.cfa.order)) {
config.bpp = 10;
config.patternSize.width = 4; /* 5 bytes per *4* pixels */
config.patternSize.height = 2;
@@ -83,7 +83,7 @@ int DebayerEGL::getInputConfig(PixelFormat inputFormat, DebayerInputConfig &conf
if (bayerFormat.bitDepth == 12 &&
bayerFormat.packing == BayerFormat::Packing::CSI2 &&
- isStandardBayerOrder(bayerFormat.order)) {
+ isStandardBayerOrder(bayerFormat.cfa.order)) {
config.bpp = 12;
config.patternSize.width = 2; /* 3 bytes per *2* pixels */
config.patternSize.height = 2;
@@ -429,22 +429,22 @@ void SwStatsCpu::finishFrame(uint32_t frame, uint32_t bufferId)
* Check if order is a standard Bayer order and setup xShift_ and swapLines_
* so that a single BGGR stats function can be used for all 4 standard orders.
*/
-int SwStatsCpu::setupStandardBayerOrder(BayerFormat::Order order)
+int SwStatsCpu::setupStandardBayerOrder(ColorFilterArray::Order order)
{
switch (order) {
- case BayerFormat::BGGR:
+ case ColorFilterArray::BGGR:
xShift_ = 0;
swapLines_ = false;
break;
- case BayerFormat::GBRG:
+ case ColorFilterArray::GBRG:
xShift_ = 1; /* BGGR -> GBRG */
swapLines_ = false;
break;
- case BayerFormat::GRBG:
+ case ColorFilterArray::GRBG:
xShift_ = 0;
swapLines_ = true; /* BGGR -> GRBG */
break;
- case BayerFormat::RGGB:
+ case ColorFilterArray::RGGB:
xShift_ = 1; /* BGGR -> GBRG */
swapLines_ = true; /* GBRG -> RGGB */
break;
@@ -474,7 +474,7 @@ int SwStatsCpu::configure(const StreamConfiguration &inputCfg, unsigned int stat
BayerFormat::fromPixelFormat(inputCfg.pixelFormat);
if (bayerFormat.packing == BayerFormat::Packing::None &&
- setupStandardBayerOrder(bayerFormat.order) == 0) {
+ setupStandardBayerOrder(bayerFormat.cfa.order) == 0) {
processFrame_ = &SwStatsCpu::processBayerFrame2;
switch (bayerFormat.bitDepth) {
case 8:
@@ -509,16 +509,16 @@ int SwStatsCpu::configure(const StreamConfiguration &inputCfg, unsigned int stat
sumShift_ = 0;
processFrame_ = &SwStatsCpu::processBayerFrame2;
- switch (bayerFormat.order) {
- case BayerFormat::BGGR:
- case BayerFormat::GRBG:
+ switch (bayerFormat.cfa.order) {
+ case ColorFilterArray::BGGR:
+ case ColorFilterArray::GRBG:
stats0_ = (bitDepth == 10) ? &SwStatsCpu::statsBGGR10PLine0 : &SwStatsCpu::statsBGGR12PLine0;
- swapLines_ = bayerFormat.order == BayerFormat::GRBG;
+ swapLines_ = bayerFormat.cfa.order == ColorFilterArray::GRBG;
return 0;
- case BayerFormat::GBRG:
- case BayerFormat::RGGB:
+ case ColorFilterArray::GBRG:
+ case ColorFilterArray::RGGB:
stats0_ = (bitDepth == 10) ? &SwStatsCpu::statsGBRG10PLine0 : &SwStatsCpu::statsGBRG12PLine0;
- swapLines_ = bayerFormat.order == BayerFormat::RGGB;
+ swapLines_ = bayerFormat.cfa.order == ColorFilterArray::RGGB;
return 0;
default:
break;
@@ -30,7 +30,7 @@ protected:
}
/* A correct Bayer format has to be valid. */
- bayerFmt = BayerFormat(BayerFormat::BGGR, 8, BayerFormat::Packing::None);
+ bayerFmt = BayerFormat(ColorFilterArray::BGGR, 8, BayerFormat::Packing::None);
if (!bayerFmt.isValid()) {
cerr << "A correct BayerFormat has to be valid."
<< endl;
@@ -41,8 +41,8 @@ protected:
* Two bayer formats created with the same order and bit depth
* have to be equal.
*/
- bayerFmt = BayerFormat(BayerFormat::BGGR, 8, BayerFormat::Packing::None);
- BayerFormat bayerFmtExpect = BayerFormat(BayerFormat::BGGR, 8,
+ bayerFmt = BayerFormat(ColorFilterArray::BGGR, 8, BayerFormat::Packing::None);
+ BayerFormat bayerFmtExpect = BayerFormat(ColorFilterArray::BGGR, 8,
BayerFormat::Packing::None);
if (bayerFmt != bayerFmtExpect) {
cerr << "Comparison of identical formats failed."
@@ -54,8 +54,8 @@ protected:
* Two Bayer formats created with the same order but with a
* different bitDepth are not equal.
*/
- bayerFmt = BayerFormat(BayerFormat::BGGR, 8, BayerFormat::Packing::None);
- bayerFmtExpect = BayerFormat(BayerFormat::BGGR, 12,
+ bayerFmt = BayerFormat(ColorFilterArray::BGGR, 8, BayerFormat::Packing::None);
+ bayerFmtExpect = BayerFormat(ColorFilterArray::BGGR, 12,
BayerFormat::Packing::None);
if (bayerFmt == bayerFmtExpect) {
cerr << "Comparison of different formats failed."
@@ -95,7 +95,7 @@ protected:
* when we convert the V4L2PixelFormat (V4L2_PIX_FMT_SBGGR8)
* to a Bayer format.
*/
- bayerFmtExpect = BayerFormat(BayerFormat::BGGR, 8,
+ bayerFmtExpect = BayerFormat(ColorFilterArray::BGGR, 8,
BayerFormat::Packing::None);
v4l2Fmt = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR8);
bayerFmt = BayerFormat::fromV4L2PixelFormat(v4l2Fmt);
@@ -123,7 +123,7 @@ protected:
* Test if a valid Bayer format can be converted to a
* string representation.
*/
- bayerFmt = BayerFormat(BayerFormat::BGGR, 8, BayerFormat::Packing::None);
+ bayerFmt = BayerFormat(ColorFilterArray::BGGR, 8, BayerFormat::Packing::None);
if (bayerFmt.toString() != "BGGR-8") {
cerr << "String representation != 'BGGR-8' (got: '"
<< bayerFmt.toString() << "' ) " << endl;
@@ -145,10 +145,11 @@ protected:
* Perform a horizontal Flip and make sure that the
* order is adjusted accordingly.
*/
- bayerFmt = BayerFormat(BayerFormat::BGGR, 8, BayerFormat::Packing::None);
- bayerFmtExpect = BayerFormat(BayerFormat::GBRG, 8,
+ bayerFmt = BayerFormat(ColorFilterArray::BGGR, 8, BayerFormat::Packing::None);
+ bayerFmtExpect = BayerFormat(ColorFilterArray::GBRG, 8,
BayerFormat::Packing::None);
- BayerFormat hFlipFmt = bayerFmt.transform(Transform::HFlip);
+ BayerFormat hFlipFmt = bayerFmt;
+ hFlipFmt.cfa = bayerFmt.cfa.transform(Transform::HFlip);
if (hFlipFmt != bayerFmtExpect) {
cerr << "Horizontal flip of 'BGGR-8' should result in '"
<< bayerFmtExpect << "', got: '"
@@ -160,10 +161,11 @@ protected:
* Perform a vertical Flip and make sure that
* the order is adjusted accordingly.
*/
- bayerFmt = BayerFormat(BayerFormat::BGGR, 8, BayerFormat::Packing::None);
- bayerFmtExpect = BayerFormat(BayerFormat::GRBG, 8,
+ bayerFmt = BayerFormat(ColorFilterArray::BGGR, 8, BayerFormat::Packing::None);
+ bayerFmtExpect = BayerFormat(ColorFilterArray::GRBG, 8,
BayerFormat::Packing::None);
- BayerFormat vFlipFmt = bayerFmt.transform(Transform::VFlip);
+ BayerFormat vFlipFmt = bayerFmt;
+ vFlipFmt.cfa = bayerFmt.cfa.transform(Transform::VFlip);
if (vFlipFmt != bayerFmtExpect) {
cerr << "Vertical flip of 'BGGR-8' should result in '"
<< bayerFmtExpect << "', got: '"
@@ -176,9 +178,9 @@ protected:
* pixels on the bottom left to top right diagonal and make
* sure, that it doesn't change.
*/
- bayerFmt = BayerFormat(BayerFormat::BGGR, 8, BayerFormat::Packing::None);
- BayerFormat transposeFmt = bayerFmt.transform(
- Transform::Transpose);
+ bayerFmt = BayerFormat(ColorFilterArray::BGGR, 8, BayerFormat::Packing::None);
+ BayerFormat transposeFmt = bayerFmt;
+ transposeFmt.cfa = bayerFmt.cfa.transform( Transform::Transpose);
if (transposeFmt != bayerFmt) {
cerr << "Transpose with both green pixels on the "
<< "antidiagonal should not change the order "
@@ -192,10 +194,10 @@ protected:
* on the bottom left to top right diagonal and make sure
* that their positions are switched.
*/
- bayerFmt = BayerFormat(BayerFormat::GBRG, 8, BayerFormat::Packing::None);
- bayerFmtExpect = BayerFormat(BayerFormat::GRBG, 8,
+ bayerFmt = BayerFormat(ColorFilterArray::GBRG, 8, BayerFormat::Packing::None);
+ bayerFmtExpect = BayerFormat(ColorFilterArray::GRBG, 8,
BayerFormat::Packing::None);
- transposeFmt = bayerFmt.transform(Transform::Transpose);
+ transposeFmt.cfa = bayerFmt.cfa.transform(Transform::Transpose);
if (transposeFmt != bayerFmtExpect) {
cerr << "Transpose with the red & blue pixels on the "
<< "antidiagonal should switch their position "
Following the common raw sensor model in V4L2, we want to separate out the bayer order of the color filter array along with the explosion of permutations caused by them, from the actual raw format transmitted on the bus, which is relatively simple (bitdepth, packing and compression). As a first step, separate out the bayer order into a separate ColorFilterArray class. This is still used by and tied closely to the BayerFormat class for now. Keep this new header external as in subsequent commits the CFA will be exposed through the StreamConfiguration to applications. Make sure all references to the BayerFormat::Order are replaced throughout the codebase. No functional changes intended in this commit. Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com> --- include/libcamera/color_filter_array.h | 58 ++++ include/libcamera/internal/bayer_format.h | 18 +- include/libcamera/internal/camera_sensor.h | 4 +- .../libcamera/internal/software_isp/swstats_cpu.h | 2 +- include/libcamera/meson.build | 1 + src/ipa/mali-c55/algorithms/agc.cpp | 14 +- src/ipa/mali-c55/algorithms/agc.h | 5 +- src/ipa/mali-c55/ipa_context.h | 5 +- src/ipa/mali-c55/mali-c55.cpp | 4 +- src/libcamera/bayer_format.cpp | 268 ++++++----------- src/libcamera/color_filter_array.cpp | 334 +++++++++++++++++++++ src/libcamera/meson.build | 1 + src/libcamera/pipeline/mali-c55/mali-c55.cpp | 11 +- .../pipeline/rpi/common/pipeline_base.cpp | 5 +- src/libcamera/pipeline/rpi/pisp/pisp.cpp | 66 ++-- src/libcamera/pipeline/simple/simple.cpp | 3 +- src/libcamera/sensor/camera_sensor_legacy.cpp | 43 +-- src/libcamera/sensor/camera_sensor_raw.cpp | 36 +-- src/libcamera/software_isp/debayer.cpp | 8 +- src/libcamera/software_isp/debayer.h | 2 +- src/libcamera/software_isp/debayer_cpu.cpp | 58 ++-- src/libcamera/software_isp/debayer_cpu.h | 2 +- src/libcamera/software_isp/debayer_egl.cpp | 6 +- src/libcamera/software_isp/swstats_cpu.cpp | 26 +- test/bayer-format.cpp | 40 +-- 25 files changed, 671 insertions(+), 349 deletions(-)