[{"id":25300,"web_url":"https://patchwork.libcamera.org/comment/25300/","msgid":"<ff03a8b6-fbb2-91a4-5ed9-9272ec6cf236@oss.nxp.com>","date":"2022-10-05T11:17:30","subject":"Re: [libcamera-devel] [PATCH 8/8] libcamera: pipeline_handler:\n\tImplement factories through class templates","submitter":{"id":107,"url":"https://patchwork.libcamera.org/api/people/107/","name":"Xavier Roumegue","email":"xavier.roumegue@oss.nxp.com"},"content":"Hi Laurent,\n\nThanks for the patch.\n\nOn 10/3/22 23:21, Laurent Pinchart via libcamera-devel wrote:\n> The REGISTER_PIPELINE_HANDLER() macro defines a class type that inherits\n> from the PipelineHandlerFactory class, and implements a constructor and\n> a createInstance() function. Replace the code generation through macro\n> with the C++ equivalent, a class template, as done in libipa with the\n> Algorithm and CameraSensorHelper factories.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>   include/libcamera/internal/pipeline_handler.h | 44 +++++++------\n>   src/libcamera/camera_manager.cpp              |  6 +-\n>   src/libcamera/pipeline_handler.cpp            | 65 ++++++++++++-------\n>   test/ipa/ipa_interface_test.cpp               |  6 +-\n>   4 files changed, 71 insertions(+), 50 deletions(-)\n> \n> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> index ad74dc823290..b6139a88d421 100644\n> --- a/include/libcamera/internal/pipeline_handler.h\n> +++ b/include/libcamera/internal/pipeline_handler.h\n> @@ -95,23 +95,23 @@ private:\n>   \tMutex lock_;\n>   \tunsigned int useCount_ LIBCAMERA_TSA_GUARDED_BY(lock_);\n>   \n> -\tfriend class PipelineHandlerFactory;\n> +\tfriend class PipelineHandlerFactoryBase;\n>   };\n>   \n> -class PipelineHandlerFactory\n> +class PipelineHandlerFactoryBase\n>   {\n>   public:\n> -\tPipelineHandlerFactory(const char *name);\n> -\tvirtual ~PipelineHandlerFactory() = default;\n> +\tPipelineHandlerFactoryBase(const char *name);\n> +\tvirtual ~PipelineHandlerFactoryBase() = default;\n>   \n>   \tstd::shared_ptr<PipelineHandler> create(CameraManager *manager) const;\n>   \n>   \tconst std::string &name() const { return name_; }\n>   \n> -\tstatic std::vector<PipelineHandlerFactory *> &factories();\n> +\tstatic std::vector<PipelineHandlerFactoryBase *> &factories();\n>   \n>   private:\n> -\tstatic void registerType(PipelineHandlerFactory *factory);\n> +\tstatic void registerType(PipelineHandlerFactoryBase *factory);\n>   \n>   \tvirtual std::unique_ptr<PipelineHandler>\n>   \tcreateInstance(CameraManager *manager) const = 0;\n> @@ -119,19 +119,23 @@ private:\n>   \tstd::string name_;\n>   };\n>   \n> -#define REGISTER_PIPELINE_HANDLER(handler)\t\t\t\t\\\n> -class handler##Factory final : public PipelineHandlerFactory\t\t\\\n> -{\t\t\t\t\t\t\t\t\t\\\n> -public:\t\t\t\t\t\t\t\t\t\\\n> -\thandler##Factory() : PipelineHandlerFactory(#handler) {}\t\\\n> -\t\t\t\t\t\t\t\t\t\\\n> -private:\t\t\t\t\t\t\t\t\\\n> -\tstd::unique_ptr<PipelineHandler>\t\t\t\t\\\n> -\tcreateInstance(CameraManager *manager) const\t\t\t\\\n> -\t{\t\t\t\t\t\t\t\t\\\n> -\t\treturn std::make_unique<handler>(manager);\t\t\\\n> -\t}\t\t\t\t\t\t\t\t\\\n> -};\t\t\t\t\t\t\t\t\t\\\n> -static handler##Factory global_##handler##Factory;\n> +template<typename _PipelineHandler>\n> +class PipelineHandlerFactory final : public PipelineHandlerFactoryBase\n> +{\n> +public:\n> +\tPipelineHandlerFactory(const char *name)\n> +\t\t: PipelineHandlerFactoryBase(name)\n> +\t{\n> +\t}\n> +\n> +\tstd::unique_ptr<PipelineHandler>\n> +\tcreateInstance(CameraManager *manager) const override\n> +\t{\n> +\t\treturn std::make_unique<_PipelineHandler>(manager);\n> +\t}\n> +};\n> +\n> +#define REGISTER_PIPELINE_HANDLER(handler) \\\n> +static PipelineHandlerFactory<handler> global_##handler##Factory(#handler);\n>   \n>   } /* namespace libcamera */\n> diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp\n> index 2c3f2d86c469..2c100c24af4d 100644\n> --- a/src/libcamera/camera_manager.cpp\n> +++ b/src/libcamera/camera_manager.cpp\n> @@ -142,10 +142,10 @@ void CameraManager::Private::createPipelineHandlers()\n>   \t * file and only fallback on all handlers if there is no\n>   \t * configuration file.\n>   \t */\n> -\tconst std::vector<PipelineHandlerFactory *> &factories =\n> -\t\tPipelineHandlerFactory::factories();\n> +\tconst std::vector<PipelineHandlerFactoryBase *> &factories =\n> +\t\tPipelineHandlerFactoryBase::factories();\n>   \n> -\tfor (const PipelineHandlerFactory *factory : factories) {\n> +\tfor (const PipelineHandlerFactoryBase *factory : factories) {\n>   \t\tLOG(Camera, Debug)\n>   \t\t\t<< \"Found registered pipeline handler '\"\n>   \t\t\t<< factory->name() << \"'\";\n> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> index 488dd8d32cdf..44f6fc531ad7 100644\n> --- a/src/libcamera/pipeline_handler.cpp\n> +++ b/src/libcamera/pipeline_handler.cpp\n> @@ -64,8 +64,7 @@ LOG_DEFINE_CATEGORY(Pipeline)\n>    *\n>    * In order to honour the std::enable_shared_from_this<> contract,\n>    * PipelineHandler instances shall never be constructed manually, but always\n> - * through the PipelineHandlerFactory::create() function implemented by the\n> - * respective factories.\n> + * through the PipelineHandlerFactoryBase::create() function.\n>    */\n>   PipelineHandler::PipelineHandler(CameraManager *manager)\n>   \t: manager_(manager), useCount_(0)\n> @@ -643,27 +642,25 @@ void PipelineHandler::disconnect()\n>    */\n>   \n>   /**\n> - * \\class PipelineHandlerFactory\n> - * \\brief Registration of PipelineHandler classes and creation of instances\n> + * \\class PipelineHandlerFactoryBase\n> + * \\brief Base class for pipeline handler factories\n>    *\n> - * To facilitate discovery and instantiation of PipelineHandler classes, the\n> - * PipelineHandlerFactory class maintains a registry of pipeline handler\n> - * classes. Each PipelineHandler subclass shall register itself using the\n> - * REGISTER_PIPELINE_HANDLER() macro, which will create a corresponding\n> - * instance of a PipelineHandlerFactory subclass and register it with the\n> - * static list of factories.\n> + * The PipelineHandlerFactoryBase class is the base of all specializations of\n> + * the PipelineHandlerFactory class template. It implements the factory\n> + * registration, maintains a registry of factories, and provides access to the\n> + * registered factories.\n>    */\n>   \n>   /**\n> - * \\brief Construct a pipeline handler factory\n> + * \\brief Construct a pipeline handler factory base\n>    * \\param[in] name Name of the pipeline handler class\n>    *\n> - * Creating an instance of the factory registers is with the global list of\n> + * Creating an instance of the factory base registers is with the global list of\ns/is/it/\n>    * factories, accessible through the factories() function.\n>    *\n>    * The factory \\a name is used for debug purpose and shall be unique.\n>    */\n> -PipelineHandlerFactory::PipelineHandlerFactory(const char *name)\n> +PipelineHandlerFactoryBase::PipelineHandlerFactoryBase(const char *name)\n>   \t: name_(name)\n>   {\n>   \tregisterType(this);\n> @@ -676,7 +673,7 @@ PipelineHandlerFactory::PipelineHandlerFactory(const char *name)\n>    * \\return A shared pointer to a new instance of the PipelineHandler subclass\n>    * corresponding to the factory\n>    */\n> -std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *manager) const\n> +std::shared_ptr<PipelineHandler> PipelineHandlerFactoryBase::create(CameraManager *manager) const\n>   {\n>   \tstd::unique_ptr<PipelineHandler> handler = createInstance(manager);\n>   \thandler->name_ = name_.c_str();\n> @@ -684,7 +681,7 @@ std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *m\n>   }\n>   \n>   /**\n> - * \\fn PipelineHandlerFactory::name()\n> + * \\fn PipelineHandlerFactoryBase::name()\n>    * \\brief Retrieve the factory name\n>    * \\return The factory name\n>    */\n> @@ -696,9 +693,10 @@ std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *m\n>    * The caller is responsible to guarantee the uniqueness of the pipeline handler\n>    * name.\n>    */\n> -void PipelineHandlerFactory::registerType(PipelineHandlerFactory *factory)\n> +void PipelineHandlerFactoryBase::registerType(PipelineHandlerFactoryBase *factory)\n>   {\n> -\tstd::vector<PipelineHandlerFactory *> &factories = PipelineHandlerFactory::factories();\n> +\tstd::vector<PipelineHandlerFactoryBase *> &factories =\n> +\t\tPipelineHandlerFactoryBase::factories();\n>   \n>   \tfactories.push_back(factory);\n>   }\n> @@ -707,26 +705,45 @@ void PipelineHandlerFactory::registerType(PipelineHandlerFactory *factory)\n>    * \\brief Retrieve the list of all pipeline handler factories\n>    * \\return the list of pipeline handler factories\n>    */\n> -std::vector<PipelineHandlerFactory *> &PipelineHandlerFactory::factories()\n> +std::vector<PipelineHandlerFactoryBase *> &PipelineHandlerFactoryBase::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\n>   \t * link order.\n>   \t */\n> -\tstatic std::vector<PipelineHandlerFactory *> factories;\n> +\tstatic std::vector<PipelineHandlerFactoryBase *> factories;\n>   \treturn factories;\n>   }\n>   \n> +/**\n> + * \\class PipelineHandlerFactory\n> + * \\brief Registration of PipelineHandler classes and creation of instances\n> + * \\tparam _PipelineHandler The pipeline handler class type for this factory\n> + *\n> + * To facilitate discovery and instantiation of PipelineHandler classes, the\n> + * PipelineHandlerFactory class implements auto-registration of pipeline\n> + * handlers. Each PipelineHandler subclass shall register itself using the\n> + * REGISTER_PIPELINE_HANDLER() macro, which will create a corresponding\n> + * instance of a PipelineHandlerFactory and register it with the static list of\n> + * factories.\n> + */\n> +\n> +/**\n> + * \\fn PipelineHandlerFactory::PipelineHandlerFactory(const char *name)\n> + * \\brief Construct a pipeline handler factory\n> + * \\param[in] name Name of the pipeline handler class\n> + *\n> + * Creating an instance of the factory registers is with the global list ofs/is/it/\n> + * factories, accessible through the factories() function.\n> + *\n> + * The factory \\a name is used for debug purpose and shall be unique.\n> + */\n> +\n>   /**\n>    * \\fn PipelineHandlerFactory::createInstance() const\n>    * \\brief Create an instance of the PipelineHandler corresponding to the factory\n>    * \\param[in] manager The camera manager\n> - *\n> - * This virtual function is implemented by the REGISTER_PIPELINE_HANDLER()\n> - * macro. It creates a pipeline handler instance associated with the camera\n> - * \\a manager.\n> - *\n>    * \\return A unique pointer to a newly constructed instance of the\n>    * PipelineHandler subclass corresponding to the factory\n>    */\n> diff --git a/test/ipa/ipa_interface_test.cpp b/test/ipa/ipa_interface_test.cpp\n> index a629abc28da7..6b93e976a587 100644\n> --- a/test/ipa/ipa_interface_test.cpp\n> +++ b/test/ipa/ipa_interface_test.cpp\n> @@ -52,9 +52,9 @@ protected:\n>   \t\tipaManager_ = make_unique<IPAManager>();\n>   \n>   \t\t/* Create a pipeline handler for vimc. */\n> -\t\tconst std::vector<PipelineHandlerFactory *> &factories =\n> -\t\t\tPipelineHandlerFactory::factories();\n> -\t\tfor (const PipelineHandlerFactory *factory : factories) {\n> +\t\tconst std::vector<PipelineHandlerFactoryBase *> &factories =\n> +\t\t\tPipelineHandlerFactoryBase::factories();\n> +\t\tfor (const PipelineHandlerFactoryBase *factory : factories) {\n>   \t\t\tif (factory->name() == \"PipelineHandlerVimc\") {\n>   \t\t\t\tpipe_ = factory->create(nullptr);\n>   \t\t\t\tbreak;\n\nWith the typos fixed:\n\nReviewed-by: Xavier Roumegue <xavier.roumegue@oss.nxp.com>","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 D8A2BBD16B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  5 Oct 2022 11:17:37 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2C99E601C7;\n\tWed,  5 Oct 2022 13:17:37 +0200 (CEST)","from EUR04-DB3-obe.outbound.protection.outlook.com\n\t(mail-eopbgr60071.outbound.protection.outlook.com [40.107.6.71])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id DBFE9601C7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  5 Oct 2022 13:17:34 +0200 (CEST)","from PAXPR04MB8703.eurprd04.prod.outlook.com\n\t(2603:10a6:102:21e::22)\n\tby DBBPR04MB7545.eurprd04.prod.outlook.com (2603:10a6:10:200::7) with\n\tMicrosoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.31;\n\tWed, 5 Oct 2022 11:17:32 +0000","from PAXPR04MB8703.eurprd04.prod.outlook.com\n\t([fe80::4f72:a35a:8c60:63f1]) by\n\tPAXPR04MB8703.eurprd04.prod.outlook.com\n\t([fe80::4f72:a35a:8c60:63f1%6]) with mapi id 15.20.5676.028;\n\tWed, 5 Oct 2022 11:17:32 +0000"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1664968657;\n\tbh=sRIKao2k5bGjasyp2Prt77YPIWDr5Q1iY0GAgwZNEGM=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=va+slelBT6o5yvdVsffl9coBPW06NHoPhOEDtJsTYbQxiwaLSlXn/ZY2JZERBAmma\n\tV3UETVyP7+INt7L+l5tH1liQk7xqgqlv6WezpVPK7kM0goppcLc6fM6gjsChxtFV8T\n\trwnIm6KY0u2bHsrZV+PL/xO0i1fCEnT9gQ4IvY1KsW6DDLreAwHBYK6oPFjY7ypFnM\n\tWibgbM3AnULzQZpGvsC3eIBedIxJNfkJjF1UDS6Och8KlZ+q+5F8Hv1SuB45S+4A1z\n\tbQzdb7q4Ikzpt3wWdf2yRi00nRKOeeaLXpUBpId/g3Cba8n7Z9VSKcqbrnB3+2+5nq\n\twA2DKRDN12k1g==","v=1; a=rsa-sha256; c=relaxed/relaxed; d=NXP1.onmicrosoft.com;\n\ts=selector2-NXP1-onmicrosoft-com;\n\th=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n\tbh=hlh+YrWliXV2lct+hb0FtFUA15hsGv3m5gi/Zl/QSz4=;\n\tb=LRBp83/BstGvCYhMoH7JXQ79scmSnGoCqC38T/zFdXQDbt5q3MtOii5e3qTVTfT6EANquqpFPuPDYiBNIHKTQMHLwAZoB3jyUllNTi1ZeNeG64GmPj4+R7713rTa8fxpk2WD2qf+t2Pip2wJ3Nfzov1AWERBRdtXyCGpFS4hYco="],"Authentication-Results":["lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=NXP1.onmicrosoft.com\n\theader.i=@NXP1.onmicrosoft.com\n\theader.b=\"LRBp83/B\"; dkim-atps=neutral","dkim=none (message not signed)\n\theader.d=none;dmarc=none action=none header.from=oss.nxp.com;"],"ARC-Seal":"i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n\tb=HRQoTsYbxKtkpD1Tr6vaigE8Lz/wIMZimrTpZYzKeSHWzUMtuMAMvDRe3+hM6O0ghkmYh3Mc/AHajSQ/FWHJYGSl9gmorimkcOXdxi2fH/GukctUkIqYU4PSMlEGgb/SghdOwB6/Gi2uVELQRsoUVVYyhWSipbJoiB9mYsaW75g5oGMStTZjEJ3f5vfQZIFrlzxnhI/8qGS3x/yiLwsq4dgpK4hKhrdZuYmG2Lld6oIFDUISfTX20B5FFDmf7YUlno5xFu22gQtWRYA/4WS3MwYhuBF4VP4FCW7XHPHfLaFyOGYXsojt2ZyMl5ax4m3F1IzS+Jxg5dMN6ZGm6qQq6g==","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n\ts=arcselector9901;\n\th=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n\tbh=hlh+YrWliXV2lct+hb0FtFUA15hsGv3m5gi/Zl/QSz4=;\n\tb=MDUmiFalbxIsjgc4e4TQJFgJAVRTIIi9PJewJqOMeagfy9RrHpxz+9QBvHakcsZYEw5bAsu1hpnu6c+fxSe5isFmJCLQPAqj4HIfWa0tV1Z0aATeWZWm2I5iNHqG22/ppKtdHX1F2AFDBfxxUjIqP6f16BxIbeh8DRjgknVf65ilGyMbBMrDX0AN4oYtb9Jl+QBKEX3LH8zLv2O6xb6DQrpA4nLwdKOOInUKa/iYmEcUJZTOIWuzFeM8RX+7XTfIVlT4MknFmO5zQLunKG3nj6A6aUAtbMPp3TmgyoDu0pQAlCj8EAuVLIdqrofq0x+iwHhruZsZNY2EjjnlKfcICA==","ARC-Authentication-Results":"i=1; mx.microsoft.com 1; spf=pass\n\tsmtp.mailfrom=oss.nxp.com;\n\tdmarc=pass action=none header.from=oss.nxp.com; \n\tdkim=pass header.d=oss.nxp.com; arc=none","Message-ID":"<ff03a8b6-fbb2-91a4-5ed9-9272ec6cf236@oss.nxp.com>","Date":"Wed, 5 Oct 2022 13:17:30 +0200","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101\n\tThunderbird/102.3.1","Content-Language":"en-US, fr","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20221003212128.32429-1-laurent.pinchart@ideasonboard.com>\n\t<20221003212128.32429-9-laurent.pinchart@ideasonboard.com>","In-Reply-To":"<20221003212128.32429-9-laurent.pinchart@ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"7bit","X-ClientProxiedBy":"PR3P250CA0015.EURP250.PROD.OUTLOOK.COM\n\t(2603:10a6:102:57::20) To PAXPR04MB8703.eurprd04.prod.outlook.com\n\t(2603:10a6:102:21e::22)","MIME-Version":"1.0","X-MS-Exchange-MessageSentRepresentingType":"1","X-MS-PublicTrafficType":"Email","X-MS-TrafficTypeDiagnostic":"PAXPR04MB8703:EE_|DBBPR04MB7545:EE_","X-MS-Office365-Filtering-Correlation-Id":"19a7e537-edb6-4f33-d06e-08daa6c33270","X-MS-Exchange-SharedMailbox-RoutingAgent-Processed":"True","X-MS-Exchange-SenderADCheck":"1","X-MS-Exchange-AntiSpam-Relay":"0","X-Microsoft-Antispam":"BCL:0;","X-Microsoft-Antispam-Message-Info":"I4qrDJ2AyXxP3jayNCZh10xa50CBduydXlppicJ3e//FB2nPSzkBmRunHxHiVDl9nUTc57XeAGNCt3kgveswEeDZQpe+nvP8MgcoVHjvOBXhT5KDxGQYlLOt22x+02gnbEXeV+qRYeaVgLQtupAelJcbuzlyelo1i3c4SHGZs5ej7OZt828VKExWdWdL0AjB3YyM2HzRW2rtdhU+Q7t/vEoSheGgtqILEVTL5gCQ4Opocyc1b9+4OSlkDUClHclJGz96mOIBhfIJciZyEySudpp/9e1B+jeJkBBDVsgLLfhaLzd3HjQmJ/+s5dayKesKcX2zvmYESZr8v8oQd5vALE6bj5J2OVeitAlKQ9W1OCKL1EwXhiCF5utqRWouOKb1qcEVJEqfB3NLiE9ZrG41vEpQfRAhANPh7LjmPlpPbt6HFD287vdwLJzLYoZxwMmILT437T1d8h0LLzMouEWpzDsJ1ut3ktb8NXCrSMTDep0w0TUgr0V2e8zGfJC3J5bPeGwYaEj96aJF1K+SlCq1oZ93+RPRv793DxX1U57qjtRwBw6pCAz+vvYISmZA52A+SYaZh/vH3tBE1UmXmE8dnNMJqyTyxBZF0sgWa34DE+AHiuUq4OGd2pxssdyJ0Zc8vZBLSqubsedyHxhcWtucQ51m6Vmda1fdSh2hQ1hu0s0xqCyNy+gJqGqvEIMc5GighVqDx+Kx1zsqciGphnoSJNyFlqF1t6/YisFQgpfLIjM0CL54P4qFGY+e1oc+OphOZDzfG1bSPgaH9Go8nkea9PzHcSPHrdcW6DMocZ+3HK4=","X-Forefront-Antispam-Report":"CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:;\n\tIPV:NLI; SFV:NSPM; H:PAXPR04MB8703.eurprd04.prod.outlook.com; PTR:;\n\tCAT:NONE; \n\tSFS:(13230022)(4636009)(39860400002)(136003)(376002)(366004)(346002)(396003)(451199015)(31686004)(2906002)(5660300002)(316002)(8676002)(66556008)(66476007)(66946007)(6486002)(86362001)(41300700001)(31696002)(8936002)(30864003)(478600001)(52116002)(53546011)(83380400001)(6506007)(38100700002)(2616005)(6512007)(186003)(43740500002)(45980500001);\n\tDIR:OUT; SFP:1101; ","X-MS-Exchange-AntiSpam-MessageData-ChunkCount":"1","X-MS-Exchange-AntiSpam-MessageData-0":"=?utf-8?q?G2rysvVC7KDsQbX0pU5k9Qe4A?=\n\t=?utf-8?q?WvgkOlwziZeb2bblV23mXgmGUGvkV7mRSNiWube5x0Dj6GZQxXFcB8vK?=\n\t=?utf-8?q?EqAGEWxTVU+LPKO2Z1pfR8SI3T/OZXnKZHVHPYp8Q5eoFgyUjxisKYKX?=\n\t=?utf-8?q?tueSJekuYgEhsNCdymWpzlNcUM3OyAZkc8h09vQJsyE6Oj/SqQRt8xaD?=\n\t=?utf-8?q?r80AuJFQD1MyGrEUYf+xA+7W3AjogNaulovRZLsa+BPSJ6W9AcdivF8t?=\n\t=?utf-8?q?UubHXtx5kd87QettJaEgRNxOCvpkib9kZTa57+4KuNOc611ZxTUyoeDz?=\n\t=?utf-8?q?vxwp7kHe/TaZ93bmDpxF3pbxsTNH5POpHstxcuLB4a3wjqa9eELiPq49?=\n\t=?utf-8?q?iWuRYY/kwDiOppw78hxmtBSfuajhiWcmMP5Gk8xp8I5QP4kemnfTBI9G?=\n\t=?utf-8?q?Uj4RJfEt5iTbrzfojSeMHSQ1vqbDjxz25GNviOmtAECPv591Bk6wciUY?=\n\t=?utf-8?q?WStEwurW4Hwv/3pJRjD/DVoK1NyGtxWVdd2ReYdSdOhi8fSLBEJVbQIo?=\n\t=?utf-8?q?aXMBio3v3TQ+iR/jtVmG8s9X5wMDLaCayBFvbVt3TsoqrxZv0V7pad0i?=\n\t=?utf-8?q?FeAMxhSPr2Fx9AU8uJxXrM4YKeQu7SJv+WsvnL3vbIq3PrRqkrwLs3UH?=\n\t=?utf-8?q?TyEU7CQPpdY8pFhUR7ApN0pliwwDrhQCFWlXy4nM7n28PcC14jAG5o/q?=\n\t=?utf-8?q?fPb1E48rObsOXuAi3M623AvWV0jogLDSufAxc0XHWlqA00JzqyYhWgmC?=\n\t=?utf-8?q?S+UEjRWtaapxlcBF88qGFkViVIVuadFq1+sDlNFOx/QrHboYAEeX70rK?=\n\t=?utf-8?q?D+WrW2WKfy3gVXH1aoYPL+OLURjrfrRVCewf+SPX3Wuy+uvyIt4fOrEn?=\n\t=?utf-8?q?yttiow+2t8br+VjD+GcD46KiDrTPmPljH18cvVZ8M5tLIXOwE7LwsKCA?=\n\t=?utf-8?q?cDlGCe7bMGZf8uAkoi9kLcHNHrDWEsHTV5mG09pHJ5MvzL3zMsDeasZG?=\n\t=?utf-8?q?97ydbgy3UXAnN/sayNOgcozO/Z+zPcjdlG9rOE2+S9sQ2PXlDlY6K/uT?=\n\t=?utf-8?q?0EU6+JGCz3dy+Irk+jDFVx9VvBS5e0Wgos4sKAX9V2B5KaNGZQ1BvncG?=\n\t=?utf-8?q?snM8Bj7E+uszhpx4RYlTSVJ2oLZo8tJp2PHwWFseGWwo8IHjeA8K2pDR?=\n\t=?utf-8?q?5g/9US6Cb8FxqrssaKvqMrG3tYHzG9a6Ww2gouTbQfWdcXwLR30UiRMU?=\n\t=?utf-8?q?vW1AhaROz6simvxXbSCZfqI1Arfev0g+xtUrevjFm4HFS8v5gKEStREG?=\n\t=?utf-8?q?cJXYkan6hIgYvROAGkU0x+YSCYDUfW29T3WkGiWH9qI0QGy1AcpTXZip?=\n\t=?utf-8?q?Vy3Jj3sq6udVUSXxKdRQprSFhKJELSikO2mIJLqOUwwSl7ownza5ybgk?=\n\t=?utf-8?q?xgTOFNyxtJDEFoWIOIEuV97uQwn7RZq4LYuRfpBGhWjK5kvEl7x3zQwZ?=\n\t=?utf-8?q?sTk6cpkRGXxNWXBnllXKggbXEjTHfwg5ZL/rDndJ2Z1nstO9XF9KjBdA?=\n\t=?utf-8?q?CjpKRT1mogTl8AilRA7lsw0FmZGtdsT7Dpm6eaY+HN225NDNof3QjcQ1?=\n\t=?utf-8?q?I2bh3zlgVBIAPP52ec3STHsfj6/YEqrR9PZDb8h5RofIVitKomY9e6aX?=\n\t=?utf-8?q?gtsADkmTIThH3vUxvUdbkJnX/kNKTPwGcBeraIkLFcq8dk84tsdz8JBy?=\n\t=?utf-8?q?BK/0W8SAPYb32s9DKtHszsUa/rb82Kmy+8YcQ=3D=3D?=","X-OriginatorOrg":"oss.nxp.com","X-MS-Exchange-CrossTenant-Network-Message-Id":"19a7e537-edb6-4f33-d06e-08daa6c33270","X-MS-Exchange-CrossTenant-AuthSource":"PAXPR04MB8703.eurprd04.prod.outlook.com","X-MS-Exchange-CrossTenant-AuthAs":"Internal","X-MS-Exchange-CrossTenant-OriginalArrivalTime":"05 Oct 2022 11:17:32.2840\n\t(UTC)","X-MS-Exchange-CrossTenant-FromEntityHeader":"Hosted","X-MS-Exchange-CrossTenant-Id":"686ea1d3-bc2b-4c6f-a92c-d99c5c301635","X-MS-Exchange-CrossTenant-MailboxType":"HOSTED","X-MS-Exchange-CrossTenant-UserPrincipalName":"epkkBFzX6RkiqSSvie1FSt4a8U7WoisJA2QlD6wTcyAnip5e7xhgGxttTPOAMgOPNbzKGBbED0g/KiAUgJ3gjQ==","X-MS-Exchange-Transport-CrossTenantHeadersStamped":"DBBPR04MB7545","Subject":"Re: [libcamera-devel] [PATCH 8/8] libcamera: pipeline_handler:\n\tImplement factories through class templates","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":"\"Xavier Roumegue \\(OSS\\) via libcamera-devel\"\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"\"Xavier Roumegue \\(OSS\\)\" <xavier.roumegue@oss.nxp.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":25341,"web_url":"https://patchwork.libcamera.org/comment/25341/","msgid":"<20221007143453.bg5qkb2l3lufxkdv@uno.localdomain>","date":"2022-10-07T14:34:53","subject":"Re: [libcamera-devel] [PATCH 8/8] libcamera: pipeline_handler:\n\tImplement factories through class templates","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent\n\nOn Tue, Oct 04, 2022 at 12:21:28AM +0300, Laurent Pinchart via libcamera-devel wrote:\n> The REGISTER_PIPELINE_HANDLER() macro defines a class type that inherits\n> from the PipelineHandlerFactory class, and implements a constructor and\n> a createInstance() function. Replace the code generation through macro\n> with the C++ equivalent, a class template, as done in libipa with the\n> Algorithm and CameraSensorHelper factories.\n>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nI briefly tried to temaple PipelineHandlerFactoryBase directly, but\nquickly gave up :)\n\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n\nThanks\n  j\n\n> ---\n>  include/libcamera/internal/pipeline_handler.h | 44 +++++++------\n>  src/libcamera/camera_manager.cpp              |  6 +-\n>  src/libcamera/pipeline_handler.cpp            | 65 ++++++++++++-------\n>  test/ipa/ipa_interface_test.cpp               |  6 +-\n>  4 files changed, 71 insertions(+), 50 deletions(-)\n>\n> diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h\n> index ad74dc823290..b6139a88d421 100644\n> --- a/include/libcamera/internal/pipeline_handler.h\n> +++ b/include/libcamera/internal/pipeline_handler.h\n> @@ -95,23 +95,23 @@ private:\n>  \tMutex lock_;\n>  \tunsigned int useCount_ LIBCAMERA_TSA_GUARDED_BY(lock_);\n>\n> -\tfriend class PipelineHandlerFactory;\n> +\tfriend class PipelineHandlerFactoryBase;\n>  };\n>\n> -class PipelineHandlerFactory\n> +class PipelineHandlerFactoryBase\n>  {\n>  public:\n> -\tPipelineHandlerFactory(const char *name);\n> -\tvirtual ~PipelineHandlerFactory() = default;\n> +\tPipelineHandlerFactoryBase(const char *name);\n> +\tvirtual ~PipelineHandlerFactoryBase() = default;\n>\n>  \tstd::shared_ptr<PipelineHandler> create(CameraManager *manager) const;\n>\n>  \tconst std::string &name() const { return name_; }\n>\n> -\tstatic std::vector<PipelineHandlerFactory *> &factories();\n> +\tstatic std::vector<PipelineHandlerFactoryBase *> &factories();\n>\n>  private:\n> -\tstatic void registerType(PipelineHandlerFactory *factory);\n> +\tstatic void registerType(PipelineHandlerFactoryBase *factory);\n>\n>  \tvirtual std::unique_ptr<PipelineHandler>\n>  \tcreateInstance(CameraManager *manager) const = 0;\n> @@ -119,19 +119,23 @@ private:\n>  \tstd::string name_;\n>  };\n>\n> -#define REGISTER_PIPELINE_HANDLER(handler)\t\t\t\t\\\n> -class handler##Factory final : public PipelineHandlerFactory\t\t\\\n> -{\t\t\t\t\t\t\t\t\t\\\n> -public:\t\t\t\t\t\t\t\t\t\\\n> -\thandler##Factory() : PipelineHandlerFactory(#handler) {}\t\\\n> -\t\t\t\t\t\t\t\t\t\\\n> -private:\t\t\t\t\t\t\t\t\\\n> -\tstd::unique_ptr<PipelineHandler>\t\t\t\t\\\n> -\tcreateInstance(CameraManager *manager) const\t\t\t\\\n> -\t{\t\t\t\t\t\t\t\t\\\n> -\t\treturn std::make_unique<handler>(manager);\t\t\\\n> -\t}\t\t\t\t\t\t\t\t\\\n> -};\t\t\t\t\t\t\t\t\t\\\n> -static handler##Factory global_##handler##Factory;\n> +template<typename _PipelineHandler>\n> +class PipelineHandlerFactory final : public PipelineHandlerFactoryBase\n> +{\n> +public:\n> +\tPipelineHandlerFactory(const char *name)\n> +\t\t: PipelineHandlerFactoryBase(name)\n> +\t{\n> +\t}\n> +\n> +\tstd::unique_ptr<PipelineHandler>\n> +\tcreateInstance(CameraManager *manager) const override\n> +\t{\n> +\t\treturn std::make_unique<_PipelineHandler>(manager);\n> +\t}\n> +};\n> +\n> +#define REGISTER_PIPELINE_HANDLER(handler) \\\n> +static PipelineHandlerFactory<handler> global_##handler##Factory(#handler);\n>\n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp\n> index 2c3f2d86c469..2c100c24af4d 100644\n> --- a/src/libcamera/camera_manager.cpp\n> +++ b/src/libcamera/camera_manager.cpp\n> @@ -142,10 +142,10 @@ void CameraManager::Private::createPipelineHandlers()\n>  \t * file and only fallback on all handlers if there is no\n>  \t * configuration file.\n>  \t */\n> -\tconst std::vector<PipelineHandlerFactory *> &factories =\n> -\t\tPipelineHandlerFactory::factories();\n> +\tconst std::vector<PipelineHandlerFactoryBase *> &factories =\n> +\t\tPipelineHandlerFactoryBase::factories();\n>\n> -\tfor (const PipelineHandlerFactory *factory : factories) {\n> +\tfor (const PipelineHandlerFactoryBase *factory : factories) {\n>  \t\tLOG(Camera, Debug)\n>  \t\t\t<< \"Found registered pipeline handler '\"\n>  \t\t\t<< factory->name() << \"'\";\n> diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\n> index 488dd8d32cdf..44f6fc531ad7 100644\n> --- a/src/libcamera/pipeline_handler.cpp\n> +++ b/src/libcamera/pipeline_handler.cpp\n> @@ -64,8 +64,7 @@ LOG_DEFINE_CATEGORY(Pipeline)\n>   *\n>   * In order to honour the std::enable_shared_from_this<> contract,\n>   * PipelineHandler instances shall never be constructed manually, but always\n> - * through the PipelineHandlerFactory::create() function implemented by the\n> - * respective factories.\n> + * through the PipelineHandlerFactoryBase::create() function.\n>   */\n>  PipelineHandler::PipelineHandler(CameraManager *manager)\n>  \t: manager_(manager), useCount_(0)\n> @@ -643,27 +642,25 @@ void PipelineHandler::disconnect()\n>   */\n>\n>  /**\n> - * \\class PipelineHandlerFactory\n> - * \\brief Registration of PipelineHandler classes and creation of instances\n> + * \\class PipelineHandlerFactoryBase\n> + * \\brief Base class for pipeline handler factories\n>   *\n> - * To facilitate discovery and instantiation of PipelineHandler classes, the\n> - * PipelineHandlerFactory class maintains a registry of pipeline handler\n> - * classes. Each PipelineHandler subclass shall register itself using the\n> - * REGISTER_PIPELINE_HANDLER() macro, which will create a corresponding\n> - * instance of a PipelineHandlerFactory subclass and register it with the\n> - * static list of factories.\n> + * The PipelineHandlerFactoryBase class is the base of all specializations of\n> + * the PipelineHandlerFactory class template. It implements the factory\n> + * registration, maintains a registry of factories, and provides access to the\n> + * registered factories.\n>   */\n>\n>  /**\n> - * \\brief Construct a pipeline handler factory\n> + * \\brief Construct a pipeline handler factory base\n>   * \\param[in] name Name of the pipeline handler class\n>   *\n> - * Creating an instance of the factory registers is with the global list of\n> + * Creating an instance of the factory base registers is with the global list of\n>   * factories, accessible through the factories() function.\n>   *\n>   * The factory \\a name is used for debug purpose and shall be unique.\n>   */\n> -PipelineHandlerFactory::PipelineHandlerFactory(const char *name)\n> +PipelineHandlerFactoryBase::PipelineHandlerFactoryBase(const char *name)\n>  \t: name_(name)\n>  {\n>  \tregisterType(this);\n> @@ -676,7 +673,7 @@ PipelineHandlerFactory::PipelineHandlerFactory(const char *name)\n>   * \\return A shared pointer to a new instance of the PipelineHandler subclass\n>   * corresponding to the factory\n>   */\n> -std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *manager) const\n> +std::shared_ptr<PipelineHandler> PipelineHandlerFactoryBase::create(CameraManager *manager) const\n>  {\n>  \tstd::unique_ptr<PipelineHandler> handler = createInstance(manager);\n>  \thandler->name_ = name_.c_str();\n> @@ -684,7 +681,7 @@ std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *m\n>  }\n>\n>  /**\n> - * \\fn PipelineHandlerFactory::name()\n> + * \\fn PipelineHandlerFactoryBase::name()\n>   * \\brief Retrieve the factory name\n>   * \\return The factory name\n>   */\n> @@ -696,9 +693,10 @@ std::shared_ptr<PipelineHandler> PipelineHandlerFactory::create(CameraManager *m\n>   * The caller is responsible to guarantee the uniqueness of the pipeline handler\n>   * name.\n>   */\n> -void PipelineHandlerFactory::registerType(PipelineHandlerFactory *factory)\n> +void PipelineHandlerFactoryBase::registerType(PipelineHandlerFactoryBase *factory)\n>  {\n> -\tstd::vector<PipelineHandlerFactory *> &factories = PipelineHandlerFactory::factories();\n> +\tstd::vector<PipelineHandlerFactoryBase *> &factories =\n> +\t\tPipelineHandlerFactoryBase::factories();\n>\n>  \tfactories.push_back(factory);\n>  }\n> @@ -707,26 +705,45 @@ void PipelineHandlerFactory::registerType(PipelineHandlerFactory *factory)\n>   * \\brief Retrieve the list of all pipeline handler factories\n>   * \\return the list of pipeline handler factories\n>   */\n> -std::vector<PipelineHandlerFactory *> &PipelineHandlerFactory::factories()\n> +std::vector<PipelineHandlerFactoryBase *> &PipelineHandlerFactoryBase::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\n>  \t * link order.\n>  \t */\n> -\tstatic std::vector<PipelineHandlerFactory *> factories;\n> +\tstatic std::vector<PipelineHandlerFactoryBase *> factories;\n>  \treturn factories;\n>  }\n>\n> +/**\n> + * \\class PipelineHandlerFactory\n> + * \\brief Registration of PipelineHandler classes and creation of instances\n> + * \\tparam _PipelineHandler The pipeline handler class type for this factory\n> + *\n> + * To facilitate discovery and instantiation of PipelineHandler classes, the\n> + * PipelineHandlerFactory class implements auto-registration of pipeline\n> + * handlers. Each PipelineHandler subclass shall register itself using the\n> + * REGISTER_PIPELINE_HANDLER() macro, which will create a corresponding\n> + * instance of a PipelineHandlerFactory and register it with the static list of\n> + * factories.\n> + */\n> +\n> +/**\n> + * \\fn PipelineHandlerFactory::PipelineHandlerFactory(const char *name)\n> + * \\brief Construct a pipeline handler factory\n> + * \\param[in] name Name of the pipeline handler class\n> + *\n> + * Creating an instance of the factory registers is with the global list of\n> + * factories, accessible through the factories() function.\n> + *\n> + * The factory \\a name is used for debug purpose and shall be unique.\n> + */\n> +\n>  /**\n>   * \\fn PipelineHandlerFactory::createInstance() const\n>   * \\brief Create an instance of the PipelineHandler corresponding to the factory\n>   * \\param[in] manager The camera manager\n> - *\n> - * This virtual function is implemented by the REGISTER_PIPELINE_HANDLER()\n> - * macro. It creates a pipeline handler instance associated with the camera\n> - * \\a manager.\n> - *\n>   * \\return A unique pointer to a newly constructed instance of the\n>   * PipelineHandler subclass corresponding to the factory\n>   */\n> diff --git a/test/ipa/ipa_interface_test.cpp b/test/ipa/ipa_interface_test.cpp\n> index a629abc28da7..6b93e976a587 100644\n> --- a/test/ipa/ipa_interface_test.cpp\n> +++ b/test/ipa/ipa_interface_test.cpp\n> @@ -52,9 +52,9 @@ protected:\n>  \t\tipaManager_ = make_unique<IPAManager>();\n>\n>  \t\t/* Create a pipeline handler for vimc. */\n> -\t\tconst std::vector<PipelineHandlerFactory *> &factories =\n> -\t\t\tPipelineHandlerFactory::factories();\n> -\t\tfor (const PipelineHandlerFactory *factory : factories) {\n> +\t\tconst std::vector<PipelineHandlerFactoryBase *> &factories =\n> +\t\t\tPipelineHandlerFactoryBase::factories();\n> +\t\tfor (const PipelineHandlerFactoryBase *factory : factories) {\n>  \t\t\tif (factory->name() == \"PipelineHandlerVimc\") {\n>  \t\t\t\tpipe_ = factory->create(nullptr);\n>  \t\t\t\tbreak;\n> --\n> Regards,\n>\n> Laurent Pinchart\n>","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 C69E0BD16B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  7 Oct 2022 14:34:57 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3A0F662D22;\n\tFri,  7 Oct 2022 16:34:57 +0200 (CEST)","from relay10.mail.gandi.net (relay10.mail.gandi.net\n\t[217.70.178.230])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A82F960A88\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  7 Oct 2022 16:34:55 +0200 (CEST)","(Authenticated sender: jacopo@jmondi.org)\n\tby mail.gandi.net (Postfix) with ESMTPSA id 238FC24000C;\n\tFri,  7 Oct 2022 14:34:54 +0000 (UTC)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1665153297;\n\tbh=C1l3J0jQVAfIIKMN2k9dNy32H3HRqmBFZdBhU5xmUzU=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=x+hO73TYmOoZsX5GufgdKY8EoLZPwbLhvXkTYI2fIvgU9RpeQeHklv3K37fUmIPR6\n\t6bpO1EqGYvNwnOCbX1bKXsepxDnXTxi8WMBjnQq2HWP6010n6gH4HBwSkLVaDNASbb\n\t/+NjD61RUkpOogpKWo/veApLsIjWUPlqX3u0YuXZI4GZKLK8rEKz/5i7WoVuJPXSar\n\tQ4e55kNF9n5Qt+WwmaltkoGWm/2rOK5VCRKmyrw1+www7eLj27esR5l6lM9wfr+9ZU\n\tzJ4oREM7/POQ3SJD+43zBAMM/1mK18bDD/BuYfxa5QJ8E3ceXhczC6Ey24paEp+95o\n\t3e0MjPd6KFziA==","Date":"Fri, 7 Oct 2022 16:34:53 +0200","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<20221007143453.bg5qkb2l3lufxkdv@uno.localdomain>","References":"<20221003212128.32429-1-laurent.pinchart@ideasonboard.com>\n\t<20221003212128.32429-9-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20221003212128.32429-9-laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH 8/8] libcamera: pipeline_handler:\n\tImplement factories through class templates","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":"Jacopo Mondi via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]