blob: b3af0f7fcfcc3b71501a5d7314c19f0675e2705f [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2019, Google Inc.
*
* formats.cpp - libcamera image formats
*/
#include "formats.h"
#include <errno.h>
#include "log.h"
/**
* \file formats.h
* \brief Types and helper methods to handle libcamera image formats
*/
namespace libcamera {
LOG_DEFINE_CATEGORY(Formats)
/**
* \class ImageFormats
* \brief Describe V4L2Device and V4L2SubDevice image formats
*
* This class stores a list of image formats, each associated with a
* corresponding set of image sizes. It is used to describe the formats and
* sizes supported by a V4L2Device or V4L2Subdevice.
*
* Formats are stored as an integer. When used for a V4L2Device, the image
* formats are fourcc pixel formats. When used for a V4L2Subdevice they are
* media bus codes. Both are defined by the V4L2 specification.
*
* Sizes are stored as a list of SizeRange.
*/
/**
* \brief Add a format and corresponding sizes to the description
* \param[in] format Pixel format or media bus code to describe
* \param[in] sizes List of supported size ranges for the format
*
* \return 0 on success or a negative error code otherwise
* \retval -EEXIST The format is already described
*/
int ImageFormats::addFormat(unsigned int format, const std::vector<SizeRange> &sizes)
{
if (data_.find(format) != data_.end())
return -EEXIST;
data_[format] = sizes;
return 0;
}
/**
* \brief Check if the list of devices supported formats is empty
* \return True if the list of supported formats is empty
*/
bool ImageFormats::isEmpty() const
{
return data_.empty();
}
/**
* \brief Retrieve a list of all supported image formats
* \return List of pixel formats or media bus codes
*/
std::vector<unsigned int> ImageFormats::formats() const
{
std::vector<unsigned int> formats;
formats.reserve(data_.size());
/* \todo: Should this be cached instead of computed each time? */
for (auto const &it : data_)
formats.push_back(it.first);
return formats;
}
/**
* \brief Retrieve all sizes for a specific format
* \param[in] format The pixel format or mbus code
*
* Retrieve all size ranges for a specific format. For V4L2Device \a format is a
* pixel format while for a V4L2Subdevice \a format is a media bus code.
*
* \return The list of image sizes supported for \a format, or an empty list if
* the format is not supported
*/
const std::vector<SizeRange> &ImageFormats::sizes(unsigned int format) const
{
static const std::vector<SizeRange> empty;
auto const &it = data_.find(format);
if (it == data_.end())
return empty;
return it->second;
}
/**
* \brief Retrieve the map that associates formats to image sizes
* \return The map that associates formats to image sizes
*/
const std::map<unsigned int, std::vector<SizeRange>> &ImageFormats::data() const
{
return data_;
}
/**
* \class PixelFormatInfo
* \brief Information about pixel formats
*
* The PixelFormatInfo class groups together information describing a pixel
* format. It facilitates handling of pixel formats by providing data commonly
* used in pipeline handlers.
*
* \var PixelFormatInfo::format
* \brief The PixelFormat described by this instance
*
* \var PixelFormatInfo::v4l2Format
* \brief The V4L2 pixel format corresponding to the PixelFormat
*
* \var PixelFormatInfo::bitsPerPixel
* \brief The average number of bits per pixel
*
* The number per pixel averages the total number of bits for all colour
* components over the whole image, excluding any padding bits or padding
* pixels.
*
* For formats that store pixels with bit padding within words, only the
* effective bits are taken into account. For instance, 12-bit Bayer data
* stored in two bytes per pixel report 12, not 16, in this field.
*
* Formats that don't have a fixed number of bits per pixel, such as compressed
* formats, report 0 in this field.
*
* \var PixelFormatInfo::colourEncoding
* \brief The colour encoding type
*
* \var PixelFormatInfo::packed
* \brief Tell if multiple pixels are packed in the same bytes
*
* Packed formats are defined as storing data from multiple pixels in the same
* bytes. For instance, 12-bit Bayer data with two pixels stored in three bytes
* is packed, while the same data stored with 4 bits of padding in two bytes
* per pixel is not packed.
*/
/**
* \enum PixelFormatInfo::ColourEncoding
* \brief The colour encoding type
*
* \var PixelFormatInfo::ColourEncodingRGB
* \brief RGB colour encoding
*
* \var PixelFormatInfo::ColourEncodingYUV
* \brief YUV colour encoding
*
* \var PixelFormatInfo::ColourEncodingRAW
* \brief RAW colour encoding
*/
namespace {
const std::map<PixelFormat, PixelFormatInfo> pixelFormatInfo{
/* RGB formats. */
{ PixelFormat(DRM_FORMAT_BGR888), {
.format = PixelFormat(DRM_FORMAT_BGR888),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_RGB24),
.bitsPerPixel = 24,
.colourEncoding = PixelFormatInfo::ColourEncodingRGB,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_RGB888), {
.format = PixelFormat(DRM_FORMAT_RGB888),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_BGR24),
.bitsPerPixel = 24,
.colourEncoding = PixelFormatInfo::ColourEncodingRGB,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_ABGR8888), {
.format = PixelFormat(DRM_FORMAT_ABGR8888),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_RGBA32),
.bitsPerPixel = 32,
.colourEncoding = PixelFormatInfo::ColourEncodingRGB,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_ARGB8888), {
.format = PixelFormat(DRM_FORMAT_ARGB8888),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_ABGR32),
.bitsPerPixel = 32,
.colourEncoding = PixelFormatInfo::ColourEncodingRGB,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_BGRA8888), {
.format = PixelFormat(DRM_FORMAT_BGRA8888),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_ARGB32),
.bitsPerPixel = 32,
.colourEncoding = PixelFormatInfo::ColourEncodingRGB,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_RGBA8888), {
.format = PixelFormat(DRM_FORMAT_RGBA8888),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_BGRA32),
.bitsPerPixel = 32,
.colourEncoding = PixelFormatInfo::ColourEncodingRGB,
.packed = false,
} },
/* YUV packed formats. */
{ PixelFormat(DRM_FORMAT_YUYV), {
.format = PixelFormat(DRM_FORMAT_YUYV),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_YUYV),
.bitsPerPixel = 16,
.colourEncoding = PixelFormatInfo::ColourEncodingYUV,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_YVYU), {
.format = PixelFormat(DRM_FORMAT_YVYU),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_YVYU),
.bitsPerPixel = 16,
.colourEncoding = PixelFormatInfo::ColourEncodingYUV,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_UYVY), {
.format = PixelFormat(DRM_FORMAT_UYVY),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_UYVY),
.bitsPerPixel = 16,
.colourEncoding = PixelFormatInfo::ColourEncodingYUV,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_VYUY), {
.format = PixelFormat(DRM_FORMAT_VYUY),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_VYUY),
.bitsPerPixel = 16,
.colourEncoding = PixelFormatInfo::ColourEncodingYUV,
.packed = false,
} },
/* YUV planar formats. */
{ PixelFormat(DRM_FORMAT_NV16), {
.format = PixelFormat(DRM_FORMAT_NV16),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_NV16),
.bitsPerPixel = 16,
.colourEncoding = PixelFormatInfo::ColourEncodingYUV,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_NV61), {
.format = PixelFormat(DRM_FORMAT_NV61),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_NV61),
.bitsPerPixel = 16,
.colourEncoding = PixelFormatInfo::ColourEncodingYUV,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_NV12), {
.format = PixelFormat(DRM_FORMAT_NV12),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_NV12),
.bitsPerPixel = 12,
.colourEncoding = PixelFormatInfo::ColourEncodingYUV,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_NV21), {
.format = PixelFormat(DRM_FORMAT_NV21),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_NV21),
.bitsPerPixel = 12,
.colourEncoding = PixelFormatInfo::ColourEncodingYUV,
.packed = false,
} },
/* Greyscale formats. */
{ PixelFormat(DRM_FORMAT_R8), {
.format = PixelFormat(DRM_FORMAT_R8),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_GREY),
.bitsPerPixel = 8,
.colourEncoding = PixelFormatInfo::ColourEncodingYUV,
.packed = false,
} },
/* Bayer formats. */
{ PixelFormat(DRM_FORMAT_SBGGR8), {
.format = PixelFormat(DRM_FORMAT_SBGGR8),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR8),
.bitsPerPixel = 8,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_SGBRG8), {
.format = PixelFormat(DRM_FORMAT_SGBRG8),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG8),
.bitsPerPixel = 8,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_SGRBG8), {
.format = PixelFormat(DRM_FORMAT_SGRBG8),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG8),
.bitsPerPixel = 8,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_SRGGB8), {
.format = PixelFormat(DRM_FORMAT_SRGGB8),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB8),
.bitsPerPixel = 8,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_SBGGR10), {
.format = PixelFormat(DRM_FORMAT_SBGGR10),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10),
.bitsPerPixel = 10,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_SGBRG10), {
.format = PixelFormat(DRM_FORMAT_SGBRG10),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10),
.bitsPerPixel = 10,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_SGRBG10), {
.format = PixelFormat(DRM_FORMAT_SGRBG10),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10),
.bitsPerPixel = 10,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_SRGGB10), {
.format = PixelFormat(DRM_FORMAT_SRGGB10),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10),
.bitsPerPixel = 10,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_SBGGR10, MIPI_FORMAT_MOD_CSI2_PACKED), {
.format = PixelFormat(DRM_FORMAT_SBGGR10, MIPI_FORMAT_MOD_CSI2_PACKED),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR10P),
.bitsPerPixel = 10,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = true,
} },
{ PixelFormat(DRM_FORMAT_SGBRG10, MIPI_FORMAT_MOD_CSI2_PACKED), {
.format = PixelFormat(DRM_FORMAT_SGBRG10, MIPI_FORMAT_MOD_CSI2_PACKED),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG10P),
.bitsPerPixel = 10,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = true,
} },
{ PixelFormat(DRM_FORMAT_SGRBG10, MIPI_FORMAT_MOD_CSI2_PACKED), {
.format = PixelFormat(DRM_FORMAT_SGRBG10, MIPI_FORMAT_MOD_CSI2_PACKED),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG10P),
.bitsPerPixel = 10,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = true,
} },
{ PixelFormat(DRM_FORMAT_SRGGB10, MIPI_FORMAT_MOD_CSI2_PACKED), {
.format = PixelFormat(DRM_FORMAT_SRGGB10, MIPI_FORMAT_MOD_CSI2_PACKED),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB10P),
.bitsPerPixel = 10,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = true,
} },
{ PixelFormat(DRM_FORMAT_SBGGR12), {
.format = PixelFormat(DRM_FORMAT_SBGGR12),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12),
.bitsPerPixel = 12,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_SGBRG12), {
.format = PixelFormat(DRM_FORMAT_SGBRG12),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12),
.bitsPerPixel = 12,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_SGRBG12), {
.format = PixelFormat(DRM_FORMAT_SGRBG12),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12),
.bitsPerPixel = 12,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_SRGGB12), {
.format = PixelFormat(DRM_FORMAT_SRGGB12),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12),
.bitsPerPixel = 12,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = false,
} },
{ PixelFormat(DRM_FORMAT_SBGGR12, MIPI_FORMAT_MOD_CSI2_PACKED), {
.format = PixelFormat(DRM_FORMAT_SBGGR12, MIPI_FORMAT_MOD_CSI2_PACKED),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR12P),
.bitsPerPixel = 12,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = true,
} },
{ PixelFormat(DRM_FORMAT_SGBRG12, MIPI_FORMAT_MOD_CSI2_PACKED), {
.format = PixelFormat(DRM_FORMAT_SGBRG12, MIPI_FORMAT_MOD_CSI2_PACKED),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGBRG12P),
.bitsPerPixel = 12,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = true,
} },
{ PixelFormat(DRM_FORMAT_SGRBG12, MIPI_FORMAT_MOD_CSI2_PACKED), {
.format = PixelFormat(DRM_FORMAT_SGRBG12, MIPI_FORMAT_MOD_CSI2_PACKED),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SGRBG12P),
.bitsPerPixel = 12,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = true,
} },
{ PixelFormat(DRM_FORMAT_SRGGB12, MIPI_FORMAT_MOD_CSI2_PACKED), {
.format = PixelFormat(DRM_FORMAT_SRGGB12, MIPI_FORMAT_MOD_CSI2_PACKED),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_SRGGB12P),
.bitsPerPixel = 12,
.colourEncoding = PixelFormatInfo::ColourEncodingRAW,
.packed = true,
} },
/* Compressed formats. */
{ PixelFormat(DRM_FORMAT_MJPEG), {
.format = PixelFormat(DRM_FORMAT_MJPEG),
.v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_MJPEG),
.bitsPerPixel = 0,
.colourEncoding = PixelFormatInfo::ColourEncodingYUV,
.packed = false,
} },
};
} /* namespace */
/**
* \fn bool PixelFormatInfo::isValid() const
* \brief Check if the pixel format info is valid
* \return True if the pixel format info is valid, false otherwise
*/
/**
* \brief Retrieve information about a pixel format
* \param[in] format The pixel format
* \return The PixelFormatInfo describing the \a format if known, or an invalid
* PixelFormatInfo otherwise
*/
const PixelFormatInfo &PixelFormatInfo::info(const PixelFormat &format)
{
static const PixelFormatInfo invalid{};
const auto iter = pixelFormatInfo.find(format);
if (iter == pixelFormatInfo.end()) {
LOG(Formats, Warning)
<< "Unsupported pixel format "
<< format.toString();
return invalid;
}
return iter->second;
}
} /* namespace libcamera */