Show a patch.

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

{
    "id": 2899,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/2899/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/2899/",
    "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": "<20200227200407.490616-18-nicolas.dufresne@collabora.com>",
    "date": "2020-02-27T20:03:57",
    "name": "[libcamera-devel,v2,17/27] gst: Add a pool and an allocator implementation",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "98d6b680ffd5ce4ad499a06d25004d227caadd9c",
    "submitter": {
        "id": 31,
        "url": "https://patchwork.libcamera.org/api/1.1/people/31/?format=api",
        "name": "Nicolas Dufresne",
        "email": "nicolas.dufresne@collabora.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/2899/mbox/",
    "series": [
        {
            "id": 693,
            "url": "https://patchwork.libcamera.org/api/1.1/series/693/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=693",
            "date": "2020-02-27T20:03:40",
            "name": "GStreamer Element for libcamera",
            "version": 2,
            "mbox": "https://patchwork.libcamera.org/series/693/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/2899/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/2899/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<nicolas.dufresne@collabora.com>",
        "Received": [
            "from bhuna.collabora.co.uk (bhuna.collabora.co.uk\n\t[IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 077E762727\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 27 Feb 2020 21:04:26 +0100 (CET)",
            "from [127.0.0.1] (localhost [127.0.0.1])\n\t(Authenticated sender: nicolas) with ESMTPSA id 7A0D429654A"
        ],
        "From": "Nicolas Dufresne <nicolas.dufresne@collabora.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Thu, 27 Feb 2020 15:03:57 -0500",
        "Message-Id": "<20200227200407.490616-18-nicolas.dufresne@collabora.com>",
        "X-Mailer": "git-send-email 2.24.1",
        "In-Reply-To": "<20200227200407.490616-1-nicolas.dufresne@collabora.com>",
        "References": "<20200227200407.490616-1-nicolas.dufresne@collabora.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH v2 17/27] gst: Add a pool and an allocator\n\timplementation",
        "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>",
        "X-List-Received-Date": "Thu, 27 Feb 2020 20:04:26 -0000"
    },
    "content": "This is needed to track the lifetime of the FrameBufferAllocator in relation to\nthe GstBuffer/GstMemory objects travelling inside GStreamer.\n\nSigned-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>\n---\n src/gstreamer/gstlibcameraallocator.cpp | 244 ++++++++++++++++++++++++\n src/gstreamer/gstlibcameraallocator.h   |  29 +++\n src/gstreamer/gstlibcamerapool.cpp      | 109 +++++++++++\n src/gstreamer/gstlibcamerapool.h        |  26 +++\n src/gstreamer/meson.build               |  13 +-\n 5 files changed, 417 insertions(+), 4 deletions(-)\n create mode 100644 src/gstreamer/gstlibcameraallocator.cpp\n create mode 100644 src/gstreamer/gstlibcameraallocator.h\n create mode 100644 src/gstreamer/gstlibcamerapool.cpp\n create mode 100644 src/gstreamer/gstlibcamerapool.h",
    "diff": "diff --git a/src/gstreamer/gstlibcameraallocator.cpp b/src/gstreamer/gstlibcameraallocator.cpp\nnew file mode 100644\nindex 0000000..f268561\n--- /dev/null\n+++ b/src/gstreamer/gstlibcameraallocator.cpp\n@@ -0,0 +1,244 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2020, Collabora Ltd.\n+ *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>\n+ *\n+ * gstlibcameraallocator.cpp - GStreamer Custom Allocator\n+ */\n+\n+#include \"gstlibcameraallocator.h\"\n+#include \"gstlibcamera-utils.h\"\n+\n+#include <libcamera/camera.h>\n+#include <libcamera/framebuffer_allocator.h>\n+#include <libcamera/stream.h>\n+\n+using namespace libcamera;\n+\n+static gboolean gst_libcamera_allocator_release(GstMiniObject *mini_object);\n+\n+/**\n+ * \\struct FrameWrap\n+ * \\brief An internal wrapper to track the relation between FrameBuffer and\n+ * GstMemory(s)\n+ *\n+ * This wrapper maintains a count of the outstanding GstMemory (there may be\n+ * multiple GstMemory per FrameBuffer), and give back the FrameBuffer to the\n+ * allocator pool when all memory objects have returned.\n+ */\n+\n+struct FrameWrap {\n+\tFrameWrap(GstAllocator *allocator, FrameBuffer *buffer,\n+\t\t  gpointer stream);\n+\t~FrameWrap();\n+\n+\tvoid acquirePlane() { ++outstandingPlanes_; }\n+\tbool releasePlane() { return --outstandingPlanes_ == 0; }\n+\n+\tstatic GQuark getQuark();\n+\n+\tgpointer stream_;\n+\tFrameBuffer *buffer_;\n+\tstd::vector<GstMemory *> planes_;\n+\tgint outstandingPlanes_;\n+};\n+\n+FrameWrap::FrameWrap(GstAllocator *allocator, FrameBuffer *buffer,\n+\t\t     gpointer stream)\n+\n+\t: stream_(stream),\n+\t  buffer_(buffer),\n+\t  outstandingPlanes_(0)\n+{\n+\tfor (const FrameBuffer::Plane &plane : buffer->planes()) {\n+\t\tGstMemory *mem = gst_fd_allocator_alloc(allocator, plane.fd.fd(), plane.length,\n+\t\t\t\t\t\t\tGST_FD_MEMORY_FLAG_DONT_CLOSE);\n+\t\tgst_mini_object_set_qdata(GST_MINI_OBJECT(mem), FrameWrap::getQuark(), this, nullptr);\n+\t\tGST_MINI_OBJECT(mem)->dispose = gst_libcamera_allocator_release;\n+\t\tg_object_unref(mem->allocator);\n+\t\tplanes_.push_back(mem);\n+\t}\n+}\n+\n+FrameWrap::~FrameWrap()\n+{\n+\tfor (GstMemory *mem : planes_) {\n+\t\tGST_MINI_OBJECT(mem)->dispose = nullptr;\n+\t\tg_object_ref(mem->allocator);\n+\t\tgst_memory_unref(mem);\n+\t}\n+}\n+\n+GQuark FrameWrap::getQuark(void)\n+{\n+\tstatic gsize frame_quark = 0;\n+\n+\tif (g_once_init_enter(&frame_quark)) {\n+\t\tGQuark quark = g_quark_from_string(\"GstLibcameraFrameWrap\");\n+\t\tg_once_init_leave(&frame_quark, quark);\n+\t}\n+\n+\treturn frame_quark;\n+}\n+\n+\n+\n+/**\n+ * \\struct _GstLibcameraAllocator\n+ * \\brief A pooling GstDmaBufAllocator for libcamera\n+ *\n+ * This is a pooling GstDmaBufAllocator implementation. This implementation override\n+ * the dispose function of memory object in order to keep them alive when they\n+ * are disposed by downstream elements.\n+ */\n+struct _GstLibcameraAllocator {\n+\tGstDmaBufAllocator parent;\n+\tFrameBufferAllocator *fb_allocator;\n+\t/* A hash table using Stream pointer as key and returning a GQueue of\n+\t * FrameWrap. */\n+\tGHashTable *pools;\n+};\n+\n+G_DEFINE_TYPE(GstLibcameraAllocator, gst_libcamera_allocator,\n+\t      GST_TYPE_DMABUF_ALLOCATOR);\n+\n+static gboolean\n+gst_libcamera_allocator_release(GstMiniObject *mini_object)\n+{\n+\tGstMemory *mem = GST_MEMORY_CAST(mini_object);\n+\tGstLibcameraAllocator *self = GST_LIBCAMERA_ALLOCATOR(mem->allocator);\n+\tGLibLocker lock(GST_OBJECT(self));\n+\tauto *frame = reinterpret_cast<FrameWrap *>(gst_mini_object_get_qdata(mini_object, FrameWrap::getQuark()));\n+\n+\tgst_memory_ref(mem);\n+\n+\tif (frame->releasePlane()) {\n+\t\tauto *pool = reinterpret_cast<GQueue *>(g_hash_table_lookup(self->pools, frame->stream_));\n+\t\tg_return_val_if_fail(pool, TRUE);\n+\t\tg_queue_push_tail(pool, frame);\n+\t}\n+\n+\t/* Keep last in case we are holding on the last allocator ref. */\n+\tg_object_unref(mem->allocator);\n+\n+\t/* Return FALSE so that our mini object isn't freed. */\n+\treturn FALSE;\n+}\n+\n+static void\n+gst_libcamera_allocator_free_pool(gpointer data)\n+{\n+\tGQueue *queue = reinterpret_cast<GQueue *>(data);\n+\tFrameWrap *frame;\n+\n+\twhile ((frame = reinterpret_cast<FrameWrap *>(g_queue_pop_head(queue)))) {\n+\t\tg_warn_if_fail(frame->outstandingPlanes_ == 0);\n+\t\tdelete frame;\n+\t}\n+\n+\tg_queue_free(queue);\n+}\n+\n+static void\n+gst_libcamera_allocator_init(GstLibcameraAllocator *self)\n+{\n+\tself->pools = g_hash_table_new_full(nullptr, nullptr, nullptr,\n+\t\t\t\t\t    gst_libcamera_allocator_free_pool);\n+\tGST_OBJECT_FLAG_SET(self, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);\n+}\n+\n+static void\n+gst_libcamera_allocator_dispose(GObject *object)\n+{\n+\tGstLibcameraAllocator *self = GST_LIBCAMERA_ALLOCATOR(object);\n+\n+\tif (self->pools) {\n+\t\tg_hash_table_unref(self->pools);\n+\t\tself->pools = nullptr;\n+\t}\n+\n+\tG_OBJECT_CLASS(gst_libcamera_allocator_parent_class)->dispose(object);\n+}\n+\n+static void\n+gst_libcamera_allocator_finalize(GObject *object)\n+{\n+\tGstLibcameraAllocator *self = GST_LIBCAMERA_ALLOCATOR(object);\n+\n+\tdelete self->fb_allocator;\n+\n+\tG_OBJECT_CLASS(gst_libcamera_allocator_parent_class)->finalize(object);\n+}\n+\n+static void\n+gst_libcamera_allocator_class_init(GstLibcameraAllocatorClass *klass)\n+{\n+\tauto *allocator_class = GST_ALLOCATOR_CLASS(klass);\n+\tauto *object_class = G_OBJECT_CLASS(klass);\n+\n+\tobject_class->dispose = gst_libcamera_allocator_dispose;\n+\tobject_class->finalize = gst_libcamera_allocator_finalize;\n+\tallocator_class->alloc = nullptr;\n+}\n+\n+GstLibcameraAllocator *\n+gst_libcamera_allocator_new(std::shared_ptr<Camera> camera)\n+{\n+\tauto *self = (GstLibcameraAllocator *)g_object_new(GST_TYPE_LIBCAMERA_ALLOCATOR,\n+\t\t\t\t\t\t\t   nullptr);\n+\n+\tself->fb_allocator = FrameBufferAllocator::create(camera);\n+\tfor (Stream *stream : camera->streams()) {\n+\t\tgint ret;\n+\n+\t\tret = self->fb_allocator->allocate(stream);\n+\t\tif (ret == 0)\n+\t\t\treturn nullptr;\n+\n+\t\tGQueue *pool = g_queue_new();\n+\t\tfor (const std::unique_ptr<FrameBuffer> &buffer :\n+\t\t     self->fb_allocator->buffers(stream)) {\n+\t\t\tauto *fb = new FrameWrap(GST_ALLOCATOR(self),\n+\t\t\t\t\t\t buffer.get(), stream);\n+\t\t\tg_queue_push_tail(pool, fb);\n+\t\t}\n+\n+\t\tg_hash_table_insert(self->pools, stream, pool);\n+\t}\n+\n+\treturn self;\n+}\n+\n+bool\n+gst_libcamera_allocator_prepare_buffer(GstLibcameraAllocator *self,\n+\t\t\t\t       Stream *stream, GstBuffer *buffer)\n+{\n+\tGLibLocker lock(GST_OBJECT(self));\n+\n+\tauto *pool = reinterpret_cast<GQueue *>(g_hash_table_lookup(self->pools, stream));\n+\tg_return_val_if_fail(pool, false);\n+\n+\tauto *frame = reinterpret_cast<FrameWrap *>(g_queue_pop_head(pool));\n+\tif (!frame)\n+\t\treturn false;\n+\n+\tfor (GstMemory *mem : frame->planes_) {\n+\t\tframe->acquirePlane();\n+\t\tgst_buffer_append_memory(buffer, mem);\n+\t\tg_object_ref(mem->allocator);\n+\t}\n+\n+\treturn true;\n+}\n+\n+gsize\n+gst_libcamera_allocator_get_pool_size(GstLibcameraAllocator *self,\n+\t\t\t\t      Stream *stream)\n+{\n+\tGLibLocker lock(GST_OBJECT(self));\n+\n+\tauto *pool = reinterpret_cast<GQueue *>(g_hash_table_lookup(self->pools, stream));\n+\tg_return_val_if_fail(pool, false);\n+\n+\treturn pool->length;\n+}\ndiff --git a/src/gstreamer/gstlibcameraallocator.h b/src/gstreamer/gstlibcameraallocator.h\nnew file mode 100644\nindex 0000000..25cbf85\n--- /dev/null\n+++ b/src/gstreamer/gstlibcameraallocator.h\n@@ -0,0 +1,29 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2020, Collabora Ltd.\n+ *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>\n+ *\n+ * gstlibcameraallocator.h - GStreamer Custom Allocator\n+ */\n+\n+#ifndef __GST_LIBCAMERA_ALLOCATOR_H__\n+#define __GST_LIBCAMERA_ALLOCATOR_H__\n+\n+#include <gst/gst.h>\n+#include <gst/allocators/allocators.h>\n+#include <libcamera/stream.h>\n+\n+#define GST_TYPE_LIBCAMERA_ALLOCATOR gst_libcamera_allocator_get_type()\n+G_DECLARE_FINAL_TYPE(GstLibcameraAllocator, gst_libcamera_allocator,\n+\t\t     GST_LIBCAMERA, ALLOCATOR, GstDmaBufAllocator)\n+\n+GstLibcameraAllocator *gst_libcamera_allocator_new(std::shared_ptr<libcamera::Camera> camera);\n+\n+bool gst_libcamera_allocator_prepare_buffer(GstLibcameraAllocator *self,\n+\t\t\t\t\t    libcamera::Stream *stream,\n+\t\t\t\t\t    GstBuffer *buffer);\n+\n+gsize gst_libcamera_allocator_get_pool_size(GstLibcameraAllocator *allocator,\n+\t\t\t\t\t    libcamera::Stream *stream);\n+\n+#endif /* __GST_LIBCAMERA_ALLOCATOR_H__ */\ndiff --git a/src/gstreamer/gstlibcamerapool.cpp b/src/gstreamer/gstlibcamerapool.cpp\nnew file mode 100644\nindex 0000000..ee106a7\n--- /dev/null\n+++ b/src/gstreamer/gstlibcamerapool.cpp\n@@ -0,0 +1,109 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2020, Collabora Ltd.\n+ *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>\n+ *\n+ * gstlibcamerapool.cpp - GStreamer Buffer Pool\n+ */\n+\n+#include \"gstlibcamera-utils.h\"\n+#include \"gstlibcamerapool.h\"\n+\n+#include <libcamera/stream.h>\n+\n+using namespace libcamera;\n+\n+struct _GstLibcameraPool {\n+\tGstBufferPool parent;\n+\n+\tGstAtomicQueue *queue;\n+\tGstLibcameraAllocator *allocator;\n+\tStream *stream;\n+};\n+\n+G_DEFINE_TYPE(GstLibcameraPool, gst_libcamera_pool, GST_TYPE_BUFFER_POOL);\n+\n+static GstFlowReturn\n+gst_libcamera_pool_acquire_buffer(GstBufferPool *pool, GstBuffer **buffer,\n+\t\t\t\t  GstBufferPoolAcquireParams *params)\n+{\n+\tGstLibcameraPool *self = GST_LIBCAMERA_POOL(pool);\n+\tGstBuffer *buf = GST_BUFFER(gst_atomic_queue_pop(self->queue));\n+\tif (!buf)\n+\t\treturn GST_FLOW_ERROR;\n+\n+\tif (!gst_libcamera_allocator_prepare_buffer(self->allocator, self->stream, buf))\n+\t\treturn GST_FLOW_ERROR;\n+\n+\t*buffer = buf;\n+\treturn GST_FLOW_OK;\n+}\n+\n+static void\n+gst_libcamera_pool_reset_buffer(GstBufferPool *pool, GstBuffer *buffer)\n+{\n+\tGstBufferPoolClass *klass = GST_BUFFER_POOL_CLASS(gst_libcamera_pool_parent_class);\n+\n+\t/* Clears all the memories and only pool the GstBuffer objects */\n+\tgst_buffer_remove_all_memory(buffer);\n+\tklass->reset_buffer(pool, buffer);\n+\tGST_BUFFER_FLAGS(buffer) = 0;\n+}\n+\n+static void\n+gst_libcamera_pool_release_buffer(GstBufferPool *pool, GstBuffer *buffer)\n+{\n+\tGstLibcameraPool *self = GST_LIBCAMERA_POOL(pool);\n+\tgst_atomic_queue_push(self->queue, buffer);\n+}\n+\n+static void\n+gst_libcamera_pool_init(GstLibcameraPool *self)\n+{\n+\tself->queue = gst_atomic_queue_new(4);\n+}\n+\n+static void\n+gst_libcamera_pool_finalize(GObject *object)\n+{\n+\tGstLibcameraPool *self = GST_LIBCAMERA_POOL(object);\n+\tGstBuffer *buf;\n+\n+\twhile ((buf = GST_BUFFER(gst_atomic_queue_pop(self->queue))))\n+\t\tgst_buffer_unref(buf);\n+\n+\tgst_atomic_queue_unref(self->queue);\n+\tg_object_unref(self->allocator);\n+\n+\tG_OBJECT_CLASS(gst_libcamera_pool_parent_class)->finalize(object);\n+}\n+\n+static void\n+gst_libcamera_pool_class_init(GstLibcameraPoolClass *klass)\n+{\n+\tauto *object_class = G_OBJECT_CLASS(klass);\n+\tauto *pool_class = GST_BUFFER_POOL_CLASS(klass);\n+\n+\tobject_class->finalize = gst_libcamera_pool_finalize;\n+\tpool_class->start = nullptr;\n+\tpool_class->acquire_buffer = gst_libcamera_pool_acquire_buffer;\n+\tpool_class->reset_buffer = gst_libcamera_pool_reset_buffer;\n+\tpool_class->release_buffer = gst_libcamera_pool_release_buffer;\n+}\n+\n+GstLibcameraPool *\n+gst_libcamera_pool_new(GstLibcameraAllocator *allocator, Stream *stream)\n+{\n+\tauto *pool = GST_LIBCAMERA_POOL(g_object_new(GST_TYPE_LIBCAMERA_POOL, nullptr));\n+\n+\tpool->allocator = GST_LIBCAMERA_ALLOCATOR(g_object_ref(allocator));\n+\tpool->stream = stream;\n+\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_atomic_queue_push(pool->queue, buffer);\n+\t}\n+\n+\treturn pool;\n+}\ndiff --git a/src/gstreamer/gstlibcamerapool.h b/src/gstreamer/gstlibcamerapool.h\nnew file mode 100644\nindex 0000000..a764c75\n--- /dev/null\n+++ b/src/gstreamer/gstlibcamerapool.h\n@@ -0,0 +1,26 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2020, Collabora Ltd.\n+ *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>\n+ *\n+ * gstlibcamerapool.h - GStreamer Buffer Pool\n+ *\n+ * This is a partial implementation of GstBufferPool intended for internal use\n+ * only. This pool cannot be configured or activated.\n+ */\n+\n+#ifndef __GST_LIBCAMERA_POOL_H__\n+#define __GST_LIBCAMERA_POOL_H__\n+\n+#include <gst/gst.h>\n+#include <libcamera/stream.h>\n+\n+#include \"gstlibcameraallocator.h\"\n+\n+#define GST_TYPE_LIBCAMERA_POOL gst_libcamera_pool_get_type()\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+\n+#endif /* __GST_LIBCAMERA_POOL_H__ */\ndiff --git a/src/gstreamer/meson.build b/src/gstreamer/meson.build\nindex 1c4a2e3..90773af 100644\n--- a/src/gstreamer/meson.build\n+++ b/src/gstreamer/meson.build\n@@ -1,7 +1,9 @@\n libcamera_gst_sources = [\n     'gstlibcamera-utils.cpp',\n     'gstlibcamera.c',\n+    'gstlibcameraallocator.cpp',\n     'gstlibcamerapad.cpp',\n+    'gstlibcamerapool.cpp',\n     'gstlibcameraprovider.cpp',\n     'gstlibcamerasrc.cpp',\n ]\n@@ -11,14 +13,17 @@ libcamera_gst_c_args = [\n     '-DPACKAGE=\"@0@\"'.format(meson.project_name()),\n ]\n \n-gst_dep = dependency('gstreamer-video-1.0', version : '>=1.16.1',\n-                     required : get_option('gstreamer'))\n+gst_req = '>=1.16.1'\n+gstvideo_dep = dependency('gstreamer-video-1.0', version : gst_req,\n+                          required : get_option('gstreamer'))\n+gstallocator_dep = dependency('gstreamer-allocators-1.0', version : gst_req,\n+                              required : get_option('gstreamer'))\n \n-if gst_dep.found()\n+if gstvideo_dep.found() and gstallocator_dep.found()\n     libcamera_gst = shared_library('gstlibcamera',\n         libcamera_gst_sources,\n         c_args : libcamera_gst_c_args,\n-        dependencies : [libcamera_dep, gst_dep],\n+        dependencies : [libcamera_dep, gstvideo_dep, gstallocator_dep],\n         install: true,\n         install_dir : '@0@/gstreamer-1.0'.format(get_option('libdir')),\n     )\n",
    "prefixes": [
        "libcamera-devel",
        "v2",
        "17/27"
    ]
}