[libcamera-devel,4/5] src: ipa: raspberrypi: Move initial frame drop decision to AGC
diff mbox series

Message ID 20201202115253.14705-5-david.plowman@raspberrypi.com
State Superseded
Headers show
Series
  • Raspberry Pi AGC: initial frame drop count
Related show

Commit Message

David Plowman Dec. 2, 2020, 11:52 a.m. UTC
Previously the CamHelper was returning the number of frames to drop
(on account of AGC converging). This wasn't really appropriate, it's
better for the AGC to do it, which now also knows when exposure and
gain have been explicitly set and therefore fewer (or no) frame drops
are necessary at all.

The CamHelper::HideFramesStartup method should now just be returning
the number of frames to hide because they're bad/invalid in some way,
not worrying about the AGC. For many sensors, the correct value for
this is zero.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
---
 src/ipa/raspberrypi/cam_helper.cpp  | 6 +++---
 src/ipa/raspberrypi/raspberrypi.cpp | 8 ++++++++
 2 files changed, 11 insertions(+), 3 deletions(-)

Comments

Naushir Patuck Dec. 4, 2020, 4:01 p.m. UTC | #1
Hi David,

Thank you for your patch.

On Wed, 2 Dec 2020 at 11:53, David Plowman <david.plowman@raspberrypi.com>
wrote:

