Patch Detail
Show a patch.
GET /api/1.1/patches/17356/?format=api
{ "id": 17356, "url": "https://patchwork.libcamera.org/api/1.1/patches/17356/?format=api", "web_url": "https://patchwork.libcamera.org/patch/17356/", "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-15-xavier.roumegue@oss.nxp.com>", "date": "2022-09-08T18:48:50", "name": "[libcamera-devel,14/14] libcamera: pipeline: rkisp1: Add converter support", "commit_ref": null, "pull_url": null, "state": "changes-requested", "archived": false, "hash": "c9efe8483ac3fe629bb718f11e0aa5c6bc0d8c56", "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/17356/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/17356/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/17356/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 A1D43C327F\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 8 Sep 2022 18:49:31 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 58795620EF;\n\tThu, 8 Sep 2022 20:49:31 +0200 (CEST)", "from EUR04-DB3-obe.outbound.protection.outlook.com\n\t(mail-eopbgr60060.outbound.protection.outlook.com [40.107.6.60])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4FFF9620D7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 8 Sep 2022 20:49:24 +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:22 +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:22 +0000" ], "DKIM-Signature": [ "v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1662662971;\n\tbh=m2ynyg7TqtczJaJAHD82Ze/daVvJ7iGwmFeJmDIk1vw=;\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=BrHZ1HPjl84FL6ls3/4OufHPWfkUkLf7BT9zfpNwavAYhGivkYilB+MDFLSryBDrK\n\t4s0oIVl+wSYOLoGxxl8ZNOZsCXaDyeigUlm0XQY3XMdn6NBLwJhTBa/KtyRW97e/Ar\n\tJv1wXCuKigJWuwh29trjdaC4BVNsIo0+q1939kcOKQ6KDJSn9kQrLCbf1u/aT++uU2\n\t6X0ol07xJqhxyjGDdgxClCRHS+QNYmltU2+EWTZ9iXleyUZITj686RvYx6Fv/LKzv2\n\tvGbN5328apDLaGrGVl0RumzPQrJjOx1oN2700rw295GIhHmNgFdBHp5dpBWn/OvaCg\n\tP8UhPiJIFc7Ig==", "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=I0tyVzsP57ZnCFW+9pOhH2unE9htnH3rC/5FYI2a+ss=;\n\tb=SceOCB9zpltKja/o3rLVVZQPQKTg0H1Yz51J19AOk0kjAtN+Ce6p/sMxEZJSDOU7VbUOb5hKFs8hYo9tnjjqbV9ZC3ucHn5w/pYV1gFFxlcqLKFVkhAy28w89nwd5YGnyeF7lZSGu6dmmhxpMzOJ7rmh6HeUKNN/Q4kiNYEa5oI=" ], "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=\"SceOCB9z\"; 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=KXBw07QCESiu1Ieya0wIOwDZeExXRZpn/mcSWQzuiY2ESBlxxj0n375FJwbceKFhldii8VN3hapIWzP8hhqvLvwaP3zCmCzE6sjWgvRaGKsH2+8lvEdJKPu/qB3veGwBM6burSrkWPb90ki9NKn3G3/p0z0syRYC/ggo5JXwv5ocLWqVOJxAwdVmKUsg76cgIreLwE14956Om/bojqAnPJOdCYcu9qxhmelKgF+jAGz8NJ+hdUlap3AUFy9Oc8U8hb4YKE1iRDhDlf6TGLvwBzdq+WvgGUIx6NWJ3VJWPDWS3q2p2d6L85CzQ/aq2GwWQILftmPJGfw4DUqaXt077A==", "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=I0tyVzsP57ZnCFW+9pOhH2unE9htnH3rC/5FYI2a+ss=;\n\tb=ctSAn7mM+7Doh5G3TH4A3cLR6ti9EbRyQORjRriVMaPwdOhHeLapwuCeFDrZzVpO6FbG5FBSUofjGkOLmHQMljZSA0mmtnZt14wnpHIB4SD/pyGycW+9td0jIBzePY9+LMk6brxJU3DuXt4f1BRiqKdmjt6C9z8qio4rBScMx6zgNPMvtN5B+wG9uqf+uRu3skYo4jK8WpOPLPdF5DsSARwUKln4qLcja7VEJSur7338l81lSXg1v5IniEHVs+NLgTbf1d8yGn7zU+BE9FwJutGRDx+Fr9KIhdd0LDVtQRm+XtdLV+lTh1VHEIqeGxEYzT9lUvjSsdeL52aEmTgByg==", "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:50 +0200", "Message-Id": "<20220908184850.1874303-15-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": "65958e69-c80f-438b-40cf-08da91cad848", "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": "+CotIftFeazBBQxG9dKl42Umv3StQac4kOkImFma1iiEuZivkyGYeeg0Yri7Szv1mkPybxONj9SWmSqmniw/SupwwsvjKih42XdeGTIgnKFx0bofHanK3NQs8oLHek/c4c/DfldaPFGaa049b+C+q1vQa9wfiFm+1q0hm6+vzOyTfTE88p0/3i7dNiu6HXqhlAGVvXGI+s97JRwERes8THNjyw5nA5CLYsiDpQjQUeb+HSspzjzmf5Ww9hBhKQFuAxilDx3Q/OSsvSJ68WI3oa1z6xo0Pheriim2quB/fBYPXYTF97D2SPSYL6lWqcBtJFOCna1U86/pyWnNRXiXNaThK/L+2f+HdA3QFBQpbKoMFVUEoz0m+Vkp2tc69nRgCzquVRjuZy1CWKasbBfmwHbmmUpDtWygWB8EsB467SKJ06umvX1VXfm9n8McBZDb4cSps7IKjagXtiRHYLj/H0YAQSdzavjoGrFXUf+ahLa6WlCLSPwnk9egn0SgsDeYX9CzYcLsOIBLciODJGOvA/n3crjzP3bruMEmAmINWE1P7x/vf1Z9AKvD8T/dOEDPt3tA4IqdbFEqXl/qna/3bvv9xffjQowXUNN+SsOoIIWSP9JHw0SV1IeYAlgd/eDjHseydVBjvKDZ52cuYOCtgTrZ0+8Y3G9mM/ncBTauZ4ZYqzoYd83H38YkwCphwSSH5bAVg25CPxnCOAJEWfgbIJKuK8ZkMF0jBzYeDGBuOBs580fFMZqK8n9GQQbnOfb+nDitoYK/B2shmEosLvmSMQ==", "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)(30864003)(44832011)(5660300002)(4326008)(8676002)(6916009)(316002)(41300700001)(186003)(1076003)(2616005)(2906002)(478600001)(6666004)(86362001)(6512007)(52116002)(6506007)(83380400001)(6486002)(309714004);\n\tDIR:OUT; SFP:1101; ", "X-MS-Exchange-AntiSpam-MessageData-ChunkCount": "1", "X-MS-Exchange-AntiSpam-MessageData-0": "OFZU2NbpIk1qnfPMJJHbw+yLg6cFFF4fdKQ/HKEW8JXaB6t8MO5eluMYSyrMb1gPN6lmXsmNDWTPqxGrbe+yI7LhJG4Cq87WV3Kyi2WA0BcSdoEPCuqXgaBMGvmmwN/7Tgg4fsEPCGtzkczVayVipCDkF1NFdUkuV3UMxxqRclxS/OFQyVjTk4ANBOV7wpjOLteU2wjZk8LpnYWVb/HscqFMygFIuiE/8t1dpRNy8q7rdwawB7lB/HgN2wz6geaIwS847VA2WU5QYxax801y4pL1mIZfA4jhZipg2iahpVsOoMBtv2MrPw9rFS5ocqBNYynLZzxIxjRUJmZl2a3QVkrJfaWFRV4QTpf/P5rdxHxKE2C8CMgVdjJFWJtyqJvH5Vikb8r4bx0nZVld7xCmvYfM2FdQCqvcnEhFF0OP1wIZ/UBBvuM7km2YMpQdHsZWUaW0etxDW6Iijca338ROu1N/DLeQK+NKx8r0q10GkHlI+EqMURfYSqsPQrRfbU3fWKMz/VbuUbMW81xqLvJXZH0xPi47Vkd5biX10CRcWNrtVVmUkI9Kr8+naH/qTwh2/SmKW8UXcoqMvn3N6KGxpn/O6AOfrjdhBteGdfuEsGGyUVHJiL+zS2qjaUk0yfXjNOJE0dNr8Vb0e7+1sY9S4fHw90zs1jIwPA43FST9v/05JAv+1HbjvQuCyB2ggX5cEwyXJdpRSVjZFK/uKqZ8DDEsJOszHrtNqTIVeMCnfGeL51cj6rHSpnV7IxvHAUT3sbpuKOMFZiVaqQHqaskISL/cwaHpHemWwysNxBvBhGiP1dFV6Qf/LcYVJDGtFA0pDV0T41sAY+zqX0vJfAmLzzi1y2ujKCIB9khA/9OORxWUHwbD4rQhozsTSNn3hxniLLPAb4GKaEdwH3v4e+up0dkWXq3K40sNstjtgFjX9K0BckpVYfv9m+8ZeWMpkCvTWkPjNzDE7JIldZuRcNWfnFDv1WVBUMdU+3xYjR8YDG+WwSLBe3G+FNNzXcNEdU14pDPKFXb8o63Pp4TCE5OE64g3e0usWvESEKEfLXxV/V9+kpm9gbZjP6oKIa3/2+T2WkSI8/Xl87B24k9z+E2hS4zVyHwPOe4iS/Jb5V/cMUMQ3U9NP5UWiBlDcM16mUZq6nUXIRTFqf1wQ6ssie2Al3j0rrr7LMjqaZio+QFKUiGoxjy+5B/gpU4B23tXa6RMb99JHcN85/vT2XvBY0w0F+IckChWvhb7ha1wi/28zAVenZrWAy2z4aWrFij2UGTJJQaognpeVQx6C3fwkNWULEqk2x+o7+3QrPQHl5Xh2wICQn92hRpFuQhr9ruvKNBNOz8t1Vx0VSwkFUSXXSzd19lu0rn4YYIR6fC7s/vtWtwAIPsIfbR8HJfSXcZdnI0tAqLxC1I2ZoiEnXnVBcPagTt8hoKTJmzdWNeURsPKUTucz8Bn5+df4sSOwpivFgKWYtA6Q8ZaU2uAJPXa8APQMJlPIAhhknufuV2hNn3XNQe7lNN6IliU9CSpqi/I5zMNAW2Vd/goaUq52WGgv2AIOsn1LsHRovfHosdA5LTfe1d6rfpqaFhWLB51LQhrrTFAjCo4zivAFYt1ADYmP2+459WYHMOWXmsqalXJYTUCS1O6x5D/ZksJXNmPRAYt10y2pP8RFQmgYg1jkjX3dK6BNA==", "X-OriginatorOrg": "oss.nxp.com", "X-MS-Exchange-CrossTenant-Network-Message-Id": "65958e69-c80f-438b-40cf-08da91cad848", "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:22.5943\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": "3IpoPMeeSm3gY/5ZWj81EB/7ya9lWcbVDrCHDadBxgrVN8py7tJIKkLzDFUFAIoPxgsDEFHHikiVGK1L7mjWLA==", "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "AS8PR04MB8852", "Subject": "[libcamera-devel] [PATCH 14/14] libcamera: pipeline: rkisp1: Add\n\tconverter support", "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": "This adds a converter, if any present in the system, on each streams\n(self and main paths). In case a configuration file is successfully\nloaded, the converter use is getting compulsory, such as a dewarping map\nis unconditionally applied. Otherwise, the converter is only used if the\nstream configuration requires it.\n\nSigned-off-by: Xavier Roumegue <xavier.roumegue@oss.nxp.com>\n---\n src/libcamera/pipeline/rkisp1/rkisp1.cpp | 126 +++---\n src/libcamera/pipeline/rkisp1/rkisp1_path.cpp | 374 +++++++++++++++++-\n src/libcamera/pipeline/rkisp1/rkisp1_path.h | 54 ++-\n 3 files changed, 485 insertions(+), 69 deletions(-)", "diff": "diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\nindex c1522ca6..6bdf5a3a 100644\n--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n@@ -1,6 +1,7 @@\n /* SPDX-License-Identifier: LGPL-2.1-or-later */\n /*\n * Copyright (C) 2019, Google Inc.\n+ * Copyright 2022 NXP\n *\n * rkisp1.cpp - Pipeline handler for Rockchip ISP1\n */\n@@ -194,6 +195,7 @@ private:\n \tCamera *activeCamera_;\n \n \tconst MediaPad *ispSink_;\n+\tMediaDevice *converter_;\n };\n \n RkISP1Frames::RkISP1Frames(PipelineHandler *pipe)\n@@ -449,57 +451,44 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n \n \tbool mainPathAvailable = true;\n \tbool selfPathAvailable = data_->selfPath_;\n+\tconst std::array<Status, 2> cameraStatus = { Valid, Adjusted };\n+\n \tfor (unsigned int index : order) {\n \t\tStreamConfiguration &cfg = config_[index];\n \n-\t\t/* Try to match stream without adjusting configuration. */\n-\t\tif (mainPathAvailable) {\n-\t\t\tStreamConfiguration tryCfg = cfg;\n-\t\t\tif (data_->mainPath_->validate(&tryCfg) == Valid) {\n-\t\t\t\tmainPathAvailable = false;\n-\t\t\t\tcfg = tryCfg;\n-\t\t\t\tcfg.setStream(const_cast<Stream *>(&data_->mainPathStream_));\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t}\n+\t\tfor (auto &_status : cameraStatus) {\n+\t\t\tStatus pipeStatus;\n \n-\t\tif (selfPathAvailable) {\n-\t\t\tStreamConfiguration tryCfg = cfg;\n-\t\t\tif (data_->selfPath_->validate(&tryCfg) == Valid) {\n-\t\t\t\tselfPathAvailable = false;\n-\t\t\t\tcfg = tryCfg;\n-\t\t\t\tcfg.setStream(const_cast<Stream *>(&data_->selfPathStream_));\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t}\n+\t\t\tif (mainPathAvailable) {\n+\t\t\t\tStreamConfiguration tryCfg = cfg;\n+\t\t\t\tpipeStatus = data_->mainPath_->validate(&tryCfg);\n \n-\t\t/* Try to match stream allowing adjusting configuration. */\n-\t\tif (mainPathAvailable) {\n-\t\t\tStreamConfiguration tryCfg = cfg;\n-\t\t\tif (data_->mainPath_->validate(&tryCfg) == Adjusted) {\n-\t\t\t\tmainPathAvailable = false;\n-\t\t\t\tcfg = tryCfg;\n-\t\t\t\tcfg.setStream(const_cast<Stream *>(&data_->mainPathStream_));\n-\t\t\t\tstatus = Adjusted;\n-\t\t\t\tcontinue;\n+\t\t\t\tif (pipeStatus == _status) {\n+\t\t\t\t\tmainPathAvailable = false;\n+\t\t\t\t\tcfg = tryCfg;\n+\t\t\t\t\tcfg.setStream(const_cast<Stream *>(&data_->mainPathStream_));\n+\t\t\t\t\tstatus = _status;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n \t\t\t}\n-\t\t}\n \n-\t\tif (selfPathAvailable) {\n-\t\t\tStreamConfiguration tryCfg = cfg;\n-\t\t\tif (data_->selfPath_->validate(&tryCfg) == Adjusted) {\n-\t\t\t\tselfPathAvailable = false;\n-\t\t\t\tcfg = tryCfg;\n-\t\t\t\tcfg.setStream(const_cast<Stream *>(&data_->selfPathStream_));\n-\t\t\t\tstatus = Adjusted;\n-\t\t\t\tcontinue;\n+\t\t\tif (selfPathAvailable) {\n+\t\t\t\tStreamConfiguration tryCfg = cfg;\n+\t\t\t\tpipeStatus = data_->selfPath_->validate(&tryCfg);\n+\n+\t\t\t\tif (pipeStatus == _status) {\n+\t\t\t\t\tselfPathAvailable = false;\n+\t\t\t\t\tcfg = tryCfg;\n+\t\t\t\t\tcfg.setStream(const_cast<Stream *>(&data_->selfPathStream_));\n+\t\t\t\t\tstatus = _status;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n \t\t\t}\n+\t\t\t/* All paths rejected configuration. */\n+\t\t\tLOG(RkISP1, Debug) << \"Camera configuration not supported \"\n+\t\t\t\t\t << cfg.toString();\n+\t\t\treturn Invalid;\n \t\t}\n-\n-\t\t/* All paths rejected configuraiton. */\n-\t\tLOG(RkISP1, Debug) << \"Camera configuration not supported \"\n-\t\t\t\t << cfg.toString();\n-\t\treturn Invalid;\n \t}\n \n \t/* Select the sensor format. */\n@@ -680,15 +669,21 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)\n \n \tstd::map<unsigned int, IPAStream> streamConfig;\n \n-\tfor (const StreamConfiguration &cfg : *config) {\n+\tfor (StreamConfiguration &cfg : *config) {\n+\t\tsize_t idx = 0;\n+\t\tStreamConfiguration internalCfg;\n \t\tif (cfg.stream() == &data->mainPathStream_) {\n+\t\t\tidx = 0;\n \t\t\tret = mainPath_.configure(cfg, format);\n-\t\t\tstreamConfig[0] = IPAStream(cfg.pixelFormat,\n-\t\t\t\t\t\t cfg.size);\n+\t\t\tinternalCfg = mainPath_.internalStream();\n+\t\t\tstreamConfig[idx] = IPAStream(internalCfg.pixelFormat,\n+\t\t\t\t\t\t internalCfg.size);\n \t\t} else if (hasSelfPath_) {\n+\t\t\tidx = 1;\n \t\t\tret = selfPath_.configure(cfg, format);\n-\t\t\tstreamConfig[1] = IPAStream(cfg.pixelFormat,\n-\t\t\t\t\t\t cfg.size);\n+\t\t\tinternalCfg = selfPath_.internalStream();\n+\t\t\tstreamConfig[idx] = IPAStream(internalCfg.pixelFormat,\n+\t\t\t\t\t\t internalCfg.size);\n \t\t} else {\n \t\t\treturn -ENODEV;\n \t\t}\n@@ -754,6 +749,20 @@ int PipelineHandlerRkISP1::allocateBuffers(Camera *camera)\n \t\tdata->selfPathStream_.configuration().bufferCount,\n \t});\n \n+\tif (data->mainPath_->isEnabled()) {\n+\t\tret = data->mainPath_->allocateBuffers(\n+\t\t\tdata->mainPathStream_.configuration().bufferCount);\n+\t\tif (ret < 0)\n+\t\t\tgoto error;\n+\t}\n+\n+\tif (hasSelfPath_ && data->selfPath_->isEnabled()) {\n+\t\tret = data->selfPath_->allocateBuffers(\n+\t\t\tdata->selfPathStream_.configuration().bufferCount);\n+\t\tif (ret < 0)\n+\t\t\tgoto error;\n+\t}\n+\n \tret = param_->allocateBuffers(maxCount, ¶mBuffers_);\n \tif (ret < 0)\n \t\tgoto error;\n@@ -813,6 +822,12 @@ int PipelineHandlerRkISP1::freeBuffers(Camera *camera)\n \tif (stat_->releaseBuffers())\n \t\tLOG(RkISP1, Error) << \"Failed to release stat buffers\";\n \n+\tif (hasSelfPath_ && data->selfPath_->isEnabled())\n+\t\tdata->selfPath_->releaseBuffers();\n+\n+\tif (data->mainPath_->isEnabled())\n+\t\tdata->mainPath_->releaseBuffers();\n+\n \treturn 0;\n }\n \n@@ -1055,6 +1070,19 @@ bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator)\n \n \thasSelfPath_ = !!media_->getEntityByName(\"rkisp1_selfpath\");\n \n+\t/* Seek for a converter */\n+\tfor (auto converterName : ConverterFactory::names()) {\n+\t\tLOG(RkISP1, Debug)\n+\t\t\t<< \"Trying \" << converterName << \" converter\";\n+\t\tDeviceMatch converterMatch(converterName);\n+\t\tconverter_ = acquireMediaDevice(enumerator, converterMatch);\n+\t\tif (converter_) {\n+\t\t\tLOG(RkISP1, Debug)\n+\t\t\t\t<< \"Get support for \" << converterName << \" converter\";\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n \t/* Create the V4L2 subdevices we will need. */\n \tisp_ = V4L2Subdevice::fromEntityName(media_, \"rkisp1_isp\");\n \tif (isp_->open() < 0)\n@@ -1086,10 +1114,10 @@ bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator)\n \t\treturn false;\n \n \t/* Locate and open the ISP main and self paths. */\n-\tif (!mainPath_.init(media_))\n+\tif (!mainPath_.init(media_, converter_))\n \t\treturn false;\n \n-\tif (hasSelfPath_ && !selfPath_.init(media_))\n+\tif (hasSelfPath_ && !selfPath_.init(media_, converter_))\n \t\treturn false;\n \n \tmainPath_.bufferReady().connect(this, &PipelineHandlerRkISP1::bufferReady);\ndiff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\nindex 2d38f0fb..c19a1e69 100644\n--- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n+++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp\n@@ -1,6 +1,7 @@\n /* SPDX-License-Identifier: LGPL-2.1-or-later */\n /*\n * Copyright (C) 2020, Google Inc.\n+ * Copyright 2022 NXP\n *\n * rkisp1path.cpp - Rockchip ISP1 path helper\n */\n@@ -28,7 +29,46 @@ RkISP1Path::RkISP1Path(const char *name, const Span<const PixelFormat> &formats,\n {\n }\n \n-bool RkISP1Path::init(MediaDevice *media)\n+void RkISP1Path::initConverter(MediaDevice *mediaConverter)\n+{\n+\thasConverter_ = false;\n+\tuseConverter_ = false;\n+\n+\tif (!mediaConverter)\n+\t\treturn;\n+\n+\tconverter_ = ConverterFactory::create(mediaConverter);\n+\n+\tif (!converter_->isValid()) {\n+\t\tLOG(RkISP1, Warning)\n+\t\t\t<< \"Failed to create converter, disabling format conversion\";\n+\t\tconverter_.reset();\n+\t} else {\n+\t\tchar const *configFromEnv = utils::secure_getenv(\"LIBCAMERA_RKISP1_CONVERTER_FILE\");\n+\n+\t\tif (configFromEnv && *configFromEnv != '\\0') {\n+\t\t\tint nrMappings;\n+\t\t\tLOG(RkISP1, Debug)\n+\t\t\t\t<< \"Getting pipeline converter filename as \" << std::string(configFromEnv);\n+\t\t\tnrMappings = converter_->loadConfiguration(std::string(configFromEnv));\n+\t\t\tif (nrMappings < 0) {\n+\t\t\t\tLOG(RkISP1, Error)\n+\t\t\t\t\t<< \"Error while reading converter configuration file\";\n+\t\t\t} else {\n+\t\t\t\tLOG(RkISP1, Debug)\n+\t\t\t\t\t<< nrMappings << \" mapping(s) loaded\";\n+\t\t\t\tif (nrMappings > 0)\n+\t\t\t\t\t/* We want to force the converter use to apply the mapping */\n+\t\t\t\t\tuseConverter_ = true;\n+\t\t\t}\n+\t\t}\n+\t\tconverter_->inputBufferReady.connect(this, &RkISP1Path::pathConverterInputDone);\n+\t\tconverter_->outputBufferReady.connect(this, &RkISP1Path::pathConverterOutputDone);\n+\t\thasConverter_ = true;\n+\t}\n+}\n+\n+bool RkISP1Path::init(MediaDevice *media, MediaDevice *mediaConverter)\n {\n \tstd::string resizer = std::string(\"rkisp1_resizer_\") + name_ + \"path\";\n \tstd::string video = std::string(\"rkisp1_\") + name_ + \"path\";\n@@ -45,10 +85,13 @@ bool RkISP1Path::init(MediaDevice *media)\n \tif (!link_)\n \t\treturn false;\n \n+\tinitConverter(mediaConverter);\n+\n+\tvideo_->bufferReady.connect(this, &RkISP1Path::pathBufferReady);\n+\n \treturn true;\n }\n-\n-StreamConfiguration RkISP1Path::generateConfiguration(const Size &resolution)\n+StreamConfiguration RkISP1Path::generateNativeConfiguration(const Size &resolution)\n {\n \tSize maxResolution = maxResolution_.boundedToAspectRatio(resolution)\n \t\t\t\t\t .boundedTo(resolution);\n@@ -67,7 +110,165 @@ StreamConfiguration RkISP1Path::generateConfiguration(const Size &resolution)\n \treturn cfg;\n }\n \n-CameraConfiguration::Status RkISP1Path::validate(StreamConfiguration *cfg)\n+StreamConfiguration RkISP1Path::generateConfiguration(const Size &resolution)\n+{\n+\tStreamConfiguration cfg = generateNativeConfiguration(resolution);\n+\tStreamFormats formats = cfg.formats();\n+\tstd::map<PixelFormat, std::vector<SizeRange>> fullFormats;\n+\n+\tfor (const PixelFormat &fmt : formats.pixelformats()) {\n+\t\tConfiguration config;\n+\t\tSizeRange szRange;\n+\n+\t\tconfig.inputFormat = fmt;\n+\t\tconfig.inputSizes = formats.range(fmt);\n+\n+\t\tif (!useConverter_) {\n+\t\t\tconfig.outputFormats.push_back(fmt);\n+\t\t\tconfig.outputSizes = config.inputSizes;\n+\t\t\tconfig.withConverter = false;\n+\t\t\tconfigs_.push_back(config);\n+\t\t\tLOG(RkISP1, Debug)\n+\t\t\t\t<< \"Pushing native format \" << fmt\n+\t\t\t\t<< \" resolution range \" << config.inputSizes;\n+\t\t\tfullFormats[fmt].push_back(config.inputSizes);\n+\t\t}\n+\n+\t\tif (hasConverter_) {\n+\t\t\tconfig.outputFormats = converter_->formats(config.inputFormat);\n+\t\t\tif (config.outputFormats.empty())\n+\t\t\t\tcontinue;\n+\t\t\tszRange.max = converter_->sizes(config.inputSizes.max).max;\n+\t\t\tszRange.min = converter_->sizes(config.inputSizes.min).min;\n+\t\t\tconfig.outputSizes = szRange;\n+\t\t\tconfig.withConverter = true;\n+\t\t\tconfigs_.push_back(config);\n+\t\t\tfor (auto &_fmt : config.outputFormats) {\n+\t\t\t\tfullFormats[_fmt].push_back(config.outputSizes);\n+\t\t\t\tLOG(RkISP1, Debug)\n+\t\t\t\t\t<< \"Pushing converted format \" << _fmt\n+\t\t\t\t\t<< \" resolution range \" << config.outputSizes;\n+\t\t\t}\n+\t\t}\n+\t}\n+\t/*\n+\t * Sort the sizes and merge any consecutive overlapping ranges.\n+\t * Imported from src/libcamera/pipeline/simple.cpp\n+\t *\n+\t * TODO: Apply policy of converter use or not.. We likely want to force\n+\t * the converter use in case there is a mapping defined in the\n+\t * configuration file if any... if so, shall we filter out resolution\n+\t * not defined in the configuration file.. or should this policy be let\n+\t * to the application\n+\t * */\n+\n+\tfor (auto &[format, sizes] : fullFormats) {\n+\t\tstd::sort(sizes.begin(), sizes.end(),\n+\t\t\t [](SizeRange &a, SizeRange &b) {\n+\t\t\t\t return a.min < b.min;\n+\t\t\t });\n+\n+\t\tauto cur = sizes.begin();\n+\t\tauto next = cur;\n+\n+\t\twhile (++next != sizes.end()) {\n+\t\t\tif (cur->max.width >= next->min.width &&\n+\t\t\t cur->max.height >= next->min.height)\n+\t\t\t\tcur->max = next->max;\n+\t\t\telse if (++cur != next)\n+\t\t\t\t*cur = *next;\n+\t\t}\n+\n+\t\tsizes.erase(++cur, sizes.end());\n+\t}\n+\n+\tStreamConfiguration fullCfg{ StreamFormats{ fullFormats } };\n+\tfullCfg.pixelFormat = fullFormats.begin()->first;\n+\tfullCfg.size = fullFormats.begin()->second[0].max;\n+\tfullCfg.bufferCount = cfg.bufferCount;\n+\n+\treturn fullCfg;\n+}\n+\n+CameraConfiguration::Status RkISP1Path::getPipeConfiguration(\n+\tStreamConfiguration &streamCfg,\n+\tconst RkISP1Path::Configuration **cfg) const\n+{\n+\tCameraConfiguration::Status _status = CameraConfiguration::Adjusted;\n+\n+\tLOG(RkISP1, Debug)\n+\t\t<< \"Looking for \"\n+\t\t<< streamCfg.pixelFormat << \"/\" << streamCfg.size\n+\t\t<< \" output configuration\";\n+\t/*\n+\t * Select the fallback configuration\n+\t */\n+\tfor (auto &_cfg : configs_) {\n+\t\tif (_cfg.withConverter == useConverter_) {\n+\t\t\t*cfg = &_cfg;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tPixelFormat pixelFormat = (*cfg)->outputFormats.front();\n+\tSize size = streamCfg.size;\n+\tsize.boundTo((*cfg)->outputSizes.max);\n+\tsize.expandTo((*cfg)->outputSizes.min);\n+\n+\t/* Unless the converter use is enforced through a loaded configuration,\n+\t * prefer a configuration without the converter if possible\n+\t */\n+\tstd::vector<bool> converterUse;\n+\tif (!useConverter_)\n+\t\tconverterUse.push_back(false);\n+\tif (hasConverter_)\n+\t\tconverterUse.push_back(true);\n+\n+\tfor (auto withConverter : converterUse) {\n+\t\tfor (auto &_cfg : configs_) {\n+\t\t\tauto &outFmts = _cfg.outputFormats;\n+\t\t\tif (withConverter != _cfg.withConverter)\n+\t\t\t\tcontinue;\n+\n+\t\t\tif ((std::find(outFmts.begin(),\n+\t\t\t\t outFmts.end(),\n+\t\t\t\t streamCfg.pixelFormat)) == outFmts.end())\n+\t\t\t\tcontinue;\n+\n+\t\t\t*cfg = &_cfg;\n+\t\t\tpixelFormat = streamCfg.pixelFormat;\n+\n+\t\t\tif (_cfg.outputSizes.contains(streamCfg.size)) {\n+\t\t\t\t_status = CameraConfiguration::Valid;\n+\t\t\t\tgoto done;\n+\t\t\t}\n+\n+\t\t\tsize.boundTo((*cfg)->outputSizes.max);\n+\t\t\tsize.expandTo((*cfg)->outputSizes.min);\n+\t\t}\n+\t}\n+\n+\tstreamCfg.pixelFormat = pixelFormat;\n+\tstreamCfg.size = size;\n+\n+done:\n+\tif ((*cfg)->withConverter) {\n+\t\tstd::tie(streamCfg.stride, streamCfg.frameSize) =\n+\t\t\tconverter_->strideAndFrameSize(streamCfg.pixelFormat,\n+\t\t\t\t\t\t streamCfg.size);\n+\t\tif (streamCfg.stride == 0)\n+\t\t\treturn CameraConfiguration::Invalid;\n+\t}\n+\n+\tLOG(RkISP1, Debug)\n+\t\t<< \"Chosen configuration: \"\n+\t\t<< (*cfg)->inputFormat << \"/\" << (*cfg)->inputSizes\n+\t\t<< \" --> \" << streamCfg.pixelFormat << \"/\" << streamCfg.size\n+\t\t<< ((*cfg)->withConverter ? \" with\" : \" without\") << \" converter\";\n+\treturn _status;\n+}\n+\n+CameraConfiguration::Status RkISP1Path::nativeValidate(StreamConfiguration *cfg)\n {\n \tconst StreamConfiguration reqCfg = *cfg;\n \tCameraConfiguration::Status status = CameraConfiguration::Valid;\n@@ -101,7 +302,39 @@ CameraConfiguration::Status RkISP1Path::validate(StreamConfiguration *cfg)\n \treturn status;\n }\n \n-int RkISP1Path::configure(const StreamConfiguration &config,\n+CameraConfiguration::Status RkISP1Path::validate(StreamConfiguration *cfg)\n+{\n+\tStreamConfiguration tryCfg = *cfg;\n+\tStreamConfiguration internalCfg;\n+\tconst Configuration *pipeCfg;\n+\tCameraConfiguration::Status pipeStatus;\n+\n+\tpipeStatus = getPipeConfiguration(tryCfg, &pipeCfg);\n+\tif (pipeStatus == CameraConfiguration::Invalid)\n+\t\treturn CameraConfiguration::Invalid;\n+\n+\tif (!pipeCfg->withConverter) {\n+\t\ttryCfg = *cfg;\n+\t\tpipeStatus = nativeValidate(&tryCfg);\n+\t\tif (pipeStatus == CameraConfiguration::Invalid)\n+\t\t\treturn CameraConfiguration::Invalid;\n+\t\tinternalCfg = tryCfg;\n+\t} else {\n+\t\tinternalCfg = tryCfg;\n+\t\tinternalCfg.pixelFormat = pipeCfg->inputFormat;\n+\t\tauto _status = nativeValidate(&internalCfg);\n+\t\tif (_status == CameraConfiguration::Invalid)\n+\t\t\treturn CameraConfiguration::Invalid;\n+\t}\n+\n+\t*cfg = tryCfg;\n+\tinternalStream_ = internalCfg;\n+\tpipeConfig_ = pipeCfg;\n+\n+\treturn pipeStatus;\n+}\n+\n+int RkISP1Path::nativeConfigure(const StreamConfiguration &config,\n \t\t\t const V4L2SubdeviceFormat &inputFormat)\n {\n \tint ret;\n@@ -165,6 +398,117 @@ int RkISP1Path::configure(const StreamConfiguration &config,\n \treturn 0;\n }\n \n+int RkISP1Path::configure(const StreamConfiguration &config,\n+\t\t\t const V4L2SubdeviceFormat &inputFormat)\n+{\n+\tint ret;\n+\tLOG(RkISP1, Debug)\n+\t\t<< \"Configuring \" << name_ << \" path \"\n+\t\t<< internalStream_.pixelFormat << \"/\" << internalStream_.size\n+\t\t<< \" --> \" << config.pixelFormat << \"/\" << config.size\n+\t\t<< (pipeConfig_->withConverter ? \" with\" : \" without\") << \" converter\";\n+\n+\tret = nativeConfigure(internalStream_, inputFormat);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (pipeConfig_->withConverter) {\n+\t\tStreamConfiguration cfg = config;\n+\t\tstd::vector<std::reference_wrapper<StreamConfiguration>> outputCfgs;\n+\t\toutputCfgs.push_back(cfg);\n+\t\tret = converter_->configure(internalStream_, outputCfgs);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int RkISP1Path::exportBuffers(unsigned int bufferCount,\n+\t\t\t std::vector<std::unique_ptr<FrameBuffer>> *buffers)\n+{\n+\tif (pipeConfig_->withConverter)\n+\t\treturn converter_->exportBuffers(0, bufferCount, buffers);\n+\telse\n+\t\treturn video_->exportBuffers(bufferCount, buffers);\n+}\n+\n+int RkISP1Path::allocateBuffers(unsigned int bufferCount)\n+{\n+\tif (pipeConfig_->withConverter) {\n+\t\tint ret = video_->allocateBuffers(bufferCount, &converterBuffers_);\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\t\tif ((unsigned int)ret != bufferCount)\n+\t\t\tLOG(RkISP1, Warning)\n+\t\t\t\t<< \"Requested \" << bufferCount << \" but got \" << ret << \" buffers\";\n+\n+\t\tfor (std::unique_ptr<FrameBuffer> &buffer : converterBuffers_)\n+\t\t\tavailableConverterBuffers_.push(buffer.get());\n+\t} else {\n+\t\treturn video_->importBuffers(bufferCount);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void RkISP1Path::releaseBuffers()\n+{\n+\twhile (!availableConverterBuffers_.empty())\n+\t\tavailableConverterBuffers_.pop();\n+\n+\tconverterBuffers_.clear();\n+\n+\tvideo_->releaseBuffers();\n+}\n+\n+void RkISP1Path::pathBufferReady(FrameBuffer *buffer)\n+{\n+\tRequest *request = buffer->request();\n+\n+\tif (request) {\n+\t\tinternalBufferReady_.emit(buffer);\n+\t} else {\n+\t\tauto iter = converterBuffersMapping_.find(buffer);\n+\t\tif (iter != converterBuffersMapping_.end()) {\n+\t\t\tconverter_->queueBuffer(buffer, iter->second);\n+\t\t\tconverterBuffersMapping_.erase(iter);\n+\t\t} else {\n+\t\t\tLOG(RkISP1, Error)\n+\t\t\t\t<< \"Final buffer associated to converted buffer not found on \"\n+\t\t\t\t<< name_ << \" path\";\n+\t\t}\n+\t}\n+}\n+\n+void RkISP1Path::pathConverterInputDone(FrameBuffer *buffer)\n+{\n+\tavailableConverterBuffers_.push(buffer);\n+}\n+\n+void RkISP1Path::pathConverterOutputDone(FrameBuffer *buffer)\n+{\n+\tinternalBufferReady_.emit(buffer);\n+}\n+\n+int RkISP1Path::queueBuffer(FrameBuffer *buffer)\n+{\n+\tFrameBuffer *_buffer;\n+\n+\tif (pipeConfig_->withConverter) {\n+\t\tif (availableConverterBuffers_.empty()) {\n+\t\t\tLOG(RkISP1, Error)\n+\t\t\t\t<< \"converter buffer underrun on \" << name_ << \" path\";\n+\t\t\treturn -ENOMEM;\n+\t\t}\n+\t\t_buffer = availableConverterBuffers_.front();\n+\t\tavailableConverterBuffers_.pop();\n+\t\tconverterBuffersMapping_[_buffer] = buffer;\n+\t} else {\n+\t\t_buffer = buffer;\n+\t}\n+\n+\treturn video_->queueBuffer(_buffer);\n+}\n+\n int RkISP1Path::start()\n {\n \tint ret;\n@@ -172,20 +516,23 @@ int RkISP1Path::start()\n \tif (running_)\n \t\treturn -EBUSY;\n \n-\t/* \\todo Make buffer count user configurable. */\n-\tret = video_->importBuffers(RKISP1_BUFFER_COUNT);\n-\tif (ret)\n-\t\treturn ret;\n-\n \tret = video_->streamOn();\n \tif (ret) {\n \t\tLOG(RkISP1, Error)\n \t\t\t<< \"Failed to start \" << name_ << \" path\";\n-\n-\t\tvideo_->releaseBuffers();\n \t\treturn ret;\n \t}\n \n+\tif (pipeConfig_->withConverter) {\n+\t\tret = converter_->start();\n+\t\tif (ret) {\n+\t\t\tLOG(RkISP1, Error)\n+\t\t\t\t<< \"Failed to start converter on \" << name_ << \" path\";\n+\t\t\tstop();\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n \trunning_ = true;\n \n \treturn 0;\n@@ -199,7 +546,8 @@ void RkISP1Path::stop()\n \tif (video_->streamOff())\n \t\tLOG(RkISP1, Warning) << \"Failed to stop \" << name_ << \" path\";\n \n-\tvideo_->releaseBuffers();\n+\tif (pipeConfig_->withConverter)\n+\t\tconverter_->stop();\n \n \trunning_ = false;\n }\ndiff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\nindex f3f1ae39..0da3594f 100644\n--- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n+++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h\n@@ -1,6 +1,7 @@\n /* SPDX-License-Identifier: LGPL-2.1-or-later */\n /*\n * Copyright (C) 2020, Google Inc.\n+ * Copyright 2022 NXP\n *\n * rkisp1path.h - Rockchip ISP1 path helper\n */\n@@ -8,6 +9,7 @@\n #pragma once\n \n #include <memory>\n+#include <queue>\n #include <vector>\n \n #include <libcamera/base/signal.h>\n@@ -17,9 +19,11 @@\n #include <libcamera/geometry.h>\n #include <libcamera/pixel_format.h>\n \n+#include \"libcamera/internal/converter.h\"\n #include \"libcamera/internal/media_object.h\"\n #include \"libcamera/internal/v4l2_videodevice.h\"\n \n+\n namespace libcamera {\n \n class MediaDevice;\n@@ -33,7 +37,7 @@ public:\n \tRkISP1Path(const char *name, const Span<const PixelFormat> &formats,\n \t\t const Size &minResolution, const Size &maxResolution);\n \n-\tbool init(MediaDevice *media);\n+\tbool init(MediaDevice *media, MediaDevice *mediaConverter = nullptr);\n \n \tint setEnabled(bool enable) { return link_->setEnabled(enable); }\n \tbool isEnabled() const { return link_->flags() & MEDIA_LNK_FL_ENABLED; }\n@@ -45,18 +49,31 @@ public:\n \t\t const V4L2SubdeviceFormat &inputFormat);\n \n \tint exportBuffers(unsigned int bufferCount,\n-\t\t\t std::vector<std::unique_ptr<FrameBuffer>> *buffers)\n-\t{\n-\t\treturn video_->exportBuffers(bufferCount, buffers);\n-\t}\n+\t\t\t std::vector<std::unique_ptr<FrameBuffer>> *buffers);\n+\n+\tint allocateBuffers(unsigned int bufferCount);\n+\tvoid releaseBuffers();\n \n \tint start();\n \tvoid stop();\n \n-\tint queueBuffer(FrameBuffer *buffer) { return video_->queueBuffer(buffer); }\n-\tSignal<FrameBuffer *> &bufferReady() { return video_->bufferReady; }\n+\tint queueBuffer(FrameBuffer *buffer);\n+\tSignal<FrameBuffer *> &bufferReady() { return internalBufferReady_; }\n+\n+\tStreamConfiguration internalStream() const\n+\t{\n+\t\treturn internalStream_;\n+\t}\n \n private:\n+\tstruct Configuration {\n+\t\tSizeRange inputSizes;\n+\t\tPixelFormat inputFormat;\n+\t\tstd::vector<PixelFormat> outputFormats;\n+\t\tSizeRange outputSizes;\n+\t\tbool withConverter;\n+\t};\n+\n \tstatic constexpr unsigned int RKISP1_BUFFER_COUNT = 4;\n \n \tconst char *name_;\n@@ -65,10 +82,33 @@ private:\n \tconst Span<const PixelFormat> formats_;\n \tconst Size minResolution_;\n \tconst Size maxResolution_;\n+\tCameraConfiguration::Status getPipeConfiguration(\n+\t\tStreamConfiguration &streamCfg,\n+\t\tconst RkISP1Path::Configuration **cfg) const;\n+\n+\tStreamConfiguration generateNativeConfiguration(const Size &resolution);\n+\tCameraConfiguration::Status nativeValidate(StreamConfiguration *cfg);\n+\tint nativeConfigure(const StreamConfiguration &config,\n+\t\t\t const V4L2SubdeviceFormat &inputFormat);\n \n \tstd::unique_ptr<V4L2Subdevice> resizer_;\n \tstd::unique_ptr<V4L2VideoDevice> video_;\n \tMediaLink *link_;\n+\n+\tvoid initConverter(MediaDevice *mediaConverter);\n+\tstd::unique_ptr<Converter> converter_;\n+\tstd::vector<Configuration> configs_;\n+\tStreamConfiguration internalStream_;\n+\tconst Configuration *pipeConfig_;\n+\tbool hasConverter_;\n+\tbool useConverter_;\n+\tSignal<FrameBuffer *> internalBufferReady_;\n+\tstd::vector<std::unique_ptr<FrameBuffer>> converterBuffers_;\n+\tstd::queue<FrameBuffer *> availableConverterBuffers_;\n+\tstd::map<FrameBuffer *, FrameBuffer *> converterBuffersMapping_;\n+\tvoid pathBufferReady(FrameBuffer *buffer);\n+\tvoid pathConverterInputDone(FrameBuffer *buffer);\n+\tvoid pathConverterOutputDone(FrameBuffer *buffer);\n };\n \n class RkISP1MainPath : public RkISP1Path\n", "prefixes": [ "libcamera-devel", "14/14" ] }