[libcamera-devel,v6,4/8] ipa: raspberrypi: Use YamlParser to replace dependency on boost
diff mbox series

Message ID 20220718081602.32535-5-naush@raspberrypi.com
State Accepted
Headers show
Series
  • Replace boost JSON parser with libyaml in Raspberry Pi IPA
Related show

Commit Message

Naushir Patuck July 18, 2022, 8:15 a.m. UTC
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

The Raspberry Pi IPA module depends on boost only to parse the JSON
tuning data files. As libcamera depends on libyaml, use the YamlParser
class to parse those files and drop the dependency on boost.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 README.rst                                    |  6 --
 src/ipa/raspberrypi/controller/algorithm.cpp  |  2 +-
 src/ipa/raspberrypi/controller/algorithm.hpp  |  6 +-
 src/ipa/raspberrypi/controller/controller.cpp | 27 ++++--
 src/ipa/raspberrypi/controller/pwl.cpp        | 12 ++-
 src/ipa/raspberrypi/controller/pwl.hpp        |  5 +-
 src/ipa/raspberrypi/controller/rpi/agc.cpp    | 94 +++++++++----------
 src/ipa/raspberrypi/controller/rpi/agc.hpp    | 10 +-
 src/ipa/raspberrypi/controller/rpi/alsc.cpp   | 94 +++++++++----------
 src/ipa/raspberrypi/controller/rpi/alsc.hpp   |  2 +-
 src/ipa/raspberrypi/controller/rpi/awb.cpp    | 89 +++++++++---------
 src/ipa/raspberrypi/controller/rpi/awb.hpp    |  8 +-
 .../controller/rpi/black_level.cpp            | 12 +--
 .../controller/rpi/black_level.hpp            |  2 +-
 src/ipa/raspberrypi/controller/rpi/ccm.cpp    | 28 +++---
 src/ipa/raspberrypi/controller/rpi/ccm.hpp    |  4 +-
 .../raspberrypi/controller/rpi/contrast.cpp   | 18 ++--
 .../raspberrypi/controller/rpi/contrast.hpp   |  2 +-
 src/ipa/raspberrypi/controller/rpi/dpc.cpp    |  4 +-
 src/ipa/raspberrypi/controller/rpi/dpc.hpp    |  2 +-
 src/ipa/raspberrypi/controller/rpi/geq.cpp    | 10 +-
 src/ipa/raspberrypi/controller/rpi/geq.hpp    |  2 +-
 src/ipa/raspberrypi/controller/rpi/lux.cpp    | 12 +--
 src/ipa/raspberrypi/controller/rpi/lux.hpp    |  2 +-
 src/ipa/raspberrypi/controller/rpi/noise.cpp  |  6 +-
 src/ipa/raspberrypi/controller/rpi/noise.hpp  |  2 +-
 src/ipa/raspberrypi/controller/rpi/sdn.cpp    |  6 +-
 src/ipa/raspberrypi/controller/rpi/sdn.hpp    |  2 +-
 .../raspberrypi/controller/rpi/sharpen.cpp    |  8 +-
 .../raspberrypi/controller/rpi/sharpen.hpp    |  2 +-
 src/ipa/raspberrypi/meson.build               |  1 -
 src/ipa/raspberrypi/raspberrypi.cpp           |  1 +
 32 files changed, 241 insertions(+), 240 deletions(-)

Comments

Laurent Pinchart July 22, 2022, 7:25 p.m. UTC | #1
Hi Naush,

On Mon, Jul 18, 2022 at 09:15:58AM +0100, Naushir Patuck wrote:
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> The Raspberry Pi IPA module depends on boost only to parse the JSON
> tuning data files. As libcamera depends on libyaml, use the YamlParser
> class to parse those files and drop the dependency on boost.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

I assume you're fine with this patch as you've posted it as part of your
series, but could you give it a review ? :-)

> ---
>  README.rst                                    |  6 --
>  src/ipa/raspberrypi/controller/algorithm.cpp  |  2 +-
>  src/ipa/raspberrypi/controller/algorithm.hpp  |  6 +-
>  src/ipa/raspberrypi/controller/controller.cpp | 27 ++++--
>  src/ipa/raspberrypi/controller/pwl.cpp        | 12 ++-
>  src/ipa/raspberrypi/controller/pwl.hpp        |  5 +-
>  src/ipa/raspberrypi/controller/rpi/agc.cpp    | 94 +++++++++----------
>  src/ipa/raspberrypi/controller/rpi/agc.hpp    | 10 +-
>  src/ipa/raspberrypi/controller/rpi/alsc.cpp   | 94 +++++++++----------
>  src/ipa/raspberrypi/controller/rpi/alsc.hpp   |  2 +-
>  src/ipa/raspberrypi/controller/rpi/awb.cpp    | 89 +++++++++---------
>  src/ipa/raspberrypi/controller/rpi/awb.hpp    |  8 +-
>  .../controller/rpi/black_level.cpp            | 12 +--
>  .../controller/rpi/black_level.hpp            |  2 +-
>  src/ipa/raspberrypi/controller/rpi/ccm.cpp    | 28 +++---
>  src/ipa/raspberrypi/controller/rpi/ccm.hpp    |  4 +-
>  .../raspberrypi/controller/rpi/contrast.cpp   | 18 ++--
>  .../raspberrypi/controller/rpi/contrast.hpp   |  2 +-
>  src/ipa/raspberrypi/controller/rpi/dpc.cpp    |  4 +-
>  src/ipa/raspberrypi/controller/rpi/dpc.hpp    |  2 +-
>  src/ipa/raspberrypi/controller/rpi/geq.cpp    | 10 +-
>  src/ipa/raspberrypi/controller/rpi/geq.hpp    |  2 +-
>  src/ipa/raspberrypi/controller/rpi/lux.cpp    | 12 +--
>  src/ipa/raspberrypi/controller/rpi/lux.hpp    |  2 +-
>  src/ipa/raspberrypi/controller/rpi/noise.cpp  |  6 +-
>  src/ipa/raspberrypi/controller/rpi/noise.hpp  |  2 +-
>  src/ipa/raspberrypi/controller/rpi/sdn.cpp    |  6 +-
>  src/ipa/raspberrypi/controller/rpi/sdn.hpp    |  2 +-
>  .../raspberrypi/controller/rpi/sharpen.cpp    |  8 +-
>  .../raspberrypi/controller/rpi/sharpen.hpp    |  2 +-
>  src/ipa/raspberrypi/meson.build               |  1 -
>  src/ipa/raspberrypi/raspberrypi.cpp           |  1 +
>  32 files changed, 241 insertions(+), 240 deletions(-)
Naushir Patuck July 25, 2022, 10:26 a.m. UTC | #2
Hi Laurent,


On Fri, 22 Jul 2022 at 20:25, Laurent Pinchart <
laurent.pinchart@ideasonboard.com> wrote:

> Hi Naush,
>
> On Mon, Jul 18, 2022 at 09:15:58AM +0100, Naushir Patuck wrote:
> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >
> > The Raspberry Pi IPA module depends on boost only to parse the JSON
> > tuning data files. As libcamera depends on libyaml, use the YamlParser
> > class to parse those files and drop the dependency on boost.
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>
> I assume you're fine with this patch as you've posted it as part of your
> series, but could you give it a review ? :-)
>

I did have one outstanding query on this about default values.

If you recall, we discussed having YamlObject::get() not take in a default
value
and complain loudly if the key is not present, similar to what the Boost
parser
does now.  This will help avoid possibly hard to debug issues if a critical
parameter is missing from the tuning config.  David, what are your thoughts?

Do you think this is something that we can add easily to this patch?

Regards,
Naush


> > ---
> >  README.rst                                    |  6 --
> >  src/ipa/raspberrypi/controller/algorithm.cpp  |  2 +-
> >  src/ipa/raspberrypi/controller/algorithm.hpp  |  6 +-
> >  src/ipa/raspberrypi/controller/controller.cpp | 27 ++++--
> >  src/ipa/raspberrypi/controller/pwl.cpp        | 12 ++-
> >  src/ipa/raspberrypi/controller/pwl.hpp        |  5 +-
> >  src/ipa/raspberrypi/controller/rpi/agc.cpp    | 94 +++++++++----------
> >  src/ipa/raspberrypi/controller/rpi/agc.hpp    | 10 +-
> >  src/ipa/raspberrypi/controller/rpi/alsc.cpp   | 94 +++++++++----------
> >  src/ipa/raspberrypi/controller/rpi/alsc.hpp   |  2 +-
> >  src/ipa/raspberrypi/controller/rpi/awb.cpp    | 89 +++++++++---------
> >  src/ipa/raspberrypi/controller/rpi/awb.hpp    |  8 +-
> >  .../controller/rpi/black_level.cpp            | 12 +--
> >  .../controller/rpi/black_level.hpp            |  2 +-
> >  src/ipa/raspberrypi/controller/rpi/ccm.cpp    | 28 +++---
> >  src/ipa/raspberrypi/controller/rpi/ccm.hpp    |  4 +-
> >  .../raspberrypi/controller/rpi/contrast.cpp   | 18 ++--
> >  .../raspberrypi/controller/rpi/contrast.hpp   |  2 +-
> >  src/ipa/raspberrypi/controller/rpi/dpc.cpp    |  4 +-
> >  src/ipa/raspberrypi/controller/rpi/dpc.hpp    |  2 +-
> >  src/ipa/raspberrypi/controller/rpi/geq.cpp    | 10 +-
> >  src/ipa/raspberrypi/controller/rpi/geq.hpp    |  2 +-
> >  src/ipa/raspberrypi/controller/rpi/lux.cpp    | 12 +--
> >  src/ipa/raspberrypi/controller/rpi/lux.hpp    |  2 +-
> >  src/ipa/raspberrypi/controller/rpi/noise.cpp  |  6 +-
> >  src/ipa/raspberrypi/controller/rpi/noise.hpp  |  2 +-
> >  src/ipa/raspberrypi/controller/rpi/sdn.cpp    |  6 +-
> >  src/ipa/raspberrypi/controller/rpi/sdn.hpp    |  2 +-
> >  .../raspberrypi/controller/rpi/sharpen.cpp    |  8 +-
> >  .../raspberrypi/controller/rpi/sharpen.hpp    |  2 +-
> >  src/ipa/raspberrypi/meson.build               |  1 -
> >  src/ipa/raspberrypi/raspberrypi.cpp           |  1 +
> >  32 files changed, 241 insertions(+), 240 deletions(-)
>
> --
> Regards,
>
> Laurent Pinchart
>
David Plowman July 25, 2022, 10:50 a.m. UTC | #3
Hi Naush, Laurent

On Mon, 25 Jul 2022 at 11:26, Naushir Patuck <naush@raspberrypi.com> wrote:
>
> Hi Laurent,
>
>
> On Fri, 22 Jul 2022 at 20:25, Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
>>
>> Hi Naush,
>>
>> On Mon, Jul 18, 2022 at 09:15:58AM +0100, Naushir Patuck wrote:
>> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> >
>> > The Raspberry Pi IPA module depends on boost only to parse the JSON
>> > tuning data files. As libcamera depends on libyaml, use the YamlParser
>> > class to parse those files and drop the dependency on boost.
>> >
>> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>>
>> I assume you're fine with this patch as you've posted it as part of your
>> series, but could you give it a review ? :-)
>
>
> I did have one outstanding query on this about default values.
>
> If you recall, we discussed having YamlObject::get() not take in a default value
> and complain loudly if the key is not present, similar to what the Boost parser
> does now.  This will help avoid possibly hard to debug issues if a critical
> parameter is missing from the tuning config.  David, what are your thoughts?

I agree it would be nice to get some kind of error or at least warning
if something that we really expected is not present. Possibly we could
review some of those and provide default values in more cases, but I'm
guessing that's not the kind of thing to "hide" inside a patch that
isn't meant to change the behaviour of any algorithms.

Thanks!
David

