Patch Detail
Show a patch.
GET /api/patches/9854/?format=api
{ "id": 9854, "url": "https://patchwork.libcamera.org/api/patches/9854/?format=api", "web_url": "https://patchwork.libcamera.org/patch/9854/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20200929095200.396199-1-paul.elder@ideasonboard.com>", "date": "2020-09-29T09:52:00", "name": "[libcamera-devel,v2] libcamera, android, cam, gstreamer, qcam, v4l2: Reuse Request", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "2608d3163e4412d782f781e118cd2e4c105fc6f8", "submitter": { "id": 17, "url": "https://patchwork.libcamera.org/api/people/17/?format=api", "name": "Paul Elder", "email": "paul.elder@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/9854/mbox/", "series": [ { "id": 1335, "url": "https://patchwork.libcamera.org/api/series/1335/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1335", "date": "2020-09-29T09:52:00", "name": "[libcamera-devel,v2] libcamera, android, cam, gstreamer, qcam, v4l2: Reuse Request", "version": 2, "mbox": "https://patchwork.libcamera.org/series/1335/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/9854/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/9854/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 E8F26C3B5C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 29 Sep 2020 09:52:16 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4B11A60BD4;\n\tTue, 29 Sep 2020 11:52:16 +0200 (CEST)", "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A0B0160576\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 29 Sep 2020 11:52:15 +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 45277540;\n\tTue, 29 Sep 2020 11:52:11 +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=\"phkV0/le\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1601373135;\n\tbh=b1c+KkoMiU0AcrtjhmbnaiKk2pKBnGyrBYaPoED1hW0=;\n\th=From:To:Cc:Subject:Date:From;\n\tb=phkV0/leCLD171jZxPFJPr6BLbL1IU6vkmGoe8nyPCBeeCT/hDmCrSvD6Y3OkNU5s\n\tU+OL7YsMyTsQ4annxi4BaOIGUNr1k6XPqSpuYtQ6oKzyBz0JdUS6OON5CTN2U/oI1n\n\tYDJZcTuG/fP0gle162uB5nncorucnJx0uzntHxCg=", "From": "Paul Elder <paul.elder@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Date": "Tue, 29 Sep 2020 18:52:00 +0900", "Message-Id": "<20200929095200.396199-1-paul.elder@ideasonboard.com>", "X-Mailer": "git-send-email 2.27.0", "MIME-Version": "1.0", "Subject": "[libcamera-devel] [PATCH v2] libcamera, android, cam, gstreamer,\n\tqcam, v4l2: 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 Request objects, so make all libcamera users (cam, qcam,\nv4l2-compat, gstreamer, android) do so.\n\nSigned-off-by: Paul Elder <paul.elder@ideasonboard.com>\n\n---\nChanges in v2:\n- clear controls_ and metadata_ and validator_ in Request::reset()\n- use unique_ptr on application side, prior to queueRequest, and use\n regular pointer for completion handler\n- make qcam's reuse request nicer\n- update Camera::queueRequest() and Camera::createRequest() documentation\n- add documentation for Request::reset()\n- make v4l2-compat reuse request\n- make gstreamer and android use the new createRequest API, though they\n do not actually reuse the requests\n - I haven't yet tested android\n---\n include/libcamera/camera.h | 2 +-\n include/libcamera/request.h | 2 ++\n src/android/camera_device.cpp | 8 +++++-\n src/cam/capture.cpp | 19 ++++++------\n src/cam/capture.h | 3 ++\n src/gstreamer/gstlibcamerasrc.cpp | 6 ++--\n src/libcamera/camera.cpp | 15 ++++------\n src/libcamera/request.cpp | 24 ++++++++++++++++\n src/qcam/main_window.cpp | 48 +++++++++++++++++++------------\n src/qcam/main_window.h | 26 +++++------------\n src/v4l2/v4l2_camera.cpp | 38 +++++++++++++++++-------\n src/v4l2/v4l2_camera.h | 4 ++-\n test/camera/buffer_import.cpp | 15 +++++-----\n test/camera/capture.cpp | 15 +++++-----\n test/camera/statemachine.cpp | 9 ++----\n 15 files changed, 141 insertions(+), 93 deletions(-)", "diff": "diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h\nindex 272c12c3..e4036b63 100644\n--- a/include/libcamera/camera.h\n+++ b/include/libcamera/camera.h\n@@ -93,7 +93,7 @@ public:\n \tstd::unique_ptr<CameraConfiguration> generateConfiguration(const StreamRoles &roles = {});\n \tint configure(CameraConfiguration *config);\n \n-\tRequest *createRequest(uint64_t cookie = 0);\n+\tstd::unique_ptr<Request> createRequest(uint64_t cookie = 0);\n \tint queueRequest(Request *request);\n \n \tint start();\ndiff --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/android/camera_device.cpp b/src/android/camera_device.cpp\nindex 70d77a17..7f288617 100644\n--- a/src/android/camera_device.cpp\n+++ b/src/android/camera_device.cpp\n@@ -1395,8 +1395,13 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n \t\tnew Camera3RequestDescriptor(camera3Request->frame_number,\n \t\t\t\t\t camera3Request->num_output_buffers);\n \n-\tRequest *request =\n+\tstd::unique_ptr<Request> r =\n \t\tcamera_->createRequest(reinterpret_cast<uint64_t>(descriptor));\n+\tRequest *request = r.release();\n+\tif (!request) {\n+\t\tLOG(HAL, Error) << \"Failed to create request\";\n+\t\treturn -ENOMEM;\n+\t}\n \n \tfor (unsigned int i = 0; i < descriptor->numBuffers; ++i) {\n \t\tCameraStream *cameraStream =\n@@ -1593,6 +1598,7 @@ void CameraDevice::requestComplete(Request *request)\n \tcallbacks_->process_capture_result(callbacks_, &captureResult);\n \n \tdelete descriptor;\n+\tdelete request;\n }\n \n std::string CameraDevice::logPrefix() const\ndiff --git a/src/cam/capture.cpp b/src/cam/capture.cpp\nindex 5510c009..5b9238e2 100644\n--- a/src/cam/capture.cpp\n+++ b/src/cam/capture.cpp\n@@ -65,6 +65,8 @@ int Capture::run(const OptionsParser::Options &options)\n \t\twriter_ = nullptr;\n \t}\n \n+\trequests_.clear();\n+\n \tdelete allocator;\n \n \treturn ret;\n@@ -92,9 +94,8 @@ 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\tstd::unique_ptr<Request> request = camera_->createRequest();\n \t\tif (!request) {\n \t\t\tstd::cerr << \"Can't create request\" << std::endl;\n \t\t\treturn -ENOMEM;\n@@ -117,7 +118,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(std::move(request));\n \t}\n \n \tret = camera_->start();\n@@ -126,8 +127,8 @@ int Capture::capture(FrameBufferAllocator *allocator)\n \t\treturn ret;\n \t}\n \n-\tfor (Request *request : requests) {\n-\t\tret = camera_->queueRequest(request);\n+\tfor (std::unique_ptr<Request> &request : requests_) {\n+\t\tret = camera_->queueRequest(request.get());\n \t\tif (ret < 0) {\n \t\t\tstd::cerr << \"Can't queue request\" << std::endl;\n \t\t\tcamera_->stop();\n@@ -156,7 +157,7 @@ void Capture::requestComplete(Request *request)\n \tif (request->status() == Request::RequestCancelled)\n \t\treturn;\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 +207,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..45e5e8a9 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<std::unique_ptr<libcamera::Request>> requests_;\n };\n \n #endif /* __CAM_CAPTURE_H__ */\ndiff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\nindex 1bfc2e2f..ca223df6 100644\n--- a/src/gstreamer/gstlibcamerasrc.cpp\n+++ b/src/gstreamer/gstlibcamerasrc.cpp\n@@ -74,6 +74,8 @@ RequestWrap::~RequestWrap()\n \t\tif (item.second)\n \t\t\tgst_buffer_unref(item.second);\n \t}\n+\n+\tdelete request_;\n }\n \n void RequestWrap::attachBuffer(GstBuffer *buffer)\n@@ -266,7 +268,8 @@ gst_libcamera_src_task_run(gpointer user_data)\n \tGstLibcameraSrc *self = GST_LIBCAMERA_SRC(user_data);\n \tGstLibcameraSrcState *state = self->state;\n \n-\tRequest *request = state->cam_->createRequest();\n+\tstd::unique_ptr<Request> request_unique = state->cam_->createRequest();\n+\tRequest *request = request_unique.release();\n \tauto wrap = std::make_unique<RequestWrap>(request);\n \tfor (GstPad *srcpad : state->srcpads_) {\n \t\tGstLibcameraPool *pool = gst_libcamera_pad_get_pool(srcpad);\n@@ -281,7 +284,6 @@ gst_libcamera_src_task_run(gpointer user_data)\n \t\t\t * queueing this one due to lack of buffers.\n \t\t\t */\n \t\t\tdelete request;\n-\t\t\trequest = nullptr;\n \t\t\tbreak;\n \t\t}\n \ndiff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp\nindex ae16a64a..8c2bbc76 100644\n--- a/src/libcamera/camera.cpp\n+++ b/src/libcamera/camera.cpp\n@@ -833,21 +833,23 @@ int Camera::configure(CameraConfiguration *config)\n * handler, and is completely opaque to libcamera.\n *\n * The ownership of the returned request is passed to the caller, which is\n- * responsible for either queueing the request or deleting it.\n+ * responsible for either queueing the request or deleting it. The caller\n+ * continues to own the request after queueing it, so deleting the request\n+ * is the responsibility of the application after the request completes.\n *\n * \\context This function is \\threadsafe. It may only be called when the camera\n * is in the Configured or Running state as defined in \\ref camera_operation.\n *\n * \\return A pointer to the newly created request, or nullptr on error\n */\n-Request *Camera::createRequest(uint64_t cookie)\n+std::unique_ptr<Request> Camera::createRequest(uint64_t cookie)\n {\n \tint ret = p_->isAccessAllowed(Private::CameraConfigured,\n \t\t\t\t Private::CameraRunning);\n \tif (ret < 0)\n \t\treturn nullptr;\n \n-\treturn new Request(this, cookie);\n+\treturn std::make_unique<Request>(this, cookie);\n }\n \n /**\n@@ -863,9 +865,6 @@ Request *Camera::createRequest(uint64_t cookie)\n * Once the request has been queued, the camera will notify its completion\n * through the \\ref requestCompleted signal.\n *\n- * Ownership of the request is transferred to the camera. It will be deleted\n- * automatically after it completes.\n- *\n * \\context This function is \\threadsafe. It may only be called when the camera\n * is in the Running state as defined in \\ref camera_operation.\n *\n@@ -974,13 +973,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..dd3040fe 100644\n--- a/src/libcamera/request.cpp\n+++ b/src/libcamera/request.cpp\n@@ -85,6 +85,30 @@ Request::~Request()\n \tdelete validator_;\n }\n \n+/*\n+ * \\brief Reset the request\n+ *\n+ * Reset the request, to allow it to be reused and requeued without\n+ * destruction. All contents of the request will be reset, so any references\n+ * previously returned by the request will become invalid.\n+ */\n+void Request::reset()\n+{\n+\tbufferMap_.clear();\n+\tpending_.clear();\n+\n+\tstatus_ = RequestPending;\n+\tcancelled_ = false;\n+\n+\tdelete metadata_;\n+\tdelete controls_;\n+\tdelete validator_;\n+\n+\tvalidator_ = new CameraControlValidator(camera_);\n+\tcontrols_ = new ControlList(controls::controls, validator_);\n+\tmetadata_ = new ControlList(controls::controls);\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..c2f8b175 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@@ -486,7 +485,7 @@ int MainWindow::startCapture()\n \twhile (!freeBuffers_[vfStream_].isEmpty()) {\n \t\tFrameBuffer *buffer = freeBuffers_[vfStream_].dequeue();\n \n-\t\tRequest *request = camera_->createRequest();\n+\t\tstd::unique_ptr<Request> request = camera_->createRequest();\n \t\tif (!request) {\n \t\t\tqWarning() << \"Can't create request\";\n \t\t\tret = -ENOMEM;\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(std::move(request));\n \t}\n \n \t/* Start the title timer and the camera. */\n@@ -518,8 +517,8 @@ int MainWindow::startCapture()\n \tcamera_->requestCompleted.connect(this, &MainWindow::requestComplete);\n \n \t/* Queue all requests. */\n-\tfor (Request *request : requests) {\n-\t\tret = camera_->queueRequest(request);\n+\tfor (std::unique_ptr<Request> &request : requests_) {\n+\t\tret = camera_->queueRequest(request.get());\n \t\tif (ret < 0) {\n \t\t\tqWarning() << \"Can't queue request\";\n \t\t\tgoto error_disconnect;\n@@ -535,8 +534,7 @@ error_disconnect:\n \tcamera_->stop();\n \n error:\n-\tfor (Request *request : requests)\n-\t\tdelete request;\n+\trequests_.clear();\n \n \tfor (auto &iter : mappedBuffers_) {\n \t\tconst MappedBuffer &buffer = iter.second;\n@@ -580,6 +578,8 @@ void MainWindow::stopCapture()\n \t}\n \tmappedBuffers_.clear();\n \n+\trequests_.clear();\n+\n \tdelete allocator_;\n \n \tisCapturing_ = false;\n@@ -701,7 +701,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);\n \t}\n \n \tQCoreApplication::postEvent(this, new CaptureEvent);\n@@ -714,8 +714,7 @@ void MainWindow::processCapture()\n \t * if stopCapture() has been called while a CaptureEvent was posted but\n \t * not processed yet. Return immediately in that case.\n \t */\n-\tCaptureRequest request;\n-\n+\tRequest *request;\n \t{\n \t\tQMutexLocker locker(&mutex_);\n \t\tif (doneQueue_.isEmpty())\n@@ -725,11 +724,19 @@ void MainWindow::processCapture()\n \t}\n \n \t/* Process buffers. */\n-\tif (request.buffers_.count(vfStream_))\n-\t\tprocessViewfinder(request.buffers_[vfStream_]);\n+\tif (request->buffers().count(vfStream_)) {\n+\t\t{\n+\t\t\tQMutexLocker locker(&mutex_);\n+\t\t\tfreeQueue_.enqueue(request);\n+\t\t}\n+\t\tRequest::BufferMap buffers = request->buffers();\n+\t\tprocessViewfinder(buffers[vfStream_]);\n+\t}\n \n-\tif (request.buffers_.count(rawStream_))\n-\t\tprocessRaw(request.buffers_[rawStream_], request.metadata_);\n+\tif (request->buffers().count(rawStream_)) {\n+\t\tRequest::BufferMap buffers = request->buffers();\n+\t\tprocessRaw(buffers[rawStream_], request->metadata());\n+\t}\n }\n \n void MainWindow::processViewfinder(FrameBuffer *buffer)\n@@ -754,12 +761,17 @@ void MainWindow::processViewfinder(FrameBuffer *buffer)\n \n void MainWindow::queueRequest(FrameBuffer *buffer)\n {\n-\tRequest *request = camera_->createRequest();\n-\tif (!request) {\n-\t\tqWarning() << \"Can't create request\";\n-\t\treturn;\n+\tRequest *request;\n+\t{\n+\t\tQMutexLocker locker(&mutex_);\n+\t\tif (freeQueue_.isEmpty())\n+\t\t\treturn;\n+\n+\t\trequest = freeQueue_.dequeue();\n \t}\n \n+\trequest->reset();\n+\n \trequest->addBuffer(vfStream_, buffer);\n \n \tif (captureRaw_) {\ndiff --git a/src/qcam/main_window.h b/src/qcam/main_window.h\nindex 5c61a4df..64bcfebc 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@@ -41,23 +43,6 @@ enum {\n \tOptStream = 's',\n };\n \n-class CaptureRequest\n-{\n-public:\n-\tCaptureRequest()\n-\t{\n-\t}\n-\n-\tCaptureRequest(const Request::BufferMap &buffers,\n-\t\t const ControlList &metadata)\n-\t\t: buffers_(buffers), metadata_(metadata)\n-\t{\n-\t}\n-\n-\tRequest::BufferMap buffers_;\n-\tControlList metadata_;\n-};\n-\n class MainWindow : public QMainWindow\n {\n \tQ_OBJECT\n@@ -128,13 +113,16 @@ private:\n \tStream *vfStream_;\n \tStream *rawStream_;\n \tstd::map<const Stream *, QQueue<FrameBuffer *>> freeBuffers_;\n-\tQQueue<CaptureRequest> doneQueue_;\n-\tQMutex mutex_; /* Protects freeBuffers_ and doneQueue_ */\n+\tQQueue<Request *> doneQueue_;\n+\tQQueue<Request *> freeQueue_;\n+\tQMutex mutex_; /* Protects freeBuffers_, doneQueue_, and freeQueue_ */\n \n \tuint64_t lastBufferTime_;\n \tQElapsedTimer frameRateInterval_;\n \tuint32_t previousFrames_;\n \tuint32_t framesCaptured_;\n+\n+\tstd::vector<std::unique_ptr<Request>> requests_;\n };\n \n #endif /* __QCAM_MAIN_WINDOW__ */\ndiff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp\nindex 3565f369..0d59502a 100644\n--- a/src/v4l2/v4l2_camera.cpp\n+++ b/src/v4l2/v4l2_camera.cpp\n@@ -49,6 +49,8 @@ int V4L2Camera::open(StreamConfiguration *streamConfig)\n \n void V4L2Camera::close()\n {\n+\trequestPool_.clear();\n+\n \tdelete bufferAllocator_;\n \tbufferAllocator_ = nullptr;\n \n@@ -154,16 +156,30 @@ int V4L2Camera::validateConfiguration(const PixelFormat &pixelFormat,\n \treturn 0;\n }\n \n-int V4L2Camera::allocBuffers([[maybe_unused]] unsigned int count)\n+int V4L2Camera::allocBuffers(unsigned int count)\n {\n \tStream *stream = config_->at(0).stream();\n \n-\treturn bufferAllocator_->allocate(stream);\n+\tint ret = bufferAllocator_->allocate(stream);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tfor (unsigned int i = 0; i < count; i++) {\n+\t\tstd::unique_ptr<Request> request = camera_->createRequest(i);\n+\t\tif (!request) {\n+\t\t\trequestPool_.clear();\n+\t\t\treturn -ENOMEM;\n+\t\t}\n+\t\trequestPool_.push_back(std::move(request));\n+\t}\n+\n+\treturn ret;\n }\n \n void V4L2Camera::freeBuffers()\n {\n \tpendingRequests_.clear();\n+\trequestPool_.clear();\n \n \tStream *stream = config_->at(0).stream();\n \tbufferAllocator_->free(stream);\n@@ -192,9 +208,9 @@ int V4L2Camera::streamOn()\n \n \tisRunning_ = true;\n \n-\tfor (std::unique_ptr<Request> &req : pendingRequests_) {\n+\tfor (Request *req : pendingRequests_) {\n \t\t/* \\todo What should we do if this returns -EINVAL? */\n-\t\tret = camera_->queueRequest(req.release());\n+\t\tret = camera_->queueRequest(req);\n \t\tif (ret < 0)\n \t\t\treturn ret == -EACCES ? -EBUSY : ret;\n \t}\n@@ -226,12 +242,12 @@ int V4L2Camera::streamOff()\n \n int V4L2Camera::qbuf(unsigned int index)\n {\n-\tstd::unique_ptr<Request> request =\n-\t\tstd::unique_ptr<Request>(camera_->createRequest(index));\n-\tif (!request) {\n-\t\tLOG(V4L2Compat, Error) << \"Can't create request\";\n-\t\treturn -ENOMEM;\n+\tif (index >= requestPool_.size()) {\n+\t\tLOG(V4L2Compat, Error) << \"Invalid index\";\n+\t\treturn -EINVAL;\n \t}\n+\tRequest *request = requestPool_[index].get();\n+\trequest->reset();\n \n \tStream *stream = config_->at(0).stream();\n \tFrameBuffer *buffer = bufferAllocator_->buffers(stream)[index].get();\n@@ -242,11 +258,11 @@ int V4L2Camera::qbuf(unsigned int index)\n \t}\n \n \tif (!isRunning_) {\n-\t\tpendingRequests_.push_back(std::move(request));\n+\t\tpendingRequests_.push_back(request);\n \t\treturn 0;\n \t}\n \n-\tret = camera_->queueRequest(request.release());\n+\tret = camera_->queueRequest(request);\n \tif (ret < 0) {\n \t\tLOG(V4L2Compat, Error) << \"Can't queue request\";\n \t\treturn ret == -EACCES ? -EBUSY : ret;\ndiff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h\nindex 1fc5ebef..a6c35a2e 100644\n--- a/src/v4l2/v4l2_camera.h\n+++ b/src/v4l2/v4l2_camera.h\n@@ -76,7 +76,9 @@ private:\n \tstd::mutex bufferLock_;\n \tFrameBufferAllocator *bufferAllocator_;\n \n-\tstd::deque<std::unique_ptr<Request>> pendingRequests_;\n+\tstd::vector<std::unique_ptr<Request>> requestPool_;\n+\n+\tstd::deque<Request *> pendingRequests_;\n \tstd::deque<std::unique_ptr<Buffer>> completedBuffers_;\n \n \tint efd_;\ndiff --git a/test/camera/buffer_import.cpp b/test/camera/buffer_import.cpp\nindex 64e96264..9cfdb388 100644\n--- a/test/camera/buffer_import.cpp\n+++ b/test/camera/buffer_import.cpp\n@@ -50,7 +50,7 @@ protected:\n \t\tif (request->status() != Request::RequestComplete)\n \t\t\treturn;\n \n-\t\tconst Request::BufferMap &buffers = request->buffers();\n+\t\tconst Request::BufferMap buffers = request->buffers();\n \n \t\tcompleteRequestsCount_++;\n \n@@ -58,7 +58,7 @@ protected:\n \t\tconst Stream *stream = buffers.begin()->first;\n \t\tFrameBuffer *buffer = buffers.begin()->second;\n \n-\t\trequest = camera_->createRequest();\n+\t\trequest->reset();\n \t\trequest->addBuffer(stream, buffer);\n \t\tcamera_->queueRequest(request);\n \t}\n@@ -98,9 +98,8 @@ protected:\n \t\tif (ret != TestPass)\n \t\t\treturn ret;\n \n-\t\tstd::vector<Request *> requests;\n \t\tfor (const std::unique_ptr<FrameBuffer> &buffer : source.buffers()) {\n-\t\t\tRequest *request = camera_->createRequest();\n+\t\t\tstd::unique_ptr<Request> request = camera_->createRequest();\n \t\t\tif (!request) {\n \t\t\t\tstd::cout << \"Failed to create request\" << std::endl;\n \t\t\t\treturn TestFail;\n@@ -111,7 +110,7 @@ protected:\n \t\t\t\treturn TestFail;\n \t\t\t}\n \n-\t\t\trequests.push_back(request);\n+\t\t\trequests_.push_back(std::move(request));\n \t\t}\n \n \t\tcompleteRequestsCount_ = 0;\n@@ -125,8 +124,8 @@ protected:\n \t\t\treturn TestFail;\n \t\t}\n \n-\t\tfor (Request *request : requests) {\n-\t\t\tif (camera_->queueRequest(request)) {\n+\t\tfor (std::unique_ptr<Request> &request : requests_) {\n+\t\t\tif (camera_->queueRequest(request.get())) {\n \t\t\t\tstd::cout << \"Failed to queue request\" << std::endl;\n \t\t\t\treturn TestFail;\n \t\t\t}\n@@ -160,6 +159,8 @@ protected:\n \t}\n \n private:\n+\tstd::vector<std::unique_ptr<Request>> requests_;\n+\n \tunsigned int completeBuffersCount_;\n \tunsigned int completeRequestsCount_;\n \tstd::unique_ptr<CameraConfiguration> config_;\ndiff --git a/test/camera/capture.cpp b/test/camera/capture.cpp\nindex 51bbd258..5c86c490 100644\n--- a/test/camera/capture.cpp\n+++ b/test/camera/capture.cpp\n@@ -44,7 +44,7 @@ protected:\n \t\tif (request->status() != Request::RequestComplete)\n \t\t\treturn;\n \n-\t\tconst Request::BufferMap &buffers = request->buffers();\n+\t\tconst Request::BufferMap buffers = request->buffers();\n \n \t\tcompleteRequestsCount_++;\n \n@@ -52,7 +52,7 @@ protected:\n \t\tconst Stream *stream = buffers.begin()->first;\n \t\tFrameBuffer *buffer = buffers.begin()->second;\n \n-\t\trequest = camera_->createRequest();\n+\t\trequest->reset();\n \t\trequest->addBuffer(stream, buffer);\n \t\tcamera_->queueRequest(request);\n \t}\n@@ -98,9 +98,8 @@ protected:\n \t\tif (ret < 0)\n \t\t\treturn TestFail;\n \n-\t\tstd::vector<Request *> requests;\n \t\tfor (const std::unique_ptr<FrameBuffer> &buffer : allocator_->buffers(stream)) {\n-\t\t\tRequest *request = camera_->createRequest();\n+\t\t\tstd::unique_ptr<Request> request = camera_->createRequest();\n \t\t\tif (!request) {\n \t\t\t\tcout << \"Failed to create request\" << endl;\n \t\t\t\treturn TestFail;\n@@ -111,7 +110,7 @@ protected:\n \t\t\t\treturn TestFail;\n \t\t\t}\n \n-\t\t\trequests.push_back(request);\n+\t\t\trequests_.push_back(std::move(request));\n \t\t}\n \n \t\tcompleteRequestsCount_ = 0;\n@@ -125,8 +124,8 @@ protected:\n \t\t\treturn TestFail;\n \t\t}\n \n-\t\tfor (Request *request : requests) {\n-\t\t\tif (camera_->queueRequest(request)) {\n+\t\tfor (std::unique_ptr<Request> &request : requests_) {\n+\t\t\tif (camera_->queueRequest(request.get())) {\n \t\t\t\tcout << \"Failed to queue request\" << endl;\n \t\t\t\treturn TestFail;\n \t\t\t}\n@@ -161,6 +160,8 @@ protected:\n \t\treturn TestPass;\n \t}\n \n+\tstd::vector<std::unique_ptr<Request>> requests_;\n+\n \tstd::unique_ptr<CameraConfiguration> config_;\n \tFrameBufferAllocator *allocator_;\n };\ndiff --git a/test/camera/statemachine.cpp b/test/camera/statemachine.cpp\nindex 28faeb91..e63ab298 100644\n--- a/test/camera/statemachine.cpp\n+++ b/test/camera/statemachine.cpp\n@@ -101,13 +101,10 @@ protected:\n \t\t\treturn TestFail;\n \n \t\t/* Test operations which should pass. */\n-\t\tRequest *request2 = camera_->createRequest();\n+\t\tstd::unique_ptr<Request> request2 = camera_->createRequest();\n \t\tif (!request2)\n \t\t\treturn TestFail;\n \n-\t\t/* Never handed to hardware so need to manually delete it. */\n-\t\tdelete request2;\n-\n \t\t/* Test valid state transitions, end in Running state. */\n \t\tif (camera_->release())\n \t\t\treturn TestFail;\n@@ -146,7 +143,7 @@ protected:\n \t\t\treturn TestFail;\n \n \t\t/* Test operations which should pass. */\n-\t\tRequest *request = camera_->createRequest();\n+\t\tstd::unique_ptr<Request> request = camera_->createRequest();\n \t\tif (!request)\n \t\t\treturn TestFail;\n \n@@ -154,7 +151,7 @@ protected:\n \t\tif (request->addBuffer(stream, allocator_->buffers(stream)[0].get()))\n \t\t\treturn TestFail;\n \n-\t\tif (camera_->queueRequest(request))\n+\t\tif (camera_->queueRequest(request.get()))\n \t\t\treturn TestFail;\n \n \t\t/* Test valid state transitions, end in Available state. */\n", "prefixes": [ "libcamera-devel", "v2" ] }