build: controls: Rework how controls and properties are generated

Add support for using separate YAML files for controls and properties
generation. The mapping of vendor/pipeline handler to control file is
done through the controls_map variable in include/libcamera/meson.build.

This simplifies management of vendor control definitions and avoids
possible merge conflicts when changing the control_ids.yaml file for
core and draft controls. With this change, libcamera and draft controls
and properties files are designated the 'libcamera' vendor tag.

In this change, we also rename control_ids.yaml -> control_ids_core.yaml
and property_ids.yaml -> property_ids_core.yaml to designate these as
core libcamera controls.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
Naushir Patuck 2023-11-08 13:44:20 +00:00
parent bba4ec63c4
commit 0455bbbf51
9 changed files with 87 additions and 30 deletions

View file

@ -587,12 +587,12 @@ immutable properties of the ``Camera`` device.
The libcamera controls and properties are defined in YAML form which is The libcamera controls and properties are defined in YAML form which is
processed to automatically generate documentation and interfaces. Controls are processed to automatically generate documentation and interfaces. Controls are
defined by the src/libcamera/`control_ids.yaml`_ file and camera properties defined by the src/libcamera/`control_ids_core.yaml`_ file and camera properties
are defined by src/libcamera/`properties_ids.yaml`_. are defined by src/libcamera/`properties_ids_core.yaml`_.
.. _controls framework: https://libcamera.org/api-html/controls_8h.html .. _controls framework: https://libcamera.org/api-html/controls_8h.html
.. _control_ids.yaml: https://libcamera.org/api-html/control__ids_8h.html .. _control_ids_core.yaml: https://libcamera.org/api-html/control__ids_8h.html
.. _properties_ids.yaml: https://libcamera.org/api-html/property__ids_8h.html .. _properties_ids_core.yaml: https://libcamera.org/api-html/property__ids_8h.html
Pipeline handlers can optionally register the list of controls an application Pipeline handlers can optionally register the list of controls an application
can set as well as a list of immutable camera properties. Being both can set as well as a list of immutable camera properties. Being both

View file

@ -32,22 +32,54 @@ install_headers(libcamera_public_headers,
libcamera_headers_install_dir = get_option('includedir') / libcamera_include_dir libcamera_headers_install_dir = get_option('includedir') / libcamera_include_dir
# control_ids.h and property_ids.h and associated modes controls_map = {
control_source_files = { 'controls': {
'control_ids': 'controls', 'core': 'control_ids_core.yaml',
'property_ids': 'properties', },
'properties': {
'core': 'property_ids_core.yaml',
}
} }
control_headers = [] control_headers = []
controls_files = []
properties_files = []
foreach header, mode : control_source_files foreach mode, entry : controls_map
input_files = files('../../src/libcamera/' + header +'.yaml') files_list = []
template_file = files(header + '.h.in') input_files = []
foreach vendor, header : entry
if vendor != 'core' and vendor != 'draft'
if vendor not in pipelines
continue
endif
endif
if header in files_list
continue
endif
files_list += header
input_files += files('../../src/libcamera/' + header)
endforeach
outfile = ''
if mode == 'controls'
outfile = 'control_ids.h'
controls_files += files_list
else
outfile = 'property_ids.h'
properties_files += files_list
endif
template_file = files(outfile + '.in')
control_headers += custom_target(header + '_h', control_headers += custom_target(header + '_h',
input : input_files, input : input_files,
output : header + '.h', output : outfile,
command : [gen_controls, '-o', '@OUTPUT@', command : [gen_controls, '-o', '@OUTPUT@',
'--mode', mode, '-t', template_file, '@INPUT@'], '--mode', mode, '-t', template_file,
'@INPUT@'],
install : true, install : true,
install_dir : libcamera_headers_install_dir) install_dir : libcamera_headers_install_dir)
endforeach endforeach

View file

