[{"id":34251,"web_url":"https://patchwork.libcamera.org/comment/34251/","msgid":"<PAXPR04MB82858951EDB8FC3BD5C66ED79793A@PAXPR04MB8285.eurprd04.prod.outlook.com>","date":"2025-05-16T07:35:49","subject":"RE: [PATCH v7] gstreamer: Add GstVideoMeta support","submitter":{"id":195,"url":"https://patchwork.libcamera.org/api/people/195/","name":"Qi Hou","email":"qi.hou@nxp.com"},"content":"V7 will cause build break since I tested it on an older local rebase. I have updated to v8. Sorry for inconvenience.\n\nRegards,\nQi Hou\n\n-----Original Message-----\nFrom: Qi Hou \nSent: 2025年5月16日 9:44\nTo: libcamera-devel@lists.libcamera.org\nCc: nicolas@ndufresne.ca; kieran.bingham@ideasonboard.com; Jared Hu <jared.hu@nxp.com>; Qi Hou <qi.hou@nxp.com>; Julien Vuillaumier <julien.vuillaumier@nxp.com>\nSubject: [PATCH v7] gstreamer: Add GstVideoMeta support\n\nGStreamer video-info calculated stride and offset may differ from those used by the camera.\n\nFor stride and offset mismatch, this patch adds video meta to buffer if downstream supports VideoMeta through allocation query. Otherwise, create a internal VideoPool using the caps, and copy video frame to this system memory.\n\nSigned-off-by: Hou Qi <qi.hou@nxp.com>\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n---\n src/gstreamer/gstlibcamera-utils.cpp |  33 ++++++\n src/gstreamer/gstlibcamera-utils.h   |   5 +\n src/gstreamer/gstlibcamerapad.cpp    |  31 ++++++\n src/gstreamer/gstlibcamerapad.h      |   8 ++\n src/gstreamer/gstlibcamerapool.cpp   |  15 ++-\n src/gstreamer/gstlibcamerapool.h     |   3 +-\n src/gstreamer/gstlibcamerasrc.cpp    | 147 ++++++++++++++++++++++++++-\n 7 files changed, 238 insertions(+), 4 deletions(-)\n\ndiff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp\nindex 2edebba0..bf12cb07 100644\n--- a/src/gstreamer/gstlibcamera-utils.cpp\n+++ b/src/gstreamer/gstlibcamera-utils.cpp\n@@ -599,6 +599,39 @@ gst_task_resume(GstTask *task)  }  #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+/* This function has been imported directly from the gstreamer project \n+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 \n+*finfo, gint plane, gint stride) {\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 4978987c..5f4e8a0f 100644\n--- a/src/gstreamer/gstlibcamera-utils.h\n+++ b/src/gstreamer/gstlibcamera-utils.h\n@@ -36,6 +36,11 @@ static inline void gst_clear_event(GstEvent **event_ptr)  #if !GST_CHECK_VERSION(1, 17, 1)  gboolean gst_task_resume(GstTask *task);  #endif\n+\n+#if !GST_CHECK_VERSION(1, 22, 0)\n+gint gst_video_format_info_extrapolate_stride(const GstVideoFormatInfo \n+*finfo, gint plane, gint stride); #endif\n+\n std::shared_ptr<libcamera::CameraManager> gst_libcamera_get_camera_manager(int &ret);\n \n /**\ndiff --git a/src/gstreamer/gstlibcamerapad.cpp b/src/gstreamer/gstlibcamerapad.cpp\nindex 7b22aebe..3bc2bc87 100644\n--- a/src/gstreamer/gstlibcamerapad.cpp\n+++ b/src/gstreamer/gstlibcamerapad.cpp\n@@ -18,6 +18,8 @@ struct _GstLibcameraPad {\n \tGstPad parent;\n \tStreamRole role;\n \tGstLibcameraPool *pool;\n+\tGstBufferPool *video_pool;\n+\tGstVideoInfo info;\n \tGstClockTime latency;\n };\n \n@@ -153,6 +155,35 @@ gst_libcamera_pad_set_pool(GstPad *pad, GstLibcameraPool *pool)\n \tself->pool = pool;\n }\n \n+GstBufferPool *\n+gst_libcamera_pad_get_video_pool(GstPad *pad) {\n+\tauto *self = GST_LIBCAMERA_PAD(pad);\n+\treturn self->video_pool;\n+}\n+\n+void gst_libcamera_pad_set_video_pool(GstPad *pad, GstBufferPool \n+*video_pool) {\n+\tauto *self = GST_LIBCAMERA_PAD(pad);\n+\n+\tif (self->video_pool)\n+\t\tg_object_unref(self->video_pool);\n+\tself->video_pool = video_pool;\n+}\n+\n+GstVideoInfo gst_libcamera_pad_get_video_info(GstPad *pad) {\n+\tauto *self = GST_LIBCAMERA_PAD(pad);\n+\treturn self->info;\n+}\n+\n+void gst_libcamera_pad_set_video_info(GstPad *pad, const GstVideoInfo \n+*info) {\n+\tauto *self = GST_LIBCAMERA_PAD(pad);\n+\n+\tself->info = *info;\n+}\n+\n Stream *\n gst_libcamera_pad_get_stream(GstPad *pad)  { diff --git a/src/gstreamer/gstlibcamerapad.h b/src/gstreamer/gstlibcamerapad.h index 630c168a..f98b8a7f 100644\n--- a/src/gstreamer/gstlibcamerapad.h\n+++ b/src/gstreamer/gstlibcamerapad.h\n@@ -23,6 +23,14 @@ GstLibcameraPool *gst_libcamera_pad_get_pool(GstPad *pad);\n \n void gst_libcamera_pad_set_pool(GstPad *pad, GstLibcameraPool *pool);\n \n+GstBufferPool *gst_libcamera_pad_get_video_pool(GstPad *pad);\n+\n+void gst_libcamera_pad_set_video_pool(GstPad *pad, GstBufferPool \n+*video_pool);\n+\n+GstVideoInfo gst_libcamera_pad_get_video_info(GstPad *pad);\n+\n+void gst_libcamera_pad_set_video_info(GstPad *pad, const GstVideoInfo \n+*info);\n+\n libcamera::Stream *gst_libcamera_pad_get_stream(GstPad *pad);\n \n void gst_libcamera_pad_set_latency(GstPad *pad, GstClockTime latency); diff --git a/src/gstreamer/gstlibcamerapool.cpp b/src/gstreamer/gstlibcamerapool.cpp\nindex 9cd7eccb..8278144f 100644\n--- a/src/gstreamer/gstlibcamerapool.cpp\n+++ b/src/gstreamer/gstlibcamerapool.cpp\n@@ -134,8 +134,20 @@ gst_libcamera_pool_class_init(GstLibcameraPoolClass *klass)\n \t\t\t\t\t\t     G_TYPE_NONE, 0);\n }\n \n+static void\n+gst_libcamera_buffer_add_video_meta(GstBuffer *buffer, GstVideoInfo \n+*info) {\n+\tGstVideoMeta *vmeta;\n+\tvmeta = gst_buffer_add_video_meta_full(buffer, GST_VIDEO_FRAME_FLAG_NONE,\n+\t\t\t\t\t       GST_VIDEO_INFO_FORMAT(info), GST_VIDEO_INFO_WIDTH(info),\n+\t\t\t\t\t       GST_VIDEO_INFO_HEIGHT(info), GST_VIDEO_INFO_N_PLANES(info),\n+\t\t\t\t\t       info->offset, info->stride);\n+\tGST_META_FLAGS(vmeta) = (GstMetaFlags)(GST_META_FLAGS(vmeta) | \n+GST_META_FLAG_POOLED); }\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)\n {\n \tauto *pool = GST_LIBCAMERA_POOL(g_object_new(GST_TYPE_LIBCAMERA_POOL, nullptr));\n \n@@ -145,6 +157,7 @@ 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\tgst_libcamera_buffer_add_video_meta(buffer, info);\n \t\tpool->queue->push_back(buffer);\n \t}\n \ndiff --git a/src/gstreamer/gstlibcamerapool.h b/src/gstreamer/gstlibcamerapool.h\nindex 2a7a9c77..02ee4dd4 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);\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 5e9e843d..7275855a 100644\n--- a/src/gstreamer/gstlibcamerasrc.cpp\n+++ b/src/gstreamer/gstlibcamerasrc.cpp\n@@ -268,6 +268,58 @@ GstLibcameraSrcState::requestCompleted(Request *request)\n \tgst_task_resume(src_->task);\n }\n \n+static void\n+gst_libcamera_extrapolate_info(GstVideoInfo *info, guint32 stride) {\n+\tguint i, estride;\n+\tgsize offset = 0;\n+\n+\t/* this should be updated if tiled formats get added in the future. */\n+\tfor (i = 0; i < GST_VIDEO_INFO_N_PLANES(info); i++) {\n+\t\testride = gst_video_format_info_extrapolate_stride(info->finfo, i, stride);\n+\t\tinfo->stride[i] = estride;\n+\t\tinfo->offset[i] = offset;\n+\t\toffset += estride * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT(info->finfo, i,\n+\t\t\t\t\t\t\t\t       GST_VIDEO_INFO_HEIGHT(info));\n+\t}\n+}\n+\n+static GstFlowReturn\n+gst_libcamera_video_frame_copy(GstBuffer *src, GstBuffer *dest, const \n+GstVideoInfo *dest_info, guint32 stride) {\n+\tGstVideoInfo src_info = *dest_info;\n+\tGstVideoFrame src_frame, dest_frame;\n+\n+\tgst_libcamera_extrapolate_info(&src_info, stride);\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\tGST_ERROR(\"Could not map buffer\");\n+\t\tgoto error;\n+\t}\n+\n+\tif (!gst_video_frame_map(&dest_frame, dest_info, dest, GST_MAP_WRITE)) {\n+\t\tGST_ERROR(\"Could not map buffer\");\n+\t\tgst_video_frame_unmap(&src_frame);\n+\t\tgoto error;\n+\t}\n+\n+\tif (!gst_video_frame_copy(&dest_frame, &src_frame)) {\n+\t\tGST_ERROR(\"Could not copy frame\");\n+\t\tgst_video_frame_unmap(&src_frame);\n+\t\tgst_video_frame_unmap(&dest_frame);\n+\t\tgoto error;\n+\t}\n+\n+\tgst_video_frame_unmap(&src_frame);\n+\tgst_video_frame_unmap(&dest_frame);\n+\n+\treturn GST_FLOW_OK;\n+\n+error:\n+\treturn GST_FLOW_ERROR;\n+}\n+\n /* Must be called with stream_lock held. */  int GstLibcameraSrcState::processRequest()\n {\n@@ -292,11 +344,41 @@ 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 < srcpads_.size(); i++) {\n+\t\tGstPad *srcpad = srcpads_[i];\n \t\tStream *stream = gst_libcamera_pad_get_stream(srcpad);\n \t\tGstBuffer *buffer = wrap->detachBuffer(stream);\n \n \t\tFrameBuffer *fb = gst_libcamera_buffer_get_frame_buffer(buffer);\n+\t\tconst StreamConfiguration &stream_cfg = config_->at(i);\n+\t\tGstBufferPool *video_pool = gst_libcamera_pad_get_video_pool(srcpad);\n+\n+\t\tif (video_pool) {\n+\t\t\t/* Only set video pool when a copy is needed */\n+\t\t\tGstBuffer *copy = NULL;\n+\t\t\tconst GstVideoInfo info = gst_libcamera_pad_get_video_info(srcpad);\n+\n+\t\t\tret = gst_buffer_pool_acquire_buffer(video_pool, &copy, NULL);\n+\t\t\tif (ret != GST_FLOW_OK) {\n+\t\t\t\tgst_buffer_unref(buffer);\n+\t\t\t\tGST_ELEMENT_ERROR(src_, RESOURCE, SETTINGS,\n+\t\t\t\t\t\t(\"Failed to acquire buffer\"),\n+\t\t\t\t\t\t(\"GstLibcameraSrcState::processRequest() failed: %s\", g_strerror(-ret)));\n+\t\t\t\treturn -EPIPE;\n+\t\t\t}\n+\n+\t\t\tret = gst_libcamera_video_frame_copy(buffer, copy, &info, stream_cfg.stride);\n+\t\t\tgst_buffer_unref(buffer);\n+\t\t\tif (ret != GST_FLOW_OK) {\n+\t\t\t\tgst_buffer_unref(copy);\n+\t\t\t\tGST_ELEMENT_ERROR(src_, RESOURCE, SETTINGS,\n+\t\t\t\t\t\t(\"Failed to copy buffer\"),\n+\t\t\t\t\t\t(\"GstLibcameraSrcState::processRequest() failed: %s\", g_strerror(-ret)));\n+\t\t\t\treturn -EPIPE;\n+\t\t\t}\n+\n+\t\t\tbuffer = copy;\n+\t\t}\n \n \t\tif (GST_CLOCK_TIME_IS_VALID(wrap->pts_)) {\n \t\t\tGST_BUFFER_PTS(buffer) = wrap->pts_; @@ -499,13 +581,68 @@ 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\tGstBufferPool *video_pool = NULL;\n+\t\tGstVideoInfo info;\n+\n+\t\tg_autoptr(GstCaps) caps = \n+gst_libcamera_stream_configuration_to_caps(stream_cfg);\n+\n+\t\tgst_video_info_from_caps(&info, caps);\n+\t\tgst_libcamera_pad_set_video_info(srcpad, &info);\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\tconst gboolean need_pool = true;\n+\t\t\tgboolean has_video_meta = false;\n+\n+\t\t\tgst_libcamera_extrapolate_info(&info, stream_cfg.stride);\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\thas_video_meta = gst_query_find_allocation_meta(query, \n+GST_VIDEO_META_API_TYPE, NULL);\n+\n+\t\t\tif (!has_video_meta) {\n+\t\t\t\tGstBufferPool *pool = NULL;\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, \n+NULL);\n+\n+\t\t\t\tif (pool)\n+\t\t\t\t\tvideo_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\tvideo_pool = gst_video_buffer_pool_new();\n+\n+\t\t\t\t\tconfig = gst_buffer_pool_get_config(video_pool);\n+\t\t\t\t\tgst_buffer_pool_config_set_params(config, caps, info.size, \n+min_buffers, 0);\n+\n+\t\t\t\t\tGST_DEBUG_OBJECT(self, \"Own pool config is %\" GST_PTR_FORMAT, \n+config);\n+\n+\t\t\t\t\tgst_buffer_pool_set_config(GST_BUFFER_POOL_CAST(video_pool), config);\n+\t\t\t\t}\n+\n+\t\t\t\tif (!gst_buffer_pool_set_active(video_pool, true)) {\n+\t\t\t\t\tgst_caps_unref(caps);\n+\t\t\t\t\tGST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,\n+\t\t\t\t\t\t\t(\"Failed to active buffer pool\"),\n+\t\t\t\t\t\t\t(\"gst_libcamera_src_negotiate() failed\"));\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\tGstLibcameraPool *pool = gst_libcamera_pool_new(self->allocator,\n-\t\t\t\t\t\t\t\tstream_cfg.stream());\n+\t\t\t\t\t\t\t\tstream_cfg.stream(), &info);\n \t\tg_signal_connect_swapped(pool, \"buffer-notify\",\n \t\t\t\t\t G_CALLBACK(gst_task_resume), self->task);\n \n \t\tgst_libcamera_pad_set_pool(srcpad, pool);\n+\t\tgst_libcamera_pad_set_video_pool(srcpad, video_pool);\n \n \t\t/* Clear all reconfigure flags. */\n \t\tgst_pad_check_reconfigure(srcpad);\n@@ -922,6 +1059,12 @@ gst_libcamera_src_release_pad(GstElement *element, GstPad *pad)\n \t\tauto end_iterator = pads.end();\n \t\tauto pad_iterator = std::find(begin_iterator, end_iterator, pad);\n \n+\t\tGstBufferPool *video_pool = gst_libcamera_pad_get_video_pool(pad);\n+\t\tif (video_pool) {\n+\t\t\tgst_buffer_pool_set_active(video_pool, false);\n+\t\t\tgst_object_unref(video_pool);\n+\t\t}\n+\n \t\tif (pad_iterator != end_iterator) {\n \t\t\tg_object_unref(*pad_iterator);\n \t\t\tpads.erase(pad_iterator);\n--\n2.34.1","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 68768C3200\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 16 May 2025 07:35:53 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6673868B55;\n\tFri, 16 May 2025 09:35:52 +0200 (CEST)","from AS8PR03CU001.outbound.protection.outlook.com\n\t(mail-westeuropeazlp170120005.outbound.protection.outlook.com\n\t[IPv6:2a01:111:f403:c201::5])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id F077268B55\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 16 May 2025 09:35:50 +0200 (CEST)","from PAXPR04MB8285.eurprd04.prod.outlook.com\n\t(2603:10a6:102:1ca::15)\n\tby PAXPR04MB9490.eurprd04.prod.outlook.com (2603:10a6:102:2c2::18)\n\twith Microsoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8722.30;\n\tFri, 16 May 2025 07:35:49 +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%3]) with mapi id 15.20.8722.031;\n\tFri, 16 May 2025 07:35:49 +0000"],"Authentication-Results":["lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=nxp.com header.i=@nxp.com header.b=\"jCU7uwHj\";\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=mHl58dJm4k087nxVhEFbWCSSgiMvca0qCF9RPq+tZbdWh4qLCaPy/buivnZ4c0DhzkPnlPzAYPvBC6TqQeb8HnMEr5/NdyI/TOUZmBfsAtTgAFsR7Xt2l2nsL9t4606UVDlQQAUuFcwnd1DIuQHOMlipxaNp07Dt6etycJn297JNMvwPKKpXBF0QfUbgxfCc5jXKva1qnS7cMb5pSWGfKvp8MAMAP/FgxQ80nPSh4dRzFSP4Rm1BRkiT+nLyO40nG/VZ21cQutQnGXBxYD4LCqNAQXRcuzWFERsBfzzgeeL82L6D5V2oU2Lk3NatCzloQqsPiMN2ONbKC5rwzZ+FVw==","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=xaiBXhKGmwXeRdUNgru2TnMR+wD3qSe7d9cBIC2tPec=;\n\tb=YYmIRMRnsUUMzWst+dZ/SAc9d1UOcNFnZw4PXVM+d5NsmSDT6tken8rlXf9+BiWOMtwJzd3jb9lGp/O4Sf/Cmor/IHfPoCFYFBVrz7h3HQ12tST56J1Qa60XG9rlOWe07PCfU8qQJMhG7Z436hQd7k8/vdtWtc0eeJ1ohqEp4GZFZJcP9LXIHtDECZuKChZwR2fW29Z3SPBN1wZ3DbW2OMhUVWjmn+V6TSs19Dk7+PH2B4tfD5hWgdpH8JfHmwk1az2+Jd/QjZkvW/AphdudY/WkNlWEcjDWQBG1aGK7yBuwH0d2Z99qgi5EDBTu/aTVHOav7PVksgLGbrfZNq8Onw==","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=xaiBXhKGmwXeRdUNgru2TnMR+wD3qSe7d9cBIC2tPec=;\n\tb=jCU7uwHjY+8TI7JWq/MQSNx3LhLq5FkwQHucLI8a7vaiCjL+MZyhiGU/sPSOG9SJ2a6XNuWs4Oj23+ddhFWcZD2I8bBnZERpiNkzO7ik3bpt5LLOGA+4LljyGw9dIQvnnEzyPoftVR3X96MV7AMNsALpKgKtGMCcDYrpwQIBiBt5IWFV4EJBPhSqAPvMcSW/A/nDeXSRwz6h/NWj2TibYbDcELsPnWgcgRP/FY2JjCWzc6b0EsivBajesYgoeehByOHCD56GtlG+ZuJ2quhhNxaouQbdhHaR5o0ACPSr+Tp0KUS/hInUCV/3mnS3acneK+Ao3gsEdF3fmoUk9nbLiA==","From":"Qi Hou <qi.hou@nxp.com>","To":"\"libcamera-devel@lists.libcamera.org\"\n\t<libcamera-devel@lists.libcamera.org>","CC":"\"nicolas@ndufresne.ca\" <nicolas@ndufresne.ca>,\n\t\"kieran.bingham@ideasonboard.com\" <kieran.bingham@ideasonboard.com>,\n\tJared Hu\n\t<jared.hu@nxp.com>, Julien Vuillaumier <julien.vuillaumier@nxp.com>","Subject":"RE: [PATCH v7] gstreamer: Add GstVideoMeta support","Thread-Topic":"[PATCH v7] gstreamer: Add GstVideoMeta support","Thread-Index":"AQHbxgP4zBpo8bRf1EOdv4e/RvNkVbPU3PBw","Date":"Fri, 16 May 2025 07:35:49 +0000","Message-ID":"<PAXPR04MB82858951EDB8FC3BD5C66ED79793A@PAXPR04MB8285.eurprd04.prod.outlook.com>","References":"<20250516014315.4015034-1-qi.hou@nxp.com>","In-Reply-To":"<20250516014315.4015034-1-qi.hou@nxp.com>","Accept-Language":"zh-CN, en-US","Content-Language":"en-US","X-MS-Has-Attach":"","X-MS-TNEF-Correlator":"","authentication-results":["lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=nxp.com header.i=@nxp.com header.b=\"jCU7uwHj\";\n\tdkim-atps=neutral","dkim=none (message not signed)\n\theader.d=none;dmarc=none action=none header.from=nxp.com;"],"x-ms-publictraffictype":"Email","x-ms-traffictypediagnostic":"PAXPR04MB8285:EE_|PAXPR04MB9490:EE_","x-ms-office365-filtering-correlation-id":"797cbaf7-769c-46af-0ba8-08dd944c477f","x-ms-exchange-senderadcheck":"1","x-ms-exchange-antispam-relay":"0","x-microsoft-antispam":"BCL:0;\n\tARA:13230040|1800799024|376014|366016|7053199007|38070700018; ","x-microsoft-antispam-message-info":"=?gb2312?b?MWY0aXd5OWY3bDZaY3JLazlY?=\n\t=?gb2312?b?dUJYcTNZNGRWSHNSczlHRjNReDN4MDBMYXNFV3R0OFZUa1BIbE9r?=\n\t=?gb2312?b?Sy9IWnBTZUt0RlBsS1g5VzJPZU10c05FdWtwMExyS2UvWFlLRWtu?=\n\t=?gb2312?b?NjV0bERUcGZrNUV5c3BnRG1oTVNsc2c4RmVONmJva09Zc3ZaY2Mw?=\n\t=?gb2312?b?azVHQkcySUkvcWtYSWRsNWZGUUF6YmJoNlBSejRtRzVncnZtQnBV?=\n\t=?gb2312?b?ZGRDTW54U1k2YTBIM25VaWIybnk2QVRUUDNGbUtGSlZsYnZDWnRi?=\n\t=?gb2312?b?MWtWYmRnQ3hWa0ljdnZ2WERxem5MWTMzbDhhWFNEU2M5UlUydUt3?=\n\t=?gb2312?b?RTB4Q3RCTXJucU03enRmcEh0UFV4ZnVmRHpPdkk2N1VRUnRGaEJF?=\n\t=?gb2312?b?NVpxU3VPRUR4Nm4yYU9WS2lDZENtS1ZTdmkrTnl2a2xOaE1KcVJs?=\n\t=?gb2312?b?ZDN3Wkx0eU9YcWNKaExaSXNiN2JmZW00eXRVcmZYYlNJUDhkdG12?=\n\t=?gb2312?b?NW42bDBHVkx1MjJxQ2VTdWN6bWpqWHA1end1K2QrQzdpdk5vWDRV?=\n\t=?gb2312?b?QXlUeDcvdGszRVdVNWxuQ3d3dVpQRHVUZndRbTR0Y2daUVpmeWdQ?=\n\t=?gb2312?b?a2hRWGVxYWVqRS90RVh0TURFOGlJaWFUb0R2bGJJbXgydHh1M1hD?=\n\t=?gb2312?b?K2JKZWE5Mk5pcy8xR3dxRVhscVo0MHhwWWh5TXN1Wm5QTW9hZ2Iz?=\n\t=?gb2312?b?aEIxRFhFVnozZVk1anRKNXBxcW9NeWdZSU0rYkNvdlJqR1g2Tlo1?=\n\t=?gb2312?b?eGdvOCt2L3BWTE9na1hQWXNmRjYwZDZhczFBT2lTejRUd1lCTjB3?=\n\t=?gb2312?b?ZHpLRk40aDllZWFjTTVTY0FwZ3ZhcXF2YTloYjRhaG5nN2o4cWJG?=\n\t=?gb2312?b?cERhUi9YUTg0VHl4cWE1eDVBVDVCM3BGQWwxVzNCamtHQ2tkMGVH?=\n\t=?gb2312?b?NGFnMjZZVE1uMDgzL2J3NTJzMC91aFFYK0N1cTFDaTBxa3BXSDNz?=\n\t=?gb2312?b?MXd2NXBNLzFUeXhaSzJDVmxreThjRFRzV2h0M0NWdGp2RVRhVkht?=\n\t=?gb2312?b?NDFNcnlFYUk4Snc1bjcyeXBxaTNhaERtb0hTejJkTjRCb2YyRGJ2?=\n\t=?gb2312?b?Z1RUdGtPOGFkeVVqV1dpdUMwaHBHZlhuMW5UWDVqQUZsd25EVXBY?=\n\t=?gb2312?b?REJUWkpzZTRPaW54bEhwM3RRTGVOaWNkMHZGRFdPTVZhdUptbmZv?=\n\t=?gb2312?b?QlVYSVhXa2djL1BNVHhpV3RsQ0lDOUs5Umx1b0QzdUJRRkNpR2pE?=\n\t=?gb2312?b?NVZBemNvMUwxLzFFNElJMWtZeGVraGo4RVpWVVk3cnFZMXFWUERX?=\n\t=?gb2312?b?MHllcmhrRGVGNXhJdVVIYk9TWEREMnFGRWtRT1JWMmM3OFNEcWZZ?=\n\t=?gb2312?b?SWJFTHRvUXdvbWNjUnE0aUMyazJUanNoVU1BdEFpTkpUNi9rMkNM?=\n\t=?gb2312?b?QXFIdW4rdDgvWVhGdUdzMWpsaHBHejRtelQwRnZ3YnBtM1FZbEpB?=\n\t=?gb2312?b?MEl1ckZ0dVpSSFBrKzR6b0EzdzFpdWNBajFXenpkNWZDdGEzdUdv?=\n\t=?gb2312?b?ZCtQSFAxZVZuaktHRldWOVAvRUhqTmFTa2VhWmNwSWNpaC9LQS9N?=\n\t=?gb2312?b?TXZBVndnbldlN1Qrd3VHcGhlcmlyQnFzdUgwQmN4aE9IcDFlQ0JO?=\n\t=?gb2312?b?QmpmaDhnOTBuUG1yUURkQlcyMzJOQmdqQ0FqbXllaHVtMXhuTThn?=\n\t=?gb2312?b?dHFYSFg4MmFVOFRhS1dqdEpxOGYydlE3Q2JhSHV2QytoUHh5SEI1?=\n\t=?gb2312?b?cEhIQTNPY0ZYQTF4MlNvWDFJTngzdHA0S2VMTTB0dUNselowVlo4?=\n\t=?gb2312?b?SVRGNkVRc2Q4eFhlSDNMKzJDdEg2UWJEY0w4Y3Njc3RCSG9KcEQ2?=\n\t=?gb2312?b?YklBN0JsQnUvR3dzKzA0Q05LbW1sZU9RTllOd2t1MDgrZ3VDWlJU?=\n\t=?gb2312?b?VTQzQ3ZYamw0OVVTSytiK2FXTmtyYkcyd2d1bVJ2NVRQc1NOajJt?=\n\t=?gb2312?b?M043czhFQWo3dGJCbUpWWDhZYmJuNnhpRmFtT0k0RVBLRnlicnFQ?=\n\t=?gb2312?b?YkR2N3hBUTdIV040UzBNbFpWbml4K2tMZ0NFV1l3U1RRPT0=?=","x-forefront-antispam-report":"CIP:255.255.255.255; CTRY:; LANG:zh-cn; SCL:1; \n\tSRV:; IPV:NLI; SFV:NSPM;\n\tH:PAXPR04MB8285.eurprd04.prod.outlook.com; PTR:; \n\tCAT:NONE;\n\tSFS:(13230040)(1800799024)(376014)(366016)(7053199007)(38070700018);\n\tDIR:OUT; SFP:1101; ","x-ms-exchange-antispam-messagedata-chunkcount":"1","x-ms-exchange-antispam-messagedata-0":"=?gb2312?b?L2lyeW9aeURseEgwRlVibXdF?=\n\t=?gb2312?b?SW5IdGs3TVlsb1pETVE1SnpBQWR1OEd4WVZPcmNTVWcwZHR2NFFM?=\n\t=?gb2312?b?NzhDeE8vNzZCMG1Ma2Z4aW4wdWIrV0tTemRNM29BNzBFUnJSdkFR?=\n\t=?gb2312?b?Q3grQUFUQU56R0VNTElRUkwwZW5YbitRNnRDZjFJQm83ZXdnK1lJ?=\n\t=?gb2312?b?L1lBcDFrQXpZbVhVZXpnK3RlZ1ZXVTdUb3I4eHZtNVdwNXNwWTZn?=\n\t=?gb2312?b?dG9BM25pcUsrcDczeVNMM2gwMkdkdE1RYmpTdXJXQWQ1dkRKNFZy?=\n\t=?gb2312?b?dTN6ZGVCTFpCRmhLRmFrYXdXbGhobmhmTE8xVzFTZktOZENwTzNB?=\n\t=?gb2312?b?VkJzNGZXU2ZTTlJlTklSZ1JCR21DdUx2MmpSOHg3TjVQcWZzVkJi?=\n\t=?gb2312?b?K2JVNVgvWExYTHdVMThZOUkyQWtpOERGU3dJK2VubzBFK3dsUFI4?=\n\t=?gb2312?b?L05tWXVwWXY1M21Tb0w1cDcvOVo4UUR1VUZ3eW5BRDA1QTNnZUt2?=\n\t=?gb2312?b?WiswZW53UnRmTCtkNlhhdldhcEVXNmlVcmZQc29iak9xd0VYSjdi?=\n\t=?gb2312?b?QnRSUDZlYVR4K3hTdEJYOStEYkJTdmcvTnlrdjZXdnM0dWZCKzRV?=\n\t=?gb2312?b?VzUvcWFhRDdxdzZKTGVCaFMrQjJFVzZHeExFVmQ4WlBNTjh2RVMx?=\n\t=?gb2312?b?QnZHMzVSYTVtVVlwZk9XRUF2Y1QxdnpxRGV0eHpqaXZvYlU4QUNN?=\n\t=?gb2312?b?eHloNS9iLytJdU5OZ2FSK1duZ2VOa0E5UGlYaEFTakFyQWdwbW4z?=\n\t=?gb2312?b?aTdNejFvb05yd214RHJTcEkxNVJDUE92QmdXYklRcUVheTY0Z3ZL?=\n\t=?gb2312?b?NTYvRjd4NUdKSVd1Wkw5d0VNaWhYTTZaUXh0cUp0MHJSQXNmT01h?=\n\t=?gb2312?b?ZHhLcGw1V1QxazNBRDJadTkvUlFleTRCbGxaOUhVZkFBSkZGcVA0?=\n\t=?gb2312?b?Znl6bkJsK0IrRW1IaG5VT3VPeE9oSUUxR0hScDdOZjR6L2ozNlRk?=\n\t=?gb2312?b?cmYrdnFJS1JUN1doNFErWHNFdHR1cW4yZnRCUFcxRy9jcGxuNVJw?=\n\t=?gb2312?b?K0JsdE1SNnd3bDNSVm5JY3NrTTBwbnlRZEpURkQySHNqWmpjU0Vi?=\n\t=?gb2312?b?alZSclJWamtoeVdzTm1KZFIrNlVFNU40K0NDU29SL3lIYis5dVk2?=\n\t=?gb2312?b?TXRONlNaYzhqekJxMDJNZSsxQWcxc2VDdzRCWmF6TDVjcmY0dTVD?=\n\t=?gb2312?b?aDh5a0N5M012Z0JoTnBpZzJVNFhSUmtmaUxVYjc1RXhEVnEwYVln?=\n\t=?gb2312?b?R0hNSjVpUzlnQ1lLUjdLTHhLQTJRMU5Rc2c1cEhNYjU5ME5qNXl5?=\n\t=?gb2312?b?a0hmTW5aWFpKWVhHbnhTZUh1UlRWeVY0RFlzSmdoclA2NHpueTh4?=\n\t=?gb2312?b?R1labkl3SGFOLzhYenp4bGFpL2pvWDllWm41THNiM1laTkRpRDB5?=\n\t=?gb2312?b?NzE5Q0JzbXJoM01lOURRNWxQQy9zNk1sN1RxUzVhM3l1ZWdTS3g4?=\n\t=?gb2312?b?dHRmenJ4bWZVWFJ1amRkdVZ4Z1lzdmJBOFMyUlNBTnpqMThZSFhQ?=\n\t=?gb2312?b?YWlHL3hTdVFTLzBZR2dPcHI3RTJxamMweGxic294bWN3clc2eUlu?=\n\t=?gb2312?b?TzI0aGxpcWVQMjIrMmhkRDRpelFCWlNHNmxKL2cwZ3dkQkxmdTQw?=\n\t=?gb2312?b?VUlWZGg1SzlQWXFWNm45R2xVRTdELzRqT1BzOGhSZjdzaVhBWXVM?=\n\t=?gb2312?b?VWd6YVJHK0JuajM0THZCWExIb2YyTjFDZEIzcVhHdkd3cVhOVXNI?=\n\t=?gb2312?b?Z1hBcW5RS3p4RnlpMUJWczVsQmwwcEtHNHdpcHdsRXJxR3ZIR2dw?=\n\t=?gb2312?b?MFE3NVVNekErQ3dBaWpycWZvWTZ5MGpZTDRxcitEV1N0Skt5OXQy?=\n\t=?gb2312?b?S3FGcysyK2k2MXFtSThLWFZIakovY3BjSWRHRFBjWXBxVGNnMThs?=\n\t=?gb2312?b?VS9MeW8zaVBnU0diOEsxUENJMFE3M3k5TUtzVzhnZFNhSG9hVTN6?=\n\t=?gb2312?b?eE1SM1RLMUkxTno3dDZRYmhqRmZBQ3ExSFY5VEFHSkdpaE9VcGFC?=\n\t=?gb2312?b?Q2pWZ1dWVytHUFhvRkdRZ0trOURSL0d5OFVwYmt5T1pXdjFDZzlx?=\n\t=?gb2312?b?Qkp5VnNhV0RRcHY4eWkwL09neDBjVU9kTldaTVpoNWtMc25GSW9o?=\n\t=?gb2312?b?SnhlTkQ3QTNUdUVIbTBLSDBrUjRpWE4ySWhVS2IwSUZZQU9qLzZH?=\n\t=?gb2312?b?WT0=?=","Content-Type":"text/plain; charset=\"gb2312\"","Content-Transfer-Encoding":"base64","MIME-Version":"1.0","X-OriginatorOrg":"nxp.com","X-MS-Exchange-CrossTenant-AuthAs":"Internal","X-MS-Exchange-CrossTenant-AuthSource":"PAXPR04MB8285.eurprd04.prod.outlook.com","X-MS-Exchange-CrossTenant-Network-Message-Id":"797cbaf7-769c-46af-0ba8-08dd944c477f","X-MS-Exchange-CrossTenant-originalarrivaltime":"16 May 2025 07:35:49.4217\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":"2czKnXAlevvawsRZf86JeNwvnhY8d/XKLW9GihDeWiOg4v4FdbFNCDp8C5fkrqih","X-MS-Exchange-Transport-CrossTenantHeadersStamped":"PAXPR04MB9490","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>"}}]