{"id":23363,"url":"https://patchwork.libcamera.org/api/patches/23363/?format=json","web_url":"https://patchwork.libcamera.org/patch/23363/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/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":"<20250513133751.1381724-2-paul.elder@ideasonboard.com>","date":"2025-05-13T13:37:51","name":"[v3,1/1] pipeline: simple: Fix matching with empty media graphs","commit_ref":"6928522db6fab5a1cb9f05ce1ba8868a38de7781","pull_url":null,"state":"accepted","archived":false,"hash":"90f080818c06e9ddbeb89ddba263359460e64e34","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/?format=json","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/23363/mbox/","series":[{"id":5171,"url":"https://patchwork.libcamera.org/api/series/5171/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5171","date":"2025-05-13T13:37:50","name":"pipeline: simple: Fix matching with an empty media graph","version":3,"mbox":"https://patchwork.libcamera.org/series/5171/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/23363/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/23363/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 E6333C3220\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 13 May 2025 13:38:04 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 9665D68B40;\n\tTue, 13 May 2025 15:38:04 +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 9BB316175C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 13 May 2025 15:38:01 +0200 (CEST)","from pyrite.lan (unknown\n\t[IPv6:2001:861:3a80:3300:4f2f:8c2c:b3ef:17d4])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id E85BC82E;\n\tTue, 13 May 2025 15:37:45 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"rZt7tUBR\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1747143466;\n\tbh=BroYt+ypOh5bI78nhZFSjW05e/Y9KpH6qW/564y6hWA=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=rZt7tUBRMhv3VzRYgeFK+PYNxdp0YIuibbZAzyw6K1qKcPDryn+Np1ZZV9zK6p3Xd\n\tTJf2VuueHyB5gy1va4DAlaB51srMjmlpq+SIrAidw6gMXqFO7H5+MaCtC+qIGPBhgn\n\t1gNlXXQpOpQLfM5j30SHEGqyw0aG7etNtju3PvXc=","From":"Paul Elder <paul.elder@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Paul Elder <paul.elder@ideasonboard.com>,\n\tlaurent.pinchart@ideasonboard.com, kieran.bingham@ideasonboard.com","Subject":"[PATCH v3 1/1] pipeline: simple: Fix matching with empty media\n\tgraphs","Date":"Tue, 13 May 2025 15:37:51 +0200","Message-Id":"<20250513133751.1381724-2-paul.elder@ideasonboard.com>","X-Mailer":"git-send-email 2.39.2","In-Reply-To":"<20250513133751.1381724-1-paul.elder@ideasonboard.com>","References":"<20250513133751.1381724-1-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"The match() function currently reports that it is not possible to create\nany cameras if it encounters an empty media graph.\n\nFix this by looping over all media graphs and only returning false when\nall of them fail to create a camera.\n\nIt is worth noting that an issue does exist when on a partial match that\nends in an invalid match, any media devices that were acquired will stay\nacquired. This is not a new issue though, as any acquired media devices\nin general are not released until pipeline handler deconstruction. This\nrequires a rework of how we do matching and pipeline handler\nconstruction, so it is captured in a comment.\n\nIn the meantime, this fix fixes a problem without increasing the net\nnumber of problems.\n\nSigned-off-by: Paul Elder <paul.elder@ideasonboard.com>\n\n---\nChanges in v3:\n- removed clearMediaDevices()\n  - the reason is elaborated on in both the commit message and the todo\n    comment\n\nChanges in v2:\n- added clearMediaDevices()\n---\n src/libcamera/pipeline/simple/simple.cpp | 62 +++++++++++++++++-------\n 1 file changed, 45 insertions(+), 17 deletions(-)","diff":"diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\nindex efb07051b..4323472e1 100644\n--- a/src/libcamera/pipeline/simple/simple.cpp\n+++ b/src/libcamera/pipeline/simple/simple.cpp\n@@ -427,6 +427,9 @@ private:\n \t\treturn static_cast<SimpleCameraData *>(camera->_d());\n \t}\n \n+\tbool matchDevice(MediaDevice *media, const SimplePipelineInfo &info,\n+\t\t\t DeviceEnumerator *enumerator);\n+\n \tstd::vector<MediaEntity *> locateSensors(MediaDevice *media);\n \tstatic int resetRoutingTable(V4L2Subdevice *subdev);\n \n@@ -1660,25 +1663,13 @@ int SimplePipelineHandler::resetRoutingTable(V4L2Subdevice *subdev)\n \treturn 0;\n }\n \n-bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)\n+bool SimplePipelineHandler::matchDevice(MediaDevice *media,\n+\t\t\t\t\tconst SimplePipelineInfo &info,\n+\t\t\t\t\tDeviceEnumerator *enumerator)\n {\n-\tconst SimplePipelineInfo *info = nullptr;\n \tunsigned int numStreams = 1;\n-\tMediaDevice *media;\n \n-\tfor (const SimplePipelineInfo &inf : supportedDevices) {\n-\t\tDeviceMatch dm(inf.driver);\n-\t\tmedia = acquireMediaDevice(enumerator, dm);\n-\t\tif (media) {\n-\t\t\tinfo = &inf;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\n-\tif (!media)\n-\t\treturn false;\n-\n-\tfor (const auto &[name, streams] : info->converters) {\n+\tfor (const auto &[name, streams] : info.converters) {\n \t\tDeviceMatch converterMatch(name);\n \t\tconverter_ = acquireMediaDevice(enumerator, converterMatch);\n \t\tif (converter_) {\n@@ -1687,7 +1678,7 @@ bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)\n \t\t}\n \t}\n \n-\tswIspEnabled_ = info->swIspEnabled;\n+\tswIspEnabled_ = info.swIspEnabled;\n \n \t/* Locate the sensors. */\n \tstd::vector<MediaEntity *> sensors = locateSensors(media);\n@@ -1806,6 +1797,43 @@ bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)\n \treturn registered;\n }\n \n+bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)\n+{\n+\tMediaDevice *media;\n+\n+\tfor (const SimplePipelineInfo &inf : supportedDevices) {\n+\t\tDeviceMatch dm(inf.driver);\n+\t\twhile ((media = acquireMediaDevice(enumerator, dm))) {\n+\t\t\t/*\n+\t\t\t * If match succeeds, return true to let match() be\n+\t\t\t * called again on a new instance of the pipeline\n+\t\t\t * handler. Otherwise keep looping until we do\n+\t\t\t * successfully match one (or run out).\n+\t\t\t */\n+\t\t\tif (matchDevice(media, inf, enumerator)) {\n+\t\t\t\tLOG(SimplePipeline, Debug)\n+\t\t\t\t\t<< \"Matched on device: \"\n+\t\t\t\t\t<< media->deviceNode();\n+\t\t\t\treturn true;\n+\t\t\t}\n+\n+\t\t\t/*\n+\t\t\t * \\todo We need to clear the list of media devices\n+\t\t\t * that we've already acquired in the event that we\n+\t\t\t * fail to create a camera. This requires a rework of\n+\t\t\t * DeviceEnumerator, or even how we create pipelines\n+\t\t\t * handlers. This is because at the moment acquired\n+\t\t\t * media devices are only released on pipeline handler\n+\t\t\t * deconstruction, and if we release them any earlier\n+\t\t\t * then DeviceEnumerator::search() will keep returning\n+\t\t\t * the same media devices.\n+\t\t\t */\n+\t\t}\n+\t}\n+\n+\treturn false;\n+}\n+\n V4L2VideoDevice *SimplePipelineHandler::video(const MediaEntity *entity)\n {\n \tauto iter = entities_.find(entity);\n","prefixes":["v3","1/1"]}