> Previously the CamHelper was returning the number of frames to drop
> (on account of AGC converging). This wasn't really appropriate, it's
> better for the AGC to do it, which now also knows when exposure and
> gain have been explicitly set and therefore fewer (or no) frame drops
> are necessary at all.
>
> The CamHelper::HideFramesStartup method should now just be returning
> the number of frames to hide because they're bad/invalid in some way,
> not worrying about the AGC. For many sensors, the correct value for
> this is zero.
>
> Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
> ---
>  src/ipa/raspberrypi/cam_helper.cpp  | 6 +++---
>  src/ipa/raspberrypi/raspberrypi.cpp | 8 ++++++++
>  2 files changed, 11 insertions(+), 3 deletions(-)
>
> diff --git a/src/ipa/raspberrypi/cam_helper.cpp
> b/src/ipa/raspberrypi/cam_helper.cpp
> index c8ac3232..6efa0d7f 100644
> --- a/src/ipa/raspberrypi/cam_helper.cpp
> +++ b/src/ipa/raspberrypi/cam_helper.cpp
> @@ -82,10 +82,10 @@ bool CamHelper::SensorEmbeddedDataPresent() const
>  unsigned int CamHelper::HideFramesStartup() const
>  {
>         /*
> -        * By default, hide 6 frames completely at start-up while AGC etc.
> sort
> -        * themselves out (converge).
> +        * The number of frames when a camera first starts that shouldn't
> be
> +        * displayed as they are invalid in some way.
>          */
> -       return 6;
> +       return 0;
>  }
>
>  unsigned int CamHelper::HideFramesModeSwitch() const
> diff --git a/src/ipa/raspberrypi/raspberrypi.cpp
> b/src/ipa/raspberrypi/raspberrypi.cpp
> index 0300b8d9..ddabdb31 100644
> --- a/src/ipa/raspberrypi/raspberrypi.cpp
> +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> @@ -192,6 +192,14 @@ int IPARPi::start(const IPAOperationData &ipaConfig,
> IPAOperationData *result)
>         unsigned int dropFrame = 0;
>         if (firstStart_) {
>                 dropFrame = helper_->HideFramesStartup();
> +
> +               /* The AGC algorithm may want us to drop more frames. */
> +               RPiController::AgcAlgorithm *agc =
> dynamic_cast<RPiController::AgcAlgorithm *>(
> +                       controller_.GetAlgorithm("agc"));
> +               if (agc)
> +                       dropFrame = std::max(dropFrame,
> agc->GetDropFrames());
> +               LOG(IPARPI, Debug) << "Drop " << dropFrame << " frames on
> startup";
> +
>

All looks good with this change, however, I have a possibly silly
question.  In the previous code, our startup frames would account for
convergence in AGC, AWB, and ALS.  Here we are explicitly accounting for
convergence only in AGC since helper_->HideFramesStartup()  will return 0
by default.  Does it matter? Should each derived CamHelper return a
non-zero number here?

Regards,
Naush



>                 mistrustCount_ = helper_->MistrustFramesStartup();
>         } else {
>                 dropFrame = helper_->HideFramesModeSwitch();
> --
> 2.20.1
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
>
Laurent Pinchart Dec. 5, 2020, 7:50 p.m. UTC | #2
Hi Naush and David,

On Fri, Dec 04, 2020 at 04:01:42PM +0000, Naushir Patuck wrote:
> On Wed, 2 Dec 2020 at 11:53, David Plowman wrote:
> 
> > Previously the CamHelper was returning the number of frames to drop
> > (on account of AGC converging). This wasn't really appropriate, it's
> > better for the AGC to do it, which now also knows when exposure and
> > gain have been explicitly set and therefore fewer (or no) frame drops
> > are necessary at all.
> >
> > The CamHelper::HideFramesStartup method should now just be returning
> > the number of frames to hide because they're bad/invalid in some way,
> > not worrying about the AGC. For many sensors, the correct value for
> > this is zero.
> >
> > Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
> > ---
> >  src/ipa/raspberrypi/cam_helper.cpp  | 6 +++---
> >  src/ipa/raspberrypi/raspberrypi.cpp | 8 ++++++++
> >  2 files changed, 11 insertions(+), 3 deletions(-)
> >
> > diff --git a/src/ipa/raspberrypi/cam_helper.cpp
> > b/src/ipa/raspberrypi/cam_helper.cpp
> > index c8ac3232..6efa0d7f 100644
> > --- a/src/ipa/raspberrypi/cam_helper.cpp
> > +++ b/src/ipa/raspberrypi/cam_helper.cpp
> > @@ -82,10 +82,10 @@ bool CamHelper::SensorEmbeddedDataPresent() const
> >  unsigned int CamHelper::HideFramesStartup() const
> >  {
> >         /*
> > -        * By default, hide 6 frames completely at start-up while AGC etc. sort
> > -        * themselves out (converge).
> > +        * The number of frames when a camera first starts that shouldn't be
> > +        * displayed as they are invalid in some way.
> >          */
> > -       return 6;
> > +       return 0;
> >  }
> >
> >  unsigned int CamHelper::HideFramesModeSwitch() const
> > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp
> > b/src/ipa/raspberrypi/raspberrypi.cpp
> > index 0300b8d9..ddabdb31 100644
> > --- a/src/ipa/raspberrypi/raspberrypi.cpp
> > +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> > @@ -192,6 +192,14 @@ int IPARPi::start(const IPAOperationData &ipaConfig,
> > IPAOperationData *result)
> >         unsigned int dropFrame = 0;
> >         if (firstStart_) {
> >                 dropFrame = helper_->HideFramesStartup();
> > +
> > +               /* The AGC algorithm may want us to drop more frames. */
> > +               RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
> > +                       controller_.GetAlgorithm("agc"));
> > +               if (agc)
> > +                       dropFrame = std::max(dropFrame, agc->GetDropFrames());
> > +               LOG(IPARPI, Debug) << "Drop " << dropFrame << " frames on startup";
> > +
> 
> All looks good with this change, however, I have a possibly silly
> question.  In the previous code, our startup frames would account for
> convergence in AGC, AWB, and ALS.  Here we are explicitly accounting for
> convergence only in AGC since helper_->HideFramesStartup()  will return 0
> by default.  Does it matter? Should each derived CamHelper return a
> non-zero number here?

Unless I'm mistaken, HideFramesStartup() is meant to report how many
incorrectly exposed (and "gained") frames are produced by the sensor at
startup, even if exposure time and gain are programmed before starting
the sensor. This will certainly impact AWB and ALS as they will have
trouble operating if the frame is greatly underexposed, but the sensor
is otherwise not involved in AWB and ALS. I thus don't think CamHelper
should take AWB and ALS into account.

With this new split of responsibilities, with CamHelper reporting the
number of frames that are bad (for different reasons, underexposed,
incorrect metadata, ...) and the algorithms then deciding how long they
need before initially converging, Shouldn't agc->GetDropFrames() be
given the HideFramesStartup() value as a parameter, and return a new
number, instead of taking the maximum between the two ?

I also wonder if we then need the hide/mistrust split anymore,
especially with the comment in CamHelperOv5647::MistrustFramesStartup()
that mentions underexposed frames. Is there still a difference between
the two concepts ?

Finally, do we actually need to report a number of frames to drop at
startup to the pipeline handler, can't we rely on the algorithms status
reported through AeLocked and AwbLocked ? Maybe we should report only
the number of frames that are definitely bad based on the CamHelper, and
use algorithm status to report initial convergence of the algorithms ?

> >                 mistrustCount_ = helper_->MistrustFramesStartup();
> >         } else {
> >                 dropFrame = helper_->HideFramesModeSwitch();
David Plowman Dec. 5, 2020, 11:28 p.m. UTC | #3
Hi again Laurent

Thanks for the comments, yes, I agree there's a little more to think about.

On Sat, 5 Dec 2020 at 19:50, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Naush and David,
>
> On Fri, Dec 04, 2020 at 04:01:42PM +0000, Naushir Patuck wrote:
> > On Wed, 2 Dec 2020 at 11:53, David Plowman wrote:
> >
> > > Previously the CamHelper was returning the number of frames to drop
> > > (on account of AGC converging). This wasn't really appropriate, it's
> > > better for the AGC to do it, which now also knows when exposure and
> > > gain have been explicitly set and therefore fewer (or no) frame drops
> > > are necessary at all.
> > >
> > > The CamHelper::HideFramesStartup method should now just be returning
> > > the number of frames to hide because they're bad/invalid in some way,
> > > not worrying about the AGC. For many sensors, the correct value for
> > > this is zero.
> > >
> > > Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
> > > ---
> > >  src/ipa/raspberrypi/cam_helper.cpp  | 6 +++---
> > >  src/ipa/raspberrypi/raspberrypi.cpp | 8 ++++++++
> > >  2 files changed, 11 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/src/ipa/raspberrypi/cam_helper.cpp
> > > b/src/ipa/raspberrypi/cam_helper.cpp
> > > index c8ac3232..6efa0d7f 100644
> > > --- a/src/ipa/raspberrypi/cam_helper.cpp
> > > +++ b/src/ipa/raspberrypi/cam_helper.cpp
> > > @@ -82,10 +82,10 @@ bool CamHelper::SensorEmbeddedDataPresent() const
> > >  unsigned int CamHelper::HideFramesStartup() const
> > >  {
> > >         /*
> > > -        * By default, hide 6 frames completely at start-up while AGC etc. sort
> > > -        * themselves out (converge).
> > > +        * The number of frames when a camera first starts that shouldn't be
> > > +        * displayed as they are invalid in some way.
> > >          */
> > > -       return 6;
> > > +       return 0;
> > >  }
> > >
> > >  unsigned int CamHelper::HideFramesModeSwitch() const
> > > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp
> > > b/src/ipa/raspberrypi/raspberrypi.cpp
> > > index 0300b8d9..ddabdb31 100644
> > > --- a/src/ipa/raspberrypi/raspberrypi.cpp
> > > +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> > > @@ -192,6 +192,14 @@ int IPARPi::start(const IPAOperationData &ipaConfig,
> > > IPAOperationData *result)
> > >         unsigned int dropFrame = 0;
> > >         if (firstStart_) {
> > >                 dropFrame = helper_->HideFramesStartup();
> > > +
> > > +               /* The AGC algorithm may want us to drop more frames. */
> > > +               RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
> > > +                       controller_.GetAlgorithm("agc"));
> > > +               if (agc)
> > > +                       dropFrame = std::max(dropFrame, agc->GetDropFrames());
> > > +               LOG(IPARPI, Debug) << "Drop " << dropFrame << " frames on startup";
> > > +
> >
> > All looks good with this change, however, I have a possibly silly
> > question.  In the previous code, our startup frames would account for
> > convergence in AGC, AWB, and ALS.  Here we are explicitly accounting for
> > convergence only in AGC since helper_->HideFramesStartup()  will return 0
> > by default.  Does it matter? Should each derived CamHelper return a
> > non-zero number here?
>
> Unless I'm mistaken, HideFramesStartup() is meant to report how many
> incorrectly exposed (and "gained") frames are produced by the sensor at
> startup, even if exposure time and gain are programmed before starting
> the sensor. This will certainly impact AWB and ALS as they will have
> trouble operating if the frame is greatly underexposed, but the sensor
> is otherwise not involved in AWB and ALS. I thus don't think CamHelper
> should take AWB and ALS into account.
>
> With this new split of responsibilities, with CamHelper reporting the
> number of frames that are bad (for different reasons, underexposed,
> incorrect metadata, ...) and the algorithms then deciding how long they
> need before initially converging, Shouldn't agc->GetDropFrames() be
> given the HideFramesStartup() value as a parameter, and return a new
> number, instead of taking the maximum between the two ?

Yes, I was already planning to change this as it's not quite right,
but I think I need to change it again. I think the correct behaviour
is as follows

Firstly, I'll look into giving AWB and ALSC the same
GetConvergenceFrames method as the AGC.

Next, I think the GetConvergenceFrames methods should be given the
MistrustFramesStartup number. If they actually have no convergence to
do (e.g. exposure and gain fixed), they return 0. Otherwise they add
their number to the MistrustFramesStartup number that they were given
and return that.

Finally, the dropFrames number is set to the maximum of
HideFramesStartup and all the GetConvergenceFrames values that we
obtained.

This gets the two important use cases right:

1. When things aren't fixed, and we give the algorithms as long as
they say plus the MistrustFramesStartup number, and

2. When everything is fixed, all the algorithms should tell us "zero",
so that we only skip frames if HideFramesStartup tells us to.

>
> I also wonder if we then need the hide/mistrust split anymore,
> especially with the comment in CamHelperOv5647::MistrustFramesStartup()
> that mentions underexposed frames. Is there still a difference between
> the two concepts ?

So I think there is, as discussed above. MistrustFramesModeSwitch,
though not used in my description above, still has a use too. If you
were to stop and restart the camera, so the algorithms don't need to
converge at all, you might still need to tell them to ignore a
frame's-worth of statistics, if they're thought to be bad in some way
(otherwise they risk making the algorithm go haywire when it tries to
process them).

>
> Finally, do we actually need to report a number of frames to drop at
> startup to the pipeline handler, can't we rely on the algorithms status
> reported through AeLocked and AwbLocked ? Maybe we should report only
> the number of frames that are definitely bad based on the CamHelper, and
> use algorithm status to report initial convergence of the algorithms ?
>
> > >                 mistrustCount_ = helper_->MistrustFramesStartup();
> > >         } else {
> > >                 dropFrame = helper_->HideFramesModeSwitch();

It's a good point. In practice we've found that users (OEMs in
particular) can be very sensitive about getting something on the
display asap, even if the AE/AWB isn't fully locked. On the other
hand, it still needs to look "visually locked", avoiding any obviously
bad frames, so we've always ended up in this sort of compromise
position where we actually display frames a little before they're
"technically" locked.

I'll make up another patch set on Monday with both your and Naush's
feedback, addressed, so thanks for all the suggestions.

Best regards
David

>
> --
> Regards,
>
> Laurent Pinchart
Naushir Patuck Dec. 6, 2020, 10:44 a.m. UTC | #4
Hi Laurent,

On Sat, 5 Dec 2020 at 19:50, Laurent Pinchart <
laurent.pinchart@ideasonboard.com> wrote:

> Hi Naush and David,
>
> On Fri, Dec 04, 2020 at 04:01:42PM +0000, Naushir Patuck wrote:
> > On Wed, 2 Dec 2020 at 11:53, David Plowman wrote:
> >
> > > Previously the CamHelper was returning the number of frames to drop
> > > (on account of AGC converging). This wasn't really appropriate, it's
> > > better for the AGC to do it, which now also knows when exposure and
> > > gain have been explicitly set and therefore fewer (or no) frame drops
> > > are necessary at all.
> > >
> > > The CamHelper::HideFramesStartup method should now just be returning
> > > the number of frames to hide because they're bad/invalid in some way,
> > > not worrying about the AGC. For many sensors, the correct value for
> > > this is zero.
> > >
> > > Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
> > > ---
> > >  src/ipa/raspberrypi/cam_helper.cpp  | 6 +++---
> > >  src/ipa/raspberrypi/raspberrypi.cpp | 8 ++++++++
> > >  2 files changed, 11 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/src/ipa/raspberrypi/cam_helper.cpp
> > > b/src/ipa/raspberrypi/cam_helper.cpp
> > > index c8ac3232..6efa0d7f 100644
> > > --- a/src/ipa/raspberrypi/cam_helper.cpp
> > > +++ b/src/ipa/raspberrypi/cam_helper.cpp
> > > @@ -82,10 +82,10 @@ bool CamHelper::SensorEmbeddedDataPresent() const
> > >  unsigned int CamHelper::HideFramesStartup() const
> > >  {
> > >         /*
> > > -        * By default, hide 6 frames completely at start-up while AGC
> etc. sort
> > > -        * themselves out (converge).
> > > +        * The number of frames when a camera first starts that
> shouldn't be
> > > +        * displayed as they are invalid in some way.
> > >          */
> > > -       return 6;
> > > +       return 0;
> > >  }
> > >
> > >  unsigned int CamHelper::HideFramesModeSwitch() const
> > > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp
> > > b/src/ipa/raspberrypi/raspberrypi.cpp
> > > index 0300b8d9..ddabdb31 100644
> > > --- a/src/ipa/raspberrypi/raspberrypi.cpp
> > > +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> > > @@ -192,6 +192,14 @@ int IPARPi::start(const IPAOperationData
> &ipaConfig,
> > > IPAOperationData *result)
> > >         unsigned int dropFrame = 0;
> > >         if (firstStart_) {
> > >                 dropFrame = helper_->HideFramesStartup();
> > > +
> > > +               /* The AGC algorithm may want us to drop more frames.
> */
> > > +               RPiController::AgcAlgorithm *agc =
> dynamic_cast<RPiController::AgcAlgorithm *>(
> > > +                       controller_.GetAlgorithm("agc"));
> > > +               if (agc)
> > > +                       dropFrame = std::max(dropFrame,
> agc->GetDropFrames());
> > > +               LOG(IPARPI, Debug) << "Drop " << dropFrame << " frames
> on startup";
> > > +
> >
> > All looks good with this change, however, I have a possibly silly
> > question.  In the previous code, our startup frames would account for
> > convergence in AGC, AWB, and ALS.  Here we are explicitly accounting for
> > convergence only in AGC since helper_->HideFramesStartup()  will return 0
> > by default.  Does it matter? Should each derived CamHelper return a
> > non-zero number here?
>
> Unless I'm mistaken, HideFramesStartup() is meant to report how many
> incorrectly exposed (and "gained") frames are produced by the sensor at
> startup, even if exposure time and gain are programmed before starting
> the sensor. This will certainly impact AWB and ALS as they will have
> trouble operating if the frame is greatly underexposed, but the sensor
> is otherwise not involved in AWB and ALS. I thus don't think CamHelper
> should take AWB and ALS into account.
>
> With this new split of responsibilities, with CamHelper reporting the
> number of frames that are bad (for different reasons, underexposed,
> incorrect metadata, ...) and the algorithms then deciding how long they
> need before initially converging, Shouldn't agc->GetDropFrames() be
> given the HideFramesStartup() value as a parameter, and return a new
> number, instead of taking the maximum between the two ?
>
> I also wonder if we then need the hide/mistrust split anymore,
> especially with the comment in CamHelperOv5647::MistrustFramesStartup()
> that mentions underexposed frames. Is there still a difference between
> the two concepts ?
>
> Finally, do we actually need to report a number of frames to drop at
> startup to the pipeline handler, can't we rely on the algorithms status
> reported through AeLocked and AwbLocked ?


In my opinion, doing it this way (making the pipeline handler drop all
frames where AE/AWB is not locked) would be very inefficient.  Knowing how
many buffers are meant to be dropped on startup as we currently do allows
the pipeline handler to efficiently pipeline(!) the buffers queued to the
device.

As an example, if the first Request after startup asks for the RAW frame to
be returned out to the application, we can pre-queue internally allocated
buffers to the count of the number of expected drop frames.  We then queue
up the Request provided RAW buffer to the device and have no additional
latency involved with handling dropped frames and returning the RAW
buffer.  If we were to wait for AE/AWB locked status without knowing the
number of dropped frames beforehand, we would have to continually queue the
Request provided RAW buffer to the device over and over again while we keep
dropping them in the pipeline handler. Typically, that doubles your capture
latency as you cannot pipeline the buffers queued to the streaming device
as is the current case.   It's a similar story for queueing ISP output
buffers, but (at least for Raspberry Pi) given the mem-to-mem behavior of
the HW, you don't take as big a hit on latency.  Hope that all makes sense!

Regards,
Naush



> Maybe we should report only
> the number of frames that are definitely bad based on the CamHelper, and
> use algorithm status to report initial convergence of the algorithms ?
>
> > >                 mistrustCount_ = helper_->MistrustFramesStartup();
> > >         } else {
> > >                 dropFrame = helper_->HideFramesModeSwitch();
>
> --
> Regards,
>
> Laurent Pinchart
>
Laurent Pinchart Dec. 8, 2020, 5:35 p.m. UTC | #5
Hi David,

On Sat, Dec 05, 2020 at 11:28:49PM +0000, David Plowman wrote:
> On Sat, 5 Dec 2020 at 19:50, Laurent Pinchart wrote:
> > On Fri, Dec 04, 2020 at 04:01:42PM +0000, Naushir Patuck wrote:
> > > On Wed, 2 Dec 2020 at 11:53, David Plowman wrote:
> > >
> > > > Previously the CamHelper was returning the number of frames to drop
> > > > (on account of AGC converging). This wasn't really appropriate, it's
> > > > better for the AGC to do it, which now also knows when exposure and
> > > > gain have been explicitly set and therefore fewer (or no) frame drops
> > > > are necessary at all.
> > > >
> > > > The CamHelper::HideFramesStartup method should now just be returning
> > > > the number of frames to hide because they're bad/invalid in some way,
> > > > not worrying about the AGC. For many sensors, the correct value for
> > > > this is zero.
> > > >
> > > > Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
> > > > ---
> > > >  src/ipa/raspberrypi/cam_helper.cpp  | 6 +++---
> > > >  src/ipa/raspberrypi/raspberrypi.cpp | 8 ++++++++
> > > >  2 files changed, 11 insertions(+), 3 deletions(-)
> > > >
> > > > diff --git a/src/ipa/raspberrypi/cam_helper.cpp
> > > > b/src/ipa/raspberrypi/cam_helper.cpp
> > > > index c8ac3232..6efa0d7f 100644
> > > > --- a/src/ipa/raspberrypi/cam_helper.cpp
> > > > +++ b/src/ipa/raspberrypi/cam_helper.cpp
> > > > @@ -82,10 +82,10 @@ bool CamHelper::SensorEmbeddedDataPresent() const
> > > >  unsigned int CamHelper::HideFramesStartup() const
> > > >  {
> > > >         /*
> > > > -        * By default, hide 6 frames completely at start-up while AGC etc. sort
> > > > -        * themselves out (converge).
> > > > +        * The number of frames when a camera first starts that shouldn't be
> > > > +        * displayed as they are invalid in some way.
> > > >          */
> > > > -       return 6;
> > > > +       return 0;
> > > >  }
> > > >
> > > >  unsigned int CamHelper::HideFramesModeSwitch() const
> > > > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp
> > > > b/src/ipa/raspberrypi/raspberrypi.cpp
> > > > index 0300b8d9..ddabdb31 100644
> > > > --- a/src/ipa/raspberrypi/raspberrypi.cpp
> > > > +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> > > > @@ -192,6 +192,14 @@ int IPARPi::start(const IPAOperationData &ipaConfig,
> > > > IPAOperationData *result)
> > > >         unsigned int dropFrame = 0;
> > > >         if (firstStart_) {
> > > >                 dropFrame = helper_->HideFramesStartup();
> > > > +
> > > > +               /* The AGC algorithm may want us to drop more frames. */
> > > > +               RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
> > > > +                       controller_.GetAlgorithm("agc"));
> > > > +               if (agc)
> > > > +                       dropFrame = std::max(dropFrame, agc->GetDropFrames());
> > > > +               LOG(IPARPI, Debug) << "Drop " << dropFrame << " frames on startup";
> > > > +
> > >
> > > All looks good with this change, however, I have a possibly silly
> > > question.  In the previous code, our startup frames would account for
> > > convergence in AGC, AWB, and ALS.  Here we are explicitly accounting for
> > > convergence only in AGC since helper_->HideFramesStartup()  will return 0
> > > by default.  Does it matter? Should each derived CamHelper return a
> > > non-zero number here?
> >
> > Unless I'm mistaken, HideFramesStartup() is meant to report how many
> > incorrectly exposed (and "gained") frames are produced by the sensor at
> > startup, even if exposure time and gain are programmed before starting
> > the sensor. This will certainly impact AWB and ALS as they will have
> > trouble operating if the frame is greatly underexposed, but the sensor
> > is otherwise not involved in AWB and ALS. I thus don't think CamHelper
> > should take AWB and ALS into account.
> >
> > With this new split of responsibilities, with CamHelper reporting the
> > number of frames that are bad (for different reasons, underexposed,
> > incorrect metadata, ...) and the algorithms then deciding how long they
> > need before initially converging, Shouldn't agc->GetDropFrames() be
> > given the HideFramesStartup() value as a parameter, and return a new
> > number, instead of taking the maximum between the two ?
> 
> Yes, I was already planning to change this as it's not quite right,
> but I think I need to change it again. I think the correct behaviour
> is as follows
> 
> Firstly, I'll look into giving AWB and ALSC the same
> GetConvergenceFrames method as the AGC.
> 
> Next, I think the GetConvergenceFrames methods should be given the
> MistrustFramesStartup number. If they actually have no convergence to
> do (e.g. exposure and gain fixed), they return 0. Otherwise they add
> their number to the MistrustFramesStartup number that they were given
> and return that.
> 
> Finally, the dropFrames number is set to the maximum of
> HideFramesStartup and all the GetConvergenceFrames values that we
> obtained.
> 
> This gets the two important use cases right:
> 
> 1. When things aren't fixed, and we give the algorithms as long as
> they say plus the MistrustFramesStartup number, and
> 
> 2. When everything is fixed, all the algorithms should tell us "zero",
> so that we only skip frames if HideFramesStartup tells us to.
> 
> > I also wonder if we then need the hide/mistrust split anymore,
> > especially with the comment in CamHelperOv5647::MistrustFramesStartup()
> > that mentions underexposed frames. Is there still a difference between
> > the two concepts ?
> 
> So I think there is, as discussed above. MistrustFramesModeSwitch,
> though not used in my description above, still has a use too. If you
> were to stop and restart the camera, so the algorithms don't need to
> converge at all, you might still need to tell them to ignore a
> frame's-worth of statistics, if they're thought to be bad in some way
> (otherwise they risk making the algorithm go haywire when it tries to
> process them).

Algorithms consume both statistics and metadata, do I assume correctly
that they would need to ignore both incorrect statistics (caused by
incorrect frames being produced by the sensor) and incorrect metadata
(caused by incorrect metadata produced by the sensor, even if the frame
itself is correct) ? If so, should mistrust frames be the highest of the
number of incorrect frames and incorrect metadata counts, or should it
model the latter only, with the IPA taking the maximum of the hide count
and the mistruct count to decide how many frames to ignore in the
beginning ? I think I have a preference for the latter, as CamHelper
should ideally report raw information about the sensor, without taking
into account how they will be used (same rationale as the one that made
this patch series exist in the first place, moving the convergence time
of the algorithms from CamHelper to the algorithms themselves). What do
you think ?

> > Finally, do we actually need to report a number of frames to drop at
> > startup to the pipeline handler, can't we rely on the algorithms status
> > reported through AeLocked and AwbLocked ? Maybe we should report only
> > the number of frames that are definitely bad based on the CamHelper, and
> > use algorithm status to report initial convergence of the algorithms ?
> >
> > > >                 mistrustCount_ = helper_->MistrustFramesStartup();
> > > >         } else {
> > > >                 dropFrame = helper_->HideFramesModeSwitch();
> 
> It's a good point. In practice we've found that users (OEMs in
> particular) can be very sensitive about getting something on the
> display asap, even if the AE/AWB isn't fully locked. On the other
> hand, it still needs to look "visually locked", avoiding any obviously
> bad frames, so we've always ended up in this sort of compromise
> position where we actually display frames a little before they're
> "technically" locked.

That's a very good point, it makes sense.

> I'll make up another patch set on Monday with both your and Naush's
> feedback, addressed, so thanks for all the suggestions.
Laurent Pinchart Dec. 8, 2020, 5:40 p.m. UTC | #6
Hi Naush,

On Sun, Dec 06, 2020 at 10:44:44AM +0000, Naushir Patuck wrote:
> On Sat, 5 Dec 2020 at 19:50, Laurent Pinchart wrote:
> > On Fri, Dec 04, 2020 at 04:01:42PM +0000, Naushir Patuck wrote:
> > > On Wed, 2 Dec 2020 at 11:53, David Plowman wrote:
> > >
> > > > Previously the CamHelper was returning the number of frames to drop
> > > > (on account of AGC converging). This wasn't really appropriate, it's
> > > > better for the AGC to do it, which now also knows when exposure and
> > > > gain have been explicitly set and therefore fewer (or no) frame drops
> > > > are necessary at all.
> > > >
> > > > The CamHelper::HideFramesStartup method should now just be returning
> > > > the number of frames to hide because they're bad/invalid in some way,
> > > > not worrying about the AGC. For many sensors, the correct value for
> > > > this is zero.
> > > >
> > > > Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
> > > > ---
> > > >  src/ipa/raspberrypi/cam_helper.cpp  | 6 +++---
> > > >  src/ipa/raspberrypi/raspberrypi.cpp | 8 ++++++++
> > > >  2 files changed, 11 insertions(+), 3 deletions(-)
> > > >
> > > > diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp
> > > > index c8ac3232..6efa0d7f 100644
> > > > --- a/src/ipa/raspberrypi/cam_helper.cpp
> > > > +++ b/src/ipa/raspberrypi/cam_helper.cpp
> > > > @@ -82,10 +82,10 @@ bool CamHelper::SensorEmbeddedDataPresent() const
> > > >  unsigned int CamHelper::HideFramesStartup() const
> > > >  {
> > > >         /*
> > > > -        * By default, hide 6 frames completely at start-up while AGC etc. sort
> > > > -        * themselves out (converge).
> > > > +        * The number of frames when a camera first starts that shouldn't be
> > > > +        * displayed as they are invalid in some way.
> > > >          */
> > > > -       return 6;
> > > > +       return 0;
> > > >  }
> > > >
> > > >  unsigned int CamHelper::HideFramesModeSwitch() const
> > > > diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp
> > > > index 0300b8d9..ddabdb31 100644
> > > > --- a/src/ipa/raspberrypi/raspberrypi.cpp
> > > > +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> > > > @@ -192,6 +192,14 @@ int IPARPi::start(const IPAOperationData &ipaConfig, IPAOperationData *result)
> > > >         unsigned int dropFrame = 0;
> > > >         if (firstStart_) {
> > > >                 dropFrame = helper_->HideFramesStartup();
> > > > +
> > > > +               /* The AGC algorithm may want us to drop more frames. */
> > > > +               RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
> > > > +                       controller_.GetAlgorithm("agc"));
> > > > +               if (agc)
> > > > +                       dropFrame = std::max(dropFrame, agc->GetDropFrames());
> > > > +               LOG(IPARPI, Debug) << "Drop " << dropFrame << " frames on startup";
> > > > +
> > >
> > > All looks good with this change, however, I have a possibly silly
> > > question.  In the previous code, our startup frames would account for
> > > convergence in AGC, AWB, and ALS.  Here we are explicitly accounting for
> > > convergence only in AGC since helper_->HideFramesStartup()  will return 0
> > > by default.  Does it matter? Should each derived CamHelper return a
> > > non-zero number here?
> >
> > Unless I'm mistaken, HideFramesStartup() is meant to report how many
> > incorrectly exposed (and "gained") frames are produced by the sensor at
> > startup, even if exposure time and gain are programmed before starting
> > the sensor. This will certainly impact AWB and ALS as they will have
> > trouble operating if the frame is greatly underexposed, but the sensor
> > is otherwise not involved in AWB and ALS. I thus don't think CamHelper
> > should take AWB and ALS into account.
> >
> > With this new split of responsibilities, with CamHelper reporting the
> > number of frames that are bad (for different reasons, underexposed,
> > incorrect metadata, ...) and the algorithms then deciding how long they
> > need before initially converging, Shouldn't agc->GetDropFrames() be
> > given the HideFramesStartup() value as a parameter, and return a new
> > number, instead of taking the maximum between the two ?
> >
> > I also wonder if we then need the hide/mistrust split anymore,
> > especially with the comment in CamHelperOv5647::MistrustFramesStartup()
> > that mentions underexposed frames. Is there still a difference between
> > the two concepts ?
> >
> > Finally, do we actually need to report a number of frames to drop at
> > startup to the pipeline handler, can't we rely on the algorithms status
> > reported through AeLocked and AwbLocked ?
> 
> In my opinion, doing it this way (making the pipeline handler drop all
> frames where AE/AWB is not locked) would be very inefficient.  Knowing how
> many buffers are meant to be dropped on startup as we currently do allows
> the pipeline handler to efficiently pipeline(!) the buffers queued to the
> device.
> 
> As an example, if the first Request after startup asks for the RAW frame to
> be returned out to the application, we can pre-queue internally allocated
> buffers to the count of the number of expected drop frames.  We then queue
> up the Request provided RAW buffer to the device and have no additional
> latency involved with handling dropped frames and returning the RAW
> buffer.  If we were to wait for AE/AWB locked status without knowing the
> number of dropped frames beforehand, we would have to continually queue the
> Request provided RAW buffer to the device over and over again while we keep
> dropping them in the pipeline handler. Typically, that doubles your capture
> latency as you cannot pipeline the buffers queued to the streaming device
> as is the current case.   It's a similar story for queueing ISP output
> buffers, but (at least for Raspberry Pi) given the mem-to-mem behavior of
> the HW, you don't take as big a hit on latency.  Hope that all makes sense!

That's a very good point too, I hadn't considered that. Thanks.

> > Maybe we should report only
> > the number of frames that are definitely bad based on the CamHelper, and
> > use algorithm status to report initial convergence of the algorithms ?
> >
> > > >                 mistrustCount_ = helper_->MistrustFramesStartup();
> > > >         } else {
> > > >                 dropFrame = helper_->HideFramesModeSwitch();

Patch
diff mbox series

diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp
index c8ac3232..6efa0d7f 100644
--- a/src/ipa/raspberrypi/cam_helper.cpp
+++ b/src/ipa/raspberrypi/cam_helper.cpp
@@ -82,10 +82,10 @@  bool CamHelper::SensorEmbeddedDataPresent() const
 unsigned int CamHelper::HideFramesStartup() const
 {
 	/*
-	 * By default, hide 6 frames completely at start-up while AGC etc. sort
-	 * themselves out (converge).
+	 * The number of frames when a camera first starts that shouldn't be
+	 * displayed as they are invalid in some way.
 	 */
-	return 6;
+	return 0;
 }
 
 unsigned int CamHelper::HideFramesModeSwitch() const
diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp
index 0300b8d9..ddabdb31 100644
--- a/src/ipa/raspberrypi/raspberrypi.cpp
+++ b/src/ipa/raspberrypi/raspberrypi.cpp
@@ -192,6 +192,14 @@  int IPARPi::start(const IPAOperationData &ipaConfig, IPAOperationData *result)
 	unsigned int dropFrame = 0;
 	if (firstStart_) {
 		dropFrame = helper_->HideFramesStartup();
+
+		/* The AGC algorithm may want us to drop more frames. */
+		RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
+			controller_.GetAlgorithm("agc"));
+		if (agc)
+			dropFrame = std::max(dropFrame, agc->GetDropFrames());
+		LOG(IPARPI, Debug) << "Drop " << dropFrame << " frames on startup";
+
 		mistrustCount_ = helper_->MistrustFramesStartup();
 	} else {
 		dropFrame = helper_->HideFramesModeSwitch();