[libcamera-devel] [PATCH v2 1/7] libcamera: Define constants for pixel formats in the public API
Kieran Bingham
kieran.bingham at ideasonboard.com
Mon Jun 15 13:04:34 CEST 2020
Hi Laurent,
On 10/06/2020 00:23, Laurent Pinchart wrote:
> libcamera uses pixel format FourCC and modifier values from DRM. This
> requires inclusion of drm_fourcc.h, creating a dependency on a header
> that is packaged differently between distributions, and causing possible
> issues with third-party applications.
>
> Define constants for the supported pixel formats in the new formats.h
> public API header, in order to remove the dependency on drm_fourcc.h.
> The header is generated by a Python script from a list of supported
> formats. The numerical values for the FourCC and modifier are extracted
> from drm_fourcc.h by the script, ensuring that numerical values are not
> inadvertently modified and preserving the direct interoperability.
>
> The pixel formats constants can't be generated solely from drm_fourcc.h,
> as that header defines FourCC values and modifier values, but doesn't
> list the valid combinations. The supported formats are thus stored in a
> YAML file, which contains the FourCC and optional modifier for each
> supported format. We may later extend the YAML file to include formats
> documentation, and possibly formats metadata to populate the
> pixelFormatInfo map (in formats.cpp) automatically.
>
> Now that two formats.h header are present (one in include/libcamera/ and
> one in include/libcamera/internal/), we need to explicitly qualify the
> Doxygen \file directive with a path.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> ---
> Changes since v1:
>
> - Add a note about the Doxygen \file change to the commit message
> - Generate formats.h from formats.yaml
> - Dropped Kieran's R-b tag due to the switch to auto-generation
> - Mention libcamera/formats.h in the PixelFormat class documentation
> - Add IPU3-packed Bayer formats
> ---
> include/libcamera/formats.h.in | 44 +++++++++++
> include/libcamera/gen-formats.py | 118 +++++++++++++++++++++++++++++
> include/libcamera/meson.build | 22 ++++++
> src/libcamera/formats.cpp | 2 +-
> src/libcamera/formats.yaml | 124 +++++++++++++++++++++++++++++++
> src/libcamera/pixel_format.cpp | 4 +-
> 6 files changed, 312 insertions(+), 2 deletions(-)
> create mode 100644 include/libcamera/formats.h.in
> create mode 100755 include/libcamera/gen-formats.py
> create mode 100644 src/libcamera/formats.yaml
>
> diff --git a/include/libcamera/formats.h.in b/include/libcamera/formats.h.in
> new file mode 100644
> index 000000000000..8e7b95812afa
> --- /dev/null
> +++ b/include/libcamera/formats.h.in
> @@ -0,0 +1,44 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Google Inc.
> + *
> + * formats.h - Formats
> + *
> + * This file is auto-generated. Do not edit.
> + */
> +#ifndef __LIBCAMERA_FORMATS_H__
> +#define __LIBCAMERA_FORMATS_H__
> +
> +#include <stdint.h>
> +
> +#include <libcamera/pixel_format.h>
> +
> +namespace libcamera {
> +
> +namespace formats {
> +
> +namespace {
> +
> +constexpr uint32_t __fourcc(char a, char b, char c, char d)
> +{
> + return (static_cast<uint32_t>(a) << 0) |
> + (static_cast<uint32_t>(b) << 8) |
> + (static_cast<uint32_t>(c) << 16) |
> + (static_cast<uint32_t>(d) << 24);
> +}
> +
> +constexpr uint64_t __mod(unsigned int vendor, unsigned int mod)
> +{
> + return (static_cast<uint64_t>(vendor) << 56) |
> + (static_cast<uint64_t>(mod) << 0);
> +}
> +
> +} /* namespace */
> +
> +${formats}
> +
> +} /* namespace formats */
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_FORMATS_H__ */
> diff --git a/include/libcamera/gen-formats.py b/include/libcamera/gen-formats.py
> new file mode 100755
> index 000000000000..9bbff5f1cf6f
> --- /dev/null
> +++ b/include/libcamera/gen-formats.py
> @@ -0,0 +1,118 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Copyright (C) 2020, Google Inc.
> +#
> +# Author: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> +#
> +# gen-formatss.py - Generate formats definitions from YAML
s/gen-formatss/gen-formats/
> +
> +import argparse
> +import re
> +import string
> +import sys
> +import yaml
> +
> +
> +class DRMFourCC(object):
> + format_regex = re.compile(r"#define (DRM_FORMAT_[A-Z0-9_]+)[ \t]+fourcc_code\(('.', '.', '.', '.')\)")
> + mod_vendor_regex = re.compile(r"#define DRM_FORMAT_MOD_VENDOR_([A-Z0-9_]+)[ \t]+([0-9a-fA-Fx]+)")
> + mod_regex = re.compile(r"#define ([A-Za-z0-9_]+)[ \t]+fourcc_mod_code\(([A-Z0-9_]+), ([0-9a-fA-Fx]+)\)")
> +
> + def __init__(self, filename):
> + self.formats = {}
> + self.vendors = {}
> + self.mods = {}
> +
> + for line in open(filename, 'rb').readlines():
> + line = line.decode('utf-8')
> +
> + match = DRMFourCC.format_regex.match(line)
> + if match:
> + format, fourcc = match.groups()
> + self.formats[format] = fourcc
> + continue
> +
> + match = DRMFourCC.mod_vendor_regex.match(line)
> + if match:
> + vendor, value = match.groups()
> + self.vendors[vendor] = int(value, 0)
> + continue
> +
> + match = DRMFourCC.mod_regex.match(line)
> + if match:
> + mod, vendor, value = match.groups()
> + self.mods[mod] = (vendor, int(value, 0))
> + continue
> +
> + def fourcc(self, name):
> + return self.formats[name]
> +
> + def mod(self, name):
> + vendor, value = self.mods[name]
> + return self.vendors[vendor], value
> +
> +
> +def generate_h(formats, drm_fourcc):
> + template = string.Template('constexpr PixelFormat ${name}{ __fourcc(${fourcc}), __mod(${mod}) };')
> +
> + fmts = []
> +
> + for format in formats:
> + name, format = format.popitem()
> +
> + data = {
> + 'name': name,
> + 'fourcc': drm_fourcc.fourcc(format['fourcc']),
> + 'mod': '0, 0',
> + }
> +
> + mod = format.get('mod')
> + if mod:
> + data['mod'] = '%u, %u' % drm_fourcc.mod(mod)
> +
> + fmts.append(template.substitute(data))
> +
> + return {'formats': '\n'.join(fmts)}
> +
> +
> +def fill_template(template, data):
> +
> + template = open(template, 'rb').read()
> + template = template.decode('utf-8')
> + template = string.Template(template)
> + return template.substitute(data)
Nice, I didn't know about pythons built in string Template ..
> +
> +
> +def main(argv):
> +
> + # Parse command line arguments
> + parser = argparse.ArgumentParser()
> + parser.add_argument('-o', dest='output', metavar='file', type=str,
> + help='Output file name. Defaults to standard output if not specified.')
> + parser.add_argument('input', type=str,
> + help='Input file name.')
> + parser.add_argument('template', type=str,
> + help='Template file name.')
> + parser.add_argument('drm_fourcc', type=str,
> + help='Path to drm_fourcc.h.')
> + args = parser.parse_args(argv[1:])
> +
> + data = open(args.input, 'rb').read()
> + formats = yaml.safe_load(data)['formats']
> + drm_fourcc = DRMFourCC(args.drm_fourcc)
> +
> + data = generate_h(formats, drm_fourcc)
> + data = fill_template(args.template, data)
> +
> + if args.output:
> + output = open(args.output, 'wb')
> + output.write(data.encode('utf-8'))
> + output.close()
> + else:
> + sys.stdout.write(data)
> +
> + return 0
> +
> +
> +if __name__ == '__main__':
> + sys.exit(main(sys.argv))
> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> index 73c5b999acf4..cdb8e0372e77 100644
> --- a/include/libcamera/meson.build
> +++ b/include/libcamera/meson.build
> @@ -29,6 +29,11 @@ subdir('ipa')
> install_headers(libcamera_public_headers,
> subdir : include_dir)
>
> +#
> +# Generate headers from templates.
> +#
> +
> +# control_ids.h and property_ids.h
> gen_controls = files('../../src/libcamera/gen-controls.py')
>
> control_source_files = [
> @@ -51,6 +56,22 @@ endforeach
>
> libcamera_public_headers += control_headers
>
> +# formats.h
> +gen_formats = files('gen-formats.py')
> +
> +formats_h = custom_target('formats_h',
> + input : files(
> + '../../src/libcamera/formats.yaml',
> + 'formats.h.in',
> + '../linux/drm_fourcc.h'
> + ),
> + output : 'formats.h',
> + command : [gen_formats, '-o', '@OUTPUT@', '@INPUT@'],
> + install : true,
> + install_dir : join_paths('include', include_dir))
> +libcamera_public_headers += formats_h
> +
> +# libcamera.h
> gen_header = files('gen-header.sh')
>
> libcamera_h = custom_target('gen-header',
> @@ -62,6 +83,7 @@ libcamera_h = custom_target('gen-header',
>
> libcamera_public_headers += libcamera_h
>
> +# version.h
> version = libcamera_version.split('.')
> libcamera_version_config = configuration_data()
> libcamera_version_config.set('LIBCAMERA_VERSION_MAJOR', version[0])
> diff --git a/src/libcamera/formats.cpp b/src/libcamera/formats.cpp
> index 2ac3b412ecdb..74c239a5e710 100644
> --- a/src/libcamera/formats.cpp
> +++ b/src/libcamera/formats.cpp
> @@ -12,7 +12,7 @@
> #include "libcamera/internal/log.h"
>
> /**
> - * \file formats.h
> + * \file internal/formats.h
> * \brief Types and helper methods to handle libcamera image formats
> */
>
> diff --git a/src/libcamera/formats.yaml b/src/libcamera/formats.yaml
> new file mode 100644
> index 000000000000..a6841c618f93
> --- /dev/null
> +++ b/src/libcamera/formats.yaml
> @@ -0,0 +1,124 @@
> +# SPDX-License-Identifier: LGPL-2.1-or-later
> +#
> +# Copyright (C) 2020, Google Inc.
> +#
> +%YAML 1.2
> +---
> +formats:
> + - R8:
> + fourcc: DRM_FORMAT_R8
> +
Initially, I was going to ask why not mask out the redundant DRM_FORMAT_
and just populate the fourcc by appending the name to the prefix,
However, now I think I prefer being explicit as it gives a good tie to
the 'actual' format source.
Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
> + - RGB888:
> + fourcc: DRM_FORMAT_RGB888
> + - BGR888:
> + fourcc: DRM_FORMAT_BGR888
> +
> + - XRGB8888:
> + fourcc: DRM_FORMAT_XRGB8888
> + - XBGR8888:
> + fourcc: DRM_FORMAT_XBGR8888
> + - RGBX8888:
> + fourcc: DRM_FORMAT_RGBX8888
> + - BGRX8888:
> + fourcc: DRM_FORMAT_BGRX8888
> +
> + - ARGB8888:
> + fourcc: DRM_FORMAT_ARGB8888
> + - ABGR8888:
> + fourcc: DRM_FORMAT_ABGR8888
> + - RGBA8888:
> + fourcc: DRM_FORMAT_RGBA8888
> + - BGRA8888:
> + fourcc: DRM_FORMAT_BGRA8888
> +
> + - YUYV:
> + fourcc: DRM_FORMAT_YUYV
> + - YVYU:
> + fourcc: DRM_FORMAT_YVYU
> + - UYVY:
> + fourcc: DRM_FORMAT_UYVY
> + - VYUY:
> + fourcc: DRM_FORMAT_VYUY
> +
> + - NV12:
> + fourcc: DRM_FORMAT_NV12
> + - NV21:
> + fourcc: DRM_FORMAT_NV21
> + - NV16:
> + fourcc: DRM_FORMAT_NV16
> + - NV61:
> + fourcc: DRM_FORMAT_NV61
> + - NV24:
> + fourcc: DRM_FORMAT_NV24
> + - NV42:
> + fourcc: DRM_FORMAT_NV42
> +
> + - MJPEG:
> + fourcc: DRM_FORMAT_MJPEG
> +
> + - SRGGB8:
> + fourcc: DRM_FORMAT_SRGGB8
> + - SGRBG8:
> + fourcc: DRM_FORMAT_SGRBG8
> + - SGBRG8:
> + fourcc: DRM_FORMAT_SGBRG8
> + - SBGGR8:
> + fourcc: DRM_FORMAT_SBGGR8
> +
> + - SRGGB10:
> + fourcc: DRM_FORMAT_SRGGB10
> + - SGRBG10:
> + fourcc: DRM_FORMAT_SGRBG10
> + - SGBRG10:
> + fourcc: DRM_FORMAT_SGBRG10
> + - SBGGR10:
> + fourcc: DRM_FORMAT_SBGGR10
> +
> + - SRGGB12:
> + fourcc: DRM_FORMAT_SRGGB12
> + - SGRBG12:
> + fourcc: DRM_FORMAT_SGRBG12
> + - SGBRG12:
> + fourcc: DRM_FORMAT_SGBRG12
> + - SBGGR12:
> + fourcc: DRM_FORMAT_SBGGR12
> +
> + - SRGGB10_CSI2P:
> + fourcc: DRM_FORMAT_SRGGB10
> + mod: MIPI_FORMAT_MOD_CSI2_PACKED
> + - SGRBG10_CSI2P:
> + fourcc: DRM_FORMAT_SGRBG10
> + mod: MIPI_FORMAT_MOD_CSI2_PACKED
> + - SGBRG10_CSI2P:
> + fourcc: DRM_FORMAT_SGBRG10
> + mod: MIPI_FORMAT_MOD_CSI2_PACKED
> + - SBGGR10_CSI2P:
> + fourcc: DRM_FORMAT_SBGGR10
> + mod: MIPI_FORMAT_MOD_CSI2_PACKED
> +
> + - SRGGB12_CSI2P:
> + fourcc: DRM_FORMAT_SRGGB12
> + mod: MIPI_FORMAT_MOD_CSI2_PACKED
> + - SGRBG12_CSI2P:
> + fourcc: DRM_FORMAT_SGRBG12
> + mod: MIPI_FORMAT_MOD_CSI2_PACKED
> + - SGBRG12_CSI2P:
> + fourcc: DRM_FORMAT_SGBRG12
> + mod: MIPI_FORMAT_MOD_CSI2_PACKED
> + - SBGGR12_CSI2P:
> + fourcc: DRM_FORMAT_SBGGR12
> + mod: MIPI_FORMAT_MOD_CSI2_PACKED
> +
> + - SRGGB10_IPU3:
> + fourcc: DRM_FORMAT_SRGGB10
> + mod: IPU3_FORMAT_MOD_PACKED
> + - SGRBG10_IPU3:
> + fourcc: DRM_FORMAT_SGRBG10
> + mod: IPU3_FORMAT_MOD_PACKED
> + - SGBRG10_IPU3:
> + fourcc: DRM_FORMAT_SGBRG10
> + mod: IPU3_FORMAT_MOD_PACKED
> + - SBGGR10_IPU3:
> + fourcc: DRM_FORMAT_SBGGR10
> + mod: IPU3_FORMAT_MOD_PACKED
> +...
> diff --git a/src/libcamera/pixel_format.cpp b/src/libcamera/pixel_format.cpp
> index d501c5f09c6b..f191851ae22c 100644
> --- a/src/libcamera/pixel_format.cpp
> +++ b/src/libcamera/pixel_format.cpp
> @@ -5,6 +5,7 @@
> * pixel_format.cpp - libcamera Pixel Format
> */
>
> +#include <libcamera/formats.h>
> #include <libcamera/pixel_format.h>
>
> /**
> @@ -21,7 +22,8 @@ namespace libcamera {
> * The PixelFormat type describes the format of images in the public libcamera
> * API. It stores a FourCC value as a 32-bit unsigned integer and a modifier.
> * The FourCC and modifier values are defined in the Linux kernel DRM/KMS API
> - * (see linux/drm_fourcc.h).
> + * (see linux/drm_fourcc.h). Constant expressions for all pixel formats
> + * supported by libcamera are available in libcamera/formats.h.
> */
>
> /**
>
--
Regards
--
Kieran
More information about the libcamera-devel
mailing list