>
> Do you think this is something that we can add easily to this patch?
>
> Regards,
> Naush
>
>>
>> > ---
>> >  README.rst                                    |  6 --
>> >  src/ipa/raspberrypi/controller/algorithm.cpp  |  2 +-
>> >  src/ipa/raspberrypi/controller/algorithm.hpp  |  6 +-
>> >  src/ipa/raspberrypi/controller/controller.cpp | 27 ++++--
>> >  src/ipa/raspberrypi/controller/pwl.cpp        | 12 ++-
>> >  src/ipa/raspberrypi/controller/pwl.hpp        |  5 +-
>> >  src/ipa/raspberrypi/controller/rpi/agc.cpp    | 94 +++++++++----------
>> >  src/ipa/raspberrypi/controller/rpi/agc.hpp    | 10 +-
>> >  src/ipa/raspberrypi/controller/rpi/alsc.cpp   | 94 +++++++++----------
>> >  src/ipa/raspberrypi/controller/rpi/alsc.hpp   |  2 +-
>> >  src/ipa/raspberrypi/controller/rpi/awb.cpp    | 89 +++++++++---------
>> >  src/ipa/raspberrypi/controller/rpi/awb.hpp    |  8 +-
>> >  .../controller/rpi/black_level.cpp            | 12 +--
>> >  .../controller/rpi/black_level.hpp            |  2 +-
>> >  src/ipa/raspberrypi/controller/rpi/ccm.cpp    | 28 +++---
>> >  src/ipa/raspberrypi/controller/rpi/ccm.hpp    |  4 +-
>> >  .../raspberrypi/controller/rpi/contrast.cpp   | 18 ++--
>> >  .../raspberrypi/controller/rpi/contrast.hpp   |  2 +-
>> >  src/ipa/raspberrypi/controller/rpi/dpc.cpp    |  4 +-
>> >  src/ipa/raspberrypi/controller/rpi/dpc.hpp    |  2 +-
>> >  src/ipa/raspberrypi/controller/rpi/geq.cpp    | 10 +-
>> >  src/ipa/raspberrypi/controller/rpi/geq.hpp    |  2 +-
>> >  src/ipa/raspberrypi/controller/rpi/lux.cpp    | 12 +--
>> >  src/ipa/raspberrypi/controller/rpi/lux.hpp    |  2 +-
>> >  src/ipa/raspberrypi/controller/rpi/noise.cpp  |  6 +-
>> >  src/ipa/raspberrypi/controller/rpi/noise.hpp  |  2 +-
>> >  src/ipa/raspberrypi/controller/rpi/sdn.cpp    |  6 +-
>> >  src/ipa/raspberrypi/controller/rpi/sdn.hpp    |  2 +-
>> >  .../raspberrypi/controller/rpi/sharpen.cpp    |  8 +-
>> >  .../raspberrypi/controller/rpi/sharpen.hpp    |  2 +-
>> >  src/ipa/raspberrypi/meson.build               |  1 -
>> >  src/ipa/raspberrypi/raspberrypi.cpp           |  1 +
>> >  32 files changed, 241 insertions(+), 240 deletions(-)
>>
>> --
>> Regards,
>>
>> Laurent Pinchart
Laurent Pinchart July 25, 2022, 1:50 p.m. UTC | #4
Hello,

On Mon, Jul 25, 2022 at 11:50:06AM +0100, David Plowman wrote:
> On Mon, 25 Jul 2022 at 11:26, Naushir Patuck <naush@raspberrypi.com> wrote:
> > On Fri, 22 Jul 2022 at 20:25, Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
> >> On Mon, Jul 18, 2022 at 09:15:58AM +0100, Naushir Patuck wrote:
> >> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >> >
> >> > The Raspberry Pi IPA module depends on boost only to parse the JSON
> >> > tuning data files. As libcamera depends on libyaml, use the YamlParser
> >> > class to parse those files and drop the dependency on boost.
> >> >
> >> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >>
> >> I assume you're fine with this patch as you've posted it as part of your
> >> series, but could you give it a review ? :-)
> >
> > I did have one outstanding query on this about default values.
> >
> > If you recall, we discussed having YamlObject::get() not take in a default value
> > and complain loudly if the key is not present, similar to what the Boost parser
> > does now.  This will help avoid possibly hard to debug issues if a critical
> > parameter is missing from the tuning config.  David, what are your thoughts?
> 
> I agree it would be nice to get some kind of error or at least warning
> if something that we really expected is not present. Possibly we could
> review some of those and provide default values in more cases, but I'm
> guessing that's not the kind of thing to "hide" inside a patch that
> isn't meant to change the behaviour of any algorithms.

I agree, that's a good point.

The boost json parser will throw an exception in this case, which I
can't replicate in YamlObject. I can update the Read() function to
return an error, would it be enough to log a message at the top level,
or would you like individual log statements in every location to tell
which parameter was missing ?

> > Do you think this is something that we can add easily to this patch?
> >
> >> > ---
> >> >  README.rst                                    |  6 --
> >> >  src/ipa/raspberrypi/controller/algorithm.cpp  |  2 +-
> >> >  src/ipa/raspberrypi/controller/algorithm.hpp  |  6 +-
> >> >  src/ipa/raspberrypi/controller/controller.cpp | 27 ++++--
> >> >  src/ipa/raspberrypi/controller/pwl.cpp        | 12 ++-
> >> >  src/ipa/raspberrypi/controller/pwl.hpp        |  5 +-
> >> >  src/ipa/raspberrypi/controller/rpi/agc.cpp    | 94 +++++++++----------
> >> >  src/ipa/raspberrypi/controller/rpi/agc.hpp    | 10 +-
> >> >  src/ipa/raspberrypi/controller/rpi/alsc.cpp   | 94 +++++++++----------
> >> >  src/ipa/raspberrypi/controller/rpi/alsc.hpp   |  2 +-
> >> >  src/ipa/raspberrypi/controller/rpi/awb.cpp    | 89 +++++++++---------
> >> >  src/ipa/raspberrypi/controller/rpi/awb.hpp    |  8 +-
> >> >  .../controller/rpi/black_level.cpp            | 12 +--
> >> >  .../controller/rpi/black_level.hpp            |  2 +-
> >> >  src/ipa/raspberrypi/controller/rpi/ccm.cpp    | 28 +++---
> >> >  src/ipa/raspberrypi/controller/rpi/ccm.hpp    |  4 +-
> >> >  .../raspberrypi/controller/rpi/contrast.cpp   | 18 ++--
> >> >  .../raspberrypi/controller/rpi/contrast.hpp   |  2 +-
> >> >  src/ipa/raspberrypi/controller/rpi/dpc.cpp    |  4 +-
> >> >  src/ipa/raspberrypi/controller/rpi/dpc.hpp    |  2 +-
> >> >  src/ipa/raspberrypi/controller/rpi/geq.cpp    | 10 +-
> >> >  src/ipa/raspberrypi/controller/rpi/geq.hpp    |  2 +-
> >> >  src/ipa/raspberrypi/controller/rpi/lux.cpp    | 12 +--
> >> >  src/ipa/raspberrypi/controller/rpi/lux.hpp    |  2 +-
> >> >  src/ipa/raspberrypi/controller/rpi/noise.cpp  |  6 +-
> >> >  src/ipa/raspberrypi/controller/rpi/noise.hpp  |  2 +-
> >> >  src/ipa/raspberrypi/controller/rpi/sdn.cpp    |  6 +-
> >> >  src/ipa/raspberrypi/controller/rpi/sdn.hpp    |  2 +-
> >> >  .../raspberrypi/controller/rpi/sharpen.cpp    |  8 +-
> >> >  .../raspberrypi/controller/rpi/sharpen.hpp    |  2 +-
> >> >  src/ipa/raspberrypi/meson.build               |  1 -
> >> >  src/ipa/raspberrypi/raspberrypi.cpp           |  1 +
> >> >  32 files changed, 241 insertions(+), 240 deletions(-)
Naushir Patuck July 25, 2022, 2:48 p.m. UTC | #5
Hi Laurent,

On Mon, 25 Jul 2022 at 14:50, Laurent Pinchart <
laurent.pinchart@ideasonboard.com> wrote:

> Hello,
>
> On Mon, Jul 25, 2022 at 11:50:06AM +0100, David Plowman wrote:
> > On Mon, 25 Jul 2022 at 11:26, Naushir Patuck <naush@raspberrypi.com>
> wrote:
> > > On Fri, 22 Jul 2022 at 20:25, Laurent Pinchart <
> laurent.pinchart@ideasonboard.com> wrote:
> > >> On Mon, Jul 18, 2022 at 09:15:58AM +0100, Naushir Patuck wrote:
> > >> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > >> >
> > >> > The Raspberry Pi IPA module depends on boost only to parse the JSON
> > >> > tuning data files. As libcamera depends on libyaml, use the
> YamlParser
> > >> > class to parse those files and drop the dependency on boost.
> > >> >
> > >> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > >>
> > >> I assume you're fine with this patch as you've posted it as part of
> your
> > >> series, but could you give it a review ? :-)
> > >
> > > I did have one outstanding query on this about default values.
> > >
> > > If you recall, we discussed having YamlObject::get() not take in a
> default value
> > > and complain loudly if the key is not present, similar to what the
> Boost parser
> > > does now.  This will help avoid possibly hard to debug issues if a
> critical
> > > parameter is missing from the tuning config.  David, what are your
> thoughts?
> >
> > I agree it would be nice to get some kind of error or at least warning
> > if something that we really expected is not present. Possibly we could
> > review some of those and provide default values in more cases, but I'm
> > guessing that's not the kind of thing to "hide" inside a patch that
> > isn't meant to change the behaviour of any algorithms.
>
> I agree, that's a good point.
>
> The boost json parser will throw an exception in this case, which I
> can't replicate in YamlObject. I can update the Read() function to
> return an error, would it be enough to log a message at the top level,
> or would you like individual log statements in every location to tell
> which parameter was missing ?
>

Having read() return an error code - provided no default is set is a good
idea.
Then the top level can decide how to handle this - a LOG(Fatal) message
in our case.  David, what do you think?

Regards,
Naush


> > > Do you think this is something that we can add easily to this patch?
> > >
> > >> > ---
> > >> >  README.rst                                    |  6 --
> > >> >  src/ipa/raspberrypi/controller/algorithm.cpp  |  2 +-
> > >> >  src/ipa/raspberrypi/controller/algorithm.hpp  |  6 +-
> > >> >  src/ipa/raspberrypi/controller/controller.cpp | 27 ++++--
> > >> >  src/ipa/raspberrypi/controller/pwl.cpp        | 12 ++-
> > >> >  src/ipa/raspberrypi/controller/pwl.hpp        |  5 +-
> > >> >  src/ipa/raspberrypi/controller/rpi/agc.cpp    | 94
> +++++++++----------
> > >> >  src/ipa/raspberrypi/controller/rpi/agc.hpp    | 10 +-
> > >> >  src/ipa/raspberrypi/controller/rpi/alsc.cpp   | 94
> +++++++++----------
> > >> >  src/ipa/raspberrypi/controller/rpi/alsc.hpp   |  2 +-
> > >> >  src/ipa/raspberrypi/controller/rpi/awb.cpp    | 89
> +++++++++---------
> > >> >  src/ipa/raspberrypi/controller/rpi/awb.hpp    |  8 +-
> > >> >  .../controller/rpi/black_level.cpp            | 12 +--
> > >> >  .../controller/rpi/black_level.hpp            |  2 +-
> > >> >  src/ipa/raspberrypi/controller/rpi/ccm.cpp    | 28 +++---
> > >> >  src/ipa/raspberrypi/controller/rpi/ccm.hpp    |  4 +-
> > >> >  .../raspberrypi/controller/rpi/contrast.cpp   | 18 ++--
> > >> >  .../raspberrypi/controller/rpi/contrast.hpp   |  2 +-
> > >> >  src/ipa/raspberrypi/controller/rpi/dpc.cpp    |  4 +-
> > >> >  src/ipa/raspberrypi/controller/rpi/dpc.hpp    |  2 +-
> > >> >  src/ipa/raspberrypi/controller/rpi/geq.cpp    | 10 +-
> > >> >  src/ipa/raspberrypi/controller/rpi/geq.hpp    |  2 +-
> > >> >  src/ipa/raspberrypi/controller/rpi/lux.cpp    | 12 +--
> > >> >  src/ipa/raspberrypi/controller/rpi/lux.hpp    |  2 +-
> > >> >  src/ipa/raspberrypi/controller/rpi/noise.cpp  |  6 +-
> > >> >  src/ipa/raspberrypi/controller/rpi/noise.hpp  |  2 +-
> > >> >  src/ipa/raspberrypi/controller/rpi/sdn.cpp    |  6 +-
> > >> >  src/ipa/raspberrypi/controller/rpi/sdn.hpp    |  2 +-
> > >> >  .../raspberrypi/controller/rpi/sharpen.cpp    |  8 +-
> > >> >  .../raspberrypi/controller/rpi/sharpen.hpp    |  2 +-
> > >> >  src/ipa/raspberrypi/meson.build               |  1 -
> > >> >  src/ipa/raspberrypi/raspberrypi.cpp           |  1 +
> > >> >  32 files changed, 241 insertions(+), 240 deletions(-)
>
> --
> Regards,
>
> Laurent Pinchart
>
David Plowman July 25, 2022, 3:48 p.m. UTC | #6
Hi everyone

