[libcamera-devel] [PATCH v4 8/9] libcamera: pipeline: raspberrypi: Add more robust stream buffer logic

Naushir Patuck naush at raspberrypi.com
Tue Jul 21 14:35:51 CEST 2020


Hi Kieran,

On Tue, 21 Jul 2020 at 12:23, Kieran Bingham
<kieran.bingham at ideasonboard.com> wrote:
>
> Hi Naush,
>
> On 20/07/2020 10:13, Naushir Patuck wrote:
> > Add further queueing into the RPiStream object to ensure that we always
> > follow the buffer ordering (be it internal or external) given by
> > incoming Requests.
> >
> > This is essential, otherwise we risk dropping frames that are meant to
> > be part of a Request, and can cause the pipeline to stall indefinitely.
> > This also prevents any possibility of mismatched frame buffers going
> > through the pipeline and out to the application.
> >
>
> Sounds helpful... some questions below ... but I suspect I've just
> misinterpreted something...
>
> > Signed-off-by: Naushir Patuck <naush at raspberrypi.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> > ---
> >  .../pipeline/raspberrypi/rpi_stream.cpp       | 70 ++++++++++++++++---
> >  .../pipeline/raspberrypi/rpi_stream.h         | 12 +++-
> >  2 files changed, 71 insertions(+), 11 deletions(-)
> >
> > diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
> > index 02f8d3e0..6635a751 100644
> > --- a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
> > +++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
> > @@ -112,25 +112,34 @@ int RPiStream::queueBuffer(FrameBuffer *buffer)
> >        */
> >       if (!buffer) {
> >               if (availableBuffers_.empty()) {
> > -                     LOG(RPISTREAM, Warning) << "No buffers available for "
> > +                     LOG(RPISTREAM, Info) << "No buffers available for "
> >                                               << name_;
> > -                     return -EINVAL;
> > +                     /*
> > +                      * Note that we need to requeue an internal buffer as soon
> > +                      * as one becomes available.
> > +                      */
> > +                     requeueBuffers_.push(nullptr);
> > +                     return 0;
> >               }
> >
> >               buffer = availableBuffers_.front();
> >               availableBuffers_.pop();
> >       }
> >
> > -     LOG(RPISTREAM, Debug) << "Queuing buffer " << buffer->cookie()
> > -                           << " for " << name_;
> > +     /*
> > +      * If no earlier requests are pending to be queued we can go ahead and
> > +      * queue the buffer into the device.
> > +      */
> > +     if (requeueBuffers_.empty())
> > +             return queueToDevice(buffer);
> >
> > -     int ret = dev_->queueBuffer(buffer);
> > -     if (ret) {
> > -             LOG(RPISTREAM, Error) << "Failed to queue buffer for "
> > -                                   << name_;
> > -     }
> > +     /*
> > +      * There are earlier buffers to be queued, so this bufferm ust go on
>
>
> s/bufferm ust/buffer must/
>
> That could be fixed up while applying. It's minor.
>
>
>
> > +      * the waiting list.
> > +      */
> > +     requeueBuffers_.push(buffer);
> >
> > -     return ret;
> > +     return 0;
> >  }
> >
> >  void RPiStream::returnBuffer(FrameBuffer *buffer)
> > @@ -138,7 +147,35 @@ void RPiStream::returnBuffer(FrameBuffer *buffer)
> >       /* This can only be called for external streams. */
> >       assert(external_);
> >
> > +     /* Push this buffer back into the queue to be used again. */
> >       availableBuffers_.push(buffer);
> > +
> > +     /*
> > +      * Do we have any buffers that are waiting to be queued?
> > +      * If so, do it now as availableBuffers_ will not be empty.
> > +      */
> > +     while (!requeueBuffers_.empty()) {
> > +             FrameBuffer *buffer = requeueBuffers_.front();
> > +
> > +             if (!buffer) {
> > +                     /*
> > +                      * We want to queue an internal buffer, but none
> > +                      * are available. Can't do anything, quit the loop.
> > +                      */
> > +                     if (availableBuffers_.empty())
> > +                             break;
>
> Can this happen?
>
> This looks like:
>
> while(requeueBuffer exist)
>         buffer = first buffer from requeueBuffers
>         if (no buffer) {
>                 /* unreachable code ? */
>         }
>

Yes it is possible, having a nullptr element in requeueBuffers_ means
a Request did not provide a buffer for that stream, so we have to use
a buffer from availableBuffers_ instead.  This buffer will not be
returned out to the applications.  Hope that makes sense.

Regards,
Naush


>
>
> > +
> > +                     /*
> > +                      * We want to queue an internal buffer, and at least one
> > +                      * is available.
> > +                      */
> > +                     buffer = availableBuffers_.front();
> > +                     availableBuffers_.pop();
> > +             }
> > +
> > +             requeueBuffers_.pop();
> > +             queueToDevice(buffer);
> > +     }
> >  }
> >
> >  bool RPiStream::findFrameBuffer(FrameBuffer *buffer) const
> > @@ -155,10 +192,23 @@ bool RPiStream::findFrameBuffer(FrameBuffer *buffer) const
> >  void RPiStream::clearBuffers()
> >  {
> >       availableBuffers_ = std::queue<FrameBuffer *>{};
> > +     requeueBuffers_ = std::queue<FrameBuffer *>{};
> >       internalBuffers_.clear();
> >       bufferList_.clear();
> >  }
> >
> > +int RPiStream::queueToDevice(FrameBuffer *buffer)
> > +{
> > +     LOG(RPISTREAM, Debug) << "Queuing buffer " << buffer->cookie()
> > +                           << " for " << name_;
> > +
> > +     int ret = dev_->queueBuffer(buffer);
> > +     if (ret)
> > +             LOG(RPISTREAM, Error) << "Failed to queue buffer for "
> > +                                   << name_;
> > +     return ret;
> > +}
> > +
> >  } /* namespace RPi */
> >
> >  } /* namespace libcamera */
> > diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.h b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
> > index af9c2ad2..6222c867 100644
> > --- a/src/libcamera/pipeline/raspberrypi/rpi_stream.h
> > +++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
> > @@ -52,6 +52,7 @@ public:
> >
> >  private:
> >       void clearBuffers();
> > +     int queueToDevice(FrameBuffer *buffer);
> >       /*
> >        * Indicates that this stream is active externally, i.e. the buffers
> >        * might be provided by (and returned to) the application.
> > @@ -63,7 +64,7 @@ private:
> >       std::string name_;
> >       /* The actual device stream. */
> >       std::unique_ptr<V4L2VideoDevice> dev_;
> > -     /* All framebuffers associated with this device stream. */
> > +     /* All frame buffers associated with this device stream. */
> >       std::vector<FrameBuffer *> bufferList_;
> >       /*
> >        * List of frame buffer that we can use if none have been provided by
> > @@ -71,6 +72,15 @@ private:
> >        * buffers exported internally.
> >        */
> >       std::queue<FrameBuffer *> availableBuffers_;
> > +     /*
> > +      * List of frame buffer that are to be re-queued into the device.
>
> "List of frame buffers ..."
>
> > +      * A nullptr indicates any internal buffer can be used (from availableBuffers_),
> > +      * whereas a valid pointer indicates an external buffer to be queued.
>
> Oh ... are we pushing nullptrs on to the queues? ... perhaps that
> answers my unreachable code question above ...
>
>
> > +      *
> > +      * Ordering buffers to be queued is important here as it must match the
> > +      * requests coming from the application.
> > +      */
> > +     std::queue<FrameBuffer *> requeueBuffers_;
> >       /*
> >        * This is a list of buffers exported internally. Need to keep this around
> >        * as the stream needs to maintain ownership of these buffers.
> >
>
> --
> Regards
> --
> Kieran


More information about the libcamera-devel mailing list