Show a patch.

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

{
    "id": 22056,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/22056/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/22056/",
    "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": "<20241122042404.474292-1-qi.hou@nxp.com>",
    "date": "2024-11-22T04:24:04",
    "name": "[v5] gstreamer: Add GstVideoMeta support",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": false,
    "hash": "32d83414d5a8076aa76369e32de451eaef87eab5",
    "submitter": {
        "id": 195,
        "url": "https://patchwork.libcamera.org/api/1.1/people/195/?format=api",
        "name": "Qi Hou",
        "email": "qi.hou@nxp.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/22056/mbox/",
    "series": [
        {
            "id": 4813,
            "url": "https://patchwork.libcamera.org/api/1.1/series/4813/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4813",
            "date": "2024-11-22T04:24:04",
            "name": "[v5] gstreamer: Add GstVideoMeta support",
            "version": 5,
            "mbox": "https://patchwork.libcamera.org/series/4813/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/22056/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/22056/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 489F7C326C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 22 Nov 2024 04:24:27 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 566BE65FD4;\n\tFri, 22 Nov 2024 05:24:26 +0100 (CET)",
            "from EUR05-AM6-obe.outbound.protection.outlook.com\n\t(mail-am6eur05on20621.outbound.protection.outlook.com\n\t[IPv6:2a01:111:f403:2612::621])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D62CB65FC6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 22 Nov 2024 05:24:24 +0100 (CET)",
            "from PAXPR04MB8285.eurprd04.prod.outlook.com\n\t(2603:10a6:102:1ca::15)\n\tby DU2PR04MB8726.eurprd04.prod.outlook.com (2603:10a6:10:2dd::9) with\n\tMicrosoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8158.23;\n\tFri, 22 Nov 2024 04:24:23 +0000",
            "from PAXPR04MB8285.eurprd04.prod.outlook.com\n\t([fe80::e003:8fb:64ea:acfd]) by\n\tPAXPR04MB8285.eurprd04.prod.outlook.com\n\t([fe80::e003:8fb:64ea:acfd%5]) with mapi id 15.20.8158.024;\n\tFri, 22 Nov 2024 04:24:23 +0000"
        ],
        "Authentication-Results": [
            "lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=nxp.com header.i=@nxp.com header.b=\"Ox9fMING\";\n\tdkim-atps=neutral",
            "dkim=none (message not signed)\n\theader.d=none;dmarc=none action=none header.from=nxp.com;"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none;\n\tb=v2TFqaejTXbGbHsFHb2CNTRi1LExvfCnEiryvll30G0wBoPeKm6BboIAxgmGlKgyBzfsfz+s2l9Z8/MQIopRg4VbeVb8PVGIoqIBQ2VM8t6PkQMZ4FqGbxUbtlyBICOCeOD/a0jjeNuEtiU3AwJpv9vYMBATh4aDgICb/JqkbG8cjJNo13WiKnNLnopJFicEosvYkyOXzCSS/o3E5jCdcQY5WqNn9eiBbXou0nbHroZ2I9BR5mwGjY7BBNX6OcQGaCgVLUN+ZF/l55cF7CP6jS8FvxETWsPrfNOnwOVCevUQ5NiUEKY1Rw575bRTEYKXhutxca0wCulfTXVDwbbv/Q==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n\ts=arcselector10001;\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=bcnICgfLSeBwv0CP4MKDacftdbLLyZ+I4RM/l0sT7yE=;\n\tb=nsBLSarJVvEQholcREyCdBFXC8sV0GPxxz5ndoAOaqv0bOHseEaEM2vUQ5N/9oWiI7DzlQuhwc7q+AJzXlnSlBSPs5N35M6asaqX+hVcimSCSLVKKOkLD0pFKM7FECJC9BHYjBJikmajX22jiBiFWeLQlLhR+vpKun6Zry3Xek7C0L8TOrW2xXZ1FE5jzIvjXjrKuatQ6wXkx7glYka64kAwuBZNeTKx9RBEovKxcgu1lUD34ApAeJySa8qkYSEwo12s6byC7llewyRQDtAsrG+BT3bhrSrseOfpQxtJjIEg9j8jLMaZZ6k42dlAYLqYdNxwZDK4xdEp+qFhMmgMIQ==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass\n\tsmtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com;\n\tdkim=pass header.d=nxp.com; arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1;\n\th=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n\tbh=bcnICgfLSeBwv0CP4MKDacftdbLLyZ+I4RM/l0sT7yE=;\n\tb=Ox9fMINGKXhNgaOw2fTgI0rSo+MKVXrP26GB1ryJpifPw5/f1XNUfnpehUivjHNMNPauSBXq1hBjQbwrLOccTiiqnB1dyX8445368amIDgtw5wlF3OhGeJ7vE6ytEwjschPLuFfts/lMIt2Zwh2oV8uJhDgYyTuHZk5EzBea/eKEedtf3Wb5AYGLjE1KBHrbgSkq5Gln/BD2oznoRfB6TU0MHytQhn6BoWmVc+ikxU5rOlfUjaaVNpOkKlNqX+SSa7iMx3aTRq8NlfXZ8D8pmModOb6hYrFJHQQhIYT132eB9Azpb/xDjAKqFJ6x7EEvkT1N6IJQFXt/NSz9L3Q4CA==",
        "From": "Hou Qi <qi.hou@nxp.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "jared.hu@nxp.com,\n\tqi.hou@nxp.com,\n\tjulien.vuillaumier@nxp.com",
        "Subject": "[PATCH v5] gstreamer: Add GstVideoMeta support",
        "Date": "Fri, 22 Nov 2024 13:24:04 +0900",
        "Message-Id": "<20241122042404.474292-1-qi.hou@nxp.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain",
        "X-ClientProxiedBy": "SI2P153CA0024.APCP153.PROD.OUTLOOK.COM\n\t(2603:1096:4:190::13) To PAXPR04MB8285.eurprd04.prod.outlook.com\n\t(2603:10a6:102:1ca::15)",
        "MIME-Version": "1.0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-TrafficTypeDiagnostic": "PAXPR04MB8285:EE_|DU2PR04MB8726:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "707bc5c5-9710-4731-8ddb-08dd0aad8aa3",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;\n\tARA:13230040|1800799024|52116014|376014|366016|38350700014; ",
        "X-Microsoft-Antispam-Message-Info": "+zIXZSgxdzylQ2V4NE+wohI4UiHzdwY6NaTDltyvbReaTqy5R2/naTfGYD9lHuiu4tB3b3UeGaXLIsDlTxjOn0PAj70Uj/yXa1QRRHrmZsY76DDIzYAQWPpzIOfXNuNQF6No/cN5axlA79NX8/apwom6ie0k83j1nm8LZk+6rFr01FFlPIgFhC4oGvrbXo0xaThlqKHp99Xu27L/2UVIc0UCS1kbmROb6HR4TNaLQHSYj3lHkPbn1d4qzM4CjGyAb0Y9Kx1A5bXpGCqXzVttHx7mXs7TH6Wpiu205fItwA4jREdAEcefX1JP0Id/BSzNSe6J7FSxhc0OknI8qcuA8NzuGQtO2x+z6xB4hRlUHnigpOwkzrTBjndQnQ4Nu4/BwIE/vQb0DxyeDDKgrGvqjzQahWKdsePY4ibFg7DQl2RFYLUpDFgujQtYUbjvep9oJaQnb1B4ObKEzMScInAy0aDiQqmE5+l74oVwtj0pKRO1UyK1OlFs+pMiBi9WEkjnMZwwusYDMaP/0bIrrySTJ5sEugE6f8DE7ki1i4fYtStyfv+oMcCIsOmkEPOORCOswQJ2l5w0dxPzJnaPTUCnOrgUyiiZgh4yhEqkHQXSiLQeciaq2+5AoNjaj1DWLmAUJgX5y8ihRanu2IEOzdLfcXUMfCiSLU3/SKG96x8JviT84Hq82BJQQfEdwqRl/zeo0twK3B1ytkMT66JOsd7+C50Cid+06qEidtPqGIiIlbVV8nKhjuKZbYQ49O5QOkRJKS0FdVZaU5cawcGKw1bmLPDSJWiilLtLAcMkrzDXtUf9ZAurmDYeQXmeffrEjrzBXseTAqoRb10t0wjI9dvmAcR5JvFH9s3MtSYQdIV4Qx+R6CPfaDA2++p+2aB+Wm3B9A4MDMKYtqdp/9LJi6lQ5/0FR1GZV8NiGl5Q3jEYRriQALYTOlp6ZAaIJFwGOI2oZuDl9/j2LLNG299zFIRW5T1vWb9rZw3NG14PO0oOVeaObvbsQC35SH0YWsCgIu9g9hPIPUMFBJiNAdrSKpF+Qv19d/AdsMcwqkUmk+Z5/ncA0/ifeY0uWG0uY9s9mkebfQh66mqy3ppt8QpSiHGgWGEVssYIOjDS0nZTDWa6TdJafcIeE1WRuQTt7u2VDrlXMesq3jk1Vew6y8jKPEr/2WnxKRKmtuMAoaW3vRlmPUhvFlVfI2EbmmCYaLJivgnCM/J3Wagg+NV/DcddJ4HRMoTjeGzk3UbUxNhRj+hbWVFVff3iGu2YO0yss7665ppgvbFRnCYBgWb6JEvpYXO8ttzyuDDkcxsopSgk9DHHYZTM5xTE1xG+Roz7/QxwT0DCcrTh/n7Y6Cf6pCXpssV0AbH70LkZZgKl8fCZDHMIW0s=",
        "X-Forefront-Antispam-Report": "CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:;\n\tIPV:NLI; SFV:NSPM; H:PAXPR04MB8285.eurprd04.prod.outlook.com; PTR:;\n\tCAT:NONE; \n\tSFS:(13230040)(1800799024)(52116014)(376014)(366016)(38350700014);\n\tDIR:OUT; SFP:1101; ",
        "X-MS-Exchange-AntiSpam-MessageData-ChunkCount": "1",
        "X-MS-Exchange-AntiSpam-MessageData-0": "C/Wak2cfoOneA9gdPVvJwuMYPTj+j5VT21OE5vic1+qzFaruyjMcZPUnSjcWH3lCYyVICDhWzMWAcEMD3jN8OpJU08bbqCTYW993q3yQ52X9BlqyXvAz9aabo++Qm6/gvIXSXm4FyhFOiL3ifl4jR7ec2Q7jhra/muDiYaE8LT2XOVAOQvneDTf9hstn7jxEfsN4dN3vnvn2FdnHrs+TOrl5ZGWJy3Xp0aMJI/EwK9nb4eOK41DpFlUWPT11EruYQm/VXXXXWThiDtBXt/n0zH2U/FVdiC4isW6+MTumVwAxyF6n0gFUuHKAjvnSqqjMP8I1KeBpyxV8T3fB8FubU+tVtUmYcwn7nq2REdTHhfXNuiAJfxw6DK7bPqn1706Y+ZePxQk9F5BrG4jZgWcCynnqPmKGxK5qffoWj/dRbCM93A4w6xvHnbt86VebFMC6LkR3USomHuChK087ODX//CCJYDsoP5XAbgq12KUQxzvKNbgp6Oj9+mLNEhKC696ygnWPCD+ZizxjRqXoSYGAq2ZwvJ7hzrPvObe1rgmS4JMEZh0THNdcRHYvl6ksumv6Id2xavMNgHArNebUgOSEzhrFUZqGiog55lRX83PvsSxhS6dyjfNzoyynr6jDQtXfLuzA4YGdWcPHKxlm5mQns/AEWeBEoqeIitgdN0DI93LBh5DuZra9F1MvA8kaL1Sla8/muGTApcl9g7VnAQyXDoaI8kXZZFQp15i0IcSUfyPx0niMVWCibwe8RSuJ0PQYXV1UZ9Ic46MILViOA2Z9+5nr9YU/Kctvog0dOujg5eymnwmWnSB0R1GIDuXmB+Z8EvFGj7lhrp0I0EFF8bf9hv+g3Y07n7UA6YiFkxvnOG9+Qf3/XSdC1KbPUxxku0wuT5HNMF57/hQ2O5H7+FwoS0NSCvjjkV1lBJmaQ95B0C+HHpb7zsCodsOqV7mAiOM0kbaijv4l0K/sb1ILy9ZJeaddQKhrTFaumOgdNZMASNcbAmclxR683hlM3uPLgLczZJ+XJTXmhkEo76m4xAPC6W0pioWNJIJLbkR53PomB1Lqado8uiO7TBQ/hL5j6kqH4WFzsY3pE0gSTjpp1lMDFc+oJ5E8bUSb9ruVLebmS7RQMgJeAbMN7pDao51kwEpMu/YtfjzWjQxFdNfPOv4fKkstfp5Ck2696XO5hEZWtmRoRR3NdYwPurZYgFdqfri70rSsU+p9Nk3cze13C2Pb8/yPMvGcRfq6gDiIPci0E0OIGp74504kOfYfbXlL4gtWuNyZPB/A61Y5/EjDWanBrNOVH6wzWklGWa1/ULHBtShr6tKykJmOygcoYNtkRETgtTFPen2bEVxebp56boLTi3QzFX3ASrnKTYnE/HGgsfgVNAKT7373YrMZvzjr7scMdz3iyubR/iAA4GyvOg3mAq9QUsa3CLqAnTmMpzlcxZ+CVyELsyu2Rdka7wf2mXrJTAA2vadmQD6EtQyii2mZ3x6T9hxIljDtXG3uZTBVhsBrSyxmsUSJvSgoJBf1HQWsRGuPhL4gvYexRNdHSUl03oWpWsUvnA0HkOPJTq4Miw0=",
        "X-OriginatorOrg": "nxp.com",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "707bc5c5-9710-4731-8ddb-08dd0aad8aa3",
        "X-MS-Exchange-CrossTenant-AuthSource": "PAXPR04MB8285.eurprd04.prod.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Internal",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "22 Nov 2024 04:24:23.0033\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": "ekK9Z6LjU/q2ezZFVDCq4H44GbcCgG50+TJNHgMvFBYip2nk5gxJu54vYj9OTGVo",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "DU2PR04MB8726",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "GStreamer video-info calculated stride and offset may differ from\nthose used by the camera.\n\nFor stride and offset mismatch, this patch adds video meta to buffer\nif downstream supports VideoMeta through allocation query. Otherwise,\nget downstream provided buffer pool or create internal buffer pool\nusing the caps, and copy video frame to the system memory acquired\nfrom the buffer pool.\n\nSigned-off-by: Hou Qi <qi.hou@nxp.com>\n---\n src/gstreamer/gstlibcamera-utils.cpp |  33 +++++++\n src/gstreamer/gstlibcamera-utils.h   |   4 +\n src/gstreamer/gstlibcamerapool.cpp   |   9 +-\n src/gstreamer/gstlibcamerapool.h     |   3 +-\n src/gstreamer/gstlibcamerasrc.cpp    | 142 ++++++++++++++++++++++++++-\n 5 files changed, 186 insertions(+), 5 deletions(-)",
    "diff": "diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp\nindex 732987ef..09af9204 100644\n--- a/src/gstreamer/gstlibcamera-utils.cpp\n+++ b/src/gstreamer/gstlibcamera-utils.cpp\n@@ -591,6 +591,39 @@ gst_task_resume(GstTask *task)\n }\n #endif\n \n+#if !GST_CHECK_VERSION(1, 22, 0)\n+/*\n+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>\n+ * Library       <2002> Ronald Bultje <rbultje@ronald.bitfreak.net>\n+ * Copyright (C) <2007> David A. Schleef <ds@schleef.org>\n+ */\n+/* This function has been imported directly from the gstreamer project to\n+ * support backwards compatibility and should be removed when the older\n+ * version is no longer supported. */\n+gint gst_video_format_info_extrapolate_stride(const GstVideoFormatInfo *finfo, gint plane, gint stride)\n+{\n+\tgint estride;\n+\tgint comp[GST_VIDEO_MAX_COMPONENTS];\n+\tgint i;\n+\n+\t/* there is nothing to extrapolate on first plane */\n+\tif (plane == 0)\n+\t\treturn stride;\n+\n+\tgst_video_format_info_component(finfo, plane, comp);\n+\n+\t/* For now, all planar formats have a single component on first plane, but\n+\t* if there was a planar format with more, we'd have to make a ratio of the\n+\t* number of component on the first plane against the number of component on\n+\t* the current plane. */\n+\testride = 0;\n+\tfor (i = 0; i < GST_VIDEO_MAX_COMPONENTS && comp[i] >= 0; i++)\n+\t\testride += GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(finfo, comp[i], stride);\n+\n+\treturn estride;\n+}\n+#endif\n+\n G_LOCK_DEFINE_STATIC(cm_singleton_lock);\n static std::weak_ptr<CameraManager> cm_singleton_ptr;\n \ndiff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h\nindex cab1c814..81149280 100644\n--- a/src/gstreamer/gstlibcamera-utils.h\n+++ b/src/gstreamer/gstlibcamera-utils.h\n@@ -35,6 +35,10 @@ static inline void gst_clear_event(GstEvent **event_ptr)\n #if !GST_CHECK_VERSION(1, 17, 1)\n gboolean gst_task_resume(GstTask *task);\n #endif\n+\n+#if !GST_CHECK_VERSION(1, 22, 0)\n+gint gst_video_format_info_extrapolate_stride(const GstVideoFormatInfo *finfo, gint plane, gint stride);\n+#endif\n std::shared_ptr<libcamera::CameraManager> gst_libcamera_get_camera_manager(int &ret);\n \n /**\ndiff --git a/src/gstreamer/gstlibcamerapool.cpp b/src/gstreamer/gstlibcamerapool.cpp\nindex 9cd7eccb..04bcaeb1 100644\n--- a/src/gstreamer/gstlibcamerapool.cpp\n+++ b/src/gstreamer/gstlibcamerapool.cpp\n@@ -135,7 +135,8 @@ gst_libcamera_pool_class_init(GstLibcameraPoolClass *klass)\n }\n \n GstLibcameraPool *\n-gst_libcamera_pool_new(GstLibcameraAllocator *allocator, Stream *stream)\n+gst_libcamera_pool_new(GstLibcameraAllocator *allocator, Stream *stream,\n+\t\t       GstVideoInfo *info, gboolean add_video_meta)\n {\n \tauto *pool = GST_LIBCAMERA_POOL(g_object_new(GST_TYPE_LIBCAMERA_POOL, nullptr));\n \n@@ -145,6 +146,12 @@ gst_libcamera_pool_new(GstLibcameraAllocator *allocator, Stream *stream)\n \tgsize pool_size = gst_libcamera_allocator_get_pool_size(allocator, stream);\n \tfor (gsize i = 0; i < pool_size; i++) {\n \t\tGstBuffer *buffer = gst_buffer_new();\n+\t\tif (add_video_meta) {\n+\t\t\tgst_buffer_add_video_meta_full(buffer, GST_VIDEO_FRAME_FLAG_NONE,\n+\t\t\t\t\t\t       GST_VIDEO_INFO_FORMAT(info), GST_VIDEO_INFO_WIDTH(info),\n+\t\t\t\t\t\t       GST_VIDEO_INFO_HEIGHT(info), GST_VIDEO_INFO_N_PLANES(info),\n+\t\t\t\t\t\t       info->offset, info->stride);\n+\t\t}\n \t\tpool->queue->push_back(buffer);\n \t}\n \ndiff --git a/src/gstreamer/gstlibcamerapool.h b/src/gstreamer/gstlibcamerapool.h\nindex 2a7a9c77..b522b4a5 100644\n--- a/src/gstreamer/gstlibcamerapool.h\n+++ b/src/gstreamer/gstlibcamerapool.h\n@@ -14,6 +14,7 @@\n #include \"gstlibcameraallocator.h\"\n \n #include <gst/gst.h>\n+#include <gst/video/video.h>\n \n #include <libcamera/stream.h>\n \n@@ -21,7 +22,7 @@\n G_DECLARE_FINAL_TYPE(GstLibcameraPool, gst_libcamera_pool, GST_LIBCAMERA, POOL, GstBufferPool)\n \n GstLibcameraPool *gst_libcamera_pool_new(GstLibcameraAllocator *allocator,\n-\t\t\t\t\t libcamera::Stream *stream);\n+\t\t\t\t\t libcamera::Stream *stream, GstVideoInfo *info, gboolean add_video_meta);\n \n libcamera::Stream *gst_libcamera_pool_get_stream(GstLibcameraPool *self);\n \ndiff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\nindex 8efa25f4..eb43f053 100644\n--- a/src/gstreamer/gstlibcamerasrc.cpp\n+++ b/src/gstreamer/gstlibcamerasrc.cpp\n@@ -150,6 +150,10 @@ struct _GstLibcameraSrc {\n \tGstLibcameraSrcState *state;\n \tGstLibcameraAllocator *allocator;\n \tGstFlowCombiner *flow_combiner;\n+\n+\tgboolean frame_copy;\n+\tGstVideoInfo info;\n+\tGstBufferPool *pool;\n };\n \n enum {\n@@ -268,6 +272,43 @@ GstLibcameraSrcState::requestCompleted(Request *request)\n \tgst_task_resume(src_->task);\n }\n \n+static GstFlowReturn\n+gst_libcamera_video_frame_copy(GstLibcameraSrc *self, GstBuffer *src, GstBuffer *dest, guint32 stride)\n+{\n+\tGstVideoInfo src_info = self->info;\n+\tGstVideoFrame src_frame, dest_frame;\n+\tgsize offset = 0;\n+\n+\tfor (guint i = 0; i < GST_VIDEO_INFO_N_PLANES(&src_info); i++) {\n+\t\tstride = gst_video_format_info_extrapolate_stride(src_info.finfo, i, stride);\n+\t\tsrc_info.stride[i] = stride;\n+\t\tsrc_info.offset[i] = offset;\n+\t\toffset += stride * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(src_info.finfo, i,\n+\t\t\t\t\t\t\t\t      GST_VIDEO_INFO_HEIGHT(&src_info));\n+\t}\n+\tsrc_info.size = gst_buffer_get_size(src);\n+\n+\tif (!gst_video_frame_map(&src_frame, &src_info, src, GST_MAP_READ))\n+\t\tgoto invalid_buffer;\n+\n+\tif (!gst_video_frame_map(&dest_frame, &self->info, dest, GST_MAP_WRITE)) {\n+\t\tgst_video_frame_unmap(&src_frame);\n+\t\tgoto invalid_buffer;\n+\t}\n+\n+\tgst_video_frame_copy(&dest_frame, &src_frame);\n+\n+\tgst_video_frame_unmap(&src_frame);\n+\tgst_video_frame_unmap(&dest_frame);\n+\n+\treturn GST_FLOW_OK;\n+\n+invalid_buffer : {\n+\tGST_ERROR_OBJECT(self, \"Could not map buffer\");\n+\treturn GST_FLOW_ERROR;\n+}\n+}\n+\n /* Must be called with stream_lock held. */\n int GstLibcameraSrcState::processRequest()\n {\n@@ -292,12 +333,34 @@ int GstLibcameraSrcState::processRequest()\n \tGstFlowReturn ret = GST_FLOW_OK;\n \tgst_flow_combiner_reset(src_->flow_combiner);\n \n-\tfor (GstPad *srcpad : srcpads_) {\n+\tfor (gsize i = 0; i < src_->state->srcpads_.size(); i++) {\n+\t\tGstPad *srcpad = src_->state->srcpads_[i];\n \t\tStream *stream = gst_libcamera_pad_get_stream(srcpad);\n \t\tGstBuffer *buffer = wrap->detachBuffer(stream);\n+\t\tGstBuffer *tmp = NULL;\n \n+\t\tconst StreamConfiguration &stream_cfg = src_->state->config_->at(i);\n \t\tFrameBuffer *fb = gst_libcamera_buffer_get_frame_buffer(buffer);\n \n+\t\tif (src_->frame_copy) {\n+\t\t\tret = gst_buffer_pool_acquire_buffer(src_->pool, &tmp, NULL);\n+\t\t\tif (ret != GST_FLOW_OK) {\n+\t\t\t\tGST_ERROR(\"Failed to acquire buffer\");\n+\t\t\t\tgst_buffer_unref(buffer);\n+\t\t\t\treturn -EPIPE;\n+\t\t\t}\n+\n+\t\t\tret = gst_libcamera_video_frame_copy(src_, buffer, tmp, stream_cfg.stride);\n+\t\t\tgst_buffer_unref(buffer);\n+\t\t\tif (ret != GST_FLOW_OK) {\n+\t\t\t\tGST_ERROR(\"Failed to copy buffer\");\n+\t\t\t\tgst_buffer_unref(tmp);\n+\t\t\t\treturn -EPIPE;\n+\t\t\t}\n+\n+\t\t\tbuffer = tmp;\n+\t\t}\n+\n \t\tif (GST_CLOCK_TIME_IS_VALID(wrap->pts_)) {\n \t\t\tGST_BUFFER_PTS(buffer) = wrap->pts_;\n \t\t\tgst_libcamera_pad_set_latency(srcpad, wrap->latency_);\n@@ -497,9 +560,74 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self)\n \tfor (gsize i = 0; i < state->srcpads_.size(); i++) {\n \t\tGstPad *srcpad = state->srcpads_[i];\n \t\tconst StreamConfiguration &stream_cfg = state->config_->at(i);\n+\t\tgboolean add_video_meta = false;\n+\t\tGstVideoInfo info;\n+\n+\t\tg_autoptr(GstCaps) caps = gst_libcamera_stream_configuration_to_caps(stream_cfg);\n+\t\tgst_libcamera_framerate_to_caps(caps, element_caps);\n \n-\t\tGstLibcameraPool *pool = gst_libcamera_pool_new(self->allocator,\n-\t\t\t\t\t\t\t\tstream_cfg.stream());\n+\t\tgst_video_info_init(&info);\n+\t\tgst_video_info_from_caps(&info, caps);\n+\n+\t\t/* stride mismatch between camera stride and that calculated by video-info */\n+\t\tif (static_cast<unsigned int>(info.stride[0]) != stream_cfg.stride &&\n+\t\t    GST_VIDEO_INFO_FORMAT(&info) != GST_VIDEO_FORMAT_ENCODED) {\n+\t\t\tGstQuery *query = NULL;\n+\t\t\tgboolean need_pool = true;\n+\n+\t\t\tquery = gst_query_new_allocation(caps, need_pool);\n+\t\t\tif (!gst_pad_peer_query(srcpad, query))\n+\t\t\t\tGST_DEBUG_OBJECT(self, \"Didn't get downstream ALLOCATION hints\");\n+\t\t\telse\n+\t\t\t\tadd_video_meta = gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL);\n+\n+\t\t\tif (add_video_meta) {\n+\t\t\t\tguint k, stride;\n+\t\t\t\tgsize offset = 0;\n+\n+\t\t\t\t/* this should be updated if tiled formats get added in the future. */\n+\t\t\t\tfor (k = 0; k < GST_VIDEO_INFO_N_PLANES(&info); k++) {\n+\t\t\t\t\tstride = gst_video_format_info_extrapolate_stride(info.finfo, k, stream_cfg.stride);\n+\t\t\t\t\tinfo.stride[k] = stride;\n+\t\t\t\t\tinfo.offset[k] = offset;\n+\t\t\t\t\toffset += stride * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info.finfo, k,\n+\t\t\t\t\t\t\t\t\t\t\t      GST_VIDEO_INFO_HEIGHT(&info));\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tGstBufferPool *pool = NULL;\n+\t\t\t\tself->frame_copy = true;\n+\n+\t\t\t\tif (gst_query_get_n_allocation_pools(query) > 0)\n+\t\t\t\t\tgst_query_parse_nth_allocation_pool(query, 0, &pool, NULL, NULL, NULL);\n+\n+\t\t\t\tif (self->pool)\n+\t\t\t\t\tgst_object_unref(self->pool);\n+\n+\t\t\t\tif (pool)\n+\t\t\t\t\tself->pool = pool;\n+\t\t\t\telse {\n+\t\t\t\t\tGstStructure *config;\n+\t\t\t\t\tguint min_buffers = 3;\n+\t\t\t\t\tself->pool = gst_video_buffer_pool_new();\n+\n+\t\t\t\t\tconfig = gst_buffer_pool_get_config(self->pool);\n+\t\t\t\t\tgst_buffer_pool_config_set_params(config, caps, info.size, min_buffers, 0);\n+\t\t\t\t\tgst_buffer_pool_set_config(GST_BUFFER_POOL_CAST(self->pool), config);\n+\t\t\t\t\tGST_DEBUG_OBJECT(self, \"Own pool config is %\" GST_PTR_FORMAT, config);\n+\t\t\t\t}\n+\n+\t\t\t\tif (!gst_buffer_pool_set_active(self->pool, true)) {\n+\t\t\t\t\tGST_ERROR_OBJECT(self, \"Failed to active buffer pool\");\n+\t\t\t\t\tgst_caps_unref(caps);\n+\t\t\t\t\treturn false;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tgst_query_unref(query);\n+\t\t}\n+\n+\t\tself->info = info;\n+\t\tGstLibcameraPool *pool = gst_libcamera_pool_new(self->allocator, stream_cfg.stream(),\n+\t\t\t\t\t\t\t\t&info, add_video_meta);\n \t\tg_signal_connect_swapped(pool, \"buffer-notify\",\n \t\t\t\t\t G_CALLBACK(gst_task_resume), self->task);\n \n@@ -842,6 +970,12 @@ gst_libcamera_src_finalize(GObject *object)\n \tGObjectClass *klass = G_OBJECT_CLASS(gst_libcamera_src_parent_class);\n \tGstLibcameraSrc *self = GST_LIBCAMERA_SRC(object);\n \n+\tif (self->pool) {\n+\t\tgst_buffer_pool_set_active(self->pool, false);\n+\t\tgst_object_unref(self->pool);\n+\t\tself->pool = NULL;\n+\t}\n+\n \tg_rec_mutex_clear(&self->stream_lock);\n \tg_clear_object(&self->task);\n \tg_mutex_clear(&self->state->lock_);\n@@ -875,6 +1009,8 @@ gst_libcamera_src_init(GstLibcameraSrc *self)\n \t/* C-style friend. */\n \tstate->src_ = self;\n \tself->state = state;\n+\tself->frame_copy = false;\n+\tself->pool = NULL;\n }\n \n static GstPad *\n",
    "prefixes": [
        "v5"
    ]
}