On Mon, 25 Jul 2022 at 15:48, Naushir Patuck <naush@raspberrypi.com> wrote:
>
> Hi Laurent,
>
> On Mon, 25 Jul 2022 at 14:50, Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
>>
>> Hello,
>>
>> On Mon, Jul 25, 2022 at 11:50:06AM +0100, David Plowman wrote:
>> > On Mon, 25 Jul 2022 at 11:26, Naushir Patuck <naush@raspberrypi.com> wrote:
>> > > On Fri, 22 Jul 2022 at 20:25, Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote:
>> > >> On Mon, Jul 18, 2022 at 09:15:58AM +0100, Naushir Patuck wrote:
>> > >> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> > >> >
>> > >> > The Raspberry Pi IPA module depends on boost only to parse the JSON
>> > >> > tuning data files. As libcamera depends on libyaml, use the YamlParser
>> > >> > class to parse those files and drop the dependency on boost.
>> > >> >
>> > >> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> > >>
>> > >> I assume you're fine with this patch as you've posted it as part of your
>> > >> series, but could you give it a review ? :-)
>> > >
>> > > I did have one outstanding query on this about default values.
>> > >
>> > > If you recall, we discussed having YamlObject::get() not take in a default value
>> > > and complain loudly if the key is not present, similar to what the Boost parser
>> > > does now.  This will help avoid possibly hard to debug issues if a critical
>> > > parameter is missing from the tuning config.  David, what are your thoughts?
>> >
>> > I agree it would be nice to get some kind of error or at least warning
>> > if something that we really expected is not present. Possibly we could
>> > review some of those and provide default values in more cases, but I'm
>> > guessing that's not the kind of thing to "hide" inside a patch that
>> > isn't meant to change the behaviour of any algorithms.
>>
>> I agree, that's a good point.
>>
>> The boost json parser will throw an exception in this case, which I
>> can't replicate in YamlObject. I can update the Read() function to
>> return an error, would it be enough to log a message at the top level,
>> or would you like individual log statements in every location to tell
>> which parameter was missing ?
>
>
> Having read() return an error code - provided no default is set is a good idea.
> Then the top level can decide how to handle this - a LOG(Fatal) message
> in our case.  David, what do you think?

Works for me!

David

>
> Regards,
> Naush
>
>>
>> > > Do you think this is something that we can add easily to this patch?
>> > >
>> > >> > ---
>> > >> >  README.rst                                    |  6 --
>> > >> >  src/ipa/raspberrypi/controller/algorithm.cpp  |  2 +-
>> > >> >  src/ipa/raspberrypi/controller/algorithm.hpp  |  6 +-
>> > >> >  src/ipa/raspberrypi/controller/controller.cpp | 27 ++++--
>> > >> >  src/ipa/raspberrypi/controller/pwl.cpp        | 12 ++-
>> > >> >  src/ipa/raspberrypi/controller/pwl.hpp        |  5 +-
>> > >> >  src/ipa/raspberrypi/controller/rpi/agc.cpp    | 94 +++++++++----------
>> > >> >  src/ipa/raspberrypi/controller/rpi/agc.hpp    | 10 +-
>> > >> >  src/ipa/raspberrypi/controller/rpi/alsc.cpp   | 94 +++++++++----------
>> > >> >  src/ipa/raspberrypi/controller/rpi/alsc.hpp   |  2 +-
>> > >> >  src/ipa/raspberrypi/controller/rpi/awb.cpp    | 89 +++++++++---------
>> > >> >  src/ipa/raspberrypi/controller/rpi/awb.hpp    |  8 +-
>> > >> >  .../controller/rpi/black_level.cpp            | 12 +--
>> > >> >  .../controller/rpi/black_level.hpp            |  2 +-
>> > >> >  src/ipa/raspberrypi/controller/rpi/ccm.cpp    | 28 +++---
>> > >> >  src/ipa/raspberrypi/controller/rpi/ccm.hpp    |  4 +-
>> > >> >  .../raspberrypi/controller/rpi/contrast.cpp   | 18 ++--
>> > >> >  .../raspberrypi/controller/rpi/contrast.hpp   |  2 +-
>> > >> >  src/ipa/raspberrypi/controller/rpi/dpc.cpp    |  4 +-
>> > >> >  src/ipa/raspberrypi/controller/rpi/dpc.hpp    |  2 +-
>> > >> >  src/ipa/raspberrypi/controller/rpi/geq.cpp    | 10 +-
>> > >> >  src/ipa/raspberrypi/controller/rpi/geq.hpp    |  2 +-
>> > >> >  src/ipa/raspberrypi/controller/rpi/lux.cpp    | 12 +--
>> > >> >  src/ipa/raspberrypi/controller/rpi/lux.hpp    |  2 +-
>> > >> >  src/ipa/raspberrypi/controller/rpi/noise.cpp  |  6 +-
>> > >> >  src/ipa/raspberrypi/controller/rpi/noise.hpp  |  2 +-
>> > >> >  src/ipa/raspberrypi/controller/rpi/sdn.cpp    |  6 +-
>> > >> >  src/ipa/raspberrypi/controller/rpi/sdn.hpp    |  2 +-
>> > >> >  .../raspberrypi/controller/rpi/sharpen.cpp    |  8 +-
>> > >> >  .../raspberrypi/controller/rpi/sharpen.hpp    |  2 +-
>> > >> >  src/ipa/raspberrypi/meson.build               |  1 -
>> > >> >  src/ipa/raspberrypi/raspberrypi.cpp           |  1 +
>> > >> >  32 files changed, 241 insertions(+), 240 deletions(-)
>>
>> --
>> Regards,
>>
>> Laurent Pinchart
Naushir Patuck July 26, 2022, 7:04 a.m. UTC | #7
On Mon, 25 Jul 2022 at 16:49, David Plowman <david.plowman@raspberrypi.com>
wrote:

> Hi everyone
>
> On Mon, 25 Jul 2022 at 15:48, Naushir Patuck <naush@raspberrypi.com>
> wrote:
> >
> > Hi Laurent,
> >
> > On Mon, 25 Jul 2022 at 14:50, Laurent Pinchart <
> laurent.pinchart@ideasonboard.com> wrote:
> >>
> >> Hello,
> >>
> >> On Mon, Jul 25, 2022 at 11:50:06AM +0100, David Plowman wrote:
> >> > On Mon, 25 Jul 2022 at 11:26, Naushir Patuck <naush@raspberrypi.com>
> wrote:
> >> > > On Fri, 22 Jul 2022 at 20:25, Laurent Pinchart <
> laurent.pinchart@ideasonboard.com> wrote:
> >> > >> On Mon, Jul 18, 2022 at 09:15:58AM +0100, Naushir Patuck wrote:
> >> > >> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >> > >> >
> >> > >> > The Raspberry Pi IPA module depends on boost only to parse the
> JSON
> >> > >> > tuning data files. As libcamera depends on libyaml, use the
> YamlParser
> >> > >> > class to parse those files and drop the dependency on boost.
> >> > >> >
> >> > >> > Signed-off-by: Laurent Pinchart <
> laurent.pinchart@ideasonboard.com>
> >> > >>
> >> > >> I assume you're fine with this patch as you've posted it as part
> of your
> >> > >> series, but could you give it a review ? :-)
> >> > >
> >> > > I did have one outstanding query on this about default values.
> >> > >
> >> > > If you recall, we discussed having YamlObject::get() not take in a
> default value
> >> > > and complain loudly if the key is not present, similar to what the
> Boost parser
> >> > > does now.  This will help avoid possibly hard to debug issues if a
> critical
> >> > > parameter is missing from the tuning config.  David, what are your
> thoughts?
> >> >
> >> > I agree it would be nice to get some kind of error or at least warning
> >> > if something that we really expected is not present. Possibly we could
> >> > review some of those and provide default values in more cases, but I'm
> >> > guessing that's not the kind of thing to "hide" inside a patch that
> >> > isn't meant to change the behaviour of any algorithms.
> >>
> >> I agree, that's a good point.
> >>
> >> The boost json parser will throw an exception in this case, which I
> >> can't replicate in YamlObject. I can update the Read() function to
> >> return an error, would it be enough to log a message at the top level,
> >> or would you like individual log statements in every location to tell
> >> which parameter was missing ?
> >
> >
> > Having read() return an error code - provided no default is set is a
> good idea.
> > Then the top level can decide how to handle this - a LOG(Fatal) message
> > in our case.  David, what do you think?
>
> Works for me!
>

Would it make sense to use std::optional as a return value from
YamlObject::get() in
a similar way to what we now do for ControlList::get()?

Naush


>
> David
>
> >
> > Regards,
> > Naush
> >
> >>
> >> > > Do you think this is something that we can add easily to this patch?
> >> > >
> >> > >> > ---
> >> > >> >  README.rst                                    |  6 --
> >> > >> >  src/ipa/raspberrypi/controller/algorithm.cpp  |  2 +-
> >> > >> >  src/ipa/raspberrypi/controller/algorithm.hpp  |  6 +-
> >> > >> >  src/ipa/raspberrypi/controller/controller.cpp | 27 ++++--
> >> > >> >  src/ipa/raspberrypi/controller/pwl.cpp        | 12 ++-
> >> > >> >  src/ipa/raspberrypi/controller/pwl.hpp        |  5 +-
> >> > >> >  src/ipa/raspberrypi/controller/rpi/agc.cpp    | 94
> +++++++++----------
> >> > >> >  src/ipa/raspberrypi/controller/rpi/agc.hpp    | 10 +-
> >> > >> >  src/ipa/raspberrypi/controller/rpi/alsc.cpp   | 94
> +++++++++----------
> >> > >> >  src/ipa/raspberrypi/controller/rpi/alsc.hpp   |  2 +-
> >> > >> >  src/ipa/raspberrypi/controller/rpi/awb.cpp    | 89
> +++++++++---------
> >> > >> >  src/ipa/raspberrypi/controller/rpi/awb.hpp    |  8 +-
> >> > >> >  .../controller/rpi/black_level.cpp            | 12 +--
> >> > >> >  .../controller/rpi/black_level.hpp            |  2 +-
> >> > >> >  src/ipa/raspberrypi/controller/rpi/ccm.cpp    | 28 +++---
> >> > >> >  src/ipa/raspberrypi/controller/rpi/ccm.hpp    |  4 +-
> >> > >> >  .../raspberrypi/controller/rpi/contrast.cpp   | 18 ++--
> >> > >> >  .../raspberrypi/controller/rpi/contrast.hpp   |  2 +-
> >> > >> >  src/ipa/raspberrypi/controller/rpi/dpc.cpp    |  4 +-
> >> > >> >  src/ipa/raspberrypi/controller/rpi/dpc.hpp    |  2 +-
> >> > >> >  src/ipa/raspberrypi/controller/rpi/geq.cpp    | 10 +-
> >> > >> >  src/ipa/raspberrypi/controller/rpi/geq.hpp    |  2 +-
> >> > >> >  src/ipa/raspberrypi/controller/rpi/lux.cpp    | 12 +--
> >> > >> >  src/ipa/raspberrypi/controller/rpi/lux.hpp    |  2 +-
> >> > >> >  src/ipa/raspberrypi/controller/rpi/noise.cpp  |  6 +-
> >> > >> >  src/ipa/raspberrypi/controller/rpi/noise.hpp  |  2 +-
> >> > >> >  src/ipa/raspberrypi/controller/rpi/sdn.cpp    |  6 +-
> >> > >> >  src/ipa/raspberrypi/controller/rpi/sdn.hpp    |  2 +-
> >> > >> >  .../raspberrypi/controller/rpi/sharpen.cpp    |  8 +-
> >> > >> >  .../raspberrypi/controller/rpi/sharpen.hpp    |  2 +-
> >> > >> >  src/ipa/raspberrypi/meson.build               |  1 -
> >> > >> >  src/ipa/raspberrypi/raspberrypi.cpp           |  1 +
> >> > >> >  32 files changed, 241 insertions(+), 240 deletions(-)
> >>
> >> --
> >> Regards,
> >>
> >> Laurent Pinchart
>
Laurent Pinchart July 26, 2022, 8:15 a.m. UTC | #8
Hi Naush,