@ -267,6 +267,8 @@ py_mod.find_installation('python3', modules : py_modules)
summary({ summary({
'Enabled pipelines': pipelines, 'Enabled pipelines': pipelines,
'Enabled IPA modules': enabled_ipa_names, 'Enabled IPA modules': enabled_ipa_names,
'Controls files': controls_files,
'Properties files': properties_files,
'Hotplug support': libudev.found(), 'Hotplug support': libudev.found(),
'Tracing support': tracing_enabled, 'Tracing support': tracing_enabled,
'Android support': android_enabled, 'Android support': android_enabled,

View file

@ -127,12 +127,23 @@ endif
control_sources = [] control_sources = []
foreach source, mode : control_source_files controls_mode_files = {
input_files = files(source +'.yaml') 'controls' : controls_files,
template_file = files(source + '.cpp.in') 'properties' : properties_files,
control_sources += custom_target(source + '_cpp', }
foreach mode, input_files : controls_mode_files
input_files = files(input_files)
if mode == 'controls'
template_file = files('control_ids.cpp.in')
else
template_file = files('property_ids.cpp.in')
endif
control_sources += custom_target(mode + '_cpp',
input : input_files, input : input_files,
output : source + '.cpp', output : mode + '_ids.cpp',
command : [gen_controls, '-o', '@OUTPUT@', command : [gen_controls, '-o', '@OUTPUT@',
'--mode', mode, '-t', template_file, '@INPUT@']) '--mode', mode, '-t', template_file, '@INPUT@'])
endforeach endforeach

View file

@ -95,7 +95,7 @@ def main(argv):
help='Output file name. Defaults to standard output if not specified.') help='Output file name. Defaults to standard output if not specified.')
parser.add_argument('--template', '-t', type=str, required=True, parser.add_argument('--template', '-t', type=str, required=True,
help='Template file name.') help='Template file name.')
parser.add_argument('input', type=str, parser.add_argument('input', type=str, nargs='+',
help='Input file name.') help='Input file name.')
args = parser.parse_args(argv[1:]) args = parser.parse_args(argv[1:])
@ -103,11 +103,11 @@ def main(argv):
print(f'Invalid mode option "{args.mode}"', file=sys.stderr) print(f'Invalid mode option "{args.mode}"', file=sys.stderr)
return -1 return -1
data = open(args.input, 'rb').read()
controls = {} controls = {}
vendor = yaml.safe_load(data)['vendor'] for input in args.input:
controls[vendor] = yaml.safe_load(data)['controls'] data = open(input, 'rb').read()
vendor = yaml.safe_load(data)['vendor']
controls[vendor] = yaml.safe_load(data)['controls']
data = generate_py(controls, args.mode) data = generate_py(controls, args.mode)

View file

@ -28,11 +28,15 @@ pycamera_sources = files([
# Generate controls # Generate controls
gen_py_controls_input_files = files('../../libcamera/control_ids.yaml') gen_py_controls_input_files = []
gen_py_controls_template = files('py_controls_generated.cpp.in') gen_py_controls_template = files('py_controls_generated.cpp.in')
gen_py_controls = files('gen-py-controls.py') gen_py_controls = files('gen-py-controls.py')
foreach file : controls_files
gen_py_controls_input_files += files('../../libcamera/' + file)
endforeach
pycamera_sources += custom_target('py_gen_controls', pycamera_sources += custom_target('py_gen_controls',
input : gen_py_controls_input_files, input : gen_py_controls_input_files,
output : ['py_controls_generated.cpp'], output : ['py_controls_generated.cpp'],
@ -41,9 +45,13 @@ pycamera_sources += custom_target('py_gen_controls',
# Generate properties # Generate properties
gen_py_property_enums_input_files = files('../../libcamera/property_ids.yaml') gen_py_property_enums_input_files = []
gen_py_properties_template = files('py_properties_generated.cpp.in') gen_py_properties_template = files('py_properties_generated.cpp.in')
foreach file : properties_files
gen_py_property_enums_input_files += files('../../libcamera/' + file)
endforeach
pycamera_sources += custom_target('py_gen_properties', pycamera_sources += custom_target('py_gen_properties',
input : gen_py_property_enums_input_files, input : gen_py_property_enums_input_files,
output : ['py_properties_generated.cpp'], output : ['py_properties_generated.cpp'],

View file

@ -12,6 +12,7 @@ import operator
import string import string
import sys import sys
import yaml import yaml
import os
class ControlEnum(object): class ControlEnum(object):
@ -342,15 +343,18 @@ def main(argv):
help='Output file name. Defaults to standard output if not specified.') help='Output file name. Defaults to standard output if not specified.')
parser.add_argument('--template', '-t', dest='template', type=str, required=True, parser.add_argument('--template', '-t', dest='template', type=str, required=True,
help='Template file name.') help='Template file name.')
parser.add_argument('input', type=str, parser.add_argument('input', type=str, nargs='+',
help='Input file name.') help='Input file name.')
args = parser.parse_args(argv[1:]) args = parser.parse_args(argv[1:])
data = open(args.input, 'rb').read() controls = []
vendor = yaml.safe_load(data)['vendor'] for input in args.input:
controls = yaml.safe_load(data)['controls'] with open(input, 'rb') as f:
controls = [Control(*ctrl.popitem(), vendor) for ctrl in controls] data = f.read()
vendor = yaml.safe_load(data)['vendor']
ctrls = yaml.safe_load(data)['controls']
controls = controls + [Control(*ctrl.popitem(), vendor) for ctrl in ctrls]
if args.template.endswith('.cpp.in'): if args.template.endswith('.cpp.in'):
data = generate_cpp(controls) data = generate_cpp(controls)