Add three additional fields to PixelFormatInfo to report the number of bits per pixel, the colour encoding, and the data packing. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
463 lines
14 KiB
C++
463 lines
14 KiB
C++
/* 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 */
|