{"id":9745,"url":"https://patchwork.libcamera.org/api/1.1/patches/9745/?format=json","web_url":"https://patchwork.libcamera.org/patch/9745/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20200923121448.281346-1-paul.elder@ideasonboard.com>","date":"2020-09-23T12:14:48","name":"[libcamera-devel,RFC] libcamera, cam, qcam: Reuse Request","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"2f307573a23ef151585d7ea561463cde33bdd265","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/1.1/people/17/?format=json","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/9745/mbox/","series":[{"id":1311,"url":"https://patchwork.libcamera.org/api/1.1/series/1311/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=1311","date":"2020-09-23T12:14:48","name":"[libcamera-devel,RFC] libcamera, cam, qcam: Reuse Request","version":1,"mbox":"https://patchwork.libcamera.org/series/1311/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/9745/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/9745/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 89E80C3B5B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 23 Sep 2020 12:15:07 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 197F162FE3;\n\tWed, 23 Sep 2020 14:15:07 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 098D160576\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 23 Sep 2020 14:15:06 +0200 (CEST)","from pyrite.rasen.tech (unknown\n\t[IPv6:2400:4051:61:600:2c71:1b79:d06d:5032])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 6CB582FD;\n\tWed, 23 Sep 2020 14:15:02 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"Sr1kcb2L\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1600863303;\n\tbh=XTjRIo3j1jveIN4lO+aSEXShPqPi4gnfRziJDeOF0oE=;\n\th=From:To:Cc:Subject:Date:From;\n\tb=Sr1kcb2Lz6k2Nbc4iGrNIYmV8dI35zvg+zWjJeU2COzVks9O6Gc2Y8k3Ki1V3i72/\n\tPpw7UP65rDVq1TqfEtuHgjhPbQH68e1kk9ag13cF5zY6V/qs9WO3QXu9ivjOEP29n5\n\tuo3Zgp9/M2im/WYf7H33kkYIKhtPzhVoK0k4MjiQ=","From":"Paul Elder <paul.elder@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Date":"Wed, 23 Sep 2020 21:14:48 +0900","Message-Id":"<20200923121448.281346-1-paul.elder@ideasonboard.com>","X-Mailer":"git-send-email 2.27.0","MIME-Version":"1.0","Subject":"[libcamera-devel] [RFC PATCH] libcamera, cam, qcam: Reuse Request","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"Allow reuse of the Request object by implementing a reset() function.\nThis means that the applications now have the responsibility of freeing\nthe the Request objects, so make cam and qcam do so.\n\nSigned-off-by: Paul Elder <paul.elder@ideasonboard.com>\n\n---\nIn this RFC, I've only made qcam and cam reuse the Request object. Just\ngauging the direction, and then I'll put it in for andoird and gstreamer\nand v4l2-compat as well.\n---\n include/libcamera/request.h |  2 ++\n src/cam/capture.cpp         | 20 ++++++++++----------\n src/cam/capture.h           |  3 +++\n src/libcamera/camera.cpp    |  4 +---\n src/libcamera/request.cpp   |  9 +++++++++\n src/qcam/main_window.cpp    | 26 ++++++++++++--------------\n src/qcam/main_window.h      | 14 ++++++++++----\n src/qcam/viewfinder.h       |  4 +++-\n src/qcam/viewfinder_gl.cpp  |  9 +++++----\n src/qcam/viewfinder_gl.h    |  5 +++--\n src/qcam/viewfinder_qt.cpp  | 10 ++++++----\n src/qcam/viewfinder_qt.h    |  8 ++++++--\n 12 files changed, 70 insertions(+), 44 deletions(-)","diff":"diff --git a/include/libcamera/request.h b/include/libcamera/request.h\nindex 5976ac50..9f615a24 100644\n--- a/include/libcamera/request.h\n+++ b/include/libcamera/request.h\n@@ -38,6 +38,8 @@ public:\n \tRequest &operator=(const Request &) = delete;\n \t~Request();\n \n+\tvoid reset();\n+\n \tControlList &controls() { return *controls_; }\n \tControlList &metadata() { return *metadata_; }\n \tconst BufferMap &buffers() const { return bufferMap_; }\ndiff --git a/src/cam/capture.cpp b/src/cam/capture.cpp\nindex 5510c009..fe9d591a 100644\n--- a/src/cam/capture.cpp\n+++ b/src/cam/capture.cpp\n@@ -65,6 +65,9 @@ int Capture::run(const OptionsParser::Options &options)\n \t\twriter_ = nullptr;\n \t}\n \n+\tfor (Request *req : requests_)\n+\t\tdelete req;\n+\n \tdelete allocator;\n \n \treturn ret;\n@@ -92,7 +95,6 @@ int Capture::capture(FrameBufferAllocator *allocator)\n \t * example pushing a button. For now run all streams all the time.\n \t */\n \n-\tstd::vector<Request *> requests;\n \tfor (unsigned int i = 0; i < nbuffers; i++) {\n \t\tRequest *request = camera_->createRequest();\n \t\tif (!request) {\n@@ -117,7 +119,7 @@ int Capture::capture(FrameBufferAllocator *allocator)\n \t\t\t\twriter_->mapBuffer(buffer.get());\n \t\t}\n \n-\t\trequests.push_back(request);\n+\t\trequests_.push_back(request);\n \t}\n \n \tret = camera_->start();\n@@ -126,7 +128,7 @@ int Capture::capture(FrameBufferAllocator *allocator)\n \t\treturn ret;\n \t}\n \n-\tfor (Request *request : requests) {\n+\tfor (Request *request : requests_) {\n \t\tret = camera_->queueRequest(request);\n \t\tif (ret < 0) {\n \t\t\tstd::cerr << \"Can't queue request\" << std::endl;\n@@ -153,10 +155,12 @@ int Capture::capture(FrameBufferAllocator *allocator)\n \n void Capture::requestComplete(Request *request)\n {\n-\tif (request->status() == Request::RequestCancelled)\n+\tif (request->status() == Request::RequestCancelled) {\n+\t\trequest->reset();\n \t\treturn;\n+\t}\n \n-\tconst Request::BufferMap &buffers = request->buffers();\n+\tconst Request::BufferMap buffers = request->buffers();\n \n \t/*\n \t * Compute the frame rate. The timestamp is arbitrarily retrieved from\n@@ -206,11 +210,7 @@ void Capture::requestComplete(Request *request)\n \t * Create a new request and populate it with one buffer for each\n \t * stream.\n \t */\n-\trequest = camera_->createRequest();\n-\tif (!request) {\n-\t\tstd::cerr << \"Can't create request\" << std::endl;\n-\t\treturn;\n-\t}\n+\trequest->reset();\n \n \tfor (auto it = buffers.begin(); it != buffers.end(); ++it) {\n \t\tconst Stream *stream = it->first;\ndiff --git a/src/cam/capture.h b/src/cam/capture.h\nindex 0aebdac9..62cf9bf1 100644\n--- a/src/cam/capture.h\n+++ b/src/cam/capture.h\n@@ -9,6 +9,7 @@\n \n #include <memory>\n #include <stdint.h>\n+#include <vector>\n \n #include <libcamera/buffer.h>\n #include <libcamera/camera.h>\n@@ -43,6 +44,8 @@ private:\n \tEventLoop *loop_;\n \tunsigned int captureCount_;\n \tunsigned int captureLimit_;\n+\n+\tstd::vector<libcamera::Request *> requests_;\n };\n \n #endif /* __CAM_CAPTURE_H__ */\ndiff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp\nindex ae16a64a..4cc68bce 100644\n--- a/src/libcamera/camera.cpp\n+++ b/src/libcamera/camera.cpp\n@@ -974,13 +974,11 @@ int Camera::stop()\n  * \\param[in] request The request that has completed\n  *\n  * This function is called by the pipeline handler to notify the camera that\n- * the request has completed. It emits the requestCompleted signal and deletes\n- * the request.\n+ * the request has completed. It emits the requestCompleted signal.\n  */\n void Camera::requestComplete(Request *request)\n {\n \trequestCompleted.emit(request);\n-\tdelete request;\n }\n \n } /* namespace libcamera */\ndiff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp\nindex 60b30692..606866a6 100644\n--- a/src/libcamera/request.cpp\n+++ b/src/libcamera/request.cpp\n@@ -85,6 +85,15 @@ Request::~Request()\n \tdelete validator_;\n }\n \n+void Request::reset()\n+{\n+\tbufferMap_.clear();\n+\tpending_.clear();\n+\n+\tstatus_ = RequestPending;\n+\tcancelled_ = false;\n+}\n+\n /**\n  * \\fn Request::controls()\n  * \\brief Retrieve the request's ControlList\ndiff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp\nindex 985743f3..1531b44f 100644\n--- a/src/qcam/main_window.cpp\n+++ b/src/qcam/main_window.cpp\n@@ -367,7 +367,6 @@ void MainWindow::toggleCapture(bool start)\n int MainWindow::startCapture()\n {\n \tStreamRoles roles = StreamKeyValueParser::roles(options_[OptStream]);\n-\tstd::vector<Request *> requests;\n \tint ret;\n \n \t/* Verify roles are supported. */\n@@ -499,7 +498,7 @@ int MainWindow::startCapture()\n \t\t\tgoto error;\n \t\t}\n \n-\t\trequests.push_back(request);\n+\t\trequests_.push_back(request);\n \t}\n \n \t/* Start the title timer and the camera. */\n@@ -518,7 +517,7 @@ int MainWindow::startCapture()\n \tcamera_->requestCompleted.connect(this, &MainWindow::requestComplete);\n \n \t/* Queue all requests. */\n-\tfor (Request *request : requests) {\n+\tfor (Request *request : requests_) {\n \t\tret = camera_->queueRequest(request);\n \t\tif (ret < 0) {\n \t\t\tqWarning() << \"Can't queue request\";\n@@ -535,7 +534,7 @@ error_disconnect:\n \tcamera_->stop();\n \n error:\n-\tfor (Request *request : requests)\n+\tfor (Request *request : requests_)\n \t\tdelete request;\n \n \tfor (auto &iter : mappedBuffers_) {\n@@ -580,6 +579,9 @@ void MainWindow::stopCapture()\n \t}\n \tmappedBuffers_.clear();\n \n+\tfor (Request *req : requests_)\n+\t\tdelete req;\n+\n \tdelete allocator_;\n \n \tisCapturing_ = false;\n@@ -701,7 +703,7 @@ void MainWindow::requestComplete(Request *request)\n \t */\n \t{\n \t\tQMutexLocker locker(&mutex_);\n-\t\tdoneQueue_.enqueue({ request->buffers(), request->metadata() });\n+\t\tdoneQueue_.enqueue({ request->buffers(), request->metadata(), request });\n \t}\n \n \tQCoreApplication::postEvent(this, new CaptureEvent);\n@@ -726,13 +728,13 @@ void MainWindow::processCapture()\n \n \t/* Process buffers. */\n \tif (request.buffers_.count(vfStream_))\n-\t\tprocessViewfinder(request.buffers_[vfStream_]);\n+\t\tprocessViewfinder(request.request_, request.buffers_[vfStream_]);\n \n \tif (request.buffers_.count(rawStream_))\n \t\tprocessRaw(request.buffers_[rawStream_], request.metadata_);\n }\n \n-void MainWindow::processViewfinder(FrameBuffer *buffer)\n+void MainWindow::processViewfinder(Request *request, FrameBuffer *buffer)\n {\n \tframesCaptured_++;\n \n@@ -749,16 +751,12 @@ void MainWindow::processViewfinder(FrameBuffer *buffer)\n \t\t<< \"fps:\" << Qt::fixed << qSetRealNumberPrecision(2) << fps;\n \n \t/* Render the frame on the viewfinder. */\n-\tviewfinder_->render(buffer, &mappedBuffers_[buffer]);\n+\tviewfinder_->render(request, buffer, &mappedBuffers_[buffer]);\n }\n \n-void MainWindow::queueRequest(FrameBuffer *buffer)\n+void MainWindow::queueRequest(Request *request, FrameBuffer *buffer)\n {\n-\tRequest *request = camera_->createRequest();\n-\tif (!request) {\n-\t\tqWarning() << \"Can't create request\";\n-\t\treturn;\n-\t}\n+\trequest->reset();\n \n \trequest->addBuffer(vfStream_, buffer);\n \ndiff --git a/src/qcam/main_window.h b/src/qcam/main_window.h\nindex 5c61a4df..83535373 100644\n--- a/src/qcam/main_window.h\n+++ b/src/qcam/main_window.h\n@@ -8,6 +8,7 @@\n #define __QCAM_MAIN_WINDOW_H__\n \n #include <memory>\n+#include <vector>\n \n #include <QElapsedTimer>\n #include <QIcon>\n@@ -22,6 +23,7 @@\n #include <libcamera/camera_manager.h>\n #include <libcamera/controls.h>\n #include <libcamera/framebuffer_allocator.h>\n+#include <libcamera/request.h>\n #include <libcamera/stream.h>\n \n #include \"../cam/stream_options.h\"\n@@ -49,13 +51,15 @@ public:\n \t}\n \n \tCaptureRequest(const Request::BufferMap &buffers,\n-\t\t       const ControlList &metadata)\n-\t\t: buffers_(buffers), metadata_(metadata)\n+\t\t       const ControlList &metadata,\n+\t\t       Request * const request)\n+\t\t: buffers_(buffers), metadata_(metadata), request_(request)\n \t{\n \t}\n \n \tRequest::BufferMap buffers_;\n \tControlList metadata_;\n+\tRequest *request_;\n };\n \n class MainWindow : public QMainWindow\n@@ -79,7 +83,7 @@ private Q_SLOTS:\n \tvoid captureRaw();\n \tvoid processRaw(FrameBuffer *buffer, const ControlList &metadata);\n \n-\tvoid queueRequest(FrameBuffer *buffer);\n+\tvoid queueRequest(Request *request, FrameBuffer *buffer);\n \n private:\n \tint createToolbars();\n@@ -96,7 +100,7 @@ private:\n \tvoid requestComplete(Request *request);\n \tvoid processCapture();\n \tvoid processHotplug(HotplugEvent *e);\n-\tvoid processViewfinder(FrameBuffer *buffer);\n+\tvoid processViewfinder(Request *request, FrameBuffer *buffer);\n \n \t/* UI elements */\n \tQToolBar *toolbar_;\n@@ -135,6 +139,8 @@ private:\n \tQElapsedTimer frameRateInterval_;\n \tuint32_t previousFrames_;\n \tuint32_t framesCaptured_;\n+\n+\tstd::vector<Request *> requests_;\n };\n \n #endif /* __QCAM_MAIN_WINDOW__ */\ndiff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h\nindex 67da1df2..26c20f1b 100644\n--- a/src/qcam/viewfinder.h\n+++ b/src/qcam/viewfinder.h\n@@ -27,7 +27,9 @@ public:\n \tvirtual const QList<libcamera::PixelFormat> &nativeFormats() const = 0;\n \n \tvirtual int setFormat(const libcamera::PixelFormat &format, const QSize &size) = 0;\n-\tvirtual void render(libcamera::FrameBuffer *buffer, MappedBuffer *map) = 0;\n+\tvirtual void render(libcamera::Request *request,\n+\t\t\t    libcamera::FrameBuffer *buffer,\n+\t\t\t    MappedBuffer *map) = 0;\n \tvirtual void stop() = 0;\n \n \tvirtual QImage getCurrentImage() = 0;\ndiff --git a/src/qcam/viewfinder_gl.cpp b/src/qcam/viewfinder_gl.cpp\nindex fbe21dcf..c65b41f6 100644\n--- a/src/qcam/viewfinder_gl.cpp\n+++ b/src/qcam/viewfinder_gl.cpp\n@@ -23,7 +23,7 @@ static const QList<libcamera::PixelFormat> supportedFormats{\n };\n \n ViewFinderGL::ViewFinderGL(QWidget *parent)\n-\t: QOpenGLWidget(parent), buffer_(nullptr), yuvData_(nullptr),\n+\t: QOpenGLWidget(parent), request_(nullptr), buffer_(nullptr), yuvData_(nullptr),\n \t  fragmentShader_(nullptr), vertexShader_(nullptr),\n \t  vertexBuffer_(QOpenGLBuffer::VertexBuffer),\n \t  textureU_(QOpenGLTexture::Target2D),\n@@ -67,7 +67,7 @@ int ViewFinderGL::setFormat(const libcamera::PixelFormat &format,\n void ViewFinderGL::stop()\n {\n \tif (buffer_) {\n-\t\trenderComplete(buffer_);\n+\t\trenderComplete(request_, buffer_);\n \t\tbuffer_ = nullptr;\n \t}\n }\n@@ -79,7 +79,7 @@ QImage ViewFinderGL::getCurrentImage()\n \treturn grabFramebuffer();\n }\n \n-void ViewFinderGL::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)\n+void ViewFinderGL::render(libcamera::Request *request, libcamera::FrameBuffer *buffer, MappedBuffer *map)\n {\n \tif (buffer->planes().size() != 1) {\n \t\tqWarning() << \"Multi-planar buffers are not supported\";\n@@ -87,11 +87,12 @@ void ViewFinderGL::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)\n \t}\n \n \tif (buffer_)\n-\t\trenderComplete(buffer_);\n+\t\trenderComplete(request_, buffer_);\n \n \tyuvData_ = static_cast<unsigned char *>(map->memory);\n \tupdate();\n \tbuffer_ = buffer;\n+\trequest_ = request;\n }\n \n bool ViewFinderGL::selectFormat(const libcamera::PixelFormat &format)\ndiff --git a/src/qcam/viewfinder_gl.h b/src/qcam/viewfinder_gl.h\nindex 69502b7a..7db41841 100644\n--- a/src/qcam/viewfinder_gl.h\n+++ b/src/qcam/viewfinder_gl.h\n@@ -36,13 +36,13 @@ public:\n \tconst QList<libcamera::PixelFormat> &nativeFormats() const override;\n \n \tint setFormat(const libcamera::PixelFormat &format, const QSize &size) override;\n-\tvoid render(libcamera::FrameBuffer *buffer, MappedBuffer *map) override;\n+\tvoid render(libcamera::Request *request, libcamera::FrameBuffer *buffer, MappedBuffer *map) override;\n \tvoid stop() override;\n \n \tQImage getCurrentImage() override;\n \n Q_SIGNALS:\n-\tvoid renderComplete(libcamera::FrameBuffer *buffer);\n+\tvoid renderComplete(libcamera::Request *request, libcamera::FrameBuffer *buffer);\n \n protected:\n \tvoid initializeGL() override;\n@@ -60,6 +60,7 @@ private:\n \tvoid doRender();\n \n \t/* Captured image size, format and buffer */\n+\tlibcamera::Request *request_;\n \tlibcamera::FrameBuffer *buffer_;\n \tlibcamera::PixelFormat format_;\n \tQSize size_;\ndiff --git a/src/qcam/viewfinder_qt.cpp b/src/qcam/viewfinder_qt.cpp\nindex e436714c..7f9f913b 100644\n--- a/src/qcam/viewfinder_qt.cpp\n+++ b/src/qcam/viewfinder_qt.cpp\n@@ -34,7 +34,7 @@ static const QMap<libcamera::PixelFormat, QImage::Format> nativeFormats\n };\n \n ViewFinderQt::ViewFinderQt(QWidget *parent)\n-\t: QWidget(parent), buffer_(nullptr)\n+\t: QWidget(parent), request_(nullptr), buffer_(nullptr)\n {\n \ticon_ = QIcon(\":camera-off.svg\");\n }\n@@ -78,7 +78,8 @@ int ViewFinderQt::setFormat(const libcamera::PixelFormat &format,\n \treturn 0;\n }\n \n-void ViewFinderQt::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)\n+void ViewFinderQt::render(libcamera::Request *request,\n+\t\t\t  libcamera::FrameBuffer *buffer, MappedBuffer *map)\n {\n \tif (buffer->planes().size() != 1) {\n \t\tqWarning() << \"Multi-planar buffers are not supported\";\n@@ -106,6 +107,7 @@ void ViewFinderQt::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)\n \t\t\t\t\tsize / size_.height(),\n \t\t\t\t\t::nativeFormats[format_]);\n \t\t\tstd::swap(buffer, buffer_);\n+\t\t\tstd::swap(request, request_);\n \t\t} else {\n \t\t\t/*\n \t\t\t * Otherwise, convert the format and release the frame\n@@ -118,7 +120,7 @@ void ViewFinderQt::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)\n \tupdate();\n \n \tif (buffer)\n-\t\trenderComplete(buffer);\n+\t\trenderComplete(request, buffer);\n }\n \n void ViewFinderQt::stop()\n@@ -126,7 +128,7 @@ void ViewFinderQt::stop()\n \timage_ = QImage();\n \n \tif (buffer_) {\n-\t\trenderComplete(buffer_);\n+\t\trenderComplete(request_, buffer_);\n \t\tbuffer_ = nullptr;\n \t}\n \ndiff --git a/src/qcam/viewfinder_qt.h b/src/qcam/viewfinder_qt.h\nindex d7554288..5f62d7f6 100644\n--- a/src/qcam/viewfinder_qt.h\n+++ b/src/qcam/viewfinder_qt.h\n@@ -17,6 +17,7 @@\n #include <libcamera/buffer.h>\n #include <libcamera/formats.h>\n #include <libcamera/pixel_format.h>\n+#include <libcamera/request.h>\n \n #include \"format_converter.h\"\n #include \"viewfinder.h\"\n@@ -32,13 +33,15 @@ public:\n \tconst QList<libcamera::PixelFormat> &nativeFormats() const override;\n \n \tint setFormat(const libcamera::PixelFormat &format, const QSize &size) override;\n-\tvoid render(libcamera::FrameBuffer *buffer, MappedBuffer *map) override;\n+\tvoid render(libcamera::Request *request,\n+\t\t    libcamera::FrameBuffer *buffer,\n+\t\t    MappedBuffer *map) override;\n \tvoid stop() override;\n \n \tQImage getCurrentImage() override;\n \n Q_SIGNALS:\n-\tvoid renderComplete(libcamera::FrameBuffer *buffer);\n+\tvoid renderComplete(libcamera::Request *request, libcamera::FrameBuffer *buffer);\n \n protected:\n \tvoid paintEvent(QPaintEvent *) override;\n@@ -56,6 +59,7 @@ private:\n \tQPixmap pixmap_;\n \n \t/* Buffer and render image */\n+\tlibcamera::Request *request_;\n \tlibcamera::FrameBuffer *buffer_;\n \tQImage image_;\n \tQMutex mutex_; /* Prevent concurrent access to image_ */\n","prefixes":["libcamera-devel","RFC"]}