On Tue, Jul 26, 2022 at 08:04:57AM +0100, Naushir Patuck wrote:
> On Mon, 25 Jul 2022 at 16:49, David Plowman wrote:
> > On Mon, 25 Jul 2022 at 15:48, Naushir Patuck wrote:
> > > On Mon, 25 Jul 2022 at 14:50, Laurent Pinchart wrote:
> > >> On Mon, Jul 25, 2022 at 11:50:06AM +0100, David Plowman wrote:
> > >> > On Mon, 25 Jul 2022 at 11:26, Naushir Patuck wrote:
> > >> > > On Fri, 22 Jul 2022 at 20:25, Laurent Pinchart wrote:
> > >> > >> On Mon, Jul 18, 2022 at 09:15:58AM +0100, Naushir Patuck wrote:
> > >> > >> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > >> > >> >
> > >> > >> > The Raspberry Pi IPA module depends on boost only to parse the JSON
> > >> > >> > tuning data files. As libcamera depends on libyaml, use the YamlParser
> > >> > >> > class to parse those files and drop the dependency on boost.
> > >> > >> >
> > >> > >> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > >> > >>
> > >> > >> I assume you're fine with this patch as you've posted it as part of your
> > >> > >> series, but could you give it a review ? :-)
> > >> > >
> > >> > > I did have one outstanding query on this about default values.
> > >> > >
> > >> > > If you recall, we discussed having YamlObject::get() not take in a default value
> > >> > > and complain loudly if the key is not present, similar to what the Boost parser
> > >> > > does now.  This will help avoid possibly hard to debug issues if a critical
> > >> > > parameter is missing from the tuning config.  David, what are your thoughts?
> > >> >
> > >> > I agree it would be nice to get some kind of error or at least warning
> > >> > if something that we really expected is not present. Possibly we could
> > >> > review some of those and provide default values in more cases, but I'm
> > >> > guessing that's not the kind of thing to "hide" inside a patch that
> > >> > isn't meant to change the behaviour of any algorithms.
> > >>
> > >> I agree, that's a good point.
> > >>
> > >> The boost json parser will throw an exception in this case, which I
> > >> can't replicate in YamlObject. I can update the Read() function to
> > >> return an error, would it be enough to log a message at the top level,
> > >> or would you like individual log statements in every location to tell
> > >> which parameter was missing ?
> > >
> > > Having read() return an error code - provided no default is set is a good idea.
> > > Then the top level can decide how to handle this - a LOG(Fatal) message
> > > in our case.  David, what do you think?
> >
> > Works for me!
> 
> Would it make sense to use std::optional as a return value from YamlObject::get() in
> a similar way to what we now do for ControlList::get()?

Funny you mention that, it took part of last night to implement it :-)
I'll post patches soon.

> > >> > > Do you think this is something that we can add easily to this patch?
> > >> > >
> > >> > >> > ---
> > >> > >> >  README.rst                                    |  6 --
> > >> > >> >  src/ipa/raspberrypi/controller/algorithm.cpp  |  2 +-
> > >> > >> >  src/ipa/raspberrypi/controller/algorithm.hpp  |  6 +-
> > >> > >> >  src/ipa/raspberrypi/controller/controller.cpp | 27 ++++--
> > >> > >> >  src/ipa/raspberrypi/controller/pwl.cpp        | 12 ++-
> > >> > >> >  src/ipa/raspberrypi/controller/pwl.hpp        |  5 +-
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/agc.cpp    | 94 +++++++++----------
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/agc.hpp    | 10 +-
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/alsc.cpp   | 94 +++++++++----------
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/alsc.hpp   |  2 +-
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/awb.cpp    | 89 +++++++++---------
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/awb.hpp    |  8 +-
> > >> > >> >  .../controller/rpi/black_level.cpp            | 12 +--
> > >> > >> >  .../controller/rpi/black_level.hpp            |  2 +-
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/ccm.cpp    | 28 +++---
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/ccm.hpp    |  4 +-
> > >> > >> >  .../raspberrypi/controller/rpi/contrast.cpp   | 18 ++--
> > >> > >> >  .../raspberrypi/controller/rpi/contrast.hpp   |  2 +-
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/dpc.cpp    |  4 +-
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/dpc.hpp    |  2 +-
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/geq.cpp    | 10 +-
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/geq.hpp    |  2 +-
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/lux.cpp    | 12 +--
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/lux.hpp    |  2 +-
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/noise.cpp  |  6 +-
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/noise.hpp  |  2 +-
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/sdn.cpp    |  6 +-
> > >> > >> >  src/ipa/raspberrypi/controller/rpi/sdn.hpp    |  2 +-
> > >> > >> >  .../raspberrypi/controller/rpi/sharpen.cpp    |  8 +-
> > >> > >> >  .../raspberrypi/controller/rpi/sharpen.hpp    |  2 +-
> > >> > >> >  src/ipa/raspberrypi/meson.build               |  1 -
> > >> > >> >  src/ipa/raspberrypi/raspberrypi.cpp           |  1 +
> > >> > >> >  32 files changed, 241 insertions(+), 240 deletions(-)

Patch
diff mbox series

diff --git a/README.rst b/README.rst
index b9e72d81b90c..3d4e48ddc8f6 100644
--- a/README.rst
+++ b/README.rst
@@ -71,12 +71,6 @@  for improved debugging: [optional]
         information, and libunwind is not needed if both libdw and the glibc
         backtrace() function are available.
 
-for the Raspberry Pi IPA: [optional]
-        libboost-dev
-
-        Support for Raspberry Pi can be disabled through the meson
-         'pipelines' option to avoid this dependency.
-
 for device hotplug enumeration: [optional]
         libudev-dev
 
diff --git a/src/ipa/raspberrypi/controller/algorithm.cpp b/src/ipa/raspberrypi/controller/algorithm.cpp
index 43ad0a2be222..4fd36fc1be5b 100644
--- a/src/ipa/raspberrypi/controller/algorithm.cpp
+++ b/src/ipa/raspberrypi/controller/algorithm.cpp
@@ -9,7 +9,7 @@ 
 
 using namespace RPiController;
 
-void Algorithm::Read([[maybe_unused]] boost::property_tree::ptree const &params)
+void Algorithm::Read([[maybe_unused]] const libcamera::YamlObject &params)
 {
 }
 
diff --git a/src/ipa/raspberrypi/controller/algorithm.hpp b/src/ipa/raspberrypi/controller/algorithm.hpp
index 5123c87bab34..87bfca8d2045 100644
--- a/src/ipa/raspberrypi/controller/algorithm.hpp
+++ b/src/ipa/raspberrypi/controller/algorithm.hpp
@@ -13,9 +13,9 @@ 
 #include <memory>
 #include <map>
 
-#include "controller.hpp"
+#include "libcamera/internal/yaml_parser.h"
 
