[{"id":12327,"web_url":"https://patchwork.libcamera.org/comment/12327/","msgid":"<20200906004110.GR6319@pendragon.ideasonboard.com>","date":"2020-09-06T00:41:10","subject":"Re: [libcamera-devel] [PATCH v7 4/8] libcamera: Add BayerFormat type","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi David,\n\nThank you for the patch.\n\nOn Fri, Sep 04, 2020 at 11:30:38AM +0100, David Plowman wrote:\n> This type encodes BayerFormats in an explicit way, that makes them\n> easier to use than some of the other more opaque type formats. This\n> makes the BayerFormat useful for editing or manipulating Bayer types\n> more easily.\n> \n> Signed-off-by: David Plowman <david.plowman@raspberrypi.com>\n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> ---\n>  include/libcamera/internal/bayer_format.h |  60 ++++++\n>  src/libcamera/bayer_format.cpp            | 231 ++++++++++++++++++++++\n>  src/libcamera/meson.build                 |   1 +\n>  3 files changed, 292 insertions(+)\n>  create mode 100644 include/libcamera/internal/bayer_format.h\n>  create mode 100644 src/libcamera/bayer_format.cpp\n> \n> diff --git a/include/libcamera/internal/bayer_format.h b/include/libcamera/internal/bayer_format.h\n> new file mode 100644\n> index 0000000..deeef5b\n> --- /dev/null\n> +++ b/include/libcamera/internal/bayer_format.h\n> @@ -0,0 +1,60 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Raspberry Pi (Trading) Ltd.\n> + *\n> + * bayer_format.h - Bayer Pixel Format\n> + */\n> +#ifndef __LIBCAMERA_INTERNAL_BAYER_FORMAT_H__\n> +#define __LIBCAMERA_INTERNAL_BAYER_FORMAT_H__\n> +\n> +#include <stdint.h>\n> +#include <string>\n> +\n> +#include \"libcamera/internal/v4l2_pixelformat.h\"\n> +\n> +namespace libcamera {\n> +\n> +enum class Transform;\n> +\n> +class BayerFormat\n> +{\n> +public:\n> +\tenum Order : uint8_t {\n> +\t\tBGGR = 0,\n> +\t\tGBRG = 1,\n> +\t\tGRBG = 2,\n> +\t\tRGGB = 3\n> +\t};\n> +\n> +\tenum Modifier : uint16_t {\n> +\t\tNone = 0,\n> +\t\tPacked = 1,\n\nI'd name this CSI2Packed (or CSI2Packing), as other packing schemes\nexist.\n\nWhat other modifiers do we expect ? I'm wondering if we shouldn't rename\nthis to Packing, and turn the modifiers field into packing. Otherwise we\nshould define the modifiers as bitmasks (e.g. (1 << 0) for Packed), and\nit may make it more difficult to handle the modifiers.\n\n> +\t};\n> +\n> +\tconstexpr BayerFormat()\n> +\t\t: order(Order::BGGR), bitDepth(0), modifiers(Modifier::None)\n> +\t{\n> +\t}\n> +\n> +\tconstexpr BayerFormat(Order o, uint8_t b, Modifier m)\n> +\t\t: order(o), bitDepth(b), modifiers(m)\n> +\t{\n> +\t}\n> +\n> +\texplicit BayerFormat(V4L2PixelFormat v4l2Format);\n> +\tbool isValid() const { return bitDepth != 0; }\n> +\n> +\tstd::string toString() const;\n> +\n> +\tV4L2PixelFormat toV4L2PixelFormat() const;\n> +\tBayerFormat transform(Transform t) const;\n> +\n> +\tOrder order;\n> +\tuint8_t bitDepth;\n> +\n> +\tModifier modifiers;\n> +};\n> +\n> +} /* namespace libcamera */\n> +\n> +#endif /* __LIBCAMERA_INTERNAL_BAYER_FORMAT_H__ */\n> diff --git a/src/libcamera/bayer_format.cpp b/src/libcamera/bayer_format.cpp\n> new file mode 100644\n> index 0000000..3780d7d\n> --- /dev/null\n> +++ b/src/libcamera/bayer_format.cpp\n> @@ -0,0 +1,231 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2020, Raspberry Pi (Trading) Limited\n> + *\n> + * bayer_format.cpp - class to represent Bayer formats\n\ns/class/Class/ (or copy the description from the .h file)\n\n> + */\n> +\n> +#include \"libcamera/internal/bayer_format.h\"\n> +\n> +#include <map>\n> +\n> +#include <libcamera/transform.h>\n> +\n> +/**\n> + * \\file bayer_format.h\n> + * \\brief Class to represent Bayer formats and manipulate them\n> + */\n> +\n> +namespace libcamera {\n> +\n> +/**\n> + * \\class BayerFormat\n> + * \\brief Class to represent a raw image Bayer format\n> + *\n> + * This class encodes the different Bayer formats in such a way that they can\n> + * be easily manipulated. For example, the bit depth or Bayer order can be\n> + * easily altered - the Bayer order can even be \"transformed\" in the same\n> + * manner as happens in many sensors when their horizontal or vertical \"flip\"\n> + * controls are set.\n> + */\n> +\n> +/**\n> + * \\enum BayerFormat::Order\n> + * \\brief The order of the colour channels in the Bayer pattern\n> + *\n> + * \\var BayerFormat::BGGR\n> + * \\brief B then G on the first row, G then R on the second row.\n> + * \\var BayerFormat::GBRG\n> + * \\brief G then B on the first row, R then G on the second row.\n> + * \\var BayerFormat::GRBG\n> + * \\brief G then R on the first row, B then G on the second row.\n> + * \\var BayerFormat::RGGB\n> + * \\brief T then G on the first row, G then B on the second row.\n\ns/T/R/\n\n> + */\n> +\n> +/**\n> + * \\enum BayerFormat::Modifier\n> + * \\brief Modifiers that can apply to a BayerFormat\n> + *\n> + * \\var BayerFormat::None\n> + * \\brief No modifiers\n> + * \\var BayerFormat::Packed\n> + * \\brief Format uses MIPI CSI-2 style packing\n> + */\n> +\n> +namespace {\n> +\n> +const std::map<V4L2PixelFormat, BayerFormat> v4l2ToBayer{\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SBGGR8), { BayerFormat::BGGR, 8, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SGBRG8), { BayerFormat::GBRG, 8, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SGRBG8), { BayerFormat::GRBG, 8, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SRGGB8), { BayerFormat::RGGB, 8, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10), { BayerFormat::BGGR, 10, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10), { BayerFormat::GBRG, 10, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10), { BayerFormat::GRBG, 10, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10), { BayerFormat::RGGB, 10, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10P), { BayerFormat::BGGR, 10, BayerFormat::Packed } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10P), { BayerFormat::GBRG, 10, BayerFormat::Packed } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10P), { BayerFormat::GRBG, 10, BayerFormat::Packed } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P), { BayerFormat::RGGB, 10, BayerFormat::Packed } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12), { BayerFormat::BGGR, 12, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12), { BayerFormat::GBRG, 12, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12), { BayerFormat::GRBG, 12, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12), { BayerFormat::RGGB, 12, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12P), { BayerFormat::BGGR, 12, BayerFormat::Packed } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12P), { BayerFormat::GBRG, 12, BayerFormat::Packed } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12P), { BayerFormat::GRBG, 12, BayerFormat::Packed } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12P), { BayerFormat::RGGB, 12, BayerFormat::Packed } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SBGGR16), { BayerFormat::BGGR, 16, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SGBRG16), { BayerFormat::GBRG, 16, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SGRBG16), { BayerFormat::GRBG, 16, BayerFormat::None } },\n> +\t{ V4L2PixelFormat(V4L2_PIX_FMT_SRGGB16), { BayerFormat::RGGB, 16, BayerFormat::None } },\n> +};\n> +\n> +/* Define a slightly arbitrary ordering so that we can use a std::map. */\n> +struct BayerFormatComparator {\n> +\tbool operator()(const BayerFormat &left, const BayerFormat &right) const\n\nThe operands are commonly named lhs and rhs.\n\n> +\t{\n> +\t\treturn left.bitDepth > right.bitDepth ||\n> +\t\t       (left.bitDepth == right.bitDepth && left.order > right.order) ||\n> +\t\t       (left.bitDepth == right.bitDepth && left.order == right.order &&\n> +\t\t\tleft.modifiers > right.modifiers);\n\nstd::map used std::less as the default comparator. While your\nimplementation satisfies the Compare requirements, wouldn't it be good\nto implement lhs < rhs instead of lhs > rhs ?\n\nI was going to suggest that the following may be more readable\n\n\t\tif (lhs.bitDepth < rhs.bitDepth)\n\t\t\treturn true;\n\t\telse if (lhs.bitDepth > rhs.bitDepth)\n\t\t\treturn false;\n\n\t\tif (lhs.order < rhs.order)\n\t\t\treturn true;\n\t\telse if (lhs.order > rhs.order)\n\t\t\treturn false;\n\n\t\tif (lhs.modifiers < rhs.modifiers)\n\t\t\treturn true;\n\t\telse\n\t\t\treturn false;\n\nbut I'm actually not sure :-)\n\n> +\t}\n> +};\n\nNote that we could also inject a custom specialization of less<> in the\nstd namespace:\n\nnamespace std {\n\n/* Define a slightly arbitrary ordering so that we can use a std::map. */\ntemplate<> struct less<libcamera::BayerFormat> {\n\tconstexpr bool operator()(const libcamera::BayerFormat &lhs,\n\t\t\t\t  const libcamera::BayerFormat &rhs) const\n\t{\n\t\treturn lhs.bitDepth > rhs.bitDepth ||\n\t\t       (lhs.bitDepth == rhs.bitDepth && lhs.order > rhs.order) ||\n\t\t       (lhs.bitDepth == rhs.bitDepth && lhs.order == rhs.order &&\n\t\t\tlhs.modifiers > rhs.modifiers);\n\t}\n};\n\n} /* namespace std */\n\nThis is allowed by C++ (see\nhttps://en.cppreference.com/w/cpp/language/extending_std). I'll let you\npick the option you like best. The map would then be declared as\nstd::map<BayerFormat, V4L2PixelFormat>.\n\nI was going to say that we could avoid the need for an ordering function\nby switching to std::unordered_map, but then we'll need a custom hash\nfunction which may not be better. For the record (and because I wanted\nto learn how it would be done),\n\nnamespace std {\n\n/* Define a slightly arbitrary ordering so that we can use a std::map. */\ntemplate<> struct hash<libcamera::BayerFormat> {\nprivate:\n\ttemplate<typename T>\n\tvoid combine(size_t &seed, const T &v) const\n\t{\n\t\tstd::hash<T> hasher;\n\t\tseed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);\n\t}\n\npublic:\n\tsize_t operator()(const libcamera::BayerFormat &format) const\n\t{\n\t\tsize_t seed = 0;\n\t\tcombine(seed, format.bitDepth);\n\t\tcombine(seed, format.order);\n\t\tcombine(seed, format.modifiers);\n\t\treturn seed;\n\t}\n};\n\n} /* namespace std */\n\n(we would need a BayerFormat::operator==() too)\n\n> +\n> +const std::map<BayerFormat, V4L2PixelFormat, BayerFormatComparator> bayerToV4l2{\n> +\t{ { BayerFormat::BGGR, 8, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR8) },\n> +\t{ { BayerFormat::GBRG, 8, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG8) },\n> +\t{ { BayerFormat::GRBG, 8, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG8) },\n> +\t{ { BayerFormat::RGGB, 8, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB8) },\n> +\t{ { BayerFormat::BGGR, 10, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10) },\n> +\t{ { BayerFormat::GBRG, 10, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10) },\n> +\t{ { BayerFormat::GRBG, 10, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10) },\n> +\t{ { BayerFormat::RGGB, 10, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10) },\n> +\t{ { BayerFormat::BGGR, 10, BayerFormat::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10P) },\n> +\t{ { BayerFormat::GBRG, 10, BayerFormat::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10P) },\n> +\t{ { BayerFormat::GRBG, 10, BayerFormat::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10P) },\n> +\t{ { BayerFormat::RGGB, 10, BayerFormat::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P) },\n> +\t{ { BayerFormat::BGGR, 12, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12) },\n> +\t{ { BayerFormat::GBRG, 12, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12) },\n> +\t{ { BayerFormat::GRBG, 12, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12) },\n> +\t{ { BayerFormat::RGGB, 12, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12) },\n> +\t{ { BayerFormat::BGGR, 12, BayerFormat::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12P) },\n> +\t{ { BayerFormat::GBRG, 12, BayerFormat::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12P) },\n> +\t{ { BayerFormat::GRBG, 12, BayerFormat::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12P) },\n> +\t{ { BayerFormat::RGGB, 12, BayerFormat::Packed }, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12P) },\n> +\t{ { BayerFormat::BGGR, 16, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SBGGR16) },\n> +\t{ { BayerFormat::GBRG, 16, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGBRG16) },\n> +\t{ { BayerFormat::GRBG, 16, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SGRBG16) },\n> +\t{ { BayerFormat::RGGB, 16, BayerFormat::None }, V4L2PixelFormat(V4L2_PIX_FMT_SRGGB16) },\n\nCould you already add the IPU3 packed formats to these tables ? They can\nbe found in formats.cpp.\n\n> +};\n> +\n> +} // namespace\n> +\n> +/**\n> + * \\fn BayerFormat::BayerFormat()\n> + * \\brief Construct an empty (and invalid) BayerFormat\n> + */\n> +\n> +/**\n> + * \\fn BayerFormat::BayerFormat(Order o, uint8_t b, Modifier m)\n> + * \\brief Construct a BayerFormat from explicit values\n\nMissing \\param[in] for the three arguments.\n\n> + */\n> +\n> +/**\n> + * \\brief Construct a BayerFormat from a V4L2PixelFormat\n> + * \\param[in] v4l2Format The raw format to convert into a BayerFormat\n> + */\n> +BayerFormat::BayerFormat(V4L2PixelFormat v4l2Format)\n> +{\n> +\tconst auto it = v4l2ToBayer.find(v4l2Format);\n> +\tif (it == v4l2ToBayer.end())\n> +\t\tbitDepth = 0;\n\nThis will leave order and modifiers uninitialized. This should be an\nissue in most cases as the caller should call isValid() first, but it\ncould become a problem if the resulting BayerFormat was compared with\nBayerFormatComparator (or hashed) as it would generate uninitialized\nread warnings from valgrind. I think setting the other members would be\nbest.\n\n> +\telse\n> +\t\t*this = it->second;\n> +}\n> +\n> +/**\n> + * \\fn BayerFormat::isValid()\n> + * \\brief Return whether a BayerFormat is valid\n> + */\n> +\n> +/**\n> + * \\brief Returns a readable string representation of the BayerFormat\n\nFor consistency with the rest of the code base,\ns/Returns a readable string/Assemble and return a string/\n\nand\n\n * \\return A string describing the BayerFormat\n\n> + */\n> +std::string BayerFormat::toString() const\n> +{\n> +\tstd::string result;\n> +\n> +\tstatic const char *orderStrings[] = {\n> +\t\t\"BGGR\",\n> +\t\t\"GBRG\",\n> +\t\t\"GRBG\",\n> +\t\t\"RGGB\"\n> +\t};\n> +\tif (order <= RGGB)\n> +\t\tresult = orderStrings[order];\n> +\telse\n> +\t\tresult = \"unknown\";\n\nAs this should never happen, how about just\n\n\treturn \"INVALID\";\n\nor a similar string ? We should also return the same if !isValid().\n\n> +\n> +\tresult += \"-\" + std::to_string(bitDepth);\n> +\n> +\tif (modifiers & Packed)\n> +\t\tresult += \"-P\";\n> +\n> +\treturn result;\n> +}\n> +\n> +/**\n> + * \\brief Convert a BayerFormat into the corresponding V4L2PixelFormat\n\nMissing \\return\n\n> + */\n> +V4L2PixelFormat BayerFormat::toV4L2PixelFormat() const\n> +{\n> +\tconst auto it = bayerToV4l2.find(*this);\n> +\tif (it != bayerToV4l2.end())\n> +\t\treturn it->second;\n> +\n> +\treturn V4L2PixelFormat();\n> +}\n> +\n> +/**\n> + * \\brief Apply a transform to this BayerFormat.\n\ns/.$//\n\n> + * \\param[in] t The transform to apply\n> + *\n> + * For example, performing a horizontal flip on the Bayer pattern RGGB causes\n> + * the RG rows of pixels to become GR, and the GB rows become BG. So the final\n> + * result in this case would be GRBG.\n\nLet's make clear that this only affects the Bayer order.\n\n * Appplying a transform to an image stored in a Bayer format affects the Bayer\n * order. For example, performing a horizontal flip on the Bayer pattern\n * RGGB causes the RG rows of pixels to become GR, and the GB rows to become BG.\n * The transformed image would have a GRBG order. The bit depth and modifiers\n * are not affected.\n *\n * \\return The transformed Bayer format\n\n> + */\n> +BayerFormat BayerFormat::transform(Transform t) const\n> +{\n> +\tBayerFormat result = *this;\n> +\n> +\t/*\n> +\t * Observe that flipping bit 0 of the Order enum performs a horizontal\n> +\t * mirror on the Bayer pattern (e.g. RGGB goes to GRBG). Similarly,\n> +\t * flipping bit 1 performs a vertical mirror operation on it. Hence:\n> +\t */\n> +\tif (!!(t & Transform::HFlip))\n> +\t\tresult.order = static_cast<Order>(result.order ^ 1);\n> +\tif (!!(t & Transform::VFlip))\n> +\t\tresult.order = static_cast<Order>(result.order ^ 2);\n\nShouldn't we also support Transform::Transpose to be complete ?\n\n> +\n> +\treturn result;\n> +}\n> +\n> +/**\n> + * \\var BayerFormat::order\n> + * \\brief The order of the colour channels in the Bayer pattern\n> + */\n> +\n> +/**\n> + * \\var BayerFormat::bitDepth\n> + * \\brief The bit depth of the samples in the Bayer pattern\n> + */\n> +\n> +/**\n> + * \\var BayerFormat::modifiers\n> + * \\brief Any modifier flags applied to this BayerFormat\n> + */\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> index edec55e..86c225f 100644\n> --- a/src/libcamera/meson.build\n> +++ b/src/libcamera/meson.build\n> @@ -1,6 +1,7 @@\n>  # SPDX-License-Identifier: CC0-1.0\n>  \n>  libcamera_sources = files([\n> +    'bayer_format.cpp',\n>      'bound_method.cpp',\n>      'buffer.cpp',\n>      'byte_stream_buffer.cpp',","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 06EBDBDB1C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun,  6 Sep 2020 00:41:37 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 626E362B66;\n\tSun,  6 Sep 2020 02:41:36 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 6724461EA0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun,  6 Sep 2020 02:41:35 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 9643F277;\n\tSun,  6 Sep 2020 02:41:34 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"G3Y5Q2XM\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1599352894;\n\tbh=DnNXvV16pxzHPzSKn/iEebJNKQY5subpiY/KbJ18RH8=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=G3Y5Q2XMxXN3JYwtOYUKZeij3+7jRS4/f5NOdzBVEO/QBKKV07rskbmVBQZpD/vTD\n\t89NekyZCBxeDfU7ggHi0d3Ow8butlCWGfUIib71oS3MAQ9RXk9oKQUfZ7nAyCrYMai\n\tK4xRFMWfh250Xkm/Ff4fzwmmXcsif/xlSz54ID+M=","Date":"Sun, 6 Sep 2020 03:41:10 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"David Plowman <david.plowman@raspberrypi.com>","Message-ID":"<20200906004110.GR6319@pendragon.ideasonboard.com>","References":"<20200904103042.1593-1-david.plowman@raspberrypi.com>\n\t<20200904103042.1593-5-david.plowman@raspberrypi.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20200904103042.1593-5-david.plowman@raspberrypi.com>","Subject":"Re: [libcamera-devel] [PATCH v7 4/8] libcamera: Add BayerFormat type","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]