[{"id":3973,"web_url":"https://patchwork.libcamera.org/comment/3973/","msgid":"<20200306205411.GV4878@pendragon.ideasonboard.com>","date":"2020-03-06T20:54:11","subject":"Re: [libcamera-devel] [PATCH v3 17/27] gst: Add a pool and an\n\tallocator implementation","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Nicolas,\n\nThank you for the patch.\n\nOn Fri, Mar 06, 2020 at 03:26:27PM -0500, Nicolas Dufresne wrote:\n> From: Nicolas Dufresne <nicolas.dufresne@collabora.com>\n> \n> This is needed to track the lifetime of the FrameBufferAllocator in relation to\n> the GstBuffer/GstMemory objects travelling inside GStreamer.\n> \n> Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> ---\n>  src/gstreamer/gstlibcameraallocator.cpp | 245 ++++++++++++++++++++++++\n>  src/gstreamer/gstlibcameraallocator.h   |  30 +++\n>  src/gstreamer/gstlibcamerapool.cpp      | 110 +++++++++++\n>  src/gstreamer/gstlibcamerapool.h        |  27 +++\n>  src/gstreamer/meson.build               |  13 +-\n>  5 files changed, 421 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\n> \n> diff --git a/src/gstreamer/gstlibcameraallocator.cpp b/src/gstreamer/gstlibcameraallocator.cpp\n> new file mode 100644\n> index 0000000..861af59\n> --- /dev/null\n> +++ b/src/gstreamer/gstlibcameraallocator.cpp\n> @@ -0,0 +1,245 @@\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> +\n> +#include <libcamera/camera.h>\n> +#include <libcamera/framebuffer_allocator.h>\n> +#include <libcamera/stream.h>\n> +\n> +#include \"gstlibcamera-utils.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), 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> + * \\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/*\n> +\t * A hash table using Stream pointer as key and returning a GQueue of\n> +\t * FrameWrap.\n> +\t */\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 = GST_LIBCAMERA_ALLOCATOR(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> +}\n> diff --git a/src/gstreamer/gstlibcameraallocator.h b/src/gstreamer/gstlibcameraallocator.h\n> new file mode 100644\n> index 0000000..b3f7f36\n> --- /dev/null\n> +++ b/src/gstreamer/gstlibcameraallocator.h\n> @@ -0,0 +1,30 @@\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> +\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__ */\n> diff --git a/src/gstreamer/gstlibcamerapool.cpp b/src/gstreamer/gstlibcamerapool.cpp\n> new file mode 100644\n> index 0000000..75e189a\n> --- /dev/null\n> +++ b/src/gstreamer/gstlibcamerapool.cpp\n> @@ -0,0 +1,110 @@\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 \"gstlibcamerapool.h\"\n> +\n> +#include <libcamera/stream.h>\n> +\n> +#include \"gstlibcamera-utils.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> +}\n> diff --git a/src/gstreamer/gstlibcamerapool.h b/src/gstreamer/gstlibcamerapool.h\n> new file mode 100644\n> index 0000000..c0a04cf\n> --- /dev/null\n> +++ b/src/gstreamer/gstlibcamerapool.h\n> @@ -0,0 +1,27 @@\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 \"gstlibcameraallocator.h\"\n> +\n> +#include <gst/gst.h>\n> +\n> +#include <libcamera/stream.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__ */\n> diff --git a/src/gstreamer/meson.build b/src/gstreamer/meson.build\n> index c396710..ca64bf1 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.14.0',\n> -                     required : get_option('gstreamer'))\n> +gst_dep_version = '>=1.14.0'\n> +gstvideo_dep = dependency('gstreamer-video-1.0', version : gst_dep_version,\n> +                          required : get_option('gstreamer'))\n> +gstallocator_dep = dependency('gstreamer-allocators-1.0', version : gst_dep_version,\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>      )","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2633960424\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  6 Mar 2020 21:54:15 +0100 (CET)","from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 8CA2F24B;\n\tFri,  6 Mar 2020 21:54:14 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1583528054;\n\tbh=tQoCrAiNrfWiHYyzOQJlQCX6fDTBPteKEYk4RQrPd5g=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=cvmInpo4xDJ/bQg6Up+ANYSGQTfMbxaKJruOlQPNm/BkDp9bEHdGtRJOf/vGDCkCE\n\tobmsVdiIbFgBufqnthKqxt846jqqEPJOnscCJ6lIvHEUtxEe15MNbgnlSon4Q+0c6N\n\t/7JUmFtAJUV79M3th0nRz21UAEJ7GHoOMVcJtfJ4=","Date":"Fri, 6 Mar 2020 22:54:11 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Nicolas Dufresne <nicolas@ndufresne.ca>","Cc":"libcamera-devel@lists.libcamera.org,\n\tNicolas Dufresne <nicolas.dufresne@collabora.com>","Message-ID":"<20200306205411.GV4878@pendragon.ideasonboard.com>","References":"<20200306202637.525587-1-nicolas@ndufresne.ca>\n\t<20200306202637.525587-18-nicolas@ndufresne.ca>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20200306202637.525587-18-nicolas@ndufresne.ca>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v3 17/27] gst: Add a pool and an\n\tallocator implementation","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":"Fri, 06 Mar 2020 20:54:15 -0000"}}]