Patch Detail
Show a patch.
GET /api/patches/18980/?format=api
{ "id": 18980, "url": "https://patchwork.libcamera.org/api/patches/18980/?format=api", "web_url": "https://patchwork.libcamera.org/patch/18980/", "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": "<20230910175027.23384-2-andrey.konovalov@linaro.org>", "date": "2023-09-10T17:50:25", "name": "[libcamera-devel,1/3] libcamera: converter: split ConverterMD (media device) out of Converter", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "5c8068a18683fadbf042caa1dd73f67d9d133b01", "submitter": { "id": 25, "url": "https://patchwork.libcamera.org/api/people/25/?format=api", "name": "Andrey Konovalov", "email": "andrey.konovalov@linaro.org" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/18980/mbox/", "series": [ { "id": 4014, "url": "https://patchwork.libcamera.org/api/series/4014/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4014", "date": "2023-09-10T17:50:24", "name": "libcamera: converter: generalize Converter to remove MediaDevice dependency", "version": 1, "mbox": "https://patchwork.libcamera.org/series/4014/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/18980/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/18980/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 157BABD160\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 10 Sep 2023 17:52:07 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C1AE5628E7;\n\tSun, 10 Sep 2023 19:52:06 +0200 (CEST)", "from mail-ej1-x631.google.com (mail-ej1-x631.google.com\n\t[IPv6:2a00:1450:4864:20::631])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0AD7D61DF6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 10 Sep 2023 19:52:05 +0200 (CEST)", "by mail-ej1-x631.google.com with SMTP id\n\ta640c23a62f3a-99bcc0adab4so461186866b.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 10 Sep 2023 10:52:05 -0700 (PDT)", "from Lat-5310.. ([87.116.166.126]) by smtp.gmail.com with ESMTPSA\n\tid\n\tkd27-20020a17090798db00b009a57d30df89sm4090089ejc.132.2023.09.10.10.52.03\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tSun, 10 Sep 2023 10:52:04 -0700 (PDT)" ], "DKIM-Signature": [ "v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1694368326;\n\tbh=0Ni4tPfL+muGpZfcUUKdL165fs8g8IRcdghvK7bFy9M=;\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:Cc:\n\tFrom;\n\tb=tId0GfcMCtZJgpJO2iyxb031WROokOzaY/DAtRBxw0qF6IVTBw0+pnq591RhOngyg\n\t+JgQ4E7WrtKOg4ecVtFNzGRtRIZd/9ch2EZzjTvK1xNk6+6Ks3yqWJuUgkL3MedY7q\n\tU5XXJwC0vR9dpKg/5dFfXoc2Yk5fWBCje17EC1knVBhBo9FiLIRk2SVuyYZyNulZan\n\ts7YyI/jewyB6OlFt4F5/4tuPDRo35guJ5HE9TPjEIxNJzPEGz1UUJZ+FPRIpjtkSHX\n\terGQst3LSo0tCjf2wOhPGOfIeJ1AbqGK+mlvRy8udcuwWuSJpmIcGdNFboJLasoafT\n\tNtlyKOSvQnwGQ==", "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=linaro.org; s=google; t=1694368324; x=1694973124;\n\tdarn=lists.libcamera.org; \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=WC7htGSn6OAf1Z0vtHghGElAC2Fw5PErptZHPMh/4r0=;\n\tb=xFQuR7D7+wgBmfA4FWdzOSb5qKw6DfBT4Xk7shtsDpo2NWgUlGOrUpn0NplI0R7SXi\n\tqm8hmokf0SE1qAwJ93GmVxabAHiHkZvf6T54W/eN59AF49Zx5HY6S6z6HvsfHH5Djz+q\n\tFOFaSSxVmtxwR3RU4kThEhKdclD1h4LkyVs1YjPcyNmzI8U7D/cVFBvt7dokZCWfJTKw\n\ttcvE1/p5XCN1Zqs2mHGbmTfpuniZLXi8QvF3Opr5dbQmPKY1+jqaeA3eLpM/o7axB+Ma\n\tFreUBWeVJLEcY9RnzelGE5ciQlhIqp/DGpYAEbfkANC3FaGQ2RgqSOG03Na2gh75JPxC\n\tJVLA==" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (2048-bit key; \n\tunprotected) header.d=linaro.org\n\theader.i=@linaro.org header.b=\"xFQuR7D7\"; \n\tdkim-atps=neutral", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1694368324; x=1694973124;\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=WC7htGSn6OAf1Z0vtHghGElAC2Fw5PErptZHPMh/4r0=;\n\tb=DaVLGnTTMiH4GKMEUbSWWlb5pTUlr811x+aW/1OOE0KdzRLxXW0acY2kfK+fICC7Cf\n\t+IOmvQCFEm6opRzCbSmFq6/FiwGVwwxi7DNC5KNqNPDWDtqfodOYdJi2Fy/meYwsP2Tk\n\tJRnftYHCu2Ljb+aqZN2rLCEBdNCsY6Sc8wO5e9nhsxSRztiwITRD1aJQnitBXMJ9FXER\n\tm2Xum/kThLlfoamHp0DphlxrfwO/rYlCIoFl+FhO8TMQLBWcmhkEG9PlmtkBdaiwIDae\n\tXDJ+TEbjYOESRQeL677onP/+Lts9SDgkGcj29oi7lTIAglzSb87Rr5znRutLJ133TFgo\n\tnC5A==", "X-Gm-Message-State": "AOJu0Yz8Ub/MYaFBHfn6RoZqwAqI1MUK20q75Hh1nIDQT2M47Ew+ZpG5\n\t+MhdWXy/CzY9pFXseyqtQ5YhuzREqbmhPQOJnDM=", "X-Google-Smtp-Source": "AGHT+IESCMh+5YUMsj348CxUl9KVntTuYBpjdENdS3/EP4bTpsC/8wAKPD7V2vyUM/Zfphd1czdY4Q==", "X-Received": "by 2002:a17:907:2c61:b0:9a6:3d19:df7 with SMTP id\n\tib1-20020a1709072c6100b009a63d190df7mr6367897ejc.17.1694368324593; \n\tSun, 10 Sep 2023 10:52:04 -0700 (PDT)", "To": "libcamera-devel@lists.libcamera.org", "Date": "Sun, 10 Sep 2023 20:50:25 +0300", "Message-Id": "<20230910175027.23384-2-andrey.konovalov@linaro.org>", "X-Mailer": "git-send-email 2.34.1", "In-Reply-To": "<20230910175027.23384-1-andrey.konovalov@linaro.org>", "References": "<20230910175027.23384-1-andrey.konovalov@linaro.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH 1/3] libcamera: converter: split\n\tConverterMD (media device) out of Converter", "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": "Andrey Konovalov via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>", "Reply-To": "Andrey Konovalov <andrey.konovalov@linaro.org>", "Cc": "jacopo.mondi@ideasonboard.com, bryan.odonoghue@linaro.org,\n\tsrinivas.kandagatla@linaro.org", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "Make Converter a bit more generic by not requiring it to use a media device.\nFor this split out ConverterMD from Converter class, and rename\nConverterFactoryBase / ConverterFactory to ConverterMDFactoryBase /\nConverterMDFactory for consistency.\n\nSigned-off-by: Andrey Konovalov <andrey.konovalov@linaro.org>\n---\n include/libcamera/internal/converter.h | 49 +---\n .../internal/converter/converter_v4l2_m2m.h | 4 +-\n include/libcamera/internal/converter_media.h | 86 +++++++\n include/libcamera/internal/meson.build | 1 +\n src/libcamera/converter.cpp | 191 +-------------\n .../converter/converter_v4l2_m2m.cpp | 4 +-\n src/libcamera/converter_media.cpp | 241 ++++++++++++++++++\n src/libcamera/meson.build | 1 +\n src/libcamera/pipeline/simple/simple.cpp | 4 +-\n 9 files changed, 337 insertions(+), 244 deletions(-)\n create mode 100644 include/libcamera/internal/converter_media.h\n create mode 100644 src/libcamera/converter_media.cpp", "diff": "diff --git a/include/libcamera/internal/converter.h b/include/libcamera/internal/converter.h\nindex 834ec5ab..da1f5d73 100644\n--- a/include/libcamera/internal/converter.h\n+++ b/include/libcamera/internal/converter.h\n@@ -24,14 +24,13 @@\n namespace libcamera {\n \n class FrameBuffer;\n-class MediaDevice;\n class PixelFormat;\n struct StreamConfiguration;\n \n class Converter\n {\n public:\n-\tConverter(MediaDevice *media);\n+\tConverter();\n \tvirtual ~Converter();\n \n \tvirtual int loadConfiguration(const std::string &filename) = 0;\n@@ -57,52 +56,6 @@ public:\n \n \tSignal<FrameBuffer *> inputBufferReady;\n \tSignal<FrameBuffer *> outputBufferReady;\n-\n-\tconst std::string &deviceNode() const { return deviceNode_; }\n-\n-private:\n-\tstd::string deviceNode_;\n };\n \n-class ConverterFactoryBase\n-{\n-public:\n-\tConverterFactoryBase(const std::string name, std::initializer_list<std::string> compatibles);\n-\tvirtual ~ConverterFactoryBase() = default;\n-\n-\tconst std::vector<std::string> &compatibles() const { return compatibles_; }\n-\n-\tstatic std::unique_ptr<Converter> create(MediaDevice *media);\n-\tstatic std::vector<ConverterFactoryBase *> &factories();\n-\tstatic std::vector<std::string> names();\n-\n-private:\n-\tLIBCAMERA_DISABLE_COPY_AND_MOVE(ConverterFactoryBase)\n-\n-\tstatic void registerType(ConverterFactoryBase *factory);\n-\n-\tvirtual std::unique_ptr<Converter> createInstance(MediaDevice *media) const = 0;\n-\n-\tstd::string name_;\n-\tstd::vector<std::string> compatibles_;\n-};\n-\n-template<typename _Converter>\n-class ConverterFactory : public ConverterFactoryBase\n-{\n-public:\n-\tConverterFactory(const char *name, std::initializer_list<std::string> compatibles)\n-\t\t: ConverterFactoryBase(name, compatibles)\n-\t{\n-\t}\n-\n-\tstd::unique_ptr<Converter> createInstance(MediaDevice *media) const override\n-\t{\n-\t\treturn std::make_unique<_Converter>(media);\n-\t}\n-};\n-\n-#define REGISTER_CONVERTER(name, converter, compatibles) \\\n-\tstatic ConverterFactory<converter> global_##converter##Factory(name, compatibles);\n-\n } /* namespace libcamera */\ndiff --git a/include/libcamera/internal/converter/converter_v4l2_m2m.h b/include/libcamera/internal/converter/converter_v4l2_m2m.h\nindex 815916d0..aeb8c0e9 100644\n--- a/include/libcamera/internal/converter/converter_v4l2_m2m.h\n+++ b/include/libcamera/internal/converter/converter_v4l2_m2m.h\n@@ -20,7 +20,7 @@\n \n #include <libcamera/pixel_format.h>\n \n-#include \"libcamera/internal/converter.h\"\n+#include \"libcamera/internal/converter_media.h\"\n \n namespace libcamera {\n \n@@ -31,7 +31,7 @@ class SizeRange;\n struct StreamConfiguration;\n class V4L2M2MDevice;\n \n-class V4L2M2MConverter : public Converter\n+class V4L2M2MConverter : public ConverterMD\n {\n public:\n \tV4L2M2MConverter(MediaDevice *media);\ndiff --git a/include/libcamera/internal/converter_media.h b/include/libcamera/internal/converter_media.h\nnew file mode 100644\nindex 00000000..2b56ebdb\n--- /dev/null\n+++ b/include/libcamera/internal/converter_media.h\n@@ -0,0 +1,86 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2020, Laurent Pinchart\n+ * Copyright 2022 NXP\n+ *\n+ * converter_media.h - Generic media device based format converter interface\n+ */\n+\n+#pragma once\n+\n+#include <functional>\n+#include <initializer_list>\n+#include <map>\n+#include <memory>\n+#include <string>\n+#include <tuple>\n+#include <vector>\n+\n+#include <libcamera/base/class.h>\n+#include <libcamera/base/signal.h>\n+\n+#include <libcamera/geometry.h>\n+\n+#include \"libcamera/internal/converter.h\"\n+\n+namespace libcamera {\n+\n+class FrameBuffer;\n+class MediaDevice;\n+class PixelFormat;\n+struct StreamConfiguration;\n+\n+class ConverterMD : public Converter\n+{\n+public:\n+\tConverterMD(MediaDevice *media);\n+\t~ConverterMD();\n+\n+\tconst std::string &deviceNode() const { return deviceNode_; }\n+\n+private:\n+\tstd::string deviceNode_;\n+};\n+\n+class ConverterMDFactoryBase\n+{\n+public:\n+\tConverterMDFactoryBase(const std::string name, std::initializer_list<std::string> compatibles);\n+\tvirtual ~ConverterMDFactoryBase() = default;\n+\n+\tconst std::vector<std::string> &compatibles() const { return compatibles_; }\n+\n+\tstatic std::unique_ptr<ConverterMD> create(MediaDevice *media);\n+\tstatic std::vector<ConverterMDFactoryBase *> &factories();\n+\tstatic std::vector<std::string> names();\n+\n+private:\n+\tLIBCAMERA_DISABLE_COPY_AND_MOVE(ConverterMDFactoryBase)\n+\n+\tstatic void registerType(ConverterMDFactoryBase *factory);\n+\n+\tvirtual std::unique_ptr<ConverterMD> createInstance(MediaDevice *media) const = 0;\n+\n+\tstd::string name_;\n+\tstd::vector<std::string> compatibles_;\n+};\n+\n+template<typename _ConverterMD>\n+class ConverterMDFactory : public ConverterMDFactoryBase\n+{\n+public:\n+\tConverterMDFactory(const char *name, std::initializer_list<std::string> compatibles)\n+\t\t: ConverterMDFactoryBase(name, compatibles)\n+\t{\n+\t}\n+\n+\tstd::unique_ptr<ConverterMD> createInstance(MediaDevice *media) const override\n+\t{\n+\t\treturn std::make_unique<_ConverterMD>(media);\n+\t}\n+};\n+\n+#define REGISTER_CONVERTER_MD(name, converter, compatibles) \\\n+\tstatic ConverterMDFactory<converter> global_##converter##MDFactory(name, compatibles);\n+\n+} /* namespace libcamera */\ndiff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build\nindex 7f1f3440..e9c41346 100644\n--- a/include/libcamera/internal/meson.build\n+++ b/include/libcamera/internal/meson.build\n@@ -21,6 +21,7 @@ libcamera_internal_headers = files([\n 'control_serializer.h',\n 'control_validator.h',\n 'converter.h',\n+ 'converter_media.h',\n 'delayed_controls.h',\n 'device_enumerator.h',\n 'device_enumerator_sysfs.h',\ndiff --git a/src/libcamera/converter.cpp b/src/libcamera/converter.cpp\nindex fa0f1ec8..92dcdc03 100644\n--- a/src/libcamera/converter.cpp\n+++ b/src/libcamera/converter.cpp\n@@ -38,26 +38,9 @@ LOG_DEFINE_CATEGORY(Converter)\n \n /**\n * \\brief Construct a Converter instance\n- * \\param[in] media The media device implementing the converter\n- *\n- * This searches for the entity implementing the data streaming function in the\n- * media graph entities and use its device node as the converter device node.\n */\n-Converter::Converter(MediaDevice *media)\n+Converter::Converter()\n {\n-\tconst std::vector<MediaEntity *> &entities = media->entities();\n-\tauto it = std::find_if(entities.begin(), entities.end(),\n-\t\t\t [](MediaEntity *entity) {\n-\t\t\t\t return entity->function() == MEDIA_ENT_F_IO_V4L;\n-\t\t\t });\n-\tif (it == entities.end()) {\n-\t\tLOG(Converter, Error)\n-\t\t\t<< \"No entity suitable for implementing a converter in \"\n-\t\t\t<< media->driver() << \" entities list.\";\n-\t\treturn;\n-\t}\n-\n-\tdeviceNode_ = (*it)->deviceNode();\n }\n \n Converter::~Converter()\n@@ -159,176 +142,4 @@ Converter::~Converter()\n * \\brief A signal emitted on each frame buffer completion of the output queue\n */\n \n-/**\n- * \\fn Converter::deviceNode()\n- * \\brief The converter device node attribute accessor\n- * \\return The converter device node string\n- */\n-\n-/**\n- * \\class ConverterFactoryBase\n- * \\brief Base class for converter factories\n- *\n- * The ConverterFactoryBase class is the base of all specializations of the\n- * ConverterFactory class template. It implements the factory registration,\n- * maintains a registry of factories, and provides access to the registered\n- * factories.\n- */\n-\n-/**\n- * \\brief Construct a converter factory base\n- * \\param[in] name Name of the converter class\n- * \\param[in] compatibles Name aliases of the converter class\n- *\n- * Creating an instance of the factory base registers it with the global list of\n- * factories, accessible through the factories() function.\n- *\n- * The factory \\a name is used as unique identifier. If the converter\n- * implementation fully relies on a generic framework, the name should be the\n- * same as the framework. Otherwise, if the implementation is specialized, the\n- * factory name should match the driver name implementing the function.\n- *\n- * The factory \\a compatibles holds a list of driver names implementing a generic\n- * subsystem without any personalizations.\n- */\n-ConverterFactoryBase::ConverterFactoryBase(const std::string name, std::initializer_list<std::string> compatibles)\n-\t: name_(name), compatibles_(compatibles)\n-{\n-\tregisterType(this);\n-}\n-\n-/**\n- * \\fn ConverterFactoryBase::compatibles()\n- * \\return The names compatibles\n- */\n-\n-/**\n- * \\brief Create an instance of the converter corresponding to a named factory\n- * \\param[in] media Name of the factory\n- *\n- * \\return A unique pointer to a new instance of the converter subclass\n- * corresponding to the named factory or one of its alias. Otherwise a null\n- * pointer if no such factory exists\n- */\n-std::unique_ptr<Converter> ConverterFactoryBase::create(MediaDevice *media)\n-{\n-\tconst std::vector<ConverterFactoryBase *> &factories =\n-\t\tConverterFactoryBase::factories();\n-\n-\tfor (const ConverterFactoryBase *factory : factories) {\n-\t\tconst std::vector<std::string> &compatibles = factory->compatibles();\n-\t\tauto it = std::find(compatibles.begin(), compatibles.end(), media->driver());\n-\n-\t\tif (it == compatibles.end() && media->driver() != factory->name_)\n-\t\t\tcontinue;\n-\n-\t\tLOG(Converter, Debug)\n-\t\t\t<< \"Creating converter from \"\n-\t\t\t<< factory->name_ << \" factory with \"\n-\t\t\t<< (it == compatibles.end() ? \"no\" : media->driver()) << \" alias.\";\n-\n-\t\tstd::unique_ptr<Converter> converter = factory->createInstance(media);\n-\t\tif (converter->isValid())\n-\t\t\treturn converter;\n-\t}\n-\n-\treturn nullptr;\n-}\n-\n-/**\n- * \\brief Add a converter class to the registry\n- * \\param[in] factory Factory to use to construct the converter class\n- *\n- * The caller is responsible to guarantee the uniqueness of the converter name.\n- */\n-void ConverterFactoryBase::registerType(ConverterFactoryBase *factory)\n-{\n-\tstd::vector<ConverterFactoryBase *> &factories =\n-\t\tConverterFactoryBase::factories();\n-\n-\tfactories.push_back(factory);\n-}\n-\n-/**\n- * \\brief Retrieve the list of all converter factory names\n- * \\return The list of all converter factory names\n- */\n-std::vector<std::string> ConverterFactoryBase::names()\n-{\n-\tstd::vector<std::string> list;\n-\n-\tstd::vector<ConverterFactoryBase *> &factories =\n-\t\tConverterFactoryBase::factories();\n-\n-\tfor (ConverterFactoryBase *factory : factories) {\n-\t\tlist.push_back(factory->name_);\n-\t\tfor (auto alias : factory->compatibles())\n-\t\t\tlist.push_back(alias);\n-\t}\n-\n-\treturn list;\n-}\n-\n-/**\n- * \\brief Retrieve the list of all converter factories\n- * \\return The list of converter factories\n- */\n-std::vector<ConverterFactoryBase *> &ConverterFactoryBase::factories()\n-{\n-\t/*\n-\t * The static factories map is defined inside the function to ensure\n-\t * it gets initialized on first use, without any dependency on link\n-\t * order.\n-\t */\n-\tstatic std::vector<ConverterFactoryBase *> factories;\n-\treturn factories;\n-}\n-\n-/**\n- * \\var ConverterFactoryBase::name_\n- * \\brief The name of the factory\n- */\n-\n-/**\n- * \\var ConverterFactoryBase::compatibles_\n- * \\brief The list holding the factory compatibles\n- */\n-\n-/**\n- * \\class ConverterFactory\n- * \\brief Registration of ConverterFactory classes and creation of instances\n- * \\param _Converter The converter class type for this factory\n- *\n- * To facilitate discovery and instantiation of Converter classes, the\n- * ConverterFactory class implements auto-registration of converter helpers.\n- * Each Converter subclass shall register itself using the REGISTER_CONVERTER()\n- * macro, which will create a corresponding instance of a ConverterFactory\n- * subclass and register it with the static list of factories.\n- */\n-\n-/**\n- * \\fn ConverterFactory::ConverterFactory(const char *name, std::initializer_list<std::string> compatibles)\n- * \\brief Construct a converter factory\n- * \\details \\copydetails ConverterFactoryBase::ConverterFactoryBase\n- */\n-\n-/**\n- * \\fn ConverterFactory::createInstance() const\n- * \\brief Create an instance of the Converter corresponding to the factory\n- * \\param[in] media Media device pointer\n- * \\return A unique pointer to a newly constructed instance of the Converter\n- * subclass corresponding to the factory\n- */\n-\n-/**\n- * \\def REGISTER_CONVERTER\n- * \\brief Register a converter with the Converter factory\n- * \\param[in] name Converter name used to register the class\n- * \\param[in] converter Class name of Converter derived class to register\n- * \\param[in] compatibles List of compatible names\n- *\n- * Register a Converter subclass with the factory and make it available to try\n- * and match converters.\n- */\n-\n } /* namespace libcamera */\ndiff --git a/src/libcamera/converter/converter_v4l2_m2m.cpp b/src/libcamera/converter/converter_v4l2_m2m.cpp\nindex 2a4d1d99..d0a5e3bf 100644\n--- a/src/libcamera/converter/converter_v4l2_m2m.cpp\n+++ b/src/libcamera/converter/converter_v4l2_m2m.cpp\n@@ -194,7 +194,7 @@ void V4L2M2MConverter::Stream::captureBufferReady(FrameBuffer *buffer)\n */\n \n V4L2M2MConverter::V4L2M2MConverter(MediaDevice *media)\n-\t: Converter(media)\n+\t: ConverterMD(media)\n {\n \tif (deviceNode().empty())\n \t\treturn;\n@@ -448,6 +448,6 @@ static std::initializer_list<std::string> compatibles = {\n \t\"pxp\",\n };\n \n-REGISTER_CONVERTER(\"v4l2_m2m\", V4L2M2MConverter, compatibles)\n+REGISTER_CONVERTER_MD(\"v4l2_m2m\", V4L2M2MConverter, compatibles)\n \n } /* namespace libcamera */\ndiff --git a/src/libcamera/converter_media.cpp b/src/libcamera/converter_media.cpp\nnew file mode 100644\nindex 00000000..f5024764\n--- /dev/null\n+++ b/src/libcamera/converter_media.cpp\n@@ -0,0 +1,241 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright 2022 NXP\n+ *\n+ * converter.cpp - Generic format converter interface\n+ */\n+\n+#include \"libcamera/internal/converter_media.h\"\n+\n+#include <algorithm>\n+\n+#include <libcamera/base/log.h>\n+\n+#include \"libcamera/internal/media_device.h\"\n+\n+#include \"linux/media.h\"\n+\n+/**\n+ * \\file internal/converter_media.h\n+ * \\brief Abstract media device based converter\n+ */\n+\n+namespace libcamera {\n+\n+LOG_DECLARE_CATEGORY(Converter)\n+\n+/**\n+ * \\class ConverterMD\n+ * \\brief Abstract Base Class for media device based converter\n+ *\n+ * The ConverterMD class is an Abstract Base Class defining the interfaces of\n+ * media device based converter implementations.\n+ *\n+ * Converters offer scaling and pixel format conversion services on an input\n+ * stream. The converter can output multiple streams with individual conversion\n+ * parameters from the same input stream.\n+ */\n+\n+/**\n+ * \\brief Construct a ConverterMD instance\n+ * \\param[in] media The media device implementing the converter\n+ *\n+ * This searches for the entity implementing the data streaming function in the\n+ * media graph entities and use its device node as the converter device node.\n+ */\n+ConverterMD::ConverterMD(MediaDevice *media)\n+{\n+\tconst std::vector<MediaEntity *> &entities = media->entities();\n+\tauto it = std::find_if(entities.begin(), entities.end(),\n+\t\t\t [](MediaEntity *entity) {\n+\t\t\t\t return entity->function() == MEDIA_ENT_F_IO_V4L;\n+\t\t\t });\n+\tif (it == entities.end()) {\n+\t\tLOG(Converter, Error)\n+\t\t\t<< \"No entity suitable for implementing a converter in \"\n+\t\t\t<< media->driver() << \" entities list.\";\n+\t\treturn;\n+\t}\n+\n+\tdeviceNode_ = (*it)->deviceNode();\n+}\n+\n+ConverterMD::~ConverterMD()\n+{\n+}\n+\n+/**\n+ * \\fn ConverterMD::deviceNode()\n+ * \\brief The converter device node attribute accessor\n+ * \\return The converter device node string\n+ */\n+\n+/**\n+ * \\class ConverterMDFactoryBase\n+ * \\brief Base class for media device based converter factories\n+ *\n+ * The ConverterMDFactoryBase class is the base of all specializations of the\n+ * ConverterMDFactory class template. It implements the factory registration,\n+ * maintains a registry of factories, and provides access to the registered\n+ * factories.\n+ */\n+\n+/**\n+ * \\brief Construct a media device based converter factory base\n+ * \\param[in] name Name of the converter class\n+ * \\param[in] compatibles Name aliases of the converter class\n+ *\n+ * Creating an instance of the factory base registers it with the global list of\n+ * factories, accessible through the factories() function.\n+ *\n+ * The factory \\a name is used as unique identifier. If the converter\n+ * implementation fully relies on a generic framework, the name should be the\n+ * same as the framework. Otherwise, if the implementation is specialized, the\n+ * factory name should match the driver name implementing the function.\n+ *\n+ * The factory \\a compatibles holds a list of driver names implementing a generic\n+ * subsystem without any personalizations.\n+ */\n+ConverterMDFactoryBase::ConverterMDFactoryBase(const std::string name, std::initializer_list<std::string> compatibles)\n+\t: name_(name), compatibles_(compatibles)\n+{\n+\tregisterType(this);\n+}\n+\n+/**\n+ * \\fn ConverterMDFactoryBase::compatibles()\n+ * \\return The names compatibles\n+ */\n+\n+/**\n+ * \\brief Create an instance of the converter corresponding to a named factory\n+ * \\param[in] media Name of the factory\n+ *\n+ * \\return A unique pointer to a new instance of the media device based\n+ * converter subclass corresponding to the named factory or one of its alias.\n+ * Otherwise a null pointer if no such factory exists.\n+ */\n+std::unique_ptr<ConverterMD> ConverterMDFactoryBase::create(MediaDevice *media)\n+{\n+\tconst std::vector<ConverterMDFactoryBase *> &factories =\n+\t\tConverterMDFactoryBase::factories();\n+\n+\tfor (const ConverterMDFactoryBase *factory : factories) {\n+\t\tconst std::vector<std::string> &compatibles = factory->compatibles();\n+\t\tauto it = std::find(compatibles.begin(), compatibles.end(), media->driver());\n+\n+\t\tif (it == compatibles.end() && media->driver() != factory->name_)\n+\t\t\tcontinue;\n+\n+\t\tLOG(Converter, Debug)\n+\t\t\t<< \"Creating converter from \"\n+\t\t\t<< factory->name_ << \" factory with \"\n+\t\t\t<< (it == compatibles.end() ? \"no\" : media->driver()) << \" alias.\";\n+\n+\t\tstd::unique_ptr<ConverterMD> converter = factory->createInstance(media);\n+\t\tif (converter->isValid())\n+\t\t\treturn converter;\n+\t}\n+\n+\treturn nullptr;\n+}\n+\n+/**\n+ * \\brief Add a media device based converter class to the registry\n+ * \\param[in] factory Factory to use to construct the media device based\n+ * converter class\n+ *\n+ * The caller is responsible to guarantee the uniqueness of the converter name.\n+ */\n+void ConverterMDFactoryBase::registerType(ConverterMDFactoryBase *factory)\n+{\n+\tstd::vector<ConverterMDFactoryBase *> &factories =\n+\t\tConverterMDFactoryBase::factories();\n+\n+\tfactories.push_back(factory);\n+}\n+\n+/**\n+ * \\brief Retrieve the list of all media device based converter factory names\n+ * \\return The list of all media device based converter factory names\n+ */\n+std::vector<std::string> ConverterMDFactoryBase::names()\n+{\n+\tstd::vector<std::string> list;\n+\n+\tstd::vector<ConverterMDFactoryBase *> &factories =\n+\t\tConverterMDFactoryBase::factories();\n+\n+\tfor (ConverterMDFactoryBase *factory : factories) {\n+\t\tlist.push_back(factory->name_);\n+\t\tfor (auto alias : factory->compatibles())\n+\t\t\tlist.push_back(alias);\n+\t}\n+\n+\treturn list;\n+}\n+\n+/**\n+ * \\brief Retrieve the list of all media device based converter factories\n+ * \\return The list of media device based converter factories\n+ */\n+std::vector<ConverterMDFactoryBase *> &ConverterMDFactoryBase::factories()\n+{\n+\t/*\n+\t * The static factories map is defined inside the function to ensure\n+\t * it gets initialized on first use, without any dependency on link\n+\t * order.\n+\t */\n+\tstatic std::vector<ConverterMDFactoryBase *> factories;\n+\treturn factories;\n+}\n+\n+/**\n+ * \\var ConverterMDFactoryBase::name_\n+ * \\brief The name of the factory\n+ */\n+\n+/**\n+ * \\var ConverterMDFactoryBase::compatibles_\n+ * \\brief The list holding the factory compatibles\n+ */\n+\n+/**\n+ * \\class ConverterMDFactory\n+ * \\brief Registration of ConverterMDFactory classes and creation of instances\n+ * \\param _Converter The converter class type for this factory\n+ *\n+ * To facilitate discovery and instantiation of ConverterMD classes, the\n+ * ConverterMDFactory class implements auto-registration of converter helpers.\n+ * Each ConverterMD subclass shall register itself using the\n+ * REGISTER_CONVERTER() macro, which will create a corresponding instance of a\n+ * ConverterMDFactory subclass and register it with the static list of\n+ * factories.\n+ */\n+\n+/**\n+ * \\fn ConverterMDFactory::ConverterMDFactory(const char *name, std::initializer_list<std::string> compatibles)\n+ * \\brief Construct a media device converter factory\n+ * \\details \\copydetails ConverterMDFactoryBase::ConverterMDFactoryBase\n+ */\n+\n+/**\n+ * \\fn ConverterMDFactory::createInstance() const\n+ * \\brief Create an instance of the ConverterMD corresponding to the factory\n+ * \\param[in] media Media device pointer\n+ * \\return A unique pointer to a newly constructed instance of the ConverterMD\n+ * subclass corresponding to the factory\n+ */\n+\n+/**\n+ * \\def REGISTER_CONVERTER_MD\n+ * \\brief Register a media device based converter with the ConverterMD factory\n+ * \\param[in] name ConverterMD name used to register the class\n+ * \\param[in] converter Class name of ConverterMD derived class to register\n+ * \\param[in] compatibles List of compatible names\n+ *\n+ * Register a ConverterMD subclass with the factory and make it available to try\n+ * and match converters.\n+ */\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\nindex b24f8296..af8b1812 100644\n--- a/src/libcamera/meson.build\n+++ b/src/libcamera/meson.build\n@@ -14,6 +14,7 @@ libcamera_sources = files([\n 'control_serializer.cpp',\n 'control_validator.cpp',\n 'converter.cpp',\n+ 'converter_media.cpp',\n 'delayed_controls.cpp',\n 'device_enumerator.cpp',\n 'device_enumerator_sysfs.cpp',\ndiff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\nindex 05ba76bc..f0622a74 100644\n--- a/src/libcamera/pipeline/simple/simple.cpp\n+++ b/src/libcamera/pipeline/simple/simple.cpp\n@@ -30,7 +30,7 @@\n \n #include \"libcamera/internal/camera.h\"\n #include \"libcamera/internal/camera_sensor.h\"\n-#include \"libcamera/internal/converter.h\"\n+#include \"libcamera/internal/converter_media.h\"\n #include \"libcamera/internal/device_enumerator.h\"\n #include \"libcamera/internal/media_device.h\"\n #include \"libcamera/internal/pipeline_handler.h\"\n@@ -497,7 +497,7 @@ int SimpleCameraData::init()\n \t/* Open the converter, if any. */\n \tMediaDevice *converter = pipe->converter();\n \tif (converter) {\n-\t\tconverter_ = ConverterFactoryBase::create(converter);\n+\t\tconverter_ = ConverterMDFactoryBase::create(converter);\n \t\tif (!converter_) {\n \t\t\tLOG(SimplePipeline, Warning)\n \t\t\t\t<< \"Failed to create converter, disabling format conversion\";\n", "prefixes": [ "libcamera-devel", "1/3" ] }