Files
external_libcamera/src/gstreamer/gstlibcamerapool.cpp
Hou Qi 848a3017b8 gstreamer: Add GstVideoMeta support
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,
create a internal VideoPool using the caps, and copy video frame to
this system memory.

Signed-off-by: Hou Qi <qi.hou@nxp.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Tested-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-05-19 09:28:19 +01:00

179 lines
4.4 KiB
C++

/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2020, Collabora Ltd.
* Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
*
* GStreamer Buffer Pool
*/
#include "gstlibcamerapool.h"
#include <deque>
#include <libcamera/stream.h>
#include "gstlibcamera-utils.h"
using namespace libcamera;
enum {
SIGNAL_BUFFER_NOTIFY,
N_SIGNALS
};
static guint signals[N_SIGNALS];
struct _GstLibcameraPool {
GstBufferPool parent;
std::deque<GstBuffer *> *queue;
GstLibcameraAllocator *allocator;
Stream *stream;
};
G_DEFINE_TYPE(GstLibcameraPool, gst_libcamera_pool, GST_TYPE_BUFFER_POOL)
static GstBuffer *
gst_libcamera_pool_pop_buffer(GstLibcameraPool *self)
{
GLibLocker lock(GST_OBJECT(self));
GstBuffer *buf;
if (self->queue->empty())
return nullptr;
buf = self->queue->front();
self->queue->pop_front();
return buf;
}
static GstFlowReturn
gst_libcamera_pool_acquire_buffer(GstBufferPool *pool, GstBuffer **buffer,
[[maybe_unused]] GstBufferPoolAcquireParams *params)
{
GstLibcameraPool *self = GST_LIBCAMERA_POOL(pool);
GstBuffer *buf = gst_libcamera_pool_pop_buffer(self);
if (!buf)
return GST_FLOW_ERROR;
if (!gst_libcamera_allocator_prepare_buffer(self->allocator, self->stream, buf)) {
GLibLocker lock(GST_OBJECT(self));
self->queue->push_back(buf);
return GST_FLOW_ERROR;
}
*buffer = buf;
return GST_FLOW_OK;
}
static void
gst_libcamera_pool_reset_buffer(GstBufferPool *pool, GstBuffer *buffer)
{
GstBufferPoolClass *klass = GST_BUFFER_POOL_CLASS(gst_libcamera_pool_parent_class);
/* Clears all the memories and only pool the GstBuffer objects */
gst_buffer_remove_all_memory(buffer);
klass->reset_buffer(pool, buffer);
GST_BUFFER_FLAGS(buffer) = 0;
}
static void
gst_libcamera_pool_release_buffer(GstBufferPool *pool, GstBuffer *buffer)
{
GstLibcameraPool *self = GST_LIBCAMERA_POOL(pool);
bool do_notify;
{
GLibLocker lock(GST_OBJECT(self));
do_notify = self->queue->empty();
self->queue->push_back(buffer);
}
if (do_notify)
g_signal_emit(self, signals[SIGNAL_BUFFER_NOTIFY], 0);
}
static void
gst_libcamera_pool_init(GstLibcameraPool *self)
{
self->queue = new std::deque<GstBuffer *>();
}
static void
gst_libcamera_pool_finalize(GObject *object)
{
GstLibcameraPool *self = GST_LIBCAMERA_POOL(object);
GstBuffer *buf;
while ((buf = gst_libcamera_pool_pop_buffer(self)))
gst_buffer_unref(buf);
delete self->queue;
g_object_unref(self->allocator);
G_OBJECT_CLASS(gst_libcamera_pool_parent_class)->finalize(object);
}
static void
gst_libcamera_pool_class_init(GstLibcameraPoolClass *klass)
{
auto *object_class = G_OBJECT_CLASS(klass);
auto *pool_class = GST_BUFFER_POOL_CLASS(klass);
object_class->finalize = gst_libcamera_pool_finalize;
pool_class->start = nullptr;
pool_class->acquire_buffer = gst_libcamera_pool_acquire_buffer;
pool_class->reset_buffer = gst_libcamera_pool_reset_buffer;
pool_class->release_buffer = gst_libcamera_pool_release_buffer;
signals[SIGNAL_BUFFER_NOTIFY] = g_signal_new("buffer-notify",
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST,
0, nullptr, nullptr, nullptr,
G_TYPE_NONE, 0);
}
static void
gst_libcamera_buffer_add_video_meta(GstBuffer *buffer, GstVideoInfo *info)
{
GstVideoMeta *vmeta;
vmeta = 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);
GST_META_FLAGS(vmeta) = (GstMetaFlags)(GST_META_FLAGS(vmeta) | GST_META_FLAG_POOLED);
}
GstLibcameraPool *
gst_libcamera_pool_new(GstLibcameraAllocator *allocator, Stream *stream,
GstVideoInfo *info)
{
auto *pool = GST_LIBCAMERA_POOL(g_object_new(GST_TYPE_LIBCAMERA_POOL, nullptr));
pool->allocator = GST_LIBCAMERA_ALLOCATOR(g_object_ref(allocator));
pool->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();
gst_libcamera_buffer_add_video_meta(buffer, info);
pool->queue->push_back(buffer);
}
return pool;
}
Stream *
gst_libcamera_pool_get_stream(GstLibcameraPool *self)
{
return self->stream;
}
FrameBuffer *
gst_libcamera_buffer_get_frame_buffer(GstBuffer *buffer)
{
GstMemory *mem = gst_buffer_peek_memory(buffer, 0);
return gst_libcamera_memory_get_frame_buffer(mem);
}