Show a patch.

GET /api/patches/18251/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 18251,
    "url": "https://patchwork.libcamera.org/api/patches/18251/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/18251/",
    "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": "<20230203094424.25243-7-naush@raspberrypi.com>",
    "date": "2023-02-03T09:44:22",
    "name": "[libcamera-devel,v1,6/8] libcamera: apps: lcc: Add multi-stream capture test framework",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "bf61adf9caff32061692d09395f9689cfad4ba76",
    "submitter": {
        "id": 34,
        "url": "https://patchwork.libcamera.org/api/people/34/?format=api",
        "name": "Naushir Patuck",
        "email": "naush@raspberrypi.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/18251/mbox/",
    "series": [
        {
            "id": 3739,
            "url": "https://patchwork.libcamera.org/api/series/3739/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=3739",
            "date": "2023-02-03T09:44:16",
            "name": "Stream hints",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/3739/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/18251/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/18251/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 A59F2C3243\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  3 Feb 2023 09:44:35 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 53ACB625F3;\n\tFri,  3 Feb 2023 10:44:35 +0100 (CET)",
            "from mail-wr1-x436.google.com (mail-wr1-x436.google.com\n\t[IPv6:2a00:1450:4864:20::436])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 691B2625E4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  3 Feb 2023 10:44:31 +0100 (CET)",
            "by mail-wr1-x436.google.com with SMTP id o18so4115408wrj.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 03 Feb 2023 01:44:31 -0800 (PST)",
            "from localhost.localdomain ([93.93.133.154])\n\tby smtp.gmail.com with ESMTPSA id\n\tf17-20020a5d50d1000000b002bfe266d710sm1562503wrt.90.2023.02.03.01.44.30\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tFri, 03 Feb 2023 01:44:30 -0800 (PST)"
        ],
        "DKIM-Signature": [
            "v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1675417475;\n\tbh=NxhZeUKE1nvXap0YMG8vugqatVNdph4Ii/SKNyji8+Q=;\n\th=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=LvYvOKyHWAuqiBTtUdgVlq2mFtigLix+hV56Ac+xjEzJ8SYHIExkl/9iT2mOBET+w\n\t/c8LTQB+Q4kY4nKa6GUdZWK5zqFHUiyfZZy57lRK1y08mN8hJzSgjGzA5KmvFRWXCB\n\t5RxLeFvKJU/qSBoVqHNb2CSQMiVinLUs/XixcjBnVlE5UROwce9v/CxkOXwN7Yz73V\n\t8CIHoabNJaCPyQzI9fikji0qfvegTy5QWrL1hopDCEkjqIkTjEOnr+6qkQtoDtJAQV\n\tY2q6t2yNTAWuyNVGfsMeRboWvdVa0PUUlTTN5nwsvZ7xG/q2EhS4zLi5TOV1a3+7YE\n\tN5LOWKbtF77WQ==",
            "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=nytONP2YDrHV/JpeWzsmettXZPjzIzkspdiWeo6WEy0=;\n\tb=ojeDGagqcTXV80rDOVET1k4HOtW57O1a1iWnyk8a9ngMEj8ptd5gNie5QVHb632QyG\n\tcD9XCQ57h2zSKYtEyLeU7QFu8ikREJFODnZreZaz4Hv8GwEKifhaow9CwzYp9f+GZVzN\n\tHy08i66M+0A7kmqKEUOgBGQScSuaHEufRMIar0UF3bFQyCHR4KTJcGUSRV4GaAWHcOKU\n\tBzSvbwF/FY5iY/d7Y5Q8DU0wkwsrAdS98FcJUCV6PtEXyPF2D/jsEYJSCCCqgUpa5Nlf\n\tLbGgG49bBfhf57WwvV5PMX+EY6fDxXNIx49uCrO5w2Lg6i/wNBP/dTGG0gt5b3llVQEZ\n\t1ioQ=="
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (2048-bit key; \n\tunprotected) header.d=raspberrypi.com\n\theader.i=@raspberrypi.com\n\theader.b=\"ojeDGagq\"; dkim-atps=neutral",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20210112;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc\n\t:subject:date:message-id:reply-to;\n\tbh=nytONP2YDrHV/JpeWzsmettXZPjzIzkspdiWeo6WEy0=;\n\tb=XDZQh/l77g2/Zj+CS/5mDSmMy3aJtBGGDWKwd0Z0C8v9daNMQkxd+Rg4uUEt9En1Nh\n\tz6J7NRLkicJR1LHa79DsnHt/C0/UCx3BjzRKMzNmvvV9KgR7iyUr084g21hHb8I66sAU\n\txhpVvsfP3HlrSBCJFDBF6vOwqghwAfL6VKgAscr/Bmu2vR01UFtq1bgKKM2dqz5Rplmn\n\te3yjORXJVpz1nrQEXpqjsXShze5gtxPyJNtlQ5m0LC1PC/8ABwKopCPyTB5/fkOe/BBF\n\tCBEOLkBAXuTqHmDVOzHcDSbi77sqzlIFhT7VR8sJVX5GfR7SleadF3sR5GIciFSoYINe\n\tx3Qw==",
        "X-Gm-Message-State": "AO0yUKXDdikqNMx5wWfHHDDa5N/CuPZJZyEJkiLeRM2RRsdZAb3YZlp5\n\t39FYxzuRS4F6Ox5294/i3F78Hlbnny8XpDPJS+S/MA==",
        "X-Google-Smtp-Source": "AK7set+f7Fd9anaaFY3vn+5nDamJRU2/Ug1DUFtORdvwxS6qEkRdQNpb43xlphrDRlV4msEj6GpPxQ==",
        "X-Received": "by 2002:adf:f5ca:0:b0:2bf:d686:c873 with SMTP id\n\tk10-20020adff5ca000000b002bfd686c873mr2906188wrp.28.1675417470768; \n\tFri, 03 Feb 2023 01:44:30 -0800 (PST)",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Fri,  3 Feb 2023 09:44:22 +0000",
        "Message-Id": "<20230203094424.25243-7-naush@raspberrypi.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20230203094424.25243-1-naush@raspberrypi.com>",
        "References": "<20230203094424.25243-1-naush@raspberrypi.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH v1 6/8] libcamera: apps: lcc: Add\n\tmulti-stream capture test framework",
        "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>",
        "From": "Naushir Patuck via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>",
        "Reply-To": "Naushir Patuck <naush@raspberrypi.com>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Add a framework for testing multi-stream captures with lcc. To start\nwith, a single test class, MultiStream, has been implemented. This class\nis based off the SimpleCaptureBalanced behavior, and tests that the\npipeline handler completes the exact number of requests queued to it.\n\nAdd a test to capture_test.cpp using the MultiStream class to test the\npipeline handler running with two simultaneous streams. The test\nframework permutate across a list of named stream pairs.\n\nSigned-off-by: Naushir Patuck <naush@raspberrypi.com>\n---\n src/apps/lc-compliance/capture_test.cpp  |  77 ++++++++++\n src/apps/lc-compliance/meson.build       |   1 +\n src/apps/lc-compliance/multi_capture.cpp | 187 +++++++++++++++++++++++\n src/apps/lc-compliance/multi_capture.h   |  61 ++++++++\n 4 files changed, 326 insertions(+)\n create mode 100644 src/apps/lc-compliance/multi_capture.cpp\n create mode 100644 src/apps/lc-compliance/multi_capture.h",
    "diff": "diff --git a/src/apps/lc-compliance/capture_test.cpp b/src/apps/lc-compliance/capture_test.cpp\nindex 37138dfb3d2e..8d534161e985 100644\n--- a/src/apps/lc-compliance/capture_test.cpp\n+++ b/src/apps/lc-compliance/capture_test.cpp\n@@ -11,6 +11,7 @@\n #include <gtest/gtest.h>\n \n #include \"environment.h\"\n+#include \"multi_capture.h\"\n #include \"simple_capture.h\"\n \n using namespace libcamera;\n@@ -32,6 +33,13 @@ const std::vector<StreamRole> ROLES = {\n \tStreamRole::Viewfinder\n };\n \n+const std::vector<std::pair<StreamRole, StreamRole>> MULTIROLES = {\n+\t{ StreamRole::Raw, StreamRole::StillCapture },\n+\t{ StreamRole::Raw, StreamRole::VideoRecording },\n+\t{ StreamRole::StillCapture, StreamRole::VideoRecording },\n+\t{ StreamRole::VideoRecording, StreamRole::VideoRecording },\n+};\n+\n } /* namespace */\n \n class SingleStream : public testing::TestWithParam<std::tuple<StreamRole, int>>\n@@ -137,3 +145,72 @@ INSTANTIATE_TEST_SUITE_P(CaptureTests,\n \t\t\t testing::Combine(testing::ValuesIn(ROLES),\n \t\t\t\t\t  testing::ValuesIn(NUMREQUESTS)),\n \t\t\t SingleStream::nameParameters);\n+\n+class MultiStream : public testing::TestWithParam<std::tuple<std::pair<StreamRole, StreamRole>, int>>\n+{\n+public:\n+\tstatic std::string nameParameters(const testing::TestParamInfo<MultiStream::ParamType> &info);\n+\n+protected:\n+\tvoid SetUp() override;\n+\tvoid TearDown() override;\n+\n+\tstd::shared_ptr<Camera> camera_;\n+};\n+\n+/*\n+ * We use gtest's SetUp() and TearDown() instead of constructor and destructor\n+ * in order to be able to assert on them.\n+ */\n+void MultiStream::SetUp()\n+{\n+\tEnvironment *env = Environment::get();\n+\n+\tcamera_ = env->cm()->get(env->cameraId());\n+\n+\tASSERT_EQ(camera_->acquire(), 0);\n+}\n+\n+void MultiStream::TearDown()\n+{\n+\tif (!camera_)\n+\t\treturn;\n+\n+\tcamera_->release();\n+\tcamera_.reset();\n+}\n+\n+std::string MultiStream::nameParameters(const testing::TestParamInfo<MultiStream::ParamType> &info)\n+{\n+\tstd::string roleName = rolesMap[std::get<0>(info.param).first] + \"_\" +\n+\t\t\t       rolesMap[std::get<0>(info.param).second];\n+\tstd::string numRequestsName = std::to_string(std::get<1>(info.param));\n+\n+\treturn roleName + \"_\" + numRequestsName;\n+}\n+\n+/*\n+ * Test multi-stream capture cycles\n+ *\n+ * Makes sure the camera completes the exact number of requests queued. Example\n+ * failure is a camera that completes less requests than the number of requests\n+ * queued.\n+ */\n+TEST_P(MultiStream, Capture)\n+{\n+\tconstexpr unsigned int NumStreams = 2;\n+\n+\tauto [roles, numRequests] = GetParam();\n+\n+\tMultiCapture capture(camera_);\n+\n+\tcapture.configure({ roles.first, roles.second });\n+\n+\tcapture.capture(numRequests, NumStreams);\n+}\n+\n+INSTANTIATE_TEST_SUITE_P(MultiCaptureTests,\n+\t\t\t MultiStream,\n+\t\t\t testing::Combine(testing::ValuesIn(MULTIROLES),\n+\t\t\t\t\t  testing::ValuesIn(NUMREQUESTS)),\n+\t\t\t MultiStream::nameParameters);\ndiff --git a/src/apps/lc-compliance/meson.build b/src/apps/lc-compliance/meson.build\nindex 51d9075ac30b..0357cda2f301 100644\n--- a/src/apps/lc-compliance/meson.build\n+++ b/src/apps/lc-compliance/meson.build\n@@ -13,6 +13,7 @@ lc_compliance_enabled = true\n lc_compliance_sources = files([\n     'environment.cpp',\n     'main.cpp',\n+    'multi_capture.cpp',\n     'simple_capture.cpp',\n     'capture_test.cpp',\n ])\ndiff --git a/src/apps/lc-compliance/multi_capture.cpp b/src/apps/lc-compliance/multi_capture.cpp\nnew file mode 100644\nindex 000000000000..23becf964fd7\n--- /dev/null\n+++ b/src/apps/lc-compliance/multi_capture.cpp\n@@ -0,0 +1,187 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * Copyright (C) 2023, Raspberry Pi Ltd\n+ *\n+ * multi_capture.cpp - Multi-stream capture helper\n+ */\n+#include \"multi_capture.h\"\n+\n+#include <algorithm>\n+\n+#include <gtest/gtest.h>\n+\n+using namespace libcamera;\n+\n+MultiCaptureBase::MultiCaptureBase(std::shared_ptr<Camera> camera)\n+\t: loop_(nullptr), camera_(camera),\n+\t  allocator_(std::make_unique<FrameBufferAllocator>(camera))\n+{\n+}\n+\n+MultiCaptureBase::~MultiCaptureBase()\n+{\n+\tstop();\n+}\n+\n+void MultiCaptureBase::configure(const libcamera::StreamRoles &roles)\n+{\n+\tconfig_ = camera_->generateConfiguration(roles);\n+\n+\tif (!config_) {\n+\t\tstd::cout << \"Roles not supported by camera\" << std::endl;\n+\t\tGTEST_SKIP();\n+\t}\n+\n+\t/* Set the buffer counts to the largest value across all streams */\n+\tauto largest =\n+\t\tstd::max_element(config_->begin(), config_->end(),\n+\t\t\t\t [](libcamera::StreamConfiguration &l, libcamera::StreamConfiguration &r)\n+\t\t\t\t { return l.bufferCount < r.bufferCount; });\n+\n+\tfor (auto &stream : *config_)\n+\t\tstream.bufferCount = largest->bufferCount;\n+\n+\tupdateConfig();\n+\n+\tif (config_->validate() != CameraConfiguration::Valid) {\n+\t\tconfig_.reset();\n+\t\tFAIL() << \"Configuration not valid\";\n+\t}\n+\n+\tif (camera_->configure(config_.get())) {\n+\t\tconfig_.reset();\n+\t\tFAIL() << \"Failed to configure camera\";\n+\t}\n+}\n+\n+void MultiCaptureBase::start()\n+{\n+\tunsigned int i = 0;\n+\n+\tfor (auto const &config : *config_) {\n+\t\tStream *stream = config.stream();\n+\t\tint count = allocator_->allocate(stream);\n+\n+\t\tASSERT_GE(count, 0) << \"Failed to allocate buffers for stream \"\n+\t\t\t\t    << i;\n+\t\tEXPECT_EQ(count, config.bufferCount)\n+\t\t\t<< \"Alocated less buffers than expected for stream \"\n+\t\t\t<< i;\n+\t\ti++;\n+\t}\n+\n+\tcamera_->requestCompleted.connect(this, &MultiCaptureBase::requestComplete);\n+\n+\tASSERT_EQ(camera_->start(), 0) << \"Failed to start camera\";\n+}\n+\n+void MultiCaptureBase::stop()\n+{\n+\tif (!config_ || !allocator_->allocated())\n+\t\treturn;\n+\n+\tcamera_->stop();\n+\n+\tcamera_->requestCompleted.disconnect(this);\n+\n+\trequests_.clear();\n+\n+\tfor (auto const &config : *config_) {\n+\t\tStream *stream = config.stream();\n+\t\tallocator_->free(stream);\n+\t}\n+}\n+\n+std::vector<const FrameBufferList *>\n+MultiCaptureBase::prepareBuffers(unsigned int numRequests, unsigned int numStreams)\n+{\n+\tstd::vector<const FrameBufferList *> buffers;\n+\n+\tfor (unsigned int i = 0; i < numStreams; i++) {\n+\t\tStream *stream = config_->at(i).stream();\n+\n+\t\tbuffers.emplace_back(&allocator_->buffers(stream));\n+\n+\t\t/* No point in testing less requests then the camera depth. */\n+\t\tif (buffers.back()->size() > numRequests) {\n+\t\t\tstd::cout << \"Stream \" << i\n+\t\t\t\t  << \" needs \" << std::to_string(buffers.back()->size())\n+\t\t\t\t  << \" requests, can't test only \"\n+\t\t\t\t  << std::to_string(numRequests) << std::endl;\n+\t\t\treturn {};\n+\t\t}\n+\t}\n+\n+\treturn buffers;\n+}\n+\n+/* MultiCapture */\n+\n+MultiCapture::MultiCapture(std::shared_ptr<Camera> camera)\n+\t: MultiCaptureBase(camera)\n+{\n+}\n+\n+void MultiCapture::capture(unsigned int numRequests, unsigned int numStreams)\n+{\n+\tstart();\n+\n+\tqueueCount_ = 0;\n+\tcaptureCount_ = 0;\n+\tcaptureLimit_ = numRequests;\n+\n+\tstd::vector<const FrameBufferList *>\n+\t\tbuffers = prepareBuffers(numRequests, numStreams);\n+\n+\tif (!buffers.size())\n+\t\tGTEST_SKIP();\n+\n+\t/* Queue the recommended number of requests. */\n+\tconst unsigned int inFlightRequests = config_->at(0).bufferCount;\n+\tfor (unsigned int i = 0; i < inFlightRequests; i++) {\n+\t\tstd::unique_ptr<Request> request = camera_->createRequest();\n+\t\tASSERT_TRUE(request) << \"Can't create request\";\n+\n+\t\tfor (unsigned int j = 0; j < numStreams; j++) {\n+\t\t\tconst FrameBufferList *bufferList = buffers[j];\n+\t\t\tStream *stream = config_->at(j).stream();\n+\n+\t\t\tASSERT_EQ(request->addBuffer(stream, (*bufferList)[i].get()), 0)\n+\t\t\t\t<< \"Can't set buffer for request\";\n+\t\t}\n+\n+\t\tASSERT_EQ(queueRequest(request.get()), 0)\n+\t\t\t<< \"Failed to queue request\";\n+\t\trequests_.push_back(std::move(request));\n+\t}\n+\n+\t/* Run capture session. */\n+\tloop_ = new EventLoop();\n+\tloop_->exec();\n+\tstop();\n+\tdelete loop_;\n+\n+\tASSERT_EQ(captureCount_, captureLimit_);\n+}\n+\n+int MultiCapture::queueRequest(Request *request)\n+{\n+\tqueueCount_++;\n+\tif (queueCount_ > captureLimit_)\n+\t\treturn 0;\n+\n+\treturn camera_->queueRequest(request);\n+}\n+\n+void MultiCapture::requestComplete(Request *request)\n+{\n+\tcaptureCount_++;\n+\tif (captureCount_ >= captureLimit_) {\n+\t\tloop_->exit(0);\n+\t\treturn;\n+\t}\n+\n+\trequest->reuse(Request::ReuseBuffers);\n+\tif (queueRequest(request))\n+\t\tloop_->exit(-EINVAL);\n+}\ndiff --git a/src/apps/lc-compliance/multi_capture.h b/src/apps/lc-compliance/multi_capture.h\nnew file mode 100644\nindex 000000000000..9037099988e5\n--- /dev/null\n+++ b/src/apps/lc-compliance/multi_capture.h\n@@ -0,0 +1,61 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * Copyright (C) 2023, Raspberry Pi Ltd\n+ *\n+ * multi_capture.h - Multi-stream capture helper\n+ */\n+\n+#pragma once\n+\n+#include <memory>\n+#include <vector>\n+\n+#include <libcamera/libcamera.h>\n+\n+#include \"../common/event_loop.h\"\n+\n+using FrameBufferList = std::vector<std::unique_ptr<libcamera::FrameBuffer>>;\n+\n+class MultiCaptureBase\n+{\n+public:\n+\tvoid configure(const libcamera::StreamRoles &roles);\n+\n+protected:\n+\tMultiCaptureBase(std::shared_ptr<libcamera::Camera> camera);\n+\tvirtual ~MultiCaptureBase();\n+\n+\tvoid start();\n+\tvoid stop();\n+\n+\tstd::vector<const FrameBufferList *>\n+\tprepareBuffers(unsigned int numRequests, unsigned int numStreams);\n+\n+\tvirtual void requestComplete(libcamera::Request *request) = 0;\n+\tvirtual void updateConfig() = 0;\n+\n+\tEventLoop *loop_;\n+\n+\tstd::shared_ptr<libcamera::Camera> camera_;\n+\tstd::unique_ptr<libcamera::FrameBufferAllocator> allocator_;\n+\tstd::unique_ptr<libcamera::CameraConfiguration> config_;\n+\tstd::vector<std::unique_ptr<libcamera::Request>> requests_;\n+};\n+\n+class MultiCapture : public MultiCaptureBase\n+{\n+public:\n+\tMultiCapture(std::shared_ptr<libcamera::Camera> camera);\n+\n+\tvoid capture(unsigned int numRequests, unsigned int numStreams);\n+\n+protected:\n+\tint queueRequest(libcamera::Request *request);\n+\tvoid requestComplete(libcamera::Request *request) override;\n+\n+\tvoid updateConfig() override {}\n+\n+\tunsigned int queueCount_;\n+\tunsigned int captureCount_;\n+\tunsigned int captureLimit_;\n+};\n",
    "prefixes": [
        "libcamera-devel",
        "v1",
        "6/8"
    ]
}