Patch Detail
Show a patch.
GET /api/1.1/patches/23961/?format=api
{ "id": 23961, "url": "https://patchwork.libcamera.org/api/1.1/patches/23961/?format=api", "web_url": "https://patchwork.libcamera.org/patch/23961/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/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": "<20250725-multicontext-v1-7-ea558291e101@ideasonboard.com>", "date": "2025-07-25T10:33:52", "name": "[7/9] libcamera: media-device: Introduce MediaContext", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "0b23f6126a5fe9fd8a321b40014dee5ee23ae90b", "submitter": { "id": 143, "url": "https://patchwork.libcamera.org/api/1.1/people/143/?format=api", "name": "Jacopo Mondi", "email": "jacopo.mondi@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/23961/mbox/", "series": [ { "id": 5329, "url": "https://patchwork.libcamera.org/api/1.1/series/5329/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5329", "date": "2025-07-25T10:33:45", "name": "libcamera: Support for multi-context operations", "version": 1, "mbox": "https://patchwork.libcamera.org/series/5329/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/23961/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/23961/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 1738BC3323\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 25 Jul 2025 10:34:16 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7AAAE690BC;\n\tFri, 25 Jul 2025 12:34:11 +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 8CC6F6909F\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 25 Jul 2025 12:34:00 +0200 (CEST)", "from [192.168.0.172] (mob-5-90-139-29.net.vodafone.it\n\t[5.90.139.29])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 52054C73;\n\tFri, 25 Jul 2025 12:33:20 +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=\"lVHvyY3U\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1753439600;\n\tbh=h6fVQQRDCDzLgTYQD7LIce+Sr45tSyEOBhr9buH9vYA=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=lVHvyY3UpPvD1g4BKix2rto9FLdcYD+vwIx06q0jiq6VcyCE2tu8UMxB3fIsdgMdn\n\t1b9gXAhbD/LIiuCAyBGozWhjWOhM22YcfpYkn3bhe0T/7LMDjrIIoGsOOE/8mbd/i+\n\tz5JYAUGUHtPq/upBGb7Y8tqbJlRkRKBqaLeMPNv8=", "From": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>", "Date": "Fri, 25 Jul 2025 12:33:52 +0200", "Subject": "[PATCH 7/9] libcamera: media-device: Introduce MediaContext", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "7bit", "Message-Id": "<20250725-multicontext-v1-7-ea558291e101@ideasonboard.com>", "References": "<20250725-multicontext-v1-0-ea558291e101@ideasonboard.com>", "In-Reply-To": "<20250725-multicontext-v1-0-ea558291e101@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>", "X-Mailer": "b4 0.14.2", "X-Developer-Signature": "v=1; a=openpgp-sha256; l=8005;\n\ti=jacopo.mondi@ideasonboard.com; h=from:subject:message-id;\n\tbh=h6fVQQRDCDzLgTYQD7LIce+Sr45tSyEOBhr9buH9vYA=;\n\tb=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBog12UvJmBPXTa4+aDCplmm6WscOZgcTD3zCvnh\n\tXEJJZ8XRBiJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaINdlAAKCRByNAaPFqFW\n\tPES0D/wP9pW8NmeR9R1mTbxSwTOgZDgsmBG44X23brpOuRz3GKduV2AA+Yr29aPG2x7OmrKmGEL\n\tm7PkeqyJaMhvn8Wp/J8neJh9YrwPhZJ8540XBWRBma7KnsfSPOMLXOrQMfv2rOIWCPmyt1kwa26\n\tvVuBUXtUarMfHx/Pe68SetXEDLF90bj+VoCdQ8qPq8/K5N/yyfm4tfMo7Fc8nuxTPOwwKJNwgpF\n\tqVmc9c4DXsYCZA4VjcmEH2XQkthD0GOdvGZnsbpxqU+rexKr4A0Xo4X7SN9w7NOJf0o9DoMQ40k\n\tnA29b2ccCkB/mFaGZ52OUWZtRfkt7m/BVtTAUHvhEfEgELFRZ6YdMJhTbP+ZgJiJbthCEX1bXxn\n\tTXqfrdcKLxfPbrEQZsMY/Go2AL7WJ2VB6lt65Mw4QcMRGtLEXt4JxIhwOce6R94pYmCrI54r8Gn\n\tuD3VEzTzZ4zXPtBH/SzExJylc7lexO/CYlkn/XfR93Bb2tUfUt+1mGzhLSmpBJ5Nvk7Ix+hxRxn\n\tr8gsII4gl4aXCyR7gDelSknoVmFkx67zR0p7QuLXcgq+XoF9ZH7nmvhmsl6BuNDTJOGVd+VNg+V\n\t9hEl2dJOFWWXiuQqj9kH3rEc/sEooF/8uh9w8a0tbOItPCw63tm1MMvSRj256z8pNKbwZV0BIuL\n\tGG+AQKkssHCLKrg==", "X-Developer-Key": "i=jacopo.mondi@ideasonboard.com; a=openpgp;\n\tfpr=72392EDC88144A65C701EA9BA5826A2587AD026B", "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": "Introduce the MediaContext class that represents a media device\ncontext to which video devices and subdevices can be bound to.\n\nA MediaContext can be created from a MediaDevice (which does not\nsupport multi-context) and from SharedMediaDevice (which supports\nmulti-context).\n\nBinding devices to a MediaContext created from MediaDevice is a nop,\nwhile MediaContext created from SharedMediaDevice perform proper\nbindings.\n\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n include/libcamera/internal/media_device.h | 23 ++++-\n src/libcamera/media_device.cpp | 135 ++++++++++++++++++++++++++++++\n 2 files changed, 157 insertions(+), 1 deletion(-)", "diff": "diff --git a/include/libcamera/internal/media_device.h b/include/libcamera/internal/media_device.h\nindex ea0e9d66009933bbb9613d27423d2f951520c887..2dbfcc447d84bb6a1eee4ed598d22b5cc45adbe9 100644\n--- a/include/libcamera/internal/media_device.h\n+++ b/include/libcamera/internal/media_device.h\n@@ -21,6 +21,9 @@\n \n namespace libcamera {\n \n+class V4L2VideoDevice;\n+class V4L2Subdevice;\n+\n class MediaDeviceFactory\n {\n public:\n@@ -28,6 +31,19 @@ public:\n \tcreateMediaDevice(const std::string &deviceNode);\n };\n \n+class MediaContext\n+{\n+public:\n+\tMediaContext();\n+\tMediaContext(UniqueFD &&fd);\n+\n+\tint bindDevice(V4L2VideoDevice *dev);\n+\tint bindDevice(V4L2Subdevice *dev);\n+\n+private:\n+\tUniqueFD fd_;\n+};\n+\n class MediaDevice : protected Loggable\n {\n public:\n@@ -63,10 +79,14 @@ public:\n \n \tstd::vector<MediaEntity *> locateEntities(unsigned int function);\n \n+\tvirtual std::unique_ptr<MediaContext> createContext();\n+\n protected:\n \tMediaDevice(const std::string &deviceNode);\n \tstd::string logPrefix() const override;\n \n+\tstd::string deviceNode_;\n+\n private:\n \tfriend class MediaDeviceFactory;\n \n@@ -88,7 +108,6 @@ private:\n \tint setupLink(const MediaLink *link, unsigned int flags);\n \n \tstd::string driver_;\n-\tstd::string deviceNode_;\n \tstd::string model_;\n \tunsigned int version_;\n \tunsigned int hwRevision_;\n@@ -111,6 +130,8 @@ public:\n \tbool lock() override;\n \tvoid unlock() override;\n \n+\tstd::unique_ptr<MediaContext> createContext() override;\n+\n private:\n \tfriend class MediaDeviceFactory;\n \ndiff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp\nindex 70d073f964bde0236585de083baca4cd9c30d193..2b7df346ad9916cf22641ea770e0a1507921d89d 100644\n--- a/src/libcamera/media_device.cpp\n+++ b/src/libcamera/media_device.cpp\n@@ -21,6 +21,9 @@\n \n #include <libcamera/base/log.h>\n \n+#include \"libcamera/internal/v4l2_subdevice.h\"\n+#include \"libcamera/internal/v4l2_videodevice.h\"\n+\n /**\n * \\file media_device.h\n * \\brief Provide a representation of a Linux kernel Media Controller device\n@@ -81,6 +84,99 @@ MediaDeviceFactory::createMediaDevice(const std::string &deviceNode)\n \treturn std::unique_ptr<MediaDevice>(new MediaDevice(deviceNode));\n }\n \n+/**\n+ * \\class MediaContext\n+ * \\brief Represents a media device context\n+ *\n+ * A media device context is obtained from a MediaDevice or a SharedMediaDevice\n+ * instance with the MediaDevice::createContext() and\n+ * SharedMediaDevice::createContext() functions.\n+ *\n+ * MediaContext instances obtained from a MediaDevice that does not support\n+ * multi-context operations will not have a valid file descriptor associated as\n+ * the media device they are created from doesn't support multiple open. For\n+ * this reason binding a device to a context that is obtained from a MediaDevice\n+ * is a nop.\n+ *\n+ * MediaContext instances obtained from a SharedMediaDevice that supports\n+ * multi-context operations owns the file descriptor that identifies the media\n+ * context, obtained by opening the media device multiple times and provided to\n+ * the context at creation time. Binding devices to a context obtained from a\n+ * SharedMediaDevice associates the devices to an execution context which\n+ * remains valid until the last bound device stays valid.\n+ *\n+ * Users of this class can bind devices on valid and invalid MultiContext\n+ * instances alike. If the kernel driver supports multi-context operations\n+ * then the device can be opened multiple times and multiple contexts can be\n+ * created to which devices can be bound to. If the kernel driver doesn't\n+ * support multi-context operations then it can be opened a single time only\n+ * and a creating contexts and bindings devices to it is effectively a nop.\n+ */\n+\n+/**\n+ * \\brief Constructs a MediaContext not associated to any media device context\n+ *\n+ * Constructs a media device context not associated to any valid media device\n+ * context file descriptor. Binding devices to such media device context\n+ * is effectively a nop.\n+ */\n+MediaContext::MediaContext()\n+{\n+}\n+\n+/**\n+ * \\brief Construct a MediaContext associated to a valid media device context\n+ * \\param[in] fd The file descriptor that identifies a media device context\n+ *\n+ * Construct a media device context to which devices can be bound to.\n+ *\n+ * Constructing a MediaContext with an associated valid media device context\n+ * allows to create isolated execution contexts by binding devices to it.\n+ *\n+ * The file descriptor \\a fd obtained by opening the media device and that\n+ * identifies the media device context is moved in the newly constructed\n+ * MediaContext which maintains its ownership and automatically closes it at\n+ * destruction time.\n+ */\n+MediaContext::MediaContext(UniqueFD &&fd)\n+\t: fd_(std::move(fd))\n+{\n+}\n+\n+/**\n+ * \\brief Bind a V4L2 video device to a media device context\n+ * \\param[in] dev The video device to bind\n+ *\n+ * If the MediaContext has been created by a MediaDevice that does not\n+ * support multi-context operations, this function is effectively a nop.\n+ *\n+ * \\return 0 on success or a negative error code otherwise\n+ */\n+int MediaContext::bindDevice(V4L2VideoDevice *dev)\n+{\n+\tif (fd_.get() == -1)\n+\t\treturn 0;\n+\n+\treturn dev->bindContext(fd_.get());\n+}\n+\n+/**\n+ * \\brief Bind a V4L2 subdevice to a media device context\n+ * \\param[in] dev The subdevice to bind\n+ *\n+ * If the MediaContext has been created by a MediaDevice that does not\n+ * support multi-context operations, this function is effectively a nop.\n+ *\n+ * \\return 0 on success or a negative error code otherwise\n+ */\n+int MediaContext::bindDevice(V4L2Subdevice *dev)\n+{\n+\tif (fd_.get() == -1)\n+\t\treturn 0;\n+\n+\treturn dev->bindContext(fd_.get());\n+}\n+\n /**\n * \\class MediaDevice\n * \\brief The MediaDevice represents a Media Controller device with its full\n@@ -603,6 +699,45 @@ int MediaDevice::disableLinks()\n * driver unloading for most devices. The media device is passed as a parameter.\n */\n \n+/**\n+ * \\brief Create a MediaContext not associated with a media device context\n+ * \\return A MediaContext to which bindings devices is a nop\n+ */\n+std::unique_ptr<MediaContext> MediaDevice::createContext()\n+{\n+\treturn std::make_unique<MediaContext>();\n+}\n+\n+/**\n+ * \\brief Create a MediaContext associated with a media device context\n+ *\n+ * Create a MediaContext by opening the media device and create a media\n+ * device context using the obtained file descriptor.\n+ *\n+ * The open file descriptor is moved to the MediaContext whose ownership is\n+ * moved to the caller of this function.\n+ *\n+ * \\return A MediaContext to which is possible to bind devices to\n+ */\n+std::unique_ptr<MediaContext> SharedMediaDevice::createContext()\n+{\n+\tauto fd = UniqueFD(::open(deviceNode_.c_str(), O_RDWR | O_CLOEXEC));\n+\tif (!fd.isValid()) {\n+\t\tint ret = -errno;\n+\t\tLOG(MediaDevice, Error)\n+\t\t\t<< \"Failed to open media device at \"\n+\t\t\t<< deviceNode_ << \": \" << strerror(-ret);\n+\t\treturn {};\n+\t}\n+\n+\treturn std::make_unique<MediaContext>(std::move(fd));\n+}\n+\n+/**\n+ * \\var MediaDevice::deviceNode_\n+ * \\brief The media device device node path\n+ */\n+\n /**\n * \\brief Open the media device\n *\n", "prefixes": [ "7/9" ] }