[PATCH resend 5/5] libcamera: swstats_cpu: Add processFrame() method

Laurent Pinchart laurent.pinchart at ideasonboard.com
Fri Dec 6 14:28:03 CET 2024


On Fri, Dec 06, 2024 at 01:14:35PM +0000, Kieran Bingham wrote:
> Quoting Hans de Goede (2024-12-05 19:25:19)
> > Add a method to the SwstatsCpu class to process a whole Framebuffer in
> > one go, rather then line by line. This is useful for gathering stats
> > when debayering is not necessary or is not done on the CPU.
> 
> This is the bit I can see will be useful for any scenario where we don't
> have stats. I think for instance on RKISP1 when running raw mode we
> don't get stats, so something like this would be helpful to be able to
> support some AEGC control which would likely be beneficial for tuning or
> capturing raw streams.

I'm in two minds about that. If it's only about tuning with ISPs that
can't generate statistics when capturing raw frames, an application-side
AE could be a better option. We should discuss it when the need arises
before writing code.

> > Reviewed-by: Milan Zamazal <mzamazal at redhat.com>
> > Signed-off-by: Hans de Goede <hdegoede at redhat.com>
> > ---
> > Changes since the RFC:
> > - Make processFrame() call startFrame() and finishFrame() rather then
> >   making the caller do this
> > - Add doxygen documentation for processFrame()
> > ---
> >  .../internal/software_isp/swstats_cpu.h       | 12 +++++
> >  src/libcamera/software_isp/swstats_cpu.cpp    | 51 +++++++++++++++++++
> >  2 files changed, 63 insertions(+)
> > 
> > diff --git a/include/libcamera/internal/software_isp/swstats_cpu.h b/include/libcamera/internal/software_isp/swstats_cpu.h
> > index 26a2f462..fa47cec9 100644
> > --- a/include/libcamera/internal/software_isp/swstats_cpu.h
> > +++ b/include/libcamera/internal/software_isp/swstats_cpu.h
> > @@ -18,12 +18,16 @@
> >  #include <libcamera/geometry.h>
> >  
> >  #include "libcamera/internal/bayer_format.h"
> > +#include "libcamera/internal/framebuffer.h"
> >  #include "libcamera/internal/shared_mem_object.h"
> >  #include "libcamera/internal/software_isp/swisp_stats.h"
> >  
> > +#include "benchmark.h"
> > +
> >  namespace libcamera {
> >  
> >  class PixelFormat;
> > +class MappedFrameBuffer;
> >  struct StreamConfiguration;
> >  
> >  class SwStatsCpu
> > @@ -42,6 +46,7 @@ public:
> >         void setWindow(const Rectangle &window);
> >         void startFrame();
> >         void finishFrame(uint32_t frame, uint32_t bufferId);
> > +       void processFrame(uint32_t frame, uint32_t bufferId, FrameBuffer *input);
> >  
> >         void processLine0(unsigned int y, const uint8_t *src[])
> >         {
> > @@ -65,6 +70,7 @@ public:
> >  
> >  private:
> >         using statsProcessFn = void (SwStatsCpu::*)(const uint8_t *src[]);
> > +       using processFrameFn = void (SwStatsCpu::*)(MappedFrameBuffer &in);
> >  
> >         int setupStandardBayerOrder(BayerFormat::Order order);
> >         /* Bayer 8 bpp unpacked */
> > @@ -77,6 +83,10 @@ private:
> >         void statsBGGR10PLine0(const uint8_t *src[]);
> >         void statsGBRG10PLine0(const uint8_t *src[]);
> >  
> > +       void processBayerFrame2(MappedFrameBuffer &in);
> 
> Ayeee ... I shudder a little seeing 'Thing2'.
> 
> Would this really just be processMappedBayerFrame() ?
> 
> > +
> > +       processFrameFn processFrame_;
> > +
> >         /* Variables set by configure(), used every line */
> >         statsProcessFn stats0_;
> >         statsProcessFn stats2_;
> > @@ -89,9 +99,11 @@ private:
> >         Size patternSize_;
> >  
> >         unsigned int xShift_;
> > +       unsigned int stride_;
> >  
> >         SharedMemObject<SwIspStats> sharedStats_;
> >         SwIspStats stats_;
> > +       Benchmark bench_;
> >  };
> >  
> >  } /* namespace libcamera */
> > diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp
> > index aa5654dc..1ff15f5b 100644
> > --- a/src/libcamera/software_isp/swstats_cpu.cpp
> > +++ b/src/libcamera/software_isp/swstats_cpu.cpp
> > @@ -16,6 +16,7 @@
> >  #include <libcamera/stream.h>
> >  
> >  #include "libcamera/internal/bayer_format.h"
> > +#include "libcamera/internal/mapped_framebuffer.h"
> >  
> >  namespace libcamera {
> >  
> > @@ -360,11 +361,14 @@ int SwStatsCpu::setupStandardBayerOrder(BayerFormat::Order order)
> >   */
> >  int SwStatsCpu::configure(const StreamConfiguration &inputCfg)
> >  {
> > +       stride_ = inputCfg.stride;
> > +
> >         BayerFormat bayerFormat =
> >                 BayerFormat::fromPixelFormat(inputCfg.pixelFormat);
> >  
> >         if (bayerFormat.packing == BayerFormat::Packing::None &&
> >             setupStandardBayerOrder(bayerFormat.order) == 0) {
> > +               processFrame_ = &SwStatsCpu::processBayerFrame2;
> >                 switch (bayerFormat.bitDepth) {
> >                 case 8:
> >                         stats0_ = &SwStatsCpu::statsBGGR8Line0;
> > @@ -385,6 +389,7 @@ int SwStatsCpu::configure(const StreamConfiguration &inputCfg)
> >                 /* Skip every 3th and 4th line, sample every other 2x2 block */
> >                 ySkipMask_ = 0x02;
> >                 xShift_ = 0;
> > +               processFrame_ = &SwStatsCpu::processBayerFrame2;
> >  
> >                 switch (bayerFormat.order) {
> >                 case BayerFormat::BGGR:
> > @@ -425,4 +430,50 @@ void SwStatsCpu::setWindow(const Rectangle &window)
> >         window_.height &= ~(patternSize_.height - 1);
> >  }
> >  
> > +void SwStatsCpu::processBayerFrame2(MappedFrameBuffer &in)
> > +{
> > +       const uint8_t *src = in.planes()[0].data();
> > +       const uint8_t *linePointers[3];
> > +
> > +       /* Adjust src for starting at window_.y */
> > +       src += window_.y * stride_;
> > +
> > +       for (unsigned int y = 0; y < window_.height; y += 2) {
> > +               if (y & ySkipMask_) {
> > +                       src += stride_ * 2;
> > +                       continue;
> > +               }
> > +
> > +               /* linePointers[0] is not used by any stats0_ functions */
> > +               linePointers[1] = src;
> > +               linePointers[2] = src + stride_;
> > +               (this->*stats0_)(linePointers);
> > +               src += stride_ * 2;
> > +       }
> > +}
> > +
> > +/**
> > + * \brief Calculate statistics for a frame in one go
> > + * \param[in] frame The frame number
> > + * \param[in] bufferId ID of the statistics buffer
> > + * \param[in] input The frame to process
> > + *
> > + * This may only be called after a successful setWindow() call.
> > + */
> > +void SwStatsCpu::processFrame(uint32_t frame, uint32_t bufferId, FrameBuffer *input)
> > +{
> > +       bench_.startFrame();
> > +       startFrame();
> > +
> > +       MappedFrameBuffer in(input, MappedFrameBuffer::MapFlag::Read);
> > +       if (!in.isValid()) {
> > +               LOG(SwStatsCpu, Error) << "mmap-ing buffer(s) failed";
> > +               return;
> > +       }
> > +
> > +       (this->*processFrame_)(in);
> 
> I can't see why this goes through a function pointer at the moment. Is
> there some later patches that will have 'different' processFrame_
> implemenations?
> 
> Or could SwStatsCpu::processBayerFrame2 just be inlined here ?
> 
> (I'm fine keeping it separate if something else is about to use it, or
> change it soon).
> 
> > +       finishFrame(frame, bufferId);
> > +       bench_.finishFrame();
> > +}
> > +
> >  } /* namespace libcamera */

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list