Message ID | 20211020110825.12902-2-david.plowman@raspberrypi.com |
---|---|
State | Superseded |
Headers | show |
Series |
|
Related | show |
Hi David, Thank you for your work. On Wed, 20 Oct 2021 at 12:08, David Plowman <david.plowman@raspberrypi.com> wrote: > This class represents a color space by defining its color primaries, > YCbCr encoding, the transfer (gamma) function it uses, and whether the > output is full or limited range. > > Signed-off-by: David Plowman <david.plowman@raspberrypi.com> > --- > include/libcamera/color_space.h | 88 +++++++++++ > include/libcamera/meson.build | 1 + > src/libcamera/color_space.cpp | 256 ++++++++++++++++++++++++++++++++ > src/libcamera/meson.build | 1 + > 4 files changed, 346 insertions(+) > create mode 100644 include/libcamera/color_space.h > create mode 100644 src/libcamera/color_space.cpp > > diff --git a/include/libcamera/color_space.h > b/include/libcamera/color_space.h > new file mode 100644 > index 00000000..2af9da31 > --- /dev/null > +++ b/include/libcamera/color_space.h > @@ -0,0 +1,88 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2021, Raspberry Pi (Trading) Limited > + * > + * color_space.h - color space definitions > + */ > + > +#ifndef __LIBCAMERA_COLOR_SPACE_H__ > +#define __LIBCAMERA_COLOR_SPACE_H__ > + > +#include <string> > + > +namespace libcamera { > + > +class ColorSpace > +{ > +public: > + enum class Primaries : int { > + Undefined, > + Raw, > + Smpte170m, > + Rec709, > + Rec2020, > + }; > + > + enum class YcbcrEncoding : int { > + Undefined, > + Rec601, > + Rec709, > + Rec2020, > + }; > + > + enum class TransferFunction : int { > + Undefined, > + Linear, > + Srgb, > + Rec709, > + }; > + > + enum class Range : int { > + Undefined, > + Full, > + Limited, > + }; > + > + constexpr ColorSpace() > + : ColorSpace(Primaries::Undefined, > YcbcrEncoding::Undefined, TransferFunction::Undefined, Range::Undefined) > + { > + } > + > + constexpr ColorSpace(Primaries p, YcbcrEncoding e, > TransferFunction t, Range r) > + : primaries(p), ycbcrEncoding(e), transferFunction(t), > range(r) > + { > + } > + > + static const ColorSpace Undefined; > + static const ColorSpace Raw; > + static const ColorSpace Jpeg; > + static const ColorSpace Smpte170m; > + static const ColorSpace Rec709; > + static const ColorSpace Rec2020; > + > + Primaries primaries; > + YcbcrEncoding ycbcrEncoding; > + TransferFunction transferFunction; > + Range range; > + > + bool isFullyDefined() const; > Other classes seem to use an isValid() member function. Should we do the same here? Granted, this is not exactly the same, a false return value from isFullyDefined() might be allowed for a valid colourspace? > + > + const std::string toString() const; > +}; > + > +constexpr ColorSpace ColorSpace::Undefined = { Primaries::Undefined, > YcbcrEncoding::Undefined, TransferFunction::Undefined, Range::Undefined }; > +constexpr ColorSpace ColorSpace::Raw = { Primaries::Raw, > YcbcrEncoding::Rec601, TransferFunction::Linear, Range::Full }; > +constexpr ColorSpace ColorSpace::Jpeg = { Primaries::Rec709, > YcbcrEncoding::Rec601, TransferFunction::Srgb, Range::Full }; > +constexpr ColorSpace ColorSpace::Smpte170m = { Primaries::Smpte170m, > YcbcrEncoding::Rec601, TransferFunction::Rec709, Range::Limited }; > +constexpr ColorSpace ColorSpace::Rec709 = { Primaries::Rec709, > YcbcrEncoding::Rec709, TransferFunction::Rec709, Range::Limited }; > +constexpr ColorSpace ColorSpace::Rec2020 = { Primaries::Rec2020, > YcbcrEncoding::Rec2020, TransferFunction::Rec709, Range::Limited }; > + > +bool operator==(const ColorSpace &lhs, const ColorSpace &rhs); > +static inline bool operator!=(const ColorSpace &lhs, const ColorSpace > &rhs) > +{ > + return !(lhs == rhs); > +} > + > +} /* namespace libcamera */ > + > +#endif /* __LIBCAMERA_COLOR_SPACE_H__ */ > diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build > index 7155ff20..131e1740 100644 > --- a/include/libcamera/meson.build > +++ b/include/libcamera/meson.build > @@ -5,6 +5,7 @@ libcamera_include_dir = 'libcamera' / 'libcamera' > libcamera_public_headers = files([ > 'camera.h', > 'camera_manager.h', > + 'color_space.h', > 'compiler.h', > 'controls.h', > 'file_descriptor.h', > diff --git a/src/libcamera/color_space.cpp b/src/libcamera/color_space.cpp > new file mode 100644 > index 00000000..aec4107f > --- /dev/null > +++ b/src/libcamera/color_space.cpp > @@ -0,0 +1,256 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2021, Raspberry Pi (Trading) Limited > + * > + * color_space.cpp - color spaces. > + */ > + > +#include <libcamera/color_space.h> > + > +#include <algorithm> > +#include <sstream> > +#include <vector> > + > +/** > + * \file color_space.h > + * \brief Class and enums to represent color spaces > + */ > + > +namespace libcamera { > + > +/** > + * \class ColorSpace > + * \brief Class to describe a color space > + * > + * The ColorSpace class defines the color primaries, the Y'CbCr encoding, > + * the transfer function associated with the color space, and the range > + * (sometimes also referred to as the quantisation) of the color space. > + * > + * Certain combinations of these fields form well-known standard color > + * spaces such as "JPEG" or "REC709". Applications must not request color > + * spaces with undefined fields, but the "Undefined" value may be > + * returned if the camera drivers decide to use a color space that is > + * not recognised by the ColorSpace class. > + * > + * For more information on the specific color spaces described here, > please > + * see: > + * > + * <a href=" > https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-srgb">sRGB</a> > and <a href=" > https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-jpeg > ">JPEG</a> > +>* <a href=" > https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-smpte-170m">SMPTE > 170M</a> > + * <a href=" > https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-rec709 > ">Rec.709</a> > + * <a href=" > https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-bt2020 > ">Rec.2020</a> > + */ > + > +/** > + * \enum ColorSpace::Primaries > + * \brief The color primaries for this color space > + * > + * \var ColorSpace::Primaries::Undefined > + * \brief The color primaries are undefined > + * \var ColorSpace::Primaries::Raw > + * \brief These are raw colors directly from a sensor > + * \var ColorSpace::Primaries::Smpte170m > + * \brief SMPTE 170M color primaries > + * \var ColorSpace::Primaries::Rec709 > + * \brief Rec.709 color primaries > + * \var ColorSpace::Primaries::Rec2020 > + * \brief Rec.2020 color primaries > + */ > + > +/** > + * \enum ColorSpace::YcbcrEncoding > + * \brief The Y'CbCr encoding > + * > + * \var ColorSpace::YcbcrEncoding::Undefined > + * \brief The Y'CbCr encoding is undefined > + * \var ColorSpace::YcbcrEncoding::Rec601 > + * \brief Rec.601 Y'CbCr encoding > + * \var ColorSpace::YcbcrEncoding::Rec709 > + * \brief Rec.709 Y'CbCr encoding > + * \var ColorSpace::YcbcrEncoding::Rec2020 > + * \brief Rec.2020 Y'CbCr encoding > + */ > + > +/** > + * \enum ColorSpace::TransferFunction > + * \brief The transfer function used for this color space > + * > + * \var ColorSpace::TransferFunction::Undefined > + * \brief The transfer function is not specified > + * \var ColorSpace::TransferFunction::Linear > + * \brief This color space uses a linear (identity) transfer function > + * \var ColorSpace::TransferFunction::Srgb > + * \brief sRGB transfer function > + * \var ColorSpace::TransferFunction::Rec709 > + * \brief Rec709 transfer function > + */ > + > +/** > + * \enum ColorSpace::Range > + * \brief The range (sometimes "quantisation") for this color space > + * > + * \var ColorSpace::Range::Undefined > + * \brief The range is not specified > + * \var ColorSpace::Range::Full > + * \brief This color space uses full range pixel values > + * \var ColorSpace::Range::Limited > + * \brief This color space uses limited range pixel values, being > + * 16 to 235 for Y' and 16 to 240 for Cb and Cr > Perhaps add the range for 10-bit as well? > + */ > + > +/** > + * \fn ColorSpace::ColorSpace(Encoding e, TransferFunction t, Range r) > + * \brief Construct a ColorSpace from explicit values > + * \param[in] e The Y'CbCr encoding > + * \param[in] t The transfer function for the color space > + * \param[in] r The range of the pixel values in this color space > + */ > + > +/** > + * \fn ColorSpace::ColorSpace() > + * \brief Construct a color space with undefined encoding, transfer > function > + * and range > + */ > + > +/** > + * \brief Check if all the fields of the color space are defined > + * \return Return true if all the fields of the color space are defined, > + * otherwise false > + */ > +bool ColorSpace::isFullyDefined() const > +{ > + return primaries != Primaries::Undefined && > + ycbcrEncoding != YcbcrEncoding::Undefined && > + transferFunction != TransferFunction::Undefined && > + range != Range::Undefined; > +} > + > +/** > + * \brief Assemble and return a readable string representation of the > + * ColorSpace > + * \return A string describing the ColorSpace > + */ > +const std::string ColorSpace::toString() const > +{ > + /* Print out a brief name only for standard color sapces. */ > + > + static const std::vector<std::pair<ColorSpace, const char *>> > colorSpaceNames = { > + { ColorSpace::Undefined, "Undefined" }, > + { ColorSpace::Raw, "Raw" }, > + { ColorSpace::Jpeg, "Jpeg" }, > + { ColorSpace::Smpte170m, "Smpte170m" }, > + { ColorSpace::Rec709, "Rec709" }, > + { ColorSpace::Rec2020, "Rec2020" }, > + }; > + auto it = std::find_if(colorSpaceNames.begin(), > colorSpaceNames.end(), > + [this](const auto &item) { > + return *this == item.first; > + }); > Perhaps this might be better done with a std::map or even embedding the string into a member variable? Not too fussed either way. Reviewed-by: Naushir Patuck <naush@raspberrypi.com> > + if (it != colorSpaceNames.end()) > + return std::string(it->second); > + > + static const char *primariesNames[] = { > + "Undefined", > + "Raw", > + "Smpte170m", > + "Rec709", > + "Rec2020", > + }; > + static const char *encodingNames[] = { > + "Undefined", > + "Rec601", > + "Rec709", > + "Rec2020", > + }; > + static const char *transferFunctionNames[] = { > + "Undefined", > + "Linear", > + "Srgb", > + "Rec709", > + }; > + static const char *rangeNames[] = { > + "Undefined", > + "Full", > + "Limited", > + }; > + > + std::stringstream ss; > + ss << std::string(primariesNames[static_cast<int>(primaries)]) << > "/" > + << std::string(encodingNames[static_cast<int>(ycbcrEncoding)]) > << "/" > + << > std::string(transferFunctionNames[static_cast<int>(transferFunction)]) << > "/" > + << std::string(rangeNames[static_cast<int>(range)]); > + > + return ss.str(); > +} > + > +/** > + * \var ColorSpace::primaries > + * \brief The color primaries > + */ > + > +/** > + * \var ColorSpace::ycbcrEncoding > + * \brief The Y'CbCr encoding > + */ > + > +/** > + * \var ColorSpace::transferFunction > + * \brief The transfer function for this color space > + */ > + > +/** > + * \var ColorSpace::range > + * \brief The pixel range used by this color space > + */ > + > +/** > + * \var ColorSpace::Undefined > + * \brief A constant representing a fully undefined color space > + */ > + > +/** > + * \var ColorSpace::Raw > + * \brief A constant representing a raw color space (from a sensor) > + */ > + > +/** > + * \var ColorSpace::Jpeg > + * \brief A constant representing the JPEG color space used for > + * encoding JPEG images (and regarded as being the same as the sRGB > + * color space) > + */ > + > +/** > + * \var ColorSpace::Smpte170m > + * \brief A constant representing the SMPTE170M color space > + */ > + > +/** > + * \var ColorSpace::Rec709 > + * \brief A constant representing the Rec.709 color space > + */ > + > +/** > + * \var ColorSpace::Rec2020 > + * \brief A constant representing the Rec.2020 color space > + */ > + > +/** > + * \brief Compare color spaces for equality > + * \return True if the two color spaces are identical, false otherwise > + */ > +bool operator==(const ColorSpace &lhs, const ColorSpace &rhs) > +{ > + return lhs.primaries == rhs.primaries && > + lhs.ycbcrEncoding == rhs.ycbcrEncoding && > + lhs.transferFunction == rhs.transferFunction && > + lhs.range == rhs.range; > +} > + > +/** > + * \fn bool operator!=(const ColorSpace &lhs, const ColorSpace &rhs) > + * \brief Compare color spaces for inequality > + * \return True if the two color spaces are not identical, false otherwise > + */ > + > +} /* namespace libcamera */ > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build > index 243dd3c1..8dc5d39d 100644 > --- a/src/libcamera/meson.build > +++ b/src/libcamera/meson.build > @@ -8,6 +8,7 @@ libcamera_sources = files([ > 'camera_manager.cpp', > 'camera_sensor.cpp', > 'camera_sensor_properties.cpp', > + 'color_space.cpp', > 'controls.cpp', > 'control_serializer.cpp', > 'control_validator.cpp', > -- > 2.20.1 > >
Hi Naush Thanks for all the reviews, obviously I'll make up a v4 shortly! On Mon, 25 Oct 2021 at 08:36, Naushir Patuck <naush@raspberrypi.com> wrote: > > Hi David, > > Thank you for your work. > > On Wed, 20 Oct 2021 at 12:08, David Plowman <david.plowman@raspberrypi.com> wrote: >> >> This class represents a color space by defining its color primaries, >> YCbCr encoding, the transfer (gamma) function it uses, and whether the >> output is full or limited range. >> >> Signed-off-by: David Plowman <david.plowman@raspberrypi.com> >> --- >> include/libcamera/color_space.h | 88 +++++++++++ >> include/libcamera/meson.build | 1 + >> src/libcamera/color_space.cpp | 256 ++++++++++++++++++++++++++++++++ >> src/libcamera/meson.build | 1 + >> 4 files changed, 346 insertions(+) >> create mode 100644 include/libcamera/color_space.h >> create mode 100644 src/libcamera/color_space.cpp >> >> diff --git a/include/libcamera/color_space.h b/include/libcamera/color_space.h >> new file mode 100644 >> index 00000000..2af9da31 >> --- /dev/null >> +++ b/include/libcamera/color_space.h >> @@ -0,0 +1,88 @@ >> +/* SPDX-License-Identifier: LGPL-2.1-or-later */ >> +/* >> + * Copyright (C) 2021, Raspberry Pi (Trading) Limited >> + * >> + * color_space.h - color space definitions >> + */ >> + >> +#ifndef __LIBCAMERA_COLOR_SPACE_H__ >> +#define __LIBCAMERA_COLOR_SPACE_H__ >> + >> +#include <string> >> + >> +namespace libcamera { >> + >> +class ColorSpace >> +{ >> +public: >> + enum class Primaries : int { >> + Undefined, >> + Raw, >> + Smpte170m, >> + Rec709, >> + Rec2020, >> + }; >> + >> + enum class YcbcrEncoding : int { >> + Undefined, >> + Rec601, >> + Rec709, >> + Rec2020, >> + }; >> + >> + enum class TransferFunction : int { >> + Undefined, >> + Linear, >> + Srgb, >> + Rec709, >> + }; >> + >> + enum class Range : int { >> + Undefined, >> + Full, >> + Limited, >> + }; >> + >> + constexpr ColorSpace() >> + : ColorSpace(Primaries::Undefined, YcbcrEncoding::Undefined, TransferFunction::Undefined, Range::Undefined) >> + { >> + } >> + >> + constexpr ColorSpace(Primaries p, YcbcrEncoding e, TransferFunction t, Range r) >> + : primaries(p), ycbcrEncoding(e), transferFunction(t), range(r) >> + { >> + } >> + >> + static const ColorSpace Undefined; >> + static const ColorSpace Raw; >> + static const ColorSpace Jpeg; >> + static const ColorSpace Smpte170m; >> + static const ColorSpace Rec709; >> + static const ColorSpace Rec2020; >> + >> + Primaries primaries; >> + YcbcrEncoding ycbcrEncoding; >> + TransferFunction transferFunction; >> + Range range; >> + >> + bool isFullyDefined() const; > > > Other classes seem to use an isValid() member function. Should we do the same here? > Granted, this is not exactly the same, a false return value from isFullyDefined() might be > allowed for a valid colourspace? I actually prefer isFullyDefined ("are any fields undefined or not?") because "valid" seems like a slightly slippery concept here. You could have a driver choose a valid colour space but which the class doesn't recognise. Is that "valid"? I'm not sure... > > >> >> + >> + const std::string toString() const; >> +}; >> + >> +constexpr ColorSpace ColorSpace::Undefined = { Primaries::Undefined, YcbcrEncoding::Undefined, TransferFunction::Undefined, Range::Undefined }; >> +constexpr ColorSpace ColorSpace::Raw = { Primaries::Raw, YcbcrEncoding::Rec601, TransferFunction::Linear, Range::Full }; >> +constexpr ColorSpace ColorSpace::Jpeg = { Primaries::Rec709, YcbcrEncoding::Rec601, TransferFunction::Srgb, Range::Full }; >> +constexpr ColorSpace ColorSpace::Smpte170m = { Primaries::Smpte170m, YcbcrEncoding::Rec601, TransferFunction::Rec709, Range::Limited }; >> +constexpr ColorSpace ColorSpace::Rec709 = { Primaries::Rec709, YcbcrEncoding::Rec709, TransferFunction::Rec709, Range::Limited }; >> +constexpr ColorSpace ColorSpace::Rec2020 = { Primaries::Rec2020, YcbcrEncoding::Rec2020, TransferFunction::Rec709, Range::Limited }; >> + >> +bool operator==(const ColorSpace &lhs, const ColorSpace &rhs); >> +static inline bool operator!=(const ColorSpace &lhs, const ColorSpace &rhs) >> +{ >> + return !(lhs == rhs); >> +} >> + >> +} /* namespace libcamera */ >> + >> +#endif /* __LIBCAMERA_COLOR_SPACE_H__ */ >> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build >> index 7155ff20..131e1740 100644 >> --- a/include/libcamera/meson.build >> +++ b/include/libcamera/meson.build >> @@ -5,6 +5,7 @@ libcamera_include_dir = 'libcamera' / 'libcamera' >> libcamera_public_headers = files([ >> 'camera.h', >> 'camera_manager.h', >> + 'color_space.h', >> 'compiler.h', >> 'controls.h', >> 'file_descriptor.h', >> diff --git a/src/libcamera/color_space.cpp b/src/libcamera/color_space.cpp >> new file mode 100644 >> index 00000000..aec4107f >> --- /dev/null >> +++ b/src/libcamera/color_space.cpp >> @@ -0,0 +1,256 @@ >> +/* SPDX-License-Identifier: LGPL-2.1-or-later */ >> +/* >> + * Copyright (C) 2021, Raspberry Pi (Trading) Limited >> + * >> + * color_space.cpp - color spaces. >> + */ >> + >> +#include <libcamera/color_space.h> >> + >> +#include <algorithm> >> +#include <sstream> >> +#include <vector> >> + >> +/** >> + * \file color_space.h >> + * \brief Class and enums to represent color spaces >> + */ >> + >> +namespace libcamera { >> + >> +/** >> + * \class ColorSpace >> + * \brief Class to describe a color space >> + * >> + * The ColorSpace class defines the color primaries, the Y'CbCr encoding, >> + * the transfer function associated with the color space, and the range >> + * (sometimes also referred to as the quantisation) of the color space. >> + * >> + * Certain combinations of these fields form well-known standard color >> + * spaces such as "JPEG" or "REC709". Applications must not request color >> + * spaces with undefined fields, but the "Undefined" value may be >> + * returned if the camera drivers decide to use a color space that is >> + * not recognised by the ColorSpace class. >> + * >> + * For more information on the specific color spaces described here, please >> + * see: >> + * >> + * <a href="https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-srgb">sRGB</a> and <a href="https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-jpeg">JPEG</a> >> +>* <a href="https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-smpte-170m">SMPTE 170M</a> >> + * <a href="https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-rec709">Rec.709</a> >> + * <a href="https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-bt2020">Rec.2020</a> >> + */ >> + >> +/** >> + * \enum ColorSpace::Primaries >> + * \brief The color primaries for this color space >> + * >> + * \var ColorSpace::Primaries::Undefined >> + * \brief The color primaries are undefined >> + * \var ColorSpace::Primaries::Raw >> + * \brief These are raw colors directly from a sensor >> + * \var ColorSpace::Primaries::Smpte170m >> + * \brief SMPTE 170M color primaries >> + * \var ColorSpace::Primaries::Rec709 >> + * \brief Rec.709 color primaries >> + * \var ColorSpace::Primaries::Rec2020 >> + * \brief Rec.2020 color primaries >> + */ >> + >> +/** >> + * \enum ColorSpace::YcbcrEncoding >> + * \brief The Y'CbCr encoding >> + * >> + * \var ColorSpace::YcbcrEncoding::Undefined >> + * \brief The Y'CbCr encoding is undefined >> + * \var ColorSpace::YcbcrEncoding::Rec601 >> + * \brief Rec.601 Y'CbCr encoding >> + * \var ColorSpace::YcbcrEncoding::Rec709 >> + * \brief Rec.709 Y'CbCr encoding >> + * \var ColorSpace::YcbcrEncoding::Rec2020 >> + * \brief Rec.2020 Y'CbCr encoding >> + */ >> + >> +/** >> + * \enum ColorSpace::TransferFunction >> + * \brief The transfer function used for this color space >> + * >> + * \var ColorSpace::TransferFunction::Undefined >> + * \brief The transfer function is not specified >> + * \var ColorSpace::TransferFunction::Linear >> + * \brief This color space uses a linear (identity) transfer function >> + * \var ColorSpace::TransferFunction::Srgb >> + * \brief sRGB transfer function >> + * \var ColorSpace::TransferFunction::Rec709 >> + * \brief Rec709 transfer function >> + */ >> + >> +/** >> + * \enum ColorSpace::Range >> + * \brief The range (sometimes "quantisation") for this color space >> + * >> + * \var ColorSpace::Range::Undefined >> + * \brief The range is not specified >> + * \var ColorSpace::Range::Full >> + * \brief This color space uses full range pixel values >> + * \var ColorSpace::Range::Limited >> + * \brief This color space uses limited range pixel values, being >> + * 16 to 235 for Y' and 16 to 240 for Cb and Cr > > > Perhaps add the range for 10-bit as well? Good idea. > >> >> + */ >> + >> +/** >> + * \fn ColorSpace::ColorSpace(Encoding e, TransferFunction t, Range r) >> + * \brief Construct a ColorSpace from explicit values >> + * \param[in] e The Y'CbCr encoding >> + * \param[in] t The transfer function for the color space >> + * \param[in] r The range of the pixel values in this color space >> + */ >> + >> +/** >> + * \fn ColorSpace::ColorSpace() >> + * \brief Construct a color space with undefined encoding, transfer function >> + * and range >> + */ >> + >> +/** >> + * \brief Check if all the fields of the color space are defined >> + * \return Return true if all the fields of the color space are defined, >> + * otherwise false >> + */ >> +bool ColorSpace::isFullyDefined() const >> +{ >> + return primaries != Primaries::Undefined && >> + ycbcrEncoding != YcbcrEncoding::Undefined && >> + transferFunction != TransferFunction::Undefined && >> + range != Range::Undefined; >> +} >> + >> +/** >> + * \brief Assemble and return a readable string representation of the >> + * ColorSpace >> + * \return A string describing the ColorSpace >> + */ >> +const std::string ColorSpace::toString() const >> +{ >> + /* Print out a brief name only for standard color sapces. */ >> + >> + static const std::vector<std::pair<ColorSpace, const char *>> colorSpaceNames = { >> + { ColorSpace::Undefined, "Undefined" }, >> + { ColorSpace::Raw, "Raw" }, >> + { ColorSpace::Jpeg, "Jpeg" }, >> + { ColorSpace::Smpte170m, "Smpte170m" }, >> + { ColorSpace::Rec709, "Rec709" }, >> + { ColorSpace::Rec2020, "Rec2020" }, >> + }; >> + auto it = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(), >> + [this](const auto &item) { >> + return *this == item.first; >> + }); > > > Perhaps this might be better done with a std::map or even embedding the string > into a member variable? Not too fussed either way. I've not not noticed other classes do that for debug strings, but It's not a bad idea. What do other folks think? I actually ran some little experiments with vectors vs. maps, just to get some hints as to when it's worth the trouble of defining an ordering (which you need for a map), or a hash (which you need for an unordered_map). Running on a Pi I found: * A std::map becomes faster than searching a vector of pairs after about 20 or 30 entries. * A std::unordered_map becomes faster than searching a vector at just over 150 entries. * A std::unordered_map requires "a few thousand" entries to become faster than a std::map. Thanks! David > > Reviewed-by: Naushir Patuck <naush@raspberrypi.com> > >> >> + if (it != colorSpaceNames.end()) >> + return std::string(it->second); >> + >> + static const char *primariesNames[] = { >> + "Undefined", >> + "Raw", >> + "Smpte170m", >> + "Rec709", >> + "Rec2020", >> + }; >> + static const char *encodingNames[] = { >> + "Undefined", >> + "Rec601", >> + "Rec709", >> + "Rec2020", >> + }; >> + static const char *transferFunctionNames[] = { >> + "Undefined", >> + "Linear", >> + "Srgb", >> + "Rec709", >> + }; >> + static const char *rangeNames[] = { >> + "Undefined", >> + "Full", >> + "Limited", >> + }; >> + >> + std::stringstream ss; >> + ss << std::string(primariesNames[static_cast<int>(primaries)]) << "/" >> + << std::string(encodingNames[static_cast<int>(ycbcrEncoding)]) << "/" >> + << std::string(transferFunctionNames[static_cast<int>(transferFunction)]) << "/" >> + << std::string(rangeNames[static_cast<int>(range)]); >> + >> + return ss.str(); >> +} >> + >> +/** >> + * \var ColorSpace::primaries >> + * \brief The color primaries >> + */ >> + >> +/** >> + * \var ColorSpace::ycbcrEncoding >> + * \brief The Y'CbCr encoding >> + */ >> + >> +/** >> + * \var ColorSpace::transferFunction >> + * \brief The transfer function for this color space >> + */ >> + >> +/** >> + * \var ColorSpace::range >> + * \brief The pixel range used by this color space >> + */ >> + >> +/** >> + * \var ColorSpace::Undefined >> + * \brief A constant representing a fully undefined color space >> + */ >> + >> +/** >> + * \var ColorSpace::Raw >> + * \brief A constant representing a raw color space (from a sensor) >> + */ >> + >> +/** >> + * \var ColorSpace::Jpeg >> + * \brief A constant representing the JPEG color space used for >> + * encoding JPEG images (and regarded as being the same as the sRGB >> + * color space) >> + */ >> + >> +/** >> + * \var ColorSpace::Smpte170m >> + * \brief A constant representing the SMPTE170M color space >> + */ >> + >> +/** >> + * \var ColorSpace::Rec709 >> + * \brief A constant representing the Rec.709 color space >> + */ >> + >> +/** >> + * \var ColorSpace::Rec2020 >> + * \brief A constant representing the Rec.2020 color space >> + */ >> + >> +/** >> + * \brief Compare color spaces for equality >> + * \return True if the two color spaces are identical, false otherwise >> + */ >> +bool operator==(const ColorSpace &lhs, const ColorSpace &rhs) >> +{ >> + return lhs.primaries == rhs.primaries && >> + lhs.ycbcrEncoding == rhs.ycbcrEncoding && >> + lhs.transferFunction == rhs.transferFunction && >> + lhs.range == rhs.range; >> +} >> + >> +/** >> + * \fn bool operator!=(const ColorSpace &lhs, const ColorSpace &rhs) >> + * \brief Compare color spaces for inequality >> + * \return True if the two color spaces are not identical, false otherwise >> + */ >> + >> +} /* namespace libcamera */ >> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build >> index 243dd3c1..8dc5d39d 100644 >> --- a/src/libcamera/meson.build >> +++ b/src/libcamera/meson.build >> @@ -8,6 +8,7 @@ libcamera_sources = files([ >> 'camera_manager.cpp', >> 'camera_sensor.cpp', >> 'camera_sensor_properties.cpp', >> + 'color_space.cpp', >> 'controls.cpp', >> 'control_serializer.cpp', >> 'control_validator.cpp', >> -- >> 2.20.1 >>
diff --git a/include/libcamera/color_space.h b/include/libcamera/color_space.h new file mode 100644 index 00000000..2af9da31 --- /dev/null +++ b/include/libcamera/color_space.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Raspberry Pi (Trading) Limited + * + * color_space.h - color space definitions + */ + +#ifndef __LIBCAMERA_COLOR_SPACE_H__ +#define __LIBCAMERA_COLOR_SPACE_H__ + +#include <string> + +namespace libcamera { + +class ColorSpace +{ +public: + enum class Primaries : int { + Undefined, + Raw, + Smpte170m, + Rec709, + Rec2020, + }; + + enum class YcbcrEncoding : int { + Undefined, + Rec601, + Rec709, + Rec2020, + }; + + enum class TransferFunction : int { + Undefined, + Linear, + Srgb, + Rec709, + }; + + enum class Range : int { + Undefined, + Full, + Limited, + }; + + constexpr ColorSpace() + : ColorSpace(Primaries::Undefined, YcbcrEncoding::Undefined, TransferFunction::Undefined, Range::Undefined) + { + } + + constexpr ColorSpace(Primaries p, YcbcrEncoding e, TransferFunction t, Range r) + : primaries(p), ycbcrEncoding(e), transferFunction(t), range(r) + { + } + + static const ColorSpace Undefined; + static const ColorSpace Raw; + static const ColorSpace Jpeg; + static const ColorSpace Smpte170m; + static const ColorSpace Rec709; + static const ColorSpace Rec2020; + + Primaries primaries; + YcbcrEncoding ycbcrEncoding; + TransferFunction transferFunction; + Range range; + + bool isFullyDefined() const; + + const std::string toString() const; +}; + +constexpr ColorSpace ColorSpace::Undefined = { Primaries::Undefined, YcbcrEncoding::Undefined, TransferFunction::Undefined, Range::Undefined }; +constexpr ColorSpace ColorSpace::Raw = { Primaries::Raw, YcbcrEncoding::Rec601, TransferFunction::Linear, Range::Full }; +constexpr ColorSpace ColorSpace::Jpeg = { Primaries::Rec709, YcbcrEncoding::Rec601, TransferFunction::Srgb, Range::Full }; +constexpr ColorSpace ColorSpace::Smpte170m = { Primaries::Smpte170m, YcbcrEncoding::Rec601, TransferFunction::Rec709, Range::Limited }; +constexpr ColorSpace ColorSpace::Rec709 = { Primaries::Rec709, YcbcrEncoding::Rec709, TransferFunction::Rec709, Range::Limited }; +constexpr ColorSpace ColorSpace::Rec2020 = { Primaries::Rec2020, YcbcrEncoding::Rec2020, TransferFunction::Rec709, Range::Limited }; + +bool operator==(const ColorSpace &lhs, const ColorSpace &rhs); +static inline bool operator!=(const ColorSpace &lhs, const ColorSpace &rhs) +{ + return !(lhs == rhs); +} + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_COLOR_SPACE_H__ */ diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 7155ff20..131e1740 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -5,6 +5,7 @@ libcamera_include_dir = 'libcamera' / 'libcamera' libcamera_public_headers = files([ 'camera.h', 'camera_manager.h', + 'color_space.h', 'compiler.h', 'controls.h', 'file_descriptor.h', diff --git a/src/libcamera/color_space.cpp b/src/libcamera/color_space.cpp new file mode 100644 index 00000000..aec4107f --- /dev/null +++ b/src/libcamera/color_space.cpp @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Raspberry Pi (Trading) Limited + * + * color_space.cpp - color spaces. + */ + +#include <libcamera/color_space.h> + +#include <algorithm> +#include <sstream> +#include <vector> + +/** + * \file color_space.h + * \brief Class and enums to represent color spaces + */ + +namespace libcamera { + +/** + * \class ColorSpace + * \brief Class to describe a color space + * + * The ColorSpace class defines the color primaries, the Y'CbCr encoding, + * the transfer function associated with the color space, and the range + * (sometimes also referred to as the quantisation) of the color space. + * + * Certain combinations of these fields form well-known standard color + * spaces such as "JPEG" or "REC709". Applications must not request color + * spaces with undefined fields, but the "Undefined" value may be + * returned if the camera drivers decide to use a color space that is + * not recognised by the ColorSpace class. + * + * For more information on the specific color spaces described here, please + * see: + * + * <a href="https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-srgb">sRGB</a> and <a href="https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-jpeg">JPEG</a> +>* <a href="https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-smpte-170m">SMPTE 170M</a> + * <a href="https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-rec709">Rec.709</a> + * <a href="https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-007.html#col-bt2020">Rec.2020</a> + */ + +/** + * \enum ColorSpace::Primaries + * \brief The color primaries for this color space + * + * \var ColorSpace::Primaries::Undefined + * \brief The color primaries are undefined + * \var ColorSpace::Primaries::Raw + * \brief These are raw colors directly from a sensor + * \var ColorSpace::Primaries::Smpte170m + * \brief SMPTE 170M color primaries + * \var ColorSpace::Primaries::Rec709 + * \brief Rec.709 color primaries + * \var ColorSpace::Primaries::Rec2020 + * \brief Rec.2020 color primaries + */ + +/** + * \enum ColorSpace::YcbcrEncoding + * \brief The Y'CbCr encoding + * + * \var ColorSpace::YcbcrEncoding::Undefined + * \brief The Y'CbCr encoding is undefined + * \var ColorSpace::YcbcrEncoding::Rec601 + * \brief Rec.601 Y'CbCr encoding + * \var ColorSpace::YcbcrEncoding::Rec709 + * \brief Rec.709 Y'CbCr encoding + * \var ColorSpace::YcbcrEncoding::Rec2020 + * \brief Rec.2020 Y'CbCr encoding + */ + +/** + * \enum ColorSpace::TransferFunction + * \brief The transfer function used for this color space + * + * \var ColorSpace::TransferFunction::Undefined + * \brief The transfer function is not specified + * \var ColorSpace::TransferFunction::Linear + * \brief This color space uses a linear (identity) transfer function + * \var ColorSpace::TransferFunction::Srgb + * \brief sRGB transfer function + * \var ColorSpace::TransferFunction::Rec709 + * \brief Rec709 transfer function + */ + +/** + * \enum ColorSpace::Range + * \brief The range (sometimes "quantisation") for this color space + * + * \var ColorSpace::Range::Undefined + * \brief The range is not specified + * \var ColorSpace::Range::Full + * \brief This color space uses full range pixel values + * \var ColorSpace::Range::Limited + * \brief This color space uses limited range pixel values, being + * 16 to 235 for Y' and 16 to 240 for Cb and Cr + */ + +/** + * \fn ColorSpace::ColorSpace(Encoding e, TransferFunction t, Range r) + * \brief Construct a ColorSpace from explicit values + * \param[in] e The Y'CbCr encoding + * \param[in] t The transfer function for the color space + * \param[in] r The range of the pixel values in this color space + */ + +/** + * \fn ColorSpace::ColorSpace() + * \brief Construct a color space with undefined encoding, transfer function + * and range + */ + +/** + * \brief Check if all the fields of the color space are defined + * \return Return true if all the fields of the color space are defined, + * otherwise false + */ +bool ColorSpace::isFullyDefined() const +{ + return primaries != Primaries::Undefined && + ycbcrEncoding != YcbcrEncoding::Undefined && + transferFunction != TransferFunction::Undefined && + range != Range::Undefined; +} + +/** + * \brief Assemble and return a readable string representation of the + * ColorSpace + * \return A string describing the ColorSpace + */ +const std::string ColorSpace::toString() const +{ + /* Print out a brief name only for standard color sapces. */ + + static const std::vector<std::pair<ColorSpace, const char *>> colorSpaceNames = { + { ColorSpace::Undefined, "Undefined" }, + { ColorSpace::Raw, "Raw" }, + { ColorSpace::Jpeg, "Jpeg" }, + { ColorSpace::Smpte170m, "Smpte170m" }, + { ColorSpace::Rec709, "Rec709" }, + { ColorSpace::Rec2020, "Rec2020" }, + }; + auto it = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(), + [this](const auto &item) { + return *this == item.first; + }); + if (it != colorSpaceNames.end()) + return std::string(it->second); + + static const char *primariesNames[] = { + "Undefined", + "Raw", + "Smpte170m", + "Rec709", + "Rec2020", + }; + static const char *encodingNames[] = { + "Undefined", + "Rec601", + "Rec709", + "Rec2020", + }; + static const char *transferFunctionNames[] = { + "Undefined", + "Linear", + "Srgb", + "Rec709", + }; + static const char *rangeNames[] = { + "Undefined", + "Full", + "Limited", + }; + + std::stringstream ss; + ss << std::string(primariesNames[static_cast<int>(primaries)]) << "/" + << std::string(encodingNames[static_cast<int>(ycbcrEncoding)]) << "/" + << std::string(transferFunctionNames[static_cast<int>(transferFunction)]) << "/" + << std::string(rangeNames[static_cast<int>(range)]); + + return ss.str(); +} + +/** + * \var ColorSpace::primaries + * \brief The color primaries + */ + +/** + * \var ColorSpace::ycbcrEncoding + * \brief The Y'CbCr encoding + */ + +/** + * \var ColorSpace::transferFunction + * \brief The transfer function for this color space + */ + +/** + * \var ColorSpace::range + * \brief The pixel range used by this color space + */ + +/** + * \var ColorSpace::Undefined + * \brief A constant representing a fully undefined color space + */ + +/** + * \var ColorSpace::Raw + * \brief A constant representing a raw color space (from a sensor) + */ + +/** + * \var ColorSpace::Jpeg + * \brief A constant representing the JPEG color space used for + * encoding JPEG images (and regarded as being the same as the sRGB + * color space) + */ + +/** + * \var ColorSpace::Smpte170m + * \brief A constant representing the SMPTE170M color space + */ + +/** + * \var ColorSpace::Rec709 + * \brief A constant representing the Rec.709 color space + */ + +/** + * \var ColorSpace::Rec2020 + * \brief A constant representing the Rec.2020 color space + */ + +/** + * \brief Compare color spaces for equality + * \return True if the two color spaces are identical, false otherwise + */ +bool operator==(const ColorSpace &lhs, const ColorSpace &rhs) +{ + return lhs.primaries == rhs.primaries && + lhs.ycbcrEncoding == rhs.ycbcrEncoding && + lhs.transferFunction == rhs.transferFunction && + lhs.range == rhs.range; +} + +/** + * \fn bool operator!=(const ColorSpace &lhs, const ColorSpace &rhs) + * \brief Compare color spaces for inequality + * \return True if the two color spaces are not identical, false otherwise + */ + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 243dd3c1..8dc5d39d 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -8,6 +8,7 @@ libcamera_sources = files([ 'camera_manager.cpp', 'camera_sensor.cpp', 'camera_sensor_properties.cpp', + 'color_space.cpp', 'controls.cpp', 'control_serializer.cpp', 'control_validator.cpp',
This class represents a color space by defining its color primaries, YCbCr encoding, the transfer (gamma) function it uses, and whether the output is full or limited range. Signed-off-by: David Plowman <david.plowman@raspberrypi.com> --- include/libcamera/color_space.h | 88 +++++++++++ include/libcamera/meson.build | 1 + src/libcamera/color_space.cpp | 256 ++++++++++++++++++++++++++++++++ src/libcamera/meson.build | 1 + 4 files changed, 346 insertions(+) create mode 100644 include/libcamera/color_space.h create mode 100644 src/libcamera/color_space.cpp