[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