[PATCH v3] gstreamer: Add GstVideoMeta support
Hou Qi
qi.hou at nxp.com
Wed Nov 13 08:29:47 CET 2024
GStreamer video-info calculated stride and offset may differ from
those used by the camera.
This patch enhances downstream plugin's support for videometa by
adding videometa support for libcamerasrc. It ensures that when
downstream plugin supports videometa by allocation query, libcamerasrc
also attaches videometa to buffer, preventing discrepancies
between the stride and offset calculated by video-info and camera.
Signed-off-by: Hou Qi <qi.hou at nxp.com>
---
src/gstreamer/gstlibcamera-utils.cpp | 28 ++++++++++++++++++++++++
src/gstreamer/gstlibcamera-utils.h | 7 ++++++
src/gstreamer/gstlibcamerapool.cpp | 32 ++++++++++++++++++++++++----
src/gstreamer/gstlibcamerapool.h | 2 +-
src/gstreamer/gstlibcamerasrc.cpp | 14 +++++++++++-
5 files changed, 77 insertions(+), 6 deletions(-)
diff --git a/src/gstreamer/gstlibcamera-utils.cpp b/src/gstreamer/gstlibcamera-utils.cpp
index 732987ef..91de1d44 100644
--- a/src/gstreamer/gstlibcamera-utils.cpp
+++ b/src/gstreamer/gstlibcamera-utils.cpp
@@ -2,6 +2,9 @@
/*
* Copyright (C) 2020, Collabora Ltd.
* Author: Nicolas Dufresne <nicolas.dufresne at collabora.com>
+ * Copyright (C) <1999> Erik Walthinsen <omega at cse.ogi.edu>
+ * Library <2002> Ronald Bultje <rbultje at ronald.bitfreak.net>
+ * Copyright (C) <2007> David A. Schleef <ds at schleef.org>
*
* GStreamer libcamera Utility Function
*/
@@ -591,6 +594,31 @@ gst_task_resume(GstTask *task)
}
#endif
+#if !GST_CHECK_VERSION(1, 22, 0)
+gint gst_libcamera_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<CameraManager> cm_singleton_ptr;
diff --git a/src/gstreamer/gstlibcamera-utils.h b/src/gstreamer/gstlibcamera-utils.h
index cab1c814..14bf6664 100644
--- a/src/gstreamer/gstlibcamera-utils.h
+++ b/src/gstreamer/gstlibcamera-utils.h
@@ -2,6 +2,9 @@
/*
* Copyright (C) 2020, Collabora Ltd.
* Author: Nicolas Dufresne <nicolas.dufresne at collabora.com>
+ * Copyright (C) <1999> Erik Walthinsen <omega at cse.ogi.edu>
+ * Library <2002> Ronald Bultje <rbultje at ronald.bitfreak.net>
+ * Copyright (C) <2007> David A. Schleef <ds at schleef.org>
*
* GStreamer libcamera Utility Functions
*/
@@ -35,6 +38,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_libcamera_extrapolate_stride(const GstVideoFormatInfo *finfo, gint plane, gint stride);
+#endif
std::shared_ptr<libcamera::CameraManager> gst_libcamera_get_camera_manager(int &ret);
/**
diff --git a/src/gstreamer/gstlibcamerapool.cpp b/src/gstreamer/gstlibcamerapool.cpp
index 9cd7eccb..315f08ac 100644
--- a/src/gstreamer/gstlibcamerapool.cpp
+++ b/src/gstreamer/gstlibcamerapool.cpp
@@ -135,16 +135,40 @@ gst_libcamera_pool_class_init(GstLibcameraPoolClass *klass)
}
GstLibcameraPool *
-gst_libcamera_pool_new(GstLibcameraAllocator *allocator, Stream *stream)
+gst_libcamera_pool_new(GstLibcameraAllocator *allocator, const StreamConfiguration &stream_cfg,
+ GstCaps *caps, gboolean add_video_meta)
{
auto *pool = GST_LIBCAMERA_POOL(g_object_new(GST_TYPE_LIBCAMERA_POOL, nullptr));
+ GstVideoInfo info;
pool->allocator = GST_LIBCAMERA_ALLOCATOR(g_object_ref(allocator));
- pool->stream = stream;
-
- gsize pool_size = gst_libcamera_allocator_get_pool_size(allocator, stream);
+ pool->stream = stream_cfg.stream();
+
+ if (caps && gst_video_info_from_caps(&info, caps)) {
+ guint k, stride;
+ gsize offset = 0;
+ for (k = 0; k < GST_VIDEO_INFO_N_PLANES(&info); k++) {
+#if !GST_CHECK_VERSION(1, 22, 0)
+ stride = gst_libcamera_extrapolate_stride(info.finfo, k, stream_cfg.stride);
+#else
+ stride = gst_video_format_info_extrapolate_stride(info.finfo, k, stream_cfg.stride);
+#endif
+ 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
+ add_video_meta = false;
+
+ gsize pool_size = gst_libcamera_allocator_get_pool_size(allocator, stream_cfg.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..8ad87cab 100644
--- a/src/gstreamer/gstlibcamerapool.h
+++ b/src/gstreamer/gstlibcamerapool.h
@@ -21,7 +21,7 @@
G_DECLARE_FINAL_TYPE(GstLibcameraPool, gst_libcamera_pool, GST_LIBCAMERA, POOL, GstBufferPool)
GstLibcameraPool *gst_libcamera_pool_new(GstLibcameraAllocator *allocator,
- libcamera::Stream *stream);
+ const libcamera::StreamConfiguration &stream_cfg, GstCaps *caps, 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..c05a31e7 100644
--- a/src/gstreamer/gstlibcamerasrc.cpp
+++ b/src/gstreamer/gstlibcamerasrc.cpp
@@ -497,9 +497,21 @@ 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);
+ GstQuery *query = NULL;
+ gboolean add_video_meta = false;
+
+ g_autoptr(GstCaps) caps = gst_libcamera_stream_configuration_to_caps(stream_cfg);
+ gst_libcamera_framerate_to_caps(caps, element_caps);
+
+ query = gst_query_new_allocation(caps, false);
+ 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);
+ gst_query_unref(query);
GstLibcameraPool *pool = gst_libcamera_pool_new(self->allocator,
- stream_cfg.stream());
+ stream_cfg, caps, add_video_meta);
g_signal_connect_swapped(pool, "buffer-notify",
G_CALLBACK(gst_task_resume), self->task);
--
2.34.1
More information about the libcamera-devel
mailing list