1 /* GStreamer dmabuf allocator
2 * Copyright (C) 2013 Linaro SA
3 * Author: Benjamin Gaignard <benjamin.gaignard@linaro.org> for Linaro.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for mordetails.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
21 #include "gstdmabuf.h"
25 * @short_description: Memory wrapper for Linux dmabuf memory
26 * @see_also: #GstMemory
37 * @fd: the file descriptor associated this memory
38 * @data: mmapped address
39 * @mmapping_flags: mmapping flags
40 * @mmap_count: mmapping counter
41 * @lock: a mutex to make mmapping thread safe
54 #define ALLOCATOR_NAME "dmabuf"
56 GST_DEBUG_CATEGORY_STATIC (dmabuf_debug);
57 #define GST_CAT_DEFAULT dmabuf_debug
60 _dmabuf_alloc (GstAllocator * allocator, gsize size,
61 GstAllocationParams * params)
63 g_warning ("Use dmabuf_mem_alloc() to allocate from this allocator");
69 _dmabuf_free (GstAllocator * allocator, GstMemory * mem)
71 GstDmaBufMemory *dbmem = (GstDmaBufMemory *) mem;
74 g_warning ("Freeing memory still mapped");
77 g_mutex_clear (&dbmem->lock);
78 g_slice_free (GstDmaBufMemory, dbmem);
79 GST_DEBUG ("%p: freed", dbmem);
83 _dmabuf_mem_map (GstDmaBufMemory * mem, gsize maxsize, GstMapFlags flags)
88 g_mutex_lock (&mem->lock);
90 prot = flags & GST_MAP_READ ? PROT_READ : 0;
91 prot |= flags & GST_MAP_WRITE ? PROT_WRITE : 0;
93 /* do not mmap twice the buffer */
95 /* only return address if mapping flags are a subset
96 * of the previous flags */
97 if (mem->mmapping_flags & prot)
104 mem->data = mmap (0, maxsize, prot, MAP_SHARED, mem->fd, 0);
106 GST_DEBUG ("%p: fd %d: mapped %p", mem, mem->fd, mem->data);
109 mem->mmapping_flags = prot;
110 mem->mem.size = maxsize;
116 g_mutex_unlock (&mem->lock);
121 _dmabuf_mem_unmap (GstDmaBufMemory * mem)
123 g_mutex_lock (&mem->lock);
125 if (mem->data && !(--mem->mmap_count)) {
126 munmap ((void *) mem->data, mem->mem.size);
129 mem->mmapping_flags = 0;
130 GST_DEBUG ("%p: fd %d unmapped", mem, mem->fd);
132 g_mutex_unlock (&mem->lock);
136 static GstDmaBufMemory *
137 _dmabuf_mem_share (GstDmaBufMemory * mem, gssize offset, gsize size)
139 GstDmaBufMemory *sub;
141 GST_DEBUG ("%p: share %" G_GSSIZE_FORMAT " %" G_GSIZE_FORMAT, mem, offset,
144 /* find the real parent */
145 if ((parent = mem->mem.parent) == NULL)
146 parent = (GstMemory *) mem;
149 size = mem->mem.size - offset;
151 sub = g_slice_new (GstDmaBufMemory);
152 /* the shared memory is always readonly */
153 gst_memory_init (GST_MEMORY_CAST (sub), GST_MINI_OBJECT_FLAGS (parent) |
154 GST_MINI_OBJECT_FLAG_LOCK_READONLY, mem->mem.allocator, parent,
155 mem->mem.maxsize, mem->mem.align, mem->mem.offset + offset, size);
160 static GstDmaBufMemory *
161 _dmabuf_mem_copy (GstDmaBufMemory * mem, gssize offset, gsize size)
163 gint newfd = dup (mem->fd);
166 GST_WARNING ("Can't duplicate dmabuf file descriptor");
170 GST_DEBUG ("%p: copy %" G_GSSIZE_FORMAT " %" G_GSIZE_FORMAT, mem, offset,
172 return (GstDmaBufMemory *) gst_dmabuf_allocator_alloc (mem->mem.allocator,
179 } dmabuf_mem_Allocator;
183 GstAllocatorClass parent_class;
184 } dmabuf_mem_AllocatorClass;
186 GType dmabuf_mem_allocator_get_type (void);
187 G_DEFINE_TYPE (dmabuf_mem_Allocator, dmabuf_mem_allocator, GST_TYPE_ALLOCATOR);
189 #define GST_TYPE_DMABUF_ALLOCATOR (dmabuf_mem_allocator_get_type())
190 #define GST_IS_DMABUF_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DMABUF_ALLOCATOR))
193 dmabuf_mem_allocator_class_init (dmabuf_mem_AllocatorClass * klass)
195 GstAllocatorClass *allocator_class;
197 allocator_class = (GstAllocatorClass *) klass;
199 allocator_class->alloc = _dmabuf_alloc;
200 allocator_class->free = _dmabuf_free;
204 dmabuf_mem_allocator_init (dmabuf_mem_Allocator * allocator)
206 GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
208 alloc->mem_type = ALLOCATOR_NAME;
209 alloc->mem_map = (GstMemoryMapFunction) _dmabuf_mem_map;
210 alloc->mem_unmap = (GstMemoryUnmapFunction) _dmabuf_mem_unmap;
211 alloc->mem_share = (GstMemoryShareFunction) _dmabuf_mem_share;
212 alloc->mem_copy = (GstMemoryCopyFunction) _dmabuf_mem_copy;
216 _dmabuf_mem_init (void)
218 GstAllocator *allocator =
219 g_object_new (dmabuf_mem_allocator_get_type (), NULL);
220 gst_allocator_register (ALLOCATOR_NAME, allocator);
222 GST_DEBUG_CATEGORY_INIT (dmabuf_debug, "dmabuf", 0, "dmabuf memory");
226 * gst_dmabuf_allocator_obtain:
228 * Return a dmabuf allocator.
230 * Returns: (transfer full): a dmabuf allocator, or NULL if the allocator
231 * isn't available. Use gst_object_unref() to release the allocator after
237 gst_dmabuf_allocator_obtain (void)
239 static GOnce dmabuf_allocator_once = G_ONCE_INIT;
240 GstAllocator *allocator;
242 g_once (&dmabuf_allocator_once, (GThreadFunc) _dmabuf_mem_init, NULL);
244 allocator = gst_allocator_find (ALLOCATOR_NAME);
246 GST_WARNING ("No allocator named %s found", ALLOCATOR_NAME);
251 * gst_dmabuf_allocator_alloc:
252 * @allocator: allocator to be used for this memory
253 * @fd: dmabuf file descriptor
256 * Return a %GstMemory that wraps a dmabuf file descriptor.
258 * Returns: (transfer full): a GstMemory based on @allocator.
259 * When the buffer will be released dmabuf allocator will close the @fd.
260 * The memory is only mmapped on gst_buffer_mmap() request.
265 gst_dmabuf_allocator_alloc (GstAllocator * allocator, gint fd, gsize size)
267 GstDmaBufMemory *mem;
270 allocator = gst_dmabuf_allocator_obtain ();
273 if (!GST_IS_DMABUF_ALLOCATOR (allocator)) {
274 GST_WARNING ("it isn't the correct allocator for dmabuf");
278 GST_DEBUG ("alloc from allocator %p", allocator);
280 mem = g_slice_new (GstDmaBufMemory);
282 gst_memory_init (GST_MEMORY_CAST (mem), 0, allocator, NULL, size, 0, 0, 0);
286 mem->mmapping_flags = 0;
288 g_mutex_init (&mem->lock);
290 GST_DEBUG ("%p: fd: %d size %d", mem, mem->fd, mem->mem.maxsize);
292 return (GstMemory *) mem;
296 * gst_dmabuf_memory_get_fd:
297 * @mem: the memory to get the file descriptor
299 * Return the file descriptor associated with @mem.
301 * Returns: the file descriptor associated with the memory, or -1
306 gst_dmabuf_memory_get_fd (GstMemory * mem)
308 GstDmaBufMemory *dbmem = (GstDmaBufMemory *) mem;
310 g_return_val_if_fail (gst_is_dmabuf_memory (mem), -1);
316 * gst_is_dmabuf_memory:
317 * @mem: the memory to be check
319 * Check if @mem is dmabuf memory.
321 * Returns: %TRUE if @mem is dmabuf memory, otherwise %FALSE
326 gst_is_dmabuf_memory (GstMemory * mem)
328 return g_strcmp0 (mem->allocator->mem_type, ALLOCATOR_NAME) == 0;
331 #else /* !HAVE_MMAP */
334 gst_dmabuf_allocator_obtain (void)
340 gst_dmabuf_allocator_alloc (GstAllocator * allocator, gint fd, gsize size)
346 gst_dmabuf_memory_get_fd (GstMemory * mem)
352 gst_is_dmabuf_memory (GstMemory * mem)
357 #endif /* HAVE_MMAP */