[{"id":15094,"web_url":"https://patchwork.libcamera.org/comment/15094/","msgid":"<b86e4962-c2f5-89a5-8f23-83116fa60be2@ideasonboard.com>","date":"2021-02-11T14:41:28","subject":"Re: [libcamera-devel] [PATCH/RFC 1/2] libcamera: Generate Control\n\tinstances for V4L2 controls","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Laurent,\n\nOn 08/02/2021 22:54, Laurent Pinchart wrote:\n> The ControlList class is used for both libcamera controls and V4L2\n> controls, with very different APIs. For libcamera controls, all controls\n> have a corresponding Control instance, which can be used to access a\n> ControlList with a type-safe API. For V4L2 controls, on the other hand,\n> only numerical IDs are available, leading to the usage of an unsafe API.\n> \n> Improve handling of V4L2 controls by generating Control instances for\n> each V4L2 control used by libcamera, using a similar code generation\n> mechanism as for libcamera controls.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  include/libcamera/internal/meson.build        |  29 +++-\n>  .../libcamera/internal/v4l2_control_ids.h.in  |  29 ++++\n>  include/libcamera/internal/v4l2_controls.h    |   2 +\n>  src/libcamera/meson.build                     |   8 +-\n>  src/libcamera/v4l2_control_ids.cpp.in         |  34 +++++\n>  src/libcamera/v4l2_control_ids.yaml           |  62 +++++++++\n>  utils/gen-v4l2-controls.py                    | 126 ++++++++++++++++++\n>  utils/meson.build                             |   1 +\n>  8 files changed, 283 insertions(+), 8 deletions(-)\n>  create mode 100644 include/libcamera/internal/v4l2_control_ids.h.in\n>  create mode 100644 src/libcamera/v4l2_control_ids.cpp.in\n>  create mode 100644 src/libcamera/v4l2_control_ids.yaml\n>  create mode 100755 utils/gen-v4l2-controls.py\n> \n> diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build\n> index a1071721967e..f96eec9602d8 100644\n> --- a/include/libcamera/internal/meson.build\n> +++ b/include/libcamera/internal/meson.build\n> @@ -2,13 +2,6 @@\n>  \n>  subdir('tracepoints')\n>  \n> -libcamera_tracepoint_header = custom_target(\n> -    'tp_header',\n> -    input: ['tracepoints.h.in', tracepoint_files],\n> -    output: 'tracepoints.h',\n> -    command: [gen_tracepoints_header, '@OUTPUT@', '@INPUT@'],\n> -)\n> -\n>  libcamera_internal_headers = files([\n>      'bayer_format.h',\n>      'buffer.h',\n> @@ -49,3 +42,25 @@ libcamera_internal_headers = files([\n>      'v4l2_subdevice.h',\n>      'v4l2_videodevice.h',\n>  ])\n> +\n> +#\n> +# Generate headers from templates.\n> +#\n> +\n> +v4l2_control_header = custom_target(\n> +    'v4l2_control_ids_h',\n> +    input : files('../../../src/libcamera/v4l2_control_ids.yaml', 'v4l2_control_ids.h.in'),\n> +    output : 'v4l2_control_ids.h',\n> +    command : [gen_v4l2_controls, '-o', '@OUTPUT@', '@INPUT@'],\n> +)\n> +\n> +libcamera_internal_headers += v4l2_control_header\n> +\n> +tracepoint_header = custom_target(\n> +    'tp_header',\n> +    input: ['tracepoints.h.in', tracepoint_files],\n> +    output: 'tracepoints.h',\n> +    command: [gen_tracepoints_header, '@OUTPUT@', '@INPUT@'],\n> +)\n> +\n> +libcamera_internal_headers += tracepoint_header\n> diff --git a/include/libcamera/internal/v4l2_control_ids.h.in b/include/libcamera/internal/v4l2_control_ids.h.in\n> new file mode 100644\n> index 000000000000..3f00449c9adf\n> --- /dev/null\n> +++ b/include/libcamera/internal/v4l2_control_ids.h.in\n> @@ -0,0 +1,29 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2021, Google Inc.\n> + *\n> + * v4l2_control_ids.h - V4L2 Control ID list\n> + *\n> + * This file is auto-generated. Do not edit.\n> + */\n> +\n> +#ifndef __LIBCAMERA_V4L2_CONTROL_IDS_H__\n> +#define __LIBCAMERA_V4L2_CONTROL_IDS_H__\n> +\n> +#include <stdint.h>\n> +\n> +#include <libcamera/controls.h>\n> +\n> +namespace libcamera {\n> +\n> +namespace v4l2 {\n> +\n> +#ifndef __DOXYGEN__\n> +${controls}\n> +#endif\n> +\n> +} /* namespace v4l2 */\n> +\n> +} /* namespace libcamera */\n> +\n> +#endif /* __LIBCAMERA_V4L2_CONTROL_IDS_H__ */\n> diff --git a/include/libcamera/internal/v4l2_controls.h b/include/libcamera/internal/v4l2_controls.h\n> index 0851b8ddb128..c54aed00cfae 100644\n> --- a/include/libcamera/internal/v4l2_controls.h\n> +++ b/include/libcamera/internal/v4l2_controls.h\n> @@ -12,6 +12,8 @@\n>  \n>  #include <libcamera/controls.h>\n>  \n> +#include \"libcamera/internal/v4l2_control_ids.h\"\n> +\n>  namespace libcamera {\n>  \n>  class V4L2ControlId : public ControlId\n> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> index ebce19d90c1e..36f79e11e1ac 100644\n> --- a/src/libcamera/meson.build\n> +++ b/src/libcamera/meson.build\n> @@ -57,7 +57,7 @@ libcamera_sources = files([\n>  ])\n>  \n>  libcamera_sources += libcamera_public_headers\n> -libcamera_sources += libcamera_tracepoint_header\n> +libcamera_sources += libcamera_internal_headers\n>  \n>  includes = [\n>      libcamera_includes,\n> @@ -97,6 +97,12 @@ foreach source : control_source_files\n>                                       command : [gen_controls, '-o', '@OUTPUT@', '@INPUT@'])\n>  endforeach\n>  \n> +control_sources += custom_target('v4l2_control_ids_cpp',\n> +                                 input : files('v4l2_control_ids.yaml',\n> +                                               'v4l2_control_ids.cpp.in'),\n> +                                 output : 'v4l2_control_ids.cpp',\n> +                                 command : [gen_v4l2_controls, '-o', '@OUTPUT@', '@INPUT@'])\n> +\n>  libcamera_sources += control_sources\n>  \n>  gen_version = join_paths(meson.source_root(), 'utils', 'gen-version.sh')\n> diff --git a/src/libcamera/v4l2_control_ids.cpp.in b/src/libcamera/v4l2_control_ids.cpp.in\n> new file mode 100644\n> index 000000000000..6c57a5b0e4eb\n> --- /dev/null\n> +++ b/src/libcamera/v4l2_control_ids.cpp.in\n> @@ -0,0 +1,34 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2031, Google Inc.\n\nPlease please please let me borrow your time machine ...\n\nI promise I will only use it for ... good investments.\n\n> + *\n> + * v4l2_control_ids.cpp : V4L2 Control ID list\n> + *\n> + * This file is auto-generated. Do not edit.\n> + */\n> +\n> +#include <linux/v4l2-controls.h>\n> +\n> +#include <libcamera/controls.h>\n> +\n> +#include \"libcamera/internal/v4l2_control_ids.h\"\n> +\n> +/**\n> + * \\file v4l2_control_ids.h\n> + * \\brief V4L2 control identifiers\n> + */\n> +\n> +namespace libcamera {\n> +\n> +/**\n> + * \\brief Namespace for V4L2 controls\n> + */\n> +namespace v4l2 {\n> +\n> +#ifndef __DOXYGEN__\n> +${controls_def}\n> +#endif\n> +\n> +} /* namespace v4l2 */\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/v4l2_control_ids.yaml b/src/libcamera/v4l2_control_ids.yaml\n> new file mode 100644\n> index 000000000000..ec0adb21695f\n> --- /dev/null\n> +++ b/src/libcamera/v4l2_control_ids.yaml\n> @@ -0,0 +1,62 @@\n> +# SPDX-License-Identifier: LGPL-2.1-or-later\n> +#\n> +# Copyright (C) 2021, Google Inc.\n> +#\n> +%YAML 1.2\n> +---\n> +\n> +controls:\n> +  - V4L2_CID_ANALOGUE_GAIN:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_BLUE_BALANCE:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_BRIGHTNESS:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_CAMERA_ORIENTATION:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_CAMERA_SENSOR_ROTATION:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_CONTRAST:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_DIGITAL_GAIN:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_EXPOSURE:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_EXPOSURE_ABSOLUTE:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_EXPOSURE_AUTO:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_GAIN:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_HBLANK:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_HFLIP:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_PIXEL_RATE:\n> +      type: int64_t\n> +\n> +  - V4L2_CID_RED_BALANCE:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_SATURATION:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_VBLANK:\n> +      type: int32_t\n> +\n> +  - V4L2_CID_VFLIP:\n> +      type: int32_t\n\nMy earlier concern about this is that now we need to have a specific\ndefinition for every v4l2 control, but perhaps there's nothing wrong\nwith adding a new declaration to this list when it's required.\n\nIt's not public API so it's internal only, which even means the ordering\ncan change to keep the list sorted.\n\nOtherwise, we could generate the list from the v4l2 header -but that\nthen defines more controls than are needed.\n\nSo ... this probably works.\n\n\nThis also means we have a centralised list of V4L2 controls to\nreference, and from the looks of 2/2 means we don't have to directly\npull in v4l2 kernel headers into IPAs which feels like a bit of a win.\n\nI'm not 100% sure I like the idea of 'wrapping' V4L2_CID_EXPOSURE to\nv4l2::EXPOSURE, because I'm weary that the name change (or rather prefix\nsubstitution) would make it harder to find references to specific\ncontrols but ... I can't see how that would actually be a problem yet.\n\nI'd be quite happy to see  this progress, so as I expect it is already\nfunctional:\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n\n\n> +...\n> diff --git a/utils/gen-v4l2-controls.py b/utils/gen-v4l2-controls.py\n> new file mode 100755\n> index 000000000000..2eb964f6f459\n> --- /dev/null\n> +++ b/utils/gen-v4l2-controls.py\n> @@ -0,0 +1,126 @@\n> +#!/usr/bin/env python3\n> +# SPDX-License-Identifier: GPL-2.0-or-later\n> +# Copyright (C) 2021, Google Inc.\n> +#\n> +# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> +#\n> +# gen-v4l2-controls.py - Generate V4L2 control definitions from YAML\n> +\n> +import argparse\n> +import string\n> +import sys\n> +import yaml\n> +\n> +PREFIX = 'V4L2_CID_'\n> +\n> +\n> +def generate_cpp(controls):\n> +    def_template = string.Template('extern const Control<${type}> ${name}(${id_name}, \"${name}\");')\n> +\n> +    ctrls_def = []\n> +\n> +    for ctrl in controls:\n> +        name, ctrl = ctrl.popitem()\n> +\n> +        if not name.startswith(PREFIX):\n> +            raise RuntimeError(f'Invalid control name {name}')\n> +\n> +        id_name = name\n> +        name = name[len(PREFIX):]\n> +\n> +        ctrl_type = ctrl['type']\n> +        if ctrl_type == 'string':\n> +            ctrl_type = 'std::string'\n> +        elif ctrl.get('size'):\n> +            ctrl_type = 'Span<const %s>' % ctrl_type\n> +\n> +        info = {\n> +            'name': name,\n> +            'type': ctrl_type,\n> +            'id_name': id_name,\n> +        }\n> +\n> +        ctrls_def.append(def_template.substitute(info))\n> +\n> +    return {\n> +        'controls_def': '\\n'.join(ctrls_def),\n> +    }\n> +\n> +\n> +def generate_h(controls):\n> +    template = string.Template('''extern const Control<${type}> ${name};''')\n> +\n> +    ctrls = []\n> +    draft_ctrls = []\n> +    ids = []\n> +\n> +    for ctrl in controls:\n> +        name, ctrl = ctrl.popitem()\n> +\n> +        if not name.startswith(PREFIX):\n> +            raise RuntimeError(f'Invalid control name {name}')\n> +\n> +        name = name[len(PREFIX):]\n> +\n> +        ctrl_type = ctrl['type']\n> +        if ctrl_type == 'string':\n> +            ctrl_type = 'std::string'\n> +        elif ctrl.get('size'):\n> +            ctrl_type = 'Span<const %s>' % ctrl_type\n> +\n> +        info = {\n> +            'name': name,\n> +            'type': ctrl_type,\n> +        }\n> +\n> +        ctrls.append(template.substitute(info))\n> +\n> +    return {\n> +        'controls': '\\n'.join(ctrls),\n> +    }\n> +\n> +\n> +def fill_template(template, data):\n> +\n> +    template = open(template, 'rb').read()\n> +    template = template.decode('utf-8')\n> +    template = string.Template(template)\n> +    return template.substitute(data)\n> +\n> +\n> +def main(argv):\n> +\n> +    # Parse command line arguments\n> +    parser = argparse.ArgumentParser()\n> +    parser.add_argument('-o', dest='output', metavar='file', type=str,\n> +                        help='Output file name. Defaults to standard output if not specified.')\n> +    parser.add_argument('input', type=str,\n> +                        help='Input file name.')\n> +    parser.add_argument('template', type=str,\n> +                        help='Template file name.')\n> +    args = parser.parse_args(argv[1:])\n> +\n> +    data = open(args.input, 'rb').read()\n> +    controls = yaml.safe_load(data)['controls']\n> +\n> +    if args.template.endswith('.cpp.in'):\n> +        data = generate_cpp(controls)\n> +    elif args.template.endswith('.h.in'):\n> +        data = generate_h(controls)\n> +    else:\n> +        raise RuntimeError('Unknown template type')\n> +\n> +    data = fill_template(args.template, data)\n> +\n> +    if args.output:\n> +        output = open(args.output, 'wb')\n> +        output.write(data.encode('utf-8'))\n> +        output.close()\n> +    else:\n> +        sys.stdout.write(data)\n> +\n> +    return 0\n> +\n> +\n> +if __name__ == '__main__':\n> +    sys.exit(main(sys.argv))\n> diff --git a/utils/meson.build b/utils/meson.build\n> index 8e28ada7165a..8ff1e40dbe81 100644\n> --- a/utils/meson.build\n> +++ b/utils/meson.build\n> @@ -9,6 +9,7 @@ py_modules += ['yaml']\n>  gen_controls = files('gen-controls.py')\n>  gen_formats = files('gen-formats.py')\n>  gen_header = files('gen-header.sh')\n> +gen_v4l2_controls = files('gen-v4l2-controls.py')\n>  \n>  ## Module signing\n>  gen_ipa_priv_key = files('gen-ipa-priv-key.sh')\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id D2E34BD162\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 11 Feb 2021 14:41:32 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4893D6373B;\n\tThu, 11 Feb 2021 15:41:32 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4ECA8601B5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 11 Feb 2021 15:41:31 +0100 (CET)","from [192.168.0.20]\n\t(cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id A5C1241;\n\tThu, 11 Feb 2021 15:41:30 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"LqQnOZrn\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1613054490;\n\tbh=KF0pxaVIxNJ3hbonvOoTVS2KaYky+lImtxSfyDWBoCQ=;\n\th=Reply-To:Subject:To:References:From:Date:In-Reply-To:From;\n\tb=LqQnOZrnHrjMZq36LW88J7b8gdlBKhsnUx3xSPY6qspygta1NNnsLoKmDb38fwdQ1\n\tYP9LmrguVHnf0PSWHM96zwEqTuzdAGfA9CXFYbyChel0Vpt1Mya8jEpGScfupoQFQa\n\t6y/9khURfruk5B66V4uiTyZZGS+hMJ75K7F1evnQ=","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20210208225429.31627-1-laurent.pinchart@ideasonboard.com>\n\t<20210208225429.31627-2-laurent.pinchart@ideasonboard.com>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Autocrypt":"addr=kieran.bingham@ideasonboard.com; keydata=\n\t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\n\tWZw01QYHU/GUV/zHJSFk","Organization":"Ideas on Board","Message-ID":"<b86e4962-c2f5-89a5-8f23-83116fa60be2@ideasonboard.com>","Date":"Thu, 11 Feb 2021 14:41:28 +0000","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101\n\tThunderbird/68.10.0","MIME-Version":"1.0","In-Reply-To":"<20210208225429.31627-2-laurent.pinchart@ideasonboard.com>","Content-Language":"en-GB","Subject":"Re: [libcamera-devel] [PATCH/RFC 1/2] libcamera: Generate Control\n\tinstances for V4L2 controls","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Reply-To":"kieran.bingham@ideasonboard.com","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]