From patchwork Fri Nov 22 04:24:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hou Qi X-Patchwork-Id: 22056 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 489F7C326C for ; Fri, 22 Nov 2024 04:24:27 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 566BE65FD4; Fri, 22 Nov 2024 05:24:26 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=nxp.com header.i=@nxp.com header.b="Ox9fMING"; dkim-atps=neutral Received: from EUR05-AM6-obe.outbound.protection.outlook.com (mail-am6eur05on20621.outbound.protection.outlook.com [IPv6:2a01:111:f403:2612::621]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D62CB65FC6 for ; Fri, 22 Nov 2024 05:24:24 +0100 (CET) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=v2TFqaejTXbGbHsFHb2CNTRi1LExvfCnEiryvll30G0wBoPeKm6BboIAxgmGlKgyBzfsfz+s2l9Z8/MQIopRg4VbeVb8PVGIoqIBQ2VM8t6PkQMZ4FqGbxUbtlyBICOCeOD/a0jjeNuEtiU3AwJpv9vYMBATh4aDgICb/JqkbG8cjJNo13WiKnNLnopJFicEosvYkyOXzCSS/o3E5jCdcQY5WqNn9eiBbXou0nbHroZ2I9BR5mwGjY7BBNX6OcQGaCgVLUN+ZF/l55cF7CP6jS8FvxETWsPrfNOnwOVCevUQ5NiUEKY1Rw575bRTEYKXhutxca0wCulfTXVDwbbv/Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=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; bh=bcnICgfLSeBwv0CP4MKDacftdbLLyZ+I4RM/l0sT7yE=; b=nsBLSarJVvEQholcREyCdBFXC8sV0GPxxz5ndoAOaqv0bOHseEaEM2vUQ5N/9oWiI7DzlQuhwc7q+AJzXlnSlBSPs5N35M6asaqX+hVcimSCSLVKKOkLD0pFKM7FECJC9BHYjBJikmajX22jiBiFWeLQlLhR+vpKun6Zry3Xek7C0L8TOrW2xXZ1FE5jzIvjXjrKuatQ6wXkx7glYka64kAwuBZNeTKx9RBEovKxcgu1lUD34ApAeJySa8qkYSEwo12s6byC7llewyRQDtAsrG+BT3bhrSrseOfpQxtJjIEg9j8jLMaZZ6k42dlAYLqYdNxwZDK4xdEp+qFhMmgMIQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=bcnICgfLSeBwv0CP4MKDacftdbLLyZ+I4RM/l0sT7yE=; b=Ox9fMINGKXhNgaOw2fTgI0rSo+MKVXrP26GB1ryJpifPw5/f1XNUfnpehUivjHNMNPauSBXq1hBjQbwrLOccTiiqnB1dyX8445368amIDgtw5wlF3OhGeJ7vE6ytEwjschPLuFfts/lMIt2Zwh2oV8uJhDgYyTuHZk5EzBea/eKEedtf3Wb5AYGLjE1KBHrbgSkq5Gln/BD2oznoRfB6TU0MHytQhn6BoWmVc+ikxU5rOlfUjaaVNpOkKlNqX+SSa7iMx3aTRq8NlfXZ8D8pmModOb6hYrFJHQQhIYT132eB9Azpb/xDjAKqFJ6x7EEvkT1N6IJQFXt/NSz9L3Q4CA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PAXPR04MB8285.eurprd04.prod.outlook.com (2603:10a6:102:1ca::15) by DU2PR04MB8726.eurprd04.prod.outlook.com (2603:10a6:10:2dd::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8158.23; Fri, 22 Nov 2024 04:24:23 +0000 Received: from PAXPR04MB8285.eurprd04.prod.outlook.com ([fe80::e003:8fb:64ea:acfd]) by PAXPR04MB8285.eurprd04.prod.outlook.com ([fe80::e003:8fb:64ea:acfd%5]) with mapi id 15.20.8158.024; Fri, 22 Nov 2024 04:24:23 +0000 From: Hou Qi To: libcamera-devel@lists.libcamera.org Cc: jared.hu@nxp.com, qi.hou@nxp.com, julien.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 X-ClientProxiedBy: SI2P153CA0024.APCP153.PROD.OUTLOOK.COM (2603:1096:4:190::13) To PAXPR04MB8285.eurprd04.prod.outlook.com (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; ARA: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:; IPV:NLI; SFV:NSPM; H:PAXPR04MB8285.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(1800799024)(52116014)(376014)(366016)(38350700014); DIR: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 (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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" GStreamer video-info calculated stride and offset may differ from those used by the camera. For stride and offset mismatch, this patch adds video meta to buffer if downstream supports VideoMeta through allocation query. Otherwise, get downstream provided buffer pool or create internal buffer pool using the caps, and copy video frame to the system memory acquired from the buffer pool. Signed-off-by: Hou Qi --- src/gstreamer/gstlibcamera-utils.cpp | 33 +++++++ src/gstreamer/gstlibcamera-utils.h | 4 + src/gstreamer/gstlibcamerapool.cpp | 9 +- src/gstreamer/gstlibcamerapool.h | 3 +- src/gstreamer/gstlibcamerasrc.cpp | 142 ++++++++++++++++++++++++++- 5 files changed, 186 insertions(+), 5 deletions(-) diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp index 732987ef..09af9204 100644 --- a/src/gstreamer/gstlibcamera-utils.cpp +++ b/src/gstreamer/gstlibcamera-utils.cpp @@ -591,6 +591,39 @@ gst_task_resume(GstTask *task) } #endif +#if !GST_CHECK_VERSION(1, 22, 0) +/* + * Copyright (C) <1999> Erik Walthinsen + * Library <2002> Ronald Bultje + * Copyright (C) <2007> David A. Schleef + */ +/* This function has been imported directly from the gstreamer project to + * support backwards compatibility and should be removed when the older + * version is no longer supported. */ +gint gst_video_format_info_extrapolate_stride(const GstVideoFormatInfo *finfo, gint plane, gint stride) +{ + gint estride; + gint comp[GST_VIDEO_MAX_COMPONENTS]; + gint i; + + /* there is nothing to extrapolate on first plane */ + if (plane == 0) + return stride; + + gst_video_format_info_component(finfo, plane, comp); + + /* For now, all planar formats have a single component on first plane, but + * if there was a planar format with more, we'd have to make a ratio of the + * number of component on the first plane against the number of component on + * the current plane. */ + estride = 0; + for (i = 0; i < GST_VIDEO_MAX_COMPONENTS && comp[i] >= 0; i++) + estride += GST_VIDEO_FORMAT_INFO_SCALE_WIDTH(finfo, comp[i], stride); + + return estride; +} +#endif + G_LOCK_DEFINE_STATIC(cm_singleton_lock); static std::weak_ptr cm_singleton_ptr; diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h index cab1c814..81149280 100644 --- a/src/gstreamer/gstlibcamera-utils.h +++ b/src/gstreamer/gstlibcamera-utils.h @@ -35,6 +35,10 @@ static inline void gst_clear_event(GstEvent **event_ptr) #if !GST_CHECK_VERSION(1, 17, 1) gboolean gst_task_resume(GstTask *task); #endif + +#if !GST_CHECK_VERSION(1, 22, 0) +gint gst_video_format_info_extrapolate_stride(const GstVideoFormatInfo *finfo, gint plane, gint stride); +#endif std::shared_ptr gst_libcamera_get_camera_manager(int &ret); /** diff --git a/src/gstreamer/gstlibcamerapool.cpp b/src/gstreamer/gstlibcamerapool.cpp index 9cd7eccb..04bcaeb1 100644 --- a/src/gstreamer/gstlibcamerapool.cpp +++ b/src/gstreamer/gstlibcamerapool.cpp @@ -135,7 +135,8 @@ gst_libcamera_pool_class_init(GstLibcameraPoolClass *klass) } GstLibcameraPool * -gst_libcamera_pool_new(GstLibcameraAllocator *allocator, Stream *stream) +gst_libcamera_pool_new(GstLibcameraAllocator *allocator, Stream *stream, + GstVideoInfo *info, gboolean add_video_meta) { auto *pool = GST_LIBCAMERA_POOL(g_object_new(GST_TYPE_LIBCAMERA_POOL, nullptr)); @@ -145,6 +146,12 @@ gst_libcamera_pool_new(GstLibcameraAllocator *allocator, Stream *stream) gsize pool_size = gst_libcamera_allocator_get_pool_size(allocator, stream); for (gsize i = 0; i < pool_size; i++) { GstBuffer *buffer = gst_buffer_new(); + if (add_video_meta) { + gst_buffer_add_video_meta_full(buffer, GST_VIDEO_FRAME_FLAG_NONE, + GST_VIDEO_INFO_FORMAT(info), GST_VIDEO_INFO_WIDTH(info), + GST_VIDEO_INFO_HEIGHT(info), GST_VIDEO_INFO_N_PLANES(info), + info->offset, info->stride); + } pool->queue->push_back(buffer); } diff --git a/src/gstreamer/gstlibcamerapool.h b/src/gstreamer/gstlibcamerapool.h index 2a7a9c77..b522b4a5 100644 --- a/src/gstreamer/gstlibcamerapool.h +++ b/src/gstreamer/gstlibcamerapool.h @@ -14,6 +14,7 @@ #include "gstlibcameraallocator.h" #include +#include #include @@ -21,7 +22,7 @@ G_DECLARE_FINAL_TYPE(GstLibcameraPool, gst_libcamera_pool, GST_LIBCAMERA, POOL, GstBufferPool) GstLibcameraPool *gst_libcamera_pool_new(GstLibcameraAllocator *allocator, - libcamera::Stream *stream); + libcamera::Stream *stream, GstVideoInfo *info, gboolean add_video_meta); libcamera::Stream *gst_libcamera_pool_get_stream(GstLibcameraPool *self); diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp index 8efa25f4..eb43f053 100644 --- a/src/gstreamer/gstlibcamerasrc.cpp +++ b/src/gstreamer/gstlibcamerasrc.cpp @@ -150,6 +150,10 @@ struct _GstLibcameraSrc { GstLibcameraSrcState *state; GstLibcameraAllocator *allocator; GstFlowCombiner *flow_combiner; + + gboolean frame_copy; + GstVideoInfo info; + GstBufferPool *pool; }; enum { @@ -268,6 +272,43 @@ GstLibcameraSrcState::requestCompleted(Request *request) gst_task_resume(src_->task); } +static GstFlowReturn +gst_libcamera_video_frame_copy(GstLibcameraSrc *self, GstBuffer *src, GstBuffer *dest, guint32 stride) +{ + GstVideoInfo src_info = self->info; + GstVideoFrame src_frame, dest_frame; + gsize offset = 0; + + for (guint i = 0; i < GST_VIDEO_INFO_N_PLANES(&src_info); i++) { + stride = gst_video_format_info_extrapolate_stride(src_info.finfo, i, stride); + src_info.stride[i] = stride; + src_info.offset[i] = offset; + offset += stride * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(src_info.finfo, i, + GST_VIDEO_INFO_HEIGHT(&src_info)); + } + src_info.size = gst_buffer_get_size(src); + + if (!gst_video_frame_map(&src_frame, &src_info, src, GST_MAP_READ)) + goto invalid_buffer; + + if (!gst_video_frame_map(&dest_frame, &self->info, dest, GST_MAP_WRITE)) { + gst_video_frame_unmap(&src_frame); + goto invalid_buffer; + } + + gst_video_frame_copy(&dest_frame, &src_frame); + + gst_video_frame_unmap(&src_frame); + gst_video_frame_unmap(&dest_frame); + + return GST_FLOW_OK; + +invalid_buffer : { + GST_ERROR_OBJECT(self, "Could not map buffer"); + return GST_FLOW_ERROR; +} +} + /* Must be called with stream_lock held. */ int GstLibcameraSrcState::processRequest() { @@ -292,12 +333,34 @@ int GstLibcameraSrcState::processRequest() GstFlowReturn ret = GST_FLOW_OK; gst_flow_combiner_reset(src_->flow_combiner); - for (GstPad *srcpad : srcpads_) { + for (gsize i = 0; i < src_->state->srcpads_.size(); i++) { + GstPad *srcpad = src_->state->srcpads_[i]; Stream *stream = gst_libcamera_pad_get_stream(srcpad); GstBuffer *buffer = wrap->detachBuffer(stream); + GstBuffer *tmp = NULL; + const StreamConfiguration &stream_cfg = src_->state->config_->at(i); FrameBuffer *fb = gst_libcamera_buffer_get_frame_buffer(buffer); + if (src_->frame_copy) { + ret = gst_buffer_pool_acquire_buffer(src_->pool, &tmp, NULL); + if (ret != GST_FLOW_OK) { + GST_ERROR("Failed to acquire buffer"); + gst_buffer_unref(buffer); + return -EPIPE; + } + + ret = gst_libcamera_video_frame_copy(src_, buffer, tmp, stream_cfg.stride); + gst_buffer_unref(buffer); + if (ret != GST_FLOW_OK) { + GST_ERROR("Failed to copy buffer"); + gst_buffer_unref(tmp); + return -EPIPE; + } + + buffer = tmp; + } + if (GST_CLOCK_TIME_IS_VALID(wrap->pts_)) { GST_BUFFER_PTS(buffer) = wrap->pts_; gst_libcamera_pad_set_latency(srcpad, wrap->latency_); @@ -497,9 +560,74 @@ gst_libcamera_src_negotiate(GstLibcameraSrc *self) for (gsize i = 0; i < state->srcpads_.size(); i++) { GstPad *srcpad = state->srcpads_[i]; const StreamConfiguration &stream_cfg = state->config_->at(i); + gboolean add_video_meta = false; + GstVideoInfo info; + + g_autoptr(GstCaps) caps = gst_libcamera_stream_configuration_to_caps(stream_cfg); + gst_libcamera_framerate_to_caps(caps, element_caps); - GstLibcameraPool *pool = gst_libcamera_pool_new(self->allocator, - stream_cfg.stream()); + gst_video_info_init(&info); + gst_video_info_from_caps(&info, caps); + + /* stride mismatch between camera stride and that calculated by video-info */ + if (static_cast(info.stride[0]) != stream_cfg.stride && + GST_VIDEO_INFO_FORMAT(&info) != GST_VIDEO_FORMAT_ENCODED) { + GstQuery *query = NULL; + gboolean need_pool = true; + + query = gst_query_new_allocation(caps, need_pool); + if (!gst_pad_peer_query(srcpad, query)) + GST_DEBUG_OBJECT(self, "Didn't get downstream ALLOCATION hints"); + else + add_video_meta = gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL); + + if (add_video_meta) { + guint k, stride; + gsize offset = 0; + + /* this should be updated if tiled formats get added in the future. */ + for (k = 0; k < GST_VIDEO_INFO_N_PLANES(&info); k++) { + stride = gst_video_format_info_extrapolate_stride(info.finfo, k, stream_cfg.stride); + info.stride[k] = stride; + info.offset[k] = offset; + offset += stride * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info.finfo, k, + GST_VIDEO_INFO_HEIGHT(&info)); + } + } else { + GstBufferPool *pool = NULL; + self->frame_copy = true; + + if (gst_query_get_n_allocation_pools(query) > 0) + gst_query_parse_nth_allocation_pool(query, 0, &pool, NULL, NULL, NULL); + + if (self->pool) + gst_object_unref(self->pool); + + if (pool) + self->pool = pool; + else { + GstStructure *config; + guint min_buffers = 3; + self->pool = gst_video_buffer_pool_new(); + + config = gst_buffer_pool_get_config(self->pool); + gst_buffer_pool_config_set_params(config, caps, info.size, min_buffers, 0); + gst_buffer_pool_set_config(GST_BUFFER_POOL_CAST(self->pool), config); + GST_DEBUG_OBJECT(self, "Own pool config is %" GST_PTR_FORMAT, config); + } + + if (!gst_buffer_pool_set_active(self->pool, true)) { + GST_ERROR_OBJECT(self, "Failed to active buffer pool"); + gst_caps_unref(caps); + return false; + } + } + gst_query_unref(query); + } + + self->info = info; + GstLibcameraPool *pool = gst_libcamera_pool_new(self->allocator, stream_cfg.stream(), + &info, add_video_meta); g_signal_connect_swapped(pool, "buffer-notify", G_CALLBACK(gst_task_resume), self->task); @@ -842,6 +970,12 @@ gst_libcamera_src_finalize(GObject *object) GObjectClass *klass = G_OBJECT_CLASS(gst_libcamera_src_parent_class); GstLibcameraSrc *self = GST_LIBCAMERA_SRC(object); + if (self->pool) { + gst_buffer_pool_set_active(self->pool, false); + gst_object_unref(self->pool); + self->pool = NULL; + } + g_rec_mutex_clear(&self->stream_lock); g_clear_object(&self->task); g_mutex_clear(&self->state->lock_); @@ -875,6 +1009,8 @@ gst_libcamera_src_init(GstLibcameraSrc *self) /* C-style friend. */ state->src_ = self; self->state = state; + self->frame_copy = false; + self->pool = NULL; } static GstPad *