[libcamera-devel,v3,5/7] libcamera: controls: Use vendor tags for draft controls and properties
diff mbox series

Message ID 20231124123713.22519-6-naush@raspberrypi.com
State Accepted
Headers show
Series
  • Vendor controls and properties
Related show

Commit Message

Naushir Patuck Nov. 24, 2023, 12:37 p.m. UTC
Label draft controls and properties through the "draft" vendor tag
and deprecate the existing "draft: true" mechanism. This uses the new
vendor tags mechanism to place draft controls in the same
libcamera::controls::draft namespace and provide a defined control id
range for these controls. This requires moving all draft controls from
control_ids.yaml to control_ids_draft.yaml.

One breaking change in this commit is that draft control ids also move
to the libcamera::controls::draft namespace from the existing
libcamera::controls namespace. This is desirable to avoid API breakages
when adding new libcamera controls. So, for example, the use of
controls::NOISE_REDUCTION_MODE will need to be replaced with
controls::draft::NOISE_REDUCTION_MODE.

Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
 include/libcamera/control_ids.h.in            |   6 -
 include/libcamera/meson.build                 |   2 +
 include/libcamera/property_ids.h.in           |   6 -
 src/ipa/rpi/common/ipa_base.cpp               |   2 +-
 src/ipa/rpi/vc4/vc4.cpp                       |   2 +-
 src/libcamera/control_ids.cpp.in              |  16 +-
 src/libcamera/control_ids_core.yaml           | 232 -----------------
 src/libcamera/control_ids_draft.yaml          | 240 ++++++++++++++++++
 src/libcamera/property_ids.cpp.in             |  16 +-
 src/libcamera/property_ids_core.yaml          |  33 ---
 src/libcamera/property_ids_draft.yaml         |  39 +++
 src/py/libcamera/gen-py-controls.py           |   5 +-
 src/py/libcamera/py_controls_generated.cpp.in |   5 -
 .../libcamera/py_properties_generated.cpp.in  |   1 -
 utils/gen-controls.py                         |  36 +--
 15 files changed, 295 insertions(+), 346 deletions(-)
 create mode 100644 src/libcamera/control_ids_draft.yaml
 create mode 100644 src/libcamera/property_ids_draft.yaml

Comments

Jacopo Mondi Nov. 27, 2023, 4:57 p.m. UTC | #1
Hi Naush

On Fri, Nov 24, 2023 at 12:37:11PM +0000, Naushir Patuck via libcamera-devel wrote:
> Label draft controls and properties through the "draft" vendor tag
> and deprecate the existing "draft: true" mechanism. This uses the new
> vendor tags mechanism to place draft controls in the same
> libcamera::controls::draft namespace and provide a defined control id
> range for these controls. This requires moving all draft controls from
> control_ids.yaml to control_ids_draft.yaml.
>
> One breaking change in this commit is that draft control ids also move
> to the libcamera::controls::draft namespace from the existing
> libcamera::controls namespace. This is desirable to avoid API breakages
> when adding new libcamera controls. So, for example, the use of
> controls::NOISE_REDUCTION_MODE will need to be replaced with
> controls::draft::NOISE_REDUCTION_MODE.
>
> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>

Thanks, I like this change!

Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>

