[libcamera-devel] [RFC 10/12] libcamera: buffer: Store buffer information in separate container
Niklas Söderlund
niklas.soderlund at ragnatech.se
Thu Nov 21 22:02:37 CET 2019
Hi All,
Thanks all for your feedback!
On 2019-11-18 22:22:54 +0200, Laurent Pinchart wrote:
> Hi Niklas,
>
> Thank you for the patch.
>
> On Wed, Nov 06, 2019 at 11:18:30AM +0100, Jacopo Mondi wrote:
> > On Fri, Nov 01, 2019 at 01:15:58PM +0000, Kieran Bingham wrote:
> > > On 28/10/2019 02:25, Niklas Söderlund wrote:
> > > > Use the new BufferInfo container to store information from when a buffer
> > > > is dequeued. This will aid in the ongoing buffer rework and simplify the
> > > > code.
> > > >
> > > > This commits breaks the buffer sharing test case as it only deals with
> > > > buffer information going out of the video device. The next patch will
> > > > restore the test as it will address the incoming information. All other
> > > > tests as well as cam and qcam works as expected on pipelines not require
> > > > buffer importing.
> > >
> > > I certainly like moving all the BufferInfo data to it's own class to
> > > keep it distinct (and tidy), but I wonder - why not then just put the
> > > BufferInfo into the Buffer?
> > >
> > > Then the association between the Buffer and the BufferInfo is
> > > maintained, rather than having to provide separate lists and determine
> > > which BufferInfo belongs to which Buffer?
> > >
> > > (Or at the very least, doing so in this patch might prevent the
> > > temporary test breakage you report?)
> > >
> > > Do we have cases where we have a Buffer - but we do not need or care
> > > about the associated BufferInfo data?
> >
> > I was about to ask the same actually.
> >
> > The BufferInfo is created by the V4L2VideoDevice at queueBuffer() and
> > streaOff() time, and associated to a Buffer for its whole lifetime.
> > I would store a BufferInfo * in a Buffer, but then the question is:
> > could the pointer be retreived and accessed before it gets initialized
> > by V4L2VideoDevice::queueBuffer() ? In that case I agree it might make
> > sense to make the BufferInfo accessible only after a Request or a
> > Buffer has completed, to guarantee the association is in place.
> >
> > But then in that case, we should really avoid copies, so I would make
> > BufferInfo movable, as in Request::completeBuffer() the BufferInfo is
> > actually copied into the Request::info_ map.
>
> BufferInfo holds data directly, a move constructor or assignment
> operator won't help much. Data will still be copied, perhaps with the
> exception of the PlaneInfo vector, but that's very small anyway.
>
> > Or we could use the BufferInfo as temporary instances. At
>
> We shouldn't make BufferInfo temporary, as we shouldn't allocate any
> memory during the streaming cycle. I would thus either store the
> BufferInfo inside Buffer, or store it in a separate container that is
> allocated at stream start (which may be what this patch is doing).
>
> > Request::completeBuffer() time, we use the fields of the BufferInfo
> > received as parameter to create a new BufferInfo and store it in the
> > map, but at that point, a move constructor might be better. As
> > BufferInfo has fields which are not trivially movable we need to
> > define our own move constructor. (right? BufferInfo has a vector, so
> > the implicitly movable constructor is not generated if I'm not
> > mistaken)
>
> std::vector has a move constructor, so I don't think it would block
> anything.
BufferInfo is now stored inside the new FrameBuffer class.
>
> > > > Signed-off-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> > > > ---
> > > > include/libcamera/request.h | 6 ++-
> > > > src/cam/buffer_writer.cpp | 5 ++-
> > > > src/cam/buffer_writer.h | 4 +-
> > > > src/cam/capture.cpp | 21 ++++-----
> > > > src/libcamera/include/pipeline_handler.h | 3 +-
> > > > src/libcamera/include/v4l2_videodevice.h | 4 +-
> > > > src/libcamera/pipeline/ipu3/ipu3.cpp | 20 ++++-----
> > > > src/libcamera/pipeline/rkisp1/rkisp1.cpp | 40 ++++++++---------
> > > > src/libcamera/pipeline/uvcvideo.cpp | 6 +--
> > > > src/libcamera/pipeline/vimc.cpp | 6 +--
> > > > src/libcamera/pipeline_handler.cpp | 5 ++-
> > > > src/libcamera/request.cpp | 6 ++-
> > > > src/libcamera/v4l2_videodevice.cpp | 55 ++++++++----------------
> > > > src/qcam/main_window.cpp | 18 ++++----
> > > > src/qcam/main_window.h | 2 +-
> > > > test/camera/capture.cpp | 4 +-
> > > > test/v4l2_videodevice/buffer_sharing.cpp | 17 ++++----
> > > > test/v4l2_videodevice/capture_async.cpp | 4 +-
> > > > test/v4l2_videodevice/v4l2_m2mdevice.cpp | 8 ++--
> > > > 19 files changed, 114 insertions(+), 120 deletions(-)
> > > >
> > > > diff --git a/include/libcamera/request.h b/include/libcamera/request.h
> > > > index 2d5a5964e99eb75f..88ef7bf03fcfb77b 100644
> > > > --- a/include/libcamera/request.h
> > > > +++ b/include/libcamera/request.h
> > > > @@ -12,12 +12,12 @@
> > > > #include <stdint.h>
> > > > #include <unordered_set>
> > > >
> > > > +#include <libcamera/buffer.h>
> > > > #include <libcamera/controls.h>
> > > > #include <libcamera/signal.h>
> > > >
> > > > namespace libcamera {
> > > >
> > > > -class Buffer;
> > > > class Camera;
> > > > class CameraControlValidator;
> > > > class Stream;
> > > > @@ -39,6 +39,7 @@ public:
> > > > ControlList &controls() { return *controls_; }
> > > > ControlList &metadata() { return *metadata_; }
> > > > const std::map<Stream *, Buffer *> &buffers() const { return bufferMap_; }
> > > > + const BufferInfo &info(Buffer *frame) const { return info_.find(frame)->second; };
>
> The additional complexity is a bit of a shame :-( I wonder if this
> calls for storing BufferInfo in Buffer.
>
> > > > int addBuffer(std::unique_ptr<Buffer> buffer);
> > > > Buffer *findBuffer(Stream *stream) const;
> > > >
> > > > @@ -54,13 +55,14 @@ private:
> > > > int prepare();
> > > > void complete();
> > > >
> > > > - bool completeBuffer(Buffer *buffer);
> > > > + bool completeBuffer(Buffer *buffer, const BufferInfo &info);
>
> It would also help keeping this simpler.
>
> > > >
> > > > Camera *camera_;
> > > > CameraControlValidator *validator_;
> > > > ControlList *controls_;
> > > > ControlList *metadata_;
> > > > std::map<Stream *, Buffer *> bufferMap_;
> > > > + std::map<Buffer *, BufferInfo> info_;
> > > > std::unordered_set<Buffer *> pending_;
> > > >
> > > > const uint64_t cookie_;
> > > > diff --git a/src/cam/buffer_writer.cpp b/src/cam/buffer_writer.cpp
> > > > index c33e99c5f8173db8..3ee9e82ba216abb6 100644
> > > > --- a/src/cam/buffer_writer.cpp
> > > > +++ b/src/cam/buffer_writer.cpp
> > > > @@ -21,7 +21,8 @@ BufferWriter::BufferWriter(const std::string &pattern)
> > > > {
> > > > }
> > > >
> > > > -int BufferWriter::write(Buffer *buffer, const std::string &streamName)
> > > > +int BufferWriter::write(Buffer *buffer, const BufferInfo &info,
> > > > + const std::string &streamName)
> > > > {
> > > > std::string filename;
> > > > size_t pos;
> > > > @@ -32,7 +33,7 @@ int BufferWriter::write(Buffer *buffer, const std::string &streamName)
> > > > if (pos != std::string::npos) {
> > > > std::stringstream ss;
> > > > ss << streamName << "-" << std::setw(6)
> > > > - << std::setfill('0') << buffer->sequence();
> > > > + << std::setfill('0') << info.sequence();
> > > > filename.replace(pos, 1, ss.str());
> > > > }
> > > >
> > > > diff --git a/src/cam/buffer_writer.h b/src/cam/buffer_writer.h
> > > > index 7bf785d1e83235ff..38f7045c7d4e68a4 100644
> > > > --- a/src/cam/buffer_writer.h
> > > > +++ b/src/cam/buffer_writer.h
> > > > @@ -16,7 +16,9 @@ class BufferWriter
> > > > public:
> > > > BufferWriter(const std::string &pattern = "frame-#.bin");
> > > >
> > > > - int write(libcamera::Buffer *buffer, const std::string &streamName);
> > > > + int write(libcamera::Buffer *buffer,
> > > > + const libcamera::BufferInfo &info,
> > > > + const std::string &streamName);
> > > >
> > > > private:
> > > > std::string pattern_;
> > > > diff --git a/src/cam/capture.cpp b/src/cam/capture.cpp
> > > > index e665d819fb777a90..251e9f86c86b508d 100644
> > > > --- a/src/cam/capture.cpp
> > > > +++ b/src/cam/capture.cpp
> > > > @@ -138,32 +138,33 @@ void Capture::requestComplete(Request *request)
> > > > if (request->status() == Request::RequestCancelled)
> > > > return;
> > > >
> > > > - const std::map<Stream *, Buffer *> &buffers = request->buffers();
> > > > -
> > > > std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
> > > > double fps = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_).count();
> > > > fps = last_ != std::chrono::steady_clock::time_point() && fps
> > > > ? 1000.0 / fps : 0.0;
> > > > last_ = now;
> > > >
> > > > - std::stringstream info;
> > > > - info << "fps: " << std::fixed << std::setprecision(2) << fps;
> > > > + std::stringstream infostr;
> > > > + infostr << "fps: " << std::fixed << std::setprecision(2) << fps;
> > > >
> > > > + const std::map<Stream *, Buffer *> &buffers = request->buffers();
> > > > for (auto it = buffers.begin(); it != buffers.end(); ++it) {
> > > > Stream *stream = it->first;
> > > > Buffer *buffer = it->second;
> > > > + const BufferInfo &info = request->info(buffer);
> > > > const std::string &name = streamName_[stream];
> > > >
> > > > - info << " " << name
> > > > - << " (" << buffer->index() << ")"
> > > > - << " seq: " << std::setw(6) << std::setfill('0') << buffer->sequence()
> > > > - << " bytesused: " << buffer->bytesused();
> > > > + infostr << " " << name
> > > > + << " seq: " << std::setw(6) << std::setfill('0') << info.sequence();
> > > > +
> > > > + for (unsigned int i = 0; i < info.planes(); i++)
> > > > + infostr << " bytesused(" << i << "): " << info.plane(i).bytesused;
> > > >
> > > > if (writer_)
> > > > - writer_->write(buffer, name);
> > > > + writer_->write(buffer, info, name);
> > > > }
> > > >
> > > > - std::cout << info.str() << std::endl;
> > > > + std::cout << infostr.str() << std::endl;
> > > >
> > > > /*
> > > > * Create a new request and populate it with one buffer for each
> > > > diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h
> > > > index 6024357e266c2e2b..e6dbd7687021e4ff 100644
> > > > --- a/src/libcamera/include/pipeline_handler.h
> > > > +++ b/src/libcamera/include/pipeline_handler.h
> > > > @@ -81,7 +81,8 @@ public:
> > > >
> > > > virtual int queueRequest(Camera *camera, Request *request);
> > > >
> > > > - bool completeBuffer(Camera *camera, Request *request, Buffer *buffer);
> > > > + bool completeBuffer(Camera *camera, Request *request, Buffer *buffer,
> > > > + const BufferInfo &info);
> > > > void completeRequest(Camera *camera, Request *request);
> > > >
> > > > const char *name() const { return name_; }
> > > > diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h
> > > > index 5b178339d0ce7e2c..01b90ab4654bfba2 100644
> > > > --- a/src/libcamera/include/v4l2_videodevice.h
> > > > +++ b/src/libcamera/include/v4l2_videodevice.h
> > > > @@ -12,6 +12,7 @@
> > > >
> > > > #include <linux/videodev2.h>
> > > >
> > > > +#include <libcamera/buffer.h>
> > > > #include <libcamera/geometry.h>
> > > > #include <libcamera/signal.h>
> > > >
> > > > @@ -166,7 +167,7 @@ public:
> > > >
> > > > int queueBuffer(Buffer *buffer);
> > > > std::vector<std::unique_ptr<Buffer>> queueAllBuffers();
> > > > - Signal<Buffer *> bufferReady;
> > > > + Signal<Buffer *, const BufferInfo &> bufferReady;
> > > >
> > > > int streamOn();
> > > > int streamOff();
> > > > @@ -194,7 +195,6 @@ private:
> > > > int createPlane(BufferMemory *buffer, unsigned int index,
> > > > unsigned int plane, unsigned int length);
> > > >
> > > > - Buffer *dequeueBuffer();
>
> This isn't nice :-( It would be better if pipeline handler didn't have
> to dequeue buffers synchronously with the bufferReady signal, to make
> the API more flexible for them.
I have restored this for the next version.
>
> > > > void bufferAvailable(EventNotifier *notifier);
> > > >
> > > > V4L2Capability caps_;
> > > > diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
> > > > index 8aa5f34febf16585..01064ac09859155d 100644
> > > > --- a/src/libcamera/pipeline/ipu3/ipu3.cpp
> > > > +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
> > > > @@ -161,9 +161,9 @@ public:
> > > > delete vfStream_;
> > > > }
> > > >
> > > > - void imguOutputBufferReady(Buffer *buffer);
> > > > - void imguInputBufferReady(Buffer *buffer);
> > > > - void cio2BufferReady(Buffer *buffer);
> > > > + void imguOutputBufferReady(Buffer *buffer, const BufferInfo &info);
> > > > + void imguInputBufferReady(Buffer *buffer, const BufferInfo &info);
> > > > + void cio2BufferReady(Buffer *buffer, const BufferInfo &info);
> > > >
> > > > CIO2Device cio2_;
> > > > ImgUDevice *imgu_;
> > > > @@ -931,10 +931,10 @@ int PipelineHandlerIPU3::registerCameras()
> > > > * Buffers completed from the ImgU input are immediately queued back to the
> > > > * CIO2 unit to continue frame capture.
> > > > */
> > > > -void IPU3CameraData::imguInputBufferReady(Buffer *buffer)
> > > > +void IPU3CameraData::imguInputBufferReady(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > /* \todo Handle buffer failures when state is set to BufferError. */
> > > > - if (buffer->status() == Buffer::BufferCancelled)
> > > > + if (info.status() == BufferInfo::BufferCancelled)
> > > > return;
> > > >
> > > > cio2_.output_->queueBuffer(buffer);
> > > > @@ -946,15 +946,13 @@ void IPU3CameraData::imguInputBufferReady(Buffer *buffer)
> > > > *
> > > > * Buffers completed from the ImgU output are directed to the application.
> > > > */
> > > > -void IPU3CameraData::imguOutputBufferReady(Buffer *buffer)
> > > > +void IPU3CameraData::imguOutputBufferReady(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > Request *request = requestFromBuffer(buffer);
> > > >
> > > > - if (!pipe_->completeBuffer(camera_, request, buffer))
> > > > - /* Request not completed yet, return here. */
> > > > + if (!pipe_->completeBuffer(camera_, request, buffer, info))
> > > > return;
> > > >
> > > > - /* Mark the request as complete. */
> > > > pipe_->completeRequest(camera_, request);
> > > > }
> > > >
> > > > @@ -965,10 +963,10 @@ void IPU3CameraData::imguOutputBufferReady(Buffer *buffer)
> > > > * Buffers completed from the CIO2 are immediately queued to the ImgU unit
> > > > * for further processing.
> > > > */
> > > > -void IPU3CameraData::cio2BufferReady(Buffer *buffer)
> > > > +void IPU3CameraData::cio2BufferReady(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > /* \todo Handle buffer failures when state is set to BufferError. */
> > > > - if (buffer->status() == Buffer::BufferCancelled)
> > > > + if (info.status() == BufferInfo::BufferCancelled)
> > > > return;
> > > >
> > > > imgu_->input_->queueBuffer(buffer);
> > > > diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > index 0803572754364beb..33a058de18b8cf2e 100644
> > > > --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
> > > > @@ -88,7 +88,7 @@ public:
> > > > setDelay(QueueBuffers, -1, 10);
> > > > }
> > > >
> > > > - void bufferReady(Buffer *buffer)
> > > > + void bufferReady(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > /*
> > > > * Calculate SOE by taking the end of DMA set by the kernel and applying
> > > > @@ -99,10 +99,10 @@ public:
> > > > ASSERT(frameOffset(SOE) == 0);
> > > >
> > > > utils::time_point soe = std::chrono::time_point<utils::clock>()
> > > > - + std::chrono::nanoseconds(buffer->timestamp())
> > > > + + std::chrono::nanoseconds(info.timestamp())
> > > > + timeOffset(SOE);
> > > >
> > > > - notifyStartOfExposure(buffer->sequence(), soe);
> > > > + notifyStartOfExposure(info.sequence(), soe);
> > > > }
> > > >
> > > > void setDelay(unsigned int type, int frame, int msdelay)
> > > > @@ -202,9 +202,9 @@ private:
> > > > int initLinks();
> > > > int createCamera(MediaEntity *sensor);
> > > > void tryCompleteRequest(Request *request);
> > > > - void bufferReady(Buffer *buffer);
> > > > - void paramReady(Buffer *buffer);
> > > > - void statReady(Buffer *buffer);
> > > > + void bufferReady(Buffer *buffer, const BufferInfo &info);
> > > > + void paramReady(Buffer *buffer, const BufferInfo &info);
> > > > + void statReady(Buffer *buffer, const BufferInfo &info);
> > > >
> > > > MediaDevice *media_;
> > > > V4L2Subdevice *dphy_;
> > > > @@ -987,43 +987,43 @@ void PipelineHandlerRkISP1::tryCompleteRequest(Request *request)
> > > > data->frameInfo_.destroy(info->frame);
> > > > }
> > > >
> > > > -void PipelineHandlerRkISP1::bufferReady(Buffer *buffer)
> > > > +void PipelineHandlerRkISP1::bufferReady(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > ASSERT(activeCamera_);
> > > > RkISP1CameraData *data = cameraData(activeCamera_);
> > > > Request *request = data->requestFromBuffer(buffer);
> > > >
> > > > - data->timeline_.bufferReady(buffer);
> > > > + data->timeline_.bufferReady(buffer, info);
> > > >
> > > > - if (data->frame_ <= buffer->sequence())
> > > > - data->frame_ = buffer->sequence() + 1;
> > > > + if (data->frame_ <= info.sequence())
> > > > + data->frame_ = info.sequence() + 1;
> > > >
> > > > - completeBuffer(activeCamera_, request, buffer);
> > > > + completeBuffer(activeCamera_, request, buffer, info);
> > > > tryCompleteRequest(request);
> > > > }
> > > >
> > > > -void PipelineHandlerRkISP1::paramReady(Buffer *buffer)
> > > > +void PipelineHandlerRkISP1::paramReady(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > ASSERT(activeCamera_);
> > > > RkISP1CameraData *data = cameraData(activeCamera_);
> > > >
> > > > - RkISP1FrameInfo *info = data->frameInfo_.find(buffer);
> > > > + RkISP1FrameInfo *rkinfo = data->frameInfo_.find(buffer);
> > > >
> > > > - info->paramDequeued = true;
> > > > - tryCompleteRequest(info->request);
> > > > + rkinfo->paramDequeued = true;
> > > > + tryCompleteRequest(rkinfo->request);
> > > > }
> > > >
> > > > -void PipelineHandlerRkISP1::statReady(Buffer *buffer)
> > > > +void PipelineHandlerRkISP1::statReady(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > ASSERT(activeCamera_);
> > > > RkISP1CameraData *data = cameraData(activeCamera_);
> > > >
> > > > - RkISP1FrameInfo *info = data->frameInfo_.find(buffer);
> > > > - if (!info)
> > > > + RkISP1FrameInfo *rkinfo = data->frameInfo_.find(buffer);
> > > > + if (!rkinfo)
> > > > return;
> > > >
> > > > - unsigned int frame = info->frame;
> > > > - unsigned int statid = RKISP1_STAT_BASE | info->statBuffer->index();
> > > > + unsigned int frame = rkinfo->frame;
> > > > + unsigned int statid = RKISP1_STAT_BASE | rkinfo->statBuffer->index();
> > > >
> > > > IPAOperationData op;
> > > > op.operation = RKISP1_IPA_EVENT_SIGNAL_STAT_BUFFER;
> > > > diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp
> > > > index 679d82d38227b991..ef2e8c9734f844ce 100644
> > > > --- a/src/libcamera/pipeline/uvcvideo.cpp
> > > > +++ b/src/libcamera/pipeline/uvcvideo.cpp
> > > > @@ -42,7 +42,7 @@ public:
> > > > }
> > > >
> > > > int init(MediaEntity *entity);
> > > > - void bufferReady(Buffer *buffer);
> > > > + void bufferReady(Buffer *buffer, const BufferInfo &info);
> > > >
> > > > V4L2VideoDevice *video_;
> > > > Stream *stream_;
> > > > @@ -373,11 +373,11 @@ int UVCCameraData::init(MediaEntity *entity)
> > > > return 0;
> > > > }
> > > >
> > > > -void UVCCameraData::bufferReady(Buffer *buffer)
> > > > +void UVCCameraData::bufferReady(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > Request *request = requestFromBuffer(buffer);
> > > >
> > > > - pipe_->completeBuffer(camera_, request, buffer);
> > > > + pipe_->completeBuffer(camera_, request, buffer, info);
> > > > pipe_->completeRequest(camera_, request);
> > > > }
> > > >
> > > > diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp
> > > > index 56898716a8cde074..e3eefc49135179f2 100644
> > > > --- a/src/libcamera/pipeline/vimc.cpp
> > > > +++ b/src/libcamera/pipeline/vimc.cpp
> > > > @@ -56,7 +56,7 @@ public:
> > > > }
> > > >
> > > > int init(MediaDevice *media);
> > > > - void bufferReady(Buffer *buffer);
> > > > + void bufferReady(Buffer *buffer, const BufferInfo &info);
> > > >
> > > > CameraSensor *sensor_;
> > > > V4L2Subdevice *debayer_;
> > > > @@ -458,11 +458,11 @@ int VimcCameraData::init(MediaDevice *media)
> > > > return 0;
> > > > }
> > > >
> > > > -void VimcCameraData::bufferReady(Buffer *buffer)
> > > > +void VimcCameraData::bufferReady(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > Request *request = requestFromBuffer(buffer);
> > > >
> > > > - pipe_->completeBuffer(camera_, request, buffer);
> > > > + pipe_->completeBuffer(camera_, request, buffer, info);
> > > > pipe_->completeRequest(camera_, request);
> > > > }
> > > >
> > > > diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
> > > > index d70e286661aded8e..9ce9432449e0e133 100644
> > > > --- a/src/libcamera/pipeline_handler.cpp
> > > > +++ b/src/libcamera/pipeline_handler.cpp
> > > > @@ -393,10 +393,11 @@ int PipelineHandler::queueRequest(Camera *camera, Request *request)
> > > > * otherwise
> > > > */
> > > > bool PipelineHandler::completeBuffer(Camera *camera, Request *request,
> > > > - Buffer *buffer)
> > > > + Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > + bool ret = request->completeBuffer(buffer, info);
> > > > camera->bufferCompleted.emit(request, buffer);
> > > > - return request->completeBuffer(buffer);
> > > > + return ret;
> > > > }
> > > >
> > > > /**
> > > > diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp
> > > > index a9468ed4b0512a7f..9a0e439a3d05d780 100644
> > > > --- a/src/libcamera/request.cpp
> > > > +++ b/src/libcamera/request.cpp
> > > > @@ -252,12 +252,14 @@ void Request::complete()
> > > > * \return True if all buffers contained in the request have completed, false
> > > > * otherwise
> > > > */
> > > > -bool Request::completeBuffer(Buffer *buffer)
> > > > +bool Request::completeBuffer(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > int ret = pending_.erase(buffer);
> > > > ASSERT(ret == 1);
> > > >
> > > > - if (buffer->status() == Buffer::BufferCancelled)
> > > > + info_.emplace(buffer, info);
>
> If we want to store BufferInfo in a separate container, it should be
> allocated at stream start time (or, possibly, the first time a Buffer is
> queued), not at every completion (or queue operation). This seems to
> call for storing BufferInfo in Buffer.
>
> > > > +
> > > > + if (info.status() == BufferInfo::BufferCancelled)
> > > > cancelled_ = true;
> > > >
> > > > return !hasPendingBuffers();
> > > > diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
> > > > index 8bc2e439e4faeb68..97c6722b8c4c98cf 100644
> > > > --- a/src/libcamera/v4l2_videodevice.cpp
> > > > +++ b/src/libcamera/v4l2_videodevice.cpp
> > > > @@ -1119,14 +1119,16 @@ std::vector<std::unique_ptr<Buffer>> V4L2VideoDevice::queueAllBuffers()
> > > > }
> > > >
> > > > /**
> > > > - * \brief Dequeue the next available buffer from the video device
> > > > + * \brief Slot to handle completed buffer events from the V4L2 video device
> > > > + * \param[in] notifier The event notifier
> > > > *
> > > > - * This method dequeues the next available buffer from the device. If no buffer
> > > > - * is available to be dequeued it will return nullptr immediately.
> > > > + * When this slot is called, a Buffer has become available from the device, and
> > > > + * will be emitted through the bufferReady Signal.
> > > > *
> > > > - * \return A pointer to the dequeued buffer on success, or nullptr otherwise
> > > > + * For Capture video devices the Buffer will contain valid data.
> > > > + * For Output video devices the Buffer can be considered empty.
> > > > */
> > > > -Buffer *V4L2VideoDevice::dequeueBuffer()
> > > > +void V4L2VideoDevice::bufferAvailable(EventNotifier *notifier)
> > > > {
> > > > struct v4l2_buffer buf = {};
> > > > struct v4l2_plane planes[VIDEO_MAX_PLANES] = {};
> > > > @@ -1144,10 +1146,10 @@ Buffer *V4L2VideoDevice::dequeueBuffer()
> > > > if (ret < 0) {
> > > > LOG(V4L2, Error)
> > > > << "Failed to dequeue buffer: " << strerror(-ret);
> > > > - return nullptr;
> > > > + return;
> > > > }
> > > >
> > > > - ASSERT(buf.index < bufferPool_->count());
> > > > + LOG(V4L2, Debug) << "Buffer " << buf.index << " is available";
> > > >
> > > > auto it = queuedBuffers_.find(buf.index);
> > > > Buffer *buffer = it->second;
> > > > @@ -1156,37 +1158,16 @@ Buffer *V4L2VideoDevice::dequeueBuffer()
> > > > if (queuedBuffers_.empty())
> > > > fdEvent_->setEnabled(false);
> > > >
> > > > - buffer->index_ = buf.index;
> > > > - buffer->bytesused_ = buf.bytesused;
> > > > - buffer->timestamp_ = buf.timestamp.tv_sec * 1000000000ULL
> > > > - + buf.timestamp.tv_usec * 1000ULL;
> > > > - buffer->sequence_ = buf.sequence;
> > > > - buffer->status_ = buf.flags & V4L2_BUF_FLAG_ERROR
> > > > - ? Buffer::BufferError : Buffer::BufferSuccess;
> > > > -
> > > > - return buffer;
> > > > -}
> > > > + BufferInfo::Status status = buf.flags & V4L2_BUF_FLAG_ERROR
> > > > + ? BufferInfo::BufferError : BufferInfo::BufferSuccess;
> > > > + uint64_t timestamp = buf.timestamp.tv_sec * 1000000000ULL
> > > > + + buf.timestamp.tv_usec * 1000ULL;
> > > >
> > > > -/**
> > > > - * \brief Slot to handle completed buffer events from the V4L2 video device
> > > > - * \param[in] notifier The event notifier
> > > > - *
> > > > - * When this slot is called, a Buffer has become available from the device, and
> > > > - * will be emitted through the bufferReady Signal.
> > > > - *
> > > > - * For Capture video devices the Buffer will contain valid data.
> > > > - * For Output video devices the Buffer can be considered empty.
> > > > - */
> > > > -void V4L2VideoDevice::bufferAvailable(EventNotifier *notifier)
> > > > -{
> > > > - Buffer *buffer = dequeueBuffer();
> > > > - if (!buffer)
> > > > - return;
> > > > -
> > > > - LOG(V4L2, Debug) << "Buffer " << buffer->index() << " is available";
> > > > + BufferInfo info(status, buf.sequence, timestamp, { { buf.bytesused } });
> > > > + buffer->index_ = buf.index;
> > > >
> > > > /* Notify anyone listening to the device. */
> > > > - bufferReady.emit(buffer);
> > > > + bufferReady.emit(buffer, info);
> > > > }
> > > >
> > > > /**
> > > > @@ -1238,9 +1219,11 @@ int V4L2VideoDevice::streamOff()
> > > > unsigned int index = it.first;
> > > > Buffer *buffer = it.second;
> > > >
> > > > + BufferInfo info(BufferInfo::BufferCancelled, 0, 0, { {} });
> > > > +
> > > > buffer->index_ = index;
> > > > buffer->cancel();
> > > > - bufferReady.emit(buffer);
> > > > + bufferReady.emit(buffer, info);
> > > > }
> > > >
> > > > queuedBuffers_.clear();
> > > > diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> > > > index cca7365ae75687f9..2d7f4ba84fbb6838 100644
> > > > --- a/src/qcam/main_window.cpp
> > > > +++ b/src/qcam/main_window.cpp
> > > > @@ -258,19 +258,19 @@ void MainWindow::requestComplete(Request *request)
> > > > framesCaptured_++;
> > > >
> > > > Buffer *buffer = buffers.begin()->second;
> > > > + const BufferInfo &info = request->info(buffer);
> > > >
> > > > - double fps = buffer->timestamp() - lastBufferTime_;
> > > > + double fps = info.timestamp() - lastBufferTime_;
> > > > fps = lastBufferTime_ && fps ? 1000000000.0 / fps : 0.0;
> > > > - lastBufferTime_ = buffer->timestamp();
> > > > + lastBufferTime_ = info.timestamp();
> > > >
> > > > - std::cout << "seq: " << std::setw(6) << std::setfill('0') << buffer->sequence()
> > > > - << " buf: " << buffer->index()
> > > > - << " bytesused: " << buffer->bytesused()
> > > > - << " timestamp: " << buffer->timestamp()
> > > > + std::cout << "seq: " << std::setw(6) << std::setfill('0') << info.sequence()
> > > > + << " bytesused: " << info.plane(0).bytesused
> > > > + << " timestamp: " << info.timestamp()
> > > > << " fps: " << std::fixed << std::setprecision(2) << fps
> > > > << std::endl;
> > > >
> > > > - display(buffer);
> > > > + display(buffer, info);
> > > >
> > > > request = camera_->createRequest();
> > > > if (!request) {
> > > > @@ -295,7 +295,7 @@ void MainWindow::requestComplete(Request *request)
> > > > camera_->queueRequest(request);
> > > > }
> > > >
> > > > -int MainWindow::display(Buffer *buffer)
> > > > +int MainWindow::display(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > BufferMemory *mem = buffer->mem();
> > > > if (mem->planes().size() != 1)
> > > > @@ -303,7 +303,7 @@ int MainWindow::display(Buffer *buffer)
> > > >
> > > > Plane &plane = mem->planes().front();
> > > > unsigned char *raw = static_cast<unsigned char *>(plane.mem());
> > > > - viewfinder_->display(raw, buffer->bytesused());
> > > > + viewfinder_->display(raw, info.plane(0).bytesused);
> > > >
> > > > return 0;
> > > > }
> > > > diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h
> > > > index 78511581a8d5c025..8cbd72eb0d63cbea 100644
> > > > --- a/src/qcam/main_window.h
> > > > +++ b/src/qcam/main_window.h
> > > > @@ -50,7 +50,7 @@ private:
> > > > void stopCapture();
> > > >
> > > > void requestComplete(Request *request);
> > > > - int display(Buffer *buffer);
> > > > + int display(Buffer *frame, const BufferInfo &info);
> > > >
> > > > QString title_;
> > > > QTimer titleTimer_;
> > > > diff --git a/test/camera/capture.cpp b/test/camera/capture.cpp
> > > > index 83f974749affd3cd..3cf5b798448d01db 100644
> > > > --- a/test/camera/capture.cpp
> > > > +++ b/test/camera/capture.cpp
> > > > @@ -21,7 +21,9 @@ protected:
> > > >
> > > > void bufferComplete(Request *request, Buffer *buffer)
> > > > {
> > > > - if (buffer->status() != Buffer::BufferSuccess)
> > > > + const BufferInfo &info = request->info(buffer);
> > > > +
> > > > + if (info.status() != BufferInfo::BufferSuccess)
> > > > return;
> > > >
> > > > completeBuffersCount_++;
> > > > diff --git a/test/v4l2_videodevice/buffer_sharing.cpp b/test/v4l2_videodevice/buffer_sharing.cpp
> > > > index 1629f34cfa6c79fe..3609c331cf10e056 100644
> > > > --- a/test/v4l2_videodevice/buffer_sharing.cpp
> > > > +++ b/test/v4l2_videodevice/buffer_sharing.cpp
> > > > @@ -90,24 +90,25 @@ protected:
> > > > return 0;
> > > > }
> > > >
> > > > - void captureBufferReady(Buffer *buffer)
> > > > + void captureBufferReady(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > - std::cout << "Received capture buffer: " << buffer->index()
> > > > - << " sequence " << buffer->sequence() << std::endl;
> > > > + std::cout << "Received capture buffer sequence "
> > > > + << info.sequence() << std::endl;
> > > >
> > > > - if (buffer->status() != Buffer::BufferSuccess)
> > > > + if (info.status() != BufferInfo::BufferSuccess)
> > > > return;
> > > >
> > > > + BufferInfo infocopy = info;
> > > > output_->queueBuffer(buffer);
> > > > framesCaptured_++;
> > > > }
> > > >
> > > > - void outputBufferReady(Buffer *buffer)
> > > > + void outputBufferReady(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > - std::cout << "Received output buffer: " << buffer->index()
> > > > - << " sequence " << buffer->sequence() << std::endl;
> > > > + std::cout << "Received output buffer sequence "
> > > > + << info.sequence() << std::endl;
> > > >
> > > > - if (buffer->status() != Buffer::BufferSuccess)
> > > > + if (info.status() != BufferInfo::BufferSuccess)
> > > > return;
> > > >
> > > > capture_->queueBuffer(buffer);
> > > > diff --git a/test/v4l2_videodevice/capture_async.cpp b/test/v4l2_videodevice/capture_async.cpp
> > > > index 442a4fe56eace57e..26ea1d17fd901ef8 100644
> > > > --- a/test/v4l2_videodevice/capture_async.cpp
> > > > +++ b/test/v4l2_videodevice/capture_async.cpp
> > > > @@ -20,9 +20,9 @@ public:
> > > > CaptureAsyncTest()
> > > > : V4L2VideoDeviceTest("vimc", "Raw Capture 0"), frames(0) {}
> > > >
> > > > - void receiveBuffer(Buffer *buffer)
> > > > + void receiveBuffer(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > - std::cout << "Received buffer " << buffer->index() << std::endl;
> > > > + std::cout << "Received buffer" << std::endl;
> > > > frames++;
> > > >
> > > > /* Requeue the buffer for further use. */
> > > > diff --git a/test/v4l2_videodevice/v4l2_m2mdevice.cpp b/test/v4l2_videodevice/v4l2_m2mdevice.cpp
> > > > index 4d3644c2d28792f1..e6ca90a4604dfcda 100644
> > > > --- a/test/v4l2_videodevice/v4l2_m2mdevice.cpp
> > > > +++ b/test/v4l2_videodevice/v4l2_m2mdevice.cpp
> > > > @@ -29,9 +29,9 @@ public:
> > > > {
> > > > }
> > > >
> > > > - void outputBufferComplete(Buffer *buffer)
> > > > + void outputBufferComplete(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > - cout << "Received output buffer " << buffer->index() << endl;
> > > > + cout << "Received output buffer" << endl;
> > > >
> > > > outputFrames_++;
> > > >
> > > > @@ -39,9 +39,9 @@ public:
> > > > vim2m_->output()->queueBuffer(buffer);
> > > > }
> > > >
> > > > - void receiveCaptureBuffer(Buffer *buffer)
> > > > + void receiveCaptureBuffer(Buffer *buffer, const BufferInfo &info)
> > > > {
> > > > - cout << "Received capture buffer " << buffer->index() << endl;
> > > > + cout << "Received capture buffer" << endl;
> > >
> > > I actually liked seeing the indexes in my output - so I can see which
> > > buffers are in use... I guess we no longer have anything that maps to
> > > the index though...
> > >
> > > Perhaps at least making that info->sequence() would be better to keep
> > > some sort of a view of active data processing.
> > >
> > >
> > > > captureFrames_++;
>
> --
> Regards,
>
> Laurent Pinchart
--
Regards,
Niklas Söderlund
More information about the libcamera-devel
mailing list