-#include <boost/property_tree/ptree.hpp>
+#include "controller.hpp"
 
 namespace RPiController {
 
@@ -33,7 +33,7 @@  public:
 	virtual bool IsPaused() const { return paused_; }
 	virtual void Pause() { paused_ = true; }
 	virtual void Resume() { paused_ = false; }
-	virtual void Read(boost::property_tree::ptree const &params);
+	virtual void Read(const libcamera::YamlObject &params);
 	virtual void Initialise();
 	virtual void SwitchMode(CameraMode const &camera_mode, Metadata *metadata);
 	virtual void Prepare(Metadata *image_metadata);
diff --git a/src/ipa/raspberrypi/controller/controller.cpp b/src/ipa/raspberrypi/controller/controller.cpp
index d3433ad2e7e8..67d650ef0c1b 100644
--- a/src/ipa/raspberrypi/controller/controller.cpp
+++ b/src/ipa/raspberrypi/controller/controller.cpp
@@ -5,14 +5,16 @@ 
  * controller.cpp - ISP controller
  */
 
+#include <assert.h>
+
+#include <libcamera/base/file.h>
 #include <libcamera/base/log.h>
 
+#include "libcamera/internal/yaml_parser.h"
+
 #include "algorithm.hpp"
 #include "controller.hpp"
 
-#include <boost/property_tree/json_parser.hpp>
-#include <boost/property_tree/ptree.hpp>
-
 using namespace RPiController;
 using namespace libcamera;
 
@@ -32,16 +34,23 @@  Controller::~Controller() {}
 
 void Controller::Read(char const *filename)
 {
-	boost::property_tree::ptree root;
-	boost::property_tree::read_json(filename, root);
-	for (auto const &key_and_value : root) {
-		Algorithm *algo = CreateAlgorithm(key_and_value.first.c_str());
+	File file(filename);
+	if (!file.open(File::OpenModeFlag::ReadOnly)) {
+		LOG(RPiController, Warning)
+			<< "Failed to open tuning file '" << filename << "'";
+		return;
+	}
+
+	std::unique_ptr<YamlObject> root = YamlParser::parse(file);
+
+	for (auto const &[key, value] : root->asDict()) {
+		Algorithm *algo = CreateAlgorithm(key.c_str());
 		if (algo) {
-			algo->Read(key_and_value.second);
+			algo->Read(value);
 			algorithms_.push_back(AlgorithmPtr(algo));
 		} else
 			LOG(RPiController, Warning)
-				<< "No algorithm found for \"" << key_and_value.first << "\"";
+				<< "No algorithm found for \"" << key << "\"";
 	}
 }
 
diff --git a/src/ipa/raspberrypi/controller/pwl.cpp b/src/ipa/raspberrypi/controller/pwl.cpp
index 130c820b559f..9c7bc94dd484 100644
--- a/src/ipa/raspberrypi/controller/pwl.cpp
+++ b/src/ipa/raspberrypi/controller/pwl.cpp
@@ -12,13 +12,15 @@ 
 
 using namespace RPiController;
 
-void Pwl::Read(boost::property_tree::ptree const &params)
+void Pwl::Read(const libcamera::YamlObject &params)
 {
-	for (auto it = params.begin(); it != params.end(); it++) {
-		double x = it->second.get_value<double>();
-		assert(it == params.begin() || x > points_.back().x);
+	const auto &list = params.asList();
+
+	for (auto it = list.begin(); it != list.end(); it++) {
+		double x = it->get<double>(0.0);
+		assert(it == list.begin() || x > points_.back().x);
 		it++;
-		double y = it->second.get_value<double>();
+		double y = it->get<double>(0.0);
 		points_.push_back(Point(x, y));
 	}
 	assert(points_.size() >= 2);
diff --git a/src/ipa/raspberrypi/controller/pwl.hpp b/src/ipa/raspberrypi/controller/pwl.hpp
index 484672f64095..70df4ba0daea 100644
--- a/src/ipa/raspberrypi/controller/pwl.hpp
+++ b/src/ipa/raspberrypi/controller/pwl.hpp
@@ -6,10 +6,11 @@ 
  */
 #pragma once
 
+#include <functional>
 #include <math.h>
 #include <vector>
 
-#include <boost/property_tree/ptree.hpp>
+#include "libcamera/internal/yaml_parser.h"
 
 namespace RPiController {
 
@@ -55,7 +56,7 @@  public:
 	};
 	Pwl() {}
 	Pwl(std::vector<Point> const &points) : points_(points) {}
-	void Read(boost::property_tree::ptree const &params);
+	void Read(const libcamera::YamlObject &params);
 	void Append(double x, double y, const double eps = 1e-6);
 	void Prepend(double x, double y, const double eps = 1e-6);
 	Interval Domain() const;
diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp
index f6a9cb0a2cd8..c82f29600be7 100644
--- a/src/ipa/raspberrypi/controller/rpi/agc.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp
@@ -30,13 +30,13 @@  LOG_DEFINE_CATEGORY(RPiAgc)
 
 #define PIPELINE_BITS 13 // seems to be a 13-bit pipeline
 
-void AgcMeteringMode::Read(boost::property_tree::ptree const &params)
+void AgcMeteringMode::Read(const libcamera::YamlObject &params)
 {
 	int num = 0;
-	for (auto &p : params.get_child("weights")) {
+	for (const auto &p : params["weights"].asList()) {
 		if (num == AGC_STATS_SIZE)
 			throw std::runtime_error("AgcConfig: too many weights");
-		weights[num++] = p.second.get_value<double>();
+		weights[num++] = p.get<double>(0.0);
 	}
 	if (num != AGC_STATS_SIZE)
 		throw std::runtime_error("AgcConfig: insufficient weights");
@@ -44,39 +44,39 @@  void AgcMeteringMode::Read(boost::property_tree::ptree const &params)
 
 static std::string
 read_metering_modes(std::map<std::string, AgcMeteringMode> &metering_modes,
-		    boost::property_tree::ptree const &params)
+		    const libcamera::YamlObject &params)
 {
 	std::string first;
-	for (auto &p : params) {
+	for (const auto &[key, value] : params.asDict()) {
 		AgcMeteringMode metering_mode;
-		metering_mode.Read(p.second);
-		metering_modes[p.first] = std::move(metering_mode);
+		metering_mode.Read(value);
+		metering_modes[key] = std::move(metering_mode);
 		if (first.empty())
-			first = p.first;
+			first = key;
 	}
 	return first;
 }
 
 static int read_list(std::vector<double> &list,
-		     boost::property_tree::ptree const &params)
+		     const libcamera::YamlObject &params)
 {
-	for (auto &p : params)
-		list.push_back(p.second.get_value<double>());
+	for (const auto &p : params.asList())
+		list.push_back(p.get<double>(0.0));
 	return list.size();
 }
 
 static int read_list(std::vector<Duration> &list,
-		     boost::property_tree::ptree const &params)
+		     const libcamera::YamlObject &params)
 {
-	for (auto &p : params)
-		list.push_back(p.second.get_value<double>() * 1us);
+	for (const auto &p : params.asList())
+		list.push_back(p.get<double>(0.0) * 1us);
 	return list.size();
 }
 
-void AgcExposureMode::Read(boost::property_tree::ptree const &params)
+void AgcExposureMode::Read(const libcamera::YamlObject &params)
 {
-	int num_shutters = read_list(shutter, params.get_child("shutter"));
-	int num_ags = read_list(gain, params.get_child("gain"));
+	int num_shutters = read_list(shutter, params["shutter"]);
+	int num_ags = read_list(gain, params["gain"]);
 	if (num_shutters < 2 || num_ags < 2)
 		throw std::runtime_error(
 			"AgcConfig: must have at least two entries in exposure profile");
@@ -87,40 +87,40 @@  void AgcExposureMode::Read(boost::property_tree::ptree const &params)
 
 static std::string
 read_exposure_modes(std::map<std::string, AgcExposureMode> &exposure_modes,
-		    boost::property_tree::ptree const &params)
+		    const libcamera::YamlObject &params)
 {
 	std::string first;
-	for (auto &p : params) {
+	for (const auto &[key, value] : params.asDict()) {
 		AgcExposureMode exposure_mode;
-		exposure_mode.Read(p.second);
-		exposure_modes[p.first] = std::move(exposure_mode);
+		exposure_mode.Read(value);
+		exposure_modes[key] = std::move(exposure_mode);
 		if (first.empty())
-			first = p.first;
+			first = key;
 	}
 	return first;
 }
 
-void AgcConstraint::Read(boost::property_tree::ptree const &params)
+void AgcConstraint::Read(const libcamera::YamlObject &params)
 {
-	std::string bound_string = params.get<std::string>("bound", "");
+	std::string bound_string = params["bound"].get<std::string>("");
 	transform(bound_string.begin(), bound_string.end(),
 		  bound_string.begin(), ::toupper);
 	if (bound_string != "UPPER" && bound_string != "LOWER")
 		throw std::runtime_error(
 			"AGC constraint type should be UPPER or LOWER");
 	bound = bound_string == "UPPER" ? Bound::UPPER : Bound::LOWER;
-	q_lo = params.get<double>("q_lo");
-	q_hi = params.get<double>("q_hi");
-	Y_target.Read(params.get_child("y_target"));
+	q_lo = params["q_lo"].get<double>(0.0);
+	q_hi = params["q_hi"].get<double>(0.0);
+	Y_target.Read(params["y_target"]);
 }
 
 static AgcConstraintMode
-read_constraint_mode(boost::property_tree::ptree const &params)
+read_constraint_mode(const libcamera::YamlObject &params)
 {
 	AgcConstraintMode mode;
-	for (auto &p : params) {
+	for (const auto &p : params.asList()) {
 		AgcConstraint constraint;
-		constraint.Read(p.second);
+		constraint.Read(p);
 		mode.push_back(std::move(constraint));
 	}
 	return mode;
@@ -128,36 +128,36 @@  read_constraint_mode(boost::property_tree::ptree const &params)
 
 static std::string read_constraint_modes(
 	std::map<std::string, AgcConstraintMode> &constraint_modes,
-	boost::property_tree::ptree const &params)
+	const libcamera::YamlObject &params)
 {
 	std::string first;
-	for (auto &p : params) {
-		constraint_modes[p.first] = read_constraint_mode(p.second);
+	for (const auto &[key, value] : params.asDict()) {
+		constraint_modes[key] = read_constraint_mode(value);
 		if (first.empty())
-			first = p.first;
+			first = key;
 	}
 	return first;
 }
 
-void AgcConfig::Read(boost::property_tree::ptree const &params)
+void AgcConfig::Read(const libcamera::YamlObject &params)
 {
 	LOG(RPiAgc, Debug) << "AgcConfig";
 	default_metering_mode = read_metering_modes(
-		metering_modes, params.get_child("metering_modes"));
+		metering_modes, params["metering_modes"]);
 	default_exposure_mode = read_exposure_modes(
-		exposure_modes, params.get_child("exposure_modes"));
+		exposure_modes, params["exposure_modes"]);
 	default_constraint_mode = read_constraint_modes(
-		constraint_modes, params.get_child("constraint_modes"));
-	Y_target.Read(params.get_child("y_target"));
-	speed = params.get<double>("speed", 0.2);
-	startup_frames = params.get<uint16_t>("startup_frames", 10);
-	convergence_frames = params.get<unsigned int>("convergence_frames", 6);
+		constraint_modes, params["constraint_modes"]);
+	Y_target.Read(params["y_target"]);
+	speed = params["speed"].get<double>(0.2);
+	startup_frames = params["startup_frames"].get<uint16_t>(10);
+	convergence_frames = params["convergence_frames"].get<unsigned int>(6);
 	fast_reduce_threshold =
-		params.get<double>("fast_reduce_threshold", 0.4);
-	base_ev = params.get<double>("base_ev", 1.0);
+		params["fast_reduce_threshold"].get<double>(0.4);
+	base_ev = params["base_ev"].get<double>(1.0);
 	// Start with quite a low value as ramping up is easier than ramping down.
-	default_exposure_time = params.get<double>("default_exposure_time", 1000) * 1us;
-	default_analogue_gain = params.get<double>("default_analogue_gain", 1.0);
+	default_exposure_time = params["default_exposure_time"].get<double>(1000) * 1us;
+	default_analogue_gain = params["default_analogue_gain"].get<double>(1.0);
 }
 
 Agc::ExposureValues::ExposureValues()
@@ -186,7 +186,7 @@  char const *Agc::Name() const
 	return NAME;
 }
 
-void Agc::Read(boost::property_tree::ptree const &params)
+void Agc::Read(const libcamera::YamlObject &params)
 {
 	LOG(RPiAgc, Debug) << "Agc";
 	config_.Read(params);
diff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp
index c100d3128c90..7794ba744efc 100644
--- a/src/ipa/raspberrypi/controller/rpi/agc.hpp
+++ b/src/ipa/raspberrypi/controller/rpi/agc.hpp
@@ -26,13 +26,13 @@  namespace RPiController {
 
 struct AgcMeteringMode {
 	double weights[AGC_STATS_SIZE];
-	void Read(boost::property_tree::ptree const &params);
+	void Read(const libcamera::YamlObject &params);
 };
 
 struct AgcExposureMode {
 	std::vector<libcamera::utils::Duration> shutter;
 	std::vector<double> gain;
-	void Read(boost::property_tree::ptree const &params);
+	void Read(const libcamera::YamlObject &params);
 };
 
 struct AgcConstraint {
@@ -41,13 +41,13 @@  struct AgcConstraint {
 	double q_lo;
 	double q_hi;
 	Pwl Y_target;
-	void Read(boost::property_tree::ptree const &params);
+	void Read(const libcamera::YamlObject &params);
 };
 
 typedef std::vector<AgcConstraint> AgcConstraintMode;
 
 struct AgcConfig {
-	void Read(boost::property_tree::ptree const &params);
+	void Read(const libcamera::YamlObject &params);
 	std::map<std::string, AgcMeteringMode> metering_modes;
 	std::map<std::string, AgcExposureMode> exposure_modes;
 	std::map<std::string, AgcConstraintMode> constraint_modes;
@@ -72,7 +72,7 @@  class Agc : public AgcAlgorithm
 public:
 	Agc(Controller *controller);
 	char const *Name() const override;
-	void Read(boost::property_tree::ptree const &params) override;
+	void Read(const libcamera::YamlObject &params) override;
 	// AGC handles "pausing" for itself.
 	bool IsPaused() const override;
 	void Pause() override;
diff --git a/src/ipa/raspberrypi/controller/rpi/alsc.cpp b/src/ipa/raspberrypi/controller/rpi/alsc.cpp
index e575c14a92db..b38b037c7713 100644
--- a/src/ipa/raspberrypi/controller/rpi/alsc.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/alsc.cpp
@@ -5,6 +5,7 @@ 
  * alsc.cpp - ALSC (auto lens shading correction) control algorithm
  */
 
+#include <functional>
 #include <math.h>
 #include <numeric>
 
@@ -50,12 +51,12 @@  char const *Alsc::Name() const
 	return NAME;
 }
 
-static void generate_lut(double *lut, boost::property_tree::ptree const &params)
+static void generate_lut(double *lut, const libcamera::YamlObject &params)
 {
-	double cstrength = params.get<double>("corner_strength", 2.0);
+	double cstrength = params["corner_strength"].get<double>(2.0);
 	if (cstrength <= 1.0)
 		throw std::runtime_error("Alsc: corner_strength must be > 1.0");
-	double asymmetry = params.get<double>("asymmetry", 1.0);
+	double asymmetry = params["asymmetry"].get<double>(1.0);
 	if (asymmetry < 0)
 		throw std::runtime_error("Alsc: asymmetry must be >= 0");
 	double f1 = cstrength - 1, f2 = 1 + sqrt(cstrength);
@@ -73,50 +74,43 @@  static void generate_lut(double *lut, boost::property_tree::ptree const &params)
 	}
 }
 
-static void read_lut(double *lut, boost::property_tree::ptree const &params)
+static void read_lut(double *lut, const libcamera::YamlObject &params)
 {
+	if (params.size() != XY)
+		throw std::runtime_error(
+			"Alsc: invalid number of entries in LSC table");
+
 	int num = 0;
-	const int max_num = XY;
-	for (auto &p : params) {
-		if (num == max_num)
-			throw std::runtime_error(
-				"Alsc: too many entries in LSC table");
-		lut[num++] = p.second.get_value<double>();
-	}
-	if (num < max_num)
-		throw std::runtime_error("Alsc: too few entries in LSC table");
+	for (const auto &p : params.asList())
+		lut[num++] = p.get<double>(0.0);
 }
 
 static void read_calibrations(std::vector<AlscCalibration> &calibrations,
-			      boost::property_tree::ptree const &params,
+			      const libcamera::YamlObject &params,
 			      std::string const &name)
 {
-	if (params.get_child_optional(name)) {
+	if (params.contains(name)) {
 		double last_ct = 0;
-		for (auto &p : params.get_child(name)) {
-			double ct = p.second.get<double>("ct");
+		for (const auto &p : params[name].asList()) {
+			double ct = p["ct"].get<double>(0.0);
 			if (ct <= last_ct)
 				throw std::runtime_error(
 					"Alsc: entries in " + name +
 					" must be in increasing ct order");
 			AlscCalibration calibration;
 			calibration.ct = last_ct = ct;
-			boost::property_tree::ptree const &table =
-				p.second.get_child("table");
-			int num = 0;
-			for (auto it = table.begin(); it != table.end(); it++) {
-				if (num == XY)
-					throw std::runtime_error(
-						"Alsc: too many values for ct " +
-						std::to_string(ct) + " in " +
-						name);
-				calibration.table[num++] =
-					it->second.get_value<double>();
-			}
-			if (num != XY)
+
+			const libcamera::YamlObject &table = p["table"];
+			if (table.size() != XY)
 				throw std::runtime_error(
-					"Alsc: too few values for ct " +
-					std::to_string(ct) + " in " + name);
+					"Alsc: incorrect number of values for ct " +
+					std::to_string(ct) + " in " +
+					name);
+
+			int num = 0;
+			for (const auto &value : table.asList())
+				calibration.table[num++] = value.get<double>(0.0);
+
 			calibrations.push_back(calibration);
 			LOG(RPiAlsc, Debug)
 				<< "Read " << name << " calibration for ct " << ct;
@@ -124,35 +118,35 @@  static void read_calibrations(std::vector<AlscCalibration> &calibrations,
 	}
 }
 
-void Alsc::Read(boost::property_tree::ptree const &params)
+void Alsc::Read(const libcamera::YamlObject &params)
 {
-	config_.frame_period = params.get<uint16_t>("frame_period", 12);
-	config_.startup_frames = params.get<uint16_t>("startup_frames", 10);
-	config_.speed = params.get<double>("speed", 0.05);
-	double sigma = params.get<double>("sigma", 0.01);
-	config_.sigma_Cr = params.get<double>("sigma_Cr", sigma);
-	config_.sigma_Cb = params.get<double>("sigma_Cb", sigma);
-	config_.min_count = params.get<double>("min_count", 10.0);
-	config_.min_G = params.get<uint16_t>("min_G", 50);
-	config_.omega = params.get<double>("omega", 1.3);
-	config_.n_iter = params.get<uint32_t>("n_iter", X + Y);
+	config_.frame_period = params["frame_period"].get<uint16_t>(12);
+	config_.startup_frames = params["startup_frames"].get<uint16_t>(10);
+	config_.speed = params["speed"].get<double>(0.05);
+	double sigma = params["sigma"].get<double>(0.01);
+	config_.sigma_Cr = params["sigma_Cr"].get<double>(sigma);
+	config_.sigma_Cb = params["sigma_Cb"].get<double>(sigma);
+	config_.min_count = params["min_count"].get<double>(10.0);
+	config_.min_G = params["min_G"].get<uint16_t>(50);
+	config_.omega = params["omega"].get<double>(1.3);
+	config_.n_iter = params["n_iter"].get<uint32_t>(X + Y);
 	config_.luminance_strength =
-		params.get<double>("luminance_strength", 1.0);
+		params["luminance_strength"].get<double>(1.0);
 	for (int i = 0; i < XY; i++)
 		config_.luminance_lut[i] = 1.0;
-	if (params.get_child_optional("corner_strength"))
+	if (params.contains("corner_strength"))
 		generate_lut(config_.luminance_lut, params);
-	else if (params.get_child_optional("luminance_lut"))
+	else if (params.contains("luminance_lut"))
 		read_lut(config_.luminance_lut,
-			 params.get_child("luminance_lut"));
+			 params["luminance_lut"]);
 	else
 		LOG(RPiAlsc, Warning)
 			<< "no luminance table - assume unity everywhere";
 	read_calibrations(config_.calibrations_Cr, params, "calibrations_Cr");
 	read_calibrations(config_.calibrations_Cb, params, "calibrations_Cb");
-	config_.default_ct = params.get<double>("default_ct", 4500.0);
-	config_.threshold = params.get<double>("threshold", 1e-3);
-	config_.lambda_bound = params.get<double>("lambda_bound", 0.05);
+	config_.default_ct = params["default_ct"].get<double>(4500.0);
+	config_.threshold = params["threshold"].get<double>(1e-3);
+	config_.lambda_bound = params["lambda_bound"].get<double>(0.05);
 }
 
 static double get_ct(Metadata *metadata, double default_ct);
diff --git a/src/ipa/raspberrypi/controller/rpi/alsc.hpp b/src/ipa/raspberrypi/controller/rpi/alsc.hpp
index d1dbe0d1d22d..9d28c1b49a6d 100644
--- a/src/ipa/raspberrypi/controller/rpi/alsc.hpp
+++ b/src/ipa/raspberrypi/controller/rpi/alsc.hpp
@@ -52,7 +52,7 @@  public:
 	char const *Name() const override;
 	void Initialise() override;
 	void SwitchMode(CameraMode const &camera_mode, Metadata *metadata) override;
-	void Read(boost::property_tree::ptree const &params) override;
+	void Read(const libcamera::YamlObject &params) override;
 	void Prepare(Metadata *image_metadata) override;
 	void Process(StatisticsPtr &stats, Metadata *image_metadata) override;
 
diff --git a/src/ipa/raspberrypi/controller/rpi/awb.cpp b/src/ipa/raspberrypi/controller/rpi/awb.cpp
index d4c934473832..1c40bf878cd3 100644
--- a/src/ipa/raspberrypi/controller/rpi/awb.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/awb.cpp
@@ -5,6 +5,8 @@ 
  * awb.cpp - AWB control algorithm
  */
 
+#include <assert.h>
+
 #include <libcamera/base/log.h>
 
 #include "../lux_status.h"
@@ -24,33 +26,35 @@  LOG_DEFINE_CATEGORY(RPiAwb)
 // todo - the locking in this algorithm needs some tidying up as has been done
 // elsewhere (ALSC and AGC).
 
-void AwbMode::Read(boost::property_tree::ptree const &params)
+void AwbMode::Read(const libcamera::YamlObject &params)
 {
-	ct_lo = params.get<double>("lo");
-	ct_hi = params.get<double>("hi");
+	ct_lo = params["lo"].get<double>(0.0);
+	ct_hi = params["hi"].get<double>(0.0);
 }
 
-void AwbPrior::Read(boost::property_tree::ptree const &params)
+void AwbPrior::Read(const libcamera::YamlObject &params)
 {
-	lux = params.get<double>("lux");
-	prior.Read(params.get_child("prior"));
+	lux = params["lux"].get<double>(0.0);
+	prior.Read(params["prior"]);
 }
 
 static void read_ct_curve(Pwl &ct_r, Pwl &ct_b,
-			  boost::property_tree::ptree const &params)
+			  const libcamera::YamlObject &params)
 {
+	const auto &list = params.asList();
 	int num = 0;
-	for (auto it = params.begin(); it != params.end(); it++) {
-		double ct = it->second.get_value<double>();
-		assert(it == params.begin() || ct != ct_r.Domain().end);
-		if (++it == params.end())
+
+	for (auto it = list.begin(); it != list.end(); it++) {
+		double ct = it->get<double>(0.0);
+		assert(it == list.begin() || ct != ct_r.Domain().end);
+		if (++it == list.end())
 			throw std::runtime_error(
 				"AwbConfig: incomplete CT curve entry");
-		ct_r.Append(ct, it->second.get_value<double>());
-		if (++it == params.end())
+		ct_r.Append(ct, it->get<double>(0.0));
+		if (++it == list.end())
 			throw std::runtime_error(
 				"AwbConfig: incomplete CT curve entry");
-		ct_b.Append(ct, it->second.get_value<double>());
+		ct_b.Append(ct, it->get<double>(0.0));
 		num++;
 	}
 	if (num < 2)
@@ -58,19 +62,19 @@  static void read_ct_curve(Pwl &ct_r, Pwl &ct_b,
 			"AwbConfig: insufficient points in CT curve");
 }
 
-void AwbConfig::Read(boost::property_tree::ptree const &params)
+void AwbConfig::Read(const libcamera::YamlObject &params)
 {
-	bayes = params.get<int>("bayes", 1);
-	frame_period = params.get<uint16_t>("frame_period", 10);
-	startup_frames = params.get<uint16_t>("startup_frames", 10);
-	convergence_frames = params.get<unsigned int>("convergence_frames", 3);
-	speed = params.get<double>("speed", 0.05);
-	if (params.get_child_optional("ct_curve"))
-		read_ct_curve(ct_r, ct_b, params.get_child("ct_curve"));
-	if (params.get_child_optional("priors")) {
-		for (auto &p : params.get_child("priors")) {
+	bayes = params["bayes"].get<int>(1);
+	frame_period = params["frame_period"].get<uint16_t>(10);
+	startup_frames = params["startup_frames"].get<uint16_t>(10);
+	convergence_frames = params["convergence_frames"].get<unsigned int>(3);
+	speed = params["speed"].get<double>(0.05);
+	if (params.contains("ct_curve"))
+		read_ct_curve(ct_r, ct_b, params["ct_curve"]);
+	if (params.contains("priors")) {
+		for (const auto &p : params["priors"].asList()) {
 			AwbPrior prior;
-			prior.Read(p.second);
+			prior.Read(p);
 			if (!priors.empty() && prior.lux <= priors.back().lux)
 				throw std::runtime_error(
 					"AwbConfig: Prior must be ordered in increasing lux value");
@@ -80,28 +84,28 @@  void AwbConfig::Read(boost::property_tree::ptree const &params)
 			throw std::runtime_error(
 				"AwbConfig: no AWB priors configured");
 	}
-	if (params.get_child_optional("modes")) {
-		for (auto &p : params.get_child("modes")) {
-			modes[p.first].Read(p.second);
+	if (params.contains("modes")) {
+		for (const auto &[key, value] : params["modes"].asDict()) {
+			modes[key].Read(value);
 			if (default_mode == nullptr)
-				default_mode = &modes[p.first];
+				default_mode = &modes[key];
 		}
 		if (default_mode == nullptr)
 			throw std::runtime_error(
 				"AwbConfig: no AWB modes configured");
 	}
-	min_pixels = params.get<double>("min_pixels", 16.0);
-	min_G = params.get<uint16_t>("min_G", 32);
-	min_regions = params.get<uint32_t>("min_regions", 10);
-	delta_limit = params.get<double>("delta_limit", 0.2);
-	coarse_step = params.get<double>("coarse_step", 0.2);
-	transverse_pos = params.get<double>("transverse_pos", 0.01);
-	transverse_neg = params.get<double>("transverse_neg", 0.01);
+	min_pixels = params["min_pixels"].get<double>(16.0);
+	min_G = params["min_G"].get<uint16_t>(32);
+	min_regions = params["min_regions"].get<uint32_t>(10);
+	delta_limit = params["delta_limit"].get<double>(0.2);
+	coarse_step = params["coarse_step"].get<double>(0.2);
+	transverse_pos = params["transverse_pos"].get<double>(0.01);
+	transverse_neg = params["transverse_neg"].get<double>(0.01);
 	if (transverse_pos <= 0 || transverse_neg <= 0)
 		throw std::runtime_error(
 			"AwbConfig: transverse_pos/neg must be > 0");
-	sensitivity_r = params.get<double>("sensitivity_r", 1.0);
-	sensitivity_b = params.get<double>("sensitivity_b", 1.0);
+	sensitivity_r = params["sensitivity_r"].get<double>(1.0);
+	sensitivity_b = params["sensitivity_b"].get<double>(1.0);
 	if (bayes) {
 		if (ct_r.Empty() || ct_b.Empty() || priors.empty() ||
 		    default_mode == nullptr) {
@@ -110,10 +114,9 @@  void AwbConfig::Read(boost::property_tree::ptree const &params)
 			bayes = false;
 		}
 	}
-	fast = params.get<int>(
-		"fast", bayes); // default to fast for Bayesian, otherwise slow
-	whitepoint_r = params.get<double>("whitepoint_r", 0.0);
-	whitepoint_b = params.get<double>("whitepoint_b", 0.0);
+	fast = params[fast].get<int>(bayes); // default to fast for Bayesian, otherwise slow
+	whitepoint_r = params["whitepoint_r"].get<double>(0.0);
+	whitepoint_b = params["whitepoint_b"].get<double>(0.0);
 	if (bayes == false)
 		sensitivity_r = sensitivity_b =
 			1.0; // nor do sensitivities make any sense
@@ -144,7 +147,7 @@  char const *Awb::Name() const
 	return NAME;
 }
 
-void Awb::Read(boost::property_tree::ptree const &params)
+void Awb::Read(const libcamera::YamlObject &params)
 {
 	config_.Read(params);
 }
diff --git a/src/ipa/raspberrypi/controller/rpi/awb.hpp b/src/ipa/raspberrypi/controller/rpi/awb.hpp
index ac3dca6f42fc..41334f798e2f 100644
--- a/src/ipa/raspberrypi/controller/rpi/awb.hpp
+++ b/src/ipa/raspberrypi/controller/rpi/awb.hpp
@@ -19,20 +19,20 @@  namespace RPiController {
 // Control algorithm to perform AWB calculations.
 
 struct AwbMode {
-	void Read(boost::property_tree::ptree const &params);
+	void Read(const libcamera::YamlObject &params);
 	double ct_lo; // low CT value for search
 	double ct_hi; // high CT value for search
 };
 
 struct AwbPrior {
-	void Read(boost::property_tree::ptree const &params);
+	void Read(const libcamera::YamlObject &params);
 	double lux; // lux level
 	Pwl prior; // maps CT to prior log likelihood for this lux level
 };
 
 struct AwbConfig {
 	AwbConfig() : default_mode(nullptr) {}
-	void Read(boost::property_tree::ptree const &params);
+	void Read(const libcamera::YamlObject &params);
 	// Only repeat the AWB calculation every "this many" frames
 	uint16_t frame_period;
 	// number of initial frames for which speed taken as 1.0 (maximum)
@@ -82,7 +82,7 @@  public:
 	~Awb();
 	char const *Name() const override;
 	void Initialise() override;
-	void Read(boost::property_tree::ptree const &params) override;
+	void Read(const libcamera::YamlObject &params) override;
 	// AWB handles "pausing" for itself.
 	bool IsPaused() const override;
 	void Pause() override;
diff --git a/src/ipa/raspberrypi/controller/rpi/black_level.cpp b/src/ipa/raspberrypi/controller/rpi/black_level.cpp
index 6b3497f13c19..de3a1e98ca1c 100644
--- a/src/ipa/raspberrypi/controller/rpi/black_level.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/black_level.cpp
@@ -31,13 +31,13 @@  char const *BlackLevel::Name() const
 	return NAME;
 }
 
-void BlackLevel::Read(boost::property_tree::ptree const &params)
+void BlackLevel::Read(const libcamera::YamlObject &params)
 {
-	uint16_t black_level = params.get<uint16_t>(
-		"black_level", 4096); // 64 in 10 bits scaled to 16 bits
-	black_level_r_ = params.get<uint16_t>("black_level_r", black_level);
-	black_level_g_ = params.get<uint16_t>("black_level_g", black_level);
-	black_level_b_ = params.get<uint16_t>("black_level_b", black_level);
+	// 64 in 10 bits scaled to 16 bits
+	uint16_t black_level = params["black_level"].get<uint16_t>(4096);
+	black_level_r_ = params["black_level_r"].get<uint16_t>(black_level);
+	black_level_g_ = params["black_level_g"].get<uint16_t>(black_level);
+	black_level_b_ = params["black_level_b"].get<uint16_t>(black_level);
 	LOG(RPiBlackLevel, Debug)
 		<< " Read black levels red " << black_level_r_
 		<< " green " << black_level_g_
diff --git a/src/ipa/raspberrypi/controller/rpi/black_level.hpp b/src/ipa/raspberrypi/controller/rpi/black_level.hpp
index 65ec4d0ed26c..5a63b5faef21 100644
--- a/src/ipa/raspberrypi/controller/rpi/black_level.hpp
+++ b/src/ipa/raspberrypi/controller/rpi/black_level.hpp
@@ -18,7 +18,7 @@  class BlackLevel : public Algorithm
 public:
 	BlackLevel(Controller *controller);
 	char const *Name() const override;
-	void Read(boost::property_tree::ptree const &params) override;
+	void Read(const libcamera::YamlObject &params) override;
 	void Prepare(Metadata *image_metadata) override;
 
 private:
diff --git a/src/ipa/raspberrypi/controller/rpi/ccm.cpp b/src/ipa/raspberrypi/controller/rpi/ccm.cpp
index 821a4c7c98c5..0e02a524c68d 100644
--- a/src/ipa/raspberrypi/controller/rpi/ccm.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/ccm.cpp
@@ -37,17 +37,15 @@  Matrix::Matrix(double m0, double m1, double m2, double m3, double m4, double m5,
 	m[0][0] = m0, m[0][1] = m1, m[0][2] = m2, m[1][0] = m3, m[1][1] = m4,
 	m[1][2] = m5, m[2][0] = m6, m[2][1] = m7, m[2][2] = m8;
 }
-void Matrix::Read(boost::property_tree::ptree const &params)
+void Matrix::Read(const libcamera::YamlObject &params)
 {
 	double *ptr = (double *)m;
-	int n = 0;
-	for (auto it = params.begin(); it != params.end(); it++) {
-		if (n++ == 9)
-			throw std::runtime_error("Ccm: too many values in CCM");
-		*ptr++ = it->second.get_value<double>();
-	}
-	if (n < 9)
-		throw std::runtime_error("Ccm: too few values in CCM");
+
+	if (params.size() != 9)
+		throw std::runtime_error("Ccm: wrong number of values in CCM");
+
+	for (const auto &param : params.asList())
+		*ptr++ = param.get<double>(0.0);
 }
 
 Ccm::Ccm(Controller *controller)
@@ -58,14 +56,14 @@  char const *Ccm::Name() const
 	return NAME;
 }
 
-void Ccm::Read(boost::property_tree::ptree const &params)
+void Ccm::Read(const libcamera::YamlObject &params)
 {
-	if (params.get_child_optional("saturation"))
-		config_.saturation.Read(params.get_child("saturation"));
-	for (auto &p : params.get_child("ccms")) {
+	if (params.contains("saturation"))
+		config_.saturation.Read(params["saturation"]);
+	for (auto &p : params["ccms"].asList()) {
 		CtCcm ct_ccm;
-		ct_ccm.ct = p.second.get<double>("ct");
-		ct_ccm.ccm.Read(p.second.get_child("ccm"));
+		ct_ccm.ct = p["ct"].get<double>(0.0);
+		ct_ccm.ccm.Read(p["ccm"]);
 		if (!config_.ccms.empty() &&
 		    ct_ccm.ct <= config_.ccms.back().ct)
 			throw std::runtime_error(
diff --git a/src/ipa/raspberrypi/controller/rpi/ccm.hpp b/src/ipa/raspberrypi/controller/rpi/ccm.hpp
index 330ed51fe398..073f02526850 100644
--- a/src/ipa/raspberrypi/controller/rpi/ccm.hpp
+++ b/src/ipa/raspberrypi/controller/rpi/ccm.hpp
@@ -20,7 +20,7 @@  struct Matrix {
 	       double m6, double m7, double m8);
 	Matrix();
 	double m[3][3];
-	void Read(boost::property_tree::ptree const &params);
+	void Read(const libcamera::YamlObject &params);
 };
 static inline Matrix operator*(double d, Matrix const &m)
 {
@@ -62,7 +62,7 @@  class Ccm : public CcmAlgorithm
 public:
 	Ccm(Controller *controller = NULL);
 	char const *Name() const override;
-	void Read(boost::property_tree::ptree const &params) override;
+	void Read(const libcamera::YamlObject &params) override;
 	void SetSaturation(double saturation) override;
 	void Initialise() override;
 	void Prepare(Metadata *image_metadata) override;
diff --git a/src/ipa/raspberrypi/controller/rpi/contrast.cpp b/src/ipa/raspberrypi/controller/rpi/contrast.cpp
index ae55aad56739..534f8b48a59b 100644
--- a/src/ipa/raspberrypi/controller/rpi/contrast.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/contrast.cpp
@@ -36,21 +36,21 @@  char const *Contrast::Name() const
 	return NAME;
 }
 
-void Contrast::Read(boost::property_tree::ptree const &params)
+void Contrast::Read(const libcamera::YamlObject &params)
 {
 	// enable adaptive enhancement by default
-	config_.ce_enable = params.get<int>("ce_enable", 1);
+	config_.ce_enable = params["ce_enable"].get<int>(1);
 	// the point near the bottom of the histogram to move
-	config_.lo_histogram = params.get<double>("lo_histogram", 0.01);
+	config_.lo_histogram = params["lo_histogram"].get<double>(0.01);
 	// where in the range to try and move it to
-	config_.lo_level = params.get<double>("lo_level", 0.015);
+	config_.lo_level = params["lo_level"].get<double>(0.015);
 	// but don't move by more than this
-	config_.lo_max = params.get<double>("lo_max", 500);
+	config_.lo_max = params["lo_max"].get<double>(500);
 	// equivalent values for the top of the histogram...
-	config_.hi_histogram = params.get<double>("hi_histogram", 0.95);
-	config_.hi_level = params.get<double>("hi_level", 0.95);
-	config_.hi_max = params.get<double>("hi_max", 2000);
-	config_.gamma_curve.Read(params.get_child("gamma_curve"));
+	config_.hi_histogram = params["hi_histogram"].get<double>(0.95);
+	config_.hi_level = params["hi_level"].get<double>(0.95);
+	config_.hi_max = params["hi_max"].get<double>(2000);
+	config_.gamma_curve.Read(params["gamma_curve"]);
 }
 
 void Contrast::SetBrightness(double brightness)
diff --git a/src/ipa/raspberrypi/controller/rpi/contrast.hpp b/src/ipa/raspberrypi/controller/rpi/contrast.hpp
index 85624539a1da..6b1e41724f5b 100644
--- a/src/ipa/raspberrypi/controller/rpi/contrast.hpp
+++ b/src/ipa/raspberrypi/controller/rpi/contrast.hpp
@@ -32,7 +32,7 @@  class Contrast : public ContrastAlgorithm
 public:
 	Contrast(Controller *controller = NULL);
 	char const *Name() const override;
-	void Read(boost::property_tree::ptree const &params) override;
+	void Read(const libcamera::YamlObject &params) override;
 	void SetBrightness(double brightness) override;
 	void SetContrast(double contrast) override;
 	void Initialise() override;
diff --git a/src/ipa/raspberrypi/controller/rpi/dpc.cpp b/src/ipa/raspberrypi/controller/rpi/dpc.cpp
index 110f50560e76..ac8aa78921c6 100644
--- a/src/ipa/raspberrypi/controller/rpi/dpc.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/dpc.cpp
@@ -29,9 +29,9 @@  char const *Dpc::Name() const
 	return NAME;
 }
 
-void Dpc::Read(boost::property_tree::ptree const &params)
+void Dpc::Read(const libcamera::YamlObject &params)
 {
-	config_.strength = params.get<int>("strength", 1);
+	config_.strength = params["strength"].get<int>(1);
 	if (config_.strength < 0 || config_.strength > 2)
 		throw std::runtime_error("Dpc: bad strength value");
 }
diff --git a/src/ipa/raspberrypi/controller/rpi/dpc.hpp b/src/ipa/raspberrypi/controller/rpi/dpc.hpp
index d90285c4eb56..382e20a6f1db 100644
--- a/src/ipa/raspberrypi/controller/rpi/dpc.hpp
+++ b/src/ipa/raspberrypi/controller/rpi/dpc.hpp
@@ -22,7 +22,7 @@  class Dpc : public Algorithm
 public:
 	Dpc(Controller *controller);
 	char const *Name() const override;
-	void Read(boost::property_tree::ptree const &params) override;
+	void Read(const libcamera::YamlObject &params) override;
 	void Prepare(Metadata *image_metadata) override;
 
 private:
diff --git a/src/ipa/raspberrypi/controller/rpi/geq.cpp b/src/ipa/raspberrypi/controller/rpi/geq.cpp
index 4530cb75792c..cff3bfe01ed6 100644
--- a/src/ipa/raspberrypi/controller/rpi/geq.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/geq.cpp
@@ -33,14 +33,14 @@  char const *Geq::Name() const
 	return NAME;
 }
 
-void Geq::Read(boost::property_tree::ptree const &params)
+void Geq::Read(const libcamera::YamlObject &params)
 {
-	config_.offset = params.get<uint16_t>("offset", 0);
-	config_.slope = params.get<double>("slope", 0.0);
+	config_.offset = params["offset"].get<uint16_t>(0);
+	config_.slope = params["slope"].get<double>(0.0);
 	if (config_.slope < 0.0 || config_.slope >= 1.0)
 		throw std::runtime_error("Geq: bad slope value");
-	if (params.get_child_optional("strength"))
-		config_.strength.Read(params.get_child("strength"));
+	if (params.contains("strength"))
+		config_.strength.Read(params["strength"]);
 }
 
 void Geq::Prepare(Metadata *image_metadata)
diff --git a/src/ipa/raspberrypi/controller/rpi/geq.hpp b/src/ipa/raspberrypi/controller/rpi/geq.hpp
index 8ba3046b2a2b..84104be40452 100644
--- a/src/ipa/raspberrypi/controller/rpi/geq.hpp
+++ b/src/ipa/raspberrypi/controller/rpi/geq.hpp
@@ -24,7 +24,7 @@  class Geq : public Algorithm
 public:
 	Geq(Controller *controller);
 	char const *Name() const override;
-	void Read(boost::property_tree::ptree const &params) override;
+	void Read(const libcamera::YamlObject &params) override;
 	void Prepare(Metadata *image_metadata) override;
 
 private:
diff --git a/src/ipa/raspberrypi/controller/rpi/lux.cpp b/src/ipa/raspberrypi/controller/rpi/lux.cpp
index 4d145b6ff0e9..f10be2014f6a 100644
--- a/src/ipa/raspberrypi/controller/rpi/lux.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/lux.cpp
@@ -36,14 +36,14 @@  char const *Lux::Name() const
 	return NAME;
 }
 
-void Lux::Read(boost::property_tree::ptree const &params)
+void Lux::Read(const libcamera::YamlObject &params)
 {
 	reference_shutter_speed_ =
-		params.get<double>("reference_shutter_speed") * 1.0us;
-	reference_gain_ = params.get<double>("reference_gain");
-	reference_aperture_ = params.get<double>("reference_aperture", 1.0);
-	reference_Y_ = params.get<double>("reference_Y");
-	reference_lux_ = params.get<double>("reference_lux");
+		params["reference_shutter_speed"].get<double>(0.0) * 1.0us;
+	reference_gain_ = params["reference_gain"].get<double>(0.0);
+	reference_aperture_ = params["reference_aperture"].get<double>(1.0);
+	reference_Y_ = params["reference_Y"].get<double>(0.0);
+	reference_lux_ = params["reference_lux"].get<double>(0.0);
 	current_aperture_ = reference_aperture_;
 }
 
diff --git a/src/ipa/raspberrypi/controller/rpi/lux.hpp b/src/ipa/raspberrypi/controller/rpi/lux.hpp
index 3ebd35d1e382..7d85199f7def 100644
--- a/src/ipa/raspberrypi/controller/rpi/lux.hpp
+++ b/src/ipa/raspberrypi/controller/rpi/lux.hpp
@@ -22,7 +22,7 @@  class Lux : public Algorithm
 public:
 	Lux(Controller *controller);
 	char const *Name() const override;
-	void Read(boost::property_tree::ptree const &params) override;
+	void Read(const libcamera::YamlObject &params) override;
 	void Prepare(Metadata *image_metadata) override;
 	void Process(StatisticsPtr &stats, Metadata *image_metadata) override;
 	void SetCurrentAperture(double aperture);
diff --git a/src/ipa/raspberrypi/controller/rpi/noise.cpp b/src/ipa/raspberrypi/controller/rpi/noise.cpp
index 63cad639f313..66a2a7f3486c 100644
--- a/src/ipa/raspberrypi/controller/rpi/noise.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/noise.cpp
@@ -39,10 +39,10 @@  void Noise::SwitchMode(CameraMode const &camera_mode,
 	mode_factor_ = std::max(1.0, camera_mode.noise_factor);
 }
 
-void Noise::Read(boost::property_tree::ptree const &params)
+void Noise::Read(const libcamera::YamlObject &params)
 {
-	reference_constant_ = params.get<double>("reference_constant");
-	reference_slope_ = params.get<double>("reference_slope");
+	reference_constant_ = params["reference_constant"].get<double>(0.0);
+	reference_slope_ = params["reference_slope"].get<double>(0.0);
 }
 
 void Noise::Prepare(Metadata *image_metadata)
diff --git a/src/ipa/raspberrypi/controller/rpi/noise.hpp b/src/ipa/raspberrypi/controller/rpi/noise.hpp
index 1c9de5c87d08..353e79fa2a8c 100644
--- a/src/ipa/raspberrypi/controller/rpi/noise.hpp
+++ b/src/ipa/raspberrypi/controller/rpi/noise.hpp
@@ -19,7 +19,7 @@  public:
 	Noise(Controller *controller);
 	char const *Name() const override;
 	void SwitchMode(CameraMode const &camera_mode, Metadata *metadata) override;
-	void Read(boost::property_tree::ptree const &params) override;
+	void Read(const libcamera::YamlObject &params) override;
 	void Prepare(Metadata *image_metadata) override;
 
 private:
diff --git a/src/ipa/raspberrypi/controller/rpi/sdn.cpp b/src/ipa/raspberrypi/controller/rpi/sdn.cpp
index 9384550983e7..619a793cbdfb 100644
--- a/src/ipa/raspberrypi/controller/rpi/sdn.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/sdn.cpp
@@ -32,10 +32,10 @@  char const *Sdn::Name() const
 	return NAME;
 }
 
-void Sdn::Read(boost::property_tree::ptree const &params)
+void Sdn::Read(const libcamera::YamlObject &params)
 {
-	deviation_ = params.get<double>("deviation", 3.2);
-	strength_ = params.get<double>("strength", 0.75);
+	deviation_ = params["deviation"].get<double>(3.2);
+	strength_ = params["strength"].get<double>(0.75);
 }
 
 void Sdn::Initialise() {}
diff --git a/src/ipa/raspberrypi/controller/rpi/sdn.hpp b/src/ipa/raspberrypi/controller/rpi/sdn.hpp
index 2371ce04163f..e69557908cea 100644
--- a/src/ipa/raspberrypi/controller/rpi/sdn.hpp
+++ b/src/ipa/raspberrypi/controller/rpi/sdn.hpp
@@ -18,7 +18,7 @@  class Sdn : public DenoiseAlgorithm
 public:
 	Sdn(Controller *controller = NULL);
 	char const *Name() const override;
-	void Read(boost::property_tree::ptree const &params) override;
+	void Read(const libcamera::YamlObject &params) override;
 	void Initialise() override;
 	void Prepare(Metadata *image_metadata) override;
 	void SetMode(DenoiseMode mode) override;
diff --git a/src/ipa/raspberrypi/controller/rpi/sharpen.cpp b/src/ipa/raspberrypi/controller/rpi/sharpen.cpp
index 18825a43867b..491f88d06c79 100644
--- a/src/ipa/raspberrypi/controller/rpi/sharpen.cpp
+++ b/src/ipa/raspberrypi/controller/rpi/sharpen.cpp
@@ -37,11 +37,11 @@  void Sharpen::SwitchMode(CameraMode const &camera_mode,
 	mode_factor_ = std::max(1.0, camera_mode.noise_factor);
 }
 
-void Sharpen::Read(boost::property_tree::ptree const &params)
+void Sharpen::Read(const libcamera::YamlObject &params)
 {
-	threshold_ = params.get<double>("threshold", 1.0);
-	strength_ = params.get<double>("strength", 1.0);
-	limit_ = params.get<double>("limit", 1.0);
+	threshold_ = params["threshold"].get<double>(1.0);
+	strength_ = params["strength"].get<double>(1.0);
+	limit_ = params["limit"].get<double>(1.0);
 	LOG(RPiSharpen, Debug)
 		<< "Read threshold " << threshold_
 		<< " strength " << strength_
diff --git a/src/ipa/raspberrypi/controller/rpi/sharpen.hpp b/src/ipa/raspberrypi/controller/rpi/sharpen.hpp
index 13a076a86895..6dfc79afb0ac 100644
--- a/src/ipa/raspberrypi/controller/rpi/sharpen.hpp
+++ b/src/ipa/raspberrypi/controller/rpi/sharpen.hpp
@@ -19,7 +19,7 @@  public:
 	Sharpen(Controller *controller);
 	char const *Name() const override;
 	void SwitchMode(CameraMode const &camera_mode, Metadata *metadata) override;
-	void Read(boost::property_tree::ptree const &params) override;
+	void Read(const libcamera::YamlObject &params) override;
 	void SetStrength(double strength) override;
 	void Prepare(Metadata *image_metadata) override;
 
diff --git a/src/ipa/raspberrypi/meson.build b/src/ipa/raspberrypi/meson.build
index 32897e07dad9..517d815bb98c 100644
--- a/src/ipa/raspberrypi/meson.build
+++ b/src/ipa/raspberrypi/meson.build
@@ -4,7 +4,6 @@  ipa_name = 'ipa_rpi'
 
 rpi_ipa_deps = [
     libcamera_private,
-    dependency('boost'),
     libatomic,
 ]
 
diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp
index f8d37b876c54..952a6ace2911 100644
--- a/src/ipa/raspberrypi/raspberrypi.cpp
+++ b/src/ipa/raspberrypi/raspberrypi.cpp
@@ -7,6 +7,7 @@ 
 
 #include <algorithm>
 #include <array>
+#include <cstring>
 #include <fcntl.h>
 #include <math.h>
 #include <stdint.h>