> ---
>  include/libcamera/control_ids.h.in            |   6 -
>  include/libcamera/meson.build                 |   2 +
>  include/libcamera/property_ids.h.in           |   6 -
>  src/ipa/rpi/common/ipa_base.cpp               |   2 +-
>  src/ipa/rpi/vc4/vc4.cpp                       |   2 +-
>  src/libcamera/control_ids.cpp.in              |  16 +-
>  src/libcamera/control_ids_core.yaml           | 232 -----------------
>  src/libcamera/control_ids_draft.yaml          | 240 ++++++++++++++++++
>  src/libcamera/property_ids.cpp.in             |  16 +-
>  src/libcamera/property_ids_core.yaml          |  33 ---
>  src/libcamera/property_ids_draft.yaml         |  39 +++
>  src/py/libcamera/gen-py-controls.py           |   5 +-
>  src/py/libcamera/py_controls_generated.cpp.in |   5 -
>  .../libcamera/py_properties_generated.cpp.in  |   1 -
>  utils/gen-controls.py                         |  36 +--
>  15 files changed, 295 insertions(+), 346 deletions(-)
>  create mode 100644 src/libcamera/control_ids_draft.yaml
>  create mode 100644 src/libcamera/property_ids_draft.yaml
>
> diff --git a/include/libcamera/control_ids.h.in b/include/libcamera/control_ids.h.in
> index c97b09a82450..d53b1cf7beb2 100644
> --- a/include/libcamera/control_ids.h.in
> +++ b/include/libcamera/control_ids.h.in
> @@ -26,12 +26,6 @@ ${controls}
>
>  extern const ControlIdMap controls;
>
> -namespace draft {
> -
> -${draft_controls}
> -
> -} /* namespace draft */
> -
>  ${vendor_controls}
>
>  } /* namespace controls */
> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> index 79187d3fdfc9..1504f741ae2f 100644
> --- a/include/libcamera/meson.build
> +++ b/include/libcamera/meson.build
> @@ -34,10 +34,12 @@ libcamera_headers_install_dir = get_option('includedir') / libcamera_include_dir
>
>  controls_map = {
>      'controls': {
> +        'draft': 'control_ids_draft.yaml',
>          'core': 'control_ids_core.yaml',
>      },
>
>      'properties': {
> +        'draft': 'property_ids_draft.yaml',
>          'core': 'property_ids_core.yaml',
>      }
>  }
> diff --git a/include/libcamera/property_ids.h.in b/include/libcamera/property_ids.h.in
> index 47c5d6bf2e28..43372c718fc9 100644
> --- a/include/libcamera/property_ids.h.in
> +++ b/include/libcamera/property_ids.h.in
> @@ -23,12 +23,6 @@ ${ids}
>
>  ${controls}
>
> -namespace draft {
> -
> -${draft_controls}
> -
> -} /* namespace draft */
> -
>  extern const ControlIdMap properties;
>
>  ${vendor_controls}
> diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp
> index a1fec3aa3dd1..6ac9d5de2f88 100644
> --- a/src/ipa/rpi/common/ipa_base.cpp
> +++ b/src/ipa/rpi/common/ipa_base.cpp
> @@ -1024,7 +1024,7 @@ void IpaBase::applyControls(const ControlList &controls)
>  			break;
>  		}
>
> -		case controls::NOISE_REDUCTION_MODE:
> +		case controls::draft::NOISE_REDUCTION_MODE:
>  			/* Handled below in handleControls() */
>  			libcameraMetadata_.set(controls::draft::NoiseReductionMode,
>  					       ctrl.second.get<int32_t>());
> diff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp
> index c4baf04fb1e7..c165a5b8b0b6 100644
> --- a/src/ipa/rpi/vc4/vc4.cpp
> +++ b/src/ipa/rpi/vc4/vc4.cpp
> @@ -260,7 +260,7 @@ void IpaVc4::handleControls(const ControlList &controls)
>
>  	for (auto const &ctrl : controls) {
>  		switch (ctrl.first) {
> -		case controls::NOISE_REDUCTION_MODE: {
> +		case controls::draft::NOISE_REDUCTION_MODE: {
>  			RPiController::DenoiseAlgorithm *sdn = dynamic_cast<RPiController::DenoiseAlgorithm *>(
>  				controller_.getAlgorithm("SDN"));
>  			/* Some platforms may have a combined "denoise" algorithm instead. */
> diff --git a/src/libcamera/control_ids.cpp.in b/src/libcamera/control_ids.cpp.in
> index be86548cf73f..d283c1c1f401 100644
> --- a/src/libcamera/control_ids.cpp.in
> +++ b/src/libcamera/control_ids.cpp.in
> @@ -24,15 +24,6 @@ namespace controls {
>
>  ${controls_doc}
>
> -/**
> - * \brief Namespace for libcamera draft controls
> - */
> -namespace draft {
> -
> -${draft_controls_doc}
> -
> -} /* namespace draft */
> -
>  ${vendor_controls_doc}
>
>  #ifndef __DOXYGEN__
> @@ -42,13 +33,8 @@ ${vendor_controls_doc}
>   */
>  ${controls_def}
>
> -namespace draft {
> -
> -${draft_controls_def}
> -
> -} /* namespace draft */
> -
>  ${vendor_controls_def}
> +
>  #endif
>
>  /**
> diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml
> index ff74ce1deedb..76fb9347d8e3 100644
> --- a/src/libcamera/control_ids_core.yaml
> +++ b/src/libcamera/control_ids_core.yaml
> @@ -865,236 +865,4 @@ controls:
>            description: |
>              This is a long exposure image.
>
> -  # ----------------------------------------------------------------------------
> -  # Draft controls section
> -
> -  - AePrecaptureTrigger:
> -      type: int32_t
> -      draft: true
> -      description: |
> -        Control for AE metering trigger. Currently identical to
> -        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> -
> -        Whether the camera device will trigger a precapture metering sequence
> -        when it processes this request.
> -      enum:
> -        - name: AePrecaptureTriggerIdle
> -          value: 0
> -          description: The trigger is idle.
> -        - name: AePrecaptureTriggerStart
> -          value: 1
> -          description: The pre-capture AE metering is started by the camera.
> -        - name: AePrecaptureTriggerCancel
> -          value: 2
> -          description: |
> -            The camera will cancel any active or completed metering sequence.
> -            The AE algorithm is reset to its initial state.
> -
> -  - NoiseReductionMode:
> -      type: int32_t
> -      draft: true
> -      description: |
> -       Control to select the noise reduction algorithm mode. Currently
> -       identical to ANDROID_NOISE_REDUCTION_MODE.
> -
> -        Mode of operation for the noise reduction algorithm.
> -      enum:
> -        - name: NoiseReductionModeOff
> -          value: 0
> -          description: No noise reduction is applied
> -        - name: NoiseReductionModeFast
> -          value: 1
> -          description: |
> -            Noise reduction is applied without reducing the frame rate.
> -        - name: NoiseReductionModeHighQuality
> -          value: 2
> -          description: |
> -            High quality noise reduction at the expense of frame rate.
> -        - name: NoiseReductionModeMinimal
> -          value: 3
> -          description: |
> -            Minimal noise reduction is applied without reducing the frame rate.
> -        - name: NoiseReductionModeZSL
> -          value: 4
> -          description: |
> -            Noise reduction is applied at different levels to different streams.
> -
> -  - ColorCorrectionAberrationMode:
> -      type: int32_t
> -      draft: true
> -      description: |
> -       Control to select the color correction aberration mode. Currently
> -       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> -
> -        Mode of operation for the chromatic aberration correction algorithm.
> -      enum:
> -        - name: ColorCorrectionAberrationOff
> -          value: 0
> -          description: No aberration correction is applied.
> -        - name: ColorCorrectionAberrationFast
> -          value: 1
> -          description: Aberration correction will not slow down the frame rate.
> -        - name: ColorCorrectionAberrationHighQuality
> -          value: 2
> -          description: |
> -            High quality aberration correction which might reduce the frame
> -            rate.
> -
> -  - AeState:
> -      type: int32_t
> -      draft: true
> -      description: |
> -       Control to report the current AE algorithm state. Currently identical to
> -       ANDROID_CONTROL_AE_STATE.
> -
> -        Current state of the AE algorithm.
> -      enum:
> -        - name: AeStateInactive
> -          value: 0
> -          description: The AE algorithm is inactive.
> -        - name: AeStateSearching
> -          value: 1
> -          description: The AE algorithm has not converged yet.
> -        - name: AeStateConverged
> -          value: 2
> -          description: The AE algorithm has converged.
> -        - name: AeStateLocked
> -          value: 3
> -          description: The AE algorithm is locked.
> -        - name: AeStateFlashRequired
> -          value: 4
> -          description: The AE algorithm would need a flash for good results
> -        - name: AeStatePrecapture
> -          value: 5
> -          description: |
> -            The AE algorithm has started a pre-capture metering session.
> -            \sa AePrecaptureTrigger
> -
> -  - AwbState:
> -      type: int32_t
> -      draft: true
> -      description: |
> -       Control to report the current AWB algorithm state. Currently identical
> -       to ANDROID_CONTROL_AWB_STATE.
> -
> -        Current state of the AWB algorithm.
> -      enum:
> -        - name: AwbStateInactive
> -          value: 0
> -          description: The AWB algorithm is inactive.
> -        - name: AwbStateSearching
> -          value: 1
> -          description: The AWB algorithm has not converged yet.
> -        - name: AwbConverged
> -          value: 2
> -          description: The AWB algorithm has converged.
> -        - name: AwbLocked
> -          value: 3
> -          description: The AWB algorithm is locked.
> -
> -  - SensorRollingShutterSkew:
> -      type: int64_t
> -      draft: true
> -      description: |
> -       Control to report the time between the start of exposure of the first
> -       row and the start of exposure of the last row. Currently identical to
> -       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> -
> -  - LensShadingMapMode:
> -      type: int32_t
> -      draft: true
> -      description: |
> -       Control to report if the lens shading map is available. Currently
> -       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> -      enum:
> -        - name: LensShadingMapModeOff
> -          value: 0
> -          description: No lens shading map mode is available.
> -        - name: LensShadingMapModeOn
> -          value: 1
> -          description: The lens shading map mode is available.
> -
> -  - PipelineDepth:
> -      type: int32_t
> -      draft: true
> -      description: |
> -        Specifies the number of pipeline stages the frame went through from when
> -        it was exposed to when the final completed result was available to the
> -        framework. Always less than or equal to PipelineMaxDepth. Currently
> -        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> -
> -        The typical value for this control is 3 as a frame is first exposed,
> -        captured and then processed in a single pass through the ISP. Any
> -        additional processing step performed after the ISP pass (in example face
> -        detection, additional format conversions etc) count as an additional
> -        pipeline stage.
> -
> -  - MaxLatency:
> -      type: int32_t
> -      draft: true
> -      description: |
> -        The maximum number of frames that can occur after a request (different
> -        than the previous) has been submitted, and before the result's state
> -        becomes synchronized. A value of -1 indicates unknown latency, and 0
> -        indicates per-frame control. Currently identical to
> -        ANDROID_SYNC_MAX_LATENCY.
> -
> -  - TestPatternMode:
> -      type: int32_t
> -      draft: true
> -      description: |
> -        Control to select the test pattern mode. Currently identical to
> -        ANDROID_SENSOR_TEST_PATTERN_MODE.
> -      enum:
> -        - name: TestPatternModeOff
> -          value: 0
> -          description: |
> -            No test pattern mode is used. The camera device returns frames from
> -            the image sensor.
> -        - name: TestPatternModeSolidColor
> -          value: 1
> -          description: |
> -            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> -            color channel provided in test pattern data.
> -            \todo Add control for test pattern data.
> -        - name: TestPatternModeColorBars
> -          value: 2
> -          description: |
> -            All pixel data is replaced with an 8-bar color pattern. The vertical
> -            bars (left-to-right) are as follows; white, yellow, cyan, green,
> -            magenta, red, blue and black. Each bar should take up 1/8 of the
> -            sensor pixel array width. When this is not possible, the bar size
> -            should be rounded down to the nearest integer and the pattern can
> -            repeat on the right side. Each bar's height must always take up the
> -            full sensor pixel array height.
> -        - name: TestPatternModeColorBarsFadeToGray
> -          value: 3
> -          description: |
> -            The test pattern is similar to TestPatternModeColorBars,
> -            except that each bar should start at its specified color at the top
> -            and fade to gray at the bottom. Furthermore each bar is further
> -            subdevided into a left and right half. The left half should have a
> -            smooth gradient, and the right half should have a quantized
> -            gradient. In particular, the right half's should consist of blocks
> -            of the same color for 1/16th active sensor pixel array width. The
> -            least significant bits in the quantized gradient should be copied
> -            from the most significant bits of the smooth gradient. The height of
> -            each bar should always be a multiple of 128. When this is not the
> -            case, the pattern should repeat at the bottom of the image.
> -        - name: TestPatternModePn9
> -          value: 4
> -          description: |
> -            All pixel data is replaced by a pseudo-random sequence generated
> -            from a PN9 512-bit sequence (typically implemented in hardware with
> -            a linear feedback shift register). The generator should be reset at
> -            the beginning of each frame, and thus each subsequent raw frame with
> -            this test pattern should be exactly the same as the last.
> -        - name: TestPatternModeCustom1
> -          value: 256
> -          description: |
> -            The first custom test pattern. All custom patterns that are
> -            available only on this camera device are at least this numeric
> -            value. All of the custom test patterns will be static (that is the
> -            raw image must not vary from frame to frame).
> -
>  ...
> diff --git a/src/libcamera/control_ids_draft.yaml b/src/libcamera/control_ids_draft.yaml
> new file mode 100644
> index 000000000000..e4f53ea51d7a
> --- /dev/null
> +++ b/src/libcamera/control_ids_draft.yaml
> @@ -0,0 +1,240 @@
> +# SPDX-License-Identifier: LGPL-2.1-or-later
> +#
> +# Copyright (C) 2019, Google Inc.
> +#
> +%YAML 1.1
> +---
> +# Unless otherwise stated, all controls are bi-directional, i.e. they can be
> +# set through Request::controls() and returned out through Request::metadata().
> +vendor: draft
> +controls:
> +  - AePrecaptureTrigger:
> +      type: int32_t
> +      draft: true
> +      description: |
> +        Control for AE metering trigger. Currently identical to
> +        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> +
> +        Whether the camera device will trigger a precapture metering sequence
> +        when it processes this request.
> +      enum:
> +        - name: AePrecaptureTriggerIdle
> +          value: 0
> +          description: The trigger is idle.
> +        - name: AePrecaptureTriggerStart
> +          value: 1
> +          description: The pre-capture AE metering is started by the camera.
> +        - name: AePrecaptureTriggerCancel
> +          value: 2
> +          description: |
> +            The camera will cancel any active or completed metering sequence.
> +            The AE algorithm is reset to its initial state.
> +
> +  - NoiseReductionMode:
> +      type: int32_t
> +      draft: true
> +      description: |
> +       Control to select the noise reduction algorithm mode. Currently
> +       identical to ANDROID_NOISE_REDUCTION_MODE.
> +
> +        Mode of operation for the noise reduction algorithm.
> +      enum:
> +        - name: NoiseReductionModeOff
> +          value: 0
> +          description: No noise reduction is applied
> +        - name: NoiseReductionModeFast
> +          value: 1
> +          description: |
> +            Noise reduction is applied without reducing the frame rate.
> +        - name: NoiseReductionModeHighQuality
> +          value: 2
> +          description: |
> +            High quality noise reduction at the expense of frame rate.
> +        - name: NoiseReductionModeMinimal
> +          value: 3
> +          description: |
> +            Minimal noise reduction is applied without reducing the frame rate.
> +        - name: NoiseReductionModeZSL
> +          value: 4
> +          description: |
> +            Noise reduction is applied at different levels to different streams.
> +
> +  - ColorCorrectionAberrationMode:
> +      type: int32_t
> +      draft: true
> +      description: |
> +       Control to select the color correction aberration mode. Currently
> +       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> +
> +        Mode of operation for the chromatic aberration correction algorithm.
> +      enum:
> +        - name: ColorCorrectionAberrationOff
> +          value: 0
> +          description: No aberration correction is applied.
> +        - name: ColorCorrectionAberrationFast
> +          value: 1
> +          description: Aberration correction will not slow down the frame rate.
> +        - name: ColorCorrectionAberrationHighQuality
> +          value: 2
> +          description: |
> +            High quality aberration correction which might reduce the frame
> +            rate.
> +
> +  - AeState:
> +      type: int32_t
> +      draft: true
> +      description: |
> +       Control to report the current AE algorithm state. Currently identical to
> +       ANDROID_CONTROL_AE_STATE.
> +
> +        Current state of the AE algorithm.
> +      enum:
> +        - name: AeStateInactive
> +          value: 0
> +          description: The AE algorithm is inactive.
> +        - name: AeStateSearching
> +          value: 1
> +          description: The AE algorithm has not converged yet.
> +        - name: AeStateConverged
> +          value: 2
> +          description: The AE algorithm has converged.
> +        - name: AeStateLocked
> +          value: 3
> +          description: The AE algorithm is locked.
> +        - name: AeStateFlashRequired
> +          value: 4
> +          description: The AE algorithm would need a flash for good results
> +        - name: AeStatePrecapture
> +          value: 5
> +          description: |
> +            The AE algorithm has started a pre-capture metering session.
> +            \sa AePrecaptureTrigger
> +
> +  - AwbState:
> +      type: int32_t
> +      draft: true
> +      description: |
> +       Control to report the current AWB algorithm state. Currently identical
> +       to ANDROID_CONTROL_AWB_STATE.
> +
> +        Current state of the AWB algorithm.
> +      enum:
> +        - name: AwbStateInactive
> +          value: 0
> +          description: The AWB algorithm is inactive.
> +        - name: AwbStateSearching
> +          value: 1
> +          description: The AWB algorithm has not converged yet.
> +        - name: AwbConverged
> +          value: 2
> +          description: The AWB algorithm has converged.
> +        - name: AwbLocked
> +          value: 3
> +          description: The AWB algorithm is locked.
> +
> +  - SensorRollingShutterSkew:
> +      type: int64_t
> +      draft: true
> +      description: |
> +       Control to report the time between the start of exposure of the first
> +       row and the start of exposure of the last row. Currently identical to
> +       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> +
> +  - LensShadingMapMode:
> +      type: int32_t
> +      draft: true
> +      description: |
> +       Control to report if the lens shading map is available. Currently
> +       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> +      enum:
> +        - name: LensShadingMapModeOff
> +          value: 0
> +          description: No lens shading map mode is available.
> +        - name: LensShadingMapModeOn
> +          value: 1
> +          description: The lens shading map mode is available.
> +
> +  - PipelineDepth:
> +      type: int32_t
> +      draft: true
> +      description: |
> +        Specifies the number of pipeline stages the frame went through from when
> +        it was exposed to when the final completed result was available to the
> +        framework. Always less than or equal to PipelineMaxDepth. Currently
> +        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> +
> +        The typical value for this control is 3 as a frame is first exposed,
> +        captured and then processed in a single pass through the ISP. Any
> +        additional processing step performed after the ISP pass (in example face
> +        detection, additional format conversions etc) count as an additional
> +        pipeline stage.
> +
> +  - MaxLatency:
> +      type: int32_t
> +      draft: true
> +      description: |
> +        The maximum number of frames that can occur after a request (different
> +        than the previous) has been submitted, and before the result's state
> +        becomes synchronized. A value of -1 indicates unknown latency, and 0
> +        indicates per-frame control. Currently identical to
> +        ANDROID_SYNC_MAX_LATENCY.
> +
> +  - TestPatternMode:
> +      type: int32_t
> +      draft: true
> +      description: |
> +        Control to select the test pattern mode. Currently identical to
> +        ANDROID_SENSOR_TEST_PATTERN_MODE.
> +      enum:
> +        - name: TestPatternModeOff
> +          value: 0
> +          description: |
> +            No test pattern mode is used. The camera device returns frames from
> +            the image sensor.
> +        - name: TestPatternModeSolidColor
> +          value: 1
> +          description: |
> +            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> +            color channel provided in test pattern data.
> +            \todo Add control for test pattern data.
> +        - name: TestPatternModeColorBars
> +          value: 2
> +          description: |
> +            All pixel data is replaced with an 8-bar color pattern. The vertical
> +            bars (left-to-right) are as follows; white, yellow, cyan, green,
> +            magenta, red, blue and black. Each bar should take up 1/8 of the
> +            sensor pixel array width. When this is not possible, the bar size
> +            should be rounded down to the nearest integer and the pattern can
> +            repeat on the right side. Each bar's height must always take up the
> +            full sensor pixel array height.
> +        - name: TestPatternModeColorBarsFadeToGray
> +          value: 3
> +          description: |
> +            The test pattern is similar to TestPatternModeColorBars,
> +            except that each bar should start at its specified color at the top
> +            and fade to gray at the bottom. Furthermore each bar is further
> +            subdevided into a left and right half. The left half should have a
> +            smooth gradient, and the right half should have a quantized
> +            gradient. In particular, the right half's should consist of blocks
> +            of the same color for 1/16th active sensor pixel array width. The
> +            least significant bits in the quantized gradient should be copied
> +            from the most significant bits of the smooth gradient. The height of
> +            each bar should always be a multiple of 128. When this is not the
> +            case, the pattern should repeat at the bottom of the image.
> +        - name: TestPatternModePn9
> +          value: 4
> +          description: |
> +            All pixel data is replaced by a pseudo-random sequence generated
> +            from a PN9 512-bit sequence (typically implemented in hardware with
> +            a linear feedback shift register). The generator should be reset at
> +            the beginning of each frame, and thus each subsequent raw frame with
> +            this test pattern should be exactly the same as the last.
> +        - name: TestPatternModeCustom1
> +          value: 256
> +          description: |
> +            The first custom test pattern. All custom patterns that are
> +            available only on this camera device are at least this numeric
> +            value. All of the custom test patterns will be static (that is the
> +            raw image must not vary from frame to frame).
> +
> +...
> diff --git a/src/libcamera/property_ids.cpp.in b/src/libcamera/property_ids.cpp.in
> index 0771ac5c091f..8b274c38c74b 100644
> --- a/src/libcamera/property_ids.cpp.in
> +++ b/src/libcamera/property_ids.cpp.in
> @@ -23,15 +23,6 @@ namespace properties {
>
>  ${controls_doc}
>
> -/**
> - * \brief Namespace for libcamera draft properties
> - */
> -namespace draft {
> -
> -${draft_controls_doc}
> -
> -} /* namespace draft */
> -
>  ${vendor_controls_doc}
>
>  #ifndef __DOXYGEN__
> @@ -41,13 +32,8 @@ ${vendor_controls_doc}
>   */
>  ${controls_def}
>
> -namespace draft {
> -
> -${draft_controls_def}
> -
> -} /* namespace draft */
> -
>  ${vendor_controls_def}
> +
>  #endif
>
>  /**
> diff --git a/src/libcamera/property_ids_core.yaml b/src/libcamera/property_ids_core.yaml
> index 45f3609b4236..834454a4e087 100644
> --- a/src/libcamera/property_ids_core.yaml
> +++ b/src/libcamera/property_ids_core.yaml
> @@ -701,37 +701,4 @@ controls:
>
>          Different cameras may report identical devices.
>
> -  # ----------------------------------------------------------------------------
> -  # Draft properties section
> -
> -  - ColorFilterArrangement:
> -      type: int32_t
> -      draft: true
> -      description: |
> -        The arrangement of color filters on sensor; represents the colors in the
> -        top-left 2x2 section of the sensor, in reading order. Currently
> -        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> -      enum:
> -        - name: RGGB
> -          value: 0
> -          description: RGGB Bayer pattern
> -        - name: GRBG
> -          value: 1
> -          description: GRBG Bayer pattern
> -        - name: GBRG
> -          value: 2
> -          description: GBRG Bayer pattern
> -        - name: BGGR
> -          value: 3
> -          description: BGGR Bayer pattern
> -        - name: RGB
> -          value: 4
> -          description: |
> -            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> -            instead of just 1 16-bit value per pixel.
> -        - name: MONO
> -          value: 5
> -          description: |
> -            Sensor is not Bayer; output consists of a single colour channel.
> -
>  ...
> diff --git a/src/libcamera/property_ids_draft.yaml b/src/libcamera/property_ids_draft.yaml
> new file mode 100644
> index 000000000000..62f0e242d0c6
> --- /dev/null
> +++ b/src/libcamera/property_ids_draft.yaml
> @@ -0,0 +1,39 @@
> +# SPDX-License-Identifier: LGPL-2.1-or-later
> +#
> +# Copyright (C) 2019, Google Inc.
> +#
> +%YAML 1.1
> +---
> +vendor: draft
> +controls:
> +  - ColorFilterArrangement:
> +      type: int32_t
> +      vendor: draft
> +      description: |
> +        The arrangement of color filters on sensor; represents the colors in the
> +        top-left 2x2 section of the sensor, in reading order. Currently
> +        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> +      enum:
> +        - name: RGGB
> +          value: 0
> +          description: RGGB Bayer pattern
> +        - name: GRBG
> +          value: 1
> +          description: GRBG Bayer pattern
> +        - name: GBRG
> +          value: 2
> +          description: GBRG Bayer pattern
> +        - name: BGGR
> +          value: 3
> +          description: BGGR Bayer pattern
> +        - name: RGB
> +          value: 4
> +          description: |
> +            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> +            instead of just 1 16-bit value per pixel.
> +        - name: MONO
> +          value: 5
> +          description: |
> +            Sensor is not Bayer; output consists of a single colour channel.
> +
> +...
> diff --git a/src/py/libcamera/gen-py-controls.py b/src/py/libcamera/gen-py-controls.py
> index 8ae8d5126e39..55e0b4e8e3d6 100755
> --- a/src/py/libcamera/gen-py-controls.py
> +++ b/src/py/libcamera/gen-py-controls.py
> @@ -36,10 +36,7 @@ def generate_py(controls, mode):
>                  vendor_defs.append('\tauto {} = py::class_<Py{}Controls>(controls, \"{}\");'.format(vendor, vendor, vendor))
>                  vendors.append(vendor)
>
> -            if ctrl.get('draft'):
> -                ns = 'libcamera::{}::draft::'.format(mode)
> -                container = 'draft'
> -            elif vendor != 'libcamera':
> +            if vendor != 'libcamera':
>                  ns = 'libcamera::{}::{}::'.format(mode, vendor)
>                  container = vendor
>              else:
> diff --git a/src/py/libcamera/py_controls_generated.cpp.in b/src/py/libcamera/py_controls_generated.cpp.in
> index ec4b55ef2011..8d282ce51856 100644
> --- a/src/py/libcamera/py_controls_generated.cpp.in
> +++ b/src/py/libcamera/py_controls_generated.cpp.in
> @@ -17,16 +17,11 @@ class PyControls
>  {
>  };
>
> -class PyDraftControls
> -{
> -};
> -
>  ${vendors_class_def}
>
>  void init_py_controls_generated(py::module& m)
>  {
>  	auto controls = py::class_<PyControls>(m, "controls");
> -	auto draft = py::class_<PyDraftControls>(controls, "draft");
>  ${vendors_defs}
>
>  ${controls}
> diff --git a/src/py/libcamera/py_properties_generated.cpp.in b/src/py/libcamera/py_properties_generated.cpp.in
> index f7b5ec8c635d..ae61c5440d31 100644
> --- a/src/py/libcamera/py_properties_generated.cpp.in
> +++ b/src/py/libcamera/py_properties_generated.cpp.in
> @@ -26,7 +26,6 @@ ${vendors_class_def}
>  void init_py_properties_generated(py::module& m)
>  {
>  	auto controls = py::class_<PyProperties>(m, "properties");
> -	auto draft = py::class_<PyDraftProperties>(controls, "draft");
>  ${vendors_defs}
>
>  ${controls}
> diff --git a/utils/gen-controls.py b/utils/gen-controls.py
> index 04c63098b19b..45da571e83e0 100755
> --- a/utils/gen-controls.py
> +++ b/utils/gen-controls.py
> @@ -86,11 +86,6 @@ class Control(object):
>          """Is the control an enumeration"""
>          return self.__enum_values is not None
>
> -    @property
> -    def is_draft(self):
> -        """Is the control a draft control"""
> -        return self.__data.get('draft') is not None
> -
>      @property
>      def vendor(self):
>          """The vendor string, or None"""
> @@ -101,12 +96,6 @@ class Control(object):
>          """The control name (CamelCase)"""
>          return self.__name
>
> -    @property
> -    def q_name(self):
> -        """The control name, qualified with a namespace"""
> -        ns = 'draft::' if self.is_draft else ''
> -        return ns + self.__name
> -
>      @property
>      def type(self):
>          typ = self.__data.get('type')
> @@ -159,7 +148,7 @@ ${description}
>      for ctrl in controls:
>          id_name = snake_case(ctrl.name).upper()
>
> -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> +        vendor = ctrl.vendor
>          if vendor not in ctrls_doc:
>              ctrls_doc[vendor] = []
>              ctrls_def[vendor] = []
> @@ -208,7 +197,8 @@ ${description}
>          target_doc.append(doc_template.substitute(info))
>          target_def.append(def_template.substitute(info))
>
> -        ctrls_map.append('\t{ ' + id_name + ', &' + ctrl.q_name + ' },')
> +        vendor_ns = vendor + '::' if vendor != "libcamera" else ''
> +        ctrls_map.append('\t{ ' + vendor_ns + id_name + ', &' + vendor_ns + ctrl.name + ' },')
>
>      vendor_ctrl_doc_sub = []
>      vendor_ctrl_template = string.Template('''
> @@ -218,18 +208,16 @@ ${vendor_controls_str}
>
>  } /* namespace ${vendor} */''')
>
> -    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera', 'draft']]:
> +    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera']]:
>          vendor_ctrl_doc_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n\n'.join(ctrls_doc[vendor])}))
>
>      vendor_ctrl_def_sub = []
> -    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera', 'draft']]:
> +    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera']]:
>          vendor_ctrl_def_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n'.join(ctrls_def[vendor])}))
>
>      return {
>          'controls_doc': '\n\n'.join(ctrls_doc['libcamera']),
>          'controls_def': '\n'.join(ctrls_def['libcamera']),
> -        'draft_controls_doc': '\n\n'.join(ctrls_doc['draft']),
> -        'draft_controls_def': '\n\n'.join(ctrls_def['draft']),
>          'controls_map': '\n'.join(ctrls_map),
>          'vendor_controls_doc': '\n'.join(vendor_ctrl_doc_sub),
>          'vendor_controls_def': '\n'.join(vendor_ctrl_def_sub),
> @@ -249,7 +237,7 @@ def generate_h(controls, mode, ranges):
>      for ctrl in controls:
>          id_name = snake_case(ctrl.name).upper()
>
> -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> +        vendor = ctrl.vendor
>          if vendor not in ctrls:
>              if vendor not in ranges.keys():
>                  raise RuntimeError(f'Control id range is not defined for vendor {vendor}')
> @@ -257,8 +245,7 @@ def generate_h(controls, mode, ranges):
>              ids[vendor] = []
>              ctrls[vendor] = []
>
> -        # Core and draft controls use the same ID value
> -        target_ids = ids['libcamera'] if vendor in ['libcamera', 'draft'] else ids[vendor]
> +        target_ids = ids[vendor]
>          target_ids.append('\t' + id_name + ' = ' + str(id_value[vendor]) + ',')
>
>          info = {
> @@ -266,11 +253,7 @@ def generate_h(controls, mode, ranges):
>              'type': ctrl.type,
>          }
>
> -        target_ctrls = ctrls['libcamera']
> -        if ctrl.is_draft:
> -            target_ctrls = ctrls['draft']
> -        elif vendor != 'libcamera':
> -            target_ctrls = ctrls[vendor]
> +        target_ctrls = ctrls[vendor]
>
>          if ctrl.is_enum:
>              target_ctrls.append(enum_template_start.substitute(info))
> @@ -309,7 +292,7 @@ ${vendor_controls}
>  ''')
>
>      vendor_sub = []
> -    for vendor in [v for v in ctrls.keys() if v not in ['libcamera', 'draft']]:
> +    for vendor in [v for v in ctrls.keys() if v != 'libcamera']:
>          vendor_sub.append(vendor_template.substitute({'mode': mode.upper(),
>                                                        'vendor': vendor,
>                                                        'vendor_def': vendor.upper(),
> @@ -319,7 +302,6 @@ ${vendor_controls}
>      return {
>          'ids': '\n'.join(ids['libcamera']),
>          'controls': '\n'.join(ctrls['libcamera']),
> -        'draft_controls': '\n'.join(ctrls['draft']),
>          'vendor_controls': '\n'.join(vendor_sub)
>      }
>
> --
> 2.34.1
>
Kieran Bingham Nov. 28, 2023, 10:01 a.m. UTC | #2
Quoting Jacopo Mondi via libcamera-devel (2023-11-27 16:57:06)
> Hi Naush
> 
> On Fri, Nov 24, 2023 at 12:37:11PM +0000, Naushir Patuck via libcamera-devel wrote:
> > Label draft controls and properties through the "draft" vendor tag
> > and deprecate the existing "draft: true" mechanism. This uses the new
> > vendor tags mechanism to place draft controls in the same
> > libcamera::controls::draft namespace and provide a defined control id
> > range for these controls. This requires moving all draft controls from
> > control_ids.yaml to control_ids_draft.yaml.
> >
> > One breaking change in this commit is that draft control ids also move
> > to the libcamera::controls::draft namespace from the existing
> > libcamera::controls namespace. This is desirable to avoid API breakages
> > when adding new libcamera controls. So, for example, the use of
> > controls::NOISE_REDUCTION_MODE will need to be replaced with
> > controls::draft::NOISE_REDUCTION_MODE.
> >
> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> 
> Thanks, I like this change!
> 
> Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> 
> > ---
> >  include/libcamera/control_ids.h.in            |   6 -
> >  include/libcamera/meson.build                 |   2 +
> >  include/libcamera/property_ids.h.in           |   6 -
> >  src/ipa/rpi/common/ipa_base.cpp               |   2 +-
> >  src/ipa/rpi/vc4/vc4.cpp                       |   2 +-
> >  src/libcamera/control_ids.cpp.in              |  16 +-
> >  src/libcamera/control_ids_core.yaml           | 232 -----------------
> >  src/libcamera/control_ids_draft.yaml          | 240 ++++++++++++++++++
> >  src/libcamera/property_ids.cpp.in             |  16 +-
> >  src/libcamera/property_ids_core.yaml          |  33 ---
> >  src/libcamera/property_ids_draft.yaml         |  39 +++
> >  src/py/libcamera/gen-py-controls.py           |   5 +-
> >  src/py/libcamera/py_controls_generated.cpp.in |   5 -
> >  .../libcamera/py_properties_generated.cpp.in  |   1 -
> >  utils/gen-controls.py                         |  36 +--
> >  15 files changed, 295 insertions(+), 346 deletions(-)
> >  create mode 100644 src/libcamera/control_ids_draft.yaml
> >  create mode 100644 src/libcamera/property_ids_draft.yaml
> >
> > diff --git a/include/libcamera/control_ids.h.in b/include/libcamera/control_ids.h.in
> > index c97b09a82450..d53b1cf7beb2 100644
> > --- a/include/libcamera/control_ids.h.in
> > +++ b/include/libcamera/control_ids.h.in
> > @@ -26,12 +26,6 @@ ${controls}
> >
> >  extern const ControlIdMap controls;
> >
> > -namespace draft {
> > -
> > -${draft_controls}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls}
> >
> >  } /* namespace controls */
> > diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> > index 79187d3fdfc9..1504f741ae2f 100644
> > --- a/include/libcamera/meson.build
> > +++ b/include/libcamera/meson.build
> > @@ -34,10 +34,12 @@ libcamera_headers_install_dir = get_option('includedir') / libcamera_include_dir
> >
> >  controls_map = {
> >      'controls': {
> > +        'draft': 'control_ids_draft.yaml',
> >          'core': 'control_ids_core.yaml',
> >      },
> >
> >      'properties': {
> > +        'draft': 'property_ids_draft.yaml',
> >          'core': 'property_ids_core.yaml',
> >      }
> >  }
> > diff --git a/include/libcamera/property_ids.h.in b/include/libcamera/property_ids.h.in
> > index 47c5d6bf2e28..43372c718fc9 100644
> > --- a/include/libcamera/property_ids.h.in
> > +++ b/include/libcamera/property_ids.h.in
> > @@ -23,12 +23,6 @@ ${ids}
> >
> >  ${controls}
> >
> > -namespace draft {
> > -
> > -${draft_controls}
> > -
> > -} /* namespace draft */
> > -
> >  extern const ControlIdMap properties;
> >
> >  ${vendor_controls}
> > diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp
> > index a1fec3aa3dd1..6ac9d5de2f88 100644
> > --- a/src/ipa/rpi/common/ipa_base.cpp
> > +++ b/src/ipa/rpi/common/ipa_base.cpp
> > @@ -1024,7 +1024,7 @@ void IpaBase::applyControls(const ControlList &controls)
> >                       break;
> >               }
> >
> > -             case controls::NOISE_REDUCTION_MODE:
> > +             case controls::draft::NOISE_REDUCTION_MODE:
> >                       /* Handled below in handleControls() */
> >                       libcameraMetadata_.set(controls::draft::NoiseReductionMode,
> >                                              ctrl.second.get<int32_t>());
> > diff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp
> > index c4baf04fb1e7..c165a5b8b0b6 100644
> > --- a/src/ipa/rpi/vc4/vc4.cpp
> > +++ b/src/ipa/rpi/vc4/vc4.cpp
> > @@ -260,7 +260,7 @@ void IpaVc4::handleControls(const ControlList &controls)
> >
> >       for (auto const &ctrl : controls) {
> >               switch (ctrl.first) {
> > -             case controls::NOISE_REDUCTION_MODE: {
> > +             case controls::draft::NOISE_REDUCTION_MODE: {
> >                       RPiController::DenoiseAlgorithm *sdn = dynamic_cast<RPiController::DenoiseAlgorithm *>(
> >                               controller_.getAlgorithm("SDN"));
> >                       /* Some platforms may have a combined "denoise" algorithm instead. */
> > diff --git a/src/libcamera/control_ids.cpp.in b/src/libcamera/control_ids.cpp.in
> > index be86548cf73f..d283c1c1f401 100644
> > --- a/src/libcamera/control_ids.cpp.in
> > +++ b/src/libcamera/control_ids.cpp.in
> > @@ -24,15 +24,6 @@ namespace controls {
> >
> >  ${controls_doc}
> >
> > -/**
> > - * \brief Namespace for libcamera draft controls
> > - */
> > -namespace draft {
> > -
> > -${draft_controls_doc}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls_doc}
> >
> >  #ifndef __DOXYGEN__
> > @@ -42,13 +33,8 @@ ${vendor_controls_doc}
> >   */
> >  ${controls_def}
> >
> > -namespace draft {
> > -
> > -${draft_controls_def}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls_def}
> > +
> >  #endif
> >
> >  /**
> > diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml
> > index ff74ce1deedb..76fb9347d8e3 100644
> > --- a/src/libcamera/control_ids_core.yaml
> > +++ b/src/libcamera/control_ids_core.yaml
> > @@ -865,236 +865,4 @@ controls:
> >            description: |
> >              This is a long exposure image.
> >
> > -  # ----------------------------------------------------------------------------
> > -  # Draft controls section
> > -
> > -  - AePrecaptureTrigger:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        Control for AE metering trigger. Currently identical to
> > -        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> > -
> > -        Whether the camera device will trigger a precapture metering sequence
> > -        when it processes this request.
> > -      enum:
> > -        - name: AePrecaptureTriggerIdle
> > -          value: 0
> > -          description: The trigger is idle.
> > -        - name: AePrecaptureTriggerStart
> > -          value: 1
> > -          description: The pre-capture AE metering is started by the camera.
> > -        - name: AePrecaptureTriggerCancel
> > -          value: 2
> > -          description: |
> > -            The camera will cancel any active or completed metering sequence.
> > -            The AE algorithm is reset to its initial state.
> > -
> > -  - NoiseReductionMode:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to select the noise reduction algorithm mode. Currently
> > -       identical to ANDROID_NOISE_REDUCTION_MODE.
> > -
> > -        Mode of operation for the noise reduction algorithm.
> > -      enum:
> > -        - name: NoiseReductionModeOff
> > -          value: 0
> > -          description: No noise reduction is applied
> > -        - name: NoiseReductionModeFast
> > -          value: 1
> > -          description: |
> > -            Noise reduction is applied without reducing the frame rate.
> > -        - name: NoiseReductionModeHighQuality
> > -          value: 2
> > -          description: |
> > -            High quality noise reduction at the expense of frame rate.
> > -        - name: NoiseReductionModeMinimal
> > -          value: 3
> > -          description: |
> > -            Minimal noise reduction is applied without reducing the frame rate.
> > -        - name: NoiseReductionModeZSL
> > -          value: 4
> > -          description: |
> > -            Noise reduction is applied at different levels to different streams.
> > -
> > -  - ColorCorrectionAberrationMode:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to select the color correction aberration mode. Currently
> > -       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> > -
> > -        Mode of operation for the chromatic aberration correction algorithm.
> > -      enum:
> > -        - name: ColorCorrectionAberrationOff
> > -          value: 0
> > -          description: No aberration correction is applied.
> > -        - name: ColorCorrectionAberrationFast
> > -          value: 1
> > -          description: Aberration correction will not slow down the frame rate.
> > -        - name: ColorCorrectionAberrationHighQuality
> > -          value: 2
> > -          description: |
> > -            High quality aberration correction which might reduce the frame
> > -            rate.
> > -
> > -  - AeState:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to report the current AE algorithm state. Currently identical to
> > -       ANDROID_CONTROL_AE_STATE.
> > -
> > -        Current state of the AE algorithm.
> > -      enum:
> > -        - name: AeStateInactive
> > -          value: 0
> > -          description: The AE algorithm is inactive.
> > -        - name: AeStateSearching
> > -          value: 1
> > -          description: The AE algorithm has not converged yet.
> > -        - name: AeStateConverged
> > -          value: 2
> > -          description: The AE algorithm has converged.
> > -        - name: AeStateLocked
> > -          value: 3
> > -          description: The AE algorithm is locked.
> > -        - name: AeStateFlashRequired
> > -          value: 4
> > -          description: The AE algorithm would need a flash for good results
> > -        - name: AeStatePrecapture
> > -          value: 5
> > -          description: |
> > -            The AE algorithm has started a pre-capture metering session.
> > -            \sa AePrecaptureTrigger
> > -
> > -  - AwbState:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to report the current AWB algorithm state. Currently identical
> > -       to ANDROID_CONTROL_AWB_STATE.
> > -
> > -        Current state of the AWB algorithm.
> > -      enum:
> > -        - name: AwbStateInactive
> > -          value: 0
> > -          description: The AWB algorithm is inactive.
> > -        - name: AwbStateSearching
> > -          value: 1
> > -          description: The AWB algorithm has not converged yet.
> > -        - name: AwbConverged
> > -          value: 2
> > -          description: The AWB algorithm has converged.
> > -        - name: AwbLocked
> > -          value: 3
> > -          description: The AWB algorithm is locked.
> > -
> > -  - SensorRollingShutterSkew:
> > -      type: int64_t
> > -      draft: true
> > -      description: |
> > -       Control to report the time between the start of exposure of the first
> > -       row and the start of exposure of the last row. Currently identical to
> > -       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> > -
> > -  - LensShadingMapMode:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to report if the lens shading map is available. Currently
> > -       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> > -      enum:
> > -        - name: LensShadingMapModeOff
> > -          value: 0
> > -          description: No lens shading map mode is available.
> > -        - name: LensShadingMapModeOn
> > -          value: 1
> > -          description: The lens shading map mode is available.
> > -
> > -  - PipelineDepth:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        Specifies the number of pipeline stages the frame went through from when
> > -        it was exposed to when the final completed result was available to the
> > -        framework. Always less than or equal to PipelineMaxDepth. Currently
> > -        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> > -
> > -        The typical value for this control is 3 as a frame is first exposed,
> > -        captured and then processed in a single pass through the ISP. Any
> > -        additional processing step performed after the ISP pass (in example face
> > -        detection, additional format conversions etc) count as an additional
> > -        pipeline stage.
> > -
> > -  - MaxLatency:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        The maximum number of frames that can occur after a request (different
> > -        than the previous) has been submitted, and before the result's state
> > -        becomes synchronized. A value of -1 indicates unknown latency, and 0
> > -        indicates per-frame control. Currently identical to
> > -        ANDROID_SYNC_MAX_LATENCY.
> > -
> > -  - TestPatternMode:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        Control to select the test pattern mode. Currently identical to
> > -        ANDROID_SENSOR_TEST_PATTERN_MODE.
> > -      enum:
> > -        - name: TestPatternModeOff
> > -          value: 0
> > -          description: |
> > -            No test pattern mode is used. The camera device returns frames from
> > -            the image sensor.
> > -        - name: TestPatternModeSolidColor
> > -          value: 1
> > -          description: |
> > -            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> > -            color channel provided in test pattern data.
> > -            \todo Add control for test pattern data.
> > -        - name: TestPatternModeColorBars
> > -          value: 2
> > -          description: |
> > -            All pixel data is replaced with an 8-bar color pattern. The vertical
> > -            bars (left-to-right) are as follows; white, yellow, cyan, green,
> > -            magenta, red, blue and black. Each bar should take up 1/8 of the
> > -            sensor pixel array width. When this is not possible, the bar size
> > -            should be rounded down to the nearest integer and the pattern can
> > -            repeat on the right side. Each bar's height must always take up the
> > -            full sensor pixel array height.
> > -        - name: TestPatternModeColorBarsFadeToGray
> > -          value: 3
> > -          description: |
> > -            The test pattern is similar to TestPatternModeColorBars,
> > -            except that each bar should start at its specified color at the top
> > -            and fade to gray at the bottom. Furthermore each bar is further
> > -            subdevided into a left and right half. The left half should have a
> > -            smooth gradient, and the right half should have a quantized
> > -            gradient. In particular, the right half's should consist of blocks
> > -            of the same color for 1/16th active sensor pixel array width. The
> > -            least significant bits in the quantized gradient should be copied
> > -            from the most significant bits of the smooth gradient. The height of
> > -            each bar should always be a multiple of 128. When this is not the
> > -            case, the pattern should repeat at the bottom of the image.
> > -        - name: TestPatternModePn9
> > -          value: 4
> > -          description: |
> > -            All pixel data is replaced by a pseudo-random sequence generated
> > -            from a PN9 512-bit sequence (typically implemented in hardware with
> > -            a linear feedback shift register). The generator should be reset at
> > -            the beginning of each frame, and thus each subsequent raw frame with
> > -            this test pattern should be exactly the same as the last.
> > -        - name: TestPatternModeCustom1
> > -          value: 256
> > -          description: |
> > -            The first custom test pattern. All custom patterns that are
> > -            available only on this camera device are at least this numeric
> > -            value. All of the custom test patterns will be static (that is the
> > -            raw image must not vary from frame to frame).
> > -
> >  ...
> > diff --git a/src/libcamera/control_ids_draft.yaml b/src/libcamera/control_ids_draft.yaml
> > new file mode 100644
> > index 000000000000..e4f53ea51d7a
> > --- /dev/null
> > +++ b/src/libcamera/control_ids_draft.yaml
> > @@ -0,0 +1,240 @@
> > +# SPDX-License-Identifier: LGPL-2.1-or-later
> > +#
> > +# Copyright (C) 2019, Google Inc.
> > +#
> > +%YAML 1.1
> > +---
> > +# Unless otherwise stated, all controls are bi-directional, i.e. they can be
> > +# set through Request::controls() and returned out through Request::metadata().
> > +vendor: draft
> > +controls:
> > +  - AePrecaptureTrigger:
> > +      type: int32_t
> > +      draft: true

Is the draft property still used? Or is this now conveyed as the vendor?

The parameter could always be dropped later.

And I'm also a big fan of the draft controls being moved to their own
namespace and indexing which will lower ABI breakage in the future!


Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> > +      description: |
> > +        Control for AE metering trigger. Currently identical to
> > +        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> > +
> > +        Whether the camera device will trigger a precapture metering sequence
> > +        when it processes this request.
> > +      enum:
> > +        - name: AePrecaptureTriggerIdle
> > +          value: 0
> > +          description: The trigger is idle.
> > +        - name: AePrecaptureTriggerStart
> > +          value: 1
> > +          description: The pre-capture AE metering is started by the camera.
> > +        - name: AePrecaptureTriggerCancel
> > +          value: 2
> > +          description: |
> > +            The camera will cancel any active or completed metering sequence.
> > +            The AE algorithm is reset to its initial state.
> > +
> > +  - NoiseReductionMode:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to select the noise reduction algorithm mode. Currently
> > +       identical to ANDROID_NOISE_REDUCTION_MODE.
> > +
> > +        Mode of operation for the noise reduction algorithm.
> > +      enum:
> > +        - name: NoiseReductionModeOff
> > +          value: 0
> > +          description: No noise reduction is applied
> > +        - name: NoiseReductionModeFast
> > +          value: 1
> > +          description: |
> > +            Noise reduction is applied without reducing the frame rate.
> > +        - name: NoiseReductionModeHighQuality
> > +          value: 2
> > +          description: |
> > +            High quality noise reduction at the expense of frame rate.
> > +        - name: NoiseReductionModeMinimal
> > +          value: 3
> > +          description: |
> > +            Minimal noise reduction is applied without reducing the frame rate.
> > +        - name: NoiseReductionModeZSL
> > +          value: 4
> > +          description: |
> > +            Noise reduction is applied at different levels to different streams.
> > +
> > +  - ColorCorrectionAberrationMode:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to select the color correction aberration mode. Currently
> > +       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> > +
> > +        Mode of operation for the chromatic aberration correction algorithm.
> > +      enum:
> > +        - name: ColorCorrectionAberrationOff
> > +          value: 0
> > +          description: No aberration correction is applied.
> > +        - name: ColorCorrectionAberrationFast
> > +          value: 1
> > +          description: Aberration correction will not slow down the frame rate.
> > +        - name: ColorCorrectionAberrationHighQuality
> > +          value: 2
> > +          description: |
> > +            High quality aberration correction which might reduce the frame
> > +            rate.
> > +
> > +  - AeState:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to report the current AE algorithm state. Currently identical to
> > +       ANDROID_CONTROL_AE_STATE.
> > +
> > +        Current state of the AE algorithm.
> > +      enum:
> > +        - name: AeStateInactive
> > +          value: 0
> > +          description: The AE algorithm is inactive.
> > +        - name: AeStateSearching
> > +          value: 1
> > +          description: The AE algorithm has not converged yet.
> > +        - name: AeStateConverged
> > +          value: 2
> > +          description: The AE algorithm has converged.
> > +        - name: AeStateLocked
> > +          value: 3
> > +          description: The AE algorithm is locked.
> > +        - name: AeStateFlashRequired
> > +          value: 4
> > +          description: The AE algorithm would need a flash for good results
> > +        - name: AeStatePrecapture
> > +          value: 5
> > +          description: |
> > +            The AE algorithm has started a pre-capture metering session.
> > +            \sa AePrecaptureTrigger
> > +
> > +  - AwbState:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to report the current AWB algorithm state. Currently identical
> > +       to ANDROID_CONTROL_AWB_STATE.
> > +
> > +        Current state of the AWB algorithm.
> > +      enum:
> > +        - name: AwbStateInactive
> > +          value: 0
> > +          description: The AWB algorithm is inactive.
> > +        - name: AwbStateSearching
> > +          value: 1
> > +          description: The AWB algorithm has not converged yet.
> > +        - name: AwbConverged
> > +          value: 2
> > +          description: The AWB algorithm has converged.
> > +        - name: AwbLocked
> > +          value: 3
> > +          description: The AWB algorithm is locked.
> > +
> > +  - SensorRollingShutterSkew:
> > +      type: int64_t
> > +      draft: true
> > +      description: |
> > +       Control to report the time between the start of exposure of the first
> > +       row and the start of exposure of the last row. Currently identical to
> > +       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> > +
> > +  - LensShadingMapMode:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to report if the lens shading map is available. Currently
> > +       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> > +      enum:
> > +        - name: LensShadingMapModeOff
> > +          value: 0
> > +          description: No lens shading map mode is available.
> > +        - name: LensShadingMapModeOn
> > +          value: 1
> > +          description: The lens shading map mode is available.
> > +
> > +  - PipelineDepth:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +        Specifies the number of pipeline stages the frame went through from when
> > +        it was exposed to when the final completed result was available to the
> > +        framework. Always less than or equal to PipelineMaxDepth. Currently
> > +        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> > +
> > +        The typical value for this control is 3 as a frame is first exposed,
> > +        captured and then processed in a single pass through the ISP. Any
> > +        additional processing step performed after the ISP pass (in example face
> > +        detection, additional format conversions etc) count as an additional
> > +        pipeline stage.
> > +
> > +  - MaxLatency:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +        The maximum number of frames that can occur after a request (different
> > +        than the previous) has been submitted, and before the result's state
> > +        becomes synchronized. A value of -1 indicates unknown latency, and 0
> > +        indicates per-frame control. Currently identical to
> > +        ANDROID_SYNC_MAX_LATENCY.
> > +
> > +  - TestPatternMode:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +        Control to select the test pattern mode. Currently identical to
> > +        ANDROID_SENSOR_TEST_PATTERN_MODE.
> > +      enum:
> > +        - name: TestPatternModeOff
> > +          value: 0
> > +          description: |
> > +            No test pattern mode is used. The camera device returns frames from
> > +            the image sensor.
> > +        - name: TestPatternModeSolidColor
> > +          value: 1
> > +          description: |
> > +            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> > +            color channel provided in test pattern data.
> > +            \todo Add control for test pattern data.
> > +        - name: TestPatternModeColorBars
> > +          value: 2
> > +          description: |
> > +            All pixel data is replaced with an 8-bar color pattern. The vertical
> > +            bars (left-to-right) are as follows; white, yellow, cyan, green,
> > +            magenta, red, blue and black. Each bar should take up 1/8 of the
> > +            sensor pixel array width. When this is not possible, the bar size
> > +            should be rounded down to the nearest integer and the pattern can
> > +            repeat on the right side. Each bar's height must always take up the
> > +            full sensor pixel array height.
> > +        - name: TestPatternModeColorBarsFadeToGray
> > +          value: 3
> > +          description: |
> > +            The test pattern is similar to TestPatternModeColorBars,
> > +            except that each bar should start at its specified color at the top
> > +            and fade to gray at the bottom. Furthermore each bar is further
> > +            subdevided into a left and right half. The left half should have a
> > +            smooth gradient, and the right half should have a quantized
> > +            gradient. In particular, the right half's should consist of blocks
> > +            of the same color for 1/16th active sensor pixel array width. The
> > +            least significant bits in the quantized gradient should be copied
> > +            from the most significant bits of the smooth gradient. The height of
> > +            each bar should always be a multiple of 128. When this is not the
> > +            case, the pattern should repeat at the bottom of the image.
> > +        - name: TestPatternModePn9
> > +          value: 4
> > +          description: |
> > +            All pixel data is replaced by a pseudo-random sequence generated
> > +            from a PN9 512-bit sequence (typically implemented in hardware with
> > +            a linear feedback shift register). The generator should be reset at
> > +            the beginning of each frame, and thus each subsequent raw frame with
> > +            this test pattern should be exactly the same as the last.
> > +        - name: TestPatternModeCustom1
> > +          value: 256
> > +          description: |
> > +            The first custom test pattern. All custom patterns that are
> > +            available only on this camera device are at least this numeric
> > +            value. All of the custom test patterns will be static (that is the
> > +            raw image must not vary from frame to frame).
> > +
> > +...
> > diff --git a/src/libcamera/property_ids.cpp.in b/src/libcamera/property_ids.cpp.in
> > index 0771ac5c091f..8b274c38c74b 100644
> > --- a/src/libcamera/property_ids.cpp.in
> > +++ b/src/libcamera/property_ids.cpp.in
> > @@ -23,15 +23,6 @@ namespace properties {
> >
> >  ${controls_doc}
> >
> > -/**
> > - * \brief Namespace for libcamera draft properties
> > - */
> > -namespace draft {
> > -
> > -${draft_controls_doc}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls_doc}
> >
> >  #ifndef __DOXYGEN__
> > @@ -41,13 +32,8 @@ ${vendor_controls_doc}
> >   */
> >  ${controls_def}
> >
> > -namespace draft {
> > -
> > -${draft_controls_def}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls_def}
> > +
> >  #endif
> >
> >  /**
> > diff --git a/src/libcamera/property_ids_core.yaml b/src/libcamera/property_ids_core.yaml
> > index 45f3609b4236..834454a4e087 100644
> > --- a/src/libcamera/property_ids_core.yaml
> > +++ b/src/libcamera/property_ids_core.yaml
> > @@ -701,37 +701,4 @@ controls:
> >
> >          Different cameras may report identical devices.
> >
> > -  # ----------------------------------------------------------------------------
> > -  # Draft properties section
> > -
> > -  - ColorFilterArrangement:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        The arrangement of color filters on sensor; represents the colors in the
> > -        top-left 2x2 section of the sensor, in reading order. Currently
> > -        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> > -      enum:
> > -        - name: RGGB
> > -          value: 0
> > -          description: RGGB Bayer pattern
> > -        - name: GRBG
> > -          value: 1
> > -          description: GRBG Bayer pattern
> > -        - name: GBRG
> > -          value: 2
> > -          description: GBRG Bayer pattern
> > -        - name: BGGR
> > -          value: 3
> > -          description: BGGR Bayer pattern
> > -        - name: RGB
> > -          value: 4
> > -          description: |
> > -            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> > -            instead of just 1 16-bit value per pixel.
> > -        - name: MONO
> > -          value: 5
> > -          description: |
> > -            Sensor is not Bayer; output consists of a single colour channel.
> > -
> >  ...
> > diff --git a/src/libcamera/property_ids_draft.yaml b/src/libcamera/property_ids_draft.yaml
> > new file mode 100644
> > index 000000000000..62f0e242d0c6
> > --- /dev/null
> > +++ b/src/libcamera/property_ids_draft.yaml
> > @@ -0,0 +1,39 @@
> > +# SPDX-License-Identifier: LGPL-2.1-or-later
> > +#
> > +# Copyright (C) 2019, Google Inc.
> > +#
> > +%YAML 1.1
> > +---
> > +vendor: draft
> > +controls:
> > +  - ColorFilterArrangement:
> > +      type: int32_t
> > +      vendor: draft
> > +      description: |
> > +        The arrangement of color filters on sensor; represents the colors in the
> > +        top-left 2x2 section of the sensor, in reading order. Currently
> > +        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> > +      enum:
> > +        - name: RGGB
> > +          value: 0
> > +          description: RGGB Bayer pattern
> > +        - name: GRBG
> > +          value: 1
> > +          description: GRBG Bayer pattern
> > +        - name: GBRG
> > +          value: 2
> > +          description: GBRG Bayer pattern
> > +        - name: BGGR
> > +          value: 3
> > +          description: BGGR Bayer pattern
> > +        - name: RGB
> > +          value: 4
> > +          description: |
> > +            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> > +            instead of just 1 16-bit value per pixel.
> > +        - name: MONO
> > +          value: 5
> > +          description: |
> > +            Sensor is not Bayer; output consists of a single colour channel.
> > +
> > +...
> > diff --git a/src/py/libcamera/gen-py-controls.py b/src/py/libcamera/gen-py-controls.py
> > index 8ae8d5126e39..55e0b4e8e3d6 100755
> > --- a/src/py/libcamera/gen-py-controls.py
> > +++ b/src/py/libcamera/gen-py-controls.py
> > @@ -36,10 +36,7 @@ def generate_py(controls, mode):
> >                  vendor_defs.append('\tauto {} = py::class_<Py{}Controls>(controls, \"{}\");'.format(vendor, vendor, vendor))
> >                  vendors.append(vendor)
> >
> > -            if ctrl.get('draft'):
> > -                ns = 'libcamera::{}::draft::'.format(mode)
> > -                container = 'draft'
> > -            elif vendor != 'libcamera':
> > +            if vendor != 'libcamera':
> >                  ns = 'libcamera::{}::{}::'.format(mode, vendor)
> >                  container = vendor
> >              else:
> > diff --git a/src/py/libcamera/py_controls_generated.cpp.in b/src/py/libcamera/py_controls_generated.cpp.in
> > index ec4b55ef2011..8d282ce51856 100644
> > --- a/src/py/libcamera/py_controls_generated.cpp.in
> > +++ b/src/py/libcamera/py_controls_generated.cpp.in
> > @@ -17,16 +17,11 @@ class PyControls
> >  {
> >  };
> >
> > -class PyDraftControls
> > -{
> > -};
> > -
> >  ${vendors_class_def}
> >
> >  void init_py_controls_generated(py::module& m)
> >  {
> >       auto controls = py::class_<PyControls>(m, "controls");
> > -     auto draft = py::class_<PyDraftControls>(controls, "draft");
> >  ${vendors_defs}
> >
> >  ${controls}
> > diff --git a/src/py/libcamera/py_properties_generated.cpp.in b/src/py/libcamera/py_properties_generated.cpp.in
> > index f7b5ec8c635d..ae61c5440d31 100644
> > --- a/src/py/libcamera/py_properties_generated.cpp.in
> > +++ b/src/py/libcamera/py_properties_generated.cpp.in
> > @@ -26,7 +26,6 @@ ${vendors_class_def}
> >  void init_py_properties_generated(py::module& m)
> >  {
> >       auto controls = py::class_<PyProperties>(m, "properties");
> > -     auto draft = py::class_<PyDraftProperties>(controls, "draft");
> >  ${vendors_defs}
> >
> >  ${controls}
> > diff --git a/utils/gen-controls.py b/utils/gen-controls.py
> > index 04c63098b19b..45da571e83e0 100755
> > --- a/utils/gen-controls.py
> > +++ b/utils/gen-controls.py
> > @@ -86,11 +86,6 @@ class Control(object):
> >          """Is the control an enumeration"""
> >          return self.__enum_values is not None
> >
> > -    @property
> > -    def is_draft(self):
> > -        """Is the control a draft control"""
> > -        return self.__data.get('draft') is not None
> > -
> >      @property
> >      def vendor(self):
> >          """The vendor string, or None"""
> > @@ -101,12 +96,6 @@ class Control(object):
> >          """The control name (CamelCase)"""
> >          return self.__name
> >
> > -    @property
> > -    def q_name(self):
> > -        """The control name, qualified with a namespace"""
> > -        ns = 'draft::' if self.is_draft else ''
> > -        return ns + self.__name
> > -
> >      @property
> >      def type(self):
> >          typ = self.__data.get('type')
> > @@ -159,7 +148,7 @@ ${description}
> >      for ctrl in controls:
> >          id_name = snake_case(ctrl.name).upper()
> >
> > -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> > +        vendor = ctrl.vendor
> >          if vendor not in ctrls_doc:
> >              ctrls_doc[vendor] = []
> >              ctrls_def[vendor] = []
> > @@ -208,7 +197,8 @@ ${description}
> >          target_doc.append(doc_template.substitute(info))
> >          target_def.append(def_template.substitute(info))
> >
> > -        ctrls_map.append('\t{ ' + id_name + ', &' + ctrl.q_name + ' },')
> > +        vendor_ns = vendor + '::' if vendor != "libcamera" else ''
> > +        ctrls_map.append('\t{ ' + vendor_ns + id_name + ', &' + vendor_ns + ctrl.name + ' },')
> >
> >      vendor_ctrl_doc_sub = []
> >      vendor_ctrl_template = string.Template('''
> > @@ -218,18 +208,16 @@ ${vendor_controls_str}
> >
> >  } /* namespace ${vendor} */''')
> >
> > -    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera', 'draft']]:
> > +    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera']]:
> >          vendor_ctrl_doc_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n\n'.join(ctrls_doc[vendor])}))
> >
> >      vendor_ctrl_def_sub = []
> > -    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera', 'draft']]:
> > +    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera']]:
> >          vendor_ctrl_def_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n'.join(ctrls_def[vendor])}))
> >
> >      return {
> >          'controls_doc': '\n\n'.join(ctrls_doc['libcamera']),
> >          'controls_def': '\n'.join(ctrls_def['libcamera']),
> > -        'draft_controls_doc': '\n\n'.join(ctrls_doc['draft']),
> > -        'draft_controls_def': '\n\n'.join(ctrls_def['draft']),
> >          'controls_map': '\n'.join(ctrls_map),
> >          'vendor_controls_doc': '\n'.join(vendor_ctrl_doc_sub),
> >          'vendor_controls_def': '\n'.join(vendor_ctrl_def_sub),
> > @@ -249,7 +237,7 @@ def generate_h(controls, mode, ranges):
> >      for ctrl in controls:
> >          id_name = snake_case(ctrl.name).upper()
> >
> > -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> > +        vendor = ctrl.vendor
> >          if vendor not in ctrls:
> >              if vendor not in ranges.keys():
> >                  raise RuntimeError(f'Control id range is not defined for vendor {vendor}')
> > @@ -257,8 +245,7 @@ def generate_h(controls, mode, ranges):
> >              ids[vendor] = []
> >              ctrls[vendor] = []
> >
> > -        # Core and draft controls use the same ID value
> > -        target_ids = ids['libcamera'] if vendor in ['libcamera', 'draft'] else ids[vendor]
> > +        target_ids = ids[vendor]
> >          target_ids.append('\t' + id_name + ' = ' + str(id_value[vendor]) + ',')
> >
> >          info = {
> > @@ -266,11 +253,7 @@ def generate_h(controls, mode, ranges):
> >              'type': ctrl.type,
> >          }
> >
> > -        target_ctrls = ctrls['libcamera']
> > -        if ctrl.is_draft:
> > -            target_ctrls = ctrls['draft']
> > -        elif vendor != 'libcamera':
> > -            target_ctrls = ctrls[vendor]
> > +        target_ctrls = ctrls[vendor]
> >
> >          if ctrl.is_enum:
> >              target_ctrls.append(enum_template_start.substitute(info))
> > @@ -309,7 +292,7 @@ ${vendor_controls}
> >  ''')
> >
> >      vendor_sub = []
> > -    for vendor in [v for v in ctrls.keys() if v not in ['libcamera', 'draft']]:
> > +    for vendor in [v for v in ctrls.keys() if v != 'libcamera']:
> >          vendor_sub.append(vendor_template.substitute({'mode': mode.upper(),
> >                                                        'vendor': vendor,
> >                                                        'vendor_def': vendor.upper(),
> > @@ -319,7 +302,6 @@ ${vendor_controls}
> >      return {
> >          'ids': '\n'.join(ids['libcamera']),
> >          'controls': '\n'.join(ctrls['libcamera']),
> > -        'draft_controls': '\n'.join(ctrls['draft']),
> >          'vendor_controls': '\n'.join(vendor_sub)
> >      }
> >
> > --
> > 2.34.1
> >
Naushir Patuck Nov. 28, 2023, 10:43 a.m. UTC | #3
Hi Kieran,

Thank you for the feedback!

On Tue, 28 Nov 2023 at 10:01, Kieran Bingham
<kieran.bingham@ideasonboard.com> wrote:
>
> Quoting Jacopo Mondi via libcamera-devel (2023-11-27 16:57:06)
> > Hi Naush
> >
> > On Fri, Nov 24, 2023 at 12:37:11PM +0000, Naushir Patuck via libcamera-devel wrote:
> > > Label draft controls and properties through the "draft" vendor tag
> > > and deprecate the existing "draft: true" mechanism. This uses the new
> > > vendor tags mechanism to place draft controls in the same
> > > libcamera::controls::draft namespace and provide a defined control id
> > > range for these controls. This requires moving all draft controls from
> > > control_ids.yaml to control_ids_draft.yaml.
> > >
> > > One breaking change in this commit is that draft control ids also move
> > > to the libcamera::controls::draft namespace from the existing
> > > libcamera::controls namespace. This is desirable to avoid API breakages
> > > when adding new libcamera controls. So, for example, the use of
> > > controls::NOISE_REDUCTION_MODE will need to be replaced with
> > > controls::draft::NOISE_REDUCTION_MODE.
> > >
> > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> >
> > Thanks, I like this change!
> >
> > Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> >
> > > ---
> > >  include/libcamera/control_ids.h.in            |   6 -
> > >  include/libcamera/meson.build                 |   2 +
> > >  include/libcamera/property_ids.h.in           |   6 -
> > >  src/ipa/rpi/common/ipa_base.cpp               |   2 +-
> > >  src/ipa/rpi/vc4/vc4.cpp                       |   2 +-
> > >  src/libcamera/control_ids.cpp.in              |  16 +-
> > >  src/libcamera/control_ids_core.yaml           | 232 -----------------
> > >  src/libcamera/control_ids_draft.yaml          | 240 ++++++++++++++++++
> > >  src/libcamera/property_ids.cpp.in             |  16 +-
> > >  src/libcamera/property_ids_core.yaml          |  33 ---
> > >  src/libcamera/property_ids_draft.yaml         |  39 +++
> > >  src/py/libcamera/gen-py-controls.py           |   5 +-
> > >  src/py/libcamera/py_controls_generated.cpp.in |   5 -
> > >  .../libcamera/py_properties_generated.cpp.in  |   1 -
> > >  utils/gen-controls.py                         |  36 +--
> > >  15 files changed, 295 insertions(+), 346 deletions(-)
> > >  create mode 100644 src/libcamera/control_ids_draft.yaml
> > >  create mode 100644 src/libcamera/property_ids_draft.yaml
> > >
> > > diff --git a/include/libcamera/control_ids.h.in b/include/libcamera/control_ids.h.in
> > > index c97b09a82450..d53b1cf7beb2 100644
> > > --- a/include/libcamera/control_ids.h.in
> > > +++ b/include/libcamera/control_ids.h.in
> > > @@ -26,12 +26,6 @@ ${controls}
> > >
> > >  extern const ControlIdMap controls;
> > >
> > > -namespace draft {
> > > -
> > > -${draft_controls}
> > > -
> > > -} /* namespace draft */
> > > -
> > >  ${vendor_controls}
> > >
> > >  } /* namespace controls */
> > > diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> > > index 79187d3fdfc9..1504f741ae2f 100644
> > > --- a/include/libcamera/meson.build
> > > +++ b/include/libcamera/meson.build
> > > @@ -34,10 +34,12 @@ libcamera_headers_install_dir = get_option('includedir') / libcamera_include_dir
> > >
> > >  controls_map = {
> > >      'controls': {
> > > +        'draft': 'control_ids_draft.yaml',
> > >          'core': 'control_ids_core.yaml',
> > >      },
> > >
> > >      'properties': {
> > > +        'draft': 'property_ids_draft.yaml',
> > >          'core': 'property_ids_core.yaml',
> > >      }
> > >  }
> > > diff --git a/include/libcamera/property_ids.h.in b/include/libcamera/property_ids.h.in
> > > index 47c5d6bf2e28..43372c718fc9 100644
> > > --- a/include/libcamera/property_ids.h.in
> > > +++ b/include/libcamera/property_ids.h.in
> > > @@ -23,12 +23,6 @@ ${ids}
> > >
> > >  ${controls}
> > >
> > > -namespace draft {
> > > -
> > > -${draft_controls}
> > > -
> > > -} /* namespace draft */
> > > -
> > >  extern const ControlIdMap properties;
> > >
> > >  ${vendor_controls}
> > > diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp
> > > index a1fec3aa3dd1..6ac9d5de2f88 100644
> > > --- a/src/ipa/rpi/common/ipa_base.cpp
> > > +++ b/src/ipa/rpi/common/ipa_base.cpp
> > > @@ -1024,7 +1024,7 @@ void IpaBase::applyControls(const ControlList &controls)
> > >                       break;
> > >               }
> > >
> > > -             case controls::NOISE_REDUCTION_MODE:
> > > +             case controls::draft::NOISE_REDUCTION_MODE:
> > >                       /* Handled below in handleControls() */
> > >                       libcameraMetadata_.set(controls::draft::NoiseReductionMode,
> > >                                              ctrl.second.get<int32_t>());
> > > diff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp
> > > index c4baf04fb1e7..c165a5b8b0b6 100644
> > > --- a/src/ipa/rpi/vc4/vc4.cpp
> > > +++ b/src/ipa/rpi/vc4/vc4.cpp
> > > @@ -260,7 +260,7 @@ void IpaVc4::handleControls(const ControlList &controls)
> > >
> > >       for (auto const &ctrl : controls) {
> > >               switch (ctrl.first) {
> > > -             case controls::NOISE_REDUCTION_MODE: {
> > > +             case controls::draft::NOISE_REDUCTION_MODE: {
> > >                       RPiController::DenoiseAlgorithm *sdn = dynamic_cast<RPiController::DenoiseAlgorithm *>(
> > >                               controller_.getAlgorithm("SDN"));
> > >                       /* Some platforms may have a combined "denoise" algorithm instead. */
> > > diff --git a/src/libcamera/control_ids.cpp.in b/src/libcamera/control_ids.cpp.in
> > > index be86548cf73f..d283c1c1f401 100644
> > > --- a/src/libcamera/control_ids.cpp.in
> > > +++ b/src/libcamera/control_ids.cpp.in
> > > @@ -24,15 +24,6 @@ namespace controls {
> > >
> > >  ${controls_doc}
> > >
> > > -/**
> > > - * \brief Namespace for libcamera draft controls
> > > - */
> > > -namespace draft {
> > > -
> > > -${draft_controls_doc}
> > > -
> > > -} /* namespace draft */
> > > -
> > >  ${vendor_controls_doc}
> > >
> > >  #ifndef __DOXYGEN__
> > > @@ -42,13 +33,8 @@ ${vendor_controls_doc}
> > >   */
> > >  ${controls_def}
> > >
> > > -namespace draft {
> > > -
> > > -${draft_controls_def}
> > > -
> > > -} /* namespace draft */
> > > -
> > >  ${vendor_controls_def}
> > > +
> > >  #endif
> > >
> > >  /**
> > > diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml
> > > index ff74ce1deedb..76fb9347d8e3 100644
> > > --- a/src/libcamera/control_ids_core.yaml
> > > +++ b/src/libcamera/control_ids_core.yaml
> > > @@ -865,236 +865,4 @@ controls:
> > >            description: |
> > >              This is a long exposure image.
> > >
> > > -  # ----------------------------------------------------------------------------
> > > -  # Draft controls section
> > > -
> > > -  - AePrecaptureTrigger:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -        Control for AE metering trigger. Currently identical to
> > > -        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> > > -
> > > -        Whether the camera device will trigger a precapture metering sequence
> > > -        when it processes this request.
> > > -      enum:
> > > -        - name: AePrecaptureTriggerIdle
> > > -          value: 0
> > > -          description: The trigger is idle.
> > > -        - name: AePrecaptureTriggerStart
> > > -          value: 1
> > > -          description: The pre-capture AE metering is started by the camera.
> > > -        - name: AePrecaptureTriggerCancel
> > > -          value: 2
> > > -          description: |
> > > -            The camera will cancel any active or completed metering sequence.
> > > -            The AE algorithm is reset to its initial state.
> > > -
> > > -  - NoiseReductionMode:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -       Control to select the noise reduction algorithm mode. Currently
> > > -       identical to ANDROID_NOISE_REDUCTION_MODE.
> > > -
> > > -        Mode of operation for the noise reduction algorithm.
> > > -      enum:
> > > -        - name: NoiseReductionModeOff
> > > -          value: 0
> > > -          description: No noise reduction is applied
> > > -        - name: NoiseReductionModeFast
> > > -          value: 1
> > > -          description: |
> > > -            Noise reduction is applied without reducing the frame rate.
> > > -        - name: NoiseReductionModeHighQuality
> > > -          value: 2
> > > -          description: |
> > > -            High quality noise reduction at the expense of frame rate.
> > > -        - name: NoiseReductionModeMinimal
> > > -          value: 3
> > > -          description: |
> > > -            Minimal noise reduction is applied without reducing the frame rate.
> > > -        - name: NoiseReductionModeZSL
> > > -          value: 4
> > > -          description: |
> > > -            Noise reduction is applied at different levels to different streams.
> > > -
> > > -  - ColorCorrectionAberrationMode:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -       Control to select the color correction aberration mode. Currently
> > > -       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> > > -
> > > -        Mode of operation for the chromatic aberration correction algorithm.
> > > -      enum:
> > > -        - name: ColorCorrectionAberrationOff
> > > -          value: 0
> > > -          description: No aberration correction is applied.
> > > -        - name: ColorCorrectionAberrationFast
> > > -          value: 1
> > > -          description: Aberration correction will not slow down the frame rate.
> > > -        - name: ColorCorrectionAberrationHighQuality
> > > -          value: 2
> > > -          description: |
> > > -            High quality aberration correction which might reduce the frame
> > > -            rate.
> > > -
> > > -  - AeState:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -       Control to report the current AE algorithm state. Currently identical to
> > > -       ANDROID_CONTROL_AE_STATE.
> > > -
> > > -        Current state of the AE algorithm.
> > > -      enum:
> > > -        - name: AeStateInactive
> > > -          value: 0
> > > -          description: The AE algorithm is inactive.
> > > -        - name: AeStateSearching
> > > -          value: 1
> > > -          description: The AE algorithm has not converged yet.
> > > -        - name: AeStateConverged
> > > -          value: 2
> > > -          description: The AE algorithm has converged.
> > > -        - name: AeStateLocked
> > > -          value: 3
> > > -          description: The AE algorithm is locked.
> > > -        - name: AeStateFlashRequired
> > > -          value: 4
> > > -          description: The AE algorithm would need a flash for good results
> > > -        - name: AeStatePrecapture
> > > -          value: 5
> > > -          description: |
> > > -            The AE algorithm has started a pre-capture metering session.
> > > -            \sa AePrecaptureTrigger
> > > -
> > > -  - AwbState:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -       Control to report the current AWB algorithm state. Currently identical
> > > -       to ANDROID_CONTROL_AWB_STATE.
> > > -
> > > -        Current state of the AWB algorithm.
> > > -      enum:
> > > -        - name: AwbStateInactive
> > > -          value: 0
> > > -          description: The AWB algorithm is inactive.
> > > -        - name: AwbStateSearching
> > > -          value: 1
> > > -          description: The AWB algorithm has not converged yet.
> > > -        - name: AwbConverged
> > > -          value: 2
> > > -          description: The AWB algorithm has converged.
> > > -        - name: AwbLocked
> > > -          value: 3
> > > -          description: The AWB algorithm is locked.
> > > -
> > > -  - SensorRollingShutterSkew:
> > > -      type: int64_t
> > > -      draft: true
> > > -      description: |
> > > -       Control to report the time between the start of exposure of the first
> > > -       row and the start of exposure of the last row. Currently identical to
> > > -       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> > > -
> > > -  - LensShadingMapMode:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -       Control to report if the lens shading map is available. Currently
> > > -       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> > > -      enum:
> > > -        - name: LensShadingMapModeOff
> > > -          value: 0
> > > -          description: No lens shading map mode is available.
> > > -        - name: LensShadingMapModeOn
> > > -          value: 1
> > > -          description: The lens shading map mode is available.
> > > -
> > > -  - PipelineDepth:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -        Specifies the number of pipeline stages the frame went through from when
> > > -        it was exposed to when the final completed result was available to the
> > > -        framework. Always less than or equal to PipelineMaxDepth. Currently
> > > -        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> > > -
> > > -        The typical value for this control is 3 as a frame is first exposed,
> > > -        captured and then processed in a single pass through the ISP. Any
> > > -        additional processing step performed after the ISP pass (in example face
> > > -        detection, additional format conversions etc) count as an additional
> > > -        pipeline stage.
> > > -
> > > -  - MaxLatency:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -        The maximum number of frames that can occur after a request (different
> > > -        than the previous) has been submitted, and before the result's state
> > > -        becomes synchronized. A value of -1 indicates unknown latency, and 0
> > > -        indicates per-frame control. Currently identical to
> > > -        ANDROID_SYNC_MAX_LATENCY.
> > > -
> > > -  - TestPatternMode:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -        Control to select the test pattern mode. Currently identical to
> > > -        ANDROID_SENSOR_TEST_PATTERN_MODE.
> > > -      enum:
> > > -        - name: TestPatternModeOff
> > > -          value: 0
> > > -          description: |
> > > -            No test pattern mode is used. The camera device returns frames from
> > > -            the image sensor.
> > > -        - name: TestPatternModeSolidColor
> > > -          value: 1
> > > -          description: |
> > > -            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> > > -            color channel provided in test pattern data.
> > > -            \todo Add control for test pattern data.
> > > -        - name: TestPatternModeColorBars
> > > -          value: 2
> > > -          description: |
> > > -            All pixel data is replaced with an 8-bar color pattern. The vertical
> > > -            bars (left-to-right) are as follows; white, yellow, cyan, green,
> > > -            magenta, red, blue and black. Each bar should take up 1/8 of the
> > > -            sensor pixel array width. When this is not possible, the bar size
> > > -            should be rounded down to the nearest integer and the pattern can
> > > -            repeat on the right side. Each bar's height must always take up the
> > > -            full sensor pixel array height.
> > > -        - name: TestPatternModeColorBarsFadeToGray
> > > -          value: 3
> > > -          description: |
> > > -            The test pattern is similar to TestPatternModeColorBars,
> > > -            except that each bar should start at its specified color at the top
> > > -            and fade to gray at the bottom. Furthermore each bar is further
> > > -            subdevided into a left and right half. The left half should have a
> > > -            smooth gradient, and the right half should have a quantized
> > > -            gradient. In particular, the right half's should consist of blocks
> > > -            of the same color for 1/16th active sensor pixel array width. The
> > > -            least significant bits in the quantized gradient should be copied
> > > -            from the most significant bits of the smooth gradient. The height of
> > > -            each bar should always be a multiple of 128. When this is not the
> > > -            case, the pattern should repeat at the bottom of the image.
> > > -        - name: TestPatternModePn9
> > > -          value: 4
> > > -          description: |
> > > -            All pixel data is replaced by a pseudo-random sequence generated
> > > -            from a PN9 512-bit sequence (typically implemented in hardware with
> > > -            a linear feedback shift register). The generator should be reset at
> > > -            the beginning of each frame, and thus each subsequent raw frame with
> > > -            this test pattern should be exactly the same as the last.
> > > -        - name: TestPatternModeCustom1
> > > -          value: 256
> > > -          description: |
> > > -            The first custom test pattern. All custom patterns that are
> > > -            available only on this camera device are at least this numeric
> > > -            value. All of the custom test patterns will be static (that is the
> > > -            raw image must not vary from frame to frame).
> > > -
> > >  ...
> > > diff --git a/src/libcamera/control_ids_draft.yaml b/src/libcamera/control_ids_draft.yaml
> > > new file mode 100644
> > > index 000000000000..e4f53ea51d7a
> > > --- /dev/null
> > > +++ b/src/libcamera/control_ids_draft.yaml
> > > @@ -0,0 +1,240 @@
> > > +# SPDX-License-Identifier: LGPL-2.1-or-later
> > > +#
> > > +# Copyright (C) 2019, Google Inc.
> > > +#
> > > +%YAML 1.1
> > > +---
> > > +# Unless otherwise stated, all controls are bi-directional, i.e. they can be
> > > +# set through Request::controls() and returned out through Request::metadata().
> > > +vendor: draft
> > > +controls:
> > > +  - AePrecaptureTrigger:
> > > +      type: int32_t
> > > +      draft: true
>
> Is the draft property still used? Or is this now conveyed as the vendor?

No, that's not used any more with this patch.  I'll remove it!

Regards,
Naush

>
> The parameter could always be dropped later.
>
> And I'm also a big fan of the draft controls being moved to their own
> namespace and indexing which will lower ABI breakage in the future!
>
>
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
>
> > > +      description: |
> > > +        Control for AE metering trigger. Currently identical to
> > > +        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> > > +
> > > +        Whether the camera device will trigger a precapture metering sequence
> > > +        when it processes this request.
> > > +      enum:
> > > +        - name: AePrecaptureTriggerIdle
> > > +          value: 0
> > > +          description: The trigger is idle.
> > > +        - name: AePrecaptureTriggerStart
> > > +          value: 1
> > > +          description: The pre-capture AE metering is started by the camera.
> > > +        - name: AePrecaptureTriggerCancel
> > > +          value: 2
> > > +          description: |
> > > +            The camera will cancel any active or completed metering sequence.
> > > +            The AE algorithm is reset to its initial state.
> > > +
> > > +  - NoiseReductionMode:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +       Control to select the noise reduction algorithm mode. Currently
> > > +       identical to ANDROID_NOISE_REDUCTION_MODE.
> > > +
> > > +        Mode of operation for the noise reduction algorithm.
> > > +      enum:
> > > +        - name: NoiseReductionModeOff
> > > +          value: 0
> > > +          description: No noise reduction is applied
> > > +        - name: NoiseReductionModeFast
> > > +          value: 1
> > > +          description: |
> > > +            Noise reduction is applied without reducing the frame rate.
> > > +        - name: NoiseReductionModeHighQuality
> > > +          value: 2
> > > +          description: |
> > > +            High quality noise reduction at the expense of frame rate.
> > > +        - name: NoiseReductionModeMinimal
> > > +          value: 3
> > > +          description: |
> > > +            Minimal noise reduction is applied without reducing the frame rate.
> > > +        - name: NoiseReductionModeZSL
> > > +          value: 4
> > > +          description: |
> > > +            Noise reduction is applied at different levels to different streams.
> > > +
> > > +  - ColorCorrectionAberrationMode:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +       Control to select the color correction aberration mode. Currently
> > > +       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> > > +
> > > +        Mode of operation for the chromatic aberration correction algorithm.
> > > +      enum:
> > > +        - name: ColorCorrectionAberrationOff
> > > +          value: 0
> > > +          description: No aberration correction is applied.
> > > +        - name: ColorCorrectionAberrationFast
> > > +          value: 1
> > > +          description: Aberration correction will not slow down the frame rate.
> > > +        - name: ColorCorrectionAberrationHighQuality
> > > +          value: 2
> > > +          description: |
> > > +            High quality aberration correction which might reduce the frame
> > > +            rate.
> > > +
> > > +  - AeState:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +       Control to report the current AE algorithm state. Currently identical to
> > > +       ANDROID_CONTROL_AE_STATE.
> > > +
> > > +        Current state of the AE algorithm.
> > > +      enum:
> > > +        - name: AeStateInactive
> > > +          value: 0
> > > +          description: The AE algorithm is inactive.
> > > +        - name: AeStateSearching
> > > +          value: 1
> > > +          description: The AE algorithm has not converged yet.
> > > +        - name: AeStateConverged
> > > +          value: 2
> > > +          description: The AE algorithm has converged.
> > > +        - name: AeStateLocked
> > > +          value: 3
> > > +          description: The AE algorithm is locked.
> > > +        - name: AeStateFlashRequired
> > > +          value: 4
> > > +          description: The AE algorithm would need a flash for good results
> > > +        - name: AeStatePrecapture
> > > +          value: 5
> > > +          description: |
> > > +            The AE algorithm has started a pre-capture metering session.
> > > +            \sa AePrecaptureTrigger
> > > +
> > > +  - AwbState:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +       Control to report the current AWB algorithm state. Currently identical
> > > +       to ANDROID_CONTROL_AWB_STATE.
> > > +
> > > +        Current state of the AWB algorithm.
> > > +      enum:
> > > +        - name: AwbStateInactive
> > > +          value: 0
> > > +          description: The AWB algorithm is inactive.
> > > +        - name: AwbStateSearching
> > > +          value: 1
> > > +          description: The AWB algorithm has not converged yet.
> > > +        - name: AwbConverged
> > > +          value: 2
> > > +          description: The AWB algorithm has converged.
> > > +        - name: AwbLocked
> > > +          value: 3
> > > +          description: The AWB algorithm is locked.
> > > +
> > > +  - SensorRollingShutterSkew:
> > > +      type: int64_t
> > > +      draft: true
> > > +      description: |
> > > +       Control to report the time between the start of exposure of the first
> > > +       row and the start of exposure of the last row. Currently identical to
> > > +       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> > > +
> > > +  - LensShadingMapMode:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +       Control to report if the lens shading map is available. Currently
> > > +       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> > > +      enum:
> > > +        - name: LensShadingMapModeOff
> > > +          value: 0
> > > +          description: No lens shading map mode is available.
> > > +        - name: LensShadingMapModeOn
> > > +          value: 1
> > > +          description: The lens shading map mode is available.
> > > +
> > > +  - PipelineDepth:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +        Specifies the number of pipeline stages the frame went through from when
> > > +        it was exposed to when the final completed result was available to the
> > > +        framework. Always less than or equal to PipelineMaxDepth. Currently
> > > +        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> > > +
> > > +        The typical value for this control is 3 as a frame is first exposed,
> > > +        captured and then processed in a single pass through the ISP. Any
> > > +        additional processing step performed after the ISP pass (in example face
> > > +        detection, additional format conversions etc) count as an additional
> > > +        pipeline stage.
> > > +
> > > +  - MaxLatency:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +        The maximum number of frames that can occur after a request (different
> > > +        than the previous) has been submitted, and before the result's state
> > > +        becomes synchronized. A value of -1 indicates unknown latency, and 0
> > > +        indicates per-frame control. Currently identical to
> > > +        ANDROID_SYNC_MAX_LATENCY.
> > > +
> > > +  - TestPatternMode:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +        Control to select the test pattern mode. Currently identical to
> > > +        ANDROID_SENSOR_TEST_PATTERN_MODE.
> > > +      enum:
> > > +        - name: TestPatternModeOff
> > > +          value: 0
> > > +          description: |
> > > +            No test pattern mode is used. The camera device returns frames from
> > > +            the image sensor.
> > > +        - name: TestPatternModeSolidColor
> > > +          value: 1
> > > +          description: |
> > > +            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> > > +            color channel provided in test pattern data.
> > > +            \todo Add control for test pattern data.
> > > +        - name: TestPatternModeColorBars
> > > +          value: 2
> > > +          description: |
> > > +            All pixel data is replaced with an 8-bar color pattern. The vertical
> > > +            bars (left-to-right) are as follows; white, yellow, cyan, green,
> > > +            magenta, red, blue and black. Each bar should take up 1/8 of the
> > > +            sensor pixel array width. When this is not possible, the bar size
> > > +            should be rounded down to the nearest integer and the pattern can
> > > +            repeat on the right side. Each bar's height must always take up the
> > > +            full sensor pixel array height.
> > > +        - name: TestPatternModeColorBarsFadeToGray
> > > +          value: 3
> > > +          description: |
> > > +            The test pattern is similar to TestPatternModeColorBars,
> > > +            except that each bar should start at its specified color at the top
> > > +            and fade to gray at the bottom. Furthermore each bar is further
> > > +            subdevided into a left and right half. The left half should have a
> > > +            smooth gradient, and the right half should have a quantized
> > > +            gradient. In particular, the right half's should consist of blocks
> > > +            of the same color for 1/16th active sensor pixel array width. The
> > > +            least significant bits in the quantized gradient should be copied
> > > +            from the most significant bits of the smooth gradient. The height of
> > > +            each bar should always be a multiple of 128. When this is not the
> > > +            case, the pattern should repeat at the bottom of the image.
> > > +        - name: TestPatternModePn9
> > > +          value: 4
> > > +          description: |
> > > +            All pixel data is replaced by a pseudo-random sequence generated
> > > +            from a PN9 512-bit sequence (typically implemented in hardware with
> > > +            a linear feedback shift register). The generator should be reset at
> > > +            the beginning of each frame, and thus each subsequent raw frame with
> > > +            this test pattern should be exactly the same as the last.
> > > +        - name: TestPatternModeCustom1
> > > +          value: 256
> > > +          description: |
> > > +            The first custom test pattern. All custom patterns that are
> > > +            available only on this camera device are at least this numeric
> > > +            value. All of the custom test patterns will be static (that is the
> > > +            raw image must not vary from frame to frame).
> > > +
> > > +...
> > > diff --git a/src/libcamera/property_ids.cpp.in b/src/libcamera/property_ids.cpp.in
> > > index 0771ac5c091f..8b274c38c74b 100644
> > > --- a/src/libcamera/property_ids.cpp.in
> > > +++ b/src/libcamera/property_ids.cpp.in
> > > @@ -23,15 +23,6 @@ namespace properties {
> > >
> > >  ${controls_doc}
> > >
> > > -/**
> > > - * \brief Namespace for libcamera draft properties
> > > - */
> > > -namespace draft {
> > > -
> > > -${draft_controls_doc}
> > > -
> > > -} /* namespace draft */
> > > -
> > >  ${vendor_controls_doc}
> > >
> > >  #ifndef __DOXYGEN__
> > > @@ -41,13 +32,8 @@ ${vendor_controls_doc}
> > >   */
> > >  ${controls_def}
> > >
> > > -namespace draft {
> > > -
> > > -${draft_controls_def}
> > > -
> > > -} /* namespace draft */
> > > -
> > >  ${vendor_controls_def}
> > > +
> > >  #endif
> > >
> > >  /**
> > > diff --git a/src/libcamera/property_ids_core.yaml b/src/libcamera/property_ids_core.yaml
> > > index 45f3609b4236..834454a4e087 100644
> > > --- a/src/libcamera/property_ids_core.yaml
> > > +++ b/src/libcamera/property_ids_core.yaml
> > > @@ -701,37 +701,4 @@ controls:
> > >
> > >          Different cameras may report identical devices.
> > >
> > > -  # ----------------------------------------------------------------------------
> > > -  # Draft properties section
> > > -
> > > -  - ColorFilterArrangement:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -        The arrangement of color filters on sensor; represents the colors in the
> > > -        top-left 2x2 section of the sensor, in reading order. Currently
> > > -        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> > > -      enum:
> > > -        - name: RGGB
> > > -          value: 0
> > > -          description: RGGB Bayer pattern
> > > -        - name: GRBG
> > > -          value: 1
> > > -          description: GRBG Bayer pattern
> > > -        - name: GBRG
> > > -          value: 2
> > > -          description: GBRG Bayer pattern
> > > -        - name: BGGR
> > > -          value: 3
> > > -          description: BGGR Bayer pattern
> > > -        - name: RGB
> > > -          value: 4
> > > -          description: |
> > > -            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> > > -            instead of just 1 16-bit value per pixel.
> > > -        - name: MONO
> > > -          value: 5
> > > -          description: |
> > > -            Sensor is not Bayer; output consists of a single colour channel.
> > > -
> > >  ...
> > > diff --git a/src/libcamera/property_ids_draft.yaml b/src/libcamera/property_ids_draft.yaml
> > > new file mode 100644
> > > index 000000000000..62f0e242d0c6
> > > --- /dev/null
> > > +++ b/src/libcamera/property_ids_draft.yaml
> > > @@ -0,0 +1,39 @@
> > > +# SPDX-License-Identifier: LGPL-2.1-or-later
> > > +#
> > > +# Copyright (C) 2019, Google Inc.
> > > +#
> > > +%YAML 1.1
> > > +---
> > > +vendor: draft
> > > +controls:
> > > +  - ColorFilterArrangement:
> > > +      type: int32_t
> > > +      vendor: draft
> > > +      description: |
> > > +        The arrangement of color filters on sensor; represents the colors in the
> > > +        top-left 2x2 section of the sensor, in reading order. Currently
> > > +        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> > > +      enum:
> > > +        - name: RGGB
> > > +          value: 0
> > > +          description: RGGB Bayer pattern
> > > +        - name: GRBG
> > > +          value: 1
> > > +          description: GRBG Bayer pattern
> > > +        - name: GBRG
> > > +          value: 2
> > > +          description: GBRG Bayer pattern
> > > +        - name: BGGR
> > > +          value: 3
> > > +          description: BGGR Bayer pattern
> > > +        - name: RGB
> > > +          value: 4
> > > +          description: |
> > > +            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> > > +            instead of just 1 16-bit value per pixel.
> > > +        - name: MONO
> > > +          value: 5
> > > +          description: |
> > > +            Sensor is not Bayer; output consists of a single colour channel.
> > > +
> > > +...
> > > diff --git a/src/py/libcamera/gen-py-controls.py b/src/py/libcamera/gen-py-controls.py
> > > index 8ae8d5126e39..55e0b4e8e3d6 100755
> > > --- a/src/py/libcamera/gen-py-controls.py
> > > +++ b/src/py/libcamera/gen-py-controls.py
> > > @@ -36,10 +36,7 @@ def generate_py(controls, mode):
> > >                  vendor_defs.append('\tauto {} = py::class_<Py{}Controls>(controls, \"{}\");'.format(vendor, vendor, vendor))
> > >                  vendors.append(vendor)
> > >
> > > -            if ctrl.get('draft'):
> > > -                ns = 'libcamera::{}::draft::'.format(mode)
> > > -                container = 'draft'
> > > -            elif vendor != 'libcamera':
> > > +            if vendor != 'libcamera':
> > >                  ns = 'libcamera::{}::{}::'.format(mode, vendor)
> > >                  container = vendor
> > >              else:
> > > diff --git a/src/py/libcamera/py_controls_generated.cpp.in b/src/py/libcamera/py_controls_generated.cpp.in
> > > index ec4b55ef2011..8d282ce51856 100644
> > > --- a/src/py/libcamera/py_controls_generated.cpp.in
> > > +++ b/src/py/libcamera/py_controls_generated.cpp.in
> > > @@ -17,16 +17,11 @@ class PyControls
> > >  {
> > >  };
> > >
> > > -class PyDraftControls
> > > -{
> > > -};
> > > -
> > >  ${vendors_class_def}
> > >
> > >  void init_py_controls_generated(py::module& m)
> > >  {
> > >       auto controls = py::class_<PyControls>(m, "controls");
> > > -     auto draft = py::class_<PyDraftControls>(controls, "draft");
> > >  ${vendors_defs}
> > >
> > >  ${controls}
> > > diff --git a/src/py/libcamera/py_properties_generated.cpp.in b/src/py/libcamera/py_properties_generated.cpp.in
> > > index f7b5ec8c635d..ae61c5440d31 100644
> > > --- a/src/py/libcamera/py_properties_generated.cpp.in
> > > +++ b/src/py/libcamera/py_properties_generated.cpp.in
> > > @@ -26,7 +26,6 @@ ${vendors_class_def}
> > >  void init_py_properties_generated(py::module& m)
> > >  {
> > >       auto controls = py::class_<PyProperties>(m, "properties");
> > > -     auto draft = py::class_<PyDraftProperties>(controls, "draft");
> > >  ${vendors_defs}
> > >
> > >  ${controls}
> > > diff --git a/utils/gen-controls.py b/utils/gen-controls.py
> > > index 04c63098b19b..45da571e83e0 100755
> > > --- a/utils/gen-controls.py
> > > +++ b/utils/gen-controls.py
> > > @@ -86,11 +86,6 @@ class Control(object):
> > >          """Is the control an enumeration"""
> > >          return self.__enum_values is not None
> > >
> > > -    @property
> > > -    def is_draft(self):
> > > -        """Is the control a draft control"""
> > > -        return self.__data.get('draft') is not None
> > > -
> > >      @property
> > >      def vendor(self):
> > >          """The vendor string, or None"""
> > > @@ -101,12 +96,6 @@ class Control(object):
> > >          """The control name (CamelCase)"""
> > >          return self.__name
> > >
> > > -    @property
> > > -    def q_name(self):
> > > -        """The control name, qualified with a namespace"""
> > > -        ns = 'draft::' if self.is_draft else ''
> > > -        return ns + self.__name
> > > -
> > >      @property
> > >      def type(self):
> > >          typ = self.__data.get('type')
> > > @@ -159,7 +148,7 @@ ${description}
> > >      for ctrl in controls:
> > >          id_name = snake_case(ctrl.name).upper()
> > >
> > > -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> > > +        vendor = ctrl.vendor
> > >          if vendor not in ctrls_doc:
> > >              ctrls_doc[vendor] = []
> > >              ctrls_def[vendor] = []
> > > @@ -208,7 +197,8 @@ ${description}
> > >          target_doc.append(doc_template.substitute(info))
> > >          target_def.append(def_template.substitute(info))
> > >
> > > -        ctrls_map.append('\t{ ' + id_name + ', &' + ctrl.q_name + ' },')
> > > +        vendor_ns = vendor + '::' if vendor != "libcamera" else ''
> > > +        ctrls_map.append('\t{ ' + vendor_ns + id_name + ', &' + vendor_ns + ctrl.name + ' },')
> > >
> > >      vendor_ctrl_doc_sub = []
> > >      vendor_ctrl_template = string.Template('''
> > > @@ -218,18 +208,16 @@ ${vendor_controls_str}
> > >
> > >  } /* namespace ${vendor} */''')
> > >
> > > -    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera', 'draft']]:
> > > +    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera']]:
> > >          vendor_ctrl_doc_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n\n'.join(ctrls_doc[vendor])}))
> > >
> > >      vendor_ctrl_def_sub = []
> > > -    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera', 'draft']]:
> > > +    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera']]:
> > >          vendor_ctrl_def_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n'.join(ctrls_def[vendor])}))
> > >
> > >      return {
> > >          'controls_doc': '\n\n'.join(ctrls_doc['libcamera']),
> > >          'controls_def': '\n'.join(ctrls_def['libcamera']),
> > > -        'draft_controls_doc': '\n\n'.join(ctrls_doc['draft']),
> > > -        'draft_controls_def': '\n\n'.join(ctrls_def['draft']),
> > >          'controls_map': '\n'.join(ctrls_map),
> > >          'vendor_controls_doc': '\n'.join(vendor_ctrl_doc_sub),
> > >          'vendor_controls_def': '\n'.join(vendor_ctrl_def_sub),
> > > @@ -249,7 +237,7 @@ def generate_h(controls, mode, ranges):
> > >      for ctrl in controls:
> > >          id_name = snake_case(ctrl.name).upper()
> > >
> > > -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> > > +        vendor = ctrl.vendor
> > >          if vendor not in ctrls:
> > >              if vendor not in ranges.keys():
> > >                  raise RuntimeError(f'Control id range is not defined for vendor {vendor}')
> > > @@ -257,8 +245,7 @@ def generate_h(controls, mode, ranges):
> > >              ids[vendor] = []
> > >              ctrls[vendor] = []
> > >
> > > -        # Core and draft controls use the same ID value
> > > -        target_ids = ids['libcamera'] if vendor in ['libcamera', 'draft'] else ids[vendor]
> > > +        target_ids = ids[vendor]
> > >          target_ids.append('\t' + id_name + ' = ' + str(id_value[vendor]) + ',')
> > >
> > >          info = {
> > > @@ -266,11 +253,7 @@ def generate_h(controls, mode, ranges):
> > >              'type': ctrl.type,
> > >          }
> > >
> > > -        target_ctrls = ctrls['libcamera']
> > > -        if ctrl.is_draft:
> > > -            target_ctrls = ctrls['draft']
> > > -        elif vendor != 'libcamera':
> > > -            target_ctrls = ctrls[vendor]
> > > +        target_ctrls = ctrls[vendor]
> > >
> > >          if ctrl.is_enum:
> > >              target_ctrls.append(enum_template_start.substitute(info))
> > > @@ -309,7 +292,7 @@ ${vendor_controls}
> > >  ''')
> > >
> > >      vendor_sub = []
> > > -    for vendor in [v for v in ctrls.keys() if v not in ['libcamera', 'draft']]:
> > > +    for vendor in [v for v in ctrls.keys() if v != 'libcamera']:
> > >          vendor_sub.append(vendor_template.substitute({'mode': mode.upper(),
> > >                                                        'vendor': vendor,
> > >                                                        'vendor_def': vendor.upper(),
> > > @@ -319,7 +302,6 @@ ${vendor_controls}
> > >      return {
> > >          'ids': '\n'.join(ids['libcamera']),
> > >          'controls': '\n'.join(ctrls['libcamera']),
> > > -        'draft_controls': '\n'.join(ctrls['draft']),
> > >          'vendor_controls': '\n'.join(vendor_sub)
> > >      }
> > >
> > > --
> > > 2.34.1
> > >
Naushir Patuck Nov. 29, 2023, 9:11 a.m. UTC | #4
Hi Kieran and Jacopo,

Version 3 of this patch introduces a minor regression in the python
bindings.  The fix is quite simple:

diff --git a/src/py/libcamera/gen-py-controls.py
b/src/py/libcamera/gen-py-controls.py
index 55e0b4e8e3d6..d0150598ba43 100755
--- a/src/py/libcamera/gen-py-controls.py
+++ b/src/py/libcamera/gen-py-controls.py
@@ -32,8 +32,9 @@ def generate_py(controls, mode):
             name, ctrl = ctrls.popitem()

             if vendor not in vendors and vendor != 'libcamera':
-                vendors_class_def.append('class
Py{}Controls\n{{\n}};\n'.format(vendor))
-                vendor_defs.append('\tauto {} =
py::class_<Py{}Controls>(controls, \"{}\");'.format(vendor, vendor,
vendor))
+                vendor_mode_str = f'{vendor}{mode.capitalize()}'
+                vendors_class_def.append('class
Py{}\n{{\n}};\n'.format(vendor_mode_str))
+                vendor_defs.append('\tauto {} =
py::class_<Py{}>(controls, \"{}\");'.format(vendor, vendor_mode_str,
vendor))
                 vendors.append(vendor)

Given you both have tagged this already, are you ok to keep your tags?
If so, I'll make a git-request-pull for this series.

Thanks,
Naush


On Fri, 24 Nov 2023 at 12:37, Naushir Patuck <naush@raspberrypi.com> wrote:
>
> Label draft controls and properties through the "draft" vendor tag
> and deprecate the existing "draft: true" mechanism. This uses the new
> vendor tags mechanism to place draft controls in the same
> libcamera::controls::draft namespace and provide a defined control id
> range for these controls. This requires moving all draft controls from
> control_ids.yaml to control_ids_draft.yaml.
>
> One breaking change in this commit is that draft control ids also move
> to the libcamera::controls::draft namespace from the existing
> libcamera::controls namespace. This is desirable to avoid API breakages
> when adding new libcamera controls. So, for example, the use of
> controls::NOISE_REDUCTION_MODE will need to be replaced with
> controls::draft::NOISE_REDUCTION_MODE.
>
> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> ---
>  include/libcamera/control_ids.h.in            |   6 -
>  include/libcamera/meson.build                 |   2 +
>  include/libcamera/property_ids.h.in           |   6 -
>  src/ipa/rpi/common/ipa_base.cpp               |   2 +-
>  src/ipa/rpi/vc4/vc4.cpp                       |   2 +-
>  src/libcamera/control_ids.cpp.in              |  16 +-
>  src/libcamera/control_ids_core.yaml           | 232 -----------------
>  src/libcamera/control_ids_draft.yaml          | 240 ++++++++++++++++++
>  src/libcamera/property_ids.cpp.in             |  16 +-
>  src/libcamera/property_ids_core.yaml          |  33 ---
>  src/libcamera/property_ids_draft.yaml         |  39 +++
>  src/py/libcamera/gen-py-controls.py           |   5 +-
>  src/py/libcamera/py_controls_generated.cpp.in |   5 -
>  .../libcamera/py_properties_generated.cpp.in  |   1 -
>  utils/gen-controls.py                         |  36 +--
>  15 files changed, 295 insertions(+), 346 deletions(-)
>  create mode 100644 src/libcamera/control_ids_draft.yaml
>  create mode 100644 src/libcamera/property_ids_draft.yaml
>
> diff --git a/include/libcamera/control_ids.h.in b/include/libcamera/control_ids.h.in
> index c97b09a82450..d53b1cf7beb2 100644
> --- a/include/libcamera/control_ids.h.in
> +++ b/include/libcamera/control_ids.h.in
> @@ -26,12 +26,6 @@ ${controls}
>
>  extern const ControlIdMap controls;
>
> -namespace draft {
> -
> -${draft_controls}
> -
> -} /* namespace draft */
> -
>  ${vendor_controls}
>
>  } /* namespace controls */
> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> index 79187d3fdfc9..1504f741ae2f 100644
> --- a/include/libcamera/meson.build
> +++ b/include/libcamera/meson.build
> @@ -34,10 +34,12 @@ libcamera_headers_install_dir = get_option('includedir') / libcamera_include_dir
>
>  controls_map = {
>      'controls': {
> +        'draft': 'control_ids_draft.yaml',
>          'core': 'control_ids_core.yaml',
>      },
>
>      'properties': {
> +        'draft': 'property_ids_draft.yaml',
>          'core': 'property_ids_core.yaml',
>      }
>  }
> diff --git a/include/libcamera/property_ids.h.in b/include/libcamera/property_ids.h.in
> index 47c5d6bf2e28..43372c718fc9 100644
> --- a/include/libcamera/property_ids.h.in
> +++ b/include/libcamera/property_ids.h.in
> @@ -23,12 +23,6 @@ ${ids}
>
>  ${controls}
>
> -namespace draft {
> -
> -${draft_controls}
> -
> -} /* namespace draft */
> -
>  extern const ControlIdMap properties;
>
>  ${vendor_controls}
> diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp
> index a1fec3aa3dd1..6ac9d5de2f88 100644
> --- a/src/ipa/rpi/common/ipa_base.cpp
> +++ b/src/ipa/rpi/common/ipa_base.cpp
> @@ -1024,7 +1024,7 @@ void IpaBase::applyControls(const ControlList &controls)
>                         break;
>                 }
>
> -               case controls::NOISE_REDUCTION_MODE:
> +               case controls::draft::NOISE_REDUCTION_MODE:
>                         /* Handled below in handleControls() */
>                         libcameraMetadata_.set(controls::draft::NoiseReductionMode,
>                                                ctrl.second.get<int32_t>());
> diff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp
> index c4baf04fb1e7..c165a5b8b0b6 100644
> --- a/src/ipa/rpi/vc4/vc4.cpp
> +++ b/src/ipa/rpi/vc4/vc4.cpp
> @@ -260,7 +260,7 @@ void IpaVc4::handleControls(const ControlList &controls)
>
>         for (auto const &ctrl : controls) {
>                 switch (ctrl.first) {
> -               case controls::NOISE_REDUCTION_MODE: {
> +               case controls::draft::NOISE_REDUCTION_MODE: {
>                         RPiController::DenoiseAlgorithm *sdn = dynamic_cast<RPiController::DenoiseAlgorithm *>(
>                                 controller_.getAlgorithm("SDN"));
>                         /* Some platforms may have a combined "denoise" algorithm instead. */
> diff --git a/src/libcamera/control_ids.cpp.in b/src/libcamera/control_ids.cpp.in
> index be86548cf73f..d283c1c1f401 100644
> --- a/src/libcamera/control_ids.cpp.in
> +++ b/src/libcamera/control_ids.cpp.in
> @@ -24,15 +24,6 @@ namespace controls {
>
>  ${controls_doc}
>
> -/**
> - * \brief Namespace for libcamera draft controls
> - */
> -namespace draft {
> -
> -${draft_controls_doc}
> -
> -} /* namespace draft */
> -
>  ${vendor_controls_doc}
>
>  #ifndef __DOXYGEN__
> @@ -42,13 +33,8 @@ ${vendor_controls_doc}
>   */
>  ${controls_def}
>
> -namespace draft {
> -
> -${draft_controls_def}
> -
> -} /* namespace draft */
> -
>  ${vendor_controls_def}
> +
>  #endif
>
>  /**
> diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml
> index ff74ce1deedb..76fb9347d8e3 100644
> --- a/src/libcamera/control_ids_core.yaml
> +++ b/src/libcamera/control_ids_core.yaml
> @@ -865,236 +865,4 @@ controls:
>            description: |
>              This is a long exposure image.
>
> -  # ----------------------------------------------------------------------------
> -  # Draft controls section
> -
> -  - AePrecaptureTrigger:
> -      type: int32_t
> -      draft: true
> -      description: |
> -        Control for AE metering trigger. Currently identical to
> -        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> -
> -        Whether the camera device will trigger a precapture metering sequence
> -        when it processes this request.
> -      enum:
> -        - name: AePrecaptureTriggerIdle
> -          value: 0
> -          description: The trigger is idle.
> -        - name: AePrecaptureTriggerStart
> -          value: 1
> -          description: The pre-capture AE metering is started by the camera.
> -        - name: AePrecaptureTriggerCancel
> -          value: 2
> -          description: |
> -            The camera will cancel any active or completed metering sequence.
> -            The AE algorithm is reset to its initial state.
> -
> -  - NoiseReductionMode:
> -      type: int32_t
> -      draft: true
> -      description: |
> -       Control to select the noise reduction algorithm mode. Currently
> -       identical to ANDROID_NOISE_REDUCTION_MODE.
> -
> -        Mode of operation for the noise reduction algorithm.
> -      enum:
> -        - name: NoiseReductionModeOff
> -          value: 0
> -          description: No noise reduction is applied
> -        - name: NoiseReductionModeFast
> -          value: 1
> -          description: |
> -            Noise reduction is applied without reducing the frame rate.
> -        - name: NoiseReductionModeHighQuality
> -          value: 2
> -          description: |
> -            High quality noise reduction at the expense of frame rate.
> -        - name: NoiseReductionModeMinimal
> -          value: 3
> -          description: |
> -            Minimal noise reduction is applied without reducing the frame rate.
> -        - name: NoiseReductionModeZSL
> -          value: 4
> -          description: |
> -            Noise reduction is applied at different levels to different streams.
> -
> -  - ColorCorrectionAberrationMode:
> -      type: int32_t
> -      draft: true
> -      description: |
> -       Control to select the color correction aberration mode. Currently
> -       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> -
> -        Mode of operation for the chromatic aberration correction algorithm.
> -      enum:
> -        - name: ColorCorrectionAberrationOff
> -          value: 0
> -          description: No aberration correction is applied.
> -        - name: ColorCorrectionAberrationFast
> -          value: 1
> -          description: Aberration correction will not slow down the frame rate.
> -        - name: ColorCorrectionAberrationHighQuality
> -          value: 2
> -          description: |
> -            High quality aberration correction which might reduce the frame
> -            rate.
> -
> -  - AeState:
> -      type: int32_t
> -      draft: true
> -      description: |
> -       Control to report the current AE algorithm state. Currently identical to
> -       ANDROID_CONTROL_AE_STATE.
> -
> -        Current state of the AE algorithm.
> -      enum:
> -        - name: AeStateInactive
> -          value: 0
> -          description: The AE algorithm is inactive.
> -        - name: AeStateSearching
> -          value: 1
> -          description: The AE algorithm has not converged yet.
> -        - name: AeStateConverged
> -          value: 2
> -          description: The AE algorithm has converged.
> -        - name: AeStateLocked
> -          value: 3
> -          description: The AE algorithm is locked.
> -        - name: AeStateFlashRequired
> -          value: 4
> -          description: The AE algorithm would need a flash for good results
> -        - name: AeStatePrecapture
> -          value: 5
> -          description: |
> -            The AE algorithm has started a pre-capture metering session.
> -            \sa AePrecaptureTrigger
> -
> -  - AwbState:
> -      type: int32_t
> -      draft: true
> -      description: |
> -       Control to report the current AWB algorithm state. Currently identical
> -       to ANDROID_CONTROL_AWB_STATE.
> -
> -        Current state of the AWB algorithm.
> -      enum:
> -        - name: AwbStateInactive
> -          value: 0
> -          description: The AWB algorithm is inactive.
> -        - name: AwbStateSearching
> -          value: 1
> -          description: The AWB algorithm has not converged yet.
> -        - name: AwbConverged
> -          value: 2
> -          description: The AWB algorithm has converged.
> -        - name: AwbLocked
> -          value: 3
> -          description: The AWB algorithm is locked.
> -
> -  - SensorRollingShutterSkew:
> -      type: int64_t
> -      draft: true
> -      description: |
> -       Control to report the time between the start of exposure of the first
> -       row and the start of exposure of the last row. Currently identical to
> -       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> -
> -  - LensShadingMapMode:
> -      type: int32_t
> -      draft: true
> -      description: |
> -       Control to report if the lens shading map is available. Currently
> -       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> -      enum:
> -        - name: LensShadingMapModeOff
> -          value: 0
> -          description: No lens shading map mode is available.
> -        - name: LensShadingMapModeOn
> -          value: 1
> -          description: The lens shading map mode is available.
> -
> -  - PipelineDepth:
> -      type: int32_t
> -      draft: true
> -      description: |
> -        Specifies the number of pipeline stages the frame went through from when
> -        it was exposed to when the final completed result was available to the
> -        framework. Always less than or equal to PipelineMaxDepth. Currently
> -        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> -
> -        The typical value for this control is 3 as a frame is first exposed,
> -        captured and then processed in a single pass through the ISP. Any
> -        additional processing step performed after the ISP pass (in example face
> -        detection, additional format conversions etc) count as an additional
> -        pipeline stage.
> -
> -  - MaxLatency:
> -      type: int32_t
> -      draft: true
> -      description: |
> -        The maximum number of frames that can occur after a request (different
> -        than the previous) has been submitted, and before the result's state
> -        becomes synchronized. A value of -1 indicates unknown latency, and 0
> -        indicates per-frame control. Currently identical to
> -        ANDROID_SYNC_MAX_LATENCY.
> -
> -  - TestPatternMode:
> -      type: int32_t
> -      draft: true
> -      description: |
> -        Control to select the test pattern mode. Currently identical to
> -        ANDROID_SENSOR_TEST_PATTERN_MODE.
> -      enum:
> -        - name: TestPatternModeOff
> -          value: 0
> -          description: |
> -            No test pattern mode is used. The camera device returns frames from
> -            the image sensor.
> -        - name: TestPatternModeSolidColor
> -          value: 1
> -          description: |
> -            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> -            color channel provided in test pattern data.
> -            \todo Add control for test pattern data.
> -        - name: TestPatternModeColorBars
> -          value: 2
> -          description: |
> -            All pixel data is replaced with an 8-bar color pattern. The vertical
> -            bars (left-to-right) are as follows; white, yellow, cyan, green,
> -            magenta, red, blue and black. Each bar should take up 1/8 of the
> -            sensor pixel array width. When this is not possible, the bar size
> -            should be rounded down to the nearest integer and the pattern can
> -            repeat on the right side. Each bar's height must always take up the
> -            full sensor pixel array height.
> -        - name: TestPatternModeColorBarsFadeToGray
> -          value: 3
> -          description: |
> -            The test pattern is similar to TestPatternModeColorBars,
> -            except that each bar should start at its specified color at the top
> -            and fade to gray at the bottom. Furthermore each bar is further
> -            subdevided into a left and right half. The left half should have a
> -            smooth gradient, and the right half should have a quantized
> -            gradient. In particular, the right half's should consist of blocks
> -            of the same color for 1/16th active sensor pixel array width. The
> -            least significant bits in the quantized gradient should be copied
> -            from the most significant bits of the smooth gradient. The height of
> -            each bar should always be a multiple of 128. When this is not the
> -            case, the pattern should repeat at the bottom of the image.
> -        - name: TestPatternModePn9
> -          value: 4
> -          description: |
> -            All pixel data is replaced by a pseudo-random sequence generated
> -            from a PN9 512-bit sequence (typically implemented in hardware with
> -            a linear feedback shift register). The generator should be reset at
> -            the beginning of each frame, and thus each subsequent raw frame with
> -            this test pattern should be exactly the same as the last.
> -        - name: TestPatternModeCustom1
> -          value: 256
> -          description: |
> -            The first custom test pattern. All custom patterns that are
> -            available only on this camera device are at least this numeric
> -            value. All of the custom test patterns will be static (that is the
> -            raw image must not vary from frame to frame).
> -
>  ...
> diff --git a/src/libcamera/control_ids_draft.yaml b/src/libcamera/control_ids_draft.yaml
> new file mode 100644
> index 000000000000..e4f53ea51d7a
> --- /dev/null
> +++ b/src/libcamera/control_ids_draft.yaml
> @@ -0,0 +1,240 @@
> +# SPDX-License-Identifier: LGPL-2.1-or-later
> +#
> +# Copyright (C) 2019, Google Inc.
> +#
> +%YAML 1.1
> +---
> +# Unless otherwise stated, all controls are bi-directional, i.e. they can be
> +# set through Request::controls() and returned out through Request::metadata().
> +vendor: draft
> +controls:
> +  - AePrecaptureTrigger:
> +      type: int32_t
> +      draft: true
> +      description: |
> +        Control for AE metering trigger. Currently identical to
> +        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> +
> +        Whether the camera device will trigger a precapture metering sequence
> +        when it processes this request.
> +      enum:
> +        - name: AePrecaptureTriggerIdle
> +          value: 0
> +          description: The trigger is idle.
> +        - name: AePrecaptureTriggerStart
> +          value: 1
> +          description: The pre-capture AE metering is started by the camera.
> +        - name: AePrecaptureTriggerCancel
> +          value: 2
> +          description: |
> +            The camera will cancel any active or completed metering sequence.
> +            The AE algorithm is reset to its initial state.
> +
> +  - NoiseReductionMode:
> +      type: int32_t
> +      draft: true
> +      description: |
> +       Control to select the noise reduction algorithm mode. Currently
> +       identical to ANDROID_NOISE_REDUCTION_MODE.
> +
> +        Mode of operation for the noise reduction algorithm.
> +      enum:
> +        - name: NoiseReductionModeOff
> +          value: 0
> +          description: No noise reduction is applied
> +        - name: NoiseReductionModeFast
> +          value: 1
> +          description: |
> +            Noise reduction is applied without reducing the frame rate.
> +        - name: NoiseReductionModeHighQuality
> +          value: 2
> +          description: |
> +            High quality noise reduction at the expense of frame rate.
> +        - name: NoiseReductionModeMinimal
> +          value: 3
> +          description: |
> +            Minimal noise reduction is applied without reducing the frame rate.
> +        - name: NoiseReductionModeZSL
> +          value: 4
> +          description: |
> +            Noise reduction is applied at different levels to different streams.
> +
> +  - ColorCorrectionAberrationMode:
> +      type: int32_t
> +      draft: true
> +      description: |
> +       Control to select the color correction aberration mode. Currently
> +       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> +
> +        Mode of operation for the chromatic aberration correction algorithm.
> +      enum:
> +        - name: ColorCorrectionAberrationOff
> +          value: 0
> +          description: No aberration correction is applied.
> +        - name: ColorCorrectionAberrationFast
> +          value: 1
> +          description: Aberration correction will not slow down the frame rate.
> +        - name: ColorCorrectionAberrationHighQuality
> +          value: 2
> +          description: |
> +            High quality aberration correction which might reduce the frame
> +            rate.
> +
> +  - AeState:
> +      type: int32_t
> +      draft: true
> +      description: |
> +       Control to report the current AE algorithm state. Currently identical to
> +       ANDROID_CONTROL_AE_STATE.
> +
> +        Current state of the AE algorithm.
> +      enum:
> +        - name: AeStateInactive
> +          value: 0
> +          description: The AE algorithm is inactive.
> +        - name: AeStateSearching
> +          value: 1
> +          description: The AE algorithm has not converged yet.
> +        - name: AeStateConverged
> +          value: 2
> +          description: The AE algorithm has converged.
> +        - name: AeStateLocked
> +          value: 3
> +          description: The AE algorithm is locked.
> +        - name: AeStateFlashRequired
> +          value: 4
> +          description: The AE algorithm would need a flash for good results
> +        - name: AeStatePrecapture
> +          value: 5
> +          description: |
> +            The AE algorithm has started a pre-capture metering session.
> +            \sa AePrecaptureTrigger
> +
> +  - AwbState:
> +      type: int32_t
> +      draft: true
> +      description: |
> +       Control to report the current AWB algorithm state. Currently identical
> +       to ANDROID_CONTROL_AWB_STATE.
> +
> +        Current state of the AWB algorithm.
> +      enum:
> +        - name: AwbStateInactive
> +          value: 0
> +          description: The AWB algorithm is inactive.
> +        - name: AwbStateSearching
> +          value: 1
> +          description: The AWB algorithm has not converged yet.
> +        - name: AwbConverged
> +          value: 2
> +          description: The AWB algorithm has converged.
> +        - name: AwbLocked
> +          value: 3
> +          description: The AWB algorithm is locked.
> +
> +  - SensorRollingShutterSkew:
> +      type: int64_t
> +      draft: true
> +      description: |
> +       Control to report the time between the start of exposure of the first
> +       row and the start of exposure of the last row. Currently identical to
> +       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> +
> +  - LensShadingMapMode:
> +      type: int32_t
> +      draft: true
> +      description: |
> +       Control to report if the lens shading map is available. Currently
> +       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> +      enum:
> +        - name: LensShadingMapModeOff
> +          value: 0
> +          description: No lens shading map mode is available.
> +        - name: LensShadingMapModeOn
> +          value: 1
> +          description: The lens shading map mode is available.
> +
> +  - PipelineDepth:
> +      type: int32_t
> +      draft: true
> +      description: |
> +        Specifies the number of pipeline stages the frame went through from when
> +        it was exposed to when the final completed result was available to the
> +        framework. Always less than or equal to PipelineMaxDepth. Currently
> +        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> +
> +        The typical value for this control is 3 as a frame is first exposed,
> +        captured and then processed in a single pass through the ISP. Any
> +        additional processing step performed after the ISP pass (in example face
> +        detection, additional format conversions etc) count as an additional
> +        pipeline stage.
> +
> +  - MaxLatency:
> +      type: int32_t
> +      draft: true
> +      description: |
> +        The maximum number of frames that can occur after a request (different
> +        than the previous) has been submitted, and before the result's state
> +        becomes synchronized. A value of -1 indicates unknown latency, and 0
> +        indicates per-frame control. Currently identical to
> +        ANDROID_SYNC_MAX_LATENCY.
> +
> +  - TestPatternMode:
> +      type: int32_t
> +      draft: true
> +      description: |
> +        Control to select the test pattern mode. Currently identical to
> +        ANDROID_SENSOR_TEST_PATTERN_MODE.
> +      enum:
> +        - name: TestPatternModeOff
> +          value: 0
> +          description: |
> +            No test pattern mode is used. The camera device returns frames from
> +            the image sensor.
> +        - name: TestPatternModeSolidColor
> +          value: 1
> +          description: |
> +            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> +            color channel provided in test pattern data.
> +            \todo Add control for test pattern data.
> +        - name: TestPatternModeColorBars
> +          value: 2
> +          description: |
> +            All pixel data is replaced with an 8-bar color pattern. The vertical
> +            bars (left-to-right) are as follows; white, yellow, cyan, green,
> +            magenta, red, blue and black. Each bar should take up 1/8 of the
> +            sensor pixel array width. When this is not possible, the bar size
> +            should be rounded down to the nearest integer and the pattern can
> +            repeat on the right side. Each bar's height must always take up the
> +            full sensor pixel array height.
> +        - name: TestPatternModeColorBarsFadeToGray
> +          value: 3
> +          description: |
> +            The test pattern is similar to TestPatternModeColorBars,
> +            except that each bar should start at its specified color at the top
> +            and fade to gray at the bottom. Furthermore each bar is further
> +            subdevided into a left and right half. The left half should have a
> +            smooth gradient, and the right half should have a quantized
> +            gradient. In particular, the right half's should consist of blocks
> +            of the same color for 1/16th active sensor pixel array width. The
> +            least significant bits in the quantized gradient should be copied
> +            from the most significant bits of the smooth gradient. The height of
> +            each bar should always be a multiple of 128. When this is not the
> +            case, the pattern should repeat at the bottom of the image.
> +        - name: TestPatternModePn9
> +          value: 4
> +          description: |
> +            All pixel data is replaced by a pseudo-random sequence generated
> +            from a PN9 512-bit sequence (typically implemented in hardware with
> +            a linear feedback shift register). The generator should be reset at
> +            the beginning of each frame, and thus each subsequent raw frame with
> +            this test pattern should be exactly the same as the last.
> +        - name: TestPatternModeCustom1
> +          value: 256
> +          description: |
> +            The first custom test pattern. All custom patterns that are
> +            available only on this camera device are at least this numeric
> +            value. All of the custom test patterns will be static (that is the
> +            raw image must not vary from frame to frame).
> +
> +...
> diff --git a/src/libcamera/property_ids.cpp.in b/src/libcamera/property_ids.cpp.in
> index 0771ac5c091f..8b274c38c74b 100644
> --- a/src/libcamera/property_ids.cpp.in
> +++ b/src/libcamera/property_ids.cpp.in
> @@ -23,15 +23,6 @@ namespace properties {
>
>  ${controls_doc}
>
> -/**
> - * \brief Namespace for libcamera draft properties
> - */
> -namespace draft {
> -
> -${draft_controls_doc}
> -
> -} /* namespace draft */
> -
>  ${vendor_controls_doc}
>
>  #ifndef __DOXYGEN__
> @@ -41,13 +32,8 @@ ${vendor_controls_doc}
>   */
>  ${controls_def}
>
> -namespace draft {
> -
> -${draft_controls_def}
> -
> -} /* namespace draft */
> -
>  ${vendor_controls_def}
> +
>  #endif
>
>  /**
> diff --git a/src/libcamera/property_ids_core.yaml b/src/libcamera/property_ids_core.yaml
> index 45f3609b4236..834454a4e087 100644
> --- a/src/libcamera/property_ids_core.yaml
> +++ b/src/libcamera/property_ids_core.yaml
> @@ -701,37 +701,4 @@ controls:
>
>          Different cameras may report identical devices.
>
> -  # ----------------------------------------------------------------------------
> -  # Draft properties section
> -
> -  - ColorFilterArrangement:
> -      type: int32_t
> -      draft: true
> -      description: |
> -        The arrangement of color filters on sensor; represents the colors in the
> -        top-left 2x2 section of the sensor, in reading order. Currently
> -        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> -      enum:
> -        - name: RGGB
> -          value: 0
> -          description: RGGB Bayer pattern
> -        - name: GRBG
> -          value: 1
> -          description: GRBG Bayer pattern
> -        - name: GBRG
> -          value: 2
> -          description: GBRG Bayer pattern
> -        - name: BGGR
> -          value: 3
> -          description: BGGR Bayer pattern
> -        - name: RGB
> -          value: 4
> -          description: |
> -            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> -            instead of just 1 16-bit value per pixel.
> -        - name: MONO
> -          value: 5
> -          description: |
> -            Sensor is not Bayer; output consists of a single colour channel.
> -
>  ...
> diff --git a/src/libcamera/property_ids_draft.yaml b/src/libcamera/property_ids_draft.yaml
> new file mode 100644
> index 000000000000..62f0e242d0c6
> --- /dev/null
> +++ b/src/libcamera/property_ids_draft.yaml
> @@ -0,0 +1,39 @@
> +# SPDX-License-Identifier: LGPL-2.1-or-later
> +#
> +# Copyright (C) 2019, Google Inc.
> +#
> +%YAML 1.1
> +---
> +vendor: draft
> +controls:
> +  - ColorFilterArrangement:
> +      type: int32_t
> +      vendor: draft
> +      description: |
> +        The arrangement of color filters on sensor; represents the colors in the
> +        top-left 2x2 section of the sensor, in reading order. Currently
> +        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> +      enum:
> +        - name: RGGB
> +          value: 0
> +          description: RGGB Bayer pattern
> +        - name: GRBG
> +          value: 1
> +          description: GRBG Bayer pattern
> +        - name: GBRG
> +          value: 2
> +          description: GBRG Bayer pattern
> +        - name: BGGR
> +          value: 3
> +          description: BGGR Bayer pattern
> +        - name: RGB
> +          value: 4
> +          description: |
> +            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> +            instead of just 1 16-bit value per pixel.
> +        - name: MONO
> +          value: 5
> +          description: |
> +            Sensor is not Bayer; output consists of a single colour channel.
> +
> +...
> diff --git a/src/py/libcamera/gen-py-controls.py b/src/py/libcamera/gen-py-controls.py
> index 8ae8d5126e39..55e0b4e8e3d6 100755
> --- a/src/py/libcamera/gen-py-controls.py
> +++ b/src/py/libcamera/gen-py-controls.py
> @@ -36,10 +36,7 @@ def generate_py(controls, mode):
>                  vendor_defs.append('\tauto {} = py::class_<Py{}Controls>(controls, \"{}\");'.format(vendor, vendor, vendor))
>                  vendors.append(vendor)
>
> -            if ctrl.get('draft'):
> -                ns = 'libcamera::{}::draft::'.format(mode)
> -                container = 'draft'
> -            elif vendor != 'libcamera':
> +            if vendor != 'libcamera':
>                  ns = 'libcamera::{}::{}::'.format(mode, vendor)
>                  container = vendor
>              else:
> diff --git a/src/py/libcamera/py_controls_generated.cpp.in b/src/py/libcamera/py_controls_generated.cpp.in
> index ec4b55ef2011..8d282ce51856 100644
> --- a/src/py/libcamera/py_controls_generated.cpp.in
> +++ b/src/py/libcamera/py_controls_generated.cpp.in
> @@ -17,16 +17,11 @@ class PyControls
>  {
>  };
>
> -class PyDraftControls
> -{
> -};
> -
>  ${vendors_class_def}
>
>  void init_py_controls_generated(py::module& m)
>  {
>         auto controls = py::class_<PyControls>(m, "controls");
> -       auto draft = py::class_<PyDraftControls>(controls, "draft");
>  ${vendors_defs}
>
>  ${controls}
> diff --git a/src/py/libcamera/py_properties_generated.cpp.in b/src/py/libcamera/py_properties_generated.cpp.in
> index f7b5ec8c635d..ae61c5440d31 100644
> --- a/src/py/libcamera/py_properties_generated.cpp.in
> +++ b/src/py/libcamera/py_properties_generated.cpp.in
> @@ -26,7 +26,6 @@ ${vendors_class_def}
>  void init_py_properties_generated(py::module& m)
>  {
>         auto controls = py::class_<PyProperties>(m, "properties");
> -       auto draft = py::class_<PyDraftProperties>(controls, "draft");
>  ${vendors_defs}
>
>  ${controls}
> diff --git a/utils/gen-controls.py b/utils/gen-controls.py
> index 04c63098b19b..45da571e83e0 100755
> --- a/utils/gen-controls.py
> +++ b/utils/gen-controls.py
> @@ -86,11 +86,6 @@ class Control(object):
>          """Is the control an enumeration"""
>          return self.__enum_values is not None
>
> -    @property
> -    def is_draft(self):
> -        """Is the control a draft control"""
> -        return self.__data.get('draft') is not None
> -
>      @property
>      def vendor(self):
>          """The vendor string, or None"""
> @@ -101,12 +96,6 @@ class Control(object):
>          """The control name (CamelCase)"""
>          return self.__name
>
> -    @property
> -    def q_name(self):
> -        """The control name, qualified with a namespace"""
> -        ns = 'draft::' if self.is_draft else ''
> -        return ns + self.__name
> -
>      @property
>      def type(self):
>          typ = self.__data.get('type')
> @@ -159,7 +148,7 @@ ${description}
>      for ctrl in controls:
>          id_name = snake_case(ctrl.name).upper()
>
> -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> +        vendor = ctrl.vendor
>          if vendor not in ctrls_doc:
>              ctrls_doc[vendor] = []
>              ctrls_def[vendor] = []
> @@ -208,7 +197,8 @@ ${description}
>          target_doc.append(doc_template.substitute(info))
>          target_def.append(def_template.substitute(info))
>
> -        ctrls_map.append('\t{ ' + id_name + ', &' + ctrl.q_name + ' },')
> +        vendor_ns = vendor + '::' if vendor != "libcamera" else ''
> +        ctrls_map.append('\t{ ' + vendor_ns + id_name + ', &' + vendor_ns + ctrl.name + ' },')
>
>      vendor_ctrl_doc_sub = []
>      vendor_ctrl_template = string.Template('''
> @@ -218,18 +208,16 @@ ${vendor_controls_str}
>
>  } /* namespace ${vendor} */''')
>
> -    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera', 'draft']]:
> +    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera']]:
>          vendor_ctrl_doc_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n\n'.join(ctrls_doc[vendor])}))
>
>      vendor_ctrl_def_sub = []
> -    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera', 'draft']]:
> +    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera']]:
>          vendor_ctrl_def_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n'.join(ctrls_def[vendor])}))
>
>      return {
>          'controls_doc': '\n\n'.join(ctrls_doc['libcamera']),
>          'controls_def': '\n'.join(ctrls_def['libcamera']),
> -        'draft_controls_doc': '\n\n'.join(ctrls_doc['draft']),
> -        'draft_controls_def': '\n\n'.join(ctrls_def['draft']),
>          'controls_map': '\n'.join(ctrls_map),
>          'vendor_controls_doc': '\n'.join(vendor_ctrl_doc_sub),
>          'vendor_controls_def': '\n'.join(vendor_ctrl_def_sub),
> @@ -249,7 +237,7 @@ def generate_h(controls, mode, ranges):
>      for ctrl in controls:
>          id_name = snake_case(ctrl.name).upper()
>
> -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> +        vendor = ctrl.vendor
>          if vendor not in ctrls:
>              if vendor not in ranges.keys():
>                  raise RuntimeError(f'Control id range is not defined for vendor {vendor}')
> @@ -257,8 +245,7 @@ def generate_h(controls, mode, ranges):
>              ids[vendor] = []
>              ctrls[vendor] = []
>
> -        # Core and draft controls use the same ID value
> -        target_ids = ids['libcamera'] if vendor in ['libcamera', 'draft'] else ids[vendor]
> +        target_ids = ids[vendor]
>          target_ids.append('\t' + id_name + ' = ' + str(id_value[vendor]) + ',')
>
>          info = {
> @@ -266,11 +253,7 @@ def generate_h(controls, mode, ranges):
>              'type': ctrl.type,
>          }
>
> -        target_ctrls = ctrls['libcamera']
> -        if ctrl.is_draft:
> -            target_ctrls = ctrls['draft']
> -        elif vendor != 'libcamera':
> -            target_ctrls = ctrls[vendor]
> +        target_ctrls = ctrls[vendor]
>
>          if ctrl.is_enum:
>              target_ctrls.append(enum_template_start.substitute(info))
> @@ -309,7 +292,7 @@ ${vendor_controls}
>  ''')
>
>      vendor_sub = []
> -    for vendor in [v for v in ctrls.keys() if v not in ['libcamera', 'draft']]:
> +    for vendor in [v for v in ctrls.keys() if v != 'libcamera']:
>          vendor_sub.append(vendor_template.substitute({'mode': mode.upper(),
>                                                        'vendor': vendor,
>                                                        'vendor_def': vendor.upper(),
> @@ -319,7 +302,6 @@ ${vendor_controls}
>      return {
>          'ids': '\n'.join(ids['libcamera']),
>          'controls': '\n'.join(ctrls['libcamera']),
> -        'draft_controls': '\n'.join(ctrls['draft']),
>          'vendor_controls': '\n'.join(vendor_sub)
>      }
>
> --
> 2.34.1
>
Kieran Bingham Nov. 29, 2023, 9:32 a.m. UTC | #5
Quoting Naushir Patuck (2023-11-29 09:11:47)
> Hi Kieran and Jacopo,
> 
> Version 3 of this patch introduces a minor regression in the python
> bindings.  The fix is quite simple:
> 
> diff --git a/src/py/libcamera/gen-py-controls.py
> b/src/py/libcamera/gen-py-controls.py
> index 55e0b4e8e3d6..d0150598ba43 100755
> --- a/src/py/libcamera/gen-py-controls.py
> +++ b/src/py/libcamera/gen-py-controls.py
> @@ -32,8 +32,9 @@ def generate_py(controls, mode):
>              name, ctrl = ctrls.popitem()
> 
>              if vendor not in vendors and vendor != 'libcamera':
> -                vendors_class_def.append('class
> Py{}Controls\n{{\n}};\n'.format(vendor))
> -                vendor_defs.append('\tauto {} =
> py::class_<Py{}Controls>(controls, \"{}\");'.format(vendor, vendor,
> vendor))
> +                vendor_mode_str = f'{vendor}{mode.capitalize()}'
> +                vendors_class_def.append('class
> Py{}\n{{\n}};\n'.format(vendor_mode_str))
> +                vendor_defs.append('\tauto {} =
> py::class_<Py{}>(controls, \"{}\");'.format(vendor, vendor_mode_str,
> vendor))
>                  vendors.append(vendor)
> 
> Given you both have tagged this already, are you ok to keep your tags?
> If so, I'll make a git-request-pull for this series.

Yes, that's fine with me.

--
Kieran


> 
> Thanks,
> Naush
> 
> 
> On Fri, 24 Nov 2023 at 12:37, Naushir Patuck <naush@raspberrypi.com> wrote:
> >
> > Label draft controls and properties through the "draft" vendor tag
> > and deprecate the existing "draft: true" mechanism. This uses the new
> > vendor tags mechanism to place draft controls in the same
> > libcamera::controls::draft namespace and provide a defined control id
> > range for these controls. This requires moving all draft controls from
> > control_ids.yaml to control_ids_draft.yaml.
> >
> > One breaking change in this commit is that draft control ids also move
> > to the libcamera::controls::draft namespace from the existing
> > libcamera::controls namespace. This is desirable to avoid API breakages
> > when adding new libcamera controls. So, for example, the use of
> > controls::NOISE_REDUCTION_MODE will need to be replaced with
> > controls::draft::NOISE_REDUCTION_MODE.
> >
> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > ---
> >  include/libcamera/control_ids.h.in            |   6 -
> >  include/libcamera/meson.build                 |   2 +
> >  include/libcamera/property_ids.h.in           |   6 -
> >  src/ipa/rpi/common/ipa_base.cpp               |   2 +-
> >  src/ipa/rpi/vc4/vc4.cpp                       |   2 +-
> >  src/libcamera/control_ids.cpp.in              |  16 +-
> >  src/libcamera/control_ids_core.yaml           | 232 -----------------
> >  src/libcamera/control_ids_draft.yaml          | 240 ++++++++++++++++++
> >  src/libcamera/property_ids.cpp.in             |  16 +-
> >  src/libcamera/property_ids_core.yaml          |  33 ---
> >  src/libcamera/property_ids_draft.yaml         |  39 +++
> >  src/py/libcamera/gen-py-controls.py           |   5 +-
> >  src/py/libcamera/py_controls_generated.cpp.in |   5 -
> >  .../libcamera/py_properties_generated.cpp.in  |   1 -
> >  utils/gen-controls.py                         |  36 +--
> >  15 files changed, 295 insertions(+), 346 deletions(-)
> >  create mode 100644 src/libcamera/control_ids_draft.yaml
> >  create mode 100644 src/libcamera/property_ids_draft.yaml
> >
> > diff --git a/include/libcamera/control_ids.h.in b/include/libcamera/control_ids.h.in
> > index c97b09a82450..d53b1cf7beb2 100644
> > --- a/include/libcamera/control_ids.h.in
> > +++ b/include/libcamera/control_ids.h.in
> > @@ -26,12 +26,6 @@ ${controls}
> >
> >  extern const ControlIdMap controls;
> >
> > -namespace draft {
> > -
> > -${draft_controls}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls}
> >
> >  } /* namespace controls */
> > diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> > index 79187d3fdfc9..1504f741ae2f 100644
> > --- a/include/libcamera/meson.build
> > +++ b/include/libcamera/meson.build
> > @@ -34,10 +34,12 @@ libcamera_headers_install_dir = get_option('includedir') / libcamera_include_dir
> >
> >  controls_map = {
> >      'controls': {
> > +        'draft': 'control_ids_draft.yaml',
> >          'core': 'control_ids_core.yaml',
> >      },
> >
> >      'properties': {
> > +        'draft': 'property_ids_draft.yaml',
> >          'core': 'property_ids_core.yaml',
> >      }
> >  }
> > diff --git a/include/libcamera/property_ids.h.in b/include/libcamera/property_ids.h.in
> > index 47c5d6bf2e28..43372c718fc9 100644
> > --- a/include/libcamera/property_ids.h.in
> > +++ b/include/libcamera/property_ids.h.in
> > @@ -23,12 +23,6 @@ ${ids}
> >
> >  ${controls}
> >
> > -namespace draft {
> > -
> > -${draft_controls}
> > -
> > -} /* namespace draft */
> > -
> >  extern const ControlIdMap properties;
> >
> >  ${vendor_controls}
> > diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp
> > index a1fec3aa3dd1..6ac9d5de2f88 100644
> > --- a/src/ipa/rpi/common/ipa_base.cpp
> > +++ b/src/ipa/rpi/common/ipa_base.cpp
> > @@ -1024,7 +1024,7 @@ void IpaBase::applyControls(const ControlList &controls)
> >                         break;
> >                 }
> >
> > -               case controls::NOISE_REDUCTION_MODE:
> > +               case controls::draft::NOISE_REDUCTION_MODE:
> >                         /* Handled below in handleControls() */
> >                         libcameraMetadata_.set(controls::draft::NoiseReductionMode,
> >                                                ctrl.second.get<int32_t>());
> > diff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp
> > index c4baf04fb1e7..c165a5b8b0b6 100644
> > --- a/src/ipa/rpi/vc4/vc4.cpp
> > +++ b/src/ipa/rpi/vc4/vc4.cpp
> > @@ -260,7 +260,7 @@ void IpaVc4::handleControls(const ControlList &controls)
> >
> >         for (auto const &ctrl : controls) {
> >                 switch (ctrl.first) {
> > -               case controls::NOISE_REDUCTION_MODE: {
> > +               case controls::draft::NOISE_REDUCTION_MODE: {
> >                         RPiController::DenoiseAlgorithm *sdn = dynamic_cast<RPiController::DenoiseAlgorithm *>(
> >                                 controller_.getAlgorithm("SDN"));
> >                         /* Some platforms may have a combined "denoise" algorithm instead. */
> > diff --git a/src/libcamera/control_ids.cpp.in b/src/libcamera/control_ids.cpp.in
> > index be86548cf73f..d283c1c1f401 100644
> > --- a/src/libcamera/control_ids.cpp.in
> > +++ b/src/libcamera/control_ids.cpp.in
> > @@ -24,15 +24,6 @@ namespace controls {
> >
> >  ${controls_doc}
> >
> > -/**
> > - * \brief Namespace for libcamera draft controls
> > - */
> > -namespace draft {
> > -
> > -${draft_controls_doc}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls_doc}
> >
> >  #ifndef __DOXYGEN__
> > @@ -42,13 +33,8 @@ ${vendor_controls_doc}
> >   */
> >  ${controls_def}
> >
> > -namespace draft {
> > -
> > -${draft_controls_def}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls_def}
> > +
> >  #endif
> >
> >  /**
> > diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml
> > index ff74ce1deedb..76fb9347d8e3 100644
> > --- a/src/libcamera/control_ids_core.yaml
> > +++ b/src/libcamera/control_ids_core.yaml
> > @@ -865,236 +865,4 @@ controls:
> >            description: |
> >              This is a long exposure image.
> >
> > -  # ----------------------------------------------------------------------------
> > -  # Draft controls section
> > -
> > -  - AePrecaptureTrigger:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        Control for AE metering trigger. Currently identical to
> > -        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> > -
> > -        Whether the camera device will trigger a precapture metering sequence
> > -        when it processes this request.
> > -      enum:
> > -        - name: AePrecaptureTriggerIdle
> > -          value: 0
> > -          description: The trigger is idle.
> > -        - name: AePrecaptureTriggerStart
> > -          value: 1
> > -          description: The pre-capture AE metering is started by the camera.
> > -        - name: AePrecaptureTriggerCancel
> > -          value: 2
> > -          description: |
> > -            The camera will cancel any active or completed metering sequence.
> > -            The AE algorithm is reset to its initial state.
> > -
> > -  - NoiseReductionMode:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to select the noise reduction algorithm mode. Currently
> > -       identical to ANDROID_NOISE_REDUCTION_MODE.
> > -
> > -        Mode of operation for the noise reduction algorithm.
> > -      enum:
> > -        - name: NoiseReductionModeOff
> > -          value: 0
> > -          description: No noise reduction is applied
> > -        - name: NoiseReductionModeFast
> > -          value: 1
> > -          description: |
> > -            Noise reduction is applied without reducing the frame rate.
> > -        - name: NoiseReductionModeHighQuality
> > -          value: 2
> > -          description: |
> > -            High quality noise reduction at the expense of frame rate.
> > -        - name: NoiseReductionModeMinimal
> > -          value: 3
> > -          description: |
> > -            Minimal noise reduction is applied without reducing the frame rate.
> > -        - name: NoiseReductionModeZSL
> > -          value: 4
> > -          description: |
> > -            Noise reduction is applied at different levels to different streams.
> > -
> > -  - ColorCorrectionAberrationMode:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to select the color correction aberration mode. Currently
> > -       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> > -
> > -        Mode of operation for the chromatic aberration correction algorithm.
> > -      enum:
> > -        - name: ColorCorrectionAberrationOff
> > -          value: 0
> > -          description: No aberration correction is applied.
> > -        - name: ColorCorrectionAberrationFast
> > -          value: 1
> > -          description: Aberration correction will not slow down the frame rate.
> > -        - name: ColorCorrectionAberrationHighQuality
> > -          value: 2
> > -          description: |
> > -            High quality aberration correction which might reduce the frame
> > -            rate.
> > -
> > -  - AeState:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to report the current AE algorithm state. Currently identical to
> > -       ANDROID_CONTROL_AE_STATE.
> > -
> > -        Current state of the AE algorithm.
> > -      enum:
> > -        - name: AeStateInactive
> > -          value: 0
> > -          description: The AE algorithm is inactive.
> > -        - name: AeStateSearching
> > -          value: 1
> > -          description: The AE algorithm has not converged yet.
> > -        - name: AeStateConverged
> > -          value: 2
> > -          description: The AE algorithm has converged.
> > -        - name: AeStateLocked
> > -          value: 3
> > -          description: The AE algorithm is locked.
> > -        - name: AeStateFlashRequired
> > -          value: 4
> > -          description: The AE algorithm would need a flash for good results
> > -        - name: AeStatePrecapture
> > -          value: 5
> > -          description: |
> > -            The AE algorithm has started a pre-capture metering session.
> > -            \sa AePrecaptureTrigger
> > -
> > -  - AwbState:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to report the current AWB algorithm state. Currently identical
> > -       to ANDROID_CONTROL_AWB_STATE.
> > -
> > -        Current state of the AWB algorithm.
> > -      enum:
> > -        - name: AwbStateInactive
> > -          value: 0
> > -          description: The AWB algorithm is inactive.
> > -        - name: AwbStateSearching
> > -          value: 1
> > -          description: The AWB algorithm has not converged yet.
> > -        - name: AwbConverged
> > -          value: 2
> > -          description: The AWB algorithm has converged.
> > -        - name: AwbLocked
> > -          value: 3
> > -          description: The AWB algorithm is locked.
> > -
> > -  - SensorRollingShutterSkew:
> > -      type: int64_t
> > -      draft: true
> > -      description: |
> > -       Control to report the time between the start of exposure of the first
> > -       row and the start of exposure of the last row. Currently identical to
> > -       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> > -
> > -  - LensShadingMapMode:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to report if the lens shading map is available. Currently
> > -       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> > -      enum:
> > -        - name: LensShadingMapModeOff
> > -          value: 0
> > -          description: No lens shading map mode is available.
> > -        - name: LensShadingMapModeOn
> > -          value: 1
> > -          description: The lens shading map mode is available.
> > -
> > -  - PipelineDepth:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        Specifies the number of pipeline stages the frame went through from when
> > -        it was exposed to when the final completed result was available to the
> > -        framework. Always less than or equal to PipelineMaxDepth. Currently
> > -        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> > -
> > -        The typical value for this control is 3 as a frame is first exposed,
> > -        captured and then processed in a single pass through the ISP. Any
> > -        additional processing step performed after the ISP pass (in example face
> > -        detection, additional format conversions etc) count as an additional
> > -        pipeline stage.
> > -
> > -  - MaxLatency:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        The maximum number of frames that can occur after a request (different
> > -        than the previous) has been submitted, and before the result's state
> > -        becomes synchronized. A value of -1 indicates unknown latency, and 0
> > -        indicates per-frame control. Currently identical to
> > -        ANDROID_SYNC_MAX_LATENCY.
> > -
> > -  - TestPatternMode:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        Control to select the test pattern mode. Currently identical to
> > -        ANDROID_SENSOR_TEST_PATTERN_MODE.
> > -      enum:
> > -        - name: TestPatternModeOff
> > -          value: 0
> > -          description: |
> > -            No test pattern mode is used. The camera device returns frames from
> > -            the image sensor.
> > -        - name: TestPatternModeSolidColor
> > -          value: 1
> > -          description: |
> > -            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> > -            color channel provided in test pattern data.
> > -            \todo Add control for test pattern data.
> > -        - name: TestPatternModeColorBars
> > -          value: 2
> > -          description: |
> > -            All pixel data is replaced with an 8-bar color pattern. The vertical
> > -            bars (left-to-right) are as follows; white, yellow, cyan, green,
> > -            magenta, red, blue and black. Each bar should take up 1/8 of the
> > -            sensor pixel array width. When this is not possible, the bar size
> > -            should be rounded down to the nearest integer and the pattern can
> > -            repeat on the right side. Each bar's height must always take up the
> > -            full sensor pixel array height.
> > -        - name: TestPatternModeColorBarsFadeToGray
> > -          value: 3
> > -          description: |
> > -            The test pattern is similar to TestPatternModeColorBars,
> > -            except that each bar should start at its specified color at the top
> > -            and fade to gray at the bottom. Furthermore each bar is further
> > -            subdevided into a left and right half. The left half should have a
> > -            smooth gradient, and the right half should have a quantized
> > -            gradient. In particular, the right half's should consist of blocks
> > -            of the same color for 1/16th active sensor pixel array width. The
> > -            least significant bits in the quantized gradient should be copied
> > -            from the most significant bits of the smooth gradient. The height of
> > -            each bar should always be a multiple of 128. When this is not the
> > -            case, the pattern should repeat at the bottom of the image.
> > -        - name: TestPatternModePn9
> > -          value: 4
> > -          description: |
> > -            All pixel data is replaced by a pseudo-random sequence generated
> > -            from a PN9 512-bit sequence (typically implemented in hardware with
> > -            a linear feedback shift register). The generator should be reset at
> > -            the beginning of each frame, and thus each subsequent raw frame with
> > -            this test pattern should be exactly the same as the last.
> > -        - name: TestPatternModeCustom1
> > -          value: 256
> > -          description: |
> > -            The first custom test pattern. All custom patterns that are
> > -            available only on this camera device are at least this numeric
> > -            value. All of the custom test patterns will be static (that is the
> > -            raw image must not vary from frame to frame).
> > -
> >  ...
> > diff --git a/src/libcamera/control_ids_draft.yaml b/src/libcamera/control_ids_draft.yaml
> > new file mode 100644
> > index 000000000000..e4f53ea51d7a
> > --- /dev/null
> > +++ b/src/libcamera/control_ids_draft.yaml
> > @@ -0,0 +1,240 @@
> > +# SPDX-License-Identifier: LGPL-2.1-or-later
> > +#
> > +# Copyright (C) 2019, Google Inc.
> > +#
> > +%YAML 1.1
> > +---
> > +# Unless otherwise stated, all controls are bi-directional, i.e. they can be
> > +# set through Request::controls() and returned out through Request::metadata().
> > +vendor: draft
> > +controls:
> > +  - AePrecaptureTrigger:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +        Control for AE metering trigger. Currently identical to
> > +        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> > +
> > +        Whether the camera device will trigger a precapture metering sequence
> > +        when it processes this request.
> > +      enum:
> > +        - name: AePrecaptureTriggerIdle
> > +          value: 0
> > +          description: The trigger is idle.
> > +        - name: AePrecaptureTriggerStart
> > +          value: 1
> > +          description: The pre-capture AE metering is started by the camera.
> > +        - name: AePrecaptureTriggerCancel
> > +          value: 2
> > +          description: |
> > +            The camera will cancel any active or completed metering sequence.
> > +            The AE algorithm is reset to its initial state.
> > +
> > +  - NoiseReductionMode:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to select the noise reduction algorithm mode. Currently
> > +       identical to ANDROID_NOISE_REDUCTION_MODE.
> > +
> > +        Mode of operation for the noise reduction algorithm.
> > +      enum:
> > +        - name: NoiseReductionModeOff
> > +          value: 0
> > +          description: No noise reduction is applied
> > +        - name: NoiseReductionModeFast
> > +          value: 1
> > +          description: |
> > +            Noise reduction is applied without reducing the frame rate.
> > +        - name: NoiseReductionModeHighQuality
> > +          value: 2
> > +          description: |
> > +            High quality noise reduction at the expense of frame rate.
> > +        - name: NoiseReductionModeMinimal
> > +          value: 3
> > +          description: |
> > +            Minimal noise reduction is applied without reducing the frame rate.
> > +        - name: NoiseReductionModeZSL
> > +          value: 4
> > +          description: |
> > +            Noise reduction is applied at different levels to different streams.
> > +
> > +  - ColorCorrectionAberrationMode:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to select the color correction aberration mode. Currently
> > +       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> > +
> > +        Mode of operation for the chromatic aberration correction algorithm.
> > +      enum:
> > +        - name: ColorCorrectionAberrationOff
> > +          value: 0
> > +          description: No aberration correction is applied.
> > +        - name: ColorCorrectionAberrationFast
> > +          value: 1
> > +          description: Aberration correction will not slow down the frame rate.
> > +        - name: ColorCorrectionAberrationHighQuality
> > +          value: 2
> > +          description: |
> > +            High quality aberration correction which might reduce the frame
> > +            rate.
> > +
> > +  - AeState:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to report the current AE algorithm state. Currently identical to
> > +       ANDROID_CONTROL_AE_STATE.
> > +
> > +        Current state of the AE algorithm.
> > +      enum:
> > +        - name: AeStateInactive
> > +          value: 0
> > +          description: The AE algorithm is inactive.
> > +        - name: AeStateSearching
> > +          value: 1
> > +          description: The AE algorithm has not converged yet.
> > +        - name: AeStateConverged
> > +          value: 2
> > +          description: The AE algorithm has converged.
> > +        - name: AeStateLocked
> > +          value: 3
> > +          description: The AE algorithm is locked.
> > +        - name: AeStateFlashRequired
> > +          value: 4
> > +          description: The AE algorithm would need a flash for good results
> > +        - name: AeStatePrecapture
> > +          value: 5
> > +          description: |
> > +            The AE algorithm has started a pre-capture metering session.
> > +            \sa AePrecaptureTrigger
> > +
> > +  - AwbState:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to report the current AWB algorithm state. Currently identical
> > +       to ANDROID_CONTROL_AWB_STATE.
> > +
> > +        Current state of the AWB algorithm.
> > +      enum:
> > +        - name: AwbStateInactive
> > +          value: 0
> > +          description: The AWB algorithm is inactive.
> > +        - name: AwbStateSearching
> > +          value: 1
> > +          description: The AWB algorithm has not converged yet.
> > +        - name: AwbConverged
> > +          value: 2
> > +          description: The AWB algorithm has converged.
> > +        - name: AwbLocked
> > +          value: 3
> > +          description: The AWB algorithm is locked.
> > +
> > +  - SensorRollingShutterSkew:
> > +      type: int64_t
> > +      draft: true
> > +      description: |
> > +       Control to report the time between the start of exposure of the first
> > +       row and the start of exposure of the last row. Currently identical to
> > +       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> > +
> > +  - LensShadingMapMode:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to report if the lens shading map is available. Currently
> > +       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> > +      enum:
> > +        - name: LensShadingMapModeOff
> > +          value: 0
> > +          description: No lens shading map mode is available.
> > +        - name: LensShadingMapModeOn
> > +          value: 1
> > +          description: The lens shading map mode is available.
> > +
> > +  - PipelineDepth:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +        Specifies the number of pipeline stages the frame went through from when
> > +        it was exposed to when the final completed result was available to the
> > +        framework. Always less than or equal to PipelineMaxDepth. Currently
> > +        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> > +
> > +        The typical value for this control is 3 as a frame is first exposed,
> > +        captured and then processed in a single pass through the ISP. Any
> > +        additional processing step performed after the ISP pass (in example face
> > +        detection, additional format conversions etc) count as an additional
> > +        pipeline stage.
> > +
> > +  - MaxLatency:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +        The maximum number of frames that can occur after a request (different
> > +        than the previous) has been submitted, and before the result's state
> > +        becomes synchronized. A value of -1 indicates unknown latency, and 0
> > +        indicates per-frame control. Currently identical to
> > +        ANDROID_SYNC_MAX_LATENCY.
> > +
> > +  - TestPatternMode:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +        Control to select the test pattern mode. Currently identical to
> > +        ANDROID_SENSOR_TEST_PATTERN_MODE.
> > +      enum:
> > +        - name: TestPatternModeOff
> > +          value: 0
> > +          description: |
> > +            No test pattern mode is used. The camera device returns frames from
> > +            the image sensor.
> > +        - name: TestPatternModeSolidColor
> > +          value: 1
> > +          description: |
> > +            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> > +            color channel provided in test pattern data.
> > +            \todo Add control for test pattern data.
> > +        - name: TestPatternModeColorBars
> > +          value: 2
> > +          description: |
> > +            All pixel data is replaced with an 8-bar color pattern. The vertical
> > +            bars (left-to-right) are as follows; white, yellow, cyan, green,
> > +            magenta, red, blue and black. Each bar should take up 1/8 of the
> > +            sensor pixel array width. When this is not possible, the bar size
> > +            should be rounded down to the nearest integer and the pattern can
> > +            repeat on the right side. Each bar's height must always take up the
> > +            full sensor pixel array height.
> > +        - name: TestPatternModeColorBarsFadeToGray
> > +          value: 3
> > +          description: |
> > +            The test pattern is similar to TestPatternModeColorBars,
> > +            except that each bar should start at its specified color at the top
> > +            and fade to gray at the bottom. Furthermore each bar is further
> > +            subdevided into a left and right half. The left half should have a
> > +            smooth gradient, and the right half should have a quantized
> > +            gradient. In particular, the right half's should consist of blocks
> > +            of the same color for 1/16th active sensor pixel array width. The
> > +            least significant bits in the quantized gradient should be copied
> > +            from the most significant bits of the smooth gradient. The height of
> > +            each bar should always be a multiple of 128. When this is not the
> > +            case, the pattern should repeat at the bottom of the image.
> > +        - name: TestPatternModePn9
> > +          value: 4
> > +          description: |
> > +            All pixel data is replaced by a pseudo-random sequence generated
> > +            from a PN9 512-bit sequence (typically implemented in hardware with
> > +            a linear feedback shift register). The generator should be reset at
> > +            the beginning of each frame, and thus each subsequent raw frame with
> > +            this test pattern should be exactly the same as the last.
> > +        - name: TestPatternModeCustom1
> > +          value: 256
> > +          description: |
> > +            The first custom test pattern. All custom patterns that are
> > +            available only on this camera device are at least this numeric
> > +            value. All of the custom test patterns will be static (that is the
> > +            raw image must not vary from frame to frame).
> > +
> > +...
> > diff --git a/src/libcamera/property_ids.cpp.in b/src/libcamera/property_ids.cpp.in
> > index 0771ac5c091f..8b274c38c74b 100644
> > --- a/src/libcamera/property_ids.cpp.in
> > +++ b/src/libcamera/property_ids.cpp.in
> > @@ -23,15 +23,6 @@ namespace properties {
> >
> >  ${controls_doc}
> >
> > -/**
> > - * \brief Namespace for libcamera draft properties
> > - */
> > -namespace draft {
> > -
> > -${draft_controls_doc}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls_doc}
> >
> >  #ifndef __DOXYGEN__
> > @@ -41,13 +32,8 @@ ${vendor_controls_doc}
> >   */
> >  ${controls_def}
> >
> > -namespace draft {
> > -
> > -${draft_controls_def}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls_def}
> > +
> >  #endif
> >
> >  /**
> > diff --git a/src/libcamera/property_ids_core.yaml b/src/libcamera/property_ids_core.yaml
> > index 45f3609b4236..834454a4e087 100644
> > --- a/src/libcamera/property_ids_core.yaml
> > +++ b/src/libcamera/property_ids_core.yaml
> > @@ -701,37 +701,4 @@ controls:
> >
> >          Different cameras may report identical devices.
> >
> > -  # ----------------------------------------------------------------------------
> > -  # Draft properties section
> > -
> > -  - ColorFilterArrangement:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        The arrangement of color filters on sensor; represents the colors in the
> > -        top-left 2x2 section of the sensor, in reading order. Currently
> > -        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> > -      enum:
> > -        - name: RGGB
> > -          value: 0
> > -          description: RGGB Bayer pattern
> > -        - name: GRBG
> > -          value: 1
> > -          description: GRBG Bayer pattern
> > -        - name: GBRG
> > -          value: 2
> > -          description: GBRG Bayer pattern
> > -        - name: BGGR
> > -          value: 3
> > -          description: BGGR Bayer pattern
> > -        - name: RGB
> > -          value: 4
> > -          description: |
> > -            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> > -            instead of just 1 16-bit value per pixel.
> > -        - name: MONO
> > -          value: 5
> > -          description: |
> > -            Sensor is not Bayer; output consists of a single colour channel.
> > -
> >  ...
> > diff --git a/src/libcamera/property_ids_draft.yaml b/src/libcamera/property_ids_draft.yaml
> > new file mode 100644
> > index 000000000000..62f0e242d0c6
> > --- /dev/null
> > +++ b/src/libcamera/property_ids_draft.yaml
> > @@ -0,0 +1,39 @@
> > +# SPDX-License-Identifier: LGPL-2.1-or-later
> > +#
> > +# Copyright (C) 2019, Google Inc.
> > +#
> > +%YAML 1.1
> > +---
> > +vendor: draft
> > +controls:
> > +  - ColorFilterArrangement:
> > +      type: int32_t
> > +      vendor: draft
> > +      description: |
> > +        The arrangement of color filters on sensor; represents the colors in the
> > +        top-left 2x2 section of the sensor, in reading order. Currently
> > +        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> > +      enum:
> > +        - name: RGGB
> > +          value: 0
> > +          description: RGGB Bayer pattern
> > +        - name: GRBG
> > +          value: 1
> > +          description: GRBG Bayer pattern
> > +        - name: GBRG
> > +          value: 2
> > +          description: GBRG Bayer pattern
> > +        - name: BGGR
> > +          value: 3
> > +          description: BGGR Bayer pattern
> > +        - name: RGB
> > +          value: 4
> > +          description: |
> > +            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> > +            instead of just 1 16-bit value per pixel.
> > +        - name: MONO
> > +          value: 5
> > +          description: |
> > +            Sensor is not Bayer; output consists of a single colour channel.
> > +
> > +...
> > diff --git a/src/py/libcamera/gen-py-controls.py b/src/py/libcamera/gen-py-controls.py
> > index 8ae8d5126e39..55e0b4e8e3d6 100755
> > --- a/src/py/libcamera/gen-py-controls.py
> > +++ b/src/py/libcamera/gen-py-controls.py
> > @@ -36,10 +36,7 @@ def generate_py(controls, mode):
> >                  vendor_defs.append('\tauto {} = py::class_<Py{}Controls>(controls, \"{}\");'.format(vendor, vendor, vendor))
> >                  vendors.append(vendor)
> >
> > -            if ctrl.get('draft'):
> > -                ns = 'libcamera::{}::draft::'.format(mode)
> > -                container = 'draft'
> > -            elif vendor != 'libcamera':
> > +            if vendor != 'libcamera':
> >                  ns = 'libcamera::{}::{}::'.format(mode, vendor)
> >                  container = vendor
> >              else:
> > diff --git a/src/py/libcamera/py_controls_generated.cpp.in b/src/py/libcamera/py_controls_generated.cpp.in
> > index ec4b55ef2011..8d282ce51856 100644
> > --- a/src/py/libcamera/py_controls_generated.cpp.in
> > +++ b/src/py/libcamera/py_controls_generated.cpp.in
> > @@ -17,16 +17,11 @@ class PyControls
> >  {
> >  };
> >
> > -class PyDraftControls
> > -{
> > -};
> > -
> >  ${vendors_class_def}
> >
> >  void init_py_controls_generated(py::module& m)
> >  {
> >         auto controls = py::class_<PyControls>(m, "controls");
> > -       auto draft = py::class_<PyDraftControls>(controls, "draft");
> >  ${vendors_defs}
> >
> >  ${controls}
> > diff --git a/src/py/libcamera/py_properties_generated.cpp.in b/src/py/libcamera/py_properties_generated.cpp.in
> > index f7b5ec8c635d..ae61c5440d31 100644
> > --- a/src/py/libcamera/py_properties_generated.cpp.in
> > +++ b/src/py/libcamera/py_properties_generated.cpp.in
> > @@ -26,7 +26,6 @@ ${vendors_class_def}
> >  void init_py_properties_generated(py::module& m)
> >  {
> >         auto controls = py::class_<PyProperties>(m, "properties");
> > -       auto draft = py::class_<PyDraftProperties>(controls, "draft");
> >  ${vendors_defs}
> >
> >  ${controls}
> > diff --git a/utils/gen-controls.py b/utils/gen-controls.py
> > index 04c63098b19b..45da571e83e0 100755
> > --- a/utils/gen-controls.py
> > +++ b/utils/gen-controls.py
> > @@ -86,11 +86,6 @@ class Control(object):
> >          """Is the control an enumeration"""
> >          return self.__enum_values is not None
> >
> > -    @property
> > -    def is_draft(self):
> > -        """Is the control a draft control"""
> > -        return self.__data.get('draft') is not None
> > -
> >      @property
> >      def vendor(self):
> >          """The vendor string, or None"""
> > @@ -101,12 +96,6 @@ class Control(object):
> >          """The control name (CamelCase)"""
> >          return self.__name
> >
> > -    @property
> > -    def q_name(self):
> > -        """The control name, qualified with a namespace"""
> > -        ns = 'draft::' if self.is_draft else ''
> > -        return ns + self.__name
> > -
> >      @property
> >      def type(self):
> >          typ = self.__data.get('type')
> > @@ -159,7 +148,7 @@ ${description}
> >      for ctrl in controls:
> >          id_name = snake_case(ctrl.name).upper()
> >
> > -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> > +        vendor = ctrl.vendor
> >          if vendor not in ctrls_doc:
> >              ctrls_doc[vendor] = []
> >              ctrls_def[vendor] = []
> > @@ -208,7 +197,8 @@ ${description}
> >          target_doc.append(doc_template.substitute(info))
> >          target_def.append(def_template.substitute(info))
> >
> > -        ctrls_map.append('\t{ ' + id_name + ', &' + ctrl.q_name + ' },')
> > +        vendor_ns = vendor + '::' if vendor != "libcamera" else ''
> > +        ctrls_map.append('\t{ ' + vendor_ns + id_name + ', &' + vendor_ns + ctrl.name + ' },')
> >
> >      vendor_ctrl_doc_sub = []
> >      vendor_ctrl_template = string.Template('''
> > @@ -218,18 +208,16 @@ ${vendor_controls_str}
> >
> >  } /* namespace ${vendor} */''')
> >
> > -    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera', 'draft']]:
> > +    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera']]:
> >          vendor_ctrl_doc_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n\n'.join(ctrls_doc[vendor])}))
> >
> >      vendor_ctrl_def_sub = []
> > -    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera', 'draft']]:
> > +    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera']]:
> >          vendor_ctrl_def_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n'.join(ctrls_def[vendor])}))
> >
> >      return {
> >          'controls_doc': '\n\n'.join(ctrls_doc['libcamera']),
> >          'controls_def': '\n'.join(ctrls_def['libcamera']),
> > -        'draft_controls_doc': '\n\n'.join(ctrls_doc['draft']),
> > -        'draft_controls_def': '\n\n'.join(ctrls_def['draft']),
> >          'controls_map': '\n'.join(ctrls_map),
> >          'vendor_controls_doc': '\n'.join(vendor_ctrl_doc_sub),
> >          'vendor_controls_def': '\n'.join(vendor_ctrl_def_sub),
> > @@ -249,7 +237,7 @@ def generate_h(controls, mode, ranges):
> >      for ctrl in controls:
> >          id_name = snake_case(ctrl.name).upper()
> >
> > -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> > +        vendor = ctrl.vendor
> >          if vendor not in ctrls:
> >              if vendor not in ranges.keys():
> >                  raise RuntimeError(f'Control id range is not defined for vendor {vendor}')
> > @@ -257,8 +245,7 @@ def generate_h(controls, mode, ranges):
> >              ids[vendor] = []
> >              ctrls[vendor] = []
> >
> > -        # Core and draft controls use the same ID value
> > -        target_ids = ids['libcamera'] if vendor in ['libcamera', 'draft'] else ids[vendor]
> > +        target_ids = ids[vendor]
> >          target_ids.append('\t' + id_name + ' = ' + str(id_value[vendor]) + ',')
> >
> >          info = {
> > @@ -266,11 +253,7 @@ def generate_h(controls, mode, ranges):
> >              'type': ctrl.type,
> >          }
> >
> > -        target_ctrls = ctrls['libcamera']
> > -        if ctrl.is_draft:
> > -            target_ctrls = ctrls['draft']
> > -        elif vendor != 'libcamera':
> > -            target_ctrls = ctrls[vendor]
> > +        target_ctrls = ctrls[vendor]
> >
> >          if ctrl.is_enum:
> >              target_ctrls.append(enum_template_start.substitute(info))
> > @@ -309,7 +292,7 @@ ${vendor_controls}
> >  ''')
> >
> >      vendor_sub = []
> > -    for vendor in [v for v in ctrls.keys() if v not in ['libcamera', 'draft']]:
> > +    for vendor in [v for v in ctrls.keys() if v != 'libcamera']:
> >          vendor_sub.append(vendor_template.substitute({'mode': mode.upper(),
> >                                                        'vendor': vendor,
> >                                                        'vendor_def': vendor.upper(),
> > @@ -319,7 +302,6 @@ ${vendor_controls}
> >      return {
> >          'ids': '\n'.join(ids['libcamera']),
> >          'controls': '\n'.join(ctrls['libcamera']),
> > -        'draft_controls': '\n'.join(ctrls['draft']),
> >          'vendor_controls': '\n'.join(vendor_sub)
> >      }
> >
> > --
> > 2.34.1
> >
Laurent Pinchart Nov. 30, 2023, 12:57 p.m. UTC | #6
Hi Naush,

On Wed, Nov 29, 2023 at 09:11:47AM +0000, Naushir Patuck via libcamera-devel wrote:
> Hi Kieran and Jacopo,
> 
> Version 3 of this patch introduces a minor regression in the python
> bindings.  The fix is quite simple:
> 
> diff --git a/src/py/libcamera/gen-py-controls.py
> b/src/py/libcamera/gen-py-controls.py
> index 55e0b4e8e3d6..d0150598ba43 100755
> --- a/src/py/libcamera/gen-py-controls.py
> +++ b/src/py/libcamera/gen-py-controls.py
> @@ -32,8 +32,9 @@ def generate_py(controls, mode):
>              name, ctrl = ctrls.popitem()
> 
>              if vendor not in vendors and vendor != 'libcamera':
> -                vendors_class_def.append('class Py{}Controls\n{{\n}};\n'.format(vendor))
> -                vendor_defs.append('\tauto {} = py::class_<Py{}Controls>(controls, \"{}\");'.format(vendor, vendor, vendor))
> +                vendor_mode_str = f'{vendor}{mode.capitalize()}'
> +                vendors_class_def.append('class Py{}\n{{\n}};\n'.format(vendor_mode_str))
> +                vendor_defs.append('\tauto {} = py::class_<Py{}>(controls, \"{}\");'.format(vendor, vendor_mode_str, vendor))
>                  vendors.append(vendor)

I tested this locally, and still see

        auto controls = py::class_<PyControls>(m, "controls");
        auto draft = py::class_<PydraftControls>(controls, "draft");
        auto rpi = py::class_<PyrpiControls>(controls, "rpi");

vs.

        auto controls = py::class_<PyProperties>(m, "properties");
        auto draft = py::class_<PydraftProperties>(controls, "draft");

which looks good for the mode. I wonder though, shouldn't we also
capitalize the vendor name ?

> Given you both have tagged this already, are you ok to keep your tags?
> If so, I'll make a git-request-pull for this series.
> 
> On Fri, 24 Nov 2023 at 12:37, Naushir Patuck <naush@raspberrypi.com> wrote:
> >
> > Label draft controls and properties through the "draft" vendor tag
> > and deprecate the existing "draft: true" mechanism. This uses the new
> > vendor tags mechanism to place draft controls in the same
> > libcamera::controls::draft namespace and provide a defined control id
> > range for these controls. This requires moving all draft controls from
> > control_ids.yaml to control_ids_draft.yaml.
> >
> > One breaking change in this commit is that draft control ids also move
> > to the libcamera::controls::draft namespace from the existing
> > libcamera::controls namespace. This is desirable to avoid API breakages
> > when adding new libcamera controls. So, for example, the use of
> > controls::NOISE_REDUCTION_MODE will need to be replaced with
> > controls::draft::NOISE_REDUCTION_MODE.
> >
> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > ---
> >  include/libcamera/control_ids.h.in            |   6 -
> >  include/libcamera/meson.build                 |   2 +
> >  include/libcamera/property_ids.h.in           |   6 -
> >  src/ipa/rpi/common/ipa_base.cpp               |   2 +-
> >  src/ipa/rpi/vc4/vc4.cpp                       |   2 +-
> >  src/libcamera/control_ids.cpp.in              |  16 +-
> >  src/libcamera/control_ids_core.yaml           | 232 -----------------
> >  src/libcamera/control_ids_draft.yaml          | 240 ++++++++++++++++++
> >  src/libcamera/property_ids.cpp.in             |  16 +-
> >  src/libcamera/property_ids_core.yaml          |  33 ---
> >  src/libcamera/property_ids_draft.yaml         |  39 +++
> >  src/py/libcamera/gen-py-controls.py           |   5 +-
> >  src/py/libcamera/py_controls_generated.cpp.in |   5 -
> >  .../libcamera/py_properties_generated.cpp.in  |   1 -
> >  utils/gen-controls.py                         |  36 +--
> >  15 files changed, 295 insertions(+), 346 deletions(-)
> >  create mode 100644 src/libcamera/control_ids_draft.yaml
> >  create mode 100644 src/libcamera/property_ids_draft.yaml
> >
> > diff --git a/include/libcamera/control_ids.h.in b/include/libcamera/control_ids.h.in
> > index c97b09a82450..d53b1cf7beb2 100644
> > --- a/include/libcamera/control_ids.h.in
> > +++ b/include/libcamera/control_ids.h.in
> > @@ -26,12 +26,6 @@ ${controls}
> >
> >  extern const ControlIdMap controls;
> >
> > -namespace draft {
> > -
> > -${draft_controls}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls}
> >
> >  } /* namespace controls */
> > diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> > index 79187d3fdfc9..1504f741ae2f 100644
> > --- a/include/libcamera/meson.build
> > +++ b/include/libcamera/meson.build
> > @@ -34,10 +34,12 @@ libcamera_headers_install_dir = get_option('includedir') / libcamera_include_dir
> >
> >  controls_map = {
> >      'controls': {
> > +        'draft': 'control_ids_draft.yaml',
> >          'core': 'control_ids_core.yaml',
> >      },
> >
> >      'properties': {
> > +        'draft': 'property_ids_draft.yaml',
> >          'core': 'property_ids_core.yaml',
> >      }
> >  }
> > diff --git a/include/libcamera/property_ids.h.in b/include/libcamera/property_ids.h.in
> > index 47c5d6bf2e28..43372c718fc9 100644
> > --- a/include/libcamera/property_ids.h.in
> > +++ b/include/libcamera/property_ids.h.in
> > @@ -23,12 +23,6 @@ ${ids}
> >
> >  ${controls}
> >
> > -namespace draft {
> > -
> > -${draft_controls}
> > -
> > -} /* namespace draft */
> > -
> >  extern const ControlIdMap properties;
> >
> >  ${vendor_controls}
> > diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp
> > index a1fec3aa3dd1..6ac9d5de2f88 100644
> > --- a/src/ipa/rpi/common/ipa_base.cpp
> > +++ b/src/ipa/rpi/common/ipa_base.cpp
> > @@ -1024,7 +1024,7 @@ void IpaBase::applyControls(const ControlList &controls)
> >                         break;
> >                 }
> >
> > -               case controls::NOISE_REDUCTION_MODE:
> > +               case controls::draft::NOISE_REDUCTION_MODE:
> >                         /* Handled below in handleControls() */
> >                         libcameraMetadata_.set(controls::draft::NoiseReductionMode,
> >                                                ctrl.second.get<int32_t>());
> > diff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp
> > index c4baf04fb1e7..c165a5b8b0b6 100644
> > --- a/src/ipa/rpi/vc4/vc4.cpp
> > +++ b/src/ipa/rpi/vc4/vc4.cpp
> > @@ -260,7 +260,7 @@ void IpaVc4::handleControls(const ControlList &controls)
> >
> >         for (auto const &ctrl : controls) {
> >                 switch (ctrl.first) {
> > -               case controls::NOISE_REDUCTION_MODE: {
> > +               case controls::draft::NOISE_REDUCTION_MODE: {
> >                         RPiController::DenoiseAlgorithm *sdn = dynamic_cast<RPiController::DenoiseAlgorithm *>(
> >                                 controller_.getAlgorithm("SDN"));
> >                         /* Some platforms may have a combined "denoise" algorithm instead. */
> > diff --git a/src/libcamera/control_ids.cpp.in b/src/libcamera/control_ids.cpp.in
> > index be86548cf73f..d283c1c1f401 100644
> > --- a/src/libcamera/control_ids.cpp.in
> > +++ b/src/libcamera/control_ids.cpp.in
> > @@ -24,15 +24,6 @@ namespace controls {
> >
> >  ${controls_doc}
> >
> > -/**
> > - * \brief Namespace for libcamera draft controls
> > - */
> > -namespace draft {
> > -
> > -${draft_controls_doc}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls_doc}
> >
> >  #ifndef __DOXYGEN__
> > @@ -42,13 +33,8 @@ ${vendor_controls_doc}
> >   */
> >  ${controls_def}
> >
> > -namespace draft {
> > -
> > -${draft_controls_def}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls_def}
> > +
> >  #endif
> >
> >  /**
> > diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml
> > index ff74ce1deedb..76fb9347d8e3 100644
> > --- a/src/libcamera/control_ids_core.yaml
> > +++ b/src/libcamera/control_ids_core.yaml
> > @@ -865,236 +865,4 @@ controls:
> >            description: |
> >              This is a long exposure image.
> >
> > -  # ----------------------------------------------------------------------------
> > -  # Draft controls section
> > -
> > -  - AePrecaptureTrigger:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        Control for AE metering trigger. Currently identical to
> > -        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> > -
> > -        Whether the camera device will trigger a precapture metering sequence
> > -        when it processes this request.
> > -      enum:
> > -        - name: AePrecaptureTriggerIdle
> > -          value: 0
> > -          description: The trigger is idle.
> > -        - name: AePrecaptureTriggerStart
> > -          value: 1
> > -          description: The pre-capture AE metering is started by the camera.
> > -        - name: AePrecaptureTriggerCancel
> > -          value: 2
> > -          description: |
> > -            The camera will cancel any active or completed metering sequence.
> > -            The AE algorithm is reset to its initial state.
> > -
> > -  - NoiseReductionMode:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to select the noise reduction algorithm mode. Currently
> > -       identical to ANDROID_NOISE_REDUCTION_MODE.
> > -
> > -        Mode of operation for the noise reduction algorithm.
> > -      enum:
> > -        - name: NoiseReductionModeOff
> > -          value: 0
> > -          description: No noise reduction is applied
> > -        - name: NoiseReductionModeFast
> > -          value: 1
> > -          description: |
> > -            Noise reduction is applied without reducing the frame rate.
> > -        - name: NoiseReductionModeHighQuality
> > -          value: 2
> > -          description: |
> > -            High quality noise reduction at the expense of frame rate.
> > -        - name: NoiseReductionModeMinimal
> > -          value: 3
> > -          description: |
> > -            Minimal noise reduction is applied without reducing the frame rate.
> > -        - name: NoiseReductionModeZSL
> > -          value: 4
> > -          description: |
> > -            Noise reduction is applied at different levels to different streams.
> > -
> > -  - ColorCorrectionAberrationMode:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to select the color correction aberration mode. Currently
> > -       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> > -
> > -        Mode of operation for the chromatic aberration correction algorithm.
> > -      enum:
> > -        - name: ColorCorrectionAberrationOff
> > -          value: 0
> > -          description: No aberration correction is applied.
> > -        - name: ColorCorrectionAberrationFast
> > -          value: 1
> > -          description: Aberration correction will not slow down the frame rate.
> > -        - name: ColorCorrectionAberrationHighQuality
> > -          value: 2
> > -          description: |
> > -            High quality aberration correction which might reduce the frame
> > -            rate.
> > -
> > -  - AeState:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to report the current AE algorithm state. Currently identical to
> > -       ANDROID_CONTROL_AE_STATE.
> > -
> > -        Current state of the AE algorithm.
> > -      enum:
> > -        - name: AeStateInactive
> > -          value: 0
> > -          description: The AE algorithm is inactive.
> > -        - name: AeStateSearching
> > -          value: 1
> > -          description: The AE algorithm has not converged yet.
> > -        - name: AeStateConverged
> > -          value: 2
> > -          description: The AE algorithm has converged.
> > -        - name: AeStateLocked
> > -          value: 3
> > -          description: The AE algorithm is locked.
> > -        - name: AeStateFlashRequired
> > -          value: 4
> > -          description: The AE algorithm would need a flash for good results
> > -        - name: AeStatePrecapture
> > -          value: 5
> > -          description: |
> > -            The AE algorithm has started a pre-capture metering session.
> > -            \sa AePrecaptureTrigger
> > -
> > -  - AwbState:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to report the current AWB algorithm state. Currently identical
> > -       to ANDROID_CONTROL_AWB_STATE.
> > -
> > -        Current state of the AWB algorithm.
> > -      enum:
> > -        - name: AwbStateInactive
> > -          value: 0
> > -          description: The AWB algorithm is inactive.
> > -        - name: AwbStateSearching
> > -          value: 1
> > -          description: The AWB algorithm has not converged yet.
> > -        - name: AwbConverged
> > -          value: 2
> > -          description: The AWB algorithm has converged.
> > -        - name: AwbLocked
> > -          value: 3
> > -          description: The AWB algorithm is locked.
> > -
> > -  - SensorRollingShutterSkew:
> > -      type: int64_t
> > -      draft: true
> > -      description: |
> > -       Control to report the time between the start of exposure of the first
> > -       row and the start of exposure of the last row. Currently identical to
> > -       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> > -
> > -  - LensShadingMapMode:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -       Control to report if the lens shading map is available. Currently
> > -       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> > -      enum:
> > -        - name: LensShadingMapModeOff
> > -          value: 0
> > -          description: No lens shading map mode is available.
> > -        - name: LensShadingMapModeOn
> > -          value: 1
> > -          description: The lens shading map mode is available.
> > -
> > -  - PipelineDepth:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        Specifies the number of pipeline stages the frame went through from when
> > -        it was exposed to when the final completed result was available to the
> > -        framework. Always less than or equal to PipelineMaxDepth. Currently
> > -        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> > -
> > -        The typical value for this control is 3 as a frame is first exposed,
> > -        captured and then processed in a single pass through the ISP. Any
> > -        additional processing step performed after the ISP pass (in example face
> > -        detection, additional format conversions etc) count as an additional
> > -        pipeline stage.
> > -
> > -  - MaxLatency:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        The maximum number of frames that can occur after a request (different
> > -        than the previous) has been submitted, and before the result's state
> > -        becomes synchronized. A value of -1 indicates unknown latency, and 0
> > -        indicates per-frame control. Currently identical to
> > -        ANDROID_SYNC_MAX_LATENCY.
> > -
> > -  - TestPatternMode:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        Control to select the test pattern mode. Currently identical to
> > -        ANDROID_SENSOR_TEST_PATTERN_MODE.
> > -      enum:
> > -        - name: TestPatternModeOff
> > -          value: 0
> > -          description: |
> > -            No test pattern mode is used. The camera device returns frames from
> > -            the image sensor.
> > -        - name: TestPatternModeSolidColor
> > -          value: 1
> > -          description: |
> > -            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> > -            color channel provided in test pattern data.
> > -            \todo Add control for test pattern data.
> > -        - name: TestPatternModeColorBars
> > -          value: 2
> > -          description: |
> > -            All pixel data is replaced with an 8-bar color pattern. The vertical
> > -            bars (left-to-right) are as follows; white, yellow, cyan, green,
> > -            magenta, red, blue and black. Each bar should take up 1/8 of the
> > -            sensor pixel array width. When this is not possible, the bar size
> > -            should be rounded down to the nearest integer and the pattern can
> > -            repeat on the right side. Each bar's height must always take up the
> > -            full sensor pixel array height.
> > -        - name: TestPatternModeColorBarsFadeToGray
> > -          value: 3
> > -          description: |
> > -            The test pattern is similar to TestPatternModeColorBars,
> > -            except that each bar should start at its specified color at the top
> > -            and fade to gray at the bottom. Furthermore each bar is further
> > -            subdevided into a left and right half. The left half should have a
> > -            smooth gradient, and the right half should have a quantized
> > -            gradient. In particular, the right half's should consist of blocks
> > -            of the same color for 1/16th active sensor pixel array width. The
> > -            least significant bits in the quantized gradient should be copied
> > -            from the most significant bits of the smooth gradient. The height of
> > -            each bar should always be a multiple of 128. When this is not the
> > -            case, the pattern should repeat at the bottom of the image.
> > -        - name: TestPatternModePn9
> > -          value: 4
> > -          description: |
> > -            All pixel data is replaced by a pseudo-random sequence generated
> > -            from a PN9 512-bit sequence (typically implemented in hardware with
> > -            a linear feedback shift register). The generator should be reset at
> > -            the beginning of each frame, and thus each subsequent raw frame with
> > -            this test pattern should be exactly the same as the last.
> > -        - name: TestPatternModeCustom1
> > -          value: 256
> > -          description: |
> > -            The first custom test pattern. All custom patterns that are
> > -            available only on this camera device are at least this numeric
> > -            value. All of the custom test patterns will be static (that is the
> > -            raw image must not vary from frame to frame).
> > -
> >  ...
> > diff --git a/src/libcamera/control_ids_draft.yaml b/src/libcamera/control_ids_draft.yaml
> > new file mode 100644
> > index 000000000000..e4f53ea51d7a
> > --- /dev/null
> > +++ b/src/libcamera/control_ids_draft.yaml
> > @@ -0,0 +1,240 @@
> > +# SPDX-License-Identifier: LGPL-2.1-or-later
> > +#
> > +# Copyright (C) 2019, Google Inc.
> > +#
> > +%YAML 1.1
> > +---
> > +# Unless otherwise stated, all controls are bi-directional, i.e. they can be
> > +# set through Request::controls() and returned out through Request::metadata().
> > +vendor: draft
> > +controls:
> > +  - AePrecaptureTrigger:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +        Control for AE metering trigger. Currently identical to
> > +        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> > +
> > +        Whether the camera device will trigger a precapture metering sequence
> > +        when it processes this request.
> > +      enum:
> > +        - name: AePrecaptureTriggerIdle
> > +          value: 0
> > +          description: The trigger is idle.
> > +        - name: AePrecaptureTriggerStart
> > +          value: 1
> > +          description: The pre-capture AE metering is started by the camera.
> > +        - name: AePrecaptureTriggerCancel
> > +          value: 2
> > +          description: |
> > +            The camera will cancel any active or completed metering sequence.
> > +            The AE algorithm is reset to its initial state.
> > +
> > +  - NoiseReductionMode:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to select the noise reduction algorithm mode. Currently
> > +       identical to ANDROID_NOISE_REDUCTION_MODE.
> > +
> > +        Mode of operation for the noise reduction algorithm.
> > +      enum:
> > +        - name: NoiseReductionModeOff
> > +          value: 0
> > +          description: No noise reduction is applied
> > +        - name: NoiseReductionModeFast
> > +          value: 1
> > +          description: |
> > +            Noise reduction is applied without reducing the frame rate.
> > +        - name: NoiseReductionModeHighQuality
> > +          value: 2
> > +          description: |
> > +            High quality noise reduction at the expense of frame rate.
> > +        - name: NoiseReductionModeMinimal
> > +          value: 3
> > +          description: |
> > +            Minimal noise reduction is applied without reducing the frame rate.
> > +        - name: NoiseReductionModeZSL
> > +          value: 4
> > +          description: |
> > +            Noise reduction is applied at different levels to different streams.
> > +
> > +  - ColorCorrectionAberrationMode:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to select the color correction aberration mode. Currently
> > +       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> > +
> > +        Mode of operation for the chromatic aberration correction algorithm.
> > +      enum:
> > +        - name: ColorCorrectionAberrationOff
> > +          value: 0
> > +          description: No aberration correction is applied.
> > +        - name: ColorCorrectionAberrationFast
> > +          value: 1
> > +          description: Aberration correction will not slow down the frame rate.
> > +        - name: ColorCorrectionAberrationHighQuality
> > +          value: 2
> > +          description: |
> > +            High quality aberration correction which might reduce the frame
> > +            rate.
> > +
> > +  - AeState:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to report the current AE algorithm state. Currently identical to
> > +       ANDROID_CONTROL_AE_STATE.
> > +
> > +        Current state of the AE algorithm.
> > +      enum:
> > +        - name: AeStateInactive
> > +          value: 0
> > +          description: The AE algorithm is inactive.
> > +        - name: AeStateSearching
> > +          value: 1
> > +          description: The AE algorithm has not converged yet.
> > +        - name: AeStateConverged
> > +          value: 2
> > +          description: The AE algorithm has converged.
> > +        - name: AeStateLocked
> > +          value: 3
> > +          description: The AE algorithm is locked.
> > +        - name: AeStateFlashRequired
> > +          value: 4
> > +          description: The AE algorithm would need a flash for good results
> > +        - name: AeStatePrecapture
> > +          value: 5
> > +          description: |
> > +            The AE algorithm has started a pre-capture metering session.
> > +            \sa AePrecaptureTrigger
> > +
> > +  - AwbState:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to report the current AWB algorithm state. Currently identical
> > +       to ANDROID_CONTROL_AWB_STATE.
> > +
> > +        Current state of the AWB algorithm.
> > +      enum:
> > +        - name: AwbStateInactive
> > +          value: 0
> > +          description: The AWB algorithm is inactive.
> > +        - name: AwbStateSearching
> > +          value: 1
> > +          description: The AWB algorithm has not converged yet.
> > +        - name: AwbConverged
> > +          value: 2
> > +          description: The AWB algorithm has converged.
> > +        - name: AwbLocked
> > +          value: 3
> > +          description: The AWB algorithm is locked.
> > +
> > +  - SensorRollingShutterSkew:
> > +      type: int64_t
> > +      draft: true
> > +      description: |
> > +       Control to report the time between the start of exposure of the first
> > +       row and the start of exposure of the last row. Currently identical to
> > +       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> > +
> > +  - LensShadingMapMode:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +       Control to report if the lens shading map is available. Currently
> > +       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> > +      enum:
> > +        - name: LensShadingMapModeOff
> > +          value: 0
> > +          description: No lens shading map mode is available.
> > +        - name: LensShadingMapModeOn
> > +          value: 1
> > +          description: The lens shading map mode is available.
> > +
> > +  - PipelineDepth:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +        Specifies the number of pipeline stages the frame went through from when
> > +        it was exposed to when the final completed result was available to the
> > +        framework. Always less than or equal to PipelineMaxDepth. Currently
> > +        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> > +
> > +        The typical value for this control is 3 as a frame is first exposed,
> > +        captured and then processed in a single pass through the ISP. Any
> > +        additional processing step performed after the ISP pass (in example face
> > +        detection, additional format conversions etc) count as an additional
> > +        pipeline stage.
> > +
> > +  - MaxLatency:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +        The maximum number of frames that can occur after a request (different
> > +        than the previous) has been submitted, and before the result's state
> > +        becomes synchronized. A value of -1 indicates unknown latency, and 0
> > +        indicates per-frame control. Currently identical to
> > +        ANDROID_SYNC_MAX_LATENCY.
> > +
> > +  - TestPatternMode:
> > +      type: int32_t
> > +      draft: true
> > +      description: |
> > +        Control to select the test pattern mode. Currently identical to
> > +        ANDROID_SENSOR_TEST_PATTERN_MODE.
> > +      enum:
> > +        - name: TestPatternModeOff
> > +          value: 0
> > +          description: |
> > +            No test pattern mode is used. The camera device returns frames from
> > +            the image sensor.
> > +        - name: TestPatternModeSolidColor
> > +          value: 1
> > +          description: |
> > +            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> > +            color channel provided in test pattern data.
> > +            \todo Add control for test pattern data.
> > +        - name: TestPatternModeColorBars
> > +          value: 2
> > +          description: |
> > +            All pixel data is replaced with an 8-bar color pattern. The vertical
> > +            bars (left-to-right) are as follows; white, yellow, cyan, green,
> > +            magenta, red, blue and black. Each bar should take up 1/8 of the
> > +            sensor pixel array width. When this is not possible, the bar size
> > +            should be rounded down to the nearest integer and the pattern can
> > +            repeat on the right side. Each bar's height must always take up the
> > +            full sensor pixel array height.
> > +        - name: TestPatternModeColorBarsFadeToGray
> > +          value: 3
> > +          description: |
> > +            The test pattern is similar to TestPatternModeColorBars,
> > +            except that each bar should start at its specified color at the top
> > +            and fade to gray at the bottom. Furthermore each bar is further
> > +            subdevided into a left and right half. The left half should have a
> > +            smooth gradient, and the right half should have a quantized
> > +            gradient. In particular, the right half's should consist of blocks
> > +            of the same color for 1/16th active sensor pixel array width. The
> > +            least significant bits in the quantized gradient should be copied
> > +            from the most significant bits of the smooth gradient. The height of
> > +            each bar should always be a multiple of 128. When this is not the
> > +            case, the pattern should repeat at the bottom of the image.
> > +        - name: TestPatternModePn9
> > +          value: 4
> > +          description: |
> > +            All pixel data is replaced by a pseudo-random sequence generated
> > +            from a PN9 512-bit sequence (typically implemented in hardware with
> > +            a linear feedback shift register). The generator should be reset at
> > +            the beginning of each frame, and thus each subsequent raw frame with
> > +            this test pattern should be exactly the same as the last.
> > +        - name: TestPatternModeCustom1
> > +          value: 256
> > +          description: |
> > +            The first custom test pattern. All custom patterns that are
> > +            available only on this camera device are at least this numeric
> > +            value. All of the custom test patterns will be static (that is the
> > +            raw image must not vary from frame to frame).
> > +
> > +...
> > diff --git a/src/libcamera/property_ids.cpp.in b/src/libcamera/property_ids.cpp.in
> > index 0771ac5c091f..8b274c38c74b 100644
> > --- a/src/libcamera/property_ids.cpp.in
> > +++ b/src/libcamera/property_ids.cpp.in
> > @@ -23,15 +23,6 @@ namespace properties {
> >
> >  ${controls_doc}
> >
> > -/**
> > - * \brief Namespace for libcamera draft properties
> > - */
> > -namespace draft {
> > -
> > -${draft_controls_doc}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls_doc}
> >
> >  #ifndef __DOXYGEN__
> > @@ -41,13 +32,8 @@ ${vendor_controls_doc}
> >   */
> >  ${controls_def}
> >
> > -namespace draft {
> > -
> > -${draft_controls_def}
> > -
> > -} /* namespace draft */
> > -
> >  ${vendor_controls_def}
> > +
> >  #endif
> >
> >  /**
> > diff --git a/src/libcamera/property_ids_core.yaml b/src/libcamera/property_ids_core.yaml
> > index 45f3609b4236..834454a4e087 100644
> > --- a/src/libcamera/property_ids_core.yaml
> > +++ b/src/libcamera/property_ids_core.yaml
> > @@ -701,37 +701,4 @@ controls:
> >
> >          Different cameras may report identical devices.
> >
> > -  # ----------------------------------------------------------------------------
> > -  # Draft properties section
> > -
> > -  - ColorFilterArrangement:
> > -      type: int32_t
> > -      draft: true
> > -      description: |
> > -        The arrangement of color filters on sensor; represents the colors in the
> > -        top-left 2x2 section of the sensor, in reading order. Currently
> > -        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> > -      enum:
> > -        - name: RGGB
> > -          value: 0
> > -          description: RGGB Bayer pattern
> > -        - name: GRBG
> > -          value: 1
> > -          description: GRBG Bayer pattern
> > -        - name: GBRG
> > -          value: 2
> > -          description: GBRG Bayer pattern
> > -        - name: BGGR
> > -          value: 3
> > -          description: BGGR Bayer pattern
> > -        - name: RGB
> > -          value: 4
> > -          description: |
> > -            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> > -            instead of just 1 16-bit value per pixel.
> > -        - name: MONO
> > -          value: 5
> > -          description: |
> > -            Sensor is not Bayer; output consists of a single colour channel.
> > -
> >  ...
> > diff --git a/src/libcamera/property_ids_draft.yaml b/src/libcamera/property_ids_draft.yaml
> > new file mode 100644
> > index 000000000000..62f0e242d0c6
> > --- /dev/null
> > +++ b/src/libcamera/property_ids_draft.yaml
> > @@ -0,0 +1,39 @@
> > +# SPDX-License-Identifier: LGPL-2.1-or-later
> > +#
> > +# Copyright (C) 2019, Google Inc.
> > +#
> > +%YAML 1.1
> > +---
> > +vendor: draft
> > +controls:
> > +  - ColorFilterArrangement:
> > +      type: int32_t
> > +      vendor: draft
> > +      description: |
> > +        The arrangement of color filters on sensor; represents the colors in the
> > +        top-left 2x2 section of the sensor, in reading order. Currently
> > +        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> > +      enum:
> > +        - name: RGGB
> > +          value: 0
> > +          description: RGGB Bayer pattern
> > +        - name: GRBG
> > +          value: 1
> > +          description: GRBG Bayer pattern
> > +        - name: GBRG
> > +          value: 2
> > +          description: GBRG Bayer pattern
> > +        - name: BGGR
> > +          value: 3
> > +          description: BGGR Bayer pattern
> > +        - name: RGB
> > +          value: 4
> > +          description: |
> > +            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> > +            instead of just 1 16-bit value per pixel.
> > +        - name: MONO
> > +          value: 5
> > +          description: |
> > +            Sensor is not Bayer; output consists of a single colour channel.
> > +
> > +...
> > diff --git a/src/py/libcamera/gen-py-controls.py b/src/py/libcamera/gen-py-controls.py
> > index 8ae8d5126e39..55e0b4e8e3d6 100755
> > --- a/src/py/libcamera/gen-py-controls.py
> > +++ b/src/py/libcamera/gen-py-controls.py
> > @@ -36,10 +36,7 @@ def generate_py(controls, mode):
> >                  vendor_defs.append('\tauto {} = py::class_<Py{}Controls>(controls, \"{}\");'.format(vendor, vendor, vendor))
> >                  vendors.append(vendor)
> >
> > -            if ctrl.get('draft'):
> > -                ns = 'libcamera::{}::draft::'.format(mode)
> > -                container = 'draft'
> > -            elif vendor != 'libcamera':
> > +            if vendor != 'libcamera':
> >                  ns = 'libcamera::{}::{}::'.format(mode, vendor)
> >                  container = vendor
> >              else:
> > diff --git a/src/py/libcamera/py_controls_generated.cpp.in b/src/py/libcamera/py_controls_generated.cpp.in
> > index ec4b55ef2011..8d282ce51856 100644
> > --- a/src/py/libcamera/py_controls_generated.cpp.in
> > +++ b/src/py/libcamera/py_controls_generated.cpp.in
> > @@ -17,16 +17,11 @@ class PyControls
> >  {
> >  };
> >
> > -class PyDraftControls
> > -{
> > -};
> > -
> >  ${vendors_class_def}
> >
> >  void init_py_controls_generated(py::module& m)
> >  {
> >         auto controls = py::class_<PyControls>(m, "controls");
> > -       auto draft = py::class_<PyDraftControls>(controls, "draft");
> >  ${vendors_defs}
> >
> >  ${controls}
> > diff --git a/src/py/libcamera/py_properties_generated.cpp.in b/src/py/libcamera/py_properties_generated.cpp.in
> > index f7b5ec8c635d..ae61c5440d31 100644
> > --- a/src/py/libcamera/py_properties_generated.cpp.in
> > +++ b/src/py/libcamera/py_properties_generated.cpp.in
> > @@ -26,7 +26,6 @@ ${vendors_class_def}
> >  void init_py_properties_generated(py::module& m)
> >  {
> >         auto controls = py::class_<PyProperties>(m, "properties");
> > -       auto draft = py::class_<PyDraftProperties>(controls, "draft");
> >  ${vendors_defs}
> >
> >  ${controls}
> > diff --git a/utils/gen-controls.py b/utils/gen-controls.py
> > index 04c63098b19b..45da571e83e0 100755
> > --- a/utils/gen-controls.py
> > +++ b/utils/gen-controls.py
> > @@ -86,11 +86,6 @@ class Control(object):
> >          """Is the control an enumeration"""
> >          return self.__enum_values is not None
> >
> > -    @property
> > -    def is_draft(self):
> > -        """Is the control a draft control"""
> > -        return self.__data.get('draft') is not None
> > -
> >      @property
> >      def vendor(self):
> >          """The vendor string, or None"""
> > @@ -101,12 +96,6 @@ class Control(object):
> >          """The control name (CamelCase)"""
> >          return self.__name
> >
> > -    @property
> > -    def q_name(self):
> > -        """The control name, qualified with a namespace"""
> > -        ns = 'draft::' if self.is_draft else ''
> > -        return ns + self.__name
> > -
> >      @property
> >      def type(self):
> >          typ = self.__data.get('type')
> > @@ -159,7 +148,7 @@ ${description}
> >      for ctrl in controls:
> >          id_name = snake_case(ctrl.name).upper()
> >
> > -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> > +        vendor = ctrl.vendor
> >          if vendor not in ctrls_doc:
> >              ctrls_doc[vendor] = []
> >              ctrls_def[vendor] = []
> > @@ -208,7 +197,8 @@ ${description}
> >          target_doc.append(doc_template.substitute(info))
> >          target_def.append(def_template.substitute(info))
> >
> > -        ctrls_map.append('\t{ ' + id_name + ', &' + ctrl.q_name + ' },')
> > +        vendor_ns = vendor + '::' if vendor != "libcamera" else ''
> > +        ctrls_map.append('\t{ ' + vendor_ns + id_name + ', &' + vendor_ns + ctrl.name + ' },')
> >
> >      vendor_ctrl_doc_sub = []
> >      vendor_ctrl_template = string.Template('''
> > @@ -218,18 +208,16 @@ ${vendor_controls_str}
> >
> >  } /* namespace ${vendor} */''')
> >
> > -    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera', 'draft']]:
> > +    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera']]:
> >          vendor_ctrl_doc_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n\n'.join(ctrls_doc[vendor])}))
> >
> >      vendor_ctrl_def_sub = []
> > -    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera', 'draft']]:
> > +    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera']]:
> >          vendor_ctrl_def_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n'.join(ctrls_def[vendor])}))
> >
> >      return {
> >          'controls_doc': '\n\n'.join(ctrls_doc['libcamera']),
> >          'controls_def': '\n'.join(ctrls_def['libcamera']),
> > -        'draft_controls_doc': '\n\n'.join(ctrls_doc['draft']),
> > -        'draft_controls_def': '\n\n'.join(ctrls_def['draft']),
> >          'controls_map': '\n'.join(ctrls_map),
> >          'vendor_controls_doc': '\n'.join(vendor_ctrl_doc_sub),
> >          'vendor_controls_def': '\n'.join(vendor_ctrl_def_sub),
> > @@ -249,7 +237,7 @@ def generate_h(controls, mode, ranges):
> >      for ctrl in controls:
> >          id_name = snake_case(ctrl.name).upper()
> >
> > -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> > +        vendor = ctrl.vendor
> >          if vendor not in ctrls:
> >              if vendor not in ranges.keys():
> >                  raise RuntimeError(f'Control id range is not defined for vendor {vendor}')
> > @@ -257,8 +245,7 @@ def generate_h(controls, mode, ranges):
> >              ids[vendor] = []
> >              ctrls[vendor] = []
> >
> > -        # Core and draft controls use the same ID value
> > -        target_ids = ids['libcamera'] if vendor in ['libcamera', 'draft'] else ids[vendor]
> > +        target_ids = ids[vendor]
> >          target_ids.append('\t' + id_name + ' = ' + str(id_value[vendor]) + ',')
> >
> >          info = {
> > @@ -266,11 +253,7 @@ def generate_h(controls, mode, ranges):
> >              'type': ctrl.type,
> >          }
> >
> > -        target_ctrls = ctrls['libcamera']
> > -        if ctrl.is_draft:
> > -            target_ctrls = ctrls['draft']
> > -        elif vendor != 'libcamera':
> > -            target_ctrls = ctrls[vendor]
> > +        target_ctrls = ctrls[vendor]
> >
> >          if ctrl.is_enum:
> >              target_ctrls.append(enum_template_start.substitute(info))
> > @@ -309,7 +292,7 @@ ${vendor_controls}
> >  ''')
> >
> >      vendor_sub = []
> > -    for vendor in [v for v in ctrls.keys() if v not in ['libcamera', 'draft']]:
> > +    for vendor in [v for v in ctrls.keys() if v != 'libcamera']:
> >          vendor_sub.append(vendor_template.substitute({'mode': mode.upper(),
> >                                                        'vendor': vendor,
> >                                                        'vendor_def': vendor.upper(),
> > @@ -319,7 +302,6 @@ ${vendor_controls}
> >      return {
> >          'ids': '\n'.join(ids['libcamera']),
> >          'controls': '\n'.join(ctrls['libcamera']),
> > -        'draft_controls': '\n'.join(ctrls['draft']),
> >          'vendor_controls': '\n'.join(vendor_sub)
> >      }
> >
Naushir Patuck Nov. 30, 2023, 1:43 p.m. UTC | #7
Hi Laurent,

On Thu, 30 Nov 2023 at 12:57, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Naush,
>
> On Wed, Nov 29, 2023 at 09:11:47AM +0000, Naushir Patuck via libcamera-devel wrote:
> > Hi Kieran and Jacopo,
> >
> > Version 3 of this patch introduces a minor regression in the python
> > bindings.  The fix is quite simple:
> >
> > diff --git a/src/py/libcamera/gen-py-controls.py
> > b/src/py/libcamera/gen-py-controls.py
> > index 55e0b4e8e3d6..d0150598ba43 100755
> > --- a/src/py/libcamera/gen-py-controls.py
> > +++ b/src/py/libcamera/gen-py-controls.py
> > @@ -32,8 +32,9 @@ def generate_py(controls, mode):
> >              name, ctrl = ctrls.popitem()
> >
> >              if vendor not in vendors and vendor != 'libcamera':
> > -                vendors_class_def.append('class Py{}Controls\n{{\n}};\n'.format(vendor))
> > -                vendor_defs.append('\tauto {} = py::class_<Py{}Controls>(controls, \"{}\");'.format(vendor, vendor, vendor))
> > +                vendor_mode_str = f'{vendor}{mode.capitalize()}'
> > +                vendors_class_def.append('class Py{}\n{{\n}};\n'.format(vendor_mode_str))
> > +                vendor_defs.append('\tauto {} = py::class_<Py{}>(controls, \"{}\");'.format(vendor, vendor_mode_str, vendor))
> >                  vendors.append(vendor)
>
> I tested this locally, and still see
>
>         auto controls = py::class_<PyControls>(m, "controls");
>         auto draft = py::class_<PydraftControls>(controls, "draft");
>         auto rpi = py::class_<PyrpiControls>(controls, "rpi");
>
> vs.
>
>         auto controls = py::class_<PyProperties>(m, "properties");
>         auto draft = py::class_<PydraftProperties>(controls, "draft");
>
> which looks good for the mode. I wonder though, shouldn't we also
> capitalize the vendor name ?

Yes, I'll make that change.

>
> > Given you both have tagged this already, are you ok to keep your tags?
> > If so, I'll make a git-request-pull for this series.
> >
> > On Fri, 24 Nov 2023 at 12:37, Naushir Patuck <naush@raspberrypi.com> wrote:
> > >
> > > Label draft controls and properties through the "draft" vendor tag
> > > and deprecate the existing "draft: true" mechanism. This uses the new
> > > vendor tags mechanism to place draft controls in the same
> > > libcamera::controls::draft namespace and provide a defined control id
> > > range for these controls. This requires moving all draft controls from
> > > control_ids.yaml to control_ids_draft.yaml.
> > >
> > > One breaking change in this commit is that draft control ids also move
> > > to the libcamera::controls::draft namespace from the existing
> > > libcamera::controls namespace. This is desirable to avoid API breakages
> > > when adding new libcamera controls. So, for example, the use of
> > > controls::NOISE_REDUCTION_MODE will need to be replaced with
> > > controls::draft::NOISE_REDUCTION_MODE.
> > >
> > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > > ---
> > >  include/libcamera/control_ids.h.in            |   6 -
> > >  include/libcamera/meson.build                 |   2 +
> > >  include/libcamera/property_ids.h.in           |   6 -
> > >  src/ipa/rpi/common/ipa_base.cpp               |   2 +-
> > >  src/ipa/rpi/vc4/vc4.cpp                       |   2 +-
> > >  src/libcamera/control_ids.cpp.in              |  16 +-
> > >  src/libcamera/control_ids_core.yaml           | 232 -----------------
> > >  src/libcamera/control_ids_draft.yaml          | 240 ++++++++++++++++++
> > >  src/libcamera/property_ids.cpp.in             |  16 +-
> > >  src/libcamera/property_ids_core.yaml          |  33 ---
> > >  src/libcamera/property_ids_draft.yaml         |  39 +++
> > >  src/py/libcamera/gen-py-controls.py           |   5 +-
> > >  src/py/libcamera/py_controls_generated.cpp.in |   5 -
> > >  .../libcamera/py_properties_generated.cpp.in  |   1 -
> > >  utils/gen-controls.py                         |  36 +--
> > >  15 files changed, 295 insertions(+), 346 deletions(-)
> > >  create mode 100644 src/libcamera/control_ids_draft.yaml
> > >  create mode 100644 src/libcamera/property_ids_draft.yaml
> > >
> > > diff --git a/include/libcamera/control_ids.h.in b/include/libcamera/control_ids.h.in
> > > index c97b09a82450..d53b1cf7beb2 100644
> > > --- a/include/libcamera/control_ids.h.in
> > > +++ b/include/libcamera/control_ids.h.in
> > > @@ -26,12 +26,6 @@ ${controls}
> > >
> > >  extern const ControlIdMap controls;
> > >
> > > -namespace draft {
> > > -
> > > -${draft_controls}
> > > -
> > > -} /* namespace draft */
> > > -
> > >  ${vendor_controls}
> > >
> > >  } /* namespace controls */
> > > diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> > > index 79187d3fdfc9..1504f741ae2f 100644
> > > --- a/include/libcamera/meson.build
> > > +++ b/include/libcamera/meson.build
> > > @@ -34,10 +34,12 @@ libcamera_headers_install_dir = get_option('includedir') / libcamera_include_dir
> > >
> > >  controls_map = {
> > >      'controls': {
> > > +        'draft': 'control_ids_draft.yaml',
> > >          'core': 'control_ids_core.yaml',
> > >      },
> > >
> > >      'properties': {
> > > +        'draft': 'property_ids_draft.yaml',
> > >          'core': 'property_ids_core.yaml',
> > >      }
> > >  }
> > > diff --git a/include/libcamera/property_ids.h.in b/include/libcamera/property_ids.h.in
> > > index 47c5d6bf2e28..43372c718fc9 100644
> > > --- a/include/libcamera/property_ids.h.in
> > > +++ b/include/libcamera/property_ids.h.in
> > > @@ -23,12 +23,6 @@ ${ids}
> > >
> > >  ${controls}
> > >
> > > -namespace draft {
> > > -
> > > -${draft_controls}
> > > -
> > > -} /* namespace draft */
> > > -
> > >  extern const ControlIdMap properties;
> > >
> > >  ${vendor_controls}
> > > diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp
> > > index a1fec3aa3dd1..6ac9d5de2f88 100644
> > > --- a/src/ipa/rpi/common/ipa_base.cpp
> > > +++ b/src/ipa/rpi/common/ipa_base.cpp
> > > @@ -1024,7 +1024,7 @@ void IpaBase::applyControls(const ControlList &controls)
> > >                         break;
> > >                 }
> > >
> > > -               case controls::NOISE_REDUCTION_MODE:
> > > +               case controls::draft::NOISE_REDUCTION_MODE:
> > >                         /* Handled below in handleControls() */
> > >                         libcameraMetadata_.set(controls::draft::NoiseReductionMode,
> > >                                                ctrl.second.get<int32_t>());
> > > diff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp
> > > index c4baf04fb1e7..c165a5b8b0b6 100644
> > > --- a/src/ipa/rpi/vc4/vc4.cpp
> > > +++ b/src/ipa/rpi/vc4/vc4.cpp
> > > @@ -260,7 +260,7 @@ void IpaVc4::handleControls(const ControlList &controls)
> > >
> > >         for (auto const &ctrl : controls) {
> > >                 switch (ctrl.first) {
> > > -               case controls::NOISE_REDUCTION_MODE: {
> > > +               case controls::draft::NOISE_REDUCTION_MODE: {
> > >                         RPiController::DenoiseAlgorithm *sdn = dynamic_cast<RPiController::DenoiseAlgorithm *>(
> > >                                 controller_.getAlgorithm("SDN"));
> > >                         /* Some platforms may have a combined "denoise" algorithm instead. */
> > > diff --git a/src/libcamera/control_ids.cpp.in b/src/libcamera/control_ids.cpp.in
> > > index be86548cf73f..d283c1c1f401 100644
> > > --- a/src/libcamera/control_ids.cpp.in
> > > +++ b/src/libcamera/control_ids.cpp.in
> > > @@ -24,15 +24,6 @@ namespace controls {
> > >
> > >  ${controls_doc}
> > >
> > > -/**
> > > - * \brief Namespace for libcamera draft controls
> > > - */
> > > -namespace draft {
> > > -
> > > -${draft_controls_doc}
> > > -
> > > -} /* namespace draft */
> > > -
> > >  ${vendor_controls_doc}
> > >
> > >  #ifndef __DOXYGEN__
> > > @@ -42,13 +33,8 @@ ${vendor_controls_doc}
> > >   */
> > >  ${controls_def}
> > >
> > > -namespace draft {
> > > -
> > > -${draft_controls_def}
> > > -
> > > -} /* namespace draft */
> > > -
> > >  ${vendor_controls_def}
> > > +
> > >  #endif
> > >
> > >  /**
> > > diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml
> > > index ff74ce1deedb..76fb9347d8e3 100644
> > > --- a/src/libcamera/control_ids_core.yaml
> > > +++ b/src/libcamera/control_ids_core.yaml
> > > @@ -865,236 +865,4 @@ controls:
> > >            description: |
> > >              This is a long exposure image.
> > >
> > > -  # ----------------------------------------------------------------------------
> > > -  # Draft controls section
> > > -
> > > -  - AePrecaptureTrigger:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -        Control for AE metering trigger. Currently identical to
> > > -        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> > > -
> > > -        Whether the camera device will trigger a precapture metering sequence
> > > -        when it processes this request.
> > > -      enum:
> > > -        - name: AePrecaptureTriggerIdle
> > > -          value: 0
> > > -          description: The trigger is idle.
> > > -        - name: AePrecaptureTriggerStart
> > > -          value: 1
> > > -          description: The pre-capture AE metering is started by the camera.
> > > -        - name: AePrecaptureTriggerCancel
> > > -          value: 2
> > > -          description: |
> > > -            The camera will cancel any active or completed metering sequence.
> > > -            The AE algorithm is reset to its initial state.
> > > -
> > > -  - NoiseReductionMode:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -       Control to select the noise reduction algorithm mode. Currently
> > > -       identical to ANDROID_NOISE_REDUCTION_MODE.
> > > -
> > > -        Mode of operation for the noise reduction algorithm.
> > > -      enum:
> > > -        - name: NoiseReductionModeOff
> > > -          value: 0
> > > -          description: No noise reduction is applied
> > > -        - name: NoiseReductionModeFast
> > > -          value: 1
> > > -          description: |
> > > -            Noise reduction is applied without reducing the frame rate.
> > > -        - name: NoiseReductionModeHighQuality
> > > -          value: 2
> > > -          description: |
> > > -            High quality noise reduction at the expense of frame rate.
> > > -        - name: NoiseReductionModeMinimal
> > > -          value: 3
> > > -          description: |
> > > -            Minimal noise reduction is applied without reducing the frame rate.
> > > -        - name: NoiseReductionModeZSL
> > > -          value: 4
> > > -          description: |
> > > -            Noise reduction is applied at different levels to different streams.
> > > -
> > > -  - ColorCorrectionAberrationMode:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -       Control to select the color correction aberration mode. Currently
> > > -       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> > > -
> > > -        Mode of operation for the chromatic aberration correction algorithm.
> > > -      enum:
> > > -        - name: ColorCorrectionAberrationOff
> > > -          value: 0
> > > -          description: No aberration correction is applied.
> > > -        - name: ColorCorrectionAberrationFast
> > > -          value: 1
> > > -          description: Aberration correction will not slow down the frame rate.
> > > -        - name: ColorCorrectionAberrationHighQuality
> > > -          value: 2
> > > -          description: |
> > > -            High quality aberration correction which might reduce the frame
> > > -            rate.
> > > -
> > > -  - AeState:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -       Control to report the current AE algorithm state. Currently identical to
> > > -       ANDROID_CONTROL_AE_STATE.
> > > -
> > > -        Current state of the AE algorithm.
> > > -      enum:
> > > -        - name: AeStateInactive
> > > -          value: 0
> > > -          description: The AE algorithm is inactive.
> > > -        - name: AeStateSearching
> > > -          value: 1
> > > -          description: The AE algorithm has not converged yet.
> > > -        - name: AeStateConverged
> > > -          value: 2
> > > -          description: The AE algorithm has converged.
> > > -        - name: AeStateLocked
> > > -          value: 3
> > > -          description: The AE algorithm is locked.
> > > -        - name: AeStateFlashRequired
> > > -          value: 4
> > > -          description: The AE algorithm would need a flash for good results
> > > -        - name: AeStatePrecapture
> > > -          value: 5
> > > -          description: |
> > > -            The AE algorithm has started a pre-capture metering session.
> > > -            \sa AePrecaptureTrigger
> > > -
> > > -  - AwbState:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -       Control to report the current AWB algorithm state. Currently identical
> > > -       to ANDROID_CONTROL_AWB_STATE.
> > > -
> > > -        Current state of the AWB algorithm.
> > > -      enum:
> > > -        - name: AwbStateInactive
> > > -          value: 0
> > > -          description: The AWB algorithm is inactive.
> > > -        - name: AwbStateSearching
> > > -          value: 1
> > > -          description: The AWB algorithm has not converged yet.
> > > -        - name: AwbConverged
> > > -          value: 2
> > > -          description: The AWB algorithm has converged.
> > > -        - name: AwbLocked
> > > -          value: 3
> > > -          description: The AWB algorithm is locked.
> > > -
> > > -  - SensorRollingShutterSkew:
> > > -      type: int64_t
> > > -      draft: true
> > > -      description: |
> > > -       Control to report the time between the start of exposure of the first
> > > -       row and the start of exposure of the last row. Currently identical to
> > > -       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> > > -
> > > -  - LensShadingMapMode:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -       Control to report if the lens shading map is available. Currently
> > > -       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> > > -      enum:
> > > -        - name: LensShadingMapModeOff
> > > -          value: 0
> > > -          description: No lens shading map mode is available.
> > > -        - name: LensShadingMapModeOn
> > > -          value: 1
> > > -          description: The lens shading map mode is available.
> > > -
> > > -  - PipelineDepth:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -        Specifies the number of pipeline stages the frame went through from when
> > > -        it was exposed to when the final completed result was available to the
> > > -        framework. Always less than or equal to PipelineMaxDepth. Currently
> > > -        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> > > -
> > > -        The typical value for this control is 3 as a frame is first exposed,
> > > -        captured and then processed in a single pass through the ISP. Any
> > > -        additional processing step performed after the ISP pass (in example face
> > > -        detection, additional format conversions etc) count as an additional
> > > -        pipeline stage.
> > > -
> > > -  - MaxLatency:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -        The maximum number of frames that can occur after a request (different
> > > -        than the previous) has been submitted, and before the result's state
> > > -        becomes synchronized. A value of -1 indicates unknown latency, and 0
> > > -        indicates per-frame control. Currently identical to
> > > -        ANDROID_SYNC_MAX_LATENCY.
> > > -
> > > -  - TestPatternMode:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -        Control to select the test pattern mode. Currently identical to
> > > -        ANDROID_SENSOR_TEST_PATTERN_MODE.
> > > -      enum:
> > > -        - name: TestPatternModeOff
> > > -          value: 0
> > > -          description: |
> > > -            No test pattern mode is used. The camera device returns frames from
> > > -            the image sensor.
> > > -        - name: TestPatternModeSolidColor
> > > -          value: 1
> > > -          description: |
> > > -            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> > > -            color channel provided in test pattern data.
> > > -            \todo Add control for test pattern data.
> > > -        - name: TestPatternModeColorBars
> > > -          value: 2
> > > -          description: |
> > > -            All pixel data is replaced with an 8-bar color pattern. The vertical
> > > -            bars (left-to-right) are as follows; white, yellow, cyan, green,
> > > -            magenta, red, blue and black. Each bar should take up 1/8 of the
> > > -            sensor pixel array width. When this is not possible, the bar size
> > > -            should be rounded down to the nearest integer and the pattern can
> > > -            repeat on the right side. Each bar's height must always take up the
> > > -            full sensor pixel array height.
> > > -        - name: TestPatternModeColorBarsFadeToGray
> > > -          value: 3
> > > -          description: |
> > > -            The test pattern is similar to TestPatternModeColorBars,
> > > -            except that each bar should start at its specified color at the top
> > > -            and fade to gray at the bottom. Furthermore each bar is further
> > > -            subdevided into a left and right half. The left half should have a
> > > -            smooth gradient, and the right half should have a quantized
> > > -            gradient. In particular, the right half's should consist of blocks
> > > -            of the same color for 1/16th active sensor pixel array width. The
> > > -            least significant bits in the quantized gradient should be copied
> > > -            from the most significant bits of the smooth gradient. The height of
> > > -            each bar should always be a multiple of 128. When this is not the
> > > -            case, the pattern should repeat at the bottom of the image.
> > > -        - name: TestPatternModePn9
> > > -          value: 4
> > > -          description: |
> > > -            All pixel data is replaced by a pseudo-random sequence generated
> > > -            from a PN9 512-bit sequence (typically implemented in hardware with
> > > -            a linear feedback shift register). The generator should be reset at
> > > -            the beginning of each frame, and thus each subsequent raw frame with
> > > -            this test pattern should be exactly the same as the last.
> > > -        - name: TestPatternModeCustom1
> > > -          value: 256
> > > -          description: |
> > > -            The first custom test pattern. All custom patterns that are
> > > -            available only on this camera device are at least this numeric
> > > -            value. All of the custom test patterns will be static (that is the
> > > -            raw image must not vary from frame to frame).
> > > -
> > >  ...
> > > diff --git a/src/libcamera/control_ids_draft.yaml b/src/libcamera/control_ids_draft.yaml
> > > new file mode 100644
> > > index 000000000000..e4f53ea51d7a
> > > --- /dev/null
> > > +++ b/src/libcamera/control_ids_draft.yaml
> > > @@ -0,0 +1,240 @@
> > > +# SPDX-License-Identifier: LGPL-2.1-or-later
> > > +#
> > > +# Copyright (C) 2019, Google Inc.
> > > +#
> > > +%YAML 1.1
> > > +---
> > > +# Unless otherwise stated, all controls are bi-directional, i.e. they can be
> > > +# set through Request::controls() and returned out through Request::metadata().
> > > +vendor: draft
> > > +controls:
> > > +  - AePrecaptureTrigger:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +        Control for AE metering trigger. Currently identical to
> > > +        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
> > > +
> > > +        Whether the camera device will trigger a precapture metering sequence
> > > +        when it processes this request.
> > > +      enum:
> > > +        - name: AePrecaptureTriggerIdle
> > > +          value: 0
> > > +          description: The trigger is idle.
> > > +        - name: AePrecaptureTriggerStart
> > > +          value: 1
> > > +          description: The pre-capture AE metering is started by the camera.
> > > +        - name: AePrecaptureTriggerCancel
> > > +          value: 2
> > > +          description: |
> > > +            The camera will cancel any active or completed metering sequence.
> > > +            The AE algorithm is reset to its initial state.
> > > +
> > > +  - NoiseReductionMode:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +       Control to select the noise reduction algorithm mode. Currently
> > > +       identical to ANDROID_NOISE_REDUCTION_MODE.
> > > +
> > > +        Mode of operation for the noise reduction algorithm.
> > > +      enum:
> > > +        - name: NoiseReductionModeOff
> > > +          value: 0
> > > +          description: No noise reduction is applied
> > > +        - name: NoiseReductionModeFast
> > > +          value: 1
> > > +          description: |
> > > +            Noise reduction is applied without reducing the frame rate.
> > > +        - name: NoiseReductionModeHighQuality
> > > +          value: 2
> > > +          description: |
> > > +            High quality noise reduction at the expense of frame rate.
> > > +        - name: NoiseReductionModeMinimal
> > > +          value: 3
> > > +          description: |
> > > +            Minimal noise reduction is applied without reducing the frame rate.
> > > +        - name: NoiseReductionModeZSL
> > > +          value: 4
> > > +          description: |
> > > +            Noise reduction is applied at different levels to different streams.
> > > +
> > > +  - ColorCorrectionAberrationMode:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +       Control to select the color correction aberration mode. Currently
> > > +       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
> > > +
> > > +        Mode of operation for the chromatic aberration correction algorithm.
> > > +      enum:
> > > +        - name: ColorCorrectionAberrationOff
> > > +          value: 0
> > > +          description: No aberration correction is applied.
> > > +        - name: ColorCorrectionAberrationFast
> > > +          value: 1
> > > +          description: Aberration correction will not slow down the frame rate.
> > > +        - name: ColorCorrectionAberrationHighQuality
> > > +          value: 2
> > > +          description: |
> > > +            High quality aberration correction which might reduce the frame
> > > +            rate.
> > > +
> > > +  - AeState:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +       Control to report the current AE algorithm state. Currently identical to
> > > +       ANDROID_CONTROL_AE_STATE.
> > > +
> > > +        Current state of the AE algorithm.
> > > +      enum:
> > > +        - name: AeStateInactive
> > > +          value: 0
> > > +          description: The AE algorithm is inactive.
> > > +        - name: AeStateSearching
> > > +          value: 1
> > > +          description: The AE algorithm has not converged yet.
> > > +        - name: AeStateConverged
> > > +          value: 2
> > > +          description: The AE algorithm has converged.
> > > +        - name: AeStateLocked
> > > +          value: 3
> > > +          description: The AE algorithm is locked.
> > > +        - name: AeStateFlashRequired
> > > +          value: 4
> > > +          description: The AE algorithm would need a flash for good results
> > > +        - name: AeStatePrecapture
> > > +          value: 5
> > > +          description: |
> > > +            The AE algorithm has started a pre-capture metering session.
> > > +            \sa AePrecaptureTrigger
> > > +
> > > +  - AwbState:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +       Control to report the current AWB algorithm state. Currently identical
> > > +       to ANDROID_CONTROL_AWB_STATE.
> > > +
> > > +        Current state of the AWB algorithm.
> > > +      enum:
> > > +        - name: AwbStateInactive
> > > +          value: 0
> > > +          description: The AWB algorithm is inactive.
> > > +        - name: AwbStateSearching
> > > +          value: 1
> > > +          description: The AWB algorithm has not converged yet.
> > > +        - name: AwbConverged
> > > +          value: 2
> > > +          description: The AWB algorithm has converged.
> > > +        - name: AwbLocked
> > > +          value: 3
> > > +          description: The AWB algorithm is locked.
> > > +
> > > +  - SensorRollingShutterSkew:
> > > +      type: int64_t
> > > +      draft: true
> > > +      description: |
> > > +       Control to report the time between the start of exposure of the first
> > > +       row and the start of exposure of the last row. Currently identical to
> > > +       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
> > > +
> > > +  - LensShadingMapMode:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +       Control to report if the lens shading map is available. Currently
> > > +       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
> > > +      enum:
> > > +        - name: LensShadingMapModeOff
> > > +          value: 0
> > > +          description: No lens shading map mode is available.
> > > +        - name: LensShadingMapModeOn
> > > +          value: 1
> > > +          description: The lens shading map mode is available.
> > > +
> > > +  - PipelineDepth:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +        Specifies the number of pipeline stages the frame went through from when
> > > +        it was exposed to when the final completed result was available to the
> > > +        framework. Always less than or equal to PipelineMaxDepth. Currently
> > > +        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
> > > +
> > > +        The typical value for this control is 3 as a frame is first exposed,
> > > +        captured and then processed in a single pass through the ISP. Any
> > > +        additional processing step performed after the ISP pass (in example face
> > > +        detection, additional format conversions etc) count as an additional
> > > +        pipeline stage.
> > > +
> > > +  - MaxLatency:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +        The maximum number of frames that can occur after a request (different
> > > +        than the previous) has been submitted, and before the result's state
> > > +        becomes synchronized. A value of -1 indicates unknown latency, and 0
> > > +        indicates per-frame control. Currently identical to
> > > +        ANDROID_SYNC_MAX_LATENCY.
> > > +
> > > +  - TestPatternMode:
> > > +      type: int32_t
> > > +      draft: true
> > > +      description: |
> > > +        Control to select the test pattern mode. Currently identical to
> > > +        ANDROID_SENSOR_TEST_PATTERN_MODE.
> > > +      enum:
> > > +        - name: TestPatternModeOff
> > > +          value: 0
> > > +          description: |
> > > +            No test pattern mode is used. The camera device returns frames from
> > > +            the image sensor.
> > > +        - name: TestPatternModeSolidColor
> > > +          value: 1
> > > +          description: |
> > > +            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
> > > +            color channel provided in test pattern data.
> > > +            \todo Add control for test pattern data.
> > > +        - name: TestPatternModeColorBars
> > > +          value: 2
> > > +          description: |
> > > +            All pixel data is replaced with an 8-bar color pattern. The vertical
> > > +            bars (left-to-right) are as follows; white, yellow, cyan, green,
> > > +            magenta, red, blue and black. Each bar should take up 1/8 of the
> > > +            sensor pixel array width. When this is not possible, the bar size
> > > +            should be rounded down to the nearest integer and the pattern can
> > > +            repeat on the right side. Each bar's height must always take up the
> > > +            full sensor pixel array height.
> > > +        - name: TestPatternModeColorBarsFadeToGray
> > > +          value: 3
> > > +          description: |
> > > +            The test pattern is similar to TestPatternModeColorBars,
> > > +            except that each bar should start at its specified color at the top
> > > +            and fade to gray at the bottom. Furthermore each bar is further
> > > +            subdevided into a left and right half. The left half should have a
> > > +            smooth gradient, and the right half should have a quantized
> > > +            gradient. In particular, the right half's should consist of blocks
> > > +            of the same color for 1/16th active sensor pixel array width. The
> > > +            least significant bits in the quantized gradient should be copied
> > > +            from the most significant bits of the smooth gradient. The height of
> > > +            each bar should always be a multiple of 128. When this is not the
> > > +            case, the pattern should repeat at the bottom of the image.
> > > +        - name: TestPatternModePn9
> > > +          value: 4
> > > +          description: |
> > > +            All pixel data is replaced by a pseudo-random sequence generated
> > > +            from a PN9 512-bit sequence (typically implemented in hardware with
> > > +            a linear feedback shift register). The generator should be reset at
> > > +            the beginning of each frame, and thus each subsequent raw frame with
> > > +            this test pattern should be exactly the same as the last.
> > > +        - name: TestPatternModeCustom1
> > > +          value: 256
> > > +          description: |
> > > +            The first custom test pattern. All custom patterns that are
> > > +            available only on this camera device are at least this numeric
> > > +            value. All of the custom test patterns will be static (that is the
> > > +            raw image must not vary from frame to frame).
> > > +
> > > +...
> > > diff --git a/src/libcamera/property_ids.cpp.in b/src/libcamera/property_ids.cpp.in
> > > index 0771ac5c091f..8b274c38c74b 100644
> > > --- a/src/libcamera/property_ids.cpp.in
> > > +++ b/src/libcamera/property_ids.cpp.in
> > > @@ -23,15 +23,6 @@ namespace properties {
> > >
> > >  ${controls_doc}
> > >
> > > -/**
> > > - * \brief Namespace for libcamera draft properties
> > > - */
> > > -namespace draft {
> > > -
> > > -${draft_controls_doc}
> > > -
> > > -} /* namespace draft */
> > > -
> > >  ${vendor_controls_doc}
> > >
> > >  #ifndef __DOXYGEN__
> > > @@ -41,13 +32,8 @@ ${vendor_controls_doc}
> > >   */
> > >  ${controls_def}
> > >
> > > -namespace draft {
> > > -
> > > -${draft_controls_def}
> > > -
> > > -} /* namespace draft */
> > > -
> > >  ${vendor_controls_def}
> > > +
> > >  #endif
> > >
> > >  /**
> > > diff --git a/src/libcamera/property_ids_core.yaml b/src/libcamera/property_ids_core.yaml
> > > index 45f3609b4236..834454a4e087 100644
> > > --- a/src/libcamera/property_ids_core.yaml
> > > +++ b/src/libcamera/property_ids_core.yaml
> > > @@ -701,37 +701,4 @@ controls:
> > >
> > >          Different cameras may report identical devices.
> > >
> > > -  # ----------------------------------------------------------------------------
> > > -  # Draft properties section
> > > -
> > > -  - ColorFilterArrangement:
> > > -      type: int32_t
> > > -      draft: true
> > > -      description: |
> > > -        The arrangement of color filters on sensor; represents the colors in the
> > > -        top-left 2x2 section of the sensor, in reading order. Currently
> > > -        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> > > -      enum:
> > > -        - name: RGGB
> > > -          value: 0
> > > -          description: RGGB Bayer pattern
> > > -        - name: GRBG
> > > -          value: 1
> > > -          description: GRBG Bayer pattern
> > > -        - name: GBRG
> > > -          value: 2
> > > -          description: GBRG Bayer pattern
> > > -        - name: BGGR
> > > -          value: 3
> > > -          description: BGGR Bayer pattern
> > > -        - name: RGB
> > > -          value: 4
> > > -          description: |
> > > -            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> > > -            instead of just 1 16-bit value per pixel.
> > > -        - name: MONO
> > > -          value: 5
> > > -          description: |
> > > -            Sensor is not Bayer; output consists of a single colour channel.
> > > -
> > >  ...
> > > diff --git a/src/libcamera/property_ids_draft.yaml b/src/libcamera/property_ids_draft.yaml
> > > new file mode 100644
> > > index 000000000000..62f0e242d0c6
> > > --- /dev/null
> > > +++ b/src/libcamera/property_ids_draft.yaml
> > > @@ -0,0 +1,39 @@
> > > +# SPDX-License-Identifier: LGPL-2.1-or-later
> > > +#
> > > +# Copyright (C) 2019, Google Inc.
> > > +#
> > > +%YAML 1.1
> > > +---
> > > +vendor: draft
> > > +controls:
> > > +  - ColorFilterArrangement:
> > > +      type: int32_t
> > > +      vendor: draft
> > > +      description: |
> > > +        The arrangement of color filters on sensor; represents the colors in the
> > > +        top-left 2x2 section of the sensor, in reading order. Currently
> > > +        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
> > > +      enum:
> > > +        - name: RGGB
> > > +          value: 0
> > > +          description: RGGB Bayer pattern
> > > +        - name: GRBG
> > > +          value: 1
> > > +          description: GRBG Bayer pattern
> > > +        - name: GBRG
> > > +          value: 2
> > > +          description: GBRG Bayer pattern
> > > +        - name: BGGR
> > > +          value: 3
> > > +          description: BGGR Bayer pattern
> > > +        - name: RGB
> > > +          value: 4
> > > +          description: |
> > > +            Sensor is not Bayer; output has 3 16-bit values for each pixel,
> > > +            instead of just 1 16-bit value per pixel.
> > > +        - name: MONO
> > > +          value: 5
> > > +          description: |
> > > +            Sensor is not Bayer; output consists of a single colour channel.
> > > +
> > > +...
> > > diff --git a/src/py/libcamera/gen-py-controls.py b/src/py/libcamera/gen-py-controls.py
> > > index 8ae8d5126e39..55e0b4e8e3d6 100755
> > > --- a/src/py/libcamera/gen-py-controls.py
> > > +++ b/src/py/libcamera/gen-py-controls.py
> > > @@ -36,10 +36,7 @@ def generate_py(controls, mode):
> > >                  vendor_defs.append('\tauto {} = py::class_<Py{}Controls>(controls, \"{}\");'.format(vendor, vendor, vendor))
> > >                  vendors.append(vendor)
> > >
> > > -            if ctrl.get('draft'):
> > > -                ns = 'libcamera::{}::draft::'.format(mode)
> > > -                container = 'draft'
> > > -            elif vendor != 'libcamera':
> > > +            if vendor != 'libcamera':
> > >                  ns = 'libcamera::{}::{}::'.format(mode, vendor)
> > >                  container = vendor
> > >              else:
> > > diff --git a/src/py/libcamera/py_controls_generated.cpp.in b/src/py/libcamera/py_controls_generated.cpp.in
> > > index ec4b55ef2011..8d282ce51856 100644
> > > --- a/src/py/libcamera/py_controls_generated.cpp.in
> > > +++ b/src/py/libcamera/py_controls_generated.cpp.in
> > > @@ -17,16 +17,11 @@ class PyControls
> > >  {
> > >  };
> > >
> > > -class PyDraftControls
> > > -{
> > > -};
> > > -
> > >  ${vendors_class_def}
> > >
> > >  void init_py_controls_generated(py::module& m)
> > >  {
> > >         auto controls = py::class_<PyControls>(m, "controls");
> > > -       auto draft = py::class_<PyDraftControls>(controls, "draft");
> > >  ${vendors_defs}
> > >
> > >  ${controls}
> > > diff --git a/src/py/libcamera/py_properties_generated.cpp.in b/src/py/libcamera/py_properties_generated.cpp.in
> > > index f7b5ec8c635d..ae61c5440d31 100644
> > > --- a/src/py/libcamera/py_properties_generated.cpp.in
> > > +++ b/src/py/libcamera/py_properties_generated.cpp.in
> > > @@ -26,7 +26,6 @@ ${vendors_class_def}
> > >  void init_py_properties_generated(py::module& m)
> > >  {
> > >         auto controls = py::class_<PyProperties>(m, "properties");
> > > -       auto draft = py::class_<PyDraftProperties>(controls, "draft");
> > >  ${vendors_defs}
> > >
> > >  ${controls}
> > > diff --git a/utils/gen-controls.py b/utils/gen-controls.py
> > > index 04c63098b19b..45da571e83e0 100755
> > > --- a/utils/gen-controls.py
> > > +++ b/utils/gen-controls.py
> > > @@ -86,11 +86,6 @@ class Control(object):
> > >          """Is the control an enumeration"""
> > >          return self.__enum_values is not None
> > >
> > > -    @property
> > > -    def is_draft(self):
> > > -        """Is the control a draft control"""
> > > -        return self.__data.get('draft') is not None
> > > -
> > >      @property
> > >      def vendor(self):
> > >          """The vendor string, or None"""
> > > @@ -101,12 +96,6 @@ class Control(object):
> > >          """The control name (CamelCase)"""
> > >          return self.__name
> > >
> > > -    @property
> > > -    def q_name(self):
> > > -        """The control name, qualified with a namespace"""
> > > -        ns = 'draft::' if self.is_draft else ''
> > > -        return ns + self.__name
> > > -
> > >      @property
> > >      def type(self):
> > >          typ = self.__data.get('type')
> > > @@ -159,7 +148,7 @@ ${description}
> > >      for ctrl in controls:
> > >          id_name = snake_case(ctrl.name).upper()
> > >
> > > -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> > > +        vendor = ctrl.vendor
> > >          if vendor not in ctrls_doc:
> > >              ctrls_doc[vendor] = []
> > >              ctrls_def[vendor] = []
> > > @@ -208,7 +197,8 @@ ${description}
> > >          target_doc.append(doc_template.substitute(info))
> > >          target_def.append(def_template.substitute(info))
> > >
> > > -        ctrls_map.append('\t{ ' + id_name + ', &' + ctrl.q_name + ' },')
> > > +        vendor_ns = vendor + '::' if vendor != "libcamera" else ''
> > > +        ctrls_map.append('\t{ ' + vendor_ns + id_name + ', &' + vendor_ns + ctrl.name + ' },')
> > >
> > >      vendor_ctrl_doc_sub = []
> > >      vendor_ctrl_template = string.Template('''
> > > @@ -218,18 +208,16 @@ ${vendor_controls_str}
> > >
> > >  } /* namespace ${vendor} */''')
> > >
> > > -    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera', 'draft']]:
> > > +    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera']]:
> > >          vendor_ctrl_doc_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n\n'.join(ctrls_doc[vendor])}))
> > >
> > >      vendor_ctrl_def_sub = []
> > > -    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera', 'draft']]:
> > > +    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera']]:
> > >          vendor_ctrl_def_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n'.join(ctrls_def[vendor])}))
> > >
> > >      return {
> > >          'controls_doc': '\n\n'.join(ctrls_doc['libcamera']),
> > >          'controls_def': '\n'.join(ctrls_def['libcamera']),
> > > -        'draft_controls_doc': '\n\n'.join(ctrls_doc['draft']),
> > > -        'draft_controls_def': '\n\n'.join(ctrls_def['draft']),
> > >          'controls_map': '\n'.join(ctrls_map),
> > >          'vendor_controls_doc': '\n'.join(vendor_ctrl_doc_sub),
> > >          'vendor_controls_def': '\n'.join(vendor_ctrl_def_sub),
> > > @@ -249,7 +237,7 @@ def generate_h(controls, mode, ranges):
> > >      for ctrl in controls:
> > >          id_name = snake_case(ctrl.name).upper()
> > >
> > > -        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
> > > +        vendor = ctrl.vendor
> > >          if vendor not in ctrls:
> > >              if vendor not in ranges.keys():
> > >                  raise RuntimeError(f'Control id range is not defined for vendor {vendor}')
> > > @@ -257,8 +245,7 @@ def generate_h(controls, mode, ranges):
> > >              ids[vendor] = []
> > >              ctrls[vendor] = []
> > >
> > > -        # Core and draft controls use the same ID value
> > > -        target_ids = ids['libcamera'] if vendor in ['libcamera', 'draft'] else ids[vendor]
> > > +        target_ids = ids[vendor]
> > >          target_ids.append('\t' + id_name + ' = ' + str(id_value[vendor]) + ',')
> > >
> > >          info = {
> > > @@ -266,11 +253,7 @@ def generate_h(controls, mode, ranges):
> > >              'type': ctrl.type,
> > >          }
> > >
> > > -        target_ctrls = ctrls['libcamera']
> > > -        if ctrl.is_draft:
> > > -            target_ctrls = ctrls['draft']
> > > -        elif vendor != 'libcamera':
> > > -            target_ctrls = ctrls[vendor]
> > > +        target_ctrls = ctrls[vendor]
> > >
> > >          if ctrl.is_enum:
> > >              target_ctrls.append(enum_template_start.substitute(info))
> > > @@ -309,7 +292,7 @@ ${vendor_controls}
> > >  ''')
> > >
> > >      vendor_sub = []
> > > -    for vendor in [v for v in ctrls.keys() if v not in ['libcamera', 'draft']]:
> > > +    for vendor in [v for v in ctrls.keys() if v != 'libcamera']:
> > >          vendor_sub.append(vendor_template.substitute({'mode': mode.upper(),
> > >                                                        'vendor': vendor,
> > >                                                        'vendor_def': vendor.upper(),
> > > @@ -319,7 +302,6 @@ ${vendor_controls}
> > >      return {
> > >          'ids': '\n'.join(ids['libcamera']),
> > >          'controls': '\n'.join(ctrls['libcamera']),
> > > -        'draft_controls': '\n'.join(ctrls['draft']),
> > >          'vendor_controls': '\n'.join(vendor_sub)
> > >      }
> > >
>
> --
> Regards,
>
> Laurent Pinchart

Patch
diff mbox series

diff --git a/include/libcamera/control_ids.h.in b/include/libcamera/control_ids.h.in
index c97b09a82450..d53b1cf7beb2 100644
--- a/include/libcamera/control_ids.h.in
+++ b/include/libcamera/control_ids.h.in
@@ -26,12 +26,6 @@  ${controls}
 
 extern const ControlIdMap controls;
 
-namespace draft {
-
-${draft_controls}
-
-} /* namespace draft */
-
 ${vendor_controls}
 
 } /* namespace controls */
diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
index 79187d3fdfc9..1504f741ae2f 100644
--- a/include/libcamera/meson.build
+++ b/include/libcamera/meson.build
@@ -34,10 +34,12 @@  libcamera_headers_install_dir = get_option('includedir') / libcamera_include_dir
 
 controls_map = {
     'controls': {
+        'draft': 'control_ids_draft.yaml',
         'core': 'control_ids_core.yaml',
     },
 
     'properties': {
+        'draft': 'property_ids_draft.yaml',
         'core': 'property_ids_core.yaml',
     }
 }
diff --git a/include/libcamera/property_ids.h.in b/include/libcamera/property_ids.h.in
index 47c5d6bf2e28..43372c718fc9 100644
--- a/include/libcamera/property_ids.h.in
+++ b/include/libcamera/property_ids.h.in
@@ -23,12 +23,6 @@  ${ids}
 
 ${controls}
 
-namespace draft {
-
-${draft_controls}
-
-} /* namespace draft */
-
 extern const ControlIdMap properties;
 
 ${vendor_controls}
diff --git a/src/ipa/rpi/common/ipa_base.cpp b/src/ipa/rpi/common/ipa_base.cpp
index a1fec3aa3dd1..6ac9d5de2f88 100644
--- a/src/ipa/rpi/common/ipa_base.cpp
+++ b/src/ipa/rpi/common/ipa_base.cpp
@@ -1024,7 +1024,7 @@  void IpaBase::applyControls(const ControlList &controls)
 			break;
 		}
 
-		case controls::NOISE_REDUCTION_MODE:
+		case controls::draft::NOISE_REDUCTION_MODE:
 			/* Handled below in handleControls() */
 			libcameraMetadata_.set(controls::draft::NoiseReductionMode,
 					       ctrl.second.get<int32_t>());
diff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp
index c4baf04fb1e7..c165a5b8b0b6 100644
--- a/src/ipa/rpi/vc4/vc4.cpp
+++ b/src/ipa/rpi/vc4/vc4.cpp
@@ -260,7 +260,7 @@  void IpaVc4::handleControls(const ControlList &controls)
 
 	for (auto const &ctrl : controls) {
 		switch (ctrl.first) {
-		case controls::NOISE_REDUCTION_MODE: {
+		case controls::draft::NOISE_REDUCTION_MODE: {
 			RPiController::DenoiseAlgorithm *sdn = dynamic_cast<RPiController::DenoiseAlgorithm *>(
 				controller_.getAlgorithm("SDN"));
 			/* Some platforms may have a combined "denoise" algorithm instead. */
diff --git a/src/libcamera/control_ids.cpp.in b/src/libcamera/control_ids.cpp.in
index be86548cf73f..d283c1c1f401 100644
--- a/src/libcamera/control_ids.cpp.in
+++ b/src/libcamera/control_ids.cpp.in
@@ -24,15 +24,6 @@  namespace controls {
 
 ${controls_doc}
 
-/**
- * \brief Namespace for libcamera draft controls
- */
-namespace draft {
-
-${draft_controls_doc}
-
-} /* namespace draft */
-
 ${vendor_controls_doc}
 
 #ifndef __DOXYGEN__
@@ -42,13 +33,8 @@  ${vendor_controls_doc}
  */
 ${controls_def}
 
-namespace draft {
-
-${draft_controls_def}
-
-} /* namespace draft */
-
 ${vendor_controls_def}
+
 #endif
 
 /**
diff --git a/src/libcamera/control_ids_core.yaml b/src/libcamera/control_ids_core.yaml
index ff74ce1deedb..76fb9347d8e3 100644
--- a/src/libcamera/control_ids_core.yaml
+++ b/src/libcamera/control_ids_core.yaml
@@ -865,236 +865,4 @@  controls:
           description: |
             This is a long exposure image.
 
-  # ----------------------------------------------------------------------------
-  # Draft controls section
-
-  - AePrecaptureTrigger:
-      type: int32_t
-      draft: true
-      description: |
-        Control for AE metering trigger. Currently identical to
-        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
-
-        Whether the camera device will trigger a precapture metering sequence
-        when it processes this request.
-      enum:
-        - name: AePrecaptureTriggerIdle
-          value: 0
-          description: The trigger is idle.
-        - name: AePrecaptureTriggerStart
-          value: 1
-          description: The pre-capture AE metering is started by the camera.
-        - name: AePrecaptureTriggerCancel
-          value: 2
-          description: |
-            The camera will cancel any active or completed metering sequence.
-            The AE algorithm is reset to its initial state.
-
-  - NoiseReductionMode:
-      type: int32_t
-      draft: true
-      description: |
-       Control to select the noise reduction algorithm mode. Currently
-       identical to ANDROID_NOISE_REDUCTION_MODE.
-
-        Mode of operation for the noise reduction algorithm.
-      enum:
-        - name: NoiseReductionModeOff
-          value: 0
-          description: No noise reduction is applied
-        - name: NoiseReductionModeFast
-          value: 1
-          description: |
-            Noise reduction is applied without reducing the frame rate.
-        - name: NoiseReductionModeHighQuality
-          value: 2
-          description: |
-            High quality noise reduction at the expense of frame rate.
-        - name: NoiseReductionModeMinimal
-          value: 3
-          description: |
-            Minimal noise reduction is applied without reducing the frame rate.
-        - name: NoiseReductionModeZSL
-          value: 4
-          description: |
-            Noise reduction is applied at different levels to different streams.
-
-  - ColorCorrectionAberrationMode:
-      type: int32_t
-      draft: true
-      description: |
-       Control to select the color correction aberration mode. Currently
-       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
-
-        Mode of operation for the chromatic aberration correction algorithm.
-      enum:
-        - name: ColorCorrectionAberrationOff
-          value: 0
-          description: No aberration correction is applied.
-        - name: ColorCorrectionAberrationFast
-          value: 1
-          description: Aberration correction will not slow down the frame rate.
-        - name: ColorCorrectionAberrationHighQuality
-          value: 2
-          description: |
-            High quality aberration correction which might reduce the frame
-            rate.
-
-  - AeState:
-      type: int32_t
-      draft: true
-      description: |
-       Control to report the current AE algorithm state. Currently identical to
-       ANDROID_CONTROL_AE_STATE.
-
-        Current state of the AE algorithm.
-      enum:
-        - name: AeStateInactive
-          value: 0
-          description: The AE algorithm is inactive.
-        - name: AeStateSearching
-          value: 1
-          description: The AE algorithm has not converged yet.
-        - name: AeStateConverged
-          value: 2
-          description: The AE algorithm has converged.
-        - name: AeStateLocked
-          value: 3
-          description: The AE algorithm is locked.
-        - name: AeStateFlashRequired
-          value: 4
-          description: The AE algorithm would need a flash for good results
-        - name: AeStatePrecapture
-          value: 5
-          description: |
-            The AE algorithm has started a pre-capture metering session.
-            \sa AePrecaptureTrigger
-
-  - AwbState:
-      type: int32_t
-      draft: true
-      description: |
-       Control to report the current AWB algorithm state. Currently identical
-       to ANDROID_CONTROL_AWB_STATE.
-
-        Current state of the AWB algorithm.
-      enum:
-        - name: AwbStateInactive
-          value: 0
-          description: The AWB algorithm is inactive.
-        - name: AwbStateSearching
-          value: 1
-          description: The AWB algorithm has not converged yet.
-        - name: AwbConverged
-          value: 2
-          description: The AWB algorithm has converged.
-        - name: AwbLocked
-          value: 3
-          description: The AWB algorithm is locked.
-
-  - SensorRollingShutterSkew:
-      type: int64_t
-      draft: true
-      description: |
-       Control to report the time between the start of exposure of the first
-       row and the start of exposure of the last row. Currently identical to
-       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
-
-  - LensShadingMapMode:
-      type: int32_t
-      draft: true
-      description: |
-       Control to report if the lens shading map is available. Currently
-       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
-      enum:
-        - name: LensShadingMapModeOff
-          value: 0
-          description: No lens shading map mode is available.
-        - name: LensShadingMapModeOn
-          value: 1
-          description: The lens shading map mode is available.
-
-  - PipelineDepth:
-      type: int32_t
-      draft: true
-      description: |
-        Specifies the number of pipeline stages the frame went through from when
-        it was exposed to when the final completed result was available to the
-        framework. Always less than or equal to PipelineMaxDepth. Currently
-        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
-
-        The typical value for this control is 3 as a frame is first exposed,
-        captured and then processed in a single pass through the ISP. Any
-        additional processing step performed after the ISP pass (in example face
-        detection, additional format conversions etc) count as an additional
-        pipeline stage.
-
-  - MaxLatency:
-      type: int32_t
-      draft: true
-      description: |
-        The maximum number of frames that can occur after a request (different
-        than the previous) has been submitted, and before the result's state
-        becomes synchronized. A value of -1 indicates unknown latency, and 0
-        indicates per-frame control. Currently identical to
-        ANDROID_SYNC_MAX_LATENCY.
-
-  - TestPatternMode:
-      type: int32_t
-      draft: true
-      description: |
-        Control to select the test pattern mode. Currently identical to
-        ANDROID_SENSOR_TEST_PATTERN_MODE.
-      enum:
-        - name: TestPatternModeOff
-          value: 0
-          description: |
-            No test pattern mode is used. The camera device returns frames from
-            the image sensor.
-        - name: TestPatternModeSolidColor
-          value: 1
-          description: |
-            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
-            color channel provided in test pattern data.
-            \todo Add control for test pattern data.
-        - name: TestPatternModeColorBars
-          value: 2
-          description: |
-            All pixel data is replaced with an 8-bar color pattern. The vertical
-            bars (left-to-right) are as follows; white, yellow, cyan, green,
-            magenta, red, blue and black. Each bar should take up 1/8 of the
-            sensor pixel array width. When this is not possible, the bar size
-            should be rounded down to the nearest integer and the pattern can
-            repeat on the right side. Each bar's height must always take up the
-            full sensor pixel array height.
-        - name: TestPatternModeColorBarsFadeToGray
-          value: 3
-          description: |
-            The test pattern is similar to TestPatternModeColorBars,
-            except that each bar should start at its specified color at the top
-            and fade to gray at the bottom. Furthermore each bar is further
-            subdevided into a left and right half. The left half should have a
-            smooth gradient, and the right half should have a quantized
-            gradient. In particular, the right half's should consist of blocks
-            of the same color for 1/16th active sensor pixel array width. The
-            least significant bits in the quantized gradient should be copied
-            from the most significant bits of the smooth gradient. The height of
-            each bar should always be a multiple of 128. When this is not the
-            case, the pattern should repeat at the bottom of the image.
-        - name: TestPatternModePn9
-          value: 4
-          description: |
-            All pixel data is replaced by a pseudo-random sequence generated
-            from a PN9 512-bit sequence (typically implemented in hardware with
-            a linear feedback shift register). The generator should be reset at
-            the beginning of each frame, and thus each subsequent raw frame with
-            this test pattern should be exactly the same as the last.
-        - name: TestPatternModeCustom1
-          value: 256
-          description: |
-            The first custom test pattern. All custom patterns that are
-            available only on this camera device are at least this numeric
-            value. All of the custom test patterns will be static (that is the
-            raw image must not vary from frame to frame).
-
 ...
diff --git a/src/libcamera/control_ids_draft.yaml b/src/libcamera/control_ids_draft.yaml
new file mode 100644
index 000000000000..e4f53ea51d7a
--- /dev/null
+++ b/src/libcamera/control_ids_draft.yaml
@@ -0,0 +1,240 @@ 
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# Copyright (C) 2019, Google Inc.
+#
+%YAML 1.1
+---
+# Unless otherwise stated, all controls are bi-directional, i.e. they can be
+# set through Request::controls() and returned out through Request::metadata().
+vendor: draft
+controls:
+  - AePrecaptureTrigger:
+      type: int32_t
+      draft: true
+      description: |
+        Control for AE metering trigger. Currently identical to
+        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER.
+
+        Whether the camera device will trigger a precapture metering sequence
+        when it processes this request.
+      enum:
+        - name: AePrecaptureTriggerIdle
+          value: 0
+          description: The trigger is idle.
+        - name: AePrecaptureTriggerStart
+          value: 1
+          description: The pre-capture AE metering is started by the camera.
+        - name: AePrecaptureTriggerCancel
+          value: 2
+          description: |
+            The camera will cancel any active or completed metering sequence.
+            The AE algorithm is reset to its initial state.
+
+  - NoiseReductionMode:
+      type: int32_t
+      draft: true
+      description: |
+       Control to select the noise reduction algorithm mode. Currently
+       identical to ANDROID_NOISE_REDUCTION_MODE.
+
+        Mode of operation for the noise reduction algorithm.
+      enum:
+        - name: NoiseReductionModeOff
+          value: 0
+          description: No noise reduction is applied
+        - name: NoiseReductionModeFast
+          value: 1
+          description: |
+            Noise reduction is applied without reducing the frame rate.
+        - name: NoiseReductionModeHighQuality
+          value: 2
+          description: |
+            High quality noise reduction at the expense of frame rate.
+        - name: NoiseReductionModeMinimal
+          value: 3
+          description: |
+            Minimal noise reduction is applied without reducing the frame rate.
+        - name: NoiseReductionModeZSL
+          value: 4
+          description: |
+            Noise reduction is applied at different levels to different streams.
+
+  - ColorCorrectionAberrationMode:
+      type: int32_t
+      draft: true
+      description: |
+       Control to select the color correction aberration mode. Currently
+       identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE.
+
+        Mode of operation for the chromatic aberration correction algorithm.
+      enum:
+        - name: ColorCorrectionAberrationOff
+          value: 0
+          description: No aberration correction is applied.
+        - name: ColorCorrectionAberrationFast
+          value: 1
+          description: Aberration correction will not slow down the frame rate.
+        - name: ColorCorrectionAberrationHighQuality
+          value: 2
+          description: |
+            High quality aberration correction which might reduce the frame
+            rate.
+
+  - AeState:
+      type: int32_t
+      draft: true
+      description: |
+       Control to report the current AE algorithm state. Currently identical to
+       ANDROID_CONTROL_AE_STATE.
+
+        Current state of the AE algorithm.
+      enum:
+        - name: AeStateInactive
+          value: 0
+          description: The AE algorithm is inactive.
+        - name: AeStateSearching
+          value: 1
+          description: The AE algorithm has not converged yet.
+        - name: AeStateConverged
+          value: 2
+          description: The AE algorithm has converged.
+        - name: AeStateLocked
+          value: 3
+          description: The AE algorithm is locked.
+        - name: AeStateFlashRequired
+          value: 4
+          description: The AE algorithm would need a flash for good results
+        - name: AeStatePrecapture
+          value: 5
+          description: |
+            The AE algorithm has started a pre-capture metering session.
+            \sa AePrecaptureTrigger
+
+  - AwbState:
+      type: int32_t
+      draft: true
+      description: |
+       Control to report the current AWB algorithm state. Currently identical
+       to ANDROID_CONTROL_AWB_STATE.
+
+        Current state of the AWB algorithm.
+      enum:
+        - name: AwbStateInactive
+          value: 0
+          description: The AWB algorithm is inactive.
+        - name: AwbStateSearching
+          value: 1
+          description: The AWB algorithm has not converged yet.
+        - name: AwbConverged
+          value: 2
+          description: The AWB algorithm has converged.
+        - name: AwbLocked
+          value: 3
+          description: The AWB algorithm is locked.
+
+  - SensorRollingShutterSkew:
+      type: int64_t
+      draft: true
+      description: |
+       Control to report the time between the start of exposure of the first
+       row and the start of exposure of the last row. Currently identical to
+       ANDROID_SENSOR_ROLLING_SHUTTER_SKEW
+
+  - LensShadingMapMode:
+      type: int32_t
+      draft: true
+      description: |
+       Control to report if the lens shading map is available. Currently
+       identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE.
+      enum:
+        - name: LensShadingMapModeOff
+          value: 0
+          description: No lens shading map mode is available.
+        - name: LensShadingMapModeOn
+          value: 1
+          description: The lens shading map mode is available.
+
+  - PipelineDepth:
+      type: int32_t
+      draft: true
+      description: |
+        Specifies the number of pipeline stages the frame went through from when
+        it was exposed to when the final completed result was available to the
+        framework. Always less than or equal to PipelineMaxDepth. Currently
+        identical to ANDROID_REQUEST_PIPELINE_DEPTH.
+
+        The typical value for this control is 3 as a frame is first exposed,
+        captured and then processed in a single pass through the ISP. Any
+        additional processing step performed after the ISP pass (in example face
+        detection, additional format conversions etc) count as an additional
+        pipeline stage.
+
+  - MaxLatency:
+      type: int32_t
+      draft: true
+      description: |
+        The maximum number of frames that can occur after a request (different
+        than the previous) has been submitted, and before the result's state
+        becomes synchronized. A value of -1 indicates unknown latency, and 0
+        indicates per-frame control. Currently identical to
+        ANDROID_SYNC_MAX_LATENCY.
+
+  - TestPatternMode:
+      type: int32_t
+      draft: true
+      description: |
+        Control to select the test pattern mode. Currently identical to
+        ANDROID_SENSOR_TEST_PATTERN_MODE.
+      enum:
+        - name: TestPatternModeOff
+          value: 0
+          description: |
+            No test pattern mode is used. The camera device returns frames from
+            the image sensor.
+        - name: TestPatternModeSolidColor
+          value: 1
+          description: |
+            Each pixel in [R, G_even, G_odd, B] is replaced by its respective
+            color channel provided in test pattern data.
+            \todo Add control for test pattern data.
+        - name: TestPatternModeColorBars
+          value: 2
+          description: |
+            All pixel data is replaced with an 8-bar color pattern. The vertical
+            bars (left-to-right) are as follows; white, yellow, cyan, green,
+            magenta, red, blue and black. Each bar should take up 1/8 of the
+            sensor pixel array width. When this is not possible, the bar size
+            should be rounded down to the nearest integer and the pattern can
+            repeat on the right side. Each bar's height must always take up the
+            full sensor pixel array height.
+        - name: TestPatternModeColorBarsFadeToGray
+          value: 3
+          description: |
+            The test pattern is similar to TestPatternModeColorBars,
+            except that each bar should start at its specified color at the top
+            and fade to gray at the bottom. Furthermore each bar is further
+            subdevided into a left and right half. The left half should have a
+            smooth gradient, and the right half should have a quantized
+            gradient. In particular, the right half's should consist of blocks
+            of the same color for 1/16th active sensor pixel array width. The
+            least significant bits in the quantized gradient should be copied
+            from the most significant bits of the smooth gradient. The height of
+            each bar should always be a multiple of 128. When this is not the
+            case, the pattern should repeat at the bottom of the image.
+        - name: TestPatternModePn9
+          value: 4
+          description: |
+            All pixel data is replaced by a pseudo-random sequence generated
+            from a PN9 512-bit sequence (typically implemented in hardware with
+            a linear feedback shift register). The generator should be reset at
+            the beginning of each frame, and thus each subsequent raw frame with
+            this test pattern should be exactly the same as the last.
+        - name: TestPatternModeCustom1
+          value: 256
+          description: |
+            The first custom test pattern. All custom patterns that are
+            available only on this camera device are at least this numeric
+            value. All of the custom test patterns will be static (that is the
+            raw image must not vary from frame to frame).
+
+...
diff --git a/src/libcamera/property_ids.cpp.in b/src/libcamera/property_ids.cpp.in
index 0771ac5c091f..8b274c38c74b 100644
--- a/src/libcamera/property_ids.cpp.in
+++ b/src/libcamera/property_ids.cpp.in
@@ -23,15 +23,6 @@  namespace properties {
 
 ${controls_doc}
 
-/**
- * \brief Namespace for libcamera draft properties
- */
-namespace draft {
-
-${draft_controls_doc}
-
-} /* namespace draft */
-
 ${vendor_controls_doc}
 
 #ifndef __DOXYGEN__
@@ -41,13 +32,8 @@  ${vendor_controls_doc}
  */
 ${controls_def}
 
-namespace draft {
-
-${draft_controls_def}
-
-} /* namespace draft */
-
 ${vendor_controls_def}
+
 #endif
 
 /**
diff --git a/src/libcamera/property_ids_core.yaml b/src/libcamera/property_ids_core.yaml
index 45f3609b4236..834454a4e087 100644
--- a/src/libcamera/property_ids_core.yaml
+++ b/src/libcamera/property_ids_core.yaml
@@ -701,37 +701,4 @@  controls:
 
         Different cameras may report identical devices.
 
-  # ----------------------------------------------------------------------------
-  # Draft properties section
-
-  - ColorFilterArrangement:
-      type: int32_t
-      draft: true
-      description: |
-        The arrangement of color filters on sensor; represents the colors in the
-        top-left 2x2 section of the sensor, in reading order. Currently
-        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
-      enum:
-        - name: RGGB
-          value: 0
-          description: RGGB Bayer pattern
-        - name: GRBG
-          value: 1
-          description: GRBG Bayer pattern
-        - name: GBRG
-          value: 2
-          description: GBRG Bayer pattern
-        - name: BGGR
-          value: 3
-          description: BGGR Bayer pattern
-        - name: RGB
-          value: 4
-          description: |
-            Sensor is not Bayer; output has 3 16-bit values for each pixel,
-            instead of just 1 16-bit value per pixel.
-        - name: MONO
-          value: 5
-          description: |
-            Sensor is not Bayer; output consists of a single colour channel.
-
 ...
diff --git a/src/libcamera/property_ids_draft.yaml b/src/libcamera/property_ids_draft.yaml
new file mode 100644
index 000000000000..62f0e242d0c6
--- /dev/null
+++ b/src/libcamera/property_ids_draft.yaml
@@ -0,0 +1,39 @@ 
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# Copyright (C) 2019, Google Inc.
+#
+%YAML 1.1
+---
+vendor: draft
+controls:
+  - ColorFilterArrangement:
+      type: int32_t
+      vendor: draft
+      description: |
+        The arrangement of color filters on sensor; represents the colors in the
+        top-left 2x2 section of the sensor, in reading order. Currently
+        identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT.
+      enum:
+        - name: RGGB
+          value: 0
+          description: RGGB Bayer pattern
+        - name: GRBG
+          value: 1
+          description: GRBG Bayer pattern
+        - name: GBRG
+          value: 2
+          description: GBRG Bayer pattern
+        - name: BGGR
+          value: 3
+          description: BGGR Bayer pattern
+        - name: RGB
+          value: 4
+          description: |
+            Sensor is not Bayer; output has 3 16-bit values for each pixel,
+            instead of just 1 16-bit value per pixel.
+        - name: MONO
+          value: 5
+          description: |
+            Sensor is not Bayer; output consists of a single colour channel.
+
+...
diff --git a/src/py/libcamera/gen-py-controls.py b/src/py/libcamera/gen-py-controls.py
index 8ae8d5126e39..55e0b4e8e3d6 100755
--- a/src/py/libcamera/gen-py-controls.py
+++ b/src/py/libcamera/gen-py-controls.py
@@ -36,10 +36,7 @@  def generate_py(controls, mode):
                 vendor_defs.append('\tauto {} = py::class_<Py{}Controls>(controls, \"{}\");'.format(vendor, vendor, vendor))
                 vendors.append(vendor)
 
-            if ctrl.get('draft'):
-                ns = 'libcamera::{}::draft::'.format(mode)
-                container = 'draft'
-            elif vendor != 'libcamera':
+            if vendor != 'libcamera':
                 ns = 'libcamera::{}::{}::'.format(mode, vendor)
                 container = vendor
             else:
diff --git a/src/py/libcamera/py_controls_generated.cpp.in b/src/py/libcamera/py_controls_generated.cpp.in
index ec4b55ef2011..8d282ce51856 100644
--- a/src/py/libcamera/py_controls_generated.cpp.in
+++ b/src/py/libcamera/py_controls_generated.cpp.in
@@ -17,16 +17,11 @@  class PyControls
 {
 };
 
-class PyDraftControls
-{
-};
-
 ${vendors_class_def}
 
 void init_py_controls_generated(py::module& m)
 {
 	auto controls = py::class_<PyControls>(m, "controls");
-	auto draft = py::class_<PyDraftControls>(controls, "draft");
 ${vendors_defs}
 
 ${controls}
diff --git a/src/py/libcamera/py_properties_generated.cpp.in b/src/py/libcamera/py_properties_generated.cpp.in
index f7b5ec8c635d..ae61c5440d31 100644
--- a/src/py/libcamera/py_properties_generated.cpp.in
+++ b/src/py/libcamera/py_properties_generated.cpp.in
@@ -26,7 +26,6 @@  ${vendors_class_def}
 void init_py_properties_generated(py::module& m)
 {
 	auto controls = py::class_<PyProperties>(m, "properties");
-	auto draft = py::class_<PyDraftProperties>(controls, "draft");
 ${vendors_defs}
 
 ${controls}
diff --git a/utils/gen-controls.py b/utils/gen-controls.py
index 04c63098b19b..45da571e83e0 100755
--- a/utils/gen-controls.py
+++ b/utils/gen-controls.py
@@ -86,11 +86,6 @@  class Control(object):
         """Is the control an enumeration"""
         return self.__enum_values is not None
 
-    @property
-    def is_draft(self):
-        """Is the control a draft control"""
-        return self.__data.get('draft') is not None
-
     @property
     def vendor(self):
         """The vendor string, or None"""
@@ -101,12 +96,6 @@  class Control(object):
         """The control name (CamelCase)"""
         return self.__name
 
-    @property
-    def q_name(self):
-        """The control name, qualified with a namespace"""
-        ns = 'draft::' if self.is_draft else ''
-        return ns + self.__name
-
     @property
     def type(self):
         typ = self.__data.get('type')
@@ -159,7 +148,7 @@  ${description}
     for ctrl in controls:
         id_name = snake_case(ctrl.name).upper()
 
-        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
+        vendor = ctrl.vendor
         if vendor not in ctrls_doc:
             ctrls_doc[vendor] = []
             ctrls_def[vendor] = []
@@ -208,7 +197,8 @@  ${description}
         target_doc.append(doc_template.substitute(info))
         target_def.append(def_template.substitute(info))
 
-        ctrls_map.append('\t{ ' + id_name + ', &' + ctrl.q_name + ' },')
+        vendor_ns = vendor + '::' if vendor != "libcamera" else ''
+        ctrls_map.append('\t{ ' + vendor_ns + id_name + ', &' + vendor_ns + ctrl.name + ' },')
 
     vendor_ctrl_doc_sub = []
     vendor_ctrl_template = string.Template('''
@@ -218,18 +208,16 @@  ${vendor_controls_str}
 
 } /* namespace ${vendor} */''')
 
-    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera', 'draft']]:
+    for vendor in [v for v in ctrls_doc.keys() if v not in ['libcamera']]:
         vendor_ctrl_doc_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n\n'.join(ctrls_doc[vendor])}))
 
     vendor_ctrl_def_sub = []
-    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera', 'draft']]:
+    for vendor in [v for v in ctrls_def.keys() if v not in ['libcamera']]:
         vendor_ctrl_def_sub.append(vendor_ctrl_template.substitute({'vendor': vendor, 'vendor_controls_str': '\n'.join(ctrls_def[vendor])}))
 
     return {
         'controls_doc': '\n\n'.join(ctrls_doc['libcamera']),
         'controls_def': '\n'.join(ctrls_def['libcamera']),
-        'draft_controls_doc': '\n\n'.join(ctrls_doc['draft']),
-        'draft_controls_def': '\n\n'.join(ctrls_def['draft']),
         'controls_map': '\n'.join(ctrls_map),
         'vendor_controls_doc': '\n'.join(vendor_ctrl_doc_sub),
         'vendor_controls_def': '\n'.join(vendor_ctrl_def_sub),
@@ -249,7 +237,7 @@  def generate_h(controls, mode, ranges):
     for ctrl in controls:
         id_name = snake_case(ctrl.name).upper()
 
-        vendor = 'draft' if ctrl.is_draft else ctrl.vendor
+        vendor = ctrl.vendor
         if vendor not in ctrls:
             if vendor not in ranges.keys():
                 raise RuntimeError(f'Control id range is not defined for vendor {vendor}')
@@ -257,8 +245,7 @@  def generate_h(controls, mode, ranges):
             ids[vendor] = []
             ctrls[vendor] = []
 
-        # Core and draft controls use the same ID value
-        target_ids = ids['libcamera'] if vendor in ['libcamera', 'draft'] else ids[vendor]
+        target_ids = ids[vendor]
         target_ids.append('\t' + id_name + ' = ' + str(id_value[vendor]) + ',')
 
         info = {
@@ -266,11 +253,7 @@  def generate_h(controls, mode, ranges):
             'type': ctrl.type,
         }
 
-        target_ctrls = ctrls['libcamera']
-        if ctrl.is_draft:
-            target_ctrls = ctrls['draft']
-        elif vendor != 'libcamera':
-            target_ctrls = ctrls[vendor]
+        target_ctrls = ctrls[vendor]
 
         if ctrl.is_enum:
             target_ctrls.append(enum_template_start.substitute(info))
@@ -309,7 +292,7 @@  ${vendor_controls}
 ''')
 
     vendor_sub = []
-    for vendor in [v for v in ctrls.keys() if v not in ['libcamera', 'draft']]:
+    for vendor in [v for v in ctrls.keys() if v != 'libcamera']:
         vendor_sub.append(vendor_template.substitute({'mode': mode.upper(),
                                                       'vendor': vendor,
                                                       'vendor_def': vendor.upper(),
@@ -319,7 +302,6 @@  ${vendor_controls}
     return {
         'ids': '\n'.join(ids['libcamera']),
         'controls': '\n'.join(ctrls['libcamera']),
-        'draft_controls': '\n'.join(ctrls['draft']),
         'vendor_controls': '\n'.join(vendor_sub)
     }