[libcamera-devel] [PATCH 3/3] ipa: raspberrypi: Generalise the SMIA metadata parser

Laurent Pinchart laurent.pinchart at ideasonboard.com
Tue Jun 22 14:25:37 CEST 2021


Hi Naush,

On Tue, Jun 22, 2021 at 01:07:10PM +0100, Naushir Patuck wrote:
> On Tue, 22 Jun 2021 at 12:13, Laurent Pinchart wrote:
> > On Tue, Jun 15, 2021 at 03:42:11PM +0100, Naushir Patuck wrote:
> > > Instead of having each CamHelper subclass the MdParserSmia, change the
> > > implementation of MdParserSmia to be more generic. The MdParserSmia now gets
> > > given a list of registers to search for and helper functions are used to compute
> > > exposure lines and gain codes from these registers.
> > >
> > > Update the imx219 and imx477 CamHelpers by using this new mechanism.
> > >
> > > Signed-off-by: Naushir Patuck <naush at raspberrypi.com>
> > > ---
> > >  src/ipa/raspberrypi/cam_helper.cpp        |  35 +++---
> > >  src/ipa/raspberrypi/cam_helper.hpp        |   2 +
> > >  src/ipa/raspberrypi/cam_helper_imx219.cpp | 118 ++++----------------
> > >  src/ipa/raspberrypi/cam_helper_imx477.cpp | 124 ++++------------------
> > >  src/ipa/raspberrypi/md_parser.hpp         |  42 +++++---
> > >  src/ipa/raspberrypi/md_parser_smia.cpp    |  66 ++++++++++--
> > >  6 files changed, 148 insertions(+), 239 deletions(-)
> > >
> > > diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp
> > > index 1474464c9257..41e292ecbb61 100644
> > > --- a/src/ipa/raspberrypi/cam_helper.cpp
> > > +++ b/src/ipa/raspberrypi/cam_helper.cpp
> > > @@ -159,32 +159,32 @@ unsigned int CamHelper::MistrustFramesModeSwitch() const
> > >  void CamHelper::parseEmbeddedData(Span<const uint8_t> buffer,
> > >                                 Metadata &metadata)
> > >  {
> > > +     MdParser::RegisterMap map;
> > > +     Metadata parsedMetadata;
> > > +
> > >       if (buffer.empty())
> > >               return;
> > >
> > > -     uint32_t exposureLines, gainCode;
> > > -
> > > -     if (parser_->Parse(buffer) != MdParser::Status::OK ||
> > > -         parser_->GetExposureLines(exposureLines) != MdParser::Status::OK ||
> > > -         parser_->GetGainCode(gainCode) != MdParser::Status::OK) {
> > > +     if (parser_->Parse(buffer, map) != MdParser::Status::OK) {
> > >               LOG(IPARPI, Error) << "Embedded data buffer parsing failed";
> > >               return;
> > >       }
> > >
> > > +     PopulateMetadata(map, parsedMetadata);
> > > +     metadata.Merge(parsedMetadata);
> > > +
> > >       /*
> > > -      * Overwrite the exposure/gain values in the DeviceStatus, as
> > > -      * we know better. Fetch it first in case any other fields were
> > > -      * set meaningfully.
> > > +      * Overwrite the exposure/gain values in the existing DeviceStatus with
> > > +      * values from the parsed embedded buffer. Fetch it first in case any
> > > +      * other fields were set meaningfully.
> > >        */
> > > -     DeviceStatus deviceStatus;
> > > -
> > > -     if (metadata.Get("device.status", deviceStatus) != 0) {
> > > -             LOG(IPARPI, Error) << "DeviceStatus not found";
> >
> > No log anymore ?
> 
> Ack, I'll add it back below.
> 
> > > +     DeviceStatus deviceStatus, parsedDeviceStatus;
> > > +     if (metadata.Get("device.status", deviceStatus) ||
> > > +         parsedMetadata.Get("device.status", parsedDeviceStatus))
> > >               return;
> > > -     }
> > >
> > > -     deviceStatus.shutter_speed = Exposure(exposureLines);
> > > -     deviceStatus.analogue_gain = Gain(gainCode);
> > > +     deviceStatus.shutter_speed = parsedDeviceStatus.shutter_speed;
> > > +     deviceStatus.analogue_gain = parsedDeviceStatus.analogue_gain;
> > >
> > >       LOG(IPARPI, Debug) << "Metadata updated - Exposure : "
> > >                          << deviceStatus.shutter_speed
> > > @@ -194,6 +194,11 @@ void CamHelper::parseEmbeddedData(Span<const uint8_t> buffer,
> > >       metadata.Set("device.status", deviceStatus);
> > >  }
> > >
> > > +void CamHelper::PopulateMetadata([[maybe_unused]] const MdParser::RegisterMap &map,
> > > +                              [[maybe_unused]] Metadata &metadata) const
> > > +{
> > > +}
> > > +
> > >  RegisterCamHelper::RegisterCamHelper(char const *cam_name,
> > >                                    CamHelperCreateFunc create_func)
> > >  {
> > > diff --git a/src/ipa/raspberrypi/cam_helper.hpp b/src/ipa/raspberrypi/cam_helper.hpp
> > > index f53f5c39b01c..30879e60b861 100644
> > > --- a/src/ipa/raspberrypi/cam_helper.hpp
> > > +++ b/src/ipa/raspberrypi/cam_helper.hpp
> > > @@ -91,6 +91,8 @@ public:
> > >  protected:
> > >       void parseEmbeddedData(libcamera::Span<const uint8_t> buffer,
> > >                              Metadata &metadata);
> > > +     virtual void PopulateMetadata([[maybe_unused]] const MdParser::RegisterMap &map,
> > > +                                   [[maybe_unused]] Metadata &metadata) const;
> > >
> > >       MdParser *parser_;
> > >       CameraMode mode_;
> > > diff --git a/src/ipa/raspberrypi/cam_helper_imx219.cpp b/src/ipa/raspberrypi/cam_helper_imx219.cpp
> > > index d951cd552a21..24818e9ec4de 100644
> > > --- a/src/ipa/raspberrypi/cam_helper_imx219.cpp
> > > +++ b/src/ipa/raspberrypi/cam_helper_imx219.cpp
> > > @@ -23,21 +23,13 @@
> > >
> > >  using namespace RPiController;
> > >
> > > -/* Metadata parser implementation specific to Sony IMX219 sensors. */
> > > -
> > > -class MdParserImx219 : public MdParserSmia
> > > -{
> > > -public:
> > > -     MdParserImx219();
> > > -     Status Parse(libcamera::Span<const uint8_t> buffer) override;
> > > -     Status GetExposureLines(unsigned int &lines) override;
> > > -     Status GetGainCode(unsigned int &gain_code) override;
> > > -private:
> > > -     /* Offset of the register's value in the metadata block. */
> > > -     int reg_offsets_[3];
> > > -     /* Value of the register, once read from the metadata block. */
> > > -     int reg_values_[3];
> > > -};
> > > +/*
> > > + * We care about one gain register and a pair of exposure registers. Their I2C
> > > + * addresses from the Sony IMX219 datasheet:
> > > + */
> > > +constexpr uint32_t gainReg = 0x157;
> > > +constexpr uint32_t expHiReg = 0x15a;
> > > +constexpr uint32_t expLoReg = 0x15b;
> > >
> > >  class CamHelperImx219 : public CamHelper
> > >  {
> > > @@ -55,15 +47,19 @@ private:
> > >        */
> > >       static constexpr int frameIntegrationDiff = 4;
> > >
> > > -     MdParserImx219 imx219_parser;
> > > +     MdParserSmia imx219_parser;
> >
> > Could you name this just "parser" ? It's a member of the CamHelperImx219
> > class, there's no need to repeat the prefix. Same for imx477.
> 
> Ack.
> 
> > > +
> > > +     void PopulateMetadata(const MdParser::RegisterMap &map,
> > > +                           Metadata &metadata) const override;
> > >  };
> > >
> > >  CamHelperImx219::CamHelperImx219()
> > >  #if ENABLE_EMBEDDED_DATA
> > > -     : CamHelper(&imx219_parser, frameIntegrationDiff)
> > > +     : CamHelper(&imx219_parser, frameIntegrationDiff),
> >
> > You're passing a pointer to an object that isn't constructed yet. The
> > base class only stores it so it should be OK, but it's a bit fragile.
> 
> I agree, this is slightly naughty.  Without relying in a dynamic
> allocation, there is no other way to construct the object before
> passing on the pointer to the base class.
> 
> Perhaps I should replace patch 1/3 to use a shared_ptr instead of

A unique_ptr may be better.

> embedding the parser object in the derived class. This way, the memory
> is correctly managed, and the object will be constructed before returning
> it to the base class.

I'm fine either way.

> > >  #else
> > > -     : CamHelper(nullptr, frameIntegrationDiff)
> > > +     : CamHelper(nullptr, frameIntegrationDiff),
> > >  #endif
> > > +       imx219_parser({ gainReg, expHiReg, expLoReg })
> > >  {
> > >  }
> > >
> > > @@ -92,88 +88,20 @@ bool CamHelperImx219::SensorEmbeddedDataPresent() const
> > >       return ENABLE_EMBEDDED_DATA;
> > >  }
> > >
> > > -static CamHelper *Create()
> > > +void CamHelperImx219::PopulateMetadata(const MdParser::RegisterMap &map,
> > > +                                    Metadata &metadata) const
> > >  {
> > > -     return new CamHelperImx219();
> > > -}
> > > +     DeviceStatus deviceStatus;
> > >
> > > -static RegisterCamHelper reg("imx219", &Create);
> > > +     deviceStatus.shutter_speed = Exposure(map.at(expHiReg) * 256 + map.at(expLoReg));
> > > +     deviceStatus.analogue_gain = Gain(map.at(gainReg));
> > >
> > > -/*
> > > - * We care about one gain register and a pair of exposure registers. Their I2C
> > > - * addresses from the Sony IMX219 datasheet:
> > > - */
> > > -#define GAIN_REG 0x157
> > > -#define EXPHI_REG 0x15A
> > > -#define EXPLO_REG 0x15B
> > > -
> > > -/*
> > > - * Index of each into the reg_offsets and reg_values arrays. Must be in
> > > - * register address order.
> > > - */
> > > -#define GAIN_INDEX 0
> > > -#define EXPHI_INDEX 1
> > > -#define EXPLO_INDEX 2
> > > -
> > > -MdParserImx219::MdParserImx219()
> > > -{
> > > -     reg_offsets_[0] = reg_offsets_[1] = reg_offsets_[2] = -1;
> > > +     metadata.Set("device.status", deviceStatus);
> > >  }
> > >
> > > -MdParser::Status MdParserImx219::Parse(libcamera::Span<const uint8_t> buffer)
> > > -{
> > > -     bool try_again = false;
> > > -
> > > -     if (reset_) {
> > > -             /*
> > > -              * Search again through the metadata for the gain and exposure
> > > -              * registers.
> > > -              */
> > > -             assert(bits_per_pixel_);
> > > -             /* Need to be ordered */
> > > -             uint32_t regs[3] = { GAIN_REG, EXPHI_REG, EXPLO_REG };
> > > -             reg_offsets_[0] = reg_offsets_[1] = reg_offsets_[2] = -1;
> > > -             int ret = static_cast<int>(findRegs(buffer,
> > > -                                                 regs, reg_offsets_, 3));
> > > -             /*
> > > -              * > 0 means "worked partially but parse again next time",
> > > -              * < 0 means "hard error".
> > > -              */
> > > -             if (ret > 0)
> > > -                     try_again = true;
> > > -             else if (ret < 0)
> > > -                     return ERROR;
> > > -     }
> > > -
> > > -     for (int i = 0; i < 3; i++) {
> > > -             if (reg_offsets_[i] == -1)
> > > -                     continue;
> > > -
> > > -             reg_values_[i] = buffer[reg_offsets_[i]];
> > > -     }
> > > -
> > > -     /* Re-parse next time if we were unhappy in some way. */
> > > -     reset_ = try_again;
> > > -
> > > -     return OK;
> > > -}
> > > -
> > > -MdParser::Status MdParserImx219::GetExposureLines(unsigned int &lines)
> > > +static CamHelper *Create()
> > >  {
> > > -     if (reg_offsets_[EXPHI_INDEX] == -1 || reg_offsets_[EXPLO_INDEX] == -1)
> > > -             return NOTFOUND;
> > > -
> > > -     lines = reg_values_[EXPHI_INDEX] * 256 + reg_values_[EXPLO_INDEX];
> > > -
> > > -     return OK;
> > > +     return new CamHelperImx219();
> > >  }
> > >
> > > -MdParser::Status MdParserImx219::GetGainCode(unsigned int &gain_code)
> > > -{
> > > -     if (reg_offsets_[GAIN_INDEX] == -1)
> > > -             return NOTFOUND;
> > > -
> > > -     gain_code = reg_values_[GAIN_INDEX];
> > > -
> > > -     return OK;
> > > -}
> > > +static RegisterCamHelper reg("imx219", &Create);
> > > diff --git a/src/ipa/raspberrypi/cam_helper_imx477.cpp b/src/ipa/raspberrypi/cam_helper_imx477.cpp
> > > index 44f030ed7da9..7586e5f897d5 100644
> > > --- a/src/ipa/raspberrypi/cam_helper_imx477.cpp
> > > +++ b/src/ipa/raspberrypi/cam_helper_imx477.cpp
> > > @@ -15,21 +15,14 @@
> > >
> > >  using namespace RPiController;
> > >
> > > -/* Metadata parser implementation specific to Sony IMX477 sensors. */
> > > -
> > > -class MdParserImx477 : public MdParserSmia
> > > -{
> > > -public:
> > > -     MdParserImx477();
> > > -     Status Parse(libcamera::Span<const uint8_t> buffer) override;
> > > -     Status GetExposureLines(unsigned int &lines) override;
> > > -     Status GetGainCode(unsigned int &gain_code) override;
> > > -private:
> > > -     /* Offset of the register's value in the metadata block. */
> > > -     int reg_offsets_[4];
> > > -     /* Value of the register, once read from the metadata block. */
> > > -     int reg_values_[4];
> > > -};
> > > +/*
> > > + * We care about two gain registers and a pair of exposure registers. Their
> > > + * I2C addresses from the Sony IMX477 datasheet:
> > > + */
> > > +constexpr uint32_t expHiReg = 0x0202;
> > > +constexpr uint32_t expLoReg = 0x0203;
> > > +constexpr uint32_t gainHiReg = 0x0204;
> > > +constexpr uint32_t gainLoReg = 0x0205;
> > >
> > >  class CamHelperImx477 : public CamHelper
> > >  {
> > > @@ -48,11 +41,15 @@ private:
> > >        */
> > >       static constexpr int frameIntegrationDiff = 22;
> > >
> > > -     MdParserImx477 imx477_parser;
> > > +     MdParserSmia imx477_parser;
> > > +
> > > +     void PopulateMetadata(const MdParser::RegisterMap &map,
> > > +                           Metadata &metadata) const override;
> > >  };
> > >
> > >  CamHelperImx477::CamHelperImx477()
> > > -     : CamHelper(&imx477_parser, frameIntegrationDiff)
> > > +     : CamHelper(&imx477_parser, frameIntegrationDiff),
> > > +       imx477_parser({ expHiReg, expLoReg, gainHiReg, gainLoReg })
> > >  {
> > >  }
> > >
> > > @@ -79,95 +76,20 @@ bool CamHelperImx477::SensorEmbeddedDataPresent() const
> > >       return true;
> > >  }
> > >
> > > -static CamHelper *Create()
> > > +void CamHelperImx477::PopulateMetadata(const MdParser::RegisterMap &map,
> > > +                                    Metadata &metadata) const
> > >  {
> > > -     return new CamHelperImx477();
> > > -}
> > > +     DeviceStatus deviceStatus;
> > >
> > > -static RegisterCamHelper reg("imx477", &Create);
> > > +     deviceStatus.shutter_speed = Exposure(map.at(expHiReg) * 256 + map.at(expLoReg));
> > > +     deviceStatus.analogue_gain = Gain(map.at(gainHiReg) * 256 + map.at (gainLoReg));
> > >
> > > -/*
> > > - * We care about two gain registers and a pair of exposure registers. Their
> > > - * I2C addresses from the Sony IMX477 datasheet:
> > > - */
> > > -#define EXPHI_REG 0x0202
> > > -#define EXPLO_REG 0x0203
> > > -#define GAINHI_REG 0x0204
> > > -#define GAINLO_REG 0x0205
> > > -
> > > -/*
> > > - * Index of each into the reg_offsets and reg_values arrays. Must be in register
> > > - * address order.
> > > - */
> > > -#define EXPHI_INDEX 0
> > > -#define EXPLO_INDEX 1
> > > -#define GAINHI_INDEX 2
> > > -#define GAINLO_INDEX 3
> > > -
> > > -MdParserImx477::MdParserImx477()
> > > -{
> > > -     reg_offsets_[0] = reg_offsets_[1] = reg_offsets_[2] = reg_offsets_[3] = -1;
> > > +     metadata.Set("device.status", deviceStatus);
> > >  }
> > >
> > > -MdParser::Status MdParserImx477::Parse(libcamera::Span<const uint8_t> buffer)
> > > -{
> > > -     bool try_again = false;
> > > -
> > > -     if (reset_) {
> > > -             /*
> > > -              * Search again through the metadata for the gain and exposure
> > > -              * registers.
> > > -              */
> > > -             assert(bits_per_pixel_);
> > > -             /* Need to be ordered */
> > > -             uint32_t regs[4] = {
> > > -                     EXPHI_REG,
> > > -                     EXPLO_REG,
> > > -                     GAINHI_REG,
> > > -                     GAINLO_REG
> > > -             };
> > > -             reg_offsets_[0] = reg_offsets_[1] = reg_offsets_[2] = reg_offsets_[3] = -1;
> > > -             int ret = static_cast<int>(findRegs(buffer,
> > > -                                                 regs, reg_offsets_, 4));
> > > -             /*
> > > -              * > 0 means "worked partially but parse again next time",
> > > -              * < 0 means "hard error".
> > > -              */
> > > -             if (ret > 0)
> > > -                     try_again = true;
> > > -             else if (ret < 0)
> > > -                     return ERROR;
> > > -     }
> > > -
> > > -     for (int i = 0; i < 4; i++) {
> > > -             if (reg_offsets_[i] == -1)
> > > -                     continue;
> > > -
> > > -             reg_values_[i] = buffer[reg_offsets_[i]];
> > > -     }
> > > -
> > > -     /* Re-parse next time if we were unhappy in some way. */
> > > -     reset_ = try_again;
> > > -
> > > -     return OK;
> > > -}
> > > -
> > > -MdParser::Status MdParserImx477::GetExposureLines(unsigned int &lines)
> > > +static CamHelper *Create()
> > >  {
> > > -     if (reg_offsets_[EXPHI_INDEX] == -1 || reg_offsets_[EXPLO_INDEX] == -1)
> > > -             return NOTFOUND;
> > > -
> > > -     lines = reg_values_[EXPHI_INDEX] * 256 + reg_values_[EXPLO_INDEX];
> > > -
> > > -     return OK;
> > > +     return new CamHelperImx477();
> > >  }
> > >
> > > -MdParser::Status MdParserImx477::GetGainCode(unsigned int &gain_code)
> > > -{
> > > -     if (reg_offsets_[GAINHI_INDEX] == -1 || reg_offsets_[GAINLO_INDEX] == -1)
> > > -             return NOTFOUND;
> > > -
> > > -     gain_code = reg_values_[GAINHI_INDEX] * 256 + reg_values_[GAINLO_INDEX];
> > > -
> > > -     return OK;
> > > -}
> > > +static RegisterCamHelper reg("imx477", &Create);
> > > diff --git a/src/ipa/raspberrypi/md_parser.hpp b/src/ipa/raspberrypi/md_parser.hpp
> > > index 65aab02d51b6..64f9bbb12845 100644
> > > --- a/src/ipa/raspberrypi/md_parser.hpp
> > > +++ b/src/ipa/raspberrypi/md_parser.hpp
> > > @@ -8,6 +8,10 @@
> > >
> > >  #include <stdint.h>
> > >
> > > +#include <map>
> > > +#include <optional>
> > > +#include <vector>
> > > +
> > >  #include <libcamera/span.h>
> > >
> > >  /*
> > > @@ -19,7 +23,7 @@
> > >   * application code doesn't have to worry which kind to instantiate. But for
> > >   * the sake of example let's suppose we're parsing imx219 metadata.
> > >   *
> > > - * MdParser *parser = new MdParserImx219();  // for example
> > > + * MdParser *parser = new MdParserSmia({ expHiReg, expLoReg, gainReg });
> > >   * parser->SetBitsPerPixel(bpp);
> > >   * parser->SetLineLengthBytes(pitch);
> > >   * parser->SetNumLines(2);
> > > @@ -32,13 +36,11 @@
> > >   *
> > >   * Then on every frame:
> > >   *
> > > - * if (parser->Parse(buffer) != MdParser::OK)
> > > + * RegisterMap map;
> > > + * if (parser->Parse(buffer, map) != MdParser::OK)
> > >   *     much badness;
> > > - * unsigned int exposure_lines, gain_code
> > > - * if (parser->GetExposureLines(exposure_lines) != MdParser::OK)
> > > - *     exposure was not found;
> > > - * if (parser->GetGainCode(parser, gain_code) != MdParser::OK)
> > > - *     gain code was not found;
> > > + * Metadata metadata;
> > > + * CamHelper::PopulateMetadata(map, metadata);
> > >   *
> > >   * (Note that the CamHelper class converts to/from exposure lines and time,
> > >   * and gain_code / actual gain.)
> > > @@ -59,6 +61,8 @@ namespace RPiController {
> > >  class MdParser
> > >  {
> > >  public:
> > > +     using RegisterMap = std::map<uint32_t, uint32_t>;
> > > +
> > >       /*
> > >        * Parser status codes:
> > >        * OK       - success
> > > @@ -98,9 +102,8 @@ public:
> > >               line_length_bytes_ = num_bytes;
> > >       }
> > >
> > > -     virtual Status Parse(libcamera::Span<const uint8_t> buffer) = 0;
> > > -     virtual Status GetExposureLines(unsigned int &lines) = 0;
> > > -     virtual Status GetGainCode(unsigned int &gain_code) = 0;
> > > +     virtual Status Parse(libcamera::Span<const uint8_t> buffer,
> > > +                          RegisterMap &map) = 0;
> >
> > I'd name the variable registers to tell what it contains (same in the
> > caller and in the example above).
> 
> Ack.
> 
> > >  protected:
> > >       bool reset_;
> > > @@ -116,14 +119,18 @@ protected:
> > >   * md_parser_imx219.cpp for an example).
> > >   */
> > >
> > > -class MdParserSmia : public MdParser
> > > +class MdParserSmia final : public MdParser
> > >  {
> > >  public:
> > > -     MdParserSmia() : MdParser()
> > > -     {
> > > -     }
> > > +     MdParserSmia(const std::vector<uint32_t> &regs);
> > > +
> > > +     MdParser::Status Parse(libcamera::Span<const uint8_t> buffer,
> > > +                            RegisterMap &map) override;
> > > +
> > > +private:
> > > +     /* Maps register address to offset in the buffer. */
> > > +     using OffsetMap = std::map<uint32_t, std::optional<uint32_t>>;
> > >
> > > -protected:
> > >       /*
> > >        * Note that error codes > 0 are regarded as non-fatal; codes < 0
> > >        * indicate a bad data buffer. Status codes are:
> > > @@ -141,8 +148,9 @@ protected:
> > >               BAD_PADDING   = -5
> > >       };
> > >
> > > -     ParseStatus findRegs(libcamera::Span<const uint8_t> buffer, uint32_t regs[],
> > > -                          int offsets[], unsigned int num_regs);
> > > +     ParseStatus findRegs(libcamera::Span<const uint8_t> buffer);
> > > +
> > > +     OffsetMap offsets_;
> > >  };
> > >
> > >  } // namespace RPi
> > > diff --git a/src/ipa/raspberrypi/md_parser_smia.cpp b/src/ipa/raspberrypi/md_parser_smia.cpp
> > > index 0a14875575a2..9920699dfe25 100644
> > > --- a/src/ipa/raspberrypi/md_parser_smia.cpp
> > > +++ b/src/ipa/raspberrypi/md_parser_smia.cpp
> > > @@ -6,9 +6,11 @@
> > >   */
> > >  #include <assert.h>
> > >
> > > +#include "libcamera/internal/log.h"
> >
> > Do you need this header ?
> 
> Yes, I do for the ASSERT() macro below.  I could use the standard assert() without
> this header, but thought the libcamera version would be more consistent.

As yes I've missed that.

> > >  #include "md_parser.hpp"
> > >
> > >  using namespace RPiController;
> > > +using namespace libcamera;
> > >
> > >  /*
> > >   * This function goes through the embedded data to find the offsets (not
> > > @@ -26,18 +28,61 @@ constexpr unsigned int REG_LOW_BITS = 0xa5;
> > >  constexpr unsigned int REG_VALUE = 0x5a;
> > >  constexpr unsigned int REG_SKIP = 0x55;
> > >
> > > -MdParserSmia::ParseStatus MdParserSmia::findRegs(libcamera::Span<const uint8_t> buffer,
> > > -                                              uint32_t regs[], int offsets[],
> > > -                                              unsigned int num_regs)
> > > +MdParserSmia::MdParserSmia(const std::vector<uint32_t> &registers)
> > >  {
> > > -     assert(num_regs > 0);
> > > +     for (auto r : registers)
> > > +             offsets_[r] = {};
> > > +}
> > > +
> > > +MdParser::Status MdParserSmia::Parse(libcamera::Span<const uint8_t> buffer,
> > > +                                  RegisterMap &map)
> > > +{
> > > +     if (reset_) {
> > > +             /*
> > > +              * Search again through the metadata for the gain and exposure
> > > +              * registers.
> > > +              */
> >
> > It's not just gain and exposure, this class is generic and can handle
> > any register.
> 
> Ack.
> 
> > I'm curious, is findRegs() that costly that you want to cache the
> > results ? Does SMIA++ guarantee that embedded data will be formatted the
> > same way for every frame ?
> 
> The original SMIA spec guarantees that the register offsets will be the same
> while streaming.  Not entirely sure about SMIA++, I have not looked at the
> updated spec yet.

CCS states

"The embedded data sequence of tags and the number of embedded data
lines shall not vary dynamically from frame to frame. This is to speed
up software-based systems, by allowing the Host to build up a positional
map (pixel number N = the value for CCI Register M) from the embedded
data lines in the first frame of image data received by the Host
system."

Sounds good.

> It is not too expensive to parse the buffer per-frame, but given that the
> offsets are fixed, I think it makes sense to cache the values as an
> optimisation.
> 
> > I've pushed 2/3 already. 1/3 looks good to me, but I've held off in case
> > some of the review for 3/3 requires changing 1/3.
> 
> Thanks, I'll submit a new version with the suggestions shortly.
> 
> > > +             ASSERT(bits_per_pixel_);
> > > +
> > > +             for (auto &kv : offsets_)
> > > +                     offsets_[kv.first] = {};
> > > +
> > > +             ParseStatus ret = findRegs(buffer);
> > > +             /*
> > > +              * > 0 means "worked partially but parse again next time",
> > > +              * < 0 means "hard error".
> > > +              *
> > > +              * In either case, we retry parsing on the next frame.
> > > +              */
> > > +             if (ret != PARSE_OK)
> > > +                     return ERROR;
> > > +
> > > +             reset_ = false;
> > > +     }
> > > +
> > > +     /* Populate the register values requested. */
> > > +     map.clear();
> > > +     for (auto &kv : offsets_) {
> > > +             if (!kv.second) {
> > > +                     reset_ = true;
> > > +                     return NOTFOUND;
> > > +             }
> > > +             map[kv.first] = buffer[kv.second.value()];
> > > +     }
> > > +
> > > +     return OK;
> > > +}
> > > +
> > > +MdParserSmia::ParseStatus MdParserSmia::findRegs(libcamera::Span<const uint8_t> buffer)
> > > +{
> > > +     ASSERT(offsets_.size());
> > >
> > >       if (buffer[0] != LINE_START)
> > >               return NO_LINE_START;
> > >
> > >       unsigned int current_offset = 1; /* after the LINE_START */
> > >       unsigned int current_line_start = 0, current_line = 0;
> > > -     unsigned int reg_num = 0, first_reg = 0;
> > > +     unsigned int reg_num = 0, regs_done = 0;
> > >
> > >       while (1) {
> > >               int tag = buffer[current_offset++];
> > > @@ -89,13 +134,12 @@ MdParserSmia::ParseStatus MdParserSmia::findRegs(libcamera::Span<const uint8_t>
> > >                       else if (tag == REG_SKIP)
> > >                               reg_num++;
> > >                       else if (tag == REG_VALUE) {
> > > -                             while (reg_num >=
> > > -                                    /* assumes registers are in order... */
> > > -                                    regs[first_reg]) {
> > > -                                     if (reg_num == regs[first_reg])
> > > -                                             offsets[first_reg] = current_offset - 1;
> > > +                             auto reg = offsets_.find(reg_num);
> > > +
> > > +                             if (reg != offsets_.end()) {
> > > +                                     offsets_[reg_num] = current_offset - 1;
> > >
> > > -                                     if (++first_reg == num_regs)
> > > +                                     if (++regs_done == offsets_.size())
> > >                                               return PARSE_OK;
> > >                               }
> > >                               reg_num++;

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list