[libcamera-devel] [RFC PATCH] libcamera, cam, qcam: Reuse Request

Laurent Pinchart laurent.pinchart at ideasonboard.com
Fri Sep 25 04:39:52 CEST 2020


Hi Paul,

On Fri, Sep 25, 2020 at 11:20:38AM +0900, paul.elder at ideasonboard.com wrote:
> On Thu, Sep 24, 2020 at 03:40:56PM +0300, Laurent Pinchart wrote:
> > On Thu, Sep 24, 2020 at 02:09:51PM +0200, Niklas Söderlund wrote:
> > > On 2020-09-23 21:14:48 +0900, Paul Elder wrote:
> > > > Allow reuse of the Request object by implementing a reset() function.
> > > > This means that the applications now have the responsibility of freeing
> > > > the the Request objects, so make cam and qcam do so.
> > > > 
> > > > Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
> > > > 
> > > > ---
> > > > In this RFC, I've only made qcam and cam reuse the Request object. Just
> > > > gauging the direction, and then I'll put it in for andoird and gstreamer
> > > > and v4l2-compat as well.
> > > > ---
> > > >  include/libcamera/request.h |  2 ++
> > > >  src/cam/capture.cpp         | 20 ++++++++++----------
> > > >  src/cam/capture.h           |  3 +++
> > > >  src/libcamera/camera.cpp    |  4 +---
> > > >  src/libcamera/request.cpp   |  9 +++++++++
> > > >  src/qcam/main_window.cpp    | 26 ++++++++++++--------------
> > > >  src/qcam/main_window.h      | 14 ++++++++++----
> > > >  src/qcam/viewfinder.h       |  4 +++-
> > > >  src/qcam/viewfinder_gl.cpp  |  9 +++++----
> > > >  src/qcam/viewfinder_gl.h    |  5 +++--
> > > >  src/qcam/viewfinder_qt.cpp  | 10 ++++++----
> > > >  src/qcam/viewfinder_qt.h    |  8 ++++++--
> > > >  12 files changed, 70 insertions(+), 44 deletions(-)
> > > > 
> > > > diff --git a/include/libcamera/request.h b/include/libcamera/request.h
> > > > index 5976ac50..9f615a24 100644
> > > > --- a/include/libcamera/request.h
> > > > +++ b/include/libcamera/request.h
> > > > @@ -38,6 +38,8 @@ public:
> > > >  	Request &operator=(const Request &) = delete;
> > > >  	~Request();
> > > >  
> > > > +	void reset();
> > > > +
> > > >  	ControlList &controls() { return *controls_; }
> > > >  	ControlList &metadata() { return *metadata_; }
> > > >  	const BufferMap &buffers() const { return bufferMap_; }
> > > > diff --git a/src/cam/capture.cpp b/src/cam/capture.cpp
> > > > index 5510c009..fe9d591a 100644
> > > > --- a/src/cam/capture.cpp
> > > > +++ b/src/cam/capture.cpp
> > > > @@ -65,6 +65,9 @@ int Capture::run(const OptionsParser::Options &options)
> > > >  		writer_ = nullptr;
> > > >  	}
> > > >  
> > > > +	for (Request *req : requests_)
> > > > +		delete req;
> > > > +
> > > >  	delete allocator;
> > > >  
> > > >  	return ret;
> > > > @@ -92,7 +95,6 @@ int Capture::capture(FrameBufferAllocator *allocator)
> > > >  	 * example pushing a button. For now run all streams all the time.
> > > >  	 */
> > > >  
> > > > -	std::vector<Request *> requests;
> > > >  	for (unsigned int i = 0; i < nbuffers; i++) {
> > > >  		Request *request = camera_->createRequest();
> > > >  		if (!request) {
> > > > @@ -117,7 +119,7 @@ int Capture::capture(FrameBufferAllocator *allocator)
> > > >  				writer_->mapBuffer(buffer.get());
> > > >  		}
> > > >  
> > > > -		requests.push_back(request);
> > > > +		requests_.push_back(request);
> > > >  	}
> > > >  
> > > >  	ret = camera_->start();
> > > > @@ -126,7 +128,7 @@ int Capture::capture(FrameBufferAllocator *allocator)
> > > >  		return ret;
> > > >  	}
> > > >  
> > > > -	for (Request *request : requests) {
> > > > +	for (Request *request : requests_) {
> > > >  		ret = camera_->queueRequest(request);
> > > >  		if (ret < 0) {
> > > >  			std::cerr << "Can't queue request" << std::endl;
> > > > @@ -153,10 +155,12 @@ int Capture::capture(FrameBufferAllocator *allocator)
> > > >  
> > > >  void Capture::requestComplete(Request *request)
> > > >  {
> > > > -	if (request->status() == Request::RequestCancelled)
> > > > +	if (request->status() == Request::RequestCancelled) {
> > > > +		request->reset();
> > > >  		return;
> > > > +	}
> > > >  
> > > > -	const Request::BufferMap &buffers = request->buffers();
> > > > +	const Request::BufferMap buffers = request->buffers();
> > 
> > A copy isn't very nice, but we can live with it for now.
> 
> Without the copy, all the buffers become invalid upon reset :/

I know, that's why I said we can live with it for now :-)

> > > >  
> > > >  	/*
> > > >  	 * Compute the frame rate. The timestamp is arbitrarily retrieved from
> > > > @@ -206,11 +210,7 @@ void Capture::requestComplete(Request *request)
> > > >  	 * Create a new request and populate it with one buffer for each
> > > >  	 * stream.
> > > >  	 */
> > > > -	request = camera_->createRequest();
> > > > -	if (!request) {
> > > > -		std::cerr << "Can't create request" << std::endl;
> > > > -		return;
> > > > -	}
> > > > +	request->reset();
> > > 
> > > Hum, is this really "reusing" the request object? I imagined a reused 
> > > request would retain its buffers while gaining the ability to be be 
> > > requeued to the Camera after it have completed. With this patch we still 
> > > need to keep the logic to fill the request with buffers each iteration, 
> > > is there some advantage to this I'm missing?
> > 
> > Two advantages, we don't free and reallocate the request needlessly, and
> > it can be stored in the application and used after the request handler
> > completes.
> > 
> > I don't think retaining buffers by default is a good idea, in many cases
> > we'll have a different number of buffers that can be cycled through than
> > the number of allocated requests.
> > 
> > > >  
> > > >  	for (auto it = buffers.begin(); it != buffers.end(); ++it) {
> > > >  		const Stream *stream = it->first;
> > > > diff --git a/src/cam/capture.h b/src/cam/capture.h
> > > > index 0aebdac9..62cf9bf1 100644
> > > > --- a/src/cam/capture.h
> > > > +++ b/src/cam/capture.h
> > > > @@ -9,6 +9,7 @@
> > > >  
> > > >  #include <memory>
> > > >  #include <stdint.h>
> > > > +#include <vector>
> > > >  
> > > >  #include <libcamera/buffer.h>
> > > >  #include <libcamera/camera.h>
> > > > @@ -43,6 +44,8 @@ private:
> > > >  	EventLoop *loop_;
> > > >  	unsigned int captureCount_;
> > > >  	unsigned int captureLimit_;
> > > > +
> > > > +	std::vector<libcamera::Request *> requests_;
> > > >  };
> > > >  
> > > >  #endif /* __CAM_CAPTURE_H__ */
> > > > diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
> > > > index ae16a64a..4cc68bce 100644
> > > > --- a/src/libcamera/camera.cpp
> > > > +++ b/src/libcamera/camera.cpp
> > > > @@ -974,13 +974,11 @@ int Camera::stop()
> > > >   * \param[in] request The request that has completed
> > > >   *
> > > >   * This function is called by the pipeline handler to notify the camera that
> > > > - * the request has completed. It emits the requestCompleted signal and deletes
> > > > - * the request.
> > > > + * the request has completed. It emits the requestCompleted signal.
> > > >   */
> > > >  void Camera::requestComplete(Request *request)
> > > >  {
> > > >  	requestCompleted.emit(request);
> > > > -	delete request;
> > > >  }
> > > >  
> > > >  } /* namespace libcamera */
> > > > diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp
> > > > index 60b30692..606866a6 100644
> > > > --- a/src/libcamera/request.cpp
> > > > +++ b/src/libcamera/request.cpp
> > > > @@ -85,6 +85,15 @@ Request::~Request()
> > > >  	delete validator_;
> > > >  }
> > > >  
> > 
> > No documentation ? :-) You should also update the documentation of
> 
> Not yet :p
> 
> > Camera::queueRequest(). Thinking about it, I think we should enforce
> > ownership of requests by the application by returning a
> > std::unique_ptr<Request> from Camera::createRequest(). We may even want
> > to drop Camera::createRequest() completely, but that can be done in a
> > separate patch.
> 
> Yeah... but I thought there was a problem when the Request completes,
> since there could be multiple slots, and they all can't receive unique
> pointers.
> 
> On the other hand... it's only one application... could we require that
> the application only connect one slot to the Request completion handler,
> and then the application can split it among multiple sub-handlers if it
> wants to? Then we can keep unique_ptr for the Request, and the ownership
> can be clear.

I don't think there's a way to implement this, the number of connected
slots isn't known at compile time, the compiler won't like a
std::unique_ptr<> in a signal in any case.

But that's not what I was proposing. With request reuse, ownership of
the request stays in the application. Passing the request pointer to
Camera::queueRequest() borrows a reference, the function shouldn't take
a unique pointer. The completion handler will thus keep using a normal
pointer too. It's only Camera::createRequest() that would return a
unique pointer, to enforce ownership of the request by the application.

> > > > +void Request::reset()
> > > > +{
> > > > +	bufferMap_.clear();
> > > > +	pending_.clear();
> > 
> > You need to clear controls_ and metadata_ too.
> 
> Oh okay, those can't be reused?

Why should they ?

> > > > +
> > > > +	status_ = RequestPending;
> > > > +	cancelled_ = false;
> > > > +}
> > > > +
> > > >  /**
> > > >   * \fn Request::controls()
> > > >   * \brief Retrieve the request's ControlList
> > > > diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> > > > index 985743f3..1531b44f 100644
> > > > --- a/src/qcam/main_window.cpp
> > > > +++ b/src/qcam/main_window.cpp
> > > > @@ -367,7 +367,6 @@ void MainWindow::toggleCapture(bool start)
> > > >  int MainWindow::startCapture()
> > > >  {
> > > >  	StreamRoles roles = StreamKeyValueParser::roles(options_[OptStream]);
> > > > -	std::vector<Request *> requests;
> > > >  	int ret;
> > > >  
> > > >  	/* Verify roles are supported. */
> > > > @@ -499,7 +498,7 @@ int MainWindow::startCapture()
> > > >  			goto error;
> > > >  		}
> > > >  
> > > > -		requests.push_back(request);
> > > > +		requests_.push_back(request);
> > > >  	}
> > > >  
> > > >  	/* Start the title timer and the camera. */
> > > > @@ -518,7 +517,7 @@ int MainWindow::startCapture()
> > > >  	camera_->requestCompleted.connect(this, &MainWindow::requestComplete);
> > > >  
> > > >  	/* Queue all requests. */
> > > > -	for (Request *request : requests) {
> > > > +	for (Request *request : requests_) {
> > > >  		ret = camera_->queueRequest(request);
> > > >  		if (ret < 0) {
> > > >  			qWarning() << "Can't queue request";
> > > > @@ -535,7 +534,7 @@ error_disconnect:
> > > >  	camera_->stop();
> > > >  
> > > >  error:
> > > > -	for (Request *request : requests)
> > > > +	for (Request *request : requests_)
> > > >  		delete request;
> > > >  
> > > >  	for (auto &iter : mappedBuffers_) {
> > > > @@ -580,6 +579,9 @@ void MainWindow::stopCapture()
> > > >  	}
> > > >  	mappedBuffers_.clear();
> > > >  
> > > > +	for (Request *req : requests_)
> > > > +		delete req;
> > 
> > Have you tried stopping and restarting capture ? You delete all the
> > requests here, but the vector still contains the pointers. When capture
> > is restarted I expect issue. A
> > 
> > 	requests_.clear();
> 
> Ah, right.
> 
> > is needed, and I would also turn it into a
> > std::vector<std::unique_ptr<Request>> to avoid the manual delete loops.
> > Same thing for the cam application (even if in that case capture can't
> > be stopped and restarted at the moment, but let's still do it right).
> > 
> > > > +
> > > >  	delete allocator_;
> > > >  
> > > >  	isCapturing_ = false;
> > > > @@ -701,7 +703,7 @@ void MainWindow::requestComplete(Request *request)
> > > >  	 */
> > > >  	{
> > > >  		QMutexLocker locker(&mutex_);
> > > > -		doneQueue_.enqueue({ request->buffers(), request->metadata() });
> > > > +		doneQueue_.enqueue({ request->buffers(), request->metadata(), request });
> > 
> > You aobut enqueuing the request only ? The reason to enqueue a copy of
> > buffers() and metadata() was because the request was deleted right after
> > this function returns, now that it's not the case anymore, we can just
> > pass the request around. The MainWindow::CaptureRequest class can be
> > removed.
> 
> ack
> 
> > > >  	}
> > > >  
> > > >  	QCoreApplication::postEvent(this, new CaptureEvent);
> > > > @@ -726,13 +728,13 @@ void MainWindow::processCapture()
> > > >  
> > > >  	/* Process buffers. */
> > > >  	if (request.buffers_.count(vfStream_))
> > > > -		processViewfinder(request.buffers_[vfStream_]);
> > > > +		processViewfinder(request.request_, request.buffers_[vfStream_]);
> > > >  
> > > >  	if (request.buffers_.count(rawStream_))
> > > >  		processRaw(request.buffers_[rawStream_], request.metadata_);
> > 
> > Instead of passing the request to processViewfinder(), how about adding
> > it to a free list here, and taking a request from the free list in
> > MainWindow::queueRequest() ? That would avoid the changes to the
> > viewfinder.
> 
> ack
> 
> > > >  }
> > > >  
> > > > -void MainWindow::processViewfinder(FrameBuffer *buffer)
> > > > +void MainWindow::processViewfinder(Request *request, FrameBuffer *buffer)
> > > >  {
> > > >  	framesCaptured_++;
> > > >  
> > > > @@ -749,16 +751,12 @@ void MainWindow::processViewfinder(FrameBuffer *buffer)
> > > >  		<< "fps:" << Qt::fixed << qSetRealNumberPrecision(2) << fps;
> > > >  
> > > >  	/* Render the frame on the viewfinder. */
> > > > -	viewfinder_->render(buffer, &mappedBuffers_[buffer]);
> > > > +	viewfinder_->render(request, buffer, &mappedBuffers_[buffer]);
> > > >  }
> > > >  
> > > > -void MainWindow::queueRequest(FrameBuffer *buffer)
> > > > +void MainWindow::queueRequest(Request *request, FrameBuffer *buffer)
> > > >  {
> > > > -	Request *request = camera_->createRequest();
> > > > -	if (!request) {
> > > > -		qWarning() << "Can't create request";
> > > > -		return;
> > > > -	}
> > > > +	request->reset();
> > > >  
> > > >  	request->addBuffer(vfStream_, buffer);
> > > >  
> > > > diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h
> > > > index 5c61a4df..83535373 100644
> > > > --- a/src/qcam/main_window.h
> > > > +++ b/src/qcam/main_window.h
> > > > @@ -8,6 +8,7 @@
> > > >  #define __QCAM_MAIN_WINDOW_H__
> > > >  
> > > >  #include <memory>
> > > > +#include <vector>
> > > >  
> > > >  #include <QElapsedTimer>
> > > >  #include <QIcon>
> > > > @@ -22,6 +23,7 @@
> > > >  #include <libcamera/camera_manager.h>
> > > >  #include <libcamera/controls.h>
> > > >  #include <libcamera/framebuffer_allocator.h>
> > > > +#include <libcamera/request.h>
> > > >  #include <libcamera/stream.h>
> > > >  
> > > >  #include "../cam/stream_options.h"
> > > > @@ -49,13 +51,15 @@ public:
> > > >  	}
> > > >  
> > > >  	CaptureRequest(const Request::BufferMap &buffers,
> > > > -		       const ControlList &metadata)
> > > > -		: buffers_(buffers), metadata_(metadata)
> > > > +		       const ControlList &metadata,
> > > > +		       Request * const request)
> > > > +		: buffers_(buffers), metadata_(metadata), request_(request)
> > > >  	{
> > > >  	}
> > > >  
> > > >  	Request::BufferMap buffers_;
> > > >  	ControlList metadata_;
> > > > +	Request *request_;
> > > >  };
> > > >  
> > > >  class MainWindow : public QMainWindow
> > > > @@ -79,7 +83,7 @@ private Q_SLOTS:
> > > >  	void captureRaw();
> > > >  	void processRaw(FrameBuffer *buffer, const ControlList &metadata);
> > > >  
> > > > -	void queueRequest(FrameBuffer *buffer);
> > > > +	void queueRequest(Request *request, FrameBuffer *buffer);
> > > >  
> > > >  private:
> > > >  	int createToolbars();
> > > > @@ -96,7 +100,7 @@ private:
> > > >  	void requestComplete(Request *request);
> > > >  	void processCapture();
> > > >  	void processHotplug(HotplugEvent *e);
> > > > -	void processViewfinder(FrameBuffer *buffer);
> > > > +	void processViewfinder(Request *request, FrameBuffer *buffer);
> > > >  
> > > >  	/* UI elements */
> > > >  	QToolBar *toolbar_;
> > > > @@ -135,6 +139,8 @@ private:
> > > >  	QElapsedTimer frameRateInterval_;
> > > >  	uint32_t previousFrames_;
> > > >  	uint32_t framesCaptured_;
> > > > +
> > > > +	std::vector<Request *> requests_;
> > > >  };
> > > >  
> > > >  #endif /* __QCAM_MAIN_WINDOW__ */
> > > > diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h
> > > > index 67da1df2..26c20f1b 100644
> > > > --- a/src/qcam/viewfinder.h
> > > > +++ b/src/qcam/viewfinder.h
> > > > @@ -27,7 +27,9 @@ public:
> > > >  	virtual const QList<libcamera::PixelFormat> &nativeFormats() const = 0;
> > > >  
> > > >  	virtual int setFormat(const libcamera::PixelFormat &format, const QSize &size) = 0;
> > > > -	virtual void render(libcamera::FrameBuffer *buffer, MappedBuffer *map) = 0;
> > > > +	virtual void render(libcamera::Request *request,
> > > > +			    libcamera::FrameBuffer *buffer,
> > > > +			    MappedBuffer *map) = 0;
> > > >  	virtual void stop() = 0;
> > > >  
> > > >  	virtual QImage getCurrentImage() = 0;
> > > > diff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp
> > > > index fbe21dcf..c65b41f6 100644
> > > > --- a/src/qcam/viewfinder_gl.cpp
> > > > +++ b/src/qcam/viewfinder_gl.cpp
> > > > @@ -23,7 +23,7 @@ static const QList<libcamera::PixelFormat> supportedFormats{
> > > >  };
> > > >  
> > > >  ViewFinderGL::ViewFinderGL(QWidget *parent)
> > > > -	: QOpenGLWidget(parent), buffer_(nullptr), yuvData_(nullptr),
> > > > +	: QOpenGLWidget(parent), request_(nullptr), buffer_(nullptr), yuvData_(nullptr),
> > > >  	  fragmentShader_(nullptr), vertexShader_(nullptr),
> > > >  	  vertexBuffer_(QOpenGLBuffer::VertexBuffer),
> > > >  	  textureU_(QOpenGLTexture::Target2D),
> > > > @@ -67,7 +67,7 @@ int ViewFinderGL::setFormat(const libcamera::PixelFormat &format,
> > > >  void ViewFinderGL::stop()
> > > >  {
> > > >  	if (buffer_) {
> > > > -		renderComplete(buffer_);
> > > > +		renderComplete(request_, buffer_);
> > > >  		buffer_ = nullptr;
> > > >  	}
> > > >  }
> > > > @@ -79,7 +79,7 @@ QImage ViewFinderGL::getCurrentImage()
> > > >  	return grabFramebuffer();
> > > >  }
> > > >  
> > > > -void ViewFinderGL::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)
> > > > +void ViewFinderGL::render(libcamera::Request *request, libcamera::FrameBuffer *buffer, MappedBuffer *map)
> > > >  {
> > > >  	if (buffer->planes().size() != 1) {
> > > >  		qWarning() << "Multi-planar buffers are not supported";
> > > > @@ -87,11 +87,12 @@ void ViewFinderGL::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)
> > > >  	}
> > > >  
> > > >  	if (buffer_)
> > > > -		renderComplete(buffer_);
> > > > +		renderComplete(request_, buffer_);
> > > >  
> > > >  	yuvData_ = static_cast<unsigned char *>(map->memory);
> > > >  	update();
> > > >  	buffer_ = buffer;
> > > > +	request_ = request;
> > > >  }
> > > >  
> > > >  bool ViewFinderGL::selectFormat(const libcamera::PixelFormat &format)
> > > > diff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h
> > > > index 69502b7a..7db41841 100644
> > > > --- a/src/qcam/viewfinder_gl.h
> > > > +++ b/src/qcam/viewfinder_gl.h
> > > > @@ -36,13 +36,13 @@ public:
> > > >  	const QList<libcamera::PixelFormat> &nativeFormats() const override;
> > > >  
> > > >  	int setFormat(const libcamera::PixelFormat &format, const QSize &size) override;
> > > > -	void render(libcamera::FrameBuffer *buffer, MappedBuffer *map) override;
> > > > +	void render(libcamera::Request *request, libcamera::FrameBuffer *buffer, MappedBuffer *map) override;
> > > >  	void stop() override;
> > > >  
> > > >  	QImage getCurrentImage() override;
> > > >  
> > > >  Q_SIGNALS:
> > > > -	void renderComplete(libcamera::FrameBuffer *buffer);
> > > > +	void renderComplete(libcamera::Request *request, libcamera::FrameBuffer *buffer);
> > > >  
> > > >  protected:
> > > >  	void initializeGL() override;
> > > > @@ -60,6 +60,7 @@ private:
> > > >  	void doRender();
> > > >  
> > > >  	/* Captured image size, format and buffer */
> > > > +	libcamera::Request *request_;
> > > >  	libcamera::FrameBuffer *buffer_;
> > > >  	libcamera::PixelFormat format_;
> > > >  	QSize size_;
> > > > diff --git a/src/qcam/viewfinder_qt.cpp b/src/qcam/viewfinder_qt.cpp
> > > > index e436714c..7f9f913b 100644
> > > > --- a/src/qcam/viewfinder_qt.cpp
> > > > +++ b/src/qcam/viewfinder_qt.cpp
> > > > @@ -34,7 +34,7 @@ static const QMap<libcamera::PixelFormat, QImage::Format> nativeFormats
> > > >  };
> > > >  
> > > >  ViewFinderQt::ViewFinderQt(QWidget *parent)
> > > > -	: QWidget(parent), buffer_(nullptr)
> > > > +	: QWidget(parent), request_(nullptr), buffer_(nullptr)
> > > >  {
> > > >  	icon_ = QIcon(":camera-off.svg");
> > > >  }
> > > > @@ -78,7 +78,8 @@ int ViewFinderQt::setFormat(const libcamera::PixelFormat &format,
> > > >  	return 0;
> > > >  }
> > > >  
> > > > -void ViewFinderQt::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)
> > > > +void ViewFinderQt::render(libcamera::Request *request,
> > > > +			  libcamera::FrameBuffer *buffer, MappedBuffer *map)
> > > >  {
> > > >  	if (buffer->planes().size() != 1) {
> > > >  		qWarning() << "Multi-planar buffers are not supported";
> > > > @@ -106,6 +107,7 @@ void ViewFinderQt::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)
> > > >  					size / size_.height(),
> > > >  					::nativeFormats[format_]);
> > > >  			std::swap(buffer, buffer_);
> > > > +			std::swap(request, request_);
> > > >  		} else {
> > > >  			/*
> > > >  			 * Otherwise, convert the format and release the frame
> > > > @@ -118,7 +120,7 @@ void ViewFinderQt::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)
> > > >  	update();
> > > >  
> > > >  	if (buffer)
> > > > -		renderComplete(buffer);
> > > > +		renderComplete(request, buffer);
> > > >  }
> > > >  
> > > >  void ViewFinderQt::stop()
> > > > @@ -126,7 +128,7 @@ void ViewFinderQt::stop()
> > > >  	image_ = QImage();
> > > >  
> > > >  	if (buffer_) {
> > > > -		renderComplete(buffer_);
> > > > +		renderComplete(request_, buffer_);
> > > >  		buffer_ = nullptr;
> > > >  	}
> > > >  
> > > > diff --git a/src/qcam/viewfinder_qt.h b/src/qcam/viewfinder_qt.h
> > > > index d7554288..5f62d7f6 100644
> > > > --- a/src/qcam/viewfinder_qt.h
> > > > +++ b/src/qcam/viewfinder_qt.h
> > > > @@ -17,6 +17,7 @@
> > > >  #include <libcamera/buffer.h>
> > > >  #include <libcamera/formats.h>
> > > >  #include <libcamera/pixel_format.h>
> > > > +#include <libcamera/request.h>
> > > >  
> > > >  #include "format_converter.h"
> > > >  #include "viewfinder.h"
> > > > @@ -32,13 +33,15 @@ public:
> > > >  	const QList<libcamera::PixelFormat> &nativeFormats() const override;
> > > >  
> > > >  	int setFormat(const libcamera::PixelFormat &format, const QSize &size) override;
> > > > -	void render(libcamera::FrameBuffer *buffer, MappedBuffer *map) override;
> > > > +	void render(libcamera::Request *request,
> > > > +		    libcamera::FrameBuffer *buffer,
> > > > +		    MappedBuffer *map) override;
> > > >  	void stop() override;
> > > >  
> > > >  	QImage getCurrentImage() override;
> > > >  
> > > >  Q_SIGNALS:
> > > > -	void renderComplete(libcamera::FrameBuffer *buffer);
> > > > +	void renderComplete(libcamera::Request *request, libcamera::FrameBuffer *buffer);
> > > >  
> > > >  protected:
> > > >  	void paintEvent(QPaintEvent *) override;
> > > > @@ -56,6 +59,7 @@ private:
> > > >  	QPixmap pixmap_;
> > > >  
> > > >  	/* Buffer and render image */
> > > > +	libcamera::Request *request_;
> > > >  	libcamera::FrameBuffer *buffer_;
> > > >  	QImage image_;
> > > >  	QMutex mutex_; /* Prevent concurrent access to image_ */

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list