blob: 895e5c8e667d24c276143a545ba95a786277f53c [file] [log] [blame]
/* 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 <array>
#include <map>
#include <sstream>
#include <utility>
/**
* \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 transfer function,
* the Y'CbCr encoding 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".
*
* In the strictest sense a "color space" formally only refers to the
* color primaries and white point. Here, however, the ColorSpace class
* adopts the common broader usage that includes the transfer function,
* Y'CbCr encoding method and quantisation.
*
* For more information on the specific color spaces described here, please
* see:
*
* - <a href="https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/colorspaces-details.html#col-srgb">sRGB</a>
* - <a href="https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/colorspaces-details.html#col-jpeg">JPEG</a>
* - <a href="https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/colorspaces-details.html#col-smpte-170m">SMPTE 170M</a>
* - <a href="https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/colorspaces-details.html#col-rec709">Rec.709</a>
* - <a href="https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/colorspaces-details.html#col-bt2020">Rec.2020</a>
*/
/**
* \enum ColorSpace::Primaries
* \brief The color primaries for this color space
*
* \var ColorSpace::Primaries::Raw
* \brief These are raw colors directly from a sensor, the primaries are
* unspecified
*
* \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::TransferFunction
* \brief The transfer function used for this color space
*
* \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 Rec.709 transfer function
*/
/**
* \enum ColorSpace::YcbcrEncoding
* \brief The Y'CbCr encoding
*
* \var ColorSpace::YcbcrEncoding::None
* \brief There is no defined Y'CbCr encoding (used for non-YUV formats)
*
* \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::Range
* \brief The range (sometimes "quantisation") for this color space
*
* \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 (8 bits per sample)
* or 64 to 940 for Y' and 16 to 960 for Cb and Cr (10 bits)
*/
/**
* \fn ColorSpace::ColorSpace(Primaries p, TransferFunction t, Encoding e, Range r)
* \brief Construct a ColorSpace from explicit values
* \param[in] p The color primaries
* \param[in] t The transfer function for the color space
* \param[in] e The Y'CbCr encoding
* \param[in] r The range of the pixel values in this color space
*/
/**
* \brief Assemble and return a readable string representation of the
* ColorSpace
*
* If the color space matches a standard ColorSpace (such as ColorSpace::Jpeg)
* then the short name of the color space ("JPEG") is returned. Otherwise
* the four constituent parts of the ColorSpace are assembled into a longer
* string.
*
* \return A string describing the ColorSpace
*/
std::string ColorSpace::toString() const
{
/* Print out a brief name only for standard color spaces. */
static const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {
{ ColorSpace::Raw, "RAW" },
{ ColorSpace::Jpeg, "JPEG" },
{ ColorSpace::Srgb, "sRGB" },
{ 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);
/* Assemble a name made of the constituent fields. */
static const std::map<Primaries, std::string> primariesNames = {
{ Primaries::Raw, "RAW" },
{ Primaries::Smpte170m, "SMPTE170M" },
{ Primaries::Rec709, "Rec709" },
{ Primaries::Rec2020, "Rec2020" },
};
static const std::map<TransferFunction, std::string> transferNames = {
{ TransferFunction::Linear, "Linear" },
{ TransferFunction::Srgb, "sRGB" },
{ TransferFunction::Rec709, "Rec709" },
};
static const std::map<YcbcrEncoding, std::string> encodingNames = {
{ YcbcrEncoding::None, "None" },
{ YcbcrEncoding::Rec601, "Rec601" },
{ YcbcrEncoding::Rec709, "Rec709" },
{ YcbcrEncoding::Rec2020, "Rec2020" },
};
static const std::map<Range, std::string> rangeNames = {
{ Range::Full, "Full" },
{ Range::Limited, "Limited" },
};
auto itPrimaries = primariesNames.find(primaries);
std::string primariesName =
itPrimaries == primariesNames.end() ? "Invalid" : itPrimaries->second;
auto itTransfer = transferNames.find(transferFunction);
std::string transferName =
itTransfer == transferNames.end() ? "Invalid" : itTransfer->second;
auto itEncoding = encodingNames.find(ycbcrEncoding);
std::string encodingName =
itEncoding == encodingNames.end() ? "Invalid" : itEncoding->second;
auto itRange = rangeNames.find(range);
std::string rangeName =
itRange == rangeNames.end() ? "Invalid" : itRange->second;
std::stringstream ss;
ss << primariesName << "/" << transferName << "/" << encodingName << "/" << rangeName;
return ss.str();
}
/**
* \brief Assemble and return a readable string representation of an
* optional ColorSpace
*
* This is a convenience helper to easily obtain a string representation
* for a ColorSpace in parts of the libcamera API where it is stored in a
* std::optional<>. If the ColorSpace is set, this function returns
* \a colorSpace.toString(), otherwise it returns "Unset".
*
* \return A string describing the optional ColorSpace
*/
std::string ColorSpace::toString(const std::optional<ColorSpace> &colorSpace)
{
if (!colorSpace)
return "Unset";
return colorSpace->toString();
}
/**
* \var ColorSpace::primaries
* \brief The color primaries of this color space
*/
/**
* \var ColorSpace::transferFunction
* \brief The transfer function used by this color space
*/
/**
* \var ColorSpace::ycbcrEncoding
* \brief The Y'CbCr encoding used by this color space
*/
/**
* \var ColorSpace::range
* \brief The pixel range used with by color space
*/
/**
* \brief A constant representing a raw color space (from a sensor)
*/
const ColorSpace ColorSpace::Raw = {
Primaries::Raw,
TransferFunction::Linear,
YcbcrEncoding::None,
Range::Full
};
/**
* \brief A constant representing the JPEG color space used for
* encoding JPEG images
*/
const ColorSpace ColorSpace::Jpeg = {
Primaries::Rec709,
TransferFunction::Srgb,
YcbcrEncoding::Rec601,
Range::Full
};
/**
* \brief A constant representing the sRGB color space
*
* This is identical to the JPEG color space except that the Y'CbCr
* range is limited rather than full.
*/
const ColorSpace ColorSpace::Srgb = {
Primaries::Rec709,
TransferFunction::Srgb,
YcbcrEncoding::Rec601,
Range::Limited
};
/**
* \brief A constant representing the SMPTE170M color space
*/
const ColorSpace ColorSpace::Smpte170m = {
Primaries::Smpte170m,
TransferFunction::Rec709,
YcbcrEncoding::Rec601,
Range::Limited
};
/**
* \brief A constant representing the Rec.709 color space
*/
const ColorSpace ColorSpace::Rec709 = {
Primaries::Rec709,
TransferFunction::Rec709,
YcbcrEncoding::Rec709,
Range::Limited
};
/**
* \brief A constant representing the Rec.2020 color space
*/
const ColorSpace ColorSpace::Rec2020 = {
Primaries::Rec2020,
TransferFunction::Rec709,
YcbcrEncoding::Rec2020,
Range::Limited
};
/**
* \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.transferFunction == rhs.transferFunction &&
lhs.ycbcrEncoding == rhs.ycbcrEncoding &&
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 */