By design, unixfd is meant to be used for zero-copy and failing when the data is not FD based memory is wanted to help debug pipelines. Though, there exists cases, notably with RTP payloader and demuxers, where its not possible to get all the data into FD memory through allocation queries. To allow using unixfd for these cases, introduce a property on the unixfdsink that enable copying the non FD data into freshly allocated memfd. Co-authored-by: Nicolas Dufresne <nicolas.dufresne@collabora.com> Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8861>
151 lines
4.1 KiB
C
151 lines
4.1 KiB
C
/* GStreamer unix file-descriptor source/sink
|
|
*
|
|
* Copyright (C) 2025 Netflix Inc.
|
|
* Author: Xavier Claessens <xclaessens@netflix.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "gstunixfdallocator.h"
|
|
|
|
struct _GstUnixFdAllocator
|
|
{
|
|
GstShmAllocator parent;
|
|
|
|
GMutex lock;
|
|
GList *pool;
|
|
gboolean flush;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GstUnixFdAllocator, gst_unix_fd_allocator,
|
|
GST_TYPE_SHM_ALLOCATOR);
|
|
|
|
static gboolean
|
|
gst_unix_fd_allocator_mem_dispose (GstMiniObject * obj)
|
|
{
|
|
GstMemory *mem = GST_MEMORY_CAST (obj);
|
|
GstUnixFdAllocator *self = GST_UNIX_FD_ALLOCATOR (mem->allocator);
|
|
|
|
g_mutex_lock (&self->lock);
|
|
|
|
if (self->flush) {
|
|
g_mutex_unlock (&self->lock);
|
|
return TRUE;
|
|
}
|
|
|
|
gsize offset, maxsize;
|
|
gst_memory_get_sizes (mem, &offset, &maxsize);
|
|
gst_memory_resize (mem, -offset, maxsize);
|
|
|
|
self->pool = g_list_prepend (self->pool, gst_memory_ref (mem));
|
|
|
|
g_mutex_unlock (&self->lock);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static GstMemory *
|
|
gst_unix_fd_allocator_alloc (GstAllocator * allocator, gsize size,
|
|
GstAllocationParams * params)
|
|
{
|
|
GstUnixFdAllocator *self = GST_UNIX_FD_ALLOCATOR (allocator);
|
|
gsize smallest_size = G_MAXSIZE;
|
|
GList *smallest_link = NULL;
|
|
|
|
/* Check if we have a memory big enough in our pool. */
|
|
g_mutex_lock (&self->lock);
|
|
for (GList * l = self->pool; l != NULL; l = l->next) {
|
|
GstMemory *mem = l->data;
|
|
gsize maxsize;
|
|
|
|
gst_memory_get_sizes (mem, NULL, &maxsize);
|
|
if (maxsize >= size) {
|
|
self->pool = g_list_delete_link (self->pool, l);
|
|
g_mutex_unlock (&self->lock);
|
|
return mem;
|
|
}
|
|
if (maxsize < smallest_size) {
|
|
smallest_size = maxsize;
|
|
smallest_link = l;
|
|
}
|
|
}
|
|
/* All our memories are too small. Delete the smallest one to converge to a
|
|
* size that will avoid re-allocations in the future. */
|
|
if (smallest_link != NULL) {
|
|
GstMemory *mem = smallest_link->data;
|
|
self->pool = g_list_delete_link (self->pool, smallest_link);
|
|
GST_MINI_OBJECT_CAST (mem)->dispose = NULL;
|
|
gst_memory_unref (mem);
|
|
}
|
|
g_mutex_unlock (&self->lock);
|
|
|
|
/* Allocate a new memory */
|
|
GstMemory *mem =
|
|
GST_ALLOCATOR_CLASS (gst_unix_fd_allocator_parent_class)->alloc
|
|
(allocator, size, params);
|
|
if (mem != NULL)
|
|
GST_MINI_OBJECT_CAST (mem)->dispose = gst_unix_fd_allocator_mem_dispose;
|
|
|
|
return mem;
|
|
}
|
|
|
|
static void
|
|
gst_unix_fd_allocator_finalize (GObject * object)
|
|
{
|
|
GstUnixFdAllocator *self = GST_UNIX_FD_ALLOCATOR (object);
|
|
|
|
g_mutex_clear (&self->lock);
|
|
|
|
G_OBJECT_CLASS (gst_unix_fd_allocator_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gst_unix_fd_allocator_class_init (GstUnixFdAllocatorClass * klass)
|
|
{
|
|
GstAllocatorClass *alloc_class = (GstAllocatorClass *) klass;
|
|
GObjectClass *object_class = (GObjectClass *) klass;
|
|
|
|
object_class->finalize = gst_unix_fd_allocator_finalize;
|
|
|
|
alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_unix_fd_allocator_alloc);
|
|
}
|
|
|
|
static void
|
|
gst_unix_fd_allocator_init (GstUnixFdAllocator * self)
|
|
{
|
|
g_mutex_init (&self->lock);
|
|
}
|
|
|
|
GstUnixFdAllocator *
|
|
gst_unix_fd_allocator_new (void)
|
|
{
|
|
return g_object_new (GST_TYPE_UNIX_FD_ALLOCATOR, NULL);
|
|
}
|
|
|
|
void
|
|
gst_unix_fd_allocator_flush (GstUnixFdAllocator * self)
|
|
{
|
|
g_return_if_fail (GST_IS_UNIX_FD_ALLOCATOR (self));
|
|
|
|
g_mutex_lock (&self->lock);
|
|
GList *pool = self->pool;
|
|
self->pool = NULL;
|
|
self->flush = TRUE;
|
|
g_mutex_unlock (&self->lock);
|
|
|
|
g_list_free_full (pool, (GDestroyNotify) gst_memory_unref);
|
|
}
|