Show a patch.

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

{
    "id": 17346,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/17346/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/17346/",
    "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": "<20220908184850.1874303-5-xavier.roumegue@oss.nxp.com>",
    "date": "2022-09-08T18:48:40",
    "name": "[libcamera-devel,04/14] libcamera: Declare generic size and format converter interface",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": false,
    "hash": "894e08b370e2e79b6582a5296052d6e26b829396",
    "submitter": {
        "id": 107,
        "url": "https://patchwork.libcamera.org/api/1.1/people/107/?format=api",
        "name": "Xavier Roumegue",
        "email": "xavier.roumegue@oss.nxp.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/17346/mbox/",
    "series": [
        {
            "id": 3477,
            "url": "https://patchwork.libcamera.org/api/1.1/series/3477/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=3477",
            "date": "2022-09-08T18:48:36",
            "name": "Add dw100 dewarper support to simple/rkisp1 pipeline",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/3477/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/17346/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/17346/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 59AEBC3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  8 Sep 2022 18:49:25 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 07D7F620B3;\n\tThu,  8 Sep 2022 20:49:24 +0200 (CEST)",
            "from EUR04-DB3-obe.outbound.protection.outlook.com\n\t(mail-eopbgr60064.outbound.protection.outlook.com [40.107.6.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0F1BA620AF\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  8 Sep 2022 20:49:20 +0200 (CEST)",
            "from PAXPR04MB8703.eurprd04.prod.outlook.com\n\t(2603:10a6:102:21e::22)\n\tby AS8PR04MB8852.eurprd04.prod.outlook.com (2603:10a6:20b:42f::14)\n\twith Microsoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5612.19;\n\tThu, 8 Sep 2022 18:49:18 +0000",
            "from PAXPR04MB8703.eurprd04.prod.outlook.com\n\t([fe80::485:adba:7081:715a]) by\n\tPAXPR04MB8703.eurprd04.prod.outlook.com\n\t([fe80::485:adba:7081:715a%3]) with mapi id 15.20.5612.019;\n\tThu, 8 Sep 2022 18:49:18 +0000"
        ],
        "DKIM-Signature": [
            "v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1662662964;\n\tbh=o187exn0iRru3cc77DWztNSBQqaSJ8ZbzcWssCaAtw0=;\n\th=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=0ICSR3QmKsYb6cROVRV7Bc4ruvfGmOaVMOFfMLL/eThz+BpjBpxqiUDYnaIK6MT7y\n\t9RxVWBPK0EpYn825s4F+GSc/wr/cQz+JMdaiX7CVEYIkVSU4jWOvxaC3D0/edIeH8w\n\tt3eT4ysgSIZjCh602p2xiHYt6z3OkcXZBFEO/I9lJVxGtQ2s+BMnuts4mK81uhalEf\n\tNOhVdu9//j++t+nvy2P1qBKg3sUCk3DOd02g/g+fzgMfjXKSULlzjx54lke8+uF5Mp\n\tAzp4La7KDOCuegZMtPw+9I6LtzkOA5R5ctIoZ8/PNiQV2/94dUA98b9LKZr2aRZgy8\n\t3MHRwNKbBiSJg==",
            "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=S2sNuxMIzSdlEJJoNgfqntq4XAIKjQDfb11cjwNMjfE=;\n\tb=YGaydutaSbmy0wHv7HpWPlFbwESZw51OzGwAsoo1yyO4rT5zHmY6c5bn6MCeBUOHAiTk+zmT6zl7NHwvotxtG6wkaVgvmIYqx5ERodL5rstm6pewLZncBK1gvkKvPKjy7G3IExDWNjRoN9qk5aYRxTmI66UIPInWpcWhyRloGz0="
        ],
        "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=\"YGayduta\"; 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=dlQAc/s+UUt6lhunECAVEFqHGWYL0tBXJfYwiOr2IcLqHHuK4voTb6VDXOPr6EGGDXgmcemOTtaQEYMkrE9HLRiJve7lzqk7mOoZPO36FexQz+kBQlewHiWEG43dH7RR5H0GYL8yfY+ff2nC2VzMvYxuOleuGfdMgUEUGPWlwLlcmx0FE3oCzdqRuwGLmrXGsYFYqA0vGN3LwcHtbW2YzIlwBhpjGWd0fK/66JCIeojwazjsZz386PEiGEMKMZwbTr0FKRnn6QHqgtynHWVootCxlCKeGF6nt9igmXfdidnFO2X9y64EeB7sbDT7dFqE2joFSvfql4BR9a/4Anu0xQ==",
        "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=S2sNuxMIzSdlEJJoNgfqntq4XAIKjQDfb11cjwNMjfE=;\n\tb=f8X5JZCJakiVnt6hWg5a2hbdG3bPLcb4hxf6+d0Ygbw2EoxXs1GJRWuWl2h+lmc7kkfxxxGAi1MStjqRAofk356CCfBycrsrn3jis1Nh+Pxxu0P2qrIxlzmEvGeyaUvgaeoBbGC0YgY7qA2U5pJhgn1ShXxkfi9zVqJ1k2CmKVPVf+OZPgfo78/Qv7O7/dC9dv/l2xNLmZN801R9/vQLuVrvkBcKop55886slGxeErEe/nkvGN2/QyxdtzpuBgAqRZYe2ldNlib1Pj67S4GOhpU1Owwk0Y6TOulJGiltFKNmKI3BUjAxFKnS3USUG2MEXH91kdtNdtYehJ+wMhIuBg==",
        "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",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Thu,  8 Sep 2022 20:48:40 +0200",
        "Message-Id": "<20220908184850.1874303-5-xavier.roumegue@oss.nxp.com>",
        "X-Mailer": "git-send-email 2.37.3",
        "In-Reply-To": "<20220908184850.1874303-1-xavier.roumegue@oss.nxp.com>",
        "References": "<20220908184850.1874303-1-xavier.roumegue@oss.nxp.com>",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain",
        "X-ClientProxiedBy": "PR3P250CA0001.EURP250.PROD.OUTLOOK.COM\n\t(2603:10a6:102:57::6) 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_|AS8PR04MB8852:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "1092cc32-246a-40ce-11c8-08da91cad5e5",
        "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": "Mb93W/cwXJp1AnF/HRP3h/f5BJcJOAr6NaVFuGNAh6iaIwfzl8RA1yAdKfjefb4jMUbk7OF0W8ekYcZC4X1PVQYk8vYlNPb3TKweG2IM77wr9HRlKx/BvOZnuqRxUb90S8jQ/lATvoVxi36JelZwL9EIcMBYVzghaqsh5p1J/rCJKrxQo4R6daFWJAoC01eqOiVtqq04v5NPe9UOHkaw/+MdyMAqadoHHk63OKtqU/cV0CkKUd9UgNA8oQAqUa+Mpsik1BRLXDpUSwNRVOpwIXYZzq1ka5Do7Jaup/2swAqdJ00NigVCqwhsyGsW8L3SHwNRXWZOfpVpSDAeyChF/4/Y+qebWZbDRSmXKs9hfUlYpvkGIv0UPK5JSAQB4cbOlYA4gLFOpAPeheCW5h5vyzfFPaoJvRq8qpVovWWyPNoqRBL236hbbBXljAnL1GwbCTeFHUTkTIXori02HSD8dAnx3knJJRaUyM+ihgCWzSzfVRoEY14NPU0qsra6QkyAO+4r+BIRIAHSYq6I9UwGx+xH37myAoXcVIzJwysjj9a3CMmYV6FLxDpofkAMO94XYzqnbBYGNCB18ahpvyhnvdKRCC+LVHbQf2PI8XUhqPSFmhVFTdWqcxUJPkQp4pTo2puE4w58oLeTt91/PmHvKxeUvd+RmGlJxxwRPqjND2XcHOL29vxPXwKgG1dPb1es7lEiyNJE4ebOdNBF25RhHZxElKTBx7rjKloM8bw2JfNw2AhHEId342T+Ivb+PuYl5PfmD6Qfp/ior5gNTF9dNg==",
        "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:(13230016)(4636009)(39860400002)(346002)(376002)(396003)(136003)(366004)(38100700002)(66556008)(66476007)(66946007)(8936002)(44832011)(5660300002)(4326008)(8676002)(6916009)(316002)(41300700001)(186003)(1076003)(2616005)(2906002)(478600001)(6666004)(86362001)(6512007)(52116002)(6506007)(83380400001)(6486002)(41533002);\n\tDIR:OUT; SFP:1101; ",
        "X-MS-Exchange-AntiSpam-MessageData-ChunkCount": "1",
        "X-MS-Exchange-AntiSpam-MessageData-0": "btF8Hl4mui7pFKKzpKKrewkpqlMwEZusPbSts9EZu6l2Y1z9X9n6f36PwMNFjQoMglvq6P6+hltOfLnIL9hjVuHoP2lG8bPnM9iDtEiUN3dTyqxPSgig/GgIwvaVgcJo2EVr95ic8UytL5+5eOuyLO7WZGWQmDVvukUwQTTs1D0HtcJPhwtd+/68moiSruGVoo+dgWY6DHOYvrE4vnjTnWaHuoPo23GLZZZ2SugMxdXcop2akKM0KpUgd9fjb8UJDH/0p1MQ7YwV4pVOJf/Ims1M7mbKFynM/If4SjH0Yo90v8cKV0dDOMRP70+pce1jxYFOrNfaNKT7wm+t6CJxdnqRQ0UJiNO3HPM0wV+vdwAyuCc6mR1sKuQjgKYi3nzaJ5H1mykTRRTaVeZfv0uaQzofaSm8xkU+Ut5/tenakd7NIEQg8NvG4Et2mFDat5A0xI4SOJN15seiGhLQvQNCt3HZZYFE7xT0xB9+6meF/FS+ybFWurUzjkPnhICZFyKDzI20AE2MVwXEPv/8rYUIUQ1cCCqz1DjUEcD9QyRuFU7QR+da/pStvUrzroj/njMeMJTGY5sv2I9h7eGhr7+AQq/MhZIiu4cjuUQOf6miWSU4ygZ1/kped1iZxkSEB7Pdn4GLd/cOpnwSM8fugBCjsy8AL33wtReRo0xqjnb9d+Q8KgmMB6H/1/Bpn5sSJFgAVevzXZm4YdHcrpRyacBprt/jekWGfE80TP/fCPxlCZ3ty/fF9L+kfEPsUs9ufRJlhQXepsopQW1JMYz82emg9vAp+RgKkkl7dev0p6yczOiPG58M/UqxAS7FYJLdL93oysrzoOg2S1W1qjcacpO8ZiVOxQ7kKSF6Tq644ZyoU0mOG6o6OBCsUuk0zV47HlWjGLDiLF3FRgFW1UvlbiypYd4N15hzRXOqIPcfDdBBlj6thCKIV1LUz38uCUbY555kKf1g806SJLb32v5KTQvrEAWP0WBG7ETe8Iieng0x88X7HtqVZjF8mb+bi0L5rID91+LvlbBi2CzqbvEX/0mtmQu49pWilTmNFICoF7xffSDNOmWfXuTu4OQWFj3MwFBOKrh/cIR6EcTF+YZGRaIYAYsAWnXsxBRMrr180x8bfMC/ohCEOwEblAS/EVXlQx5glmRjibIxPl6crPoewn4tHPxqp78vrLuneyAYTkjd6+KGwIL94HnwmCW+jHaQYxfI6h4WOKBhZ9uiN1ES9jKxI5V8lYk841UdvvfELPZ6KlKcjfMVh0C7ysZrK/nkUqlWPfqTqOgQeOJuosrSTR1DZ1JewdHv6OWrrGFiBS81YVbjdzidDM2n1WnpWzOQsIS0ERlf6QHgOnodyJ56waa/tsm9yu1TYpS0B6MnoG/YONpVg4Gf5dvSUP2IYSCoPOvmxcQQOybgxFD0r/kY5vHsz7JDLwmhrfoGcZJuo5z+7rd8QaHuUibBRniiNicJwIIalUro39W7Tlv2CDlmbxtgxkH8RJfyG39XRNep5BJuTZfwOYjAwgRk637efOQ6SqKcN0Sv9mGo1I8RUQLLE+eCfa9nD3hAjuY8osAgXYbeEY+MtBqkrYjdl+Y9sIM1JZJDFFTwKIxCRTMVOIqL4jiDX/O7e5NprhMLuLqXKY8DaUzh0O3sSc0dC4mVQBZmA8hoORBB0vJEjQU0Ky+1UE70zQ==",
        "X-OriginatorOrg": "oss.nxp.com",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "1092cc32-246a-40ce-11c8-08da91cad5e5",
        "X-MS-Exchange-CrossTenant-AuthSource": "PAXPR04MB8703.eurprd04.prod.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Internal",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "08 Sep 2022 18:49:18.6514\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": "70jmuE66fDy2Nrv96o8VyotLDKG63ZKmwstpx6tfc9Akqh0S192QhbAsmuw0iM7fZnx9gHwtbge4JE6aBbENCw==",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "AS8PR04MB8852",
        "Subject": "[libcamera-devel] [PATCH 04/14] libcamera: Declare generic size and\n\tformat converter interface",
        "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 via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>",
        "Reply-To": "Xavier Roumegue <xavier.roumegue@oss.nxp.com>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Declare a converter Abstract Base Class intented to provide generic\ninterfaces to hardware offering size and format conversion services on\nstreams. This is mainly based on the public interfaces of the current\nconverter class implementation found in the simple pipeline handler.\n\nThe main change is the introduction of load_configuration() method which\ncan be used by the concrete implementation to load hardware specific\nruntime parameters defined by the application.\n\nSigned-off-by: Xavier Roumegue <xavier.roumegue@oss.nxp.com>\n---\n include/libcamera/internal/converter.h | 101 ++++++++++++++++++++++++\n include/libcamera/internal/meson.build |   1 +\n src/libcamera/converter.cpp            | 102 +++++++++++++++++++++++++\n src/libcamera/meson.build              |   1 +\n 4 files changed, 205 insertions(+)\n create mode 100644 include/libcamera/internal/converter.h\n create mode 100644 src/libcamera/converter.cpp",
    "diff": "diff --git a/include/libcamera/internal/converter.h b/include/libcamera/internal/converter.h\nnew file mode 100644\nindex 00000000..e2237c57\n--- /dev/null\n+++ b/include/libcamera/internal/converter.h\n@@ -0,0 +1,101 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2020, Laurent Pinchart\n+ * Copyright 2022 NXP\n+ *\n+ * converter.h - Generic stream converter infrastructure\n+ */\n+\n+#pragma once\n+\n+#include <functional>\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+#include <libcamera/pixel_format.h>\n+\n+namespace libcamera {\n+\n+class FrameBuffer;\n+class MediaDevice;\n+class Size;\n+class SizeRange;\n+struct StreamConfiguration;\n+\n+class Converter\n+{\n+public:\n+\tConverter(MediaDevice *media);\n+\tvirtual ~Converter();\n+\tvirtual int loadConfiguration(const std::string &filename) = 0;\n+\n+\tvirtual bool isValid() const = 0;\n+\n+\tvirtual std::vector<PixelFormat> formats(PixelFormat input) = 0;\n+\tvirtual SizeRange sizes(const Size &input) = 0;\n+\n+\tvirtual std::tuple<unsigned int, unsigned int>\n+\tstrideAndFrameSize(const PixelFormat &pixelFormat, const Size &size) = 0;\n+\n+\tvirtual int configure(const StreamConfiguration &inputCfg,\n+\t\t\t      const std::vector<std::reference_wrapper<StreamConfiguration>> &outputCfg) = 0;\n+\tvirtual int exportBuffers(unsigned int ouput, unsigned int count,\n+\t\t\t\t  std::vector<std::unique_ptr<FrameBuffer>> *buffers) = 0;\n+\n+\tvirtual int start() = 0;\n+\tvirtual void stop() = 0;\n+\n+\tvirtual int queueBuffers(FrameBuffer *input,\n+\t\t\t\t const std::map<unsigned int, FrameBuffer *> &outputs) = 0;\n+\n+\tstd::string deviceNode_;\n+\tSignal<FrameBuffer *> inputBufferReady;\n+\tSignal<FrameBuffer *> outputBufferReady;\n+};\n+\n+class ConverterFactory\n+{\n+public:\n+\tConverterFactory(const std::string name);\n+\tvirtual ~ConverterFactory() = default;\n+\n+\tstatic std::unique_ptr<Converter> create(MediaDevice *media);\n+\n+\tstatic void registerType(ConverterFactory *factory);\n+\tstatic std::vector<ConverterFactory *> &factories();\n+\tstatic std::vector<std::string> names();\n+\n+protected:\n+\tvirtual Converter *createInstance(MediaDevice *media) = 0;\n+\tvirtual const std::vector<std::string> aliases() const = 0;\n+\n+private:\n+\tLIBCAMERA_DISABLE_COPY_AND_MOVE(ConverterFactory)\n+\n+\tstd::string name_;\n+};\n+\n+#define REGISTER_CONVERTER(name, converter, ...)                            \\\n+\tclass converter##Factory final : public ConverterFactory                \\\n+\t{                                                                       \\\n+\tpublic:                                                                 \\\n+\t\tconverter##Factory() : ConverterFactory(name) {}                    \\\n+                                                                            \\\n+\tprivate:                                                                \\\n+\t\tConverter *createInstance(MediaDevice *media)                       \\\n+\t\t{                                                                   \\\n+\t\t\treturn new converter(media);                                    \\\n+\t\t}                                                                   \\\n+\t\tstd::vector<std::string> aliases_ = { __VA_ARGS__ };                \\\n+\t\tconst std::vector<std::string> aliases() const { return aliases_; } \\\n+\t};                                                                      \\\n+\tstatic converter##Factory global_##converter##Factory;\n+\n+} /* namespace libcamera */\ndiff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build\nindex 7a780d48..8f50d755 100644\n--- a/include/libcamera/internal/meson.build\n+++ b/include/libcamera/internal/meson.build\n@@ -19,6 +19,7 @@ libcamera_internal_headers = files([\n     'camera_sensor_properties.h',\n     'control_serializer.h',\n     'control_validator.h',\n+    'converter.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\nnew file mode 100644\nindex 00000000..89a594d1\n--- /dev/null\n+++ b/src/libcamera/converter.cpp\n@@ -0,0 +1,102 @@\n+\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 <algorithm>\n+\n+#include <libcamera/base/log.h>\n+\n+#include \"libcamera/internal/converter.h\"\n+#include \"libcamera/internal/media_device.h\"\n+\n+namespace libcamera {\n+\n+LOG_DEFINE_CATEGORY(Converter)\n+\n+Converter::Converter(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\treturn;\n+\n+\tdeviceNode_ = (*it)->deviceNode();\n+}\n+\n+Converter::~Converter()\n+{\n+}\n+\n+ConverterFactory::ConverterFactory(const std::string name)\n+\t: name_(name)\n+{\n+\tregisterType(this);\n+}\n+\n+std::unique_ptr<Converter> ConverterFactory::create(MediaDevice *media)\n+{\n+\tstd::vector<ConverterFactory *> &factories =\n+\t\tConverterFactory::factories();\n+\n+\tfor (ConverterFactory *factory : factories) {\n+\t\tstd::vector<std::string> aliases = factory->aliases();\n+\t\tauto it = std::find(aliases.begin(), aliases.end(), media->driver());\n+\n+\t\tif (it == aliases.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 == aliases.end() ? \"no\" : media->driver()) << \" alias.\";\n+\n+\t\tConverter *converter = factory->createInstance(media);\n+\t\treturn std::unique_ptr<Converter>(converter);\n+\t}\n+\n+\treturn nullptr;\n+}\n+\n+void ConverterFactory::registerType(ConverterFactory *factory)\n+{\n+\tstd::vector<ConverterFactory *> &factories =\n+\t\tConverterFactory::factories();\n+\n+\tfactories.push_back(factory);\n+}\n+\n+std::vector<std::string> ConverterFactory::names()\n+{\n+\tstd::vector<std::string> list;\n+\n+\tstd::vector<ConverterFactory *> &factories =\n+\t\tConverterFactory::factories();\n+\n+\tfor (ConverterFactory *factory : factories) {\n+\t\tlist.push_back(factory->name_);\n+\t\tfor (auto alias : factory->aliases())\n+\t\t\tlist.push_back(alias);\n+\t}\n+\n+\treturn list;\n+}\n+\n+std::vector<ConverterFactory *> &ConverterFactory::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<ConverterFactory *> factories;\n+\treturn factories;\n+}\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\nindex 63b47b17..a261d4b4 100644\n--- a/src/libcamera/meson.build\n+++ b/src/libcamera/meson.build\n@@ -13,6 +13,7 @@ libcamera_sources = files([\n     'controls.cpp',\n     'control_serializer.cpp',\n     'control_validator.cpp',\n+    'converter.cpp',\n     'delayed_controls.cpp',\n     'device_enumerator.cpp',\n     'device_enumerator_sysfs.cpp',\n",
    "prefixes": [
        "libcamera-devel",
        "04/14"
    ]
}