[libcamera-devel] [PATCH v2 05/13] libcamera: controls: Auto-generate control_ids.h and control_ids.cpp

Laurent Pinchart laurent.pinchart at ideasonboard.com
Thu Oct 3 23:18:53 CEST 2019


Hi Niklas,

On Thu, Oct 03, 2019 at 09:31:14PM +0200, Niklas Söderlund wrote:
> On 2019-09-29 22:02:46 +0300, Laurent Pinchart wrote:
> > Bring back auto-generation of control ids. In this version, both the
> > header and the source files are generated from a single YAML file that
> > stores all control definitions. This allows centralising controls in a
> > single file, while the previous version required keeping both
> > declarations (in a header) and documentation (in a the source) in sync
> > manually.
> > 
> > Using YAML as a format to store control definitions is a trade-off
> > between ease of use (there are many YAML parsers available) and
> > simplicity (XML was considered, but would have lead to more complex
> > processing). A new build time dependency is added on python3-yaml, which
> > should be available as a package in all distributions and build
> > environments.
> > 
> > The YAML format is likely to change over time as we improve
> > documentation of controls, the first version simply copies the
> > information currently available. Future improvements should also include
> > a YAML schema to validate the YAML source file.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > ---
> >  Documentation/Doxyfile.in                     |   4 +-
> >  README.rst                                    |   2 +-
> >  .../{control_ids.h => control_ids.h.in}       |  16 +--
> >  include/libcamera/gen-header.sh               |   2 +-
> >  include/libcamera/meson.build                 |  18 ++-
> >  .../libcamera/libcamera-9999.ebuild           |   9 +-
> >  src/libcamera/control_ids.cpp                 |  52 --------
> >  src/libcamera/control_ids.cpp.in              |  25 ++++
> >  src/libcamera/control_ids.yaml                |  35 ++++++
> >  src/libcamera/gen-controls.py                 | 114 ++++++++++++++++++
> >  src/libcamera/meson.build                     |  12 +-
> >  11 files changed, 215 insertions(+), 74 deletions(-)
> >  rename include/libcamera/{control_ids.h => control_ids.h.in} (53%)
> >  delete mode 100644 src/libcamera/control_ids.cpp
> >  create mode 100644 src/libcamera/control_ids.cpp.in
> >  create mode 100644 src/libcamera/control_ids.yaml
> >  create mode 100755 src/libcamera/gen-controls.py
> > 
> > diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in
> > index 28a9c2da1ad4..5237cf60854f 100644
> > --- a/Documentation/Doxyfile.in
> > +++ b/Documentation/Doxyfile.in
> > @@ -793,7 +793,9 @@ WARN_LOGFILE           =
> >  
> >  INPUT                  = "@TOP_SRCDIR@/include/ipa" \
> >  			 "@TOP_SRCDIR@/include/libcamera" \
> > -			 "@TOP_SRCDIR@/src/libcamera"
> > +			 "@TOP_SRCDIR@/src/libcamera" \
> > +			 "@TOP_BUILDDIR@/include/libcamera" \
> > +			 "@TOP_BUILDDIR@/src/libcamera"
> >  
> >  # This tag can be used to specify the character encoding of the source files
> >  # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
> > diff --git a/README.rst b/README.rst
> > index 169837e41a4e..2ccf7cbec40a 100644
> > --- a/README.rst
> > +++ b/README.rst
> > @@ -40,7 +40,7 @@ A C++ toolchain: [required]
> >  	Either {g++, clang}
> >  
> >  for libcamera: [required]
> > -	meson ninja-build
> > +	meson ninja-build python3-yaml
> >  
> >  for device hotplug enumeration: [optional]
> >  	pkg-config libudev-dev
> > diff --git a/include/libcamera/control_ids.h b/include/libcamera/control_ids.h.in
> > similarity index 53%
> > rename from include/libcamera/control_ids.h
> > rename to include/libcamera/control_ids.h.in
> > index 54235f1aea95..1d0bc791e559 100644
> > --- a/include/libcamera/control_ids.h
> > +++ b/include/libcamera/control_ids.h.in
> > @@ -3,6 +3,8 @@
> >   * Copyright (C) 2019, Google Inc.
> >   *
> >   * control_ids.h : Control ID list
> > + *
> > + * This file is auto-generated. Do not edit.
> >   */
> >  
> >  #ifndef __LIBCAMERA_CONTROL_IDS_H__
> > @@ -17,20 +19,10 @@ namespace libcamera {
> >  namespace controls {
> >  
> >  enum {
> > -	AWB_ENABLE = 1,
> > -	BRIGHTNESS = 2,
> > -	CONTRAST = 3,
> > -	SATURATION = 4,
> > -	MANUAL_EXPOSURE = 5,
> > -	MANUAL_GAIN = 6,
> > +${ids}
> >  };
> >  
> > -extern const Control<bool> AwbEnable;
> > -extern const Control<int32_t> Brightness;
> > -extern const Control<int32_t> Contrast;
> > -extern const Control<int32_t> Saturation;
> > -extern const Control<int32_t> ManualExposure;
> > -extern const Control<int32_t> ManualGain;
> > +${controls}
> >  
> >  } /* namespace controls */
> >  
> > diff --git a/include/libcamera/gen-header.sh b/include/libcamera/gen-header.sh
> > index a69fe8e982a1..7f7816c9f879 100755
> > --- a/include/libcamera/gen-header.sh
> > +++ b/include/libcamera/gen-header.sh
> > @@ -19,7 +19,7 @@ EOF
> >  headers=$(for header in "$src_dir"/*.h ; do
> >  	header=$(basename "$header")
> >  	echo "$header"
> > -done ; echo "version.h" | sort)
> > +done ; echo "control_ids.h" ; echo "version.h" | sort)
> >  
> >  for header in $headers ; do
> >  	echo "#include <libcamera/$header>" >> "$dst_file"
> > diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> > index 868f1a6bf1ab..4ffbdab3b173 100644
> > --- a/include/libcamera/meson.build
> > +++ b/include/libcamera/meson.build
> > @@ -3,7 +3,6 @@ libcamera_api = files([
> >      'buffer.h',
> >      'camera.h',
> >      'camera_manager.h',
> > -    'control_ids.h',
> >      'controls.h',
> >      'event_dispatcher.h',
> >      'event_notifier.h',
> > @@ -18,6 +17,20 @@ libcamera_api = files([
> >  
> >  include_dir = join_paths(libcamera_include_dir, 'libcamera')
> >  
> > +install_headers(libcamera_api,
> > +                subdir : include_dir)
> > +
> > +gen_controls = files('../../src/libcamera/gen-controls.py')
> > +
> > +control_ids_h = custom_target('control_ids_h',
> > +                              input : files('../../src/libcamera/control_ids.yaml', 'control_ids.h.in'),
> > +                              output : 'control_ids.h',
> > +                              depend_files : gen_controls,
> > +                              command : [gen_controls, '-o', '@OUTPUT@', '@INPUT@'],
> > +                              install_dir : join_paths('include', include_dir))
> > +
> > +libcamera_api += control_ids_h
> > +
> >  gen_header = files('gen-header.sh')
> >  
> >  libcamera_h = custom_target('gen-header',
> > @@ -37,6 +50,3 @@ configure_file(input : 'version.h.in',
> >                 output : 'version.h',
> >                 configuration : libcamera_version_config,
> >                 install_dir : join_paths('include', include_dir))
> > -
> > -install_headers(libcamera_api,
> > -                subdir : include_dir)
> > diff --git a/package/gentoo/media-libs/libcamera/libcamera-9999.ebuild b/package/gentoo/media-libs/libcamera/libcamera-9999.ebuild
> > index fed2b409a91b..fc241b1f5584 100644
> > --- a/package/gentoo/media-libs/libcamera/libcamera-9999.ebuild
> > +++ b/package/gentoo/media-libs/libcamera/libcamera-9999.ebuild
> > @@ -2,7 +2,9 @@
> >  # Distributed under the terms of the GNU General Public License v2
> >  
> >  EAPI=6
> > -inherit git-r3 meson
> > +PYTHON_COMPAT=( python3_{5,6,7} )
> > +
> > +inherit git-r3 meson python-any-r1
> >  
> >  DESCRIPTION="Camera support library for Linux"
> >  HOMEPAGE="http://libcamera.org"
> > @@ -15,7 +17,10 @@ KEYWORDS="*"
> >  IUSE="udev"
> >  
> >  RDEPEND="udev? ( virtual/libudev )"
> > -DEPEND="${RDEPEND}"
> > +DEPEND="
> > +	${RDEPEND}
> > +	$(python_gen_any_dep 'dev-python/pyyaml[${PYTHON_USEDEP}]')
> > +"
> >  
> >  src_configure() {
> >  	local emesonargs=(
> > diff --git a/src/libcamera/control_ids.cpp b/src/libcamera/control_ids.cpp
> > deleted file mode 100644
> > index 3af23a458862..000000000000
> > --- a/src/libcamera/control_ids.cpp
> > +++ /dev/null
> > @@ -1,52 +0,0 @@
> > -/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > -/*
> > - * Copyright (C) 2019, Google Inc.
> > - *
> > - * control_ids.cpp : Control ID list
> > - */
> > -
> > -#include <libcamera/control_ids.h>
> > -
> > -/**
> > - * \file control_ids.h
> > - * \brief Camera control identifiers
> > - */
> > -
> > -namespace libcamera {
> > -
> > -namespace controls {
> > -
> > -/**
> > - * \brief Enables or disables the AWB.
> > - * \sa ManualGain
> > - */
> > -extern const Control<bool> AwbEnable(AWB_ENABLE, "AwbEnable");
> > -
> > -/**
> > - * \brief Specify a fixed brightness parameter.
> > - */
> > -extern const Control<int32_t> Brightness(BRIGHTNESS, "Brightness");
> > -
> > -/**
> > - * \brief Specify a fixed contrast parameter.
> > - */
> > -extern const Control<int32_t> Contrast(CONTRAST, "Contrast");
> > -
> > -/**
> > - * \brief Specify a fixed saturation parameter.
> > - */
> > -extern const Control<int32_t> Saturation(SATURATION, "Saturation");
> > -
> > -/**
> > - * \brief Specify a fixed exposure time in milli-seconds
> > - */
> > -extern const Control<int32_t> ManualExposure(MANUAL_EXPOSURE, "ManualExposure");
> > -
> > -/**
> > - * \brief Specify a fixed gain parameter
> > - */
> > -extern const Control<int32_t> ManualGain(MANUAL_GAIN, "ManualGain");
> > -
> > -} /* namespace controls */
> > -
> > -} /* namespace libcamera */
> > diff --git a/src/libcamera/control_ids.cpp.in b/src/libcamera/control_ids.cpp.in
> > new file mode 100644
> > index 000000000000..f699ac9eea54
> > --- /dev/null
> > +++ b/src/libcamera/control_ids.cpp.in
> > @@ -0,0 +1,25 @@
> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > +/*
> > + * Copyright (C) 2019, Google Inc.
> > + *
> > + * control_ids.cpp : Control ID list
> > + *
> > + * This file is auto-generated. Do not edit.
> > + */
> > +
> > +#include <libcamera/control_ids.h>
> > +
> > +/**
> > + * \file control_ids.h
> > + * \brief Camera control identifiers
> > + */
> > +
> > +namespace libcamera {
> > +
> > +namespace controls {
> > +
> > +${controls}
> > +
> > +} /* namespace controls */
> > +
> > +} /* namespace libcamera */
> > diff --git a/src/libcamera/control_ids.yaml b/src/libcamera/control_ids.yaml
> > new file mode 100644
> > index 000000000000..819a5967a2fc
> > --- /dev/null
> > +++ b/src/libcamera/control_ids.yaml
> > @@ -0,0 +1,35 @@
> > +# SPDX-License-Identifier: LGPL-2.1-or-later
> > +#
> > +# Copyright (C) 2019, Google Inc.
> > +#
> > +%YAML 1.2
> > +---
> > +controls:
> > +  - AwbEnable:
> > +      type: bool
> > +      description: |
> > +        Enables or disables the AWB.
> > +
> > +        \sa ManualGain
> > +
> > +  - Brightness:
> > +      type: int32_t
> > +      description: Specify a fixed brightness parameter
> > +
> > +  - Contrast:
> > +      type: int32_t
> > +      description: Specify a fixed contrast parameter
> > +
> > +  - Saturation:
> > +      type: int32_t
> > +      description: Specify a fixed saturation parameter
> > +
> > +  - ManualExposure:
> > +      type: int32_t
> > +      description: Specify a fixed exposure time in milli-seconds
> > +
> > +  - ManualGain:
> > +      type: int32_t
> > +      description: Specify a fixed gain parameter
> > +
> > +...
> > diff --git a/src/libcamera/gen-controls.py b/src/libcamera/gen-controls.py
> > new file mode 100755
> > index 000000000000..0899e40b4080
> > --- /dev/null
> > +++ b/src/libcamera/gen-controls.py
> > @@ -0,0 +1,114 @@
> > +#!/usr/bin/python3
> > +# SPDX-License-Identifier: GPL-2.0-or-later
> > +# Copyright (C) 2019, Google Inc.
> > +#
> > +# Author: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > +#
> > +# gen-controls.py - Generate control definitions from YAML
> > +
> > +import argparse
> > +import string
> > +import sys
> > +import yaml
> > +
> > +
> > +def snake_case(s):
> > +    return ''.join([c.isupper() and ('_' + c) or c for c in s]).strip('_')
> > +
> > +
> > +def generate_cpp(controls):
> > +    template = string.Template('''/**
> > +${description}
> > + */
> > +extern const Control<${type}> ${name}(${id_name}, "${name}");''')
> > +
> > +    ctrls = []
> > +
> > +    for ctrl in controls:
> > +        name, ctrl = ctrl.popitem()
> > +        id_name = snake_case(name).upper()
> > +
> > +        description = ctrl['description'].strip('\n').split('\n')
> > +        description[0] = '\\brief ' + description[0]
> > +        description = '\n'.join([(line and ' * ' or ' *') + line for line in description])
> > +
> > +        info = {
> > +            'name': name,
> > +            'type': ctrl['type'],
> > +            'description': description,
> > +            'id_name': id_name,
> > +        }
> > +
> > +        ctrls.append(template.substitute(info))
> > +
> > +    return {'controls': '\n\n'.join(ctrls)}
> > +
> > +
> > +def generate_h(controls):
> > +    template = string.Template('''extern const Control<${type}> ${name};''')
> > +
> > +    ctrls = []
> > +    ids = []
> > +    id_value = 1
> > +
> > +    for ctrl in controls:
> > +        name, ctrl = ctrl.popitem()
> > +        id_name = snake_case(name).upper()
> > +
> > +        ids.append('\t' + id_name + ' = ' + str(id_value) + ',')
> > +
> > +        info = {
> > +            'name': name,
> > +            'type': ctrl['type'],
> > +        }
> > +
> > +        ctrls.append(template.substitute(info))
> > +        id_value += 1
> > +
> > +    return {'ids': '\n'.join(ids), 'controls': '\n'.join(ctrls)}
> > +
> > +
> > +def fill_template(template, data):
> > +
> > +    template = open(template, 'rb').read()
> > +    template = template.decode('utf-8')
> > +    template = string.Template(template)
> > +    return template.substitute(data)
> > +
> > +
> > +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.')
> > +    args = parser.parse_args(argv[1:])
> > +
> > +    data = open(args.input, 'rb').read()
> > +    controls = yaml.safe_load(data)['controls']
> > +
> > +    if args.template.endswith('.cpp.in'):
> > +        data = generate_cpp(controls)
> > +    elif args.template.endswith('.h.in'):
> > +        data = generate_h(controls)
> > +    else:
> > +        raise RuntimeError('Unknown template type')
> > +
> > +    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/src/libcamera/meson.build b/src/libcamera/meson.build
> > index 8123d1d5bee9..6df48365266d 100644
> > --- a/src/libcamera/meson.build
> > +++ b/src/libcamera/meson.build
> > @@ -5,7 +5,6 @@ libcamera_sources = files([
> >      'camera_manager.cpp',
> >      'camera_sensor.cpp',
> >      'controls.cpp',
> > -    'control_ids.cpp',
> >      'device_enumerator.cpp',
> >      'device_enumerator_sysfs.cpp',
> >      'event_dispatcher.cpp',
> > @@ -58,6 +57,17 @@ if libudev.found()
> >      ])
> >  endif
> >  
> > +gen_controls = files('gen-controls.py')
> > +
> > +control_ids_cpp = custom_target('control_ids_cpp',
> > +                                input : files('control_ids.yaml', 'control_ids.cpp.in'),
> > +                                output : 'control_ids.cpp',
> > +                                depend_files : gen_controls,
> > +                                command : [gen_controls, '-o', '@OUTPUT@', '@INPUT@'])
> > +
> > +libcamera_sources += control_ids_cpp
> > +#libcamera_sources += control_ids_h
> 
> I assume this comment out line should be removed right?

Oops, yes, I'll fix that.

> With that fixed,
> 
> Reviewed-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> 
> > +
> >  gen_version = join_paths(meson.source_root(), 'utils', 'gen-version.sh')
> >  
> >  version_cpp = vcs_tag(command : [gen_version, meson.build_